333 |
333 |
334 (* formatted output *) |
334 (* formatted output *) |
335 |
335 |
336 local |
336 local |
337 |
337 |
338 type text = {markups: Markup.output list, tx: Bytes.T, ind: Buffer.T, pos: int, nl: int}; |
338 type context = Markup.output list; (*stack of pending markup*) |
339 |
339 |
340 val empty: text = |
340 abstype state = State of context * Bytes.T |
341 {markups = [], |
341 with |
342 tx = Bytes.empty, |
342 |
343 ind = Buffer.empty, |
343 fun state_output (State (_, output)) = output; |
344 pos = 0, |
344 |
345 nl = 0}; |
345 val empty_state = State ([], Bytes.empty); |
346 |
346 |
347 fun string (s, len) {markups, tx, ind, pos: int, nl} : text = |
347 fun add_state s (State (context, output)) = |
348 {markups = markups, |
348 State (context, Bytes.add s output); |
349 tx = Bytes.add s tx, |
349 |
350 ind = Buffer.add s ind, |
350 fun push_state (markup as (bg, _)) (State (context, output)) = |
|
351 State (markup :: context, Bytes.add bg output); |
|
352 |
|
353 fun pop_state (State ((_, en) :: context, output)) = |
|
354 State (context, Bytes.add en output); |
|
355 |
|
356 end; |
|
357 |
|
358 type text = {main: state, line: state, pos: int, nl: int}; |
|
359 |
|
360 val empty: text = {main = empty_state, line = empty_state, pos = 0, nl = 0}; |
|
361 |
|
362 fun string (s, len) {main, line, pos, nl} : text = |
|
363 {main = add_state s main, |
|
364 line = add_state s line, |
351 pos = pos + len, |
365 pos = pos + len, |
352 nl = nl}; |
366 nl = nl}; |
353 |
367 |
354 fun push (markup as (bg, _)) {markups, tx, ind, pos: int, nl} : text = |
368 fun push m {main, line, pos, nl} : text = |
355 {markups = markup :: markups, |
369 {main = push_state m main, |
356 tx = Bytes.add bg tx, |
370 line = line, |
357 ind = ind, |
|
358 pos = pos, |
371 pos = pos, |
359 nl = nl}; |
372 nl = nl}; |
360 |
373 |
361 fun pop {markups = (_, en) :: markups, tx, ind, pos: int, nl} : text = |
374 fun pop {main, line, pos, nl} : text = |
362 {markups = markups, |
375 {main = pop_state main, |
363 tx = Bytes.add en tx, |
376 line = line, |
364 ind = ind, |
|
365 pos = pos, |
377 pos = pos, |
366 nl = nl}; |
378 nl = nl}; |
|
379 |
|
380 fun result ({main, ...}: text) = state_output main; |
367 |
381 |
368 (*Add the lengths of the expressions until the next Break; if no Break then |
382 (*Add the lengths of the expressions until the next Break; if no Break then |
369 include "after", to account for text following this block.*) |
383 include "after", to account for text following this block.*) |
370 fun break_dist (Break _ :: _, _) = 0 |
384 fun break_dist (Break _ :: _, _) = 0 |
371 | break_dist (prt :: prts, after) = tree_length prt + break_dist (prts, after) |
385 | break_dist (prt :: prts, after) = tree_length prt + break_dist (prts, after) |
391 val newline = output_newline ops; |
405 val newline = output_newline ops; |
392 val blanks = string o output_spaces ops; |
406 val blanks = string o output_spaces ops; |
393 |
407 |
394 val indent_markup = #indent_markup ops; |
408 val indent_markup = #indent_markup ops; |
395 val no_indent_markup = indent_markup = Markup.no_output; |
409 val no_indent_markup = indent_markup = Markup.no_output; |
396 val (indent_bg, indent_en) = apply2 Substring.full indent_markup; |
410 |
397 |
411 val add_indent = if no_indent_markup then K I else add_state o #1 o output_spaces ops; |
398 val add_indent = if no_indent_markup then K I else output_spaces_buffer ops; |
412 |
399 |
413 fun break_indent (before_state, before_pos) ({main, line, nl, ...}: text) : text = |
400 fun break_indent (buf, n) ({markups, tx, nl, ...}: text) : text = |
|
401 let |
414 let |
402 val s = Buffer.content buf; |
415 val (main', line') = |
403 val indent = |
416 if no_indent_markup then |
404 if no_indent_markup then Bytes.add (Symbol.spaces n) |
417 (main |> add_state newline |> add_state (Symbol.spaces before_pos), line) |
405 else if s = "" then I |
418 else |
406 else Bytes.add_substring indent_bg #> Bytes.add s #> Bytes.add_substring indent_en; |
419 let |
407 val tx' = tx |> Bytes.add newline |> indent; |
420 val ss = Bytes.contents (state_output before_state); |
408 val ind' = Buffer.add s Buffer.empty; |
421 val main' = main |> add_state newline |
409 in {markups = markups, tx = tx', ind = ind', pos = n, nl = nl + 1} end; |
422 |> not (null ss) ? (push_state indent_markup #> fold add_state ss #> pop_state); |
410 |
423 val line' = fold add_state ss empty_state; |
411 nonfix before; |
424 in (main', line') end; |
|
425 in {main = main', line = line', pos = before_pos, nl = nl + 1} end; |
412 |
426 |
413 (*'before' is the indentation context of the current block*) |
427 (*'before' is the indentation context of the current block*) |
414 (*'after' is the width of the input context until the next break*) |
428 (*'after' is the width of the input context until the next break*) |
415 fun format (trees, before, after) (text as {pos, ...}) = |
429 fun format (trees, before, after) (text as {pos, ...}) = |
416 (case trees of |
430 (case trees of |
422 let |
436 let |
423 val pos' = pos + indent; |
437 val pos' = pos + indent; |
424 val pos'' = pos' mod emergencypos; |
438 val pos'' = pos' mod emergencypos; |
425 val before' = |
439 val before' = |
426 if pos' < emergencypos |
440 if pos' < emergencypos |
427 then (add_indent indent (#ind text), pos') |
441 then (add_indent indent (#line text), pos') |
428 else (add_indent pos'' Buffer.empty, pos''); |
442 else (add_indent pos'' empty_state, pos''); |
429 val after' = break_dist (ts, after) |
443 val after' = break_dist (ts, after) |
430 val body' = body |
444 val body' = body |
431 |> (consistent andalso pos + blen > margin - after') ? map force_break; |
445 |> (consistent andalso pos + blen > margin - after') ? map force_break; |
432 val btext: text = |
446 val btext: text = |
433 text |> push markup |> format (body' @ [End], before', after'); |
447 text |> push markup |> format (body' @ [End], before', after'); |
442 pos + wd <= Int.max (margin - break_dist (ts, after), #2 before + breakgain) |
456 pos + wd <= Int.max (margin - break_dist (ts, after), #2 before + breakgain) |
443 then text |> blanks wd (*just insert wd blanks*) |
457 then text |> blanks wd (*just insert wd blanks*) |
444 else text |> break_indent before |> blanks ind) |
458 else text |> break_indent before |> blanks ind) |
445 | Str str :: ts => format (ts, before, after) (string str text)); |
459 | Str str :: ts => format (ts, before, after) (string str text)); |
446 in |
460 in |
447 #tx (format ([output_tree ops true input], (Buffer.empty, 0), 0) empty) |
461 result (format ([output_tree ops true input], (empty_state, 0), 0) empty) |
448 end; |
462 end; |
449 |
463 |
450 end; |
464 end; |
451 |
465 |
452 |
466 |