[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Issue: STREAM-INFO (Version 4)
- To: CL-Cleanup@SAIL.STANFORD.EDU
- Subject: Issue: STREAM-INFO (Version 4)
- From: Kent M Pitman <KMP@STONY-BROOK.SCRC.Symbolics.COM>
- Date: Fri, 24 Jun 88 13:57 EDT
- Cc: DICK@WHEATIES.AI.MIT.EDU
Don't panic -- Versions 1-3 were circulated between Dick Waters and myself
and did not reach this list. This is the first version CL-Cleanup should
have seen.
Also, please be sure to cc Dick@WHEATIES.AI.MIT.EDU in any correspondence
on this issue since he's not on CL-Cleanup.
-kmp
----------
Issue: STREAM-INFO
References: FORMAT ~T (pp398-9) and ~<...~> (pp404-6), PPRINT (p383)
Category: ADDITION
Edit history: 22-Jun-88, Version 1 by Pitman (2d model)
23-Jun-88, Version 2 by Waters (1d model, modified 2d model)
24-Jun-88, Version 3 by Pitman (minor reformatting)
24-Jun-88, Version 4 by Pitman (remove 2d model for submission)
Status: For Internal Discussion
Problem Description:
Currently, there is no portable way to inquire about the line width
of an output stream, the current character position on a line
or the amount of space that the display of a string will take up.
This makes it essentially impossible to write a portable
implementation of a pretty printer.
Proposal (STREAM-INFO: ONE-DIMENSIONAL-FUNCTIONS):
Introduce four new functions:
OUTPUT-WIDTH &optional (OUTPUT-STREAM *STANDARD-OUTPUT*) [Function]
Returns the maximum line width that can be printed on the
OUTPUT-STREAM without causing truncation or wraparound. The
result is returned as a non-negative integer, or NIL if the stream
has no meaningful width (or the width cannot be computed). The
unit of width is arbitrary, however, given a particular output
stream, the unit must have some fixed value.
OUTPUT-POSITION &optional (OUTPUT-STREAM *STANDARD-OUTPUT*) [Function]
Returns the current horizontal position of the cursor on the given
OUTPUT-STREAM as a non-negative integer, or NIL if it cannot be
computed. (The position is the position of the distance of the
left edge of the cursor from the left margin. I.e., 0 means
cursor is at the left end of a line.) The units are arbitrary,
but for a given stream, they must be the same as the units used by
OUTPUT-WIDTH.
STRING-WIDTH STRING &optional (OUTPUT-STREAM *STANDARD-OUTPUT*)
&key (START 0) (END NIL) [Function]
The START and END parameters delimit a substring of string in the
usual manner. STRING-WIDTH returns the change in output position
that would occur if STRING were written to OUTPUT-STREAM using
(WRITE-STRING STRING OUTPUT-STREAM :start START :end END) given
the current state of OUTPUT-STREAM or NIL if the change cannot be
computed. The returned value is an integer. The units are
arbitrary, but for a given stream, they must be the same as the
units used by OUTPUT-WIDTH. STRING-WIDTH satisfies the following
constraint.
(LET* ((STREAM ...)
(STRING ...)
(CURRENT-X (OUTPUT-POSITION STREAM)))
(= (STRING-WIDTH STRING STREAM)
(- (PROGN (WRITE-STRING STRING STREAM)
(OUTPUT-POSITION STREAM))
CURRENT-X)))
STRING-WIDTH does not return any indication of the vertical
distance required when printing string. Merely the difference in
horizontal position before and after printing. This difference
may be negative (e.g., if STRING contains backspace or newline
characters.) It is possible that the width of a string will
depend on the horizontal position where output begins (e.g., if
the string contains tab characters.) If this is the case, the
width returned assumes that the output occurs starting at the
current horizontal position in the stream. Similarly, the width
of string may depend on other aspects of the state of
OUTPUT-STREAM (e.g., the font being used). In all respects the
width is computed based on the current state of the stream.
STRING-WIDTH never causes any change in the state of OUTPUT-STREAM.
OUTPUT-SPACE WIDTH &optional (OUTPUT-STREAM *STANDARD-OUTPUT*) [function]
This function causes blank space to be inserted in OUTPUT-STREAM
so that the output position is increased by WIDTH. WIDTH is an
integer. The units are arbitrary, but for a given stream, they
must be the same as the units used by OUTPUT-WIDTH. A negative
WIDTH parameter indicates backspacing. The unit of WIDTH should
be chosen so that it is possible to move the output position left
and right by a single unit. OUTPUT-SPACE satisfies the following
constraint.
(LET* ((STREAM ...)
(N ...))
(= (+ (OUTPUT-POSITION STREAM) N)
(PROGN (OUTPUT-SPACE N STREAM)
(OUTPUT-POSITION STREAM))))
OUTPUT-SPACE returns T if the spacing operation has been achieved
and NIL otherwise (e.g., if the requested spacing would move off
of the end of the line or if the the operation cannot be supported
for the given stream.)
A key motivation behind the functions above is dealing with
output streams that support variable length fonts. The unit of
width is allowed to vary from stream to stream in order to allow
for differences between output devices. The only thing that
matters is that the four functions above operate on the same units
when given the same stream.
If an output stream only supports a single fixed width font, the
logical choice of width unit is the length of a single character.
In this situation (and ignoring characters such as tab, newline,
and other control characters that do not have an output width of
one) the functions above have the following simple meanings.
OUTPUT-WIDTH returns the maximum number of characters which can be
printed on a single line. OUTPUT-POSITION returns the number of
characters which have already been printed on the current line.
STRING-LENGTH returns the number of characters in the string.
OUTPUT-SPACE prints the specified number of space, or backspace,
characters.
Another key feature of the functions above is that they are all
permitted to return NIL without performing any action. This is to
allow for the fact that the required operations might not be
supported for every kind of stream. However, it is hoped that the
functions would in fact be supported for most kinds of streams.
Test Case:
Suppose that S is an output stream that supports a single fixed
width font which can display 72 characters on a line and that the
associated width unit is the width of one character. Evaluating the
following will produce the results shown.
(output-width S) => 72
(terpri S)
(output-position S) => 0
(string-width "testing: " S) => 9
(write-string "testing: " S)
(output-position S) => 9
(write-string "foo" S)
(terpri S)
(output-space 9 S) => T
(write-string "bar" S)
The output produced is
testing: foo
bar
Rationale:
Pretty printing requires the function OUTPUT-WIDTH in order to know
how wide the output it produces can be. Pretty printing requires
OUTPUT-POSITION in order to determine where on the line output is
when pretty printing starts. Pretty printing requires STRING-WIDTH
in order to determine how much space things will take in the output.
(If a variable width font is being used, this cannot be determined
without a detailed knowledge of the font being used.) Pretty
printing requires OUTPUT-SPACE in order to get proper indentations.
(If a variable width font is being used, indentations may be
required that cannot be obtained by outputting spaces.)
Current Practice:
Essentially every implementation of Common Lisp must support the
functionality above internally in order to support PPRINT and the
FORMAT directives ~T and ~<...~>. However, there is no documented
interface to this functionality in CLTL. As a result, while some
implementations of Common Lisp make this functionality available to
users, some do not. Further, the implementations that do provide
this functionality do so in a variety of incompatible ways.
Cost to Implementors:
This proposal is written in such a way as to allow implementations which
do not have the ability to compute difficult values to just return NIL.
Very little work is forced. The idea is to offer implementors a common way
to provide this useful information to portable programs where possible.
Cost to Users:
None. This change is upward compatible.
Cost of Non-Adoption:
Complex output programs such as pretty printers cannot be written portably.
Benefits:
A wide range of programs can gain better control of the format of output.
Aesthetics:
No significant aesthetic impact other than a slight increase in the
number of functions defined.
Discussion:
Dick Waters submitted a request for changes along the line of the
horizontal aspects of these functions in a letter to X3J13 dated
June 14, 1988. Pitman and Waters wrote up the request formally.
STREAM-INFO:ONE-DIMENSIONAL-FUNCTIONS is the minimum which is
required in order to support pretty printing into a stream which
displays output using a variable width font.
We drafted an alternate proposal, STREAM-INFO:TWO-DIMENSIONAL-FUNCTIONS,
which goes significantly beyond what is needed merely for pretty printing
and provides primitives OUTPUT-DIMENSIONS, OUTPUT-POSITION,
STRING-DIMENSIONS, and OUTPUT-SPACE but it is not included here.
A key point of contention which would be likely to swamp the 2d proposal
is the age old question of how to handle the issue of vertical distance
(where is the origin, which way do you count, ...). If anyone would
prefer to see larger problem 2d proposal, it could be circulated, but at
the last minute Pitman got worried that even the 1d version was going to
be controversial enough and decided to keep things focused on that.
For his own needs, Waters is strongly interested in having either
ONE-DIMENSIONAL-FUNCTIONS or TWO-DIMENSIONAL-FUNCTIONS proposal accepted,
but does not care which. Pitman concurs.
One variation of the 1d proposal might be useful to consider:
STRING-WIDTH could return two additional values: the number of newlines
that WRITE-STRING of the string would execute and the maximum X position
encountered (which might differ from the first value if the number of
newlines was non-zero).
This feature wasn't necessary for Waters' minimalist proposal, but Pitman
would be willing to write it in here if people thought it would be useful
enough for other purposes.