aboutsummaryrefslogtreecommitdiff
path: root/parser.lua
diff options
context:
space:
mode:
authorfischerling <github@muhq.space>2021-08-16 14:10:48 +0200
committerGitHub <noreply@github.com>2021-08-16 14:10:48 +0200
commitc63d31c899c347021744502cd9b245ade5096de4 (patch)
tree26afb1bdd77762d67b3803c8068eab5f9cbdf5a5 /parser.lua
parentbcab92186e8bd66e6841f33275d261af00e43a25 (diff)
parent29b50c08a7e8524797549354a2e5063974c0e1b2 (diff)
downloadvis-lspc-c63d31c899c347021744502cd9b245ade5096de4.tar.gz
vis-lspc-c63d31c899c347021744502cd9b245ade5096de4.zip
Merge pull request #17 from fischerling/parser
Improve message parsing
Diffstat (limited to 'parser.lua')
-rw-r--r--parser.lua75
1 files changed, 75 insertions, 0 deletions
diff --git a/parser.lua b/parser.lua
new file mode 100644
index 0000000..f1b09f5
--- /dev/null
+++ b/parser.lua
@@ -0,0 +1,75 @@
+-- Copyright (c) 2021 Florian Fischer. All rights reserved.
+-- Use of this source code is governed by a MIT license found in the LICENSE file.
+
+-- Parse the data send by a language server
+-- Note the chunks received may not end with the end of a message.
+-- In the worst case a data chunk contains two partial messages on at the beginning
+-- and one at the end
+
+local function add(p, data)
+ p.data = p.data .. data
+
+ -- we have not seen a complete header in data yet
+ if not p.exp_len then
+ -- search for the end of a header
+ -- LSP message format: 'header\r\n\r\nbody'
+ local header_end, content_start = p.data:find('\r\n\r\n')
+
+ -- header is not complete yet -> save data and wait for more
+ if not header_end then
+ return
+ end
+
+ -- got a complete header
+ local header = p.data:sub(1, header_end)
+
+ -- extract content length from the header
+ p.exp_len = tonumber(header:match('%d+'))
+ if not p.exp_len then
+ return 'invalid header in data: ' .. p.data
+ end
+
+ -- consume header from data
+ p.data = p.data:sub(content_start + 1)
+ end
+
+ local data_avail = string.len(p.data)
+ -- we have no complete message yet -> await more data
+ if p.exp_len > data_avail then
+ return
+ end
+
+ local complete_msg = p.data:sub(1, p.exp_len)
+ table.insert(p.msgs, complete_msg)
+
+ -- consume complete_msg from data
+ p.data = p.data:sub(p.exp_len + 1)
+
+ local leftover = data_avail - p.exp_len
+
+ -- reset exp_len to search for a new header
+ p.exp_len = nil
+
+ if leftover > 0 then
+ return p:add('')
+ end
+end
+
+local function get_msgs(p)
+ local msgs = p.msgs
+ p.msgs = {}
+ return msgs
+end
+
+local function Parser()
+ local parser = {
+ add = add,
+ get_msgs = get_msgs,
+ exp_len = nil,
+ data = '',
+ msgs = {},
+ }
+ return parser
+end
+
+return {Parser = Parser}