src/Pure/General/pretty.ML
changeset 80844 b569fbe1c262
parent 80843 67f5861415a5
child 80846 9ed32b8a03a9
equal deleted inserted replaced
80843:67f5861415a5 80844:b569fbe1c262
    26   val add_mode: string -> ops -> unit
    26   val add_mode: string -> ops -> unit
    27   val get_mode: unit -> ops
    27   val get_mode: unit -> ops
    28   type T
    28   type T
    29   val to_ML: T -> ML_Pretty.pretty
    29   val to_ML: T -> ML_Pretty.pretty
    30   val from_ML: ML_Pretty.pretty -> T
    30   val from_ML: ML_Pretty.pretty -> T
    31   val make_block: {markup: Markup.output, consistent: bool, indent: int} ->
    31   val make_block: {markup: Markup.output, consistent: bool, indent: int} -> T list -> T
    32     T list -> T
       
    33   val markup_block: {markup: Markup.T, consistent: bool, indent: int} -> T list -> T
    32   val markup_block: {markup: Markup.T, consistent: bool, indent: int} -> T list -> T
    34   val str: string -> T
    33   val str: string -> T
    35   val dots: T
    34   val dots: T
    36   val brk: int -> T
    35   val brk: int -> T
    37   val brk_indent: int -> int -> T
    36   val brk_indent: int -> int -> T
    73     markup: Markup.output -> Markup.output,
    72     markup: Markup.output -> Markup.output,
    74     indent: string -> int -> Output.output,
    73     indent: string -> int -> Output.output,
    75     margin: int}
    74     margin: int}
    76   val output_ops: int option -> output_ops
    75   val output_ops: int option -> output_ops
    77   val markup_output_ops: int option -> output_ops
    76   val markup_output_ops: int option -> output_ops
       
    77   val symbolic_output: T -> Output.output list
       
    78   val symbolic_string_of: T -> string
       
    79   val unformatted_string_of: T -> string
    78   val regularN: string
    80   val regularN: string
    79   val symbolicN: string
    81   val symbolicN: string
    80   val output_buffer: output_ops -> T -> Buffer.T
    82   val output_buffer: output_ops -> T -> Buffer.T
    81   val output: output_ops -> T -> Output.output list
    83   val output: output_ops -> T -> Output.output list
    82   val string_of_ops: output_ops -> T -> string
    84   val string_of_ops: output_ops -> T -> string
    83   val string_of: T -> string
    85   val string_of: T -> string
    84   val writeln: T -> unit
    86   val writeln: T -> unit
    85   val symbolic_output: T -> Output.output list
       
    86   val symbolic_string_of: T -> string
       
    87   val unformatted_string_of: T -> string
       
    88   val markup_chunks: Markup.T -> T list -> T
    87   val markup_chunks: Markup.T -> T list -> T
    89   val chunks: T list -> T
    88   val chunks: T list -> T
    90   val chunks2: T list -> T
    89   val chunks2: T list -> T
    91   val block_enclose: T * T -> T list -> T
    90   val block_enclose: T * T -> T list -> T
    92   val writeln_chunks: T list -> unit
    91   val writeln_chunks: T list -> unit
    98 
    97 
    99 (** print mode operations **)
    98 (** print mode operations **)
   100 
    99 
   101 type ops = {markup: Markup.output -> Markup.output, indent: string -> int -> string};
   100 type ops = {markup: Markup.output -> Markup.output, indent: string -> int -> string};
   102 
   101 
   103 val markup_ops : ops = {markup = I, indent = K Symbol.spaces};
   102 val markup_ops: ops = {markup = I, indent = K Symbol.spaces};
   104 val no_markup_ops : ops = {markup = K Markup.no_output, indent = #indent markup_ops};
   103 val no_markup_ops: ops = {markup = K Markup.no_output, indent = #indent markup_ops};
   105 
   104 
   106 local
   105 local
   107   val modes = Synchronized.var "Pretty.modes" (Symtab.make [("", no_markup_ops)]);
   106   val modes = Synchronized.var "Pretty.modes" (Symtab.make [("", no_markup_ops)]);
   108 in
   107 in
   109   fun add_mode name ops =
   108   fun add_mode name ops =
   116       (Library.get_first (Symtab.lookup (Synchronized.value modes)) (print_mode_value ()));
   115       (Library.get_first (Symtab.lookup (Synchronized.value modes)) (print_mode_value ()));
   117 end;
   116 end;
   118 
   117 
   119 
   118 
   120 
   119 
   121 (** printing items: compound phrases, strings, and breaks **)
   120 (** Pretty.T **)
       
   121 
       
   122 (* abstype: ML_Pretty.pretty without (op =) *)
       
   123 
       
   124 abstype T = T of ML_Pretty.pretty
       
   125 with
       
   126   fun to_ML (T prt) = prt;
       
   127   val from_ML = T;
       
   128 end;
   122 
   129 
   123 val force_nat = Integer.max 0;
   130 val force_nat = Integer.max 0;
   124 val short_nat = FixedInt.fromInt o force_nat;
   131 val short_nat = FixedInt.fromInt o force_nat;
   125 val long_nat = force_nat o FixedInt.toInt;
   132 val long_nat = force_nat o FixedInt.toInt;
   126 
   133 
   127 datatype tree =
   134 
   128     Block of Markup.output * bool * int * tree list * int
   135 (* primitives *)
   129       (*markup output, consistent, indentation, body, length*)
       
   130   | Break of bool * int * int  (*mandatory flag, width if not taken, extra indentation if taken*)
       
   131   | Str of Output.output * int;  (*string output, length*)
       
   132 
       
   133 fun tree_length (Block (_, _, _, _, len)) = len
       
   134   | tree_length (Break (_, wd, _)) = wd
       
   135   | tree_length (Str (_, len)) = len;
       
   136 
       
   137 abstype T = T of ML_Pretty.pretty
       
   138 with
       
   139 
       
   140 fun to_ML (T prt) = prt;
       
   141 val from_ML = T;
       
   142 
   136 
   143 fun make_block {markup = (bg, en), consistent, indent} body =
   137 fun make_block {markup = (bg, en), consistent, indent} body =
   144   let
   138   let
   145     val context =
   139     val context =
   146       (if bg = "" then [] else [ML_Pretty.ContextProperty ("begin", bg)]) @
   140       (if bg = "" then [] else [ML_Pretty.ContextProperty ("begin", bg)]) @
   147       (if en = "" then [] else [ML_Pretty.ContextProperty ("end", en)]);
   141       (if en = "" then [] else [ML_Pretty.ContextProperty ("end", en)]);
   148     val ind = short_nat indent;
   142     val ind = short_nat indent;
   149   in T (ML_Pretty.PrettyBlock (ind, consistent, context, map to_ML body)) end;
   143   in from_ML (ML_Pretty.PrettyBlock (ind, consistent, context, map to_ML body)) end;
   150 
   144 
   151 fun markup_block {markup, consistent, indent} body =
   145 fun markup_block {markup, consistent, indent} body =
   152   make_block {markup = YXML.output_markup markup, consistent = consistent, indent = indent} body;
   146   make_block {markup = YXML.output_markup markup, consistent = consistent, indent = indent} body;
   153 
   147 
   154 
   148 val str = from_ML o ML_Pretty.str;
   155 
   149 val dots = from_ML ML_Pretty.dots;
   156 (** derived operations to create formatting expressions **)
   150 
   157 
   151 fun brk_indent wd ind = from_ML (ML_Pretty.PrettyBreak (short_nat wd, short_nat ind));
   158 val str = T o ML_Pretty.str;
       
   159 val dots = T ML_Pretty.dots;
       
   160 
       
   161 fun brk_indent wd ind = T (ML_Pretty.PrettyBreak (short_nat wd, short_nat ind));
       
   162 fun brk wd = brk_indent wd 0;
   152 fun brk wd = brk_indent wd 0;
   163 val fbrk = T ML_Pretty.PrettyLineBreak;
   153 val fbrk = from_ML ML_Pretty.PrettyLineBreak;
       
   154 
       
   155 
       
   156 (* derived operations to create formatting expressions *)
   164 
   157 
   165 fun breaks prts = Library.separate (brk 1) prts;
   158 fun breaks prts = Library.separate (brk 1) prts;
   166 fun fbreaks prts = Library.separate fbrk prts;
   159 fun fbreaks prts = Library.separate fbrk prts;
   167 
   160 
   168 fun blk (indent, es) =
   161 fun blk (indent, es) =
   261 
   254 
   262 fun output_spaces (ops: output_ops) = #output ops o Symbol.spaces;
   255 fun output_spaces (ops: output_ops) = #output ops o Symbol.spaces;
   263 fun output_spaces_buffer ops = Buffer.add o #1 o output_spaces ops;
   256 fun output_spaces_buffer ops = Buffer.add o #1 o output_spaces ops;
   264 
   257 
   265 
   258 
   266 (* formatted output *)
   259 (* output tree *)
       
   260 
       
   261 datatype tree =
       
   262     Block of Markup.output * bool * int * tree list * int
       
   263       (*markup output, consistent, indentation, body, length*)
       
   264   | Break of bool * int * int  (*mandatory flag, width if not taken, extra indentation if taken*)
       
   265   | Str of Output.output * int;  (*string output, length*)
       
   266 
       
   267 fun tree_length (Block (_, _, _, _, len)) = len
       
   268   | tree_length (Break (_, wd, _)) = wd
       
   269   | tree_length (Str (_, len)) = len;
   267 
   270 
   268 local
   271 local
   269 
   272 
   270 type text = {tx: Buffer.T, ind: Buffer.T, pos: int, nl: int};
   273 fun context_property context name =
   271 
   274   let
   272 val empty: text =
   275     fun get (ML_Pretty.ContextProperty (a, b)) = if name = a then SOME b else NONE
   273  {tx = Buffer.empty,
   276       | get _ = NONE;
   274   ind = Buffer.empty,
   277   in the_default "" (get_first get context) end;
   275   pos = 0,
       
   276   nl = 0};
       
   277 
       
   278 fun newline s {tx, ind = _, pos = _, nl} : text =
       
   279  {tx = Buffer.add s tx,
       
   280   ind = Buffer.empty,
       
   281   pos = 0,
       
   282   nl = nl + 1};
       
   283 
       
   284 fun control s {tx, ind, pos: int, nl} : text =
       
   285  {tx = Buffer.add s tx,
       
   286   ind = ind,
       
   287   pos = pos,
       
   288   nl = nl};
       
   289 
       
   290 fun string (s, len) {tx, ind, pos: int, nl} : text =
       
   291  {tx = Buffer.add s tx,
       
   292   ind = Buffer.add s ind,
       
   293   pos = pos + len,
       
   294   nl = nl};
       
   295 
       
   296 (*Add the lengths of the expressions until the next Break; if no Break then
       
   297   include "after", to account for text following this block.*)
       
   298 fun break_dist (Break _ :: _, _) = 0
       
   299   | break_dist (e :: es, after) = tree_length e + break_dist (es, after)
       
   300   | break_dist ([], after) = after;
       
   301 
       
   302 val fbreak = Break (true, 1, 0);
       
   303 
       
   304 val force_break = fn Break (false, wd, ind) => Break (true, wd, ind) | e => e;
       
   305 val force_all = map force_break;
       
   306 
       
   307 (*Search for the next break (at this or higher levels) and force it to occur.*)
       
   308 fun force_next [] = []
       
   309   | force_next ((e as Break _) :: es) = force_break e :: es
       
   310   | force_next (e :: es) = e :: force_next es;
       
   311 
   278 
   312 fun block_length indent =
   279 fun block_length indent =
   313   let
   280   let
   314     fun block_len len prts =
   281     fun block_len len prts =
   315       let
   282       let
   321             block_len len' (Break (false, indent + ind, 0) :: rest')
   288             block_len len' (Break (false, indent + ind, 0) :: rest')
   322         | [] => len')
   289         | [] => len')
   323       end;
   290       end;
   324   in block_len 0 end;
   291   in block_len 0 end;
   325 
   292 
   326 fun property context name =
   293 val fbreak = Break (true, 1, 0);
   327   let
       
   328     fun get (ML_Pretty.ContextProperty (a, b)) = if name = a then SOME b else NONE
       
   329       | get _ = NONE;
       
   330   in the_default "" (get_first get context) end;
       
   331 
   294 
   332 in
   295 in
   333 
   296 
   334 fun output_tree (ops: output_ops) make_length =
   297 fun output_tree (ops: output_ops) make_length =
   335   let
   298   let
   336     fun out (T (ML_Pretty.PrettyBlock (ind, consistent, context, body))) =
   299     fun out (ML_Pretty.PrettyBlock (ind, consistent, context, body)) =
   337           let
   300           let
   338             val bg = property context "begin";
   301             val bg = context_property context "begin";
   339             val en = property context "end";
   302             val en = context_property context "end";
   340             val m = #markup ops (bg, en);
   303             val m = #markup ops (bg, en);
   341             val indent = long_nat ind;
   304             val indent = long_nat ind;
   342             val body' = map (out o T) body;
   305             val body' = map out body;
   343             val len = if make_length then block_length indent body' else ~1;
   306             val len = if make_length then block_length indent body' else ~1;
   344           in Block (m, consistent, indent, body', len) end
   307           in Block (m, consistent, indent, body', len) end
   345       | out (T (ML_Pretty.PrettyBreak (wd, ind))) = Break (false, long_nat wd, long_nat ind)
   308       | out (ML_Pretty.PrettyBreak (wd, ind)) = Break (false, long_nat wd, long_nat ind)
   346       | out (T ML_Pretty.PrettyLineBreak) = fbreak
   309       | out ML_Pretty.PrettyLineBreak = fbreak
   347       | out (T (ML_Pretty.PrettyString s)) = Str (#output ops s ||> force_nat)
   310       | out (ML_Pretty.PrettyString s) = Str (#output ops s ||> force_nat)
   348       | out (T (ML_Pretty.PrettyStringWithWidth (s, n))) = Str (s, long_nat n);
   311       | out (ML_Pretty.PrettyStringWithWidth (s, n)) = Str (s, long_nat n);
   349   in out end;
   312   in out o to_ML end;
       
   313 
       
   314 end;
       
   315 
       
   316 
       
   317 (* formatted output *)
       
   318 
       
   319 local
       
   320 
       
   321 type text = {tx: Buffer.T, ind: Buffer.T, pos: int, nl: int};
       
   322 
       
   323 val empty: text =
       
   324  {tx = Buffer.empty,
       
   325   ind = Buffer.empty,
       
   326   pos = 0,
       
   327   nl = 0};
       
   328 
       
   329 fun newline s {tx, ind = _, pos = _, nl} : text =
       
   330  {tx = Buffer.add s tx,
       
   331   ind = Buffer.empty,
       
   332   pos = 0,
       
   333   nl = nl + 1};
       
   334 
       
   335 fun control s {tx, ind, pos: int, nl} : text =
       
   336  {tx = Buffer.add s tx,
       
   337   ind = ind,
       
   338   pos = pos,
       
   339   nl = nl};
       
   340 
       
   341 fun string (s, len) {tx, ind, pos: int, nl} : text =
       
   342  {tx = Buffer.add s tx,
       
   343   ind = Buffer.add s ind,
       
   344   pos = pos + len,
       
   345   nl = nl};
       
   346 
       
   347 (*Add the lengths of the expressions until the next Break; if no Break then
       
   348   include "after", to account for text following this block.*)
       
   349 fun break_dist (Break _ :: _, _) = 0
       
   350   | break_dist (e :: es, after) = tree_length e + break_dist (es, after)
       
   351   | break_dist ([], after) = after;
       
   352 
       
   353 val force_break = fn Break (false, wd, ind) => Break (true, wd, ind) | e => e;
       
   354 val force_all = map force_break;
       
   355 
       
   356 (*Search for the next break (at this or higher levels) and force it to occur.*)
       
   357 fun force_next [] = []
       
   358   | force_next ((e as Break _) :: es) = force_break e :: es
       
   359   | force_next (e :: es) = e :: force_next es;
       
   360 
       
   361 in
   350 
   362 
   351 fun format_tree (ops: output_ops) input =
   363 fun format_tree (ops: output_ops) input =
   352   let
   364   let
   353     val margin = #margin ops;
   365     val margin = #margin ops;
   354     val breakgain = margin div 20;     (*minimum added space required of a break*)
   366     val breakgain = margin div 20;     (*minimum added space required of a break*)
   402   end;
   414   end;
   403 
   415 
   404 end;
   416 end;
   405 
   417 
   406 
   418 
   407 (*symbolic markup -- no formatting*)
   419 
       
   420 (** no formatting **)
       
   421 
       
   422 (* symbolic output: XML markup for blocks/breaks + other markup *)
       
   423 
   408 val symbolic =
   424 val symbolic =
   409   let
   425   let
   410     val ops = markup_output_ops NONE;
   426     val ops = markup_output_ops NONE;
   411 
   427 
   412     fun markup_buffer m body =
   428     fun markup_buffer m body =
   422           markup_buffer (Markup.break wd ind) (output_spaces_buffer ops wd)
   438           markup_buffer (Markup.break wd ind) (output_spaces_buffer ops wd)
   423       | out (Break (true, _, _)) = Buffer.add (output_newline ops)
   439       | out (Break (true, _, _)) = Buffer.add (output_newline ops)
   424       | out (Str (s, _)) = Buffer.add s;
   440       | out (Str (s, _)) = Buffer.add s;
   425   in Buffer.build o out o output_tree ops false end;
   441   in Buffer.build o out o output_tree ops false end;
   426 
   442 
   427 (*unformatted output*)
   443 val symbolic_output = Buffer.contents o symbolic;
       
   444 val symbolic_string_of = implode o symbolic_output;
       
   445 
       
   446 
       
   447 (* unformatted output: other markup only *)
       
   448 
   428 fun unformatted ops =
   449 fun unformatted ops =
   429   let
   450   let
   430     fun out (Block ((bg, en), _, _, prts, _)) = Buffer.add bg #> fold out prts #> Buffer.add en
   451     fun out (Block ((bg, en), _, _, prts, _)) = Buffer.add bg #> fold out prts #> Buffer.add en
   431       | out (Break (_, wd, _)) = output_spaces_buffer ops wd
   452       | out (Break (_, wd, _)) = output_spaces_buffer ops wd
   432       | out (Str (s, _)) = Buffer.add s;
   453       | out (Str (s, _)) = Buffer.add s;
   433   in Buffer.build o out o output_tree ops false end;
   454   in Buffer.build o out o output_tree ops false end;
   434 
   455 
       
   456 fun unformatted_string_of prt =
       
   457   let val ops = output_ops NONE
       
   458   in implode (#escape ops (Buffer.contents (unformatted ops prt))) end;
       
   459 
   435 
   460 
   436 (* output interfaces *)
   461 (* output interfaces *)
   437 
   462 
   438 val regularN = "pretty_regular";
   463 val regularN = "pretty_regular";
   439 val symbolicN = "pretty_symbolic";
   464 val symbolicN = "pretty_symbolic";
   449 fun string_of prt = string_of_ops (output_ops NONE) prt;
   474 fun string_of prt = string_of_ops (output_ops NONE) prt;
   450 
   475 
   451 fun writeln prt =
   476 fun writeln prt =
   452   let val ops = output_ops NONE
   477   let val ops = output_ops NONE
   453   in Output.writelns (#escape ops (output ops prt)) end;
   478   in Output.writelns (#escape ops (output ops prt)) end;
   454 
       
   455 val symbolic_output = Buffer.contents o symbolic;
       
   456 val symbolic_string_of = implode o symbolic_output;
       
   457 
       
   458 fun unformatted_string_of prt =
       
   459   let val ops = output_ops NONE
       
   460   in implode (#escape ops (Buffer.contents (unformatted ops prt))) end;
       
   461 
   479 
   462 
   480 
   463 (* chunks *)
   481 (* chunks *)
   464 
   482 
   465 fun markup_chunks m prts = markup m (fbreaks (map (text_fold o single) prts));
   483 fun markup_chunks m prts = markup m (fbreaks (map (text_fold o single) prts));
   486         [string_of_text_fold last])
   504         [string_of_text_fold last])
   487       |> Output.writelns);
   505       |> Output.writelns);
   488 
   506 
   489 end;
   507 end;
   490 
   508 
   491 end;
   509 
       
   510 
       
   511 (** back-patching **)
   492 
   512 
   493 structure ML_Pretty: ML_PRETTY =
   513 structure ML_Pretty: ML_PRETTY =
   494 struct
   514 struct
   495   open ML_Pretty;
   515   open ML_Pretty;
   496   val string_of = Pretty.string_of o Pretty.from_ML;
   516   val string_of = Pretty.string_of o Pretty.from_ML;