Update pending mode escape code parsing to match latest shed color

This commit is contained in:
Kovid Goyal
2018-07-28 10:56:34 +05:30
parent bd4831e2ee
commit 3df78de3f8
3 changed files with 44 additions and 36 deletions

View File

@@ -795,9 +795,14 @@ dispatch_dcs(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
} }
break; break;
case PENDING_MODE_CHAR: case PENDING_MODE_CHAR:
if (screen->parser_buf[1] == 's') { if (screen->parser_buf_pos > 2 && (screen->parser_buf[1] == '1' || screen->parser_buf[2] == '2') && screen->parser_buf[2] == 's') {
screen->pending_mode.activated_at = monotonic(); if (screen->parser_buf[1] == '1') {
REPORT_COMMAND(screen_start_pending_mode); screen->pending_mode.activated_at = monotonic();
REPORT_COMMAND(screen_start_pending_mode);
} else {
// ignore stop without matching start
REPORT_COMMAND(screen_stop_pending_mode);
}
} else { } else {
REPORT_ERROR("Unrecognized DCS %c code: 0x%x", (char)screen->parser_buf[0], screen->parser_buf[1]); REPORT_ERROR("Unrecognized DCS %c code: 0x%x", (char)screen->parser_buf[0], screen->parser_buf[1]);
} }
@@ -1094,10 +1099,16 @@ FLUSH_DRAW;
static inline size_t static inline size_t
_queue_pending_bytes(Screen *screen, const uint8_t *buf, size_t len, PyObject *dump_callback DUMP_UNUSED) { _queue_pending_bytes(Screen *screen, const uint8_t *buf, size_t len, PyObject *dump_callback DUMP_UNUSED) {
size_t pos = 0; size_t pos = 0;
enum STATE { NORMAL, MAYBE_DCS, IN_DCS, EXPECTING_START_OR_ESC, EXPECTING_ESC, EXPECTING_SLASH }; enum STATE { NORMAL, MAYBE_DCS, IN_DCS, EXPECTING_DATA, EXPECTING_SLASH };
enum STATE state = screen->pending_mode.state; enum STATE state = screen->pending_mode.state;
bool is_end_code = true;
#define COPY(what) screen->pending_mode.buf[screen->pending_mode.used++] = what #define COPY(what) screen->pending_mode.buf[screen->pending_mode.used++] = what
#define COPY_STOP_BUF { \
COPY(0x1b); COPY('P'); COPY(PENDING_MODE_CHAR); \
for (size_t i = 0; i < screen->pending_mode.stop_buf_pos; i++) { \
COPY(screen->pending_mode.stop_buf[i]); \
} \
screen->pending_mode.stop_buf_pos = 0;}
while (pos < len) { while (pos < len) {
uint8_t ch = buf[pos++]; uint8_t ch = buf[pos++];
switch(state) { switch(state) {
@@ -1113,35 +1124,31 @@ _queue_pending_bytes(Screen *screen, const uint8_t *buf, size_t len, PyObject *d
} }
break; break;
case IN_DCS: case IN_DCS:
if (ch == PENDING_MODE_CHAR) { state = EXPECTING_START_OR_ESC; is_end_code = true; } if (ch == PENDING_MODE_CHAR) { state = EXPECTING_DATA; screen->pending_mode.stop_buf_pos = 0; }
else { else {
state = NORMAL; state = NORMAL;
COPY(0x1b); COPY('P'); COPY(ch); COPY(0x1b); COPY('P'); COPY(ch);
} }
break; break;
case EXPECTING_START_OR_ESC: case EXPECTING_DATA:
if (ch == 0x1b) state = EXPECTING_SLASH;
else if (ch == 's') {
state = EXPECTING_ESC;
is_end_code = false;
} else {
state = NORMAL;
COPY(0x1b); COPY('P'); COPY('='); COPY(ch);
}
break;
case EXPECTING_ESC:
if (ch == 0x1b) state = EXPECTING_SLASH; if (ch == 0x1b) state = EXPECTING_SLASH;
else { else {
state = NORMAL; screen->pending_mode.stop_buf[screen->pending_mode.stop_buf_pos++] = ch;
COPY(0x1b); COPY('P'); COPY('='); if (screen->pending_mode.stop_buf_pos >= sizeof(screen->pending_mode.stop_buf)) {
if (!is_end_code) COPY('s'); state = NORMAL;
COPY(ch); COPY_STOP_BUF;
}
} }
break; break;
case EXPECTING_SLASH: case EXPECTING_SLASH:
if (ch == '\\') { if (
ch == '\\' &&
screen->pending_mode.stop_buf_pos >= 2 &&
(screen->pending_mode.stop_buf[0] == '1' || screen->pending_mode.stop_buf[0] == '2') &&
screen->pending_mode.stop_buf[1] == 's'
) {
// We found a pending mode sequence // We found a pending mode sequence
if (is_end_code) { if (screen->pending_mode.stop_buf[0] == '2') {
REPORT_COMMAND(screen_stop_pending_mode); REPORT_COMMAND(screen_stop_pending_mode);
screen->pending_mode.activated_at = 0; screen->pending_mode.activated_at = 0;
goto end; goto end;
@@ -1151,9 +1158,7 @@ _queue_pending_bytes(Screen *screen, const uint8_t *buf, size_t len, PyObject *d
} }
} else { } else {
state = NORMAL; state = NORMAL;
COPY(0x1b); COPY('P'); COPY('='); COPY_STOP_BUF; COPY(ch);
if (!is_end_code) { COPY('s'); }
COPY(0x1b); COPY(ch);
} }
break; break;
} }
@@ -1162,6 +1167,7 @@ end:
screen->pending_mode.state = state; screen->pending_mode.state = state;
return pos; return pos;
#undef COPY #undef COPY
#undef COPY_STOP_BUF
} }
static inline void static inline void
@@ -1197,7 +1203,7 @@ do_parse_bytes(Screen *screen, const uint8_t *read_buf, const size_t read_buf_sz
break; break;
case QUEUE_PENDING: { case QUEUE_PENDING: {
if (screen->pending_mode.capacity - screen->pending_mode.used < read_buf_sz) { if (screen->pending_mode.capacity - screen->pending_mode.used < read_buf_sz + sizeof(screen->pending_mode.stop_buf)) {
if (screen->pending_mode.capacity >= READ_BUF_SZ) { if (screen->pending_mode.capacity >= READ_BUF_SZ) {
// Too much pending data, drain it // Too much pending data, drain it
screen->pending_mode.activated_at = 0; screen->pending_mode.activated_at = 0;

View File

@@ -98,10 +98,11 @@ typedef struct {
CursorRenderInfo cursor_render_info; CursorRenderInfo cursor_render_info;
struct { struct {
size_t capacity, used; size_t capacity, used, stop_buf_pos;
uint8_t *buf; uint8_t *buf;
double activated_at, wait_time; double activated_at, wait_time;
int state; int state;
uint8_t stop_buf[32];
} pending_mode; } pending_mode;
} Screen; } Screen;

View File

@@ -232,23 +232,24 @@ class TestParser(BaseTest):
timeout = 0.1 timeout = 0.1
s.set_pending_timeout(timeout) s.set_pending_timeout(timeout)
pb = partial(self.parse_bytes_dump, s) pb = partial(self.parse_bytes_dump, s)
pb('\033P=s\033\\', ('screen_start_pending_mode',)) pb('\033P=1s\033\\', ('screen_start_pending_mode',))
pb('a') pb('a')
self.ae(str(s.line(0)), '') self.ae(str(s.line(0)), '')
pb('\033P=\033\\', ('screen_stop_pending_mode',), ('draw', 'a')) pb('\033P=2s\033\\', ('screen_stop_pending_mode',), ('draw', 'a'))
self.ae(str(s.line(0)), 'a') self.ae(str(s.line(0)), 'a')
pb('\033P=s\033\\', ('screen_start_pending_mode',)) pb('\033P=1s\033\\', ('screen_start_pending_mode',))
pb('b') pb('b')
self.ae(str(s.line(0)), 'a') self.ae(str(s.line(0)), 'a')
time.sleep(timeout) time.sleep(timeout)
pb('c', ('draw', 'bc')) pb('c', ('draw', 'bc'))
self.ae(str(s.line(0)), 'abc') self.ae(str(s.line(0)), 'abc')
pb('\033P=s\033\\d', ('screen_start_pending_mode',)) pb('\033P=1s\033\\d', ('screen_start_pending_mode',))
pb('\033P=\033\\', ('screen_stop_pending_mode',), ('draw', 'd')) pb('\033P=2s\033\\', ('screen_stop_pending_mode',), ('draw', 'd'))
pb('\033P=s\033\\e', ('screen_start_pending_mode',)) pb('\033P=1s\033\\e', ('screen_start_pending_mode',))
pb('\033P'), pb('=') pb('\033P'), pb('='), pb('2s')
pb('\033\\', ('screen_stop_pending_mode',), ('draw', 'e')) pb('\033\\', ('screen_stop_pending_mode',), ('draw', 'e'))
pb('\033P=s\033\\f\033P=s\033\\', ('screen_start_pending_mode',), ('screen_start_pending_mode',)) pb('\033P=1sxyz;.;\033\\''\033P=2skjf".,><?_+)98\033\\', ('screen_start_pending_mode',), ('screen_stop_pending_mode',))
pb('\033P=1s\033\\f\033P=1s\033\\', ('screen_start_pending_mode',), ('screen_start_pending_mode',))
def test_oth_codes(self): def test_oth_codes(self):
s = self.create_screen() s = self.create_screen()