Line Layout Text Content¶
Field |
Value |
|---|---|
Status |
Draft |
Related RFC |
|
Related drafts |
Styled text content, Content representation, Plain text content, Operations, Capability negotiation, Terminal-native behavior, Concrete message schemas, Error codes |
This document defines text/lines, an optional content type: styled text
organized as lines, each with layout attributes the terminal applies at every
width. Capability Negotiation governs how a terminal
advertises it and how a TUI selects it. It complements
text/styled rather than replacing it: a terminal that
implements only styling advertises text/styled, and a TUI prefers
text/lines when both are confirmed.
1. Lines and Logical Text¶
A text/lines value is an ordered list of lines. Each line carries a span
list following the span and style rules of Styled Text
Content, except that span text contains no line break
character (LF or CR), and optional layout attributes. An empty line list is
empty content; a line with an empty span list is an empty line.
The Block’s logical text is the line texts joined by LF. Tabs and visible control labels follow Plain Text Content.
2. Wrap Mode¶
wrap selects how a line wider than the display breaks into rows:
word(the default): the terminal breaks at break opportunities. At minimum, a break opportunity follows each run of spaces and lies between any two adjacent wide (two-cell) characters. A word wider than the available width breaks between cells. Spaces at a break are not displayed but remain logical text. Terminals may use a fuller algorithm, such as Unicode line breaking.char: the terminal breaks between cells, as fortext/plain.
Rows created by wrapping are soft: they add no logical line break and no copied text.
3. Continuation Prefix¶
continuation is an optional span list displayed at the start of every
soft-wrapped row of the line, before the wrapped text. It is presentation:
it is not logical text, not matched by search, not counted by
ReplaceSuffix, and not copied. The prefix of a line’s first row is ordinary
span text. When the continuation leaves no width, the terminal omits it for
that row rather than failing.
4. Fill Line¶
A line with fill carries exactly one span whose text is one grapheme; the
terminal repeats it across the display width in whole cells, recomputed on
every reflow. Its logical text is that grapheme once, and copy yields it
once. A fill line carries no wrap or continuation.
A fill line has no maximum width: it always spans the full display width. An application that wants a shorter rule sends ordinary text instead; a width limit, if one is ever needed, would be a separate optional attribute.
5. Incremental Editing¶
Extend carries a non-empty line list. Its first line’s spans append to the current last line, whose attributes stay unchanged; that first line must not declare attributes. Each further line is appended with its own attributes. A fill line receives no further text; a fragment whose first line is empty may follow it with new lines. Extending empty content appends the lines as given.
ReplaceSuffix counts its retained prefix in Unicode scalar values of the logical text, LF separators included. The line containing the boundary is truncated with the span rule of Styled Text Content and keeps its attributes; the replacement line list, which may be empty, follows the Extend rule. A boundary at the end of a line, before its separator, removes all following lines.
Update replaces the complete value and may change the content type to any confirmed type. Seal is unchanged.
A fragment or replacement on a text/lines Block is a line list; on other
Blocks its shape follows their own type. A shape that does not match the
Block’s current content type is a content-validity failure.
6. Terminal-Native Projections¶
Selection, copy, and search operate on the logical text. A selection across soft-wrapped rows copies the text between its ends, including spaces dropped at a break, and no continuation prefix or line break; a selection starting inside a prefix starts at the row’s text. Search matches the logical text across soft breaks and never matches a prefix. Reflow changes only rows; a reading anchor bound to a logical position stays bound to it.
7. Failure Reporting¶
Reporting follows Content Representation. For
text/lines:
A malformed type field, a non-array line list, a line that is not an object, a line without a
spansarray, a field other thanspans,wrap,continuation, andfill, a non-stringwrap, a non-arraycontinuation, a non-booleanfill, or a span violating the span schema is a schema violation and reportsinvalid_message.A structurally valid value violating this type’s content rules reports
invalid_content: any span or continuation rule of Styled Text Content, a line break in span or continuation text, awrapother thanwordorchar,fillpresent but nottrue, a fill line with attributes or without exactly one single-grapheme span, a first fragment line that declares attributes, or text extending a fill line.Receiving
text/linescontent that was not confirmed reportsunsupported_content_type.Incremental Operations keep the existing
content_state_mismatchandinvalid_content_boundarysplit.
Every failure leaves the Block’s content, lifecycle, and content-state identifier unchanged.
8. JSON Mapping¶
In the initial JSON serialization, the content snapshot is:
{ "type": "text/lines", "data": [ line, ... ] }
line = {
"spans": [ span, ... ],
"wrap": "word" | "char" ?,
"continuation": [ span, ... ] ?,
"fill": true ?
}
span is the span of Styled Text Content.
For a Block whose current content is text/lines, block.extend’s
fragment is a non-empty line array and block.replace_suffix’s
replacement is a possibly empty line array. A non-empty array whose first
element has a spans field is a line array; otherwise it is a span array,
and an empty array is a valid empty replacement for either. Schema-level
validation checks structure only; the rules of section 7 that are not
schema rules are content semantics.
Open Design Choices¶
Break opportunities for scripts that neither use spaces nor render as wide characters, such as Thai.
Whether code needs a non-wrapping mode with horizontal truncation.
Experimental Evidence¶
The codec tests round-trip line snapshots, line fragments, and line replacements, and reject structural violations with their Operation identity.
The Session tests cover advertisement,
unsupported_content_type, eachinvalid_contentrule, line-aware Extend and ReplaceSuffix, and type switching through Update.The line layout prototype implements sections 2–4 and the projections of section 6; Pi 0.87.1’s output converted to
text/lineslays out exactly as Pi renders it at every width from 20 to 100 columns for a Chinese and nested-list sample.The xterm lines host and the region-aware host in the Pi stock-UI trial execute the type end to end, browser-verified, including copy, search, and reading position across resizes.