The JavaScript code works by DOM manipulations of
a top-level div
element, and assume that element
has a certain well-behaved form.
domtern-element
::= <div class="domterm">
domterm-toplevel
</div>
A top-level “DomTerm window” is a <div>
element
whose class
is domterm
.
domterm-toplevel
::= internal-div-elements
domterm-buffer
+ spacer
*
You don’t need to create domterm-toplevel
- it is created and managed by
DomTerm, based on data from the back-end.
domterm-buffer
::= <div class="interaction" buffer="name
">
block-content
* </div>
There are one or two domterm-buffer
elements,
for respectively the “normal” and “alternative” screen buffer.
These contain all the “actual” content.
If there is a single buffer, the name
is "main only"
;
if there are two buffers, the respective values for name
are "main"
and "alternate"
.
internal-div-elements
One or more invisible <div>
elements used by the implementation.
spacer
::= <div class="domterm-spacer"/>
Blank space at the bottom, used to support scrolling.
block-content
::= logical-line
| <div>
block-content
* </div>
| opaque-line
logical-line
:= <div class="domterm-pre">
line-content
* hard-nl
</pre>
<pre>
line-content
* hard-nl
</pre>
<p>
line-content
* hard-nl
</p>
A logical-line
is one or more “rows” (separated by soft-line
s),
consisting of character and other inline
data,
ending with hard-nl
representing an explicit newline.
The intent is that <div class="domterm-pre">
, <pre>
and <p>
are treated logically
the same, but <div class="domterm-pre">
(or <pre>
) will be monospace,
while <p>
can use other fonts and styling.
The line-breaking algorithm uses the width of the line,
not the number of characters, so it should also work for <p>
elements.
Normal terminal output will create <div class="domterm-pre">
elements,
rather than <pre>
, because Copy
command on some browsers (at least
current Firefox) adds extra newlines.
line-content
::= text
| <span>
line-content
* </span>
| soft-nl
| input-line
| other-content
hard-nl
::= <span line="hard">&#A;</span>
An explicit newline. Has a "\n"
text node as its sole child.
soft-nl
::= <span line="soft"></span>
An implicit newline, inserted by DomTerm when a line overflows.
Has no explicit text content, but CSS adds a "\n"
as before
content.
CSS by default also add a continuation arrow.
input-line
::= <span id="input1" std="input" contenteditable="true">
text
</span>
The location of the input cursor.
In char-mode the text
is empty. In line-mode contains
the current input line. Also used for previous input lines,
but without contenteditable
set.
Referenced by the inputLine
field of the DomTerm object.
opaque-line
A non-empty block-level element that isn’t navigable
at the level of rows and columns.
For example a <table>
.
It is treated as a single empty line.
This section discusses the mapping between the nested DOM structure and the terminal’s lines and columns.
In a well-formed tree, all line-breaks have the form
of <span>
element with a line
attribute.
The child of a <span>
element is either a text node
consisting of only a newline, or there are no children
(and a newline is added using CSS styling). Either way it is
treated as a single line-break.
Inserting HTML may also include <br>
elements and text
containing newlines. These are not handled consistently.
Ideally, we should convert newlines in pre
-style elements
to <span line="hard">
elements.
The last child of a non-empty block-level element (<div>
, <pre>
etc) should be either another block-level element or a line-break.
(We could also allow a <span>
whose last element is a line-break,
but isn’t clear if this is useful or desirable.)
Inserting HTML should insert if needed final line-break (though
it currently doesn’t). Alternatively, we can treat a missing line-break
as an implicit line-break; currently this is not handled consistently.
A “line” is then the text and elements between two (explicit or implicit) line-breaks.
“Opaque elements” include <img>
, <svg>
,
<object>
, and <iframe>
. These are treated
as single character, taking up a single “column”.
The “characters” of a line are those in text nodes in the line, plus opaque elements.
A command group is the set of input and output lines for a single user command.
command-group
::= <div class="command-group">
command-input-line
+ command-output
? </div>
Usually there is a single command-input-line
,
but there may be more than one if there are continuation lines.
command-input-line
::= <pre>
<span std="prompt">
prompt-text
</span>
<span std="input">
input-text
</span>
</pre>
A command-input-line
is logical-line
which (at least normally)
has the form of a prompt followed by the typed input command.
command-output
::= <div class="command-output">
block-content
+ </div>
The output from the command.
Normally, each block-content
is a logical-line
.
The <div class="command-output">
element may have the
domterm-hidden
attribute if it is hideable.
A hide/show button is a clickable toggle “button” that controls whether certain “associated output” is shown or hidden. For example the “associated output” of a shell command could be the set of output lines from the command. Initially, the output is in the shown state, and the button displays a “hide” icon. Clicking the button will hide output lines, as well as changing the button to display a “show” icon. Clicking the button again changes the icon to the “hide” icon and unhides the output lines.
<span std="hider"
[domterm-hiding="true"
or "false"
]>
hide-icon
</span>
This is a hide/show button. The hide-icon
is either empty or one of
the strings with odd-numbered index in DomTerm’s
showHideMarkers
property.
The value of the showHideMarkers
property is an array of strings,
where the even-numbers elements are “show” icons, and
the following odd-numbered elements are the corresponding “hide” icons.
It is suggested (but not required) that these icons be single
graphic characters.
Good choices are "\u25B6"
(▶
“black right-pointing triangle”)
for “show”, and
"\u25BC"
(▼
“black down-pointing triangle”) for “hide”.
The attribute domterm-hiding
must be "true"
or "false"
; if missing it defaults to "false"
.
Its value is flipped on each click,
If you are unsatisfied with the existing icon choices you can
either set showHideMarkers
to other strings,
or you can use CSS to change the look of the icons.
For example to use [-]
and [+]
use these CSS rules:
span[std="hider"][domterm-hiding="true"]:after { content: "[+]" } span[std="hider"]:after { content: "[-]" }
In this case, you probably want the hide-icon
text in
the <span>
to be empty.
The “associated output” for a hide/show button
is the set of sibling elements following the button,
as well as sibling elements of the button’s parent
(assuming that parent is a <pre>
or <p>
element).
Only elements that have the domterm-hidden
attribute are affected.
Hiding is done by changing the value the domterm-hidden
from
"false"
to "true"
; un-hiding changes it back to "false"
.
This is using a CSS style rule that sets the display
property
of an element to none
when domerm-hidden
is true
A future extension would allow lazy associated output: The initial state is hidden, and the back-end does not provide the output until it is requested, by clicking the hide/show button. Lazy output is useful for displaying and inspecting large (or even infinite) data structures, such as as a directory hierarchy or a complex object graph.
Xterm supports an “alternate screen buffer” which is used
by character-based programs like emacs.
Switching to the alternate buffer creates a new <div class="interaction">
,
with a buffer
attribute valued "alternate"
(and an id
attribute of the form
).
It is the sibling of the normal screen buffer,
which has a xxx
_alternatebuffer
attribute valued "main"
(with id
attribute of the form
).
This xxx
_normal<div>
contains one or more logical-line
s.
Returning to the normal screen deletes the <div>
for the
alternative screen, along with all of its contents,
and changes the buffer
attribute back to "main only"
.
<span class="pprint-group">
contents
</span>
A “logical block” of content that should be printed together,
on the same line, if possible.
If there is a prefix, it precedes the "pprint-group"
element.
If there is a per-line prefix,
it is in a <span class="pprint-prefix">
preceding element.
If there is a block suffix, it follows the "pprint-group"
element.
<span class="pprint-prefix">
per-line-prefix
</span>
A per-line prefix. This must be the previous sibling
of a <span class="pprint-group">
element.
It is displayed just before the logical group, and also
for each continuation line, at the same indentation.
<span class="pprint-indent" delta="num-chars
" />
<span class="pprint-indent" block-delta="num-chars
" />
<span class="pprint-indent" indentation="text
" />
Add extra indentation to following continuation lines.
A delta="
changes the indentation
to num-chars
"num-chars
characters relative to the current horizontal position.
A block-delta="
changes the indentation to
num-chars
"num-chars
characters relative to the start of the current logical block.
Specifying indentation="
specifies text
"text
as an extra per-line prefix.
The extra indentation is reset at the end of the logical block.
<span line="kind
" />
Represents a conditional newline of the specified kind
,
which can be fill
, linear
,
miser
(currently the same as fill
),
or required
.
indentation
::= <span class="pprint-indentation">..</span>
These represent actual calculated indentatation. They are only inserted when and if a line-break is inserted, and removed if the line-break is removed.
<span line="kind
" line-attribute
... > [pre-break-child
] [non-break-child
] [indentation
] [post-break-child
] </span>
line-attribute
::= breaking="yes|no" | pre-break="pre-break-text
" | post-break="post-break-text
"
pre-break-child
::= <span class="pprint-pre-break">contents
</span>
post-break-child
::= <span class="pprint-post-break">contents
</span>
non-break-child
::= <span class="pprint-non-break">contents
</span>
A generalized optional line-break. You can specify contents to
insert before the break (when there is a break) either with
a pre-break
attribute or with a pprint-pre-break
element.
Similarly, content after the break
can be specified using either a post-break
attribute
or a pprint-post-break
element.
(The indentation
, if any is automatically inserted before the post-break-content.)
To specify contents to be used when there is no break,
use a pprint-non-break
element.