vis-config

lua scripts to configure vis editor

git clone https://9o.is/git/vis-config.git

parser.lua

(1873B)


      1 --- Stateful parser for the data send by a language server.
      2 -- Note the chunks received may not end with the end of a message.
      3 -- In the worst case a data chunk contains two partial messages one
      4 -- at the beginning and one at the end.
      5 -- @module parser
      6 -- @author Florian Fischer
      7 -- @license GPL-3
      8 -- @copyright Florian Fischer 2021-2024
      9 local parser = {}
     10 
     11 local Parser = {}
     12 
     13 function parser.new()
     14   local self = {exp_len = nil, data = '', msgs = {}}
     15 
     16   setmetatable(self, {__index = Parser})
     17   return self
     18 end
     19 
     20 function Parser:add(data)
     21   self.data = self.data .. data
     22 
     23   -- we have not seen a complete header in data yet
     24   if not self.exp_len then
     25     -- search for the end of a header
     26     -- LSP message format: 'header\r\n\r\nbody'
     27     local header_end, content_start = self.data:find('\r\n\r\n')
     28 
     29     -- header is not complete yet -> save data and wait for more
     30     if not header_end then
     31       return
     32     end
     33 
     34     -- got a complete header
     35     local header = self.data:sub(1, header_end)
     36 
     37     -- extract content length from the header
     38     self.exp_len = tonumber(header:match('%d+'))
     39     if not self.exp_len then
     40       return 'invalid header in data: ' .. self.data
     41     end
     42 
     43     -- consume header from data
     44     self.data = self.data:sub(content_start + 1)
     45   end
     46 
     47   local data_avail = string.len(self.data)
     48   -- we have no complete message yet -> await more data
     49   if self.exp_len > data_avail then
     50     return
     51   end
     52 
     53   local complete_msg = self.data:sub(1, self.exp_len)
     54   table.insert(self.msgs, complete_msg)
     55 
     56   -- consume complete_msg from data
     57   self.data = self.data:sub(self.exp_len + 1)
     58 
     59   local leftover = data_avail - self.exp_len
     60 
     61   -- reset exp_len to search for a new header
     62   self.exp_len = nil
     63 
     64   if leftover > 0 then
     65     return self:add('')
     66   end
     67 end
     68 
     69 function Parser:get_msgs()
     70   local msgs = self.msgs
     71   self.msgs = {}
     72   return msgs
     73 end
     74 
     75 return parser