diff options
Diffstat (limited to 'src/nvim/msgpack_rpc/unpacker.c')
-rw-r--r-- | src/nvim/msgpack_rpc/unpacker.c | 99 |
1 files changed, 94 insertions, 5 deletions
diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index 26c1843026..efbb3110d9 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -292,7 +292,18 @@ bool unpacker_advance(Unpacker *p) if (!unpacker_parse_header(p)) { return false; } - p->state = p->type == kMessageTypeResponse ? 1 : 2; + if (p->type == kMessageTypeNotification && p->handler.fn == handle_ui_client_redraw) { + p->state = 10; + } else { + p->state = p->type == kMessageTypeResponse ? 1 : 2; + arena_start(&p->arena, &p->reuse_blk); + } + } + + if (p->state == 10 || p->state == 11) { + if (!unpacker_parse_redraw(p)) { + return false; + } arena_start(&p->arena, &p->reuse_blk); } @@ -310,13 +321,91 @@ rerun: return false; } - if (p->state == 1) { + switch (p->state) { + case 1: p->error = p->result; p->state = 2; goto rerun; - } else { - assert(p->state == 2); + case 2: p->state = 0; + p->is_ui = false; + return true; + case 12: + p->ncalls--; + if (p->ncalls > 0) { + p->state = 12; + } else if (p->nevents > 0) { + p->state = 11; + } else { + p->state = 0; + } + // TODO: fold into p->type + p->is_ui = true; + return true; + default: + abort(); + } +} + +// note: first {11} is not saved as a state +// <0>[2, "redraw", <10>[{11}["method", <12>[args], <12>[args], ...], <11>[...], ...]] +// +bool unpacker_parse_redraw(Unpacker *p) +{ + mpack_token_t tok; + int result; + + const char *data = p->read_ptr; + size_t size = p->read_size; + switch (p->state) { + case 10: + result = mpack_rtoken(&data, &size, &tok); + if (result == MPACK_EOF) { + return false; + } else if (result || tok.type != MPACK_TOKEN_ARRAY) { + p->state = -1; + return false; + } + + p->nevents = (int)tok.length; + FALLTHROUGH; + + case 11: + result = mpack_rtoken(&data, &size, &tok); + if (result == MPACK_EOF) { + return false; + } else if (result || tok.type != MPACK_TOKEN_ARRAY) { + abort(); + } + + p->ncalls = (int)tok.length; + if (p->ncalls-- == 0) { + p->state = -1; + return false; + } + + result = mpack_rtoken(&data, &size, &tok); + if (result == MPACK_EOF) { + return false; + } else if (result || (tok.type != MPACK_TOKEN_STR && tok.type != MPACK_TOKEN_BIN)) { + abort(); + } + + if (tok.length > size) { + return false; + } + + p->ui_handler = ui_client_get_redraw_handler(data, tok.length, NULL); + data += tok.length; + size -= tok.length; + + p->nevents--; + p->read_ptr = data; + p->read_size = size; + p->state = 12; + return true; + + default: + abort(); } - return true; } |