diff --git a/kitty/data-types.h b/kitty/data-types.h index 6385a5654..dfc1aa45f 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -320,6 +320,7 @@ void screen_set_mode(Screen *self, unsigned int mode); void screen_reset_mode(Screen *self, unsigned int mode); void screen_insert_characters(Screen *self, unsigned int count); void screen_cursor_up(Screen *self, unsigned int count/*=1*/, bool do_carriage_return/*=false*/, int move_direction/*=-1*/); +void screen_set_cursor(Screen *self, unsigned int mode, uint8_t secondary); void screen_cursor_to_column(Screen *self, unsigned int column); void screen_cursor_down(Screen *self, unsigned int count/*=1*/); void screen_cursor_forward(Screen *self, unsigned int count/*=1*/); diff --git a/kitty/parser.c b/kitty/parser.c index afb5fe6c5..55cb1413e 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -219,7 +219,7 @@ HANDLER(esc) { #define MAX_PARAMS 100 static inline unsigned int fill_params(Screen *screen, unsigned int *params, unsigned int expect) { - unsigned int start_pos = 1, i = 1, pi = 0; + unsigned int start_pos = 2, i = 2, pi = 0; uint8_t ch = 1; screen->parser_buf[screen->parser_buf_pos] = 0; @@ -272,6 +272,12 @@ HANDLER(csi) { name(screen, p1, private); \ END_DISPATCH; +#define CALL_CSI_HANDLER1M(name, defval) \ + p1 = fill_params(screen, params, 1) > 0 ? params[0] : defval; \ + REPORT_COMMAND(name, p1, screen->parser_buf[1]); \ + name(screen, p1, screen->parser_buf[1]); \ + END_DISPATCH; + #define CALL_CSI_HANDLER2(name, defval1, defval2) \ count = fill_params(screen, params, 2); \ p1 = count > 0 ? params[0] : defval1; \ @@ -314,6 +320,7 @@ HANDLER(csi) { case CPL: \ CALL_CSI_HANDLER1(screen_cursor_up1, 1); \ case CHA: \ + case HPA: \ CALL_CSI_HANDLER1(screen_cursor_to_column, 1); \ case VPA: \ CALL_CSI_HANDLER1(screen_cursor_to_line, 1); \ @@ -346,6 +353,8 @@ HANDLER(csi) { CALL_CSI_HANDLER1P(report_device_status, 0, '?'); \ case DECSTBM: \ CALL_CSI_HANDLER2(screen_set_margins, 0, 0); \ + case DECSCUSR: \ + CALL_CSI_HANDLER1M(screen_set_cursor, 1); \ uint8_t ch = buf[(*pos)++]; unsigned int params[MAX_PARAMS], p1, p2, count, i; @@ -354,10 +363,11 @@ HANDLER(csi) { case 0: // CSI starting screen->parser_buf[0] = 0; screen->parser_buf[1] = 0; + screen->parser_buf[2] = 0; switch(ch) { IS_DIGIT - screen->parser_buf_pos = 2; - screen->parser_buf[1] = ch; + screen->parser_buf_pos = 3; + screen->parser_buf[2] = ch; break; case '?': case '>': @@ -372,6 +382,8 @@ HANDLER(csi) { break; } break; + case 1: + screen->parser_buf_pos = 2; // we start params at 2 default: // CSI started switch(ch) { IS_DIGIT @@ -381,6 +393,10 @@ HANDLER(csi) { SET_STATE(NORMAL_STATE); } else screen->parser_buf[screen->parser_buf_pos++] = ch; break; + case ' ': + case '"': + screen->parser_buf[1] = ch; + break; HANDLE_BASIC_CH DISPATCH_CSI default: diff --git a/kitty/screen.c b/kitty/screen.c index 883020704..fbabcbdf7 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -792,6 +792,27 @@ void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom) { } } +void screen_set_cursor(Screen *self, unsigned int mode, uint8_t secondary) { + uint8_t shape; bool blink; + switch(secondary) { + case 0: // DECLL + break; + case '"': // DECCSA + break; + case ' ': // DECSCUSR + shape = 0; blink = false; + if (mode > 0) { + blink = mode % 2; + shape = (mode < 3) ? CURSOR_BLOCK : (mode < 5) ? CURSOR_UNDERLINE : (mode < 7) ? CURSOR_BEAM : 0; + } + if (shape != self->cursor->shape || blink != self->cursor->blink) { + self->cursor->shape = shape; self->cursor->blink = blink; + tracker_cursor_changed(self->change_tracker); + } + break; + } +} + // }}} // Python interface {{{ diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 1d4db4374..e522fdaeb 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -6,7 +6,7 @@ from functools import partial from . import BaseTest -from kitty.fast_data_types import parse_bytes, parse_bytes_dump +from kitty.fast_data_types import parse_bytes, parse_bytes_dump, CURSOR_BLOCK class CmdDump(list): @@ -31,7 +31,7 @@ class Callbacks: class TestScreen(BaseTest): - def parse_buytes_dump(self, s, x, *cmds): + def parse_bytes_dump(self, s, x, *cmds): cd = CmdDump() if isinstance(x, str): x = x.encode('utf-8') @@ -40,7 +40,7 @@ class TestScreen(BaseTest): def test_simple_parsing(self): s = self.create_screen() - pb = partial(self.parse_buytes_dump, s) + pb = partial(self.parse_bytes_dump, s) pb('12') self.ae(str(s.line(0)), '12 ') @@ -60,7 +60,7 @@ class TestScreen(BaseTest): def test_esc_codes(self): s = self.create_screen() - pb = partial(self.parse_buytes_dump, s) + pb = partial(self.parse_bytes_dump, s) pb('12\033Da', 'screen_index') self.ae(str(s.line(0)), '12 ') self.ae(str(s.line(1)), ' a ') @@ -70,7 +70,7 @@ class TestScreen(BaseTest): def test_csi_codes(self): s = self.create_screen() - pb = partial(self.parse_buytes_dump, s) + pb = partial(self.parse_bytes_dump, s) pb('abcde') s.cursor_back(5) pb('x\033[2@y', ('screen_insert_characters', 2)) @@ -120,3 +120,6 @@ class TestScreen(BaseTest): self.ae(s.margin_top, 1), self.ae(s.margin_bottom, 3) pb('\033[r', ('screen_set_margins', 0, 0)) self.ae(s.margin_top, 0), self.ae(s.margin_bottom, 4) + pb('\033[1 q', ('screen_set_cursor', 1, ord(' '))) + self.assertTrue(s.cursor.blink) + self.ae(s.cursor.shape, CURSOR_BLOCK)