aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/msgpack_rpc/unpacker.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/msgpack_rpc/unpacker.c')
-rw-r--r--src/nvim/msgpack_rpc/unpacker.c99
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;
}