diff --git a/kitty/control-codes.h b/kitty/control-codes.h index bde4e373b..8acd797c0 100644 --- a/kitty/control-codes.h +++ b/kitty/control-codes.h @@ -63,6 +63,8 @@ #define CSI 0x9b #define ST 0x9c #define OSC 0x9d +#define PM 0x9e +#define APC 0x9f // Sharp control codes // ------------------- @@ -77,6 +79,8 @@ #define ESC_OSC ']' #define ESC_CSI '[' #define ESC_ST '\\' +#define ESC_PM '^' +#define ESC_APC '_' // *Reset*. #define ESC_RIS 'c' diff --git a/kitty/parser.c b/kitty/parser.c index f5e8e641b..184226d61 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -178,6 +178,10 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal SET_STATE(OSC); break; case ESC_CSI: SET_STATE(CSI); break; + case ESC_APC: + SET_STATE(APC); break; + case ESC_PM: + SET_STATE(PM); break; case ESC_RIS: CALL_ED(screen_reset); break; case ESC_IND: @@ -554,6 +558,29 @@ END_ALLOW_CASE_RANGE return false; } + +static inline bool +accumulate_oth(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) { + switch(ch) { + case ST: + return true; + case ESC_ST: + if (screen->parser_buf_pos > 0 && screen->parser_buf[screen->parser_buf_pos - 1] == ESC) { + screen->parser_buf_pos--; + return true; + } + default: + if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) { + REPORT_ERROR("OTH sequence too long, truncating."); + return true; + } + screen->parser_buf[screen->parser_buf_pos++] = ch; + break; + } + return false; +} + + static inline bool accumulate_csi(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) { #define ENSURE_SPACE \ @@ -632,6 +659,12 @@ dispatch_unicode_char(Screen *screen, uint32_t codepoint, PyObject DUMP_UNUSED * case OSC: if (accumulate_osc(screen, codepoint, dump_callback)) { dispatch_osc(screen, dump_callback); SET_STATE(0); } break; + case APC: + if (accumulate_oth(screen, codepoint, dump_callback)) { SET_STATE(0); } + break; + case PM: + if (accumulate_oth(screen, codepoint, dump_callback)) { SET_STATE(0); } + break; case DCS: if (accumulate_dcs(screen, codepoint, dump_callback)) { dispatch_dcs(screen, dump_callback); SET_STATE(0); } if (screen->parser_state == ESC) { HANDLE(esc_mode_char); } diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index a4c208e01..654b02ec3 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -163,3 +163,10 @@ class TestParser(BaseTest): pb = partial(self.parse_bytes_dump, s) pb('a\033P+q436f\x9cbcde', 'a', ('screen_request_capabilities', '436f'), 'bcde') self.ae(str(s.line(0)), 'abcde') + + def test_oth_codes(self): + s = self.create_screen() + pb = partial(self.parse_bytes_dump, s) + for prefix in '\033_', '\033^': + for suffix in '\u009c', '\033\\': + pb('a{}+++{}bcde'.format(prefix, suffix), 'abcde')