mirror of
https://github.com/urbit/shrub.git
synced 2024-11-24 04:58:08 +03:00
hoon: moves $plum and +plume to userspace
This commit is contained in:
parent
25cea09fd1
commit
aea0f571d7
@ -29,6 +29,7 @@ done
|
||||
cp $ARVO/app/lens.hoon ./pier/home/app/
|
||||
cp $ARVO/app/dojo.hoon ./pier/home/app/
|
||||
cp $ARVO/lib/base64.hoon ./pier/home/lib/
|
||||
cp $ARVO/lib/plume.hoon ./pier/home/lib/
|
||||
cp $ARVO/lib/server.hoon ./pier/home/lib/
|
||||
cp $ARVO/lib/sole.hoon ./pier/home/lib/
|
||||
cp $ARVO/lib/xray.hoon ./pier/home/lib/
|
||||
@ -39,6 +40,7 @@ mkdir -p ./pier/home/mar/lens/
|
||||
cp $ARVO/mar/lens/* ./pier/home/mar/lens/
|
||||
|
||||
cp $ARVO/sur/lens.hoon ./pier/home/sur/
|
||||
cp $ARVO/sur/plum.hoon ./pier/home/sur/
|
||||
cp $ARVO/sur/sole.hoon ./pier/home/sur/
|
||||
|
||||
# Update +solid and its dependencies
|
||||
|
420
pkg/arvo/lib/plume.hoon
Normal file
420
pkg/arvo/lib/plume.hoon
Normal file
@ -0,0 +1,420 @@
|
||||
/- *plum
|
||||
::
|
||||
:: This library includes `plume`, the actual pretty printing logic,
|
||||
:: and a handful of utilities for constructing plums.
|
||||
::
|
||||
:: Generally, you'll just use `plume` like this:
|
||||
::
|
||||
:: ~(tall plume plum) :: Pretty print `plum` in tall mode.
|
||||
:: ~(flat plume plum) :: Pretty print `plum` in wide mode.
|
||||
::
|
||||
:: There is probably no reason to look at the utility routines unless
|
||||
:: you are writing something to generate `plum`s.
|
||||
::
|
||||
:: This is the pretty-printer. Use the `flat` arm to render a plum
|
||||
:: into a single line and use the `tall` arm to get a nice multi-line
|
||||
:: rendering that switches to wide mode if there's enough space.
|
||||
::
|
||||
:: For details about how this works and what exactly it does in various
|
||||
:: cases, take a look at the docs for `plum`, `plumfmt`, and at the
|
||||
:: docs on the arms of this door.
|
||||
::
|
||||
^? |%
|
||||
++ plume
|
||||
|_ =plum
|
||||
::
|
||||
:: An line, indented by `indent` spaces.
|
||||
::
|
||||
+$ line [indent=@ud text=tape]
|
||||
::
|
||||
:: An sequence of indented lines.
|
||||
::
|
||||
+$ block (list line)
|
||||
::
|
||||
:: +flat: print as a single line
|
||||
::
|
||||
++ flat
|
||||
^- wain
|
||||
text:linear
|
||||
::
|
||||
:: +tall: print as multiple lines
|
||||
::
|
||||
++ tall
|
||||
^- wain
|
||||
%+ turn window
|
||||
|= line
|
||||
(crip (runt [indent ' '] text))
|
||||
::
|
||||
:: +adjust: adjust lines to right
|
||||
::
|
||||
++ adjust
|
||||
|= [tab=@ud =block] ^- ^block
|
||||
(turn block |=([@ud tape] [(add tab +<-) +<+]))
|
||||
::
|
||||
:: Prepend `n` spaces to a tape.
|
||||
::
|
||||
++ prepend-spaces
|
||||
|= [n=@ t=tape] ^- tape
|
||||
(runt [n ' '] t)
|
||||
::
|
||||
:: +window: print as list of tabbed lines
|
||||
::
|
||||
++ window
|
||||
^- block
|
||||
~+ :: for random access
|
||||
?@ plum [0 (trip plum)]~ :: trivial text
|
||||
?- -.plum
|
||||
::
|
||||
:: %para: Line-wrappable paragraph. This is a stub; it should
|
||||
:: wrap text to 40 characters.
|
||||
::
|
||||
%para
|
||||
[0 +:linear]~
|
||||
::
|
||||
:: %sbrk: nested subexpression
|
||||
::
|
||||
:: This is an opportunity to switch to wide mode. First, try
|
||||
:: rendered in wide mode. If that's possible and the result
|
||||
:: isn't too big, use that. Otherwise recurse into the subplum
|
||||
:: without switching to wide mode.
|
||||
::
|
||||
%sbrk
|
||||
=/ sub kid.plum
|
||||
?+ sub
|
||||
window(plum sub)
|
||||
[%tree *]
|
||||
=/ wideresult
|
||||
?~(wide.fmt.sub ~ [~ u=linear])
|
||||
?: ?&(?=(^ wideresult) (lte length.u.wideresult 40))
|
||||
[0 text.u.wideresult]~
|
||||
window(plum sub)
|
||||
==
|
||||
::
|
||||
:: %tree: Try to render a text tree in tall mode.
|
||||
::
|
||||
:: We want to render this in tall mode. First, verify that there
|
||||
:: the plum has a tall render (if not, fall back to `linear`
|
||||
:: formatting), then render all the subplums, and then render
|
||||
:: them in one of three ways:
|
||||
::
|
||||
:: - If the `plumfmt` contains an `indef` and that indef has
|
||||
:: no prefix, then this is a variable-arity rune with a
|
||||
:: terminator: Use vertical formatting.
|
||||
::
|
||||
:: - If the `plumfmt` contains an `indef` and that indef DOES have
|
||||
:: a prefix, then this is something that looks like a core: Use
|
||||
:: `core-like` formatting.
|
||||
::
|
||||
:: - Otherwise, this is a rune with a fixed number of arguments
|
||||
:: Render the subplums using backstep indentation.
|
||||
::
|
||||
:: There's also a special case where something has exactly one sub-plum.
|
||||
:: where something has exactly one sub-block. For example, we
|
||||
:: want this output:
|
||||
::
|
||||
:: |-
|
||||
:: foo
|
||||
::
|
||||
%tree
|
||||
?~ tall.fmt.plum [0 text:linear]~
|
||||
=/ prelude (trip intro.u.tall.fmt.plum)
|
||||
|^ =/ blocks (turn kids.plum |=(=^plum window(plum plum)))
|
||||
=/ prelude (trip intro.u.tall.fmt.plum)
|
||||
?~ indef.u.tall.fmt.plum
|
||||
?: =(1 (lent blocks))
|
||||
[[0 prelude] (zing blocks)]
|
||||
(backstep prelude blocks)
|
||||
=/ prefix (trip sigil.u.indef.u.tall.fmt.plum)
|
||||
=/ finale (trip final.u.indef.u.tall.fmt.plum)
|
||||
?~ blocks %+ weld
|
||||
?~(prelude ~ [0 prelude]~)
|
||||
?~(finale ~ [0 finale]~)
|
||||
?~ prefix (running prelude blocks finale)
|
||||
(core-like prelude prefix blocks finale)
|
||||
--
|
||||
==
|
||||
::
|
||||
:: Render a plum in tall-mode using backstep indentation. Here,
|
||||
:: we are rendering things that look something like this:
|
||||
::
|
||||
:: :+ foo
|
||||
:: bar
|
||||
:: baz
|
||||
::
|
||||
++ backstep
|
||||
|= [prelude=tape blocks=(list block)]
|
||||
^- block
|
||||
%- zing
|
||||
=/ nkids (lent blocks)
|
||||
=/ idx 1
|
||||
|- ^- (list block)
|
||||
?~ blocks ~
|
||||
:_ $(blocks t.blocks, idx +(idx))
|
||||
^- block
|
||||
=/ indent (mul 2 (sub nkids idx))
|
||||
?. =(1 idx) (adjust indent i.blocks)
|
||||
(rune-inline-with-block prelude indent i.blocks)
|
||||
::
|
||||
:: To make things look a bit nicer, we want to put the first
|
||||
:: sub-block on the same line as the rune. We want this:
|
||||
::
|
||||
:: :- foo
|
||||
:: baz
|
||||
::
|
||||
:: Instead of this:
|
||||
::
|
||||
:: :-
|
||||
:: foo
|
||||
:: baz
|
||||
::
|
||||
:: This handles the "foo" case.
|
||||
::
|
||||
++ rune-inline-with-block
|
||||
|= [rune=tape indent=@ blk=block]
|
||||
^- block
|
||||
=. indent (max indent (add 2 (lent rune)))
|
||||
=. blk (adjust indent blk)
|
||||
?~ rune blk
|
||||
?~ blk [0 rune]~
|
||||
:_ t.blk
|
||||
:- 0
|
||||
%+ weld rune
|
||||
=/ spaces-btwn (sub indent.i.blk (lent rune))
|
||||
(prepend-spaces spaces-btwn text.i.blk)
|
||||
::
|
||||
:: Render a tall hoon with running indentation. Here, we are
|
||||
:: rendering things that look sopmething like:
|
||||
::
|
||||
:: :~ foo
|
||||
:: bar
|
||||
:: baz
|
||||
:: ==
|
||||
::
|
||||
:: So, there's basically three cases here: Either the prelude
|
||||
:: is a rune, the prelude is empty, or prelude is some other
|
||||
:: random-ass thing.
|
||||
::
|
||||
:: - If there is no prelude, then just combine all of the
|
||||
:: sub-blocks together unaltered.
|
||||
:: - If it's a rune (two-characters wide), then combine the
|
||||
:: rune and the first line into one line (separated by two
|
||||
:: spaces) and indent the rest of the lines by four spaces.
|
||||
:: - If the rune is some other random-ass thing (has a length
|
||||
:: that isn't 0 or 2), then render the prelude alone on the
|
||||
:: first line and then combine the sub-blocks together,
|
||||
:: all indented by another two spaces.
|
||||
::
|
||||
:: Regardless, if there's a finale, stick it on the end without
|
||||
:: any indentation.
|
||||
::
|
||||
++ running
|
||||
|= [prelude=tape blocks=(list block) finale=tape]
|
||||
^- block
|
||||
=/ result=block (zing blocks)
|
||||
=. result
|
||||
?+ (lent prelude)
|
||||
[[0 prelude] (adjust 2 result)] :: unusual prelude
|
||||
%0 :: empty prelude
|
||||
result
|
||||
%2 :: rune prelude
|
||||
(rune-inline-with-block prelude 4 result)
|
||||
==
|
||||
?~ finale result
|
||||
(snoc result [0 finale])
|
||||
::
|
||||
:: This renders sub-blocks where each sub-block needs to be
|
||||
:: prefixed by some tape. For example:
|
||||
::
|
||||
:: |%
|
||||
:: ++ foo
|
||||
:: bar
|
||||
:: ++ baz
|
||||
:: qux
|
||||
:: --
|
||||
::
|
||||
++ core-like
|
||||
|= [prelude=tape prefix=tape blocks=(list block) finale=tape]
|
||||
^- block
|
||||
=/ clear (add 2 (lent prefix))
|
||||
=/ result
|
||||
^- block
|
||||
%- zing
|
||||
^- (list block)
|
||||
%+ turn blocks
|
||||
|= blk=block
|
||||
^- block
|
||||
^+ +<
|
||||
=* tab ?~(blk 0 (sub clear (min clear indent.i.blk)))
|
||||
=. blk (adjust tab blk)
|
||||
?~ blk ~
|
||||
:_ t.blk
|
||||
:- 0
|
||||
%+ weld prefix
|
||||
(runt [(sub indent.i.blk (lent prefix)) ' '] text.i.blk)
|
||||
=. result
|
||||
?~ finale result
|
||||
(snoc result [0 finale])
|
||||
?~ prelude result
|
||||
[[0 prelude] result]
|
||||
::
|
||||
:: +linear: Render a plum onto a single line, even if it only has a
|
||||
:: wide form.
|
||||
::
|
||||
++ linear
|
||||
^- [length=@ud text=tape]
|
||||
~+ :: ~+ for random access
|
||||
?@ plum [(met 3 plum) (trip plum)] :: Just a cord.
|
||||
?- -.plum
|
||||
::
|
||||
:: This is already in wide mode, so %sbrk nodes don't matter here.
|
||||
::
|
||||
%sbrk
|
||||
linear(plum kid.plum)
|
||||
::
|
||||
:: %para: To write a wrappable text paragraph to a single line,
|
||||
:: we just combine all the lines into one, interspersing single
|
||||
:: spaces chars.
|
||||
::
|
||||
%para
|
||||
|- ^- [length=@ud text=tape]
|
||||
?~ lines.plum [0 ~]
|
||||
=/ next $(lines.plum t.lines.plum)
|
||||
=/ this [length=(met 3 i.lines.plum) text=(trip i.lines.plum)]
|
||||
:- (add +(length.this) length.next)
|
||||
(weld text.this `tape`[' ' text.next])
|
||||
::
|
||||
:: Render a text tree to a single line.
|
||||
::
|
||||
%tree
|
||||
|^ ^- [length=@ud text=tape]
|
||||
?~ wide.fmt.plum (force-wide window)
|
||||
=/ body (render-body delimit.u.wide.fmt.plum kids.plum)
|
||||
?~ enclose.u.wide.fmt.plum body
|
||||
(wrap-with-enclose u.enclose.u.wide.fmt.plum body)
|
||||
::
|
||||
:: Given a list of subplums and a delimiter, render all the
|
||||
:: subplums onto a single line, and combine them into a single
|
||||
:: string by interspersing the delimiter.
|
||||
::
|
||||
++ render-body
|
||||
|= [delimit=cord kids=(list ^plum)]
|
||||
=/ stop (trip delimit)
|
||||
|- ^- [length=@ud text=tape]
|
||||
?~ kids [0 ~]
|
||||
=/ next $(kids t.kids)
|
||||
=/ this linear(plum i.kids)
|
||||
?~ text.next this
|
||||
:- :(add length.this (lent stop) length.next)
|
||||
:(weld text.this stop text.next)
|
||||
::
|
||||
:: Wrap a wide-form-rendered result with the `enclose` cords
|
||||
:: from its `plumefmt`.
|
||||
::
|
||||
++ wrap-with-enclose
|
||||
|= [clamps=(pair cord cord) body=[length=@ text=tape]]
|
||||
^- [length=@ud text=tape]
|
||||
::
|
||||
=/ close [(trip -.clamps) (trip +.clamps)]
|
||||
:- :(add length.body (lent -.close) (lent +.close))
|
||||
:(weld -.close text.body +.close)
|
||||
::
|
||||
:: Given the result of rendering a plum in tall form, combine
|
||||
:: all the lines into one by separating each by two spaces.
|
||||
::
|
||||
++ force-wide
|
||||
|= render=(list [@ud text=tape])
|
||||
^- [length=@ud text=tape]
|
||||
::
|
||||
?~ render [0 ~]
|
||||
=/ next (force-wide t.render)
|
||||
:- :(add (lent text.i.render) 2 length.next)
|
||||
?~(text.next text.i.render :(weld text.i.render " " text.next))
|
||||
--
|
||||
==
|
||||
--
|
||||
::
|
||||
:: Convenience function to build a `plumfmt` for a rune with a fixed
|
||||
:: number of parameters.
|
||||
::
|
||||
++ fixed
|
||||
|= rune=@ta
|
||||
^- plumfmt
|
||||
[wide=`[' ' `[(cat 3 +< '(') ')']] tall=`[+< ~]]
|
||||
::
|
||||
:: Same as `fixed` but only outputs in `tall` mode.
|
||||
::
|
||||
++ tall-fixed
|
||||
|= rune=cord
|
||||
^- (unit [cord (unit [cord cord])])
|
||||
`[rune ~]
|
||||
::
|
||||
:: Convenience function to build a the `tall` part of a `plumfmt` for
|
||||
:: a running-style rune (one that takes a variable number of parameters
|
||||
:: and has a terminator).
|
||||
::
|
||||
++ tall-running
|
||||
|= [rune=cord sigil=cord term=cord]
|
||||
^- (unit [cord (unit [cord cord])])
|
||||
`[rune `[sigil term]]
|
||||
::
|
||||
:: Convenience function for rendering a rune into a plum. This takes
|
||||
:: a rune, an optional tall-form terminator, optionally a short-form (if
|
||||
:: you don't supply a short-form, it'll just construct the standard
|
||||
:: wide-form (e.g. "?~(x x ~)") for you, and a list of sub-plums.
|
||||
::
|
||||
++ rune
|
||||
|= $: rune=cord
|
||||
term=(unit cord)
|
||||
short=(unit [cord cord cord])
|
||||
kids=(list plum)
|
||||
==
|
||||
^. plum
|
||||
|^ :- %sbrk
|
||||
:+ %tree
|
||||
:- (rune-wide-form rune short)
|
||||
?~ term (tall-fixed rune)
|
||||
(tall-running rune '' u.term)
|
||||
kids
|
||||
::
|
||||
:: If you just give this a rune, it'll build the standard wide-form.
|
||||
:: Otherwise, it'll just use the one that you gave it.
|
||||
::
|
||||
++ rune-wide-form
|
||||
|= [rune=cord short=(unit [fst=cord mid=cord lst=cord])]
|
||||
^- (unit (pair cord (unit [cord cord])))
|
||||
=* fst (cat 3 rune '(')
|
||||
=* std `[' ' `[fst ')']]
|
||||
?~ short std
|
||||
`[mid.u.short `[fst.u.short lst.u.short]]
|
||||
--
|
||||
::
|
||||
:: Just a helper function for constructing a wide-form %tree plum.
|
||||
::
|
||||
++ simple-wide
|
||||
|= [init=cord sep=cord end=cord kids=(list plum)]
|
||||
^- plum
|
||||
=/ fmt=plumfmt [wide=[~ sep [~ init end]] tall=~]
|
||||
[%tree fmt kids]
|
||||
::
|
||||
:: Convenience function that builds a plum for a subexpression. The
|
||||
:: `%sbrk` tells the pretty-printer that this is a valid place to
|
||||
:: switch from tall mode to wide mode.
|
||||
::
|
||||
++ subtree
|
||||
|= [p=plumfmt q=(list plum)]
|
||||
^- plum
|
||||
[%sbrk [%tree p q]]
|
||||
::
|
||||
:: Convenience for generating plums that look like s-expressions. Useful
|
||||
:: for quickly getting decent-looking debug output.
|
||||
::
|
||||
++ sexp
|
||||
|= [sym=cord kids=(list plum)]
|
||||
^- plum
|
||||
=/ head=cord (cat 3 '(' sym)
|
||||
=/ headspc=cord (cat 3 head ' ')
|
||||
=/ symcol=cord (cat 3 sym ':')
|
||||
=/ fmt=plumfmt [[~ ' ' [~ headspc ')']] [~ symcol [~ '' '']]]
|
||||
?~ kids (cat 3 '(' (cat 3 sym ')'))
|
||||
[%sbrk [%tree fmt kids]]
|
||||
--
|
@ -1,4 +1,6 @@
|
||||
/+ libxray=xray
|
||||
/- *plum
|
||||
/+ *plume,
|
||||
libxray=xray
|
||||
::
|
||||
:: This code pretty-prints a variety of things using the `xray` and
|
||||
:: `plum` libraries:
|
||||
|
@ -1,3 +1,4 @@
|
||||
/- *plum
|
||||
::
|
||||
:: # Type Analysis
|
||||
::
|
||||
|
51
pkg/arvo/sur/plum.hoon
Normal file
51
pkg/arvo/sur/plum.hoon
Normal file
@ -0,0 +1,51 @@
|
||||
^? |%
|
||||
::
|
||||
:: A `plum` is the intermediate representation for the pretty-printer. It
|
||||
:: encodes hoon-shaped data with the least amount of structured needed
|
||||
:: for formating.
|
||||
::
|
||||
:: A `plum` is either a
|
||||
::
|
||||
:: - `cord`: A simple cord
|
||||
:: - `[%para *]`: A wrappable paragraph.
|
||||
:: - `[%tree *]`: A formatted plum tree
|
||||
:: - `[%sbrk *]`: An indication of a nested subexpression.
|
||||
::
|
||||
:: The formatter will use the tall mode unless:
|
||||
::
|
||||
:: - A plum has only a `wide` style.
|
||||
:: - The plum is in `%sbrk` form and its subplum (`kid`), when
|
||||
:: formatted in wide mode, can fit on a single line.
|
||||
::
|
||||
+$ plum
|
||||
$@ cord
|
||||
$% [%para prefix=tile lines=(list @t)]
|
||||
[%tree fmt=plumfmt kids=(list plum)]
|
||||
[%sbrk kid=plum]
|
||||
==
|
||||
::
|
||||
:: A `plumfmt` is a description of how to render a `plum`. A `plumfmt`
|
||||
:: must include a `wide`, a `tall`, or both.
|
||||
::
|
||||
:: A `wide` is a description of how to render a plum in a single
|
||||
:: line. The nested (`kids`) sub-plums will be interleaved with `delimit`
|
||||
:: strings, and, if `enclose` is set, then the output will be enclosed
|
||||
:: with `p.u.enclose` abnd `q.u.enclose`.
|
||||
::
|
||||
:: For example, to build a plumfmt for string literals, we could write:
|
||||
::
|
||||
:: [wide=[~ '' [~ '"' '"']] tall=~]
|
||||
::
|
||||
:: A `tall` is a description of how to render a plum across multiple
|
||||
:: lines. The output will be prefixed by `intro`, suffixed by
|
||||
:: `final.u.indef`, and each subplum prefixed by `sigil.u.indef`.
|
||||
::
|
||||
:: For example, to build a plumfmt for cores, we could write:
|
||||
::
|
||||
:: [wide=~ tall=`['' `['++' '--']]]
|
||||
::
|
||||
+$ plumfmt
|
||||
$: wide=(unit [delimit=tile enclose=(unit (pair tile tile))])
|
||||
tall=(unit [intro=tile indef=(unit [sigil=tile final=tile])])
|
||||
==
|
||||
--
|
@ -1973,56 +1973,6 @@
|
||||
::
|
||||
cord
|
||||
+$ tint ?($r $g $b $c $m $y $k $w $~) :: text color
|
||||
::
|
||||
:: A `plum` is the intermediate representation for the pretty-printer. It
|
||||
:: encodes hoon-shaped data with the least amount of structured needed
|
||||
:: for formating.
|
||||
::
|
||||
:: A `plum` is either a
|
||||
::
|
||||
:: - `cord`: A simple cord
|
||||
:: - `[%para *]`: A wrappable paragraph.
|
||||
:: - `[%tree *]`: A formatted plum tree
|
||||
:: - `[%sbrk *]`: An indication of a nested subexpression.
|
||||
::
|
||||
:: The formatter will use the tall mode unless:
|
||||
::
|
||||
:: - A plum has only a `wide` style.
|
||||
:: - The plum is in `%sbrk` form and its subplum (`kid`), when
|
||||
:: formatted in wide mode, can fit on a single line.
|
||||
::
|
||||
+$ plum
|
||||
$@ cord
|
||||
$% [%para prefix=tile lines=(list @t)]
|
||||
[%tree fmt=plumfmt kids=(list plum)]
|
||||
[%sbrk kid=plum]
|
||||
==
|
||||
::
|
||||
:: A `plumfmt` is a description of how to render a `plum`. A `plumfmt`
|
||||
:: must include a `wide`, a `tall`, or both.
|
||||
::
|
||||
:: A `wide` is a description of how to render a plum in a single
|
||||
:: line. The nested (`kids`) sub-plums will be interleaved with `delimit`
|
||||
:: strings, and, if `enclose` is set, then the output will be enclosed
|
||||
:: with `p.u.enclose` abnd `q.u.enclose`.
|
||||
::
|
||||
:: For example, to build a plumfmt for string literals, we could write:
|
||||
::
|
||||
:: [wide=[~ '' [~ '"' '"']] tall=~]
|
||||
::
|
||||
:: A `tall` is a description of how to render a plum across multiple
|
||||
:: lines. The output will be prefixed by `intro`, suffixed by
|
||||
:: `final.u.indef`, and each subplum prefixed by `sigil.u.indef`.
|
||||
::
|
||||
:: For example, to build a plumfmt for cores, we could write:
|
||||
::
|
||||
:: [wide=~ tall=`['' `['++' '--']]]
|
||||
::
|
||||
+$ plumfmt
|
||||
$: wide=(unit [delimit=tile enclose=(unit (pair tile tile))])
|
||||
tall=(unit [intro=tile indef=(unit [sigil=tile final=tile])])
|
||||
==
|
||||
::
|
||||
++ tang (list tank) :: bottom-first error
|
||||
++ tank $~ [%leaf ~] ::
|
||||
$% {$leaf p/tape} :: printing formats
|
||||
@ -4512,423 +4462,6 @@
|
||||
|= {{tab/@ edg/@} tac/tank} ^- wall
|
||||
(~(win re tac) tab edg)
|
||||
::
|
||||
:: This library includes `plume`, the actual pretty printing logic,
|
||||
:: and a handful of utilities for constructing plums.
|
||||
::
|
||||
:: Generally, you'll just use `plume` like this:
|
||||
::
|
||||
:: ~(plume tall plum) :: Pretty print `plum` in tall mode.
|
||||
:: ~(plume flat plum) :: Pretty print `plum` in wide mode.
|
||||
::
|
||||
:: There is probably no reason to look at the utility routines unless
|
||||
:: you are writing something to generate `plum`s.
|
||||
::
|
||||
:: This is the pretty-printer. Use the `flat` arm to render a plum
|
||||
:: into a single line and use the `tall` arm to get a nice multi-line
|
||||
:: rendering that switches to wide mode if there's enough space.
|
||||
::
|
||||
:: For details about how this works and what exactly it does in various
|
||||
:: cases, take a look at the docs for `plum`, `plumfmt`, and at the
|
||||
:: docs on the arms of this door.
|
||||
::
|
||||
++ plume
|
||||
|_ =plum
|
||||
::
|
||||
:: An line, indented by `indent` spaces.
|
||||
::
|
||||
+$ line [indent=@ud text=tape]
|
||||
::
|
||||
:: An sequence of indented lines.
|
||||
::
|
||||
+$ block (list line)
|
||||
::
|
||||
:: +flat: print as a single line
|
||||
::
|
||||
++ flat
|
||||
^- wain
|
||||
text:linear
|
||||
::
|
||||
:: +tall: print as multiple lines
|
||||
::
|
||||
++ tall
|
||||
^- wain
|
||||
%+ turn window
|
||||
|= line
|
||||
(crip (runt [indent ' '] text))
|
||||
::
|
||||
:: +adjust: adjust lines to right
|
||||
::
|
||||
++ adjust
|
||||
|= [tab=@ud =block] ^- ^block
|
||||
(turn block |=([@ud tape] [(add tab +<-) +<+]))
|
||||
::
|
||||
:: Prepend `n` spaces to a tape.
|
||||
::
|
||||
++ prepend-spaces
|
||||
|= [n=@ t=tape] ^- tape
|
||||
(runt [n ' '] t)
|
||||
::
|
||||
:: +window: print as list of tabbed lines
|
||||
::
|
||||
++ window
|
||||
^- block
|
||||
~+ :: for random access
|
||||
?@ plum [0 (trip plum)]~ :: trivial text
|
||||
?- -.plum
|
||||
::
|
||||
:: %para: Line-wrappable paragraph. This is a stub; it should
|
||||
:: wrap text to 40 characters.
|
||||
::
|
||||
%para
|
||||
[0 +:linear]~
|
||||
::
|
||||
:: %sbrk: nested subexpression
|
||||
::
|
||||
:: This is an opportunity to switch to wide mode. First, try
|
||||
:: rendered in wide mode. If that's possible and the result
|
||||
:: isn't too big, use that. Otherwise recurse into the subplum
|
||||
:: without switching to wide mode.
|
||||
::
|
||||
%sbrk
|
||||
=/ sub kid.plum
|
||||
?+ sub
|
||||
window(plum sub)
|
||||
[%tree *]
|
||||
=/ wideresult
|
||||
?~(wide.fmt.sub ~ [~ u=linear])
|
||||
?: ?&(?=(^ wideresult) (lte length.u.wideresult 40))
|
||||
[0 text.u.wideresult]~
|
||||
window(plum sub)
|
||||
==
|
||||
::
|
||||
:: %tree: Try to render a text tree in tall mode.
|
||||
::
|
||||
:: We want to render this in tall mode. First, verify that there
|
||||
:: the plum has a tall render (if not, fall back to `linear`
|
||||
:: formatting), then render all the subplums, and then render
|
||||
:: them in one of three ways:
|
||||
::
|
||||
:: - If the `plumfmt` contains an `indef` and that indef has
|
||||
:: no prefix, then this is a variable-arity rune with a
|
||||
:: terminator: Use vertical formatting.
|
||||
::
|
||||
:: - If the `plumfmt` contains an `indef` and that indef DOES have
|
||||
:: a prefix, then this is something that looks like a core: Use
|
||||
:: `core-like` formatting.
|
||||
::
|
||||
:: - Otherwise, this is a rune with a fixed number of arguments
|
||||
:: Render the subplums using backstep indentation.
|
||||
::
|
||||
:: There's also a special case where something has exactly one sub-plum.
|
||||
:: where something has exactly one sub-block. For example, we
|
||||
:: want this output:
|
||||
::
|
||||
:: |-
|
||||
:: foo
|
||||
::
|
||||
%tree
|
||||
?~ tall.fmt.plum [0 text:linear]~
|
||||
=/ prelude (trip intro.u.tall.fmt.plum)
|
||||
|^ =/ blocks (turn kids.plum |=(=^plum window(plum plum)))
|
||||
=/ prelude (trip intro.u.tall.fmt.plum)
|
||||
?~ indef.u.tall.fmt.plum
|
||||
?: =(1 (lent blocks))
|
||||
[[0 prelude] (zing blocks)]
|
||||
(backstep prelude blocks)
|
||||
=/ prefix (trip sigil.u.indef.u.tall.fmt.plum)
|
||||
=/ finale (trip final.u.indef.u.tall.fmt.plum)
|
||||
?~ blocks %+ weld
|
||||
?~(prelude ~ [0 prelude]~)
|
||||
?~(finale ~ [0 finale]~)
|
||||
?~ prefix (running prelude blocks finale)
|
||||
(core-like prelude prefix blocks finale)
|
||||
--
|
||||
==
|
||||
::
|
||||
:: Render a plum in tall-mode using backstep indentation. Here,
|
||||
:: we are rendering things that look something like this:
|
||||
::
|
||||
:: :+ foo
|
||||
:: bar
|
||||
:: baz
|
||||
::
|
||||
++ backstep
|
||||
|= [prelude=tape blocks=(list block)]
|
||||
^- block
|
||||
%- zing
|
||||
=/ nkids (lent blocks)
|
||||
=/ idx 1
|
||||
|- ^- (list block)
|
||||
?~ blocks ~
|
||||
:_ $(blocks t.blocks, idx +(idx))
|
||||
^- block
|
||||
=/ indent (mul 2 (sub nkids idx))
|
||||
?. =(1 idx) (adjust indent i.blocks)
|
||||
(rune-inline-with-block prelude indent i.blocks)
|
||||
::
|
||||
:: To make things look a bit nicer, we want to put the first
|
||||
:: sub-block on the same line as the rune. We want this:
|
||||
::
|
||||
:: :- foo
|
||||
:: baz
|
||||
::
|
||||
:: Instead of this:
|
||||
::
|
||||
:: :-
|
||||
:: foo
|
||||
:: baz
|
||||
::
|
||||
:: This handles the "foo" case.
|
||||
::
|
||||
++ rune-inline-with-block
|
||||
|= [rune=tape indent=@ blk=block]
|
||||
^- block
|
||||
=. indent (max indent (add 2 (lent rune)))
|
||||
=. blk (adjust indent blk)
|
||||
?~ rune blk
|
||||
?~ blk [0 rune]~
|
||||
:_ t.blk
|
||||
:- 0
|
||||
%+ weld rune
|
||||
=/ spaces-btwn (sub indent.i.blk (lent rune))
|
||||
(prepend-spaces spaces-btwn text.i.blk)
|
||||
::
|
||||
:: Render a tall hoon with running indentation. Here, we are
|
||||
:: rendering things that look sopmething like:
|
||||
::
|
||||
:: :~ foo
|
||||
:: bar
|
||||
:: baz
|
||||
:: ==
|
||||
::
|
||||
:: So, there's basically three cases here: Either the prelude
|
||||
:: is a rune, the prelude is empty, or prelude is some other
|
||||
:: random-ass thing.
|
||||
::
|
||||
:: - If there is no prelude, then just combine all of the
|
||||
:: sub-blocks together unaltered.
|
||||
:: - If it's a rune (two-characters wide), then combine the
|
||||
:: rune and the first line into one line (separated by two
|
||||
:: spaces) and indent the rest of the lines by four spaces.
|
||||
:: - If the rune is some other random-ass thing (has a length
|
||||
:: that isn't 0 or 2), then render the prelude alone on the
|
||||
:: first line and then combine the sub-blocks together,
|
||||
:: all indented by another two spaces.
|
||||
::
|
||||
:: Regardless, if there's a finale, stick it on the end without
|
||||
:: any indentation.
|
||||
::
|
||||
++ running
|
||||
|= [prelude=tape blocks=(list block) finale=tape]
|
||||
^- block
|
||||
=/ result=block (zing blocks)
|
||||
=. result
|
||||
?+ (lent prelude)
|
||||
[[0 prelude] (adjust 2 result)] :: unusual prelude
|
||||
%0 :: empty prelude
|
||||
result
|
||||
%2 :: rune prelude
|
||||
(rune-inline-with-block prelude 4 result)
|
||||
==
|
||||
?~ finale result
|
||||
(snoc result [0 finale])
|
||||
::
|
||||
:: This renders sub-blocks where each sub-block needs to be
|
||||
:: prefixed by some tape. For example:
|
||||
::
|
||||
:: |%
|
||||
:: ++ foo
|
||||
:: bar
|
||||
:: ++ baz
|
||||
:: qux
|
||||
:: --
|
||||
::
|
||||
++ core-like
|
||||
|= [prelude=tape prefix=tape blocks=(list block) finale=tape]
|
||||
^- block
|
||||
=/ clear (add 2 (lent prefix))
|
||||
=/ result
|
||||
^- block
|
||||
%- zing
|
||||
^- (list block)
|
||||
%+ turn blocks
|
||||
|= blk=block
|
||||
^- block
|
||||
^+ +<
|
||||
=* tab ?~(blk 0 (sub clear (min clear indent.i.blk)))
|
||||
=. blk (adjust tab blk)
|
||||
?~ blk ~
|
||||
:_ t.blk
|
||||
:- 0
|
||||
%+ weld prefix
|
||||
(runt [(sub indent.i.blk (lent prefix)) ' '] text.i.blk)
|
||||
=. result
|
||||
?~ finale result
|
||||
(snoc result [0 finale])
|
||||
?~ prelude result
|
||||
[[0 prelude] result]
|
||||
::
|
||||
:: +linear: Render a plum onto a single line, even if it only has a
|
||||
:: wide form.
|
||||
::
|
||||
++ linear
|
||||
^- [length=@ud text=tape]
|
||||
~+ :: ~+ for random access
|
||||
?@ plum [(met 3 plum) (trip plum)] :: Just a cord.
|
||||
?- -.plum
|
||||
::
|
||||
:: This is already in wide mode, so %sbrk nodes don't matter here.
|
||||
::
|
||||
%sbrk
|
||||
linear(plum kid.plum)
|
||||
::
|
||||
:: %para: To write a wrappable text paragraph to a single line,
|
||||
:: we just combine all the lines into one, interspersing single
|
||||
:: spaces chars.
|
||||
::
|
||||
%para
|
||||
|- ^- [length=@ud text=tape]
|
||||
?~ lines.plum [0 ~]
|
||||
=/ next $(lines.plum t.lines.plum)
|
||||
=/ this [length=(met 3 i.lines.plum) text=(trip i.lines.plum)]
|
||||
:- (add +(length.this) length.next)
|
||||
(weld text.this `tape`[' ' text.next])
|
||||
::
|
||||
:: Render a text tree to a single line.
|
||||
::
|
||||
%tree
|
||||
|^ ^- [length=@ud text=tape]
|
||||
?~ wide.fmt.plum (force-wide window)
|
||||
=/ body (render-body delimit.u.wide.fmt.plum kids.plum)
|
||||
?~ enclose.u.wide.fmt.plum body
|
||||
(wrap-with-enclose u.enclose.u.wide.fmt.plum body)
|
||||
::
|
||||
:: Given a list of subplums and a delimiter, render all the
|
||||
:: subplums onto a single line, and combine them into a single
|
||||
:: string by interspersing the delimiter.
|
||||
::
|
||||
++ render-body
|
||||
|= [delimit=cord kids=(list ^plum)]
|
||||
=/ stop (trip delimit)
|
||||
|- ^- [length=@ud text=tape]
|
||||
?~ kids [0 ~]
|
||||
=/ next $(kids t.kids)
|
||||
=/ this linear(plum i.kids)
|
||||
?~ text.next this
|
||||
:- :(add length.this (lent stop) length.next)
|
||||
:(weld text.this stop text.next)
|
||||
::
|
||||
:: Wrap a wide-form-rendered result with the `enclose` cords
|
||||
:: from its `plumefmt`.
|
||||
::
|
||||
++ wrap-with-enclose
|
||||
|= [clamps=(pair cord cord) body=[length=@ text=tape]]
|
||||
^- [length=@ud text=tape]
|
||||
::
|
||||
=/ close [(trip -.clamps) (trip +.clamps)]
|
||||
:- :(add length.body (lent -.close) (lent +.close))
|
||||
:(weld -.close text.body +.close)
|
||||
::
|
||||
:: Given the result of rendering a plum in tall form, combine
|
||||
:: all the lines into one by separating each by two spaces.
|
||||
::
|
||||
++ force-wide
|
||||
|= render=(list [@ud text=tape])
|
||||
^- [length=@ud text=tape]
|
||||
::
|
||||
?~ render [0 ~]
|
||||
=/ next (force-wide t.render)
|
||||
:- :(add (lent text.i.render) 2 length.next)
|
||||
?~(text.next text.i.render :(weld text.i.render " " text.next))
|
||||
--
|
||||
==
|
||||
--
|
||||
::
|
||||
:: Convenience function to build a `plumfmt` for a rune with a fixed
|
||||
:: number of parameters.
|
||||
::
|
||||
++ fixed
|
||||
|= rune=@ta
|
||||
^- plumfmt
|
||||
[wide=`[' ' `[(cat 3 +< '(') ')']] tall=`[+< ~]]
|
||||
::
|
||||
:: Same as `fixed` but only outputs in `tall` mode.
|
||||
::
|
||||
++ tall-fixed
|
||||
|= rune=cord
|
||||
^- (unit [cord (unit [cord cord])])
|
||||
`[rune ~]
|
||||
::
|
||||
:: Convenience function to build a the `tall` part of a `plumfmt` for
|
||||
:: a running-style rune (one that takes a variable number of parameters
|
||||
:: and has a terminator).
|
||||
::
|
||||
++ tall-running
|
||||
|= [rune=cord sigil=cord term=cord]
|
||||
^- (unit [cord (unit [cord cord])])
|
||||
`[rune `[sigil term]]
|
||||
::
|
||||
:: Convenience function for rendering a rune into a plum. This takes
|
||||
:: a rune, an optional tall-form terminator, optionally a short-form (if
|
||||
:: you don't supply a short-form, it'll just construct the standard
|
||||
:: wide-form (e.g. "?~(x x ~)") for you, and a list of sub-plums.
|
||||
::
|
||||
++ rune
|
||||
|= $: rune=cord
|
||||
term=(unit cord)
|
||||
short=(unit [cord cord cord])
|
||||
kids=(list plum)
|
||||
==
|
||||
^. plum
|
||||
|^ :- %sbrk
|
||||
:+ %tree
|
||||
:- (rune-wide-form rune short)
|
||||
?~ term (tall-fixed rune)
|
||||
(tall-running rune '' u.term)
|
||||
kids
|
||||
::
|
||||
:: If you just give this a rune, it'll build the standard wide-form.
|
||||
:: Otherwise, it'll just use the one that you gave it.
|
||||
::
|
||||
++ rune-wide-form
|
||||
|= [rune=cord short=(unit [fst=cord mid=cord lst=cord])]
|
||||
^- (unit (pair cord (unit [cord cord])))
|
||||
=* fst (cat 3 rune '(')
|
||||
=* std `[' ' `[fst ')']]
|
||||
?~ short std
|
||||
`[mid.u.short `[fst.u.short lst.u.short]]
|
||||
--
|
||||
::
|
||||
:: Just a helper function for constructing a wide-form %tree plum.
|
||||
::
|
||||
++ simple-wide
|
||||
|= [init=cord sep=cord end=cord kids=(list plum)]
|
||||
^- plum
|
||||
=/ fmt=plumfmt [wide=[~ sep [~ init end]] tall=~]
|
||||
[%tree fmt kids]
|
||||
::
|
||||
:: Convenience function that builds a plum for a subexpression. The
|
||||
:: `%sbrk` tells the pretty-printer that this is a valid place to
|
||||
:: switch from tall mode to wide mode.
|
||||
::
|
||||
++ subtree
|
||||
|= [p=plumfmt q=(list plum)]
|
||||
^- plum
|
||||
[%sbrk [%tree p q]]
|
||||
::
|
||||
:: Convenience for generating plums that look like s-expressions. Useful
|
||||
:: for quickly getting decent-looking debug output.
|
||||
::
|
||||
++ sexp
|
||||
|= [sym=cord kids=(list plum)]
|
||||
^- plum
|
||||
=/ head=cord (cat 3 '(' sym)
|
||||
=/ headspc=cord (cat 3 head ' ')
|
||||
=/ symcol=cord (cat 3 sym ':')
|
||||
=/ fmt=plumfmt [[~ ' ' [~ headspc ')']] [~ symcol [~ '' '']]]
|
||||
?~ kids (cat 3 '(' (cat 3 sym ')'))
|
||||
[%sbrk [%tree fmt kids]]
|
||||
::
|
||||
:: |re: tank renderer
|
||||
::
|
||||
++ re
|
||||
|
Loading…
Reference in New Issue
Block a user