


## prettyprinter.pkg
# Compiled by:
# src/lib/prettyprint/big/prettyprint.libstipulate
package fil = file__premicrothread; # file__premicrothread is from src/lib/std/src/posix/file--premicrothread.pkgherein
package prettyprinter
: (weak) Prettyprinter # Prettyprinter is from src/lib/prettyprint/big/src/prettyprinter.api {
# I find the original prettyprinter interface ugly and clumsy;
# this is an attempt to provide something simpler and cleaner.
#
# The idea is to do
#
# pp.horizontal_else_vertical_box .{
# pp.out "Various\rstuff\rof consequence.\n";
# };
#
# or
#
# pp.horizontal_else_vertical_box .{
# pp.put "Various stuff of consequence.\n";
# };
#
# instead of
#
# pp::begin_horizontal_else_vertical_box stream;
# pp::string stream "Various";
# pp::break stream { spaces=>1; indent_on_wrap=>4 };
# pp::string stream "stuff";
# pp::break stream { spaces=>1; indent_on_wrap=>4 };
# pp::string stream "of consequence.";
# pp::newline stream;
# pp::end_box stream;
#
# approximately. In particular, I see the former as:
# o Inherently keeping block open/close pairs matched.
# (The original code had at least one such bug.)
# o Reducing clutter by making the 'stream' arguments implicit.
# o Reducing clutter by allowing newlines to be included in strings
# instead of having to be separate calls.
# Currently unused, probably needs tuning.
#
#
# TO DO: XXX BUGGO FIXME
# Drop wrap'_box and wrap'_box'
# Change horizontal_else_vertical_box and horizontal_else_vertical_box' to align and align'
# Change wrap_box and wrap_box' to wrap and wrap'
# Maybe change '\r' to '\ ' (or to \{ } so we can specify the
# number of blanks in a break naturally)? Or maybe out/put distinction handles this ok?
package pp = prettyprint; # prettyprint is from src/lib/prettyprint/big/src/prettyprint.pkg Prettyprinter
=
{ stream: prettyprint::Stream,
text_stream: Null_Or( fil::Output_Stream ),
align: (Void -> Void) -> Void,
wrap: (Void -> Void) -> Void,
align': Int -> (Void -> Void) -> Void,
wrap': Int -> (Void -> Void) -> Void,
flush: Void -> Void,
close: Void -> Void,
lit: String -> Void,
out: String -> Void,
put: String -> Void
};
fun make_file_prettyprinter prettyprint_filename
=
{ text_stream = fil::open_for_write prettyprint_filename;
#
prettyprint_device
=
{ consumer => (fn string = fil::write (text_stream, string)),
linewidth => 2000, # Arbitrary large number.
flush => .{ fil::flush text_stream; }
};
stream = pp::open_stream prettyprint_device;
fun align thunk = { pp::begin_horizontal_else_vertical_box stream; thunk(); pp::end_box stream; };
fun wrap thunk = { pp::begin_wrap_box stream; thunk(); pp::end_box stream; };
fun align' i thunk = { pp::begin_indented_horizontal_else_vertical_box stream (pp::BOX_RELATIVE i); thunk(); pp::end_box stream; };
fun wrap' i thunk = { pp::begin_indented_wrap_box stream (pp::BOX_RELATIVE i); thunk(); pp::end_box stream; };
fun flush () = { pp::flush_stream stream; fil::flush text_stream; };
fun close () = { pp::close_stream stream; fil::close_output text_stream; };
##############################################################################
# lit / out / put
#
# The idea with out/put is to replace
# explicit calls to pp::break and pp::newline
# with embedded ' ' '\r' '\n' chars:
#
# lit: Entire string output literally with no special character treatments.
# out: '\n' treated as pp::newline
# '\r' treated as pp::break { spaces => 3, indent_on_wrap => 0 }
# N blanks treated as pp::break { spaces => n, indent_on_wrap => 0 }
# put: Same, except indent_on_wrap for blanks is 4.
#
# The expectation is that:
# lit: Will typically be used to format short statements in a line box.
# put: Will typically be used to wrap individual words in a wrap box.
# In the former case, one usually wants wrapped lines to be aligned, hence the 'indent_on_wrap => 0'
# In the latter case, one usually wants wrapped lines to be indented, hence the 'indent_on_wrap => 4'
#
# (I don't expect \r to appear in 'put' strings, in general,
# but there seems no reason not to support it.)
##############################################################################
fun lit string
=
pp::string stream string;
fun output indent string
=
next 0
where
len = size string;
fun next i
=
if (i < len)
#
c = string::get (string, i);
case c
'\n' => do_newline i;
'\r' => do_cr i;
' ' => do_spaces (i, i+1);
_ => do_other (i, i+1);
esac;
fi
also
fun do_newline i # Treat each \n in 'string' as a call to pp:newline.
=
{ pp::newline stream;
next (i+1);
}
also
fun do_cr i # Treat each \r in 'string' as a call to pp:break { spaces => 3, indent_on_wrap => 0 }.
=
{ pp::break stream { spaces => 1, indent_on_wrap => 0 };
next (i+1);
}
also
fun do_spaces (i, j) # Treat a run of 'n' blanks in 'string' as a call to pp:break { spaces => n, indent_on_wrap => 4 }.
=
{
if (j >= len)
pp::break stream { spaces => j-i, indent_on_wrap => indent };
else
c = string::get (string, j);
if (c == ' ')
#
do_spaces (i, j+1); # Scan to end of string of blanks.
else
pp::break stream { spaces => j-i, indent_on_wrap => 4 };
next j;
fi;
fi;
}
also # Treat literally a run of non-\n, non-\r, non-blank chars in 'string'.
fun do_other (i, j)
=
if (j >= len)
#
pp::string stream (string::substring (string, i, j-i));
else
c = string::get (string, j);
if (c != ' '
and c != '\r'
and c != '\n'
)
do_other (i, j+1); # Scan to end of string of vanilla characters.
else
substring = string::substring (string, i, j-i);
pp::string stream substring;
next j;
fi;
fi;
end; # fun output
fun out string = output 0 string;
fun put string = output 4 string;
{ stream,
text_stream => THE text_stream,
align,
wrap,
align',
wrap',
flush,
close,
lit,
out,
put
};
};
}; # package prettyprinter
end;


