diff options
Diffstat (limited to '.config/vis/plugins/vis-lspc/parser.lua')
| -rw-r--r-- | .config/vis/plugins/vis-lspc/parser.lua | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/.config/vis/plugins/vis-lspc/parser.lua b/.config/vis/plugins/vis-lspc/parser.lua new file mode 100644 index 0000000..0c9fc0a --- /dev/null +++ b/.config/vis/plugins/vis-lspc/parser.lua @@ -0,0 +1,76 @@ +--- Stateful parser for 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 one +-- at the beginning and one at the end. +-- @module parser +-- @author Florian Fischer +-- @license GPL-3 +-- @copyright Florian Fischer 2021-2024 +local parser = {} + +local Parser = {} + +function parser.new() + local self = {exp_len = nil, data = '', msgs = {}} + + setmetatable(self, {__index = Parser}) + return self +end + +function Parser:add(data) + self.data = self.data .. data + + -- we have not seen a complete header in data yet + if not self.exp_len then + -- search for the end of a header + -- LSP message format: header\r\n(header\r\n)?\r\nbody' + local header_end, content_start = self.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 = self.data:sub(1, header_end) + + -- extract content length from the header + local length = header:match('Content%-Length: %d+') + self.exp_len = tonumber(length:match('%d+')) + if not self.exp_len then + return 'invalid header in data: ' .. self.data + end + + -- consume header from data + self.data = self.data:sub(content_start + 1) + end + + local data_avail = string.len(self.data) + -- we have no complete message yet -> await more data + if self.exp_len > data_avail then + return + end + + local complete_msg = self.data:sub(1, self.exp_len) + table.insert(self.msgs, complete_msg) + + -- consume complete_msg from data + self.data = self.data:sub(self.exp_len + 1) + + local leftover = data_avail - self.exp_len + + -- reset exp_len to search for a new header + self.exp_len = nil + + if leftover > 0 then + return self:add('') + end +end + +function Parser:get_msgs() + local msgs = self.msgs + self.msgs = {} + return msgs +end + +return parser |
