src/Pure/General/pretty.ML
changeset 6321 207f518167e8
parent 6271 957d8aa4a06b
child 8456 8ccda76f07cb
equal deleted inserted replaced
6320:4df282137880 6321:207f518167e8
    26 signature PRETTY =
    26 signature PRETTY =
    27   sig
    27   sig
    28   type T
    28   type T
    29   val str: string -> T
    29   val str: string -> T
    30   val strlen: string -> int -> T
    30   val strlen: string -> int -> T
       
    31   val strlen_real: string -> real -> T
    31   val sym: string -> T
    32   val sym: string -> T
    32   val spc: int -> T
    33   val spc: int -> T
    33   val brk: int -> T
    34   val brk: int -> T
    34   val fbrk: T
    35   val fbrk: T
    35   val blk: int * T list -> T
    36   val blk: int * T list -> T
    48   val writeln: T -> unit
    49   val writeln: T -> unit
    49   val str_of: T -> string
    50   val str_of: T -> string
    50   val pprint: T -> pprint_args -> unit
    51   val pprint: T -> pprint_args -> unit
    51   val setdepth: int -> unit
    52   val setdepth: int -> unit
    52   val setmargin: int -> unit
    53   val setmargin: int -> unit
       
    54   val setmp_margin: int -> ('a -> 'b) -> 'a -> 'b
    53   end;
    55   end;
    54 
    56 
    55 structure Pretty : PRETTY =
    57 structure Pretty : PRETTY =
    56 struct
    58 struct
    57 
    59 
    98 
   100 
    99 (*** Formatting ***)
   101 (*** Formatting ***)
   100 
   102 
   101 (* margin *)
   103 (* margin *)
   102 
   104 
   103 (*example values*)
   105 fun make_margin_info m =
   104 val margin      = ref 80        (*right margin, or page width*)
   106  {margin = m,                   (*right margin, or page width*)
   105 and breakgain   = ref 4         (*minimum added space required of a break*)
   107   breakgain = m div 20,         (*minimum added space required of a break*)
   106 and emergencypos = ref 40;      (*position too far to right*)
   108   emergencypos = m div 2};      (*position too far to right*)
   107 
   109 
   108 fun setmargin m =
   110 val margin_info = ref (make_margin_info 76);
   109     (margin     := m;
   111 fun setmargin m = margin_info := make_margin_info m;
   110      breakgain  := !margin div 20;
   112 fun setmp_margin m f = setmp margin_info (make_margin_info m) f;
   111      emergencypos := !margin div 2);
       
   112 
       
   113 val () = setmargin 76;
       
   114 
       
   115 
   113 
   116 (*Search for the next break (at this or higher levels) and force it to occur*)
   114 (*Search for the next break (at this or higher levels) and force it to occur*)
   117 fun forcenext [] = []
   115 fun forcenext [] = []
   118   | forcenext (Break(_,wd) :: es) = Break(true,0) :: es
   116   | forcenext (Break(_,wd) :: es) = Break(true,0) :: es
   119   | forcenext (e :: es) = e :: forcenext es;
   117   | forcenext (e :: es) = e :: forcenext es;
   123   after is the width of the following context until next break. *)
   121   after is the width of the following context until next break. *)
   124 fun format ([], _, _) text = text
   122 fun format ([], _, _) text = text
   125   | format (e::es, blockin, after) (text as {pos,nl,...}) =
   123   | format (e::es, blockin, after) (text as {pos,nl,...}) =
   126     (case e of
   124     (case e of
   127        Block(bes,indent,wd) =>
   125        Block(bes,indent,wd) =>
   128          let val blockin' = (pos + indent) mod !emergencypos
   126          let val blockin' = (pos + indent) mod #emergencypos (! margin_info)
   129              val btext = format(bes, blockin', breakdist(es,after)) text
   127              val btext = format(bes, blockin', breakdist(es,after)) text
   130              (*If this block was broken then force the next break.*)
   128              (*If this block was broken then force the next break.*)
   131              val es2 = if nl < #nl(btext) then forcenext es else es
   129              val es2 = if nl < #nl(btext) then forcenext es else es
   132          in  format (es2,blockin,after) btext  end
   130          in  format (es2,blockin,after) btext  end
   133      | String (s, len) => format (es,blockin,after) (string s len text)
   131      | String (s, len) => format (es,blockin,after) (string s len text)
   134      | Break(force,wd) => (*no break if text to next break fits on this line
   132      | Break(force,wd) => (*no break if text to next break fits on this line
   135                             or if breaking would add only breakgain to space *)
   133                             or if breaking would add only breakgain to space *)
   136            format (es,blockin,after)
   134            format (es,blockin,after)
   137                (if not force andalso
   135                (if not force andalso
   138                    pos+wd <= Int.max(!margin - breakdist(es,after),
   136                    pos+wd <= Int.max(#margin (! margin_info) - breakdist(es,after),
   139                                      blockin + !breakgain)
   137                                      blockin + #breakgain (! margin_info))
   140                 then blanks wd text  (*just insert wd blanks*)
   138                 then blanks wd text  (*just insert wd blanks*)
   141                 else blanks blockin (newline text)));
   139                 else blanks blockin (newline text)));
   142 
   140 
   143 
   141 
   144 (*** Exported functions to create formatting expressions ***)
   142 (*** Exported functions to create formatting expressions ***)
   147   | length (String (_, len)) = len
   145   | length (String (_, len)) = len
   148   | length (Break(_, wd)) = wd;
   146   | length (Break(_, wd)) = wd;
   149 
   147 
   150 fun str s = String (s, size s);
   148 fun str s = String (s, size s);
   151 fun strlen s len = String (s, len);
   149 fun strlen s len = String (s, len);
       
   150 fun strlen_real s len = strlen s (Real.round len);
   152 val sym = String o apsnd Real.round o Symbol.output_width;
   151 val sym = String o apsnd Real.round o Symbol.output_width;
   153 
   152 
   154 fun spc n = str (repstring " " n);
   153 fun spc n = str (repstring " " n);
   155 
   154 
   156 fun brk wd = Break (false, wd);
   155 fun brk wd = Break (false, wd);
   214   | pruning dp e = e;
   213   | pruning dp e = e;
   215 
   214 
   216 fun prune dp e = if dp>0 then pruning dp e else e;
   215 fun prune dp e = if dp>0 then pruning dp e else e;
   217 
   216 
   218 
   217 
   219 fun string_of e = #tx (format ([prune (!depth) e], 0, 0) emptytext);
   218 fun string_of e = #tx (format ([prune (! depth) e], 0, 0) emptytext);
   220 
   219 
   221 val writeln = writeln o string_of;
   220 val writeln = writeln o string_of;
   222 
   221 
   223 
   222 
   224 (*Create a single flat string: no line breaking*)
   223 (*Create a single flat string: no line breaking*)
   226   let
   225   let
   227     fun s_of (Block (prts, _, _)) = implode (map s_of prts)
   226     fun s_of (Block (prts, _, _)) = implode (map s_of prts)
   228       | s_of (String (s, _)) = s
   227       | s_of (String (s, _)) = s
   229       | s_of (Break (false, wd)) = repstring " " wd
   228       | s_of (Break (false, wd)) = repstring " " wd
   230       | s_of (Break (true, _)) = " ";
   229       | s_of (Break (true, _)) = " ";
   231   in
   230   in s_of (prune (! depth) prt) end;
   232     s_of (prune (! depth) prt)
       
   233   end;
       
   234 
   231 
   235 (*Part of the interface to the Poly/ML and New Jersey ML pretty printers*)
   232 (*Part of the interface to the Poly/ML and New Jersey ML pretty printers*)
   236 fun pprint prt (put_str, begin_blk, put_brk, put_fbrk, end_blk) =
   233 fun pprint prt (put_str, begin_blk, put_brk, put_fbrk, end_blk) =
   237   let
   234   let
   238     fun pp (Block (prts, ind, _)) = (begin_blk ind; pp_lst prts; end_blk ())
   235     fun pp (Block (prts, ind, _)) = (begin_blk ind; pp_lst prts; end_blk ())