65 type text = {tx: string, nl: int, pos: int}; |
65 type text = {tx: string, nl: int, pos: int}; |
66 |
66 |
67 val emptytext = {tx="", nl=0, pos=0}; |
67 val emptytext = {tx="", nl=0, pos=0}; |
68 |
68 |
69 fun blanks wd {tx,nl,pos} = |
69 fun blanks wd {tx,nl,pos} = |
70 {tx = tx ^ repstring" "wd, |
70 {tx = tx ^ repstring " " wd, |
71 nl = nl, |
71 nl = nl, |
72 pos = pos+wd}; |
72 pos = pos+wd}; |
73 |
73 |
74 fun newline {tx,nl,pos} = |
74 fun newline {tx,nl,pos} = |
75 {tx = tx ^ "\n", |
75 {tx = tx ^ "\n", |
90 fun setmargin m = |
90 fun setmargin m = |
91 (margin := m; |
91 (margin := m; |
92 breakgain := !margin div 20; |
92 breakgain := !margin div 20; |
93 emergencypos := !margin div 2); |
93 emergencypos := !margin div 2); |
94 |
94 |
|
95 (*Search for the next break (at this or higher levels) and force it to occur*) |
95 fun forcenext [] = [] |
96 fun forcenext [] = [] |
96 | forcenext (Break(_,wd) :: es) = Break(true,0) :: es |
97 | forcenext (Break(_,wd) :: es) = Break(true,0) :: es |
97 | forcenext (e :: es) = e :: forcenext es; |
98 | forcenext (e :: es) = e :: forcenext es; |
98 |
99 |
|
100 (*es is list of expressions to print; |
|
101 blockin is the indentation of the current block; |
|
102 after is the width of the following context until next break. *) |
99 fun format ([], _, _) text = text |
103 fun format ([], _, _) text = text |
100 | format (e::es, blockin, after) (text as {pos,nl,...}) = |
104 | format (e::es, blockin, after) (text as {pos,nl,...}) = |
101 (case e of |
105 (case e of |
102 Block(bes,indent,wd) => |
106 Block(bes,indent,wd) => |
103 let val blockin' = (pos + indent) mod !emergencypos |
107 let val blockin' = (pos + indent) mod !emergencypos |
104 val btext = format(bes, blockin', breakdist(es,after)) text |
108 val btext = format(bes, blockin', breakdist(es,after)) text |
105 val es2 = if nl < #nl(btext) then forcenext es |
109 (*If this block was broken then force the next break.*) |
106 else es |
110 val es2 = if nl < #nl(btext) then forcenext es else es |
107 in format (es2,blockin,after) btext end |
111 in format (es2,blockin,after) btext end |
108 | String s => format (es,blockin,after) (string s text) |
112 | String s => format (es,blockin,after) (string s text) |
109 | Break(force,wd) => (* no break if text fits on this line |
113 | Break(force,wd) => (*no break if text to next break fits on this line |
110 or if breaking would add only breakgain to space *) |
114 or if breaking would add only breakgain to space *) |
111 format (es,blockin,after) |
115 format (es,blockin,after) |
112 (if not force andalso |
116 (if not force andalso |
113 pos+wd <= max[!margin - breakdist(es,after), |
117 pos+wd <= max[!margin - breakdist(es,after), |
114 blockin + !breakgain] |
118 blockin + !breakgain] |
115 then blanks wd text |
119 then blanks wd text (*just insert wd blanks*) |
116 else blanks blockin (newline text))); |
120 else blanks blockin (newline text))); |
117 |
121 |
118 (*** Exported functions to create formatting expressions ***) |
122 (*** Exported functions to create formatting expressions ***) |
119 |
123 |
120 fun length (Block(_,_,len)) = len |
124 fun length (Block(_,_,len)) = len |
129 fun blk (indent,es) = |
133 fun blk (indent,es) = |
130 let fun sum([], k) = k |
134 let fun sum([], k) = k |
131 | sum(e::es, k) = sum(es, length e + k) |
135 | sum(e::es, k) = sum(es, length e + k) |
132 in Block(es,indent, sum(es,0)) end; |
136 in Block(es,indent, sum(es,0)) end; |
133 |
137 |
|
138 (*Join the elements of es as a comma-separated list, bracketted by lp and rp*) |
134 fun lst(lp,rp) es = |
139 fun lst(lp,rp) es = |
135 let fun add(e,es) = str"," :: brk 1 :: e :: es; |
140 let fun add(e,es) = str"," :: brk 1 :: e :: es; |
136 fun list(e :: (es as _::_)) = str lp :: e :: foldr add (es,[str rp]) |
141 fun list(e :: (es as _::_)) = str lp :: e :: foldr add (es,[str rp]) |
137 | list(e::[]) = [str lp, e, str rp] |
142 | list(e::[]) = [str lp, e, str rp] |
138 | list([]) = [] |
143 | list([]) = [] |
139 in blk(size lp, list es) end; |
144 in blk(size lp, list es) end; |
140 |
145 |
|
146 (*Put quotation marks around the given expression*) |
141 fun quote prt = blk (1, [str "\"", prt, str "\""]); |
147 fun quote prt = blk (1, [str "\"", prt, str "\""]); |
142 |
148 |
143 |
149 |
144 (*** Pretty printing with depth limitation ***) |
150 (*** Pretty printing with depth limitation ***) |
145 |
151 |
146 val depth = ref 0; (*maximum depth; 0 means no limit*) |
152 val depth = ref 0; (*maximum depth; 0 means no limit*) |
147 |
153 |
148 fun setdepth dp = (depth := dp); |
154 fun setdepth dp = (depth := dp); |
149 |
155 |
150 |
156 (*Recursively prune blocks, discarding all text exceeding depth dp*) |
151 fun pruning dp (Block(bes,indent,wd)) = |
157 fun pruning dp (Block(bes,indent,wd)) = |
152 if dp>0 then blk(indent, map (pruning(dp-1)) bes) |
158 if dp>0 then blk(indent, map (pruning(dp-1)) bes) |
153 else String"..." |
159 else String"..." |
154 | pruning dp e = e; |
160 | pruning dp e = e; |
155 |
161 |
156 fun prune dp e = if dp>0 then pruning dp e else e; |
162 fun prune dp e = if dp>0 then pruning dp e else e; |
157 |
163 |
158 |
164 |
159 fun string_of e = #tx (format ([prune (!depth) e],0,0) emptytext); |
165 fun string_of e = #tx (format ([prune (!depth) e], 0, 0) emptytext); |
160 |
166 |
161 |
167 |
|
168 (*Create a single flat string: no line breaking*) |
162 fun str_of prt = |
169 fun str_of prt = |
163 let |
170 let |
164 fun s_of (Block (prts, _, _)) = implode (map s_of prts) |
171 fun s_of (Block (prts, _, _)) = implode (map s_of prts) |
165 | s_of (String s) = s |
172 | s_of (String s) = s |
166 | s_of (Break (false, wd)) = repstring " " wd |
173 | s_of (Break (false, wd)) = repstring " " wd |
167 | s_of (Break (true, _)) = " "; |
174 | s_of (Break (true, _)) = " "; |
168 in |
175 in |
169 s_of (prune (! depth) prt) |
176 s_of (prune (! depth) prt) |
170 end; |
177 end; |
171 |
178 |
172 |
179 (*Part of the interface to the Poly/ML and New Jersey ML pretty printers*) |
173 fun pprint prt (put_str, begin_blk, put_brk, put_fbrk, end_blk) = |
180 fun pprint prt (put_str, begin_blk, put_brk, put_fbrk, end_blk) = |
174 let |
181 let |
175 fun pp (Block (prts, ind, _)) = (begin_blk ind; pp_lst prts; end_blk ()) |
182 fun pp (Block (prts, ind, _)) = (begin_blk ind; pp_lst prts; end_blk ()) |
176 | pp (String s) = put_str s |
183 | pp (String s) = put_str s |
177 | pp (Break (false, wd)) = put_brk wd |
184 | pp (Break (false, wd)) = put_brk wd |