From 9fe631ee3f55e6795c6dd3e8e8c4383c19630dd6 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Fri, 29 May 2020 01:05:49 +0300 Subject: [PATCH 1/3] Provide support for CSI REP control code --- kitty/control-codes.h | 3 +++ kitty/line.c | 5 +++++ kitty/lineops.h | 1 + kitty/parser.c | 2 ++ kitty/screen.c | 19 +++++++++++++++++++ kitty/screen.h | 1 + kitty_tests/parser.py | 19 +++++++++++++++++++ 7 files changed, 50 insertions(+) diff --git a/kitty/control-codes.h b/kitty/control-codes.h index 66f1f770c..2931bc59b 100644 --- a/kitty/control-codes.h +++ b/kitty/control-codes.h @@ -188,6 +188,9 @@ // *Horizontal position relative*: Same as :data:`CUF`. #define HPR 'a' +// Repeat the preceding graphic character Ps times. +#define REP 'b' + // *Device Attributes*. #define DA 'c' diff --git a/kitty/line.c b/kitty/line.c index a1ddcd9e9..223ed9714 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -550,6 +550,11 @@ left_shift(Line *self, PyObject *args) { Py_RETURN_NONE; } +uint32_t +line_get_char(Line *self, unsigned int at) { + return self->cpu_cells[at].ch; +} + void line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool UNUSED is_second) { if (cursor == NULL) { diff --git a/kitty/lineops.h b/kitty/lineops.h index 81fc554dd..9f0dc9083 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -57,6 +57,7 @@ line_reset_cells(Line *line, index_type start, index_type num, GPUCell *gpu_cell typedef Line*(get_line_func)(void *, int); void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch); void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char); +uint32_t line_get_char(Line *self, unsigned int at); void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool); void line_right_shift(Line *, unsigned int , unsigned int ); void line_add_combining_char(Line *, uint32_t , unsigned int ); diff --git a/kitty/parser.c b/kitty/parser.c index c433bfc42..73a0b3c69 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -652,6 +652,8 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { case ICH: NO_MODIFIERS(end_modifier, ' ', "Shift left escape code not implemented"); CALL_CSI_HANDLER1(screen_insert_characters, 1); + case REP: + CALL_CSI_HANDLER1(screen_repeat_character, 1); case CUU: NO_MODIFIERS(end_modifier, ' ', "Shift right escape code not implemented"); CALL_CSI_HANDLER1(screen_cursor_up2, 1); diff --git a/kitty/screen.c b/kitty/screen.c index cc6196965..12bd45715 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1251,6 +1251,25 @@ screen_insert_characters(Screen *self, unsigned int count) { } } +void +screen_repeat_character(Screen *self, unsigned int count) { + unsigned int top = self->margin_top, bottom = self->margin_bottom; + unsigned int x = self->cursor->x; + if (count == 0) count = 1; + if (top <= self->cursor->y && self->cursor->y <= bottom && x > 0) { + unsigned int num = MIN(count, self->columns - x); + linebuf_init_line(self->linebuf, self->cursor->y); + uint32_t ch = line_get_char(self->linebuf->line, x - 1); + if (is_ignored_char(ch) || is_combining_char(ch)) { + return; + } + while (num > 0) { + screen_draw(self, ch); + num--; + } + } +} + void screen_delete_characters(Screen *self, unsigned int count) { // Delete characters, later characters are moved left diff --git a/kitty/screen.h b/kitty/screen.h index d337a5a5c..efa4cf788 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -165,6 +165,7 @@ void screen_cursor_up1(Screen *self, unsigned int count/*=1*/); void screen_cursor_to_line(Screen *screen, unsigned int line); void screen_insert_lines(Screen *self, unsigned int count/*=1*/); void screen_delete_lines(Screen *self, unsigned int count/*=1*/); +void screen_repeat_character(Screen *self, unsigned int count); void screen_delete_characters(Screen *self, unsigned int count); void screen_erase_characters(Screen *self, unsigned int count); void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom); diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 78ccbcac0..17df3cf3c 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -177,6 +177,25 @@ class TestParser(BaseTest): pb('\033[3 A', ('Shift right escape code not implemented',)) pb('\033[3;4 S', ('Select presentation directions escape code not implemented',)) + def test_csi_code_rep(self): + s = self.create_screen(8) + pb = partial(self.parse_bytes_dump, s) + pb('\033[1b', ('screen_repeat_character', 1)) + self.ae(str(s.line(0)), '') + pb('x\033[7b', 'x', ('screen_repeat_character', 7)) + self.ae(str(s.line(0)), 'xxxxxxxx') + pb('\033[1;3H', ('screen_cursor_position', 1, 3)) + pb('\033[byz\033[b', ('screen_repeat_character', 1), 'yz', ('screen_repeat_character', 1)) + # repeat 'x' at 3, then 'yz' at 4-5, then repeat 'z' at 6 + self.ae(str(s.line(0)), 'xxxyzzxx') + s.reset() + pb(' \033[3b', ' ', ('screen_repeat_character', 3)) + self.ae(str(s.line(0)), ' ') + s.reset() + pb('\t\033[b', ('screen_tab',), ('screen_repeat_character', 1)) + self.ae(str(s.line(0)), '\t') + s.reset() + def test_osc_codes(self): s = self.create_screen() pb = partial(self.parse_bytes_dump, s) From 390e883ecfd461c23670017978d3673dd6d45cc2 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Fri, 29 May 2020 01:06:16 +0300 Subject: [PATCH 2/3] Update terminfo with CSI REP support --- kitty/terminfo.py | 3 +++ terminfo/kitty.terminfo | 1 + terminfo/x/xterm-kitty | Bin 3197 -> 3217 bytes 3 files changed, 4 insertions(+) diff --git a/kitty/terminfo.py b/kitty/terminfo.py index 85bbd0241..348e934a9 100644 --- a/kitty/terminfo.py +++ b/kitty/terminfo.py @@ -181,6 +181,8 @@ string_capabilities = { 'kind': r'\E[1;2B', # Restore cursor 'rc': r'\E8', + # Repeat preceding character + 'rep': r'%p1%c\E[%p2%{1}%-%db', # Reverse video 'rev': r'\E[7m', # Scroll backwards the specified number of lines (reverse index) @@ -347,6 +349,7 @@ termcap_aliases.update({ 'kR': 'kri', 'kF': 'kind', 'rc': 'rc', + 'rp': 'rep', 'mr': 'rev', 'sr': 'ri', 'SR': 'rin', diff --git a/terminfo/kitty.terminfo b/terminfo/kitty.terminfo index b80645367..c5ca815cc 100644 --- a/terminfo/kitty.terminfo +++ b/terminfo/kitty.terminfo @@ -204,6 +204,7 @@ xterm-kitty|KovIdTTY, oc=\E]104\007, op=\E[39;49m, rc=\E8, + rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM, rin=\E[%p1%dT, diff --git a/terminfo/x/xterm-kitty b/terminfo/x/xterm-kitty index e3d798eed9063ba46fe6d1346a4434fb1408349b..378be2c5c12090249a10e128cca355d6a5505b6d 100644 GIT binary patch delta 361 zcmew>F;S9Ricyq7hJl|Uld*auw=<)|NyfX3|H0r1<8#JOj9(eQGyY=qVfz2ypD7SX zf=6ba@>0m<25)_kU=Op^r}#kf|3x&QyKXPVr|q)@*B$_44&2xjkqi|l7Q z#&j0Uy8fUgoLHbD5ViuVvoCyqozD^GW85%r~`}A2PpW{>c23nURH)MSw+|MUF+4 zMVG~t#g@gD#g`?NC6*?rS(o_~qp)g$p=z>pv}%EoYPDgls;+8E(&le0?d$+Veyg?s delta 341 zcmbOz`B#Elicyq7hJl|UlQDfGw=<)||Nkc$|AWB=#>ZJAw|y_tiU zBbgJKGnosSE14UaJDDdk&tzV}yqtL*^H%1)%ty7E&oWI^ T+zS@<&AQB|7&mjXwy^^MD@3KB From 42c2791182bc2b801c0a219271f5c1f1048a49af Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Fri, 29 May 2020 20:36:30 +0300 Subject: [PATCH 3/3] Do not cap repetitions by row length Instead cap by 65535 as a safeguard. This is more in line with ECMA 48. --- kitty/screen.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kitty/screen.c b/kitty/screen.c index 12bd45715..96c61e74c 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -28,6 +28,8 @@ static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true}; static Selection EMPTY_SELECTION = {{0}}; +#define CSI_REP_MAX_REPETITIONS 65535u + // Constructor/destructor {{{ static inline void @@ -1257,7 +1259,7 @@ screen_repeat_character(Screen *self, unsigned int count) { unsigned int x = self->cursor->x; if (count == 0) count = 1; if (top <= self->cursor->y && self->cursor->y <= bottom && x > 0) { - unsigned int num = MIN(count, self->columns - x); + unsigned int num = MIN(count, CSI_REP_MAX_REPETITIONS); linebuf_init_line(self->linebuf, self->cursor->y); uint32_t ch = line_get_char(self->linebuf->line, x - 1); if (is_ignored_char(ch) || is_combining_char(ch)) {