src/Pure/General/pretty.ML
changeset 61864 3a5992c3410c
parent 61863 931792ce2d83
child 61865 6dcc9e4f1aa6
equal deleted inserted replaced
61863:931792ce2d83 61864:3a5992c3410c
    10 
    10 
    11 The object to be printed is given as a tree with indentation and line
    11 The object to be printed is given as a tree with indentation and line
    12 breaking information.  A "break" inserts a newline if the text until
    12 breaking information.  A "break" inserts a newline if the text until
    13 the next break is too long to fit on the current line.  After the newline,
    13 the next break is too long to fit on the current line.  After the newline,
    14 text is indented to the level of the enclosing block.  Normally, if a block
    14 text is indented to the level of the enclosing block.  Normally, if a block
    15 is broken then all enclosing blocks will also be broken.  Only "inconsistent
    15 is broken then all enclosing blocks will also be broken.
    16 breaks" are provided.
    16 
    17 
    17 The stored length of a block is used in break_dist (to treat each inner block as
    18 The stored length of a block is used in breakdist (to treat each inner block as
       
    19 a unit for breaking).
    18 a unit for breaking).
    20 *)
    19 *)
    21 
    20 
    22 signature PRETTY =
    21 signature PRETTY =
    23 sig
    22 sig
    24   val spaces: int -> string
    23   val spaces: int -> string
    25   val default_indent: string -> int -> Output.output
    24   val default_indent: string -> int -> Output.output
    26   val add_mode: string -> (string -> int -> Output.output) -> unit
    25   val add_mode: string -> (string -> int -> Output.output) -> unit
    27   type T
    26   type T
       
    27   val make_block: Output.output * Output.output -> bool -> int -> T list -> T
    28   val str: string -> T
    28   val str: string -> T
    29   val brk: int -> T
    29   val brk: int -> T
    30   val brk_indent: int -> int -> T
    30   val brk_indent: int -> int -> T
    31   val fbrk: T
    31   val fbrk: T
    32   val breaks: T list -> T list
    32   val breaks: T list -> T list
    33   val fbreaks: T list -> T list
    33   val fbreaks: T list -> T list
    34   val blk: int * T list -> T
    34   val blk: int * T list -> T
    35   val block: T list -> T
    35   val block: T list -> T
    36   val strs: string list -> T
    36   val strs: string list -> T
    37   val raw_markup: Output.output * Output.output -> int * T list -> T
       
    38   val markup: Markup.T -> T list -> T
    37   val markup: Markup.T -> T list -> T
    39   val mark: Markup.T -> T -> T
    38   val mark: Markup.T -> T -> T
    40   val mark_str: Markup.T * string -> T
    39   val mark_str: Markup.T * string -> T
    41   val marks_str: Markup.T list * string -> T
    40   val marks_str: Markup.T list * string -> T
    42   val item: T list -> T
    41   val item: T list -> T
   122 
   121 
   123 
   122 
   124 (** printing items: compound phrases, strings, and breaks **)
   123 (** printing items: compound phrases, strings, and breaks **)
   125 
   124 
   126 abstype T =
   125 abstype T =
   127     Block of (Output.output * Output.output) * T list * int * int
   126     Block of (Output.output * Output.output) * T list * bool * int * int
   128       (*markup output, body, indentation, length*)
   127       (*markup output, body, consistent, indentation, length*)
   129   | String of Output.output * int  (*text, length*)
   128   | String of Output.output * int  (*text, length*)
   130   | Break of bool * int * int  (*mandatory flag, width if not taken, extra indentation if taken*)
   129   | Break of bool * int * int  (*mandatory flag, width if not taken, extra indentation if taken*)
   131 with
   130 with
   132 
   131 
   133 fun length (Block (_, _, _, len)) = len
   132 fun length (Block (_, _, _, _, len)) = len
   134   | length (String (_, len)) = len
   133   | length (String (_, len)) = len
   135   | length (Break (_, wd, _)) = wd;
   134   | length (Break (_, wd, _)) = wd;
       
   135 
       
   136 fun body_length [] len = len
       
   137   | body_length (e :: es) len = body_length es (length e + len);
       
   138 
       
   139 fun make_block m consistent indent es = Block (m, es, consistent, indent, body_length es 0);
       
   140 fun markup_block m indent es = make_block (Markup.output m) false indent es;
   136 
   141 
   137 
   142 
   138 
   143 
   139 (** derived operations to create formatting expressions **)
   144 (** derived operations to create formatting expressions **)
   140 
   145 
   145 val fbrk = Break (true, 1, 0);
   150 val fbrk = Break (true, 1, 0);
   146 
   151 
   147 fun breaks prts = Library.separate (brk 1) prts;
   152 fun breaks prts = Library.separate (brk 1) prts;
   148 fun fbreaks prts = Library.separate fbrk prts;
   153 fun fbreaks prts = Library.separate fbrk prts;
   149 
   154 
   150 fun raw_markup m (indent, es) =
   155 fun blk (ind, es) = markup_block Markup.empty ind es;
   151   let
       
   152     fun sum [] k = k
       
   153       | sum (e :: es) k = sum es (length e + k);
       
   154   in Block (m, es, indent, sum es 0) end;
       
   155 
       
   156 fun markup_block m arg = raw_markup (Markup.output m) arg;
       
   157 
       
   158 val blk = markup_block Markup.empty;
       
   159 fun block prts = blk (2, prts);
   156 fun block prts = blk (2, prts);
   160 val strs = block o breaks o map str;
   157 val strs = block o breaks o map str;
   161 
   158 
   162 fun markup m prts = markup_block m (0, prts);
   159 fun markup m = markup_block m 0;
   163 fun mark m prt = if m = Markup.empty then prt else markup m [prt];
   160 fun mark m prt = if m = Markup.empty then prt else markup m [prt];
   164 fun mark_str (m, s) = mark m (str s);
   161 fun mark_str (m, s) = mark m (str s);
   165 fun marks_str (ms, s) = fold_rev mark ms (str s);
   162 fun marks_str (ms, s) = fold_rev mark ms (str s);
   166 
   163 
   167 val item = markup Markup.item;
   164 val item = markup Markup.item;
   198 
   195 
   199 fun indent 0 prt = prt
   196 fun indent 0 prt = prt
   200   | indent n prt = blk (0, [str (spaces n), prt]);
   197   | indent n prt = blk (0, [str (spaces n), prt]);
   201 
   198 
   202 fun unbreakable (Break (_, wd, _)) = String (output_spaces wd, wd)
   199 fun unbreakable (Break (_, wd, _)) = String (output_spaces wd, wd)
   203   | unbreakable (Block (m, es, indent, wd)) = Block (m, map unbreakable es, indent, wd)
   200   | unbreakable (Block (m, es, _, indent, wd)) = Block (m, map unbreakable es, false, indent, wd)
   204   | unbreakable (e as String _) = e;
   201   | unbreakable (e as String _) = e;
   205 
   202 
   206 
   203 
   207 
   204 
   208 (** formatting **)
   205 (** formatting **)
   247     nl = nl}
   244     nl = nl}
   248   end;
   245   end;
   249 
   246 
   250 (*Add the lengths of the expressions until the next Break; if no Break then
   247 (*Add the lengths of the expressions until the next Break; if no Break then
   251   include "after", to account for text following this block.*)
   248   include "after", to account for text following this block.*)
   252 fun breakdist (Break _ :: _, _) = 0
   249 fun break_dist (Break _ :: _, _) = 0
   253   | breakdist (Block (_, _, _, len) :: es, after) = len + breakdist (es, after)
   250   | break_dist (Block (_, _, _, _, len) :: es, after) = len + break_dist (es, after)
   254   | breakdist (String (_, len) :: es, after) = len + breakdist (es, after)
   251   | break_dist (String (_, len) :: es, after) = len + break_dist (es, after)
   255   | breakdist ([], after) = after;
   252   | break_dist ([], after) = after;
       
   253 
       
   254 val force_break = fn Break (false, wd, ind) => Break (true, wd, ind) | e => e;
       
   255 val force_all = map force_break;
   256 
   256 
   257 (*Search for the next break (at this or higher levels) and force it to occur.*)
   257 (*Search for the next break (at this or higher levels) and force it to occur.*)
   258 val forcebreak = fn Break (false, wd, ind) => Break (true, wd, ind) | e => e;
   258 fun force_next [] = []
   259 fun forcenext [] = []
   259   | force_next ((e as Break _) :: es) = force_break e :: es
   260   | forcenext ((e as Break _) :: es) = forcebreak e :: es
   260   | force_next (e :: es) = e :: force_next es;
   261   | forcenext (e :: es) = e :: forcenext es;
       
   262 
   261 
   263 in
   262 in
   264 
   263 
   265 fun formatted margin input =
   264 fun formatted margin input =
   266   let
   265   let
   271       blockin is the indentation of the current block;
   270       blockin is the indentation of the current block;
   272       after is the width of the following context until next break.*)
   271       after is the width of the following context until next break.*)
   273     fun format ([], _, _) text = text
   272     fun format ([], _, _) text = text
   274       | format (e :: es, block as (_, blockin), after) (text as {ind, pos, nl, ...}) =
   273       | format (e :: es, block as (_, blockin), after) (text as {ind, pos, nl, ...}) =
   275           (case e of
   274           (case e of
   276             Block ((bg, en), bes, indent, _) =>
   275             Block ((bg, en), bes, consistent, indent, blen) =>
   277               let
   276               let
   278                 val pos' = pos + indent;
   277                 val pos' = pos + indent;
   279                 val pos'' = pos' mod emergencypos;
   278                 val pos'' = pos' mod emergencypos;
   280                 val block' =
   279                 val block' =
   281                   if pos' < emergencypos then (ind |> add_indent indent, pos')
   280                   if pos' < emergencypos then (ind |> add_indent indent, pos')
   282                   else (add_indent pos'' Buffer.empty, pos'');
   281                   else (add_indent pos'' Buffer.empty, pos'');
       
   282                 val d = break_dist (es, after)
       
   283                 val bes' = if consistent andalso pos + blen > margin - d then force_all bes else bes;
   283                 val btext: text = text
   284                 val btext: text = text
   284                   |> control bg
   285                   |> control bg
   285                   |> format (bes, block', breakdist (es, after))
   286                   |> format (bes', block', d)
   286                   |> control en;
   287                   |> control en;
   287                 (*if this block was broken then force the next break*)
   288                 (*if this block was broken then force the next break*)
   288                 val es' = if nl < #nl btext then forcenext es else es;
   289                 val es' = if nl < #nl btext then force_next es else es;
   289               in format (es', block, after) btext end
   290               in format (es', block, after) btext end
   290           | Break (force, wd, ind) =>
   291           | Break (force, wd, ind) =>
   291               (*no break if text to next break fits on this line
   292               (*no break if text to next break fits on this line
   292                 or if breaking would add only breakgain to space*)
   293                 or if breaking would add only breakgain to space*)
   293               format (es, block, after)
   294               format (es, block, after)
   294                 (if not force andalso
   295                 (if not force andalso
   295                     pos + wd <= Int.max (margin - breakdist (es, after), blockin + breakgain)
   296                     pos + wd <= Int.max (margin - break_dist (es, after), blockin + breakgain)
   296                   then text |> blanks wd  (*just insert wd blanks*)
   297                  then text |> blanks wd  (*just insert wd blanks*)
   297                   else text |> newline |> indentation block |> blanks ind)
   298                  else text |> newline |> indentation block |> blanks ind)
   298           | String str => format (es, block, after) (string str text));
   299           | String str => format (es, block, after) (string str text));
   299   in
   300   in
   300     #tx (format ([input], (Buffer.empty, 0), 0) empty)
   301     #tx (format ([input], (Buffer.empty, 0), 0) empty)
   301   end;
   302   end;
   302 
   303 
   306 (* special output *)
   307 (* special output *)
   307 
   308 
   308 (*symbolic markup -- no formatting*)
   309 (*symbolic markup -- no formatting*)
   309 fun symbolic prt =
   310 fun symbolic prt =
   310   let
   311   let
   311     fun out (Block ((bg, en), [], _, _)) = Buffer.add bg #> Buffer.add en
   312     fun out (Block ((bg, en), [], _, _, _)) = Buffer.add bg #> Buffer.add en
   312       | out (Block ((bg, en), prts, indent, _)) =
   313       | out (Block ((bg, en), prts, consistent, indent, _)) =
   313           Buffer.add bg #>
   314           Buffer.add bg #>
   314           Buffer.markup (Markup.block indent) (fold out prts) #>
   315           Buffer.markup (Markup.block consistent indent) (fold out prts) #>
   315           Buffer.add en
   316           Buffer.add en
   316       | out (String (s, _)) = Buffer.add s
   317       | out (String (s, _)) = Buffer.add s
   317       | out (Break (false, wd, ind)) =
   318       | out (Break (false, wd, ind)) =
   318           Buffer.markup (Markup.break wd ind) (Buffer.add (output_spaces wd))
   319           Buffer.markup (Markup.break wd ind) (Buffer.add (output_spaces wd))
   319       | out (Break (true, _, _)) = Buffer.add (Output.output "\n");
   320       | out (Break (true, _, _)) = Buffer.add (Output.output "\n");
   320   in out prt Buffer.empty end;
   321   in out prt Buffer.empty end;
   321 
   322 
   322 (*unformatted output*)
   323 (*unformatted output*)
   323 fun unformatted prt =
   324 fun unformatted prt =
   324   let
   325   let
   325     fun fmt (Block ((bg, en), prts, _, _)) = Buffer.add bg #> fold fmt prts #> Buffer.add en
   326     fun fmt (Block ((bg, en), prts, _, _, _)) = Buffer.add bg #> fold fmt prts #> Buffer.add en
   326       | fmt (String (s, _)) = Buffer.add s
   327       | fmt (String (s, _)) = Buffer.add s
   327       | fmt (Break (_, wd, _)) = Buffer.add (output_spaces wd);
   328       | fmt (Break (_, wd, _)) = Buffer.add (output_spaces wd);
   328   in fmt prt Buffer.empty end;
   329   in fmt prt Buffer.empty end;
   329 
   330 
   330 
   331 
   377 
   378 
   378 
   379 
   379 
   380 
   380 (** ML toplevel pretty printing **)
   381 (** ML toplevel pretty printing **)
   381 
   382 
   382 fun to_ML (Block (m, prts, ind, _)) = ML_Pretty.Block (m, map to_ML prts, ind)
   383 fun to_ML (Block (m, prts, consistent, indent, _)) =
       
   384       ML_Pretty.Block (m, map to_ML prts, consistent, indent)
   383   | to_ML (String s) = ML_Pretty.String s
   385   | to_ML (String s) = ML_Pretty.String s
   384   | to_ML (Break b) = ML_Pretty.Break b;
   386   | to_ML (Break b) = ML_Pretty.Break b;
   385 
   387 
   386 fun from_ML (ML_Pretty.Block (m, prts, ind)) = raw_markup m (ind, map from_ML prts)
   388 fun from_ML (ML_Pretty.Block (m, prts, consistent, indent)) =
       
   389       make_block m consistent indent (map from_ML prts)
   387   | from_ML (ML_Pretty.String s) = String s
   390   | from_ML (ML_Pretty.String s) = String s
   388   | from_ML (ML_Pretty.Break b) = Break b;
   391   | from_ML (ML_Pretty.Break b) = Break b;
   389 
   392 
   390 end;
   393 end;
   391 
   394