UnparserBuffer.mesa
Created December 7, 1982 3:57 pm by Greg Nelson
GNelson, December 6, 1983 2:03 am
Spreitzer, February 9, 1986 11:59:56 pm PST
Formatted output routines. Send a stream of characters through a buffer, delineate the stream into subsequences called objects. The objects can be nested. (Objects are called "groups" in CGN9.) For each object, specify within it a set of breakpoints. The routines will format the text as follows. (1) An object will be printed all on one line if possible. (2) If an object cannot fit on one line, new lines will be started at one or more of the object's breakpoints, so that no text overflows the right margin. (3) With each breakpoint there is associated an integer call the breakpoint's offset. If a new line is started at a breakpoint, then the new line will be indented by the sum of the breakpoint's offset plus the indentation of the first character of the smallest object that contains the breakpoint. (4) Each breakpoint is either united or ununited. If any breakpoint of an object is broken, then all that object's united breakpoints are broken. An ununited breakpoint is broken only if it is necessary to do so to prevent overflowing the right margin.
DIRECTORY Atom, IO, Rope, TiogaAccess;
UnparserBuffer: CEDAR DEFINITIONS =
BEGIN
Handle: TYPE = REF HandleRec;
NewHandle: PROC [output: BufferOutput, margin: INTEGER ← 80] RETURNS [Handle];
With spacers = LIST[IO.SP].
Init: PROC [h: Handle];
Destroys any information in the internal buffers and makes the buffers all empty. Almost like allocating a new handle, but does not affect the public parts (margin, width, output, and clientData).
Setb: PROC [h: Handle];
Begin an object.
Endb: PROC [h: Handle];
End an object.
Bp: PROC[h: Handle, united: BOOL, offset: INTEGER];
Inserts a breakpoint. If the breakpoint breaks, the next line will be indented by offset from the beginning of the object to which this breakpoint belongs.
Charb: PROC [h: Handle, ch: CHAR];
Outputs the character
Ropeb: PROC [h: Handle, r: Rope.ROPE];
Outputs the rope
Atomb: PROC [h: Handle, a: ATOM];
Outputs the pname of the atom
Newlineb: PROC [h: Handle, offset: INTEGER];
Just like a breakpoint except that it is certain to break, thus the effect is to insert a new line into the output.
Looksb: PROC [h: Handle, looks: Rope.ROPE];
Affects the looks of the following characters in the standard way.
HandleRec: TYPE = RECORD [
The following fields are public --- the client may read and write these synchronously with calls on routines in this interface.
margin: INTEGER ← 80,
Shouldn't modify this unless between lines.
width: ARRAY CHAR OF INTEGERALL [1],
spacers: LIST OF CHAR,
Width of each element should evenly divide width of previous element.
Width of last element must evenly divide every possible indentation.
output: BufferOutput,
clientData: REFNIL,
The following fields are private to the implementation --- the client should not read or write them.
bufferWidth: PRIVATE INTEGER ← 0,
bl, cl, br, cr, sr, srx: PRIVATE INTEGER ← 0,
c: PRIVATE ARRAY [0 .. n) OF CHARALL['?],
dl: PRIVATE ARRAY [0 .. n) OF Rope.ROPEALL[NIL],
b: PRIVATE ARRAY [0 .. n) OF RECORD [
type: {setb, breakpoint},
united: BOOL,
offset: INTEGER,
p: [0 .. n)] ← ALL[[setb, FALSE, 0, 0]],
s: PRIVATE ARRAY [0 .. n) OF INTEGERALL[0],
indentation: PRIVATE INTEGER ← 0,
depth: PRIVATE INTEGER ← 0,
curLooks: PRIVATE TiogaAccess.Looks ← ALL[FALSE]
];
BufferOutputKind: TYPE = {stream, access};
BufferOutput: TYPE = RECORD [
variant: SELECT kind: BufferOutputKind FROM
stream => [stream: IO.STREAM],
access => [
access: TiogaAccess.Writer,
format: ATOMNIL,
nestWidth: INTEGER ← 1],
ENDCASE];
n: INT = 256;
Size of various internal buffers; plenty large for reasonable margins. Should be a parameter of the module but ....
END.