From d0c2821339d0cc90cabfb9aeed8226e83b791ec2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Nov 2016 13:40:38 +0530 Subject: [PATCH] Start work on connecting CSI callbacks --- kitty/data-types.h | 1 + kitty/parser.c | 43 +++++++++++++++++++++++++++++++++++++++++-- kitty_tests/parser.py | 11 +++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/kitty/data-types.h b/kitty/data-types.h index be9246449..07cb5fc1c 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -313,6 +313,7 @@ void screen_reverse_index(Screen *self); void screen_index(Screen *self); void screen_reset(Screen *self); void screen_set_tab_stop(Screen *self); +void screen_insert_characters(Screen *self, unsigned int count); #define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen, uint8_t ch); DECLARE_CH_SCREEN_HANDLER(bell) DECLARE_CH_SCREEN_HANDLER(backspace) diff --git a/kitty/parser.c b/kitty/parser.c index 2bc8c94d4..c800810a2 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -6,6 +6,7 @@ */ #include +#include #include "data-types.h" #include "control-codes.h" @@ -214,6 +215,26 @@ HANDLER(esc) { // }}} // Parse CSI {{{ + +#define MAX_PARAMS 8 + +static inline unsigned int fill_params(Screen *screen, unsigned int *params, unsigned int expect) { + unsigned int start_pos = 1, i = 1, pi = 0; + uint8_t ch; + screen->parser_buf[screen->parser_buf_pos++] = ';'; + + while (pi < MIN(MAX_PARAMS, expect) && i < PARSER_BUF_SZ - 1) { + ch = screen->parser_buf[i++]; + if (ch == 0 || ch == ';') { + if (start_pos < i - 1) { + params[pi++] = atoi((const char *)screen->parser_buf + start_pos); + } + start_pos = i; + } + } + return pi; +} + HANDLER(csi) { #define CALL_BASIC_HANDLER(name) REPORT_COMMAND(screen, ch); name(screen, ch); break; #define HANDLE_BASIC_CH \ @@ -232,8 +253,17 @@ HANDLER(csi) { case NUL: \ case DEL: \ break; // no-op +#define CALL_CSI_HANDLER1(name) \ + if (fill_params(screen, params, 1) != 1) { REPORT_ERROR("Expected parameter for CSI escape sequence: %s missing", #name); } \ + else { \ + REPORT_COMMAND(name, params[0]); \ + screen_insert_characters(screen, params[0]); \ + } \ + SET_STATE(NORMAL_STATE); \ + break; uint8_t ch = buf[(*pos)++]; + unsigned int params[MAX_PARAMS]; switch(screen->parser_buf_pos) { case 0: // CSI starting screen->parser_buf[0] = 0; @@ -250,9 +280,9 @@ HANDLER(csi) { break; HANDLE_BASIC_CH default: - REPORT_ERROR("%s%d", "Invalid first character for CSI: ", (int)ch); + REPORT_ERROR("Invalid first character for CSI: 0x%x", ch); SET_STATE(NORMAL_STATE); - return; + break; } break; default: // CSI started @@ -264,12 +294,21 @@ HANDLER(csi) { SET_STATE(NORMAL_STATE); } else screen->parser_buf[screen->parser_buf_pos++] = ch; break; + HANDLE_BASIC_CH + default: + REPORT_ERROR("Invalid character for CSI: 0x%x", ch); + SET_STATE(NORMAL_STATE); + break; + case ICH: + CALL_CSI_HANDLER1(screen_insert_characters); } break; } #undef CALL_BASIC_HANDLER #undef HANDLE_BASIC_CH +#undef CALL_CSI_HANDLER1 } +#undef MAX_PARAMS // }}} // Parse OSC {{{ diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 81da952d4..8c4e3885d 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -55,3 +55,14 @@ class TestScreen(BaseTest): pb('\033x', 'Unknown char in escape_dispatch: %d' % ord('x')) pb('\033c123', 'screen_reset') self.ae(str(s.line(0)), '123 ') + + def test_csi_codes(self): + s = self.create_screen() + pb = partial(self.parse_buytes_dump, s) + pb('abcde') + s.cursor_back(5) + pb('x\033[2@y', ('screen_insert_characters', 2)) + self.ae(str(s.line(0)), 'xy bc') + pb('x\033[2;3@y', ('screen_insert_characters', 2)) + pb('x\033[@y', 'Invalid first character for CSI: 0x%x' % ord('@')) + s.reset()