1 ! Copyright (C) 2003, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays generic hashtables io kernel math assocs
4 namespaces make sequences strings io.styles vectors words
5 prettyprint.config splitting classes continuations
7 IN: prettyprint.sections
11 SYMBOL: recursion-check
12 SYMBOL: pprinter-stack
14 ! We record vocabs of all words
18 TUPLE: pprinter last-newline line-count indent ;
20 : <pprinter> ( -- pprinter ) 0 1 0 pprinter boa ;
22 : record-vocab ( word -- )
23 vocabulary>> [ pprinter-use get conjoin ] when* ;
26 : line-limit? ( -- ? )
27 line-limit get dup [ pprinter get line-count>> <= ] when ;
29 : do-indent ( -- ) pprinter get indent>> CHAR: \s <string> write ;
32 dup pprinter get last-newline>> = [
35 pprinter get (>>last-newline)
37 "..." write pprinter get return
39 pprinter get [ 1+ ] change-line-count drop
43 : text-fits? ( len -- ? )
45 [ 2drop t ] [ [ pprinter get indent>> + ] dip <= ] if ;
47 ! break only if position margin 2 / >
54 GENERIC: section-fits? ( section -- ? )
56 GENERIC: short-section ( section -- )
58 GENERIC: long-section ( section -- )
60 GENERIC: indent-section? ( section -- ? )
62 GENERIC: unindent-first-line? ( section -- ? )
64 GENERIC: newline-after? ( section -- ? )
66 GENERIC: short-section? ( section -- ? )
71 start-group? end-group?
74 : new-section ( length class -- section )
77 swap position [ + ] change
81 M: section section-fits? ( section -- ? )
82 [ end>> pprinter get last-newline>> - ]
86 M: section indent-section? drop f ;
88 M: section unindent-first-line? drop f ;
90 M: section newline-after? drop f ;
92 M: object short-section? section-fits? ;
94 : indent+ ( section n -- )
95 swap indent-section? [
96 pprinter get [ + ] change-indent drop
99 : <indent ( section -- ) tab-size get indent+ ;
101 : indent> ( section -- ) tab-size get neg indent+ ;
103 : <fresh-line ( section -- )
106 : fresh-line> ( section -- )
107 dup newline-after? [ end>> fresh-line ] [ drop ] if ;
109 : <long-section ( section -- )
110 dup unindent-first-line?
111 [ dup <fresh-line <indent ] [ dup <indent <fresh-line ] if ;
113 : long-section> ( section -- )
114 dup indent> fresh-line> ;
116 : pprint-section ( section -- )
118 dup style>> [ short-section ] with-style
121 [ dup style>> [ long-section ] with-style ]
127 TUPLE: line-break < section type ;
129 : <line-break> ( type -- section )
130 0 \ line-break new-section
133 M: line-break short-section drop ;
135 M: line-break long-section drop ;
138 TUPLE: block < section sections ;
140 : new-block ( style class -- block )
142 V{ } clone >>sections
143 swap >>style ; inline
145 : <block> ( style -- block )
148 : pprinter-block ( -- block ) pprinter-stack get peek ;
150 : add-section ( section -- )
151 pprinter-block sections>> push ;
153 : last-section ( -- section )
154 pprinter-block sections>>
155 [ line-break? not ] find-last nip ;
158 last-section t >>start-group? drop ;
161 last-section t >>end-group? drop ;
163 : advance ( section -- )
164 [ start>> pprinter get last-newline>> = not ]
165 [ short-section? ] bi
168 : line-break ( type -- ) [ <line-break> add-section ] when* ;
170 M: block section-fits? ( section -- ? )
171 line-limit? [ drop t ] [ call-next-method ] if ;
173 : pprint-sections ( block advancer -- )
175 sections>> [ line-break? not ] filter
176 unclip-slice pprint-section
178 [ [ pprint-section ] bi ] curry each ; inline
180 M: block short-section ( block -- )
181 [ advance ] pprint-sections ;
183 : do-break ( break -- )
186 [ end>> pprinter get last-newline>> - margin get 2/ > ] tri
187 or [ <fresh-line ] [ drop ] if ;
189 : empty-block? ( block -- ? ) sections>> empty? ;
191 : if-nonempty ( block quot -- )
192 [ dup empty-block? [ drop ] ] dip if ; inline
194 : (<block) ( block -- ) pprinter-stack get push ;
196 : <block ( -- ) f <block> (<block) ;
198 : <object ( obj -- ) presented associate <block> (<block) ;
201 TUPLE: text < section string ;
203 : <text> ( string style -- text )
204 over length 1+ \ text new-section
208 M: text short-section string>> write ;
210 M: text long-section short-section ;
212 : styled-text ( string style -- ) <text> add-section ;
214 : text ( string -- ) H{ } styled-text ;
217 TUPLE: inset < block narrow? ;
219 : <inset> ( narrow? -- block )
224 M: inset long-section
226 [ <fresh-line ] pprint-sections
231 M: inset indent-section? drop t ;
233 M: inset newline-after? drop t ;
235 : <inset ( narrow? -- ) <inset> (<block) ;
238 TUPLE: flow < block ;
240 : <flow> ( -- block )
241 H{ } flow new-block ;
243 M: flow short-section? ( section -- ? )
244 #! If we can make room for this entire block by inserting
245 #! a newline, do it; otherwise, don't bother, print it as
248 [ [ end>> ] [ start>> ] bi - text-fits? not ] bi
251 : <flow ( -- ) <flow> (<block) ;
253 ! Colon definition section
254 TUPLE: colon < block ;
256 : <colon> ( -- block )
257 H{ } colon new-block ;
259 M: colon long-section short-section ;
261 M: colon indent-section? drop t ;
263 M: colon unindent-first-line? drop t ;
265 : <colon ( -- ) <colon> (<block) ;
267 : save-end-position ( block -- )
268 position get >>end drop ;
271 pprinter-stack get pop
272 [ [ save-end-position ] [ add-section ] bi ] if-nonempty ;
274 : do-pprint ( block -- )
275 <pprinter> pprinter [
285 ! Long section layout algorithm
286 : chop-break ( seq -- seq )
287 dup peek line-break? [ but-last-slice chop-break ] when ;
292 : split-groups ( ? -- ) [ t , ] when ;
294 : split-before ( section -- )
295 [ start-group?>> prev get [ end-group?>> ] [ t ] if* and ]
296 [ flow? prev get flow? not and ]
299 : split-after ( section -- )
300 [ end-group?>> ] [ f ] if* split-groups ;
302 : group-flow ( seq -- newseq )
305 2dup 1- swap ?nth prev set
306 2dup 1+ swap ?nth next set
307 swap nth dup split-before dup , split-after
309 ] { } make { t } split harvest ;
311 : break-group? ( seq -- ? )
312 [ first section-fits? ] [ peek section-fits? not ] bi and ;
314 : ?break-group ( seq -- )
315 dup break-group? [ first <fresh-line ] [ drop ] if ;
317 M: block long-section ( block -- )
319 sections>> chop-break group-flow [
324 [ advance ] [ pprint-section ] bi