Is there a way to make sure that for a few lines the pretty printing machinery of Format
will not try to interfere with output instructions – basically set it in Printf
mode.
Just off the cuff, I might try to write a formatter that wrapped a provided formatter, and mappid all the interesting pp ops to no-ops: that is, boxes, cuts, breaks, etc. And just pass thru the rest. That would leave the pp context established before your code was called, I guess. Probably a way to disable that too
It depends a lot on what you mean by disabling pretty-printing and what are the source of the output instruction.
If the source is a format string, it is possible to write an alternative interpreter that ignore all formatting instructions.
If the source are printing functions (that are modifying a formatter state), it is too late to disable the emission of formatting instructions. A degraded option would be to print first to a buffer formatter with “infinite” margin and where the newline
and indent
instructions are disabled
let neutral_buffer () =
let b = Buffer.create 100 in
let ppf = Format.formatter_of_buffer b in
let fns = Format.pp_get_formatter_out_functions ppf () in
let disabled = Format.{
fns with
out_indent = ignore;
out_newline = ignore;
}
in
Format.pp_set_formatter_out_functions ppf disabled;
Format.pp_set_geometry ppf
~max_indent:(Format.pp_infinity - 2) ~margin:(Format.pp_infinity - 1);
b, ppf
let disable_formatting ppf pr =
let b, bppf = neutral_buffer () in
pr bppf;
Format.pp_print_flush bppf ();
let s = Buffer.contents b in
Format.pp_print_string ppf s
let test =
let vbox = Format.dprintf "@[<v>D@ E@ F@]" in
let bbox = Format.dprintf "@[I@ J@ K@]" in
Format.printf "@[<v>A@ B@ C%aG@ H@ %a L@ M@ J@]@."
disable_formatting vbox
disable_formatting bbox
which prints
A
B
CDEFG
H
I J K L
M
J
where the first group CDEFG
illustrates the fact that we lose information about the space component of break hints inside vbox.
I think that an accurate description would be:
let pp_no_pp ppf v = Format.fprintf ppf "%s" (to_string v)
without this disturbing too much an established pretty printing context. Of course it may break a few boxes, the point here is for the result of to_string
to be acurately represented in the output. Being understood that to_string
may have newlines therein and that I’d rather avoid first printing to a string.
The use case is an AST which has layout information under the form of strings of whitespace (including newlines). I would like to provide a pp
that ignores the layout information and does pretty printing using Format
, but also a pp_layout
that does not use the pretty printing engine but uses the layout information of the AST.
If the aim is to insert a printer output as text without modifying the current formatting context, having a secondary formatter as suggested by @Chet_Murthy might work while avoiding building the full output in a separate buffer:
let secondary_formatter ppf =
let out_spaces n = Format.pp_print_string ppf (String.make n ' ') in
let fns = Format.{
out_indent = out_spaces;
out_spaces;
out_newline = (fun () -> Format.pp_print_string ppf "\n");
out_string = (fun s start len -> Format.pp_print_string ppf (String.sub s start len));
out_flush = ignore;
}
in
Format.formatter_of_out_functions fns
let pp_no_pp ppf pr =
let intermediary = secondary_formatter ppf in
pr intermediary;
Format.pp_print_flush intermediary ()