factor/basis/prettyprint/sections/sections.factor

329 lines
7.5 KiB
Factor
Raw Normal View History

2008-04-04 05:33:35 -04:00
! Copyright (C) 2003, 2008 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
2008-04-20 06:15:46 -04:00
USING: arrays generic hashtables io kernel math assocs
namespaces make sequences strings io.styles vectors words
2007-09-20 18:09:08 -04:00
prettyprint.config splitting classes continuations
2008-06-11 03:58:38 -04:00
io.streams.nested accessors sets ;
2007-09-20 18:09:08 -04:00
IN: prettyprint.sections
! State
SYMBOL: position
SYMBOL: recursion-check
SYMBOL: pprinter-stack
! We record vocabs of all words
SYMBOL: pprinter-in
SYMBOL: pprinter-use
2008-05-07 08:49:29 -04:00
TUPLE: pprinter last-newline line-count indent ;
2008-05-07 08:49:29 -04:00
: <pprinter> ( -- pprinter ) 0 1 0 pprinter boa ;
2007-09-20 18:09:08 -04:00
: record-vocab ( word -- )
vocabulary>> [ pprinter-use get conjoin ] when* ;
2007-09-20 18:09:08 -04:00
! Utility words
: line-limit? ( -- ? )
line-limit get dup [ pprinter get line-count>> <= ] when ;
2007-09-20 18:09:08 -04:00
: do-indent ( -- ) pprinter get indent>> CHAR: \s <string> write ;
2007-09-20 18:09:08 -04:00
: fresh-line ( n -- )
dup pprinter get last-newline>> = [
2007-09-20 18:09:08 -04:00
drop
] [
pprinter get (>>last-newline)
line-limit? [
2008-05-07 08:49:29 -04:00
"..." write pprinter get return
] when
pprinter get [ 1+ ] change-line-count drop
2007-09-20 18:09:08 -04:00
nl do-indent
] if ;
: text-fits? ( len -- ? )
margin get dup zero?
2008-12-03 09:46:16 -05:00
[ 2drop t ] [ [ pprinter get indent>> + ] dip <= ] if ;
2007-09-20 18:09:08 -04:00
! break only if position margin 2 / >
SYMBOL: soft
! always breaks
SYMBOL: hard
! Section protocol
GENERIC: section-fits? ( section -- ? )
GENERIC: short-section ( section -- )
GENERIC: long-section ( section -- )
GENERIC: indent-section? ( section -- ? )
GENERIC: unindent-first-line? ( section -- ? )
GENERIC: newline-after? ( section -- ? )
GENERIC: short-section? ( section -- ? )
! Sections
TUPLE: section
start end
start-group? end-group?
style overhang ;
: new-section ( length class -- section )
new
2008-04-04 05:33:35 -04:00
position get >>start
swap position [ + ] change
position get >>end
0 >>overhang ; inline
2007-09-20 18:09:08 -04:00
M: section section-fits? ( section -- ? )
[ end>> pprinter get last-newline>> - ]
[ overhang>> ] bi
+ text-fits? ;
2007-09-20 18:09:08 -04:00
M: section indent-section? drop f ;
M: section unindent-first-line? drop f ;
M: section newline-after? drop f ;
M: object short-section? section-fits? ;
: indent+ ( section n -- )
swap indent-section? [
pprinter get [ + ] change-indent drop
] [ drop ] if ;
2007-09-20 18:09:08 -04:00
: <indent ( section -- ) tab-size get indent+ ;
2007-09-20 18:09:08 -04:00
: indent> ( section -- ) tab-size get neg indent+ ;
2007-09-20 18:09:08 -04:00
: <fresh-line ( section -- )
2008-04-04 05:33:35 -04:00
start>> fresh-line ;
2007-09-20 18:09:08 -04:00
: fresh-line> ( section -- )
2008-04-04 05:33:35 -04:00
dup newline-after? [ end>> fresh-line ] [ drop ] if ;
2007-09-20 18:09:08 -04:00
: <long-section ( section -- )
dup unindent-first-line?
[ dup <fresh-line <indent ] [ dup <indent <fresh-line ] if ;
: long-section> ( section -- )
dup indent> fresh-line> ;
: pprint-section ( section -- )
dup short-section? [
2008-08-30 22:55:29 -04:00
dup style>> [ short-section ] with-style
2007-09-20 18:09:08 -04:00
] [
[ <long-section ]
2008-08-30 22:55:29 -04:00
[ dup style>> [ long-section ] with-style ]
[ long-section> ]
tri
2007-09-20 18:09:08 -04:00
] if ;
! Break section
2008-04-04 05:33:35 -04:00
TUPLE: line-break < section type ;
2007-09-20 18:09:08 -04:00
: <line-break> ( type -- section )
0 \ line-break new-section
2008-04-04 05:33:35 -04:00
swap >>type ;
2007-09-20 18:09:08 -04:00
M: line-break short-section drop ;
2007-09-20 18:09:08 -04:00
M: line-break long-section drop ;
2007-09-20 18:09:08 -04:00
! Block sections
2008-04-04 05:33:35 -04:00
TUPLE: block < section sections ;
2007-09-20 18:09:08 -04:00
: new-block ( style class -- block )
0 swap new-section
2008-04-04 05:33:35 -04:00
V{ } clone >>sections
swap >>style ; inline
2007-09-20 18:09:08 -04:00
2008-04-04 05:33:35 -04:00
: <block> ( style -- block )
block new-block ;
2007-09-20 18:09:08 -04:00
: pprinter-block ( -- block ) pprinter-stack get peek ;
: add-section ( section -- )
2008-04-04 05:33:35 -04:00
pprinter-block sections>> push ;
2007-09-20 18:09:08 -04:00
: last-section ( -- section )
2008-04-04 05:33:35 -04:00
pprinter-block sections>>
[ line-break? not ] find-last nip ;
2007-09-20 18:09:08 -04:00
: start-group ( -- )
2008-04-04 05:33:35 -04:00
last-section t >>start-group? drop ;
2007-09-20 18:09:08 -04:00
: end-group ( -- )
2008-04-04 05:33:35 -04:00
last-section t >>end-group? drop ;
2007-09-20 18:09:08 -04:00
: advance ( section -- )
[ start>> pprinter get last-newline>> = not ]
2008-04-04 05:33:35 -04:00
[ short-section? ] bi
and [ bl ] when ;
2007-09-20 18:09:08 -04:00
: line-break ( type -- ) [ <line-break> add-section ] when* ;
2007-09-20 18:09:08 -04:00
M: block section-fits? ( section -- ? )
2008-04-04 05:33:35 -04:00
line-limit? [ drop t ] [ call-next-method ] if ;
2007-09-20 18:09:08 -04:00
: pprint-sections ( block advancer -- )
2008-08-15 05:09:34 -04:00
[
sections>> [ line-break? not ] filter
unclip-slice pprint-section
] dip
[ [ pprint-section ] bi ] curry each ; inline
2007-09-20 18:09:08 -04:00
M: block short-section ( block -- )
[ advance ] pprint-sections ;
: do-break ( break -- )
[ ]
[ type>> hard eq? ]
[ end>> pprinter get last-newline>> - margin get 2/ > ] tri
or [ <fresh-line ] [ drop ] if ;
2007-09-20 18:09:08 -04:00
2008-04-04 05:33:35 -04:00
: empty-block? ( block -- ? ) sections>> empty? ;
2007-09-20 18:09:08 -04:00
: if-nonempty ( block quot -- )
2008-12-03 09:46:16 -05:00
[ dup empty-block? [ drop ] ] dip if ; inline
2007-09-20 18:09:08 -04:00
2008-06-08 16:32:55 -04:00
: (<block) ( block -- ) pprinter-stack get push ;
2007-09-20 18:09:08 -04:00
2008-06-08 16:32:55 -04:00
: <block ( -- ) f <block> (<block) ;
2007-09-20 18:09:08 -04:00
: <object ( obj -- ) presented associate <block> (<block) ;
! Text section
2008-04-04 05:33:35 -04:00
TUPLE: text < section string ;
2007-09-20 18:09:08 -04:00
: <text> ( string style -- text )
over length 1+ \ text new-section
2008-04-04 05:33:35 -04:00
swap >>style
swap >>string ;
2007-09-20 18:09:08 -04:00
M: text short-section string>> write ;
2007-09-20 18:09:08 -04:00
M: text long-section short-section ;
: styled-text ( string style -- ) <text> add-section ;
: text ( string -- ) H{ } styled-text ;
! Inset section
2008-04-04 05:33:35 -04:00
TUPLE: inset < block narrow? ;
2007-09-20 18:09:08 -04:00
: <inset> ( narrow? -- block )
H{ } inset new-block
2008-04-04 05:33:35 -04:00
2 >>overhang
swap >>narrow? ;
2007-09-20 18:09:08 -04:00
M: inset long-section
2008-04-04 05:33:35 -04:00
dup narrow?>> [
2007-09-20 18:09:08 -04:00
[ <fresh-line ] pprint-sections
] [
2008-04-04 05:33:35 -04:00
call-next-method
2007-09-20 18:09:08 -04:00
] if ;
M: inset indent-section? drop t ;
M: inset newline-after? drop t ;
: <inset ( narrow? -- ) <inset> (<block) ;
! Flow section
2008-04-04 05:33:35 -04:00
TUPLE: flow < block ;
2007-09-20 18:09:08 -04:00
: <flow> ( -- block )
H{ } flow new-block ;
2007-09-20 18:09:08 -04:00
M: flow short-section? ( section -- ? )
#! If we can make room for this entire block by inserting
#! a newline, do it; otherwise, don't bother, print it as
#! a short section
2008-04-04 05:33:35 -04:00
[ section-fits? ]
[ [ end>> ] [ start>> ] bi - text-fits? not ] bi
or ;
2007-09-20 18:09:08 -04:00
: <flow ( -- ) <flow> (<block) ;
! Colon definition section
2008-04-04 05:33:35 -04:00
TUPLE: colon < block ;
2007-09-20 18:09:08 -04:00
: <colon> ( -- block )
H{ } colon new-block ;
2007-09-20 18:09:08 -04:00
M: colon long-section short-section ;
M: colon indent-section? drop t ;
M: colon unindent-first-line? drop t ;
: <colon ( -- ) <colon> (<block) ;
: save-end-position ( block -- )
2008-04-04 05:33:35 -04:00
position get >>end drop ;
2007-09-20 18:09:08 -04:00
: block> ( -- )
pprinter-stack get pop
2008-04-04 05:33:35 -04:00
[ [ save-end-position ] [ add-section ] bi ] if-nonempty ;
2007-09-20 18:09:08 -04:00
: do-pprint ( block -- )
<pprinter> pprinter [
2007-09-20 18:09:08 -04:00
[
2008-04-04 05:33:35 -04:00
dup style>> [
[
short-section
2008-05-07 08:49:29 -04:00
] curry with-return
] with-nesting
2007-09-20 18:09:08 -04:00
] if-nonempty
] with-variable ;
2007-09-20 18:09:08 -04:00
! Long section layout algorithm
: chop-break ( seq -- seq )
2008-05-07 02:38:34 -04:00
dup peek line-break? [ but-last-slice chop-break ] when ;
2007-09-20 18:09:08 -04:00
SYMBOL: prev
SYMBOL: next
2008-06-08 16:32:55 -04:00
: split-groups ( ? -- ) [ t , ] when ;
2007-09-20 18:09:08 -04:00
: split-before ( section -- )
[ start-group?>> prev get [ end-group?>> ] [ t ] if* and ]
2008-04-04 05:33:35 -04:00
[ flow? prev get flow? not and ]
bi or split-groups ;
2007-09-20 18:09:08 -04:00
: split-after ( section -- )
[ end-group?>> ] [ f ] if* split-groups ;
2007-09-20 18:09:08 -04:00
: group-flow ( seq -- newseq )
[
dup length [
2dup 1- swap ?nth prev set
2dup 1+ swap ?nth next set
swap nth dup split-before dup , split-after
2008-01-09 17:36:30 -05:00
] with each
2008-05-14 00:36:55 -04:00
] { } make { t } split harvest ;
2007-09-20 18:09:08 -04:00
: break-group? ( seq -- ? )
2008-04-04 05:33:35 -04:00
[ first section-fits? ] [ peek section-fits? not ] bi and ;
2007-09-20 18:09:08 -04:00
: ?break-group ( seq -- )
dup break-group? [ first <fresh-line ] [ drop ] if ;
M: block long-section ( block -- )
[
2008-04-04 05:33:35 -04:00
sections>> chop-break group-flow [
2007-09-20 18:09:08 -04:00
dup ?break-group [
dup line-break? [
2007-09-20 18:09:08 -04:00
do-break
] [
2008-04-04 05:33:35 -04:00
[ advance ] [ pprint-section ] bi
2007-09-20 18:09:08 -04:00
] if
] each
] each
] if-nonempty ;