src/Pure/General/pretty.ML
changeset 81699 d407fbe2e5a2
parent 81697 1629c2ff4880
child 81700 5c90d1f3a44c
equal deleted inserted replaced
81698:17f1a78af3f5 81699:d407fbe2e5a2
   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