| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
| |
|
| |
|
|
|
|
|
| |
This should make the code a bit more readable, hopefully. Also
simplify the conditions while we're at it.
|
|
|
|
|
|
|
| |
This makes the huge SGR parsing conditional more readable, also it is
now easier to distinguish between unsupported and non-standard (and
thus technically invalid) SGR parameters if we ever want to do
something with that information.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sequences with colons are used when only the first parameter
determines the kind of SGR event caused by the sequence and the rest
of the parameters are additional arguments. This means that the
arguments can contain numbers which are meaningful by themselves, like
0 (reset).
This means that if such a sequence is not supported by saneterm we
previously erroneously interpreted arguments in such a way that we
generated wrong events. This happened for example in vte's sgr-test.sh
which relied on kitty's non standard underline escape sequences which
we don't support at this time:
https://sw.kovidgoyal.net/kitty/protocol-extensions.html#colored-and-styled-underlines
|
|
|
|
|
|
|
|
|
| |
A TypeError is raised in Color.__init__() to show that the color
constructed is invalid. In parse_extended_color() this is a parse
failure and should cause an AssertionError instead.
Take this opportunity to refactor the (parse) error handling in this
function to use a single try … except statement.
|
|
|
|
|
|
|
|
|
| |
This breaks up the deeply indented blocks which implemented this in
pty.Parser.parse() before. It also allows us to simplify the control
flow a bit: The two nested try … except blocks for StopIteration (to
detect if we need to postpone parsing) and AssertionError (to detect
if we don't understand what looked like an escape sequence or handle
other parse errors) into a single one.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This script emits most of the SGR escape sequences supported by
saneterm, so rendering of them can easily be tested. It is not a
perfect test case since it only emits nested sequences in a limited
fashion.
Similar test tools:
* sgr-test.sh from vte:
https://gitlab.gnome.org/GNOME/vte/-/blob/c17e6d12da00a94c3768be6671182a6a039ec0c0/perf/sgr-test.sh
* 256test.sh from vte:
https://gitlab.gnome.org/GNOME/vte/-/blob/c17e6d12da00a94c3768be6671182a6a039ec0c0/perf/256test.sh
* msgcat --color=test from gettext (only uses 16 colors, sequences for
some text styles are broken like italic and underline sometimes)
* lolcat -t [-i] is useful for testing true color support
|
|
|
|
|
|
|
|
| |
* Add a shebang and make the tests.py skript executable
* Document how to run the tests in the README
* Add docstrings to the tests (which are displayed with -v)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This change addresses the previous layer violation mentioned in a
previous commit: Instead of inflating the Parser code by tracking
state which is not necessary for parsing, we now just emit events
describing text style changes in the parser code. The necessary
updates to actual display state is then handled in the Terminal
object.
We use this to map the changes to display style introduced by events
to _individual_ TextTags instead of creating a composite TextTag for
every styled stretch of text.
This makes TextTags reusable since they are less specific: Instead of
a single italic, green background and bold face tag, we now have three
different ones which are quite likely to occur again. Thus we'll store
(references to) already created tags in a dictionary to be reused.
Note that we can't use Gtk's TextTag lookup mechanism which allows to
reuse TextTags in the TextTagTable of a buffer by name since this
would not allow us to create TextTags on demand. Precreating all 13824
possible color tags is of course not an option.
While this change doesn't bring a big performance improvement it
should prevent performance from degrading over time since it limits
the number of tags being created, allocated and managed in the Gtk
TextBuffer.
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
SGR (Select Graphical Representation) escape sequences are CSI escape
sequences ending in the final byte 'm'. They are described in the
ECMA-48 standard, but we also support a compatible extension which is
commonly used nowadays, namely extended colors (256 colors and true 24
bit colors) which are specified in ITU-T Rec. T.416.
SGR sequences are probably the most commonly used escape sequences and
a lot of CLI tools now feel much more familiar in saneterm. The
implemented SGR sequences for example allow:
* to change the current text's foreground and background color in the
three commonly used color modes 8/16 colors, 256 colors and 24 bit
true color.
* to change the current text's appearance: italic, bold, underline,
strikethrough and more are supported.
The current implementation uses a new TextStyle object which is added
to pty.Parser's state to track the inherintly stateful changes in text
appearance described by SGR escape sequences.
When the TextStyle object changes, a TEXT_STYLE event is emitted and
the a Gtk.TextTag is created from the TextStyle and registered in the
widget's TextBuffer.
For the most part this is quite straightforward, just two areas
deserve more attention:
* The extended colors (256 colors and 24 bit true color) are a bit
more complicated to parse which is handled by parse_extended_color().
This function doesn't fully support everything the recommendation
mandates. Especially true color will need more real world testing,
e. g. lolcat(1) a heavy user of true color doesn't even emit true
color escape sequences conforming to the standard.
* Color handling in general contributes to most of the complexity:
* There are three ways to specify colors via SGR escape sequences
we support which all need to be converted to Gdk.RGBA objects.
This is handled by saneterm.color.Color. True color is trivial,
for 256 colors we implement the conversion instead of generating a
lookup table (like XTerm does). For the 8 basic colors in their
normal and bright variants, we use hard coded list of X11 color
names for now. This probably should become configurable in the
future.
* Many implementation use the intensity escape sequences to
influence color vibrance: SGR 2 is interpreted as dim wrt
to colors and SGR 1 not only makes the text bold but also
chooses brighter colors. So far we interpret SGR 1, 2 and 22
only in terms of font weight. EMCA-48 permits both. Changing the
color intensity as well increases complexity and has little
benefit, so this should probably be kept this way.
* Instead we implement the 90-97 and 100-107 non-standard bright
color SGR escape sequences.
The current implementation is, however, not without issues:
* Tracking the text style state in the parser is probably a layer
violation — pty.Parser should instead translate the escape sequences
into events and the state tracking done in saneterm.terminal.
* Performance is poor if a lot of escape sequences are in the input.
This is due to two reasons: a) insert_data is called with little
chunks of text which decreases performance and b) a lot of anonymous
Gtk TextTags are created which hurts performance a lot. We should
investigate a way to deduplicate the created TextTags (by using
names?) and possibly decouple the application of tags from the
insertion of text itself.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add a parser for CSI escape sequences as specified in ECMA-48 (5th
edition). All other escape sequences starting with \033 (like OSC
escape sequences) aren't supported yet and will be added to the
terminal's buffer like before.
No CSI escape sequence generates a dedicated event so far, the only
effect of them being parsed is that they are omitted from the output
in the terminal. This makes the output of programs making heavy use of
e. g. SGR escape sequences much more readable.
If the end of input is hit while parsing an escape sequence, we
postpone parsing it until the next invocation of parse().
Additionally we rely on backtracking to deal with unknown and invalid
escape sequences: By setting a hint that the sequence is to be ignored
and backtracking, the rest of the parser behaves normally and emits
the invalid/unknown sequence as normal text.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The next step for pty.Parser will be to support parsing ANSI CSI
escape sequences which consist of multiple codepoints, but need to be
treated as an unit.
Thus we need to be able to push some unparsed input to the next
invocation of parse(). The way I've chosen to support this is by
supporting backtracking in an iterator which wraps the input string.
This way we'll be able to keep consuming input from the iterator in
the main for loop, but can backtrack in case we hit the end of input
or encounter a parse failure.
I opted to implement this iterator in the form of an object that
tracks an index into a string. For one this feature also helps us in
the parser: We need to track the current index anyways and it is also
helpful for checking if the end of input has been reached.
Additionally this seems like the only feasible way to implement such a
backtracking iterator wrapper: The other alternative would've been to
copy.deepcopy() the iterator at a point we may want to return to —
however this is not practical as deepcopy will hit a recursion depth
error with the moderately sized chunks of input we handle in parse().
This commit introduces the new iterator and adapts our parser code for
it and lays the groundwork for resuming from unparsed input of a
previous invocation of parse(). Additionally it also ships a set of
unit tests for the iterator, many methods of which are still unused in
the main parser code.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This commit introduces a new object, the PtyParser, which will be
handling pty input in the future. It receives (utf-8 decoded) input
and emits a series of events which encode pty output we want to
represent in the UI:
* The most basic event type is TEXT which is plain text we need to add
to the TermBuffer.
* Additionally BELL is now supported which indicates we want to beep
(if enabled in gtk) and set the urgency flag of the window.
Events seems to be a simple way to indicate future special behavior
and by splitting the data read from the pty we can easily skip control
characters which we don't want to render (and thus get rid of ugly
codepoint boxes). Due to the use of yield and string slices, this
approach should also be efficient enough.
Using events instead of triggering the desired action in handle_pty
ad-hoc also has the advantage that we can split the parsing logic into
a separate object which is interesting for the following reasons:
* Especially when we want to support a subset of ANSI control
sequences we'll need to track parser state:
- ANSI escape sequences are multiple codepoints long, so we need to
track a parser state in order to keep it incremental.
- ANSI escape sequences allow changing the font properties (style,
weight, color) which is implemented in a stateful way, we'll also
need to keep track of.
* The parser is implemented independently of the rest of the
application and especially the UI, so we'll be able to unit
test it easily.
|
|
|
|
|
|
|
| |
This is basically yet another workaround for a bug in Gtk since Gtk
pastes the secondary clipboard by default. However, since every terminal
emulator I have used in the past pastes the primary clipboard on
Shift-Insert saneterm should too.
|
|
|
|
| |
More accurate since it also handles copy/paste stuff now.
|
|
|
|
|
|
| |
This way, the search_entry itself is not unfocused and key combinations
like ctrl+g and ctrl+shift+g, which cycle through matched strings,
continue to work.
|
|
|
|
|
|
| |
This is what most applications (with the exception of firefox) do.
Notably, this is also what evince does which inspired the design of the
current search bar version.
|
|
|
|
|
|
| |
Currently there are still some focus issue, i.e. if the button are
pressed these are focused and the Ctrl+G/Ctrl+Shift+G keybindings no
longer work. That will be fixed in a future commit.
|
|
|
|
|
| |
Currently, the tilde character is not replaced by $HOME in the file name
which may cause issues with application not expanding tilde themselves.
|
| |
|
|
|
|
|
| |
* Fix Gtk.TextIter movement
* Only handle movements of type WORD_ENDS for now
|
|
|
|
| |
This is a horrible workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/317
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
| |
Most REPLs will write a new prompt on newline but when starting a
graphical application from a shell (e.g. gitk) no output will be written
to the PTY after the newline. This causes _last_mark to not be updated
and causes cursor_at_end to always return False making it impossible to
quit the application using termios.VINTR.
|
| |
|
|
|
|
|
|
| |
I find it somewhat unpleasent to heavily rely on the mouse. Especially
considering that toggeling autoscroll is something I do a lot (e.g. when
using cat(1) on a text document).
|
| |
|
|
|
|
|
| |
Unfortunately, it does not seem to be possible to hide the scrollbar
using the standard Gtk CSS configuration mechanism.
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
| |
Still lacking some configuration options (highlight all, case
insensitive search, …) and focus is not currently restored to the
TermView on close currently.
|
| |
|
| |
|