Graphical that renders text in a terminal-style buffer with ANSI cell
colouring, a hardware-style cursor, scrollback and selection. Used to
embed a terminal view (REPL output, command transcripts, child process
I/O, …) inside an xpce frame. Subclass of graphical.
A terminal_image keeps a ring buffer of rendered cells (size
terminal_image<-save_lines),
exposes the visible region as a scrollable area with an associated terminal_image<-scroll_bar,
and emits high-level events for keystrokes and hovered hyperlinks.
<-font
if @nil.<-font
if
@nil.<-italic_font,
then terminal_image<-bold_font,
then
terminal_image<-font.style applied to selected cells.style applied to the hit of an incremental search, in place
of
terminal_image<-selection_style,
so that what a search found can be told from what the user picked with
the mouse.style applied to the matches on the screen other than the
one the user is on, or @nil
to leave them alone. It serves an incremental search and a selection
alike: what a search is looking for while one runs, and otherwise the
selected text (see terminal_image<-selection_string).
Only the visible ones: they are worked out afresh every time the window
is painted, so scrolling brings the ones it reaches into view without
the search or the selection doing anything about it..g.
accented composed characters), or @nil
to disable highlighting.colour objects: the 8 base ANSI colours
followed by their bright variants..e. in
the left margin beside a command whose output can be hidden.terminal_block objects,
oldest first. Empty unless the client marks its prompts; see class
terminal_block.->bubble_scroll_bar).->typed
normally does. @nil
unless an incremental search is running.->selection;
it is also what terminal_image->isearch_selection_forward
searches for.<->search_word,
or a selection made by double clicking a word. A search takes this from
the selection it was seeded with; one started with \C-\S-f
has no selection to take it from. This, not terminal_image<->search_word,
is what the window should show as the state of a Word box, so
that the box says what the tally beside it was counted with.<-syntax.
Both decide what counts as a match for a selection as well as for a search. Both outlive the search that used them, and setting either looks again at once, so the hit or the selection, the tally and what is painted all follow.
A selection can ask for whole words on its own account -- see
terminal_image<-match_word
-- so turning terminal_image->search_word
off also takes that back: the setting means what it says.
font, keeping its family and size. A variant
that does not advance by the same amount as font is
rejected with a message and set to @nil:
the cell grid is measured from the regular font alone, so a variant of
another pitch would not line up with it.->event
on the activate_keyboard_focus and
deactivate_keyboard_focus events. The default
implementation enables or disables the platform text input (the input
method), stops an incremental search -- it lives off the keyboard --,
updates the caret and, if the client asked to be told about the focus (CSI ? 1004 h),
sends it CSI I or CSI O.
A subclass may refine this to react on the terminal gaining or losing the focus. A refinement should call the super method to keep the above in sync.
Note that this is not graphical->keyboard_focus,
which works the other way around: it asks the window to give the focus
to this object.
s (super, Apple ⌘) or the event
has both shift and control modifiers active and the key is
handled as an accelerator, we are done.
continuation is the k=s
of a secondary prompt,
i.e. the client is collecting another line of
an input it has not finished. The default implementation is what builds terminal_image<-blocks.
A subclass may refine this to act on what its client is doing; class
prolog_terminal does, to fold the command before the one
being entered. A refinement must not write to the terminal or destroy
it: the escape sequence it arrived in is still being parsed, and
output of its own would move the very lines and blocks that parse is
holding.
->fold.<-foreground_process
reports none, leaving the interrupt to a subclass whose client is not a
process of its own.->interrupt.Selecting text says what to look for as well as what to copy. The
other places the selected text occurs on the screen are painted in
terminal_image<-isearch_other_style,
the way the other matches of an incremental search are, so that picking
out a variable or an atom finds the rest of them without typing it
again; terminal_image<->exact_case
and terminal_image<->search_word
decide what counts as one. What it reports -- through visual->report,
like a search -- says which of the matches the selection is and how many
there are, as Selection: X (2/5), counted over the whole
buffer while what is painted is the page.
Double clicking picks a word, and that says to look for the word
rather than for the letters it happens to be made of: matching is
whole-word for such a selection whatever terminal_image<->search_word
stands at (see terminal_image<-match_word),
so a double click on Bar passes over Barn while
dragging over the same three characters does not. It also makes a
one-character word worth looking for.
Not every selection is looked for, and terminal_image<-selection_string
says which are. A selection that occurs nowhere else says nothing and is
painted as a plain selection. Neither is one that is blank, that runs
over a line break, that is longer than 100 characters, or that is a
single character while terminal_image<-match_word
is @off --
each of those would light up most of the screen. Nor is anything looked
for on the alternate screen, whose lines are not in the buffer.
What is looked for is the text under the selection as it is now: a client that repaints or erases the screen changes what a selection holds without moving it, and the matches follow.
->selection)
are the ones this walks. From there it is the ordinary search below, ^S
and ^R included. \C-s and \C-r
are bound to these.
Fails when there is no such selection, and a binding that fails hands
the key on: without one, ^S and ^R mean to
whatever is reading from the terminal what they always meant, which for
the line editor is its own history search.
^G gives back the view and the selection the
search started from, so a search one did not mean to start costs
nothing.
index into view, moving as little
as possible and doing nothing while the line is already on the screen.
Fails on the alternate screen and on an index out of range.\C-\S-f is bound to
terminal_image->isearch_backward,
as a terminal's history lies behind the caret. While the search runs it
has every key (see
terminal_image<-focus_function):
The hit is painted in terminal_image<-isearch_style
and the other matches on the screen in terminal_image<-isearch_other_style.
A search owns that feedback while it runs, so the selection's own
matches (see terminal_image->selection)
are not shown as well; leaving a search with the hit selected hands them
straight over. What it reports as it goes -- through visual->report,
so where that lands is the window's business -- says which of the
matches it is on and how many there are, as
(3/4). Those are counted over the whole buffer, and from
its start whichever way the search is going, so a search backwards
begins at the last of them and counts down. Every place the string
occurs counts, overlapping ones included: a repeat steps a single
character, so those are places the search can get to.
,^S^RThe next hit, forwards resp. backwards Backspace Drop a character and search again ^WTake the word behind the hit into the search string, along with whatever separates the two, so that pressing it again walks on word by word. Not across a line: a search string with a line break in it matches almost nothing M-cTurn terminal_image <->exact_case on or offM-wTurn whole-word matching on or off, as terminal_image <-match_word reports it^GGive back the view and the selection the search started from Escape, Return Leave the search with the hit selected Any other key Leaves the search, and then means what it usually means
A search that started from a selection (terminal_image->isearch_selection_backward)
differs in one way: ^G puts that selection back rather than
leaving none.
Two things differ from editor->isearch_forward. Escape
and
Return are swallowed rather than passed on: an unhandled key
here reaches the process on the terminal, and leaving a search is no
reason to submit a line to a shell. ^C is the exception
that proves it -- it ends the search and then interrupts, or a search
started over a running program would trap the interrupt.
Running out of hits only says so; the attempt after that starts over at the far end of the buffer. A search refuses to start on the alternate screen, whose lines are not in the buffer, and an application that claims the screen ends one that is running.
.g. from an
OSC 0 sequence.
.e.
of the process running in the terminal. Fails if there is none, which is
the case while the terminal is driven by a thread of this process. While
it succeeds the control keys are passed to that process rather than
looked up in terminal_image<-bindings.
Unix only.point(col, row).|event -> name<-find
does and with the same defaults: case sensitive, ignoring word
boundaries, and -- note -- reporting the end of a match going
forwards and its start going back. A negative times
searches backwards. from outside the buffer is clamped to
the nearest end. Fails if there is no match.
Unlike text_buffer<-find,
a repeat starts one character past the match it found, so times
greater than one reaches the hits after the first.
from.<-id, or
fail if it has scrolled out of the buffer.|point|event -> terminal_block|event -> terminal_block.e.
fails unless the position is in the left margin beside a command whose
output can be hidden. What tells a click or a popup on the marker from
one on the text.column of the visible row:
the selection, the hit of an incremental search, one of its other
matches, or the hyperlink under it. Fails when the cell is drawn from
its own attributes, which is to say from the colours and the bold or
underline the client asked for.
This goes through the very computation the painter uses, so it is not a second opinion about what should be drawn. It says nothing about what has actually been drawn yet: a cell whose line has not been repainted since still shows what it showed before.
code occupies when drawn
in
terminal_image<-font:
0 for combining marks, 2 for wide characters and 1 for the rest. This is
the classification the renderer itself uses, so clients that must
predict our layout can share it rather than keep a second copy that
drifts. In particular it accounts for symbol and emoji code points that
the static Unicode tables call width 1 while an emoji-presenting font
draws them twice as wide. Fails while the terminal has no cell metrics
yet.
terminal_image<-find, terminal_image<-length, terminal_image<-contents, terminal_image->selection
and terminal_image->scroll_to
address the buffer as a flat sequence of characters. Index 0 is the
first character of the oldest line still kept. A wide character counts
once, and the cell holding the right half of it not at all; a combining
mark counts on its own. Lines are separated by a single newline, except
that a wrapped line and its continuation are not separated at all --
terminal_image<-selected,
which hands text to another program, uses \r\n instead.
Indices are relative to the oldest line still kept and shift
whenever output pushes lines out of the scroll-back. One is only
good until the client writes again; terminal_block<-id
is the handle that outlives them. These methods do not see the alternate
screen: the lines an application replaced left the buffer, and while it
is up they see the scroll-back that came before it.
The output of a command that has finished can be taken off the
display with terminal_block->fold,
leaving the command that produced it with a triangle in the left margin
and a tally of what is hidden. A click on the triangle toggles it;
unlike a hyperlink it needs no modifier, because the marker belongs to
the terminal rather than to the client.
Folding is a property of the view and not of the text. terminal_image<-contents,
terminal_image<-find, terminal_image<-selected
and terminal_image->select_all
keep seeing what a fold hides; only what is painted, the rows a click
maps to and the scrollbar leave it out. terminal_image->scroll_to
opens a fold it lands in, as does an incremental search whose hit is
inside one.
Closing a fold takes rows out of the window, so a window that was showing the end of the buffer is pulled back to go on showing it. One the user has scrolled away from stays where they put it.
terminal_image<-fold_at
says whether a position is on a marker, which is what lets a popup on
the marker be about the one command it stands beside rather than about
the terminal. Class prolog_terminal uses it for terminal_image->block_popup.
tt,
boldtt, itt and bitt.
white and black.