neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

stringbuffer.lua (2436B)


      1 -- Basic shim for LuaJIT's stringbuffer.
      2 -- Note this does not implement the full API.
      3 -- This is intentionally internal-only. If we want to expose it, we should
      4 -- reimplement this a userdata and ship it as `string.buffer`
      5 -- (minus the FFI stuff) for Lua 5.1.
      6 local M = {}
      7 
      8 local has_strbuffer, strbuffer = pcall(require, 'string.buffer')
      9 
     10 if has_strbuffer then
     11  M.new = strbuffer.new
     12 
     13  -- Lua 5.1 does not have __len metamethod so we need to provide a len()
     14  -- function to use instead.
     15 
     16  --- @param buf vim._core.stringbuffer
     17  --- @return integer
     18  function M.len(buf)
     19    return #buf
     20  end
     21 
     22  return M
     23 end
     24 
     25 --- @class vim._core.stringbuffer
     26 --- @field private buf string[]
     27 --- @field package len integer absolute length of the `buf`
     28 --- @field package skip_ptr integer
     29 local StrBuffer = {}
     30 StrBuffer.__index = StrBuffer
     31 
     32 --- @return string
     33 function StrBuffer:tostring()
     34  if #self.buf > 1 then
     35    self.buf = { table.concat(self.buf) }
     36  end
     37 
     38  -- assert(self.len == #(self.buf[1] or ''), 'len mismatch')
     39 
     40  if self.skip_ptr > 0 then
     41    if self.buf[1] then
     42      self.buf[1] = self.buf[1]:sub(self.skip_ptr + 1)
     43      self.len = self.len - self.skip_ptr
     44    end
     45    self.skip_ptr = 0
     46  end
     47 
     48  -- assert(self.len == #(self.buf[1] or ''), 'len mismatch')
     49 
     50  return self.buf[1] or ''
     51 end
     52 
     53 StrBuffer.__tostring = StrBuffer.tostring
     54 
     55 --- @private
     56 --- Efficiently peak at the first `n` characters of the buffer.
     57 --- @param n integer
     58 --- @return string
     59 function StrBuffer:_peak(n)
     60  local skip, buf1 = self.skip_ptr, self.buf[1]
     61  if buf1 and (n + skip) < #buf1 then
     62    return buf1:sub(skip + 1, skip + n)
     63  end
     64  return self:tostring():sub(1, n)
     65 end
     66 
     67 --- @param chunk string
     68 function StrBuffer:put(chunk)
     69  local s = tostring(chunk)
     70  self.buf[#self.buf + 1] = s
     71  self.len = self.len + #s
     72  return self
     73 end
     74 
     75 --- @param str string
     76 function StrBuffer:set(str)
     77  return self:reset():put(str)
     78 end
     79 
     80 --- @param n? integer
     81 --- @return string
     82 function StrBuffer:get(n)
     83  n = n or self.len
     84  local r = self:_peak(n)
     85  self:skip(n)
     86  return r
     87 end
     88 
     89 --- @param n integer
     90 function StrBuffer:skip(n)
     91  self.skip_ptr = math.min(self.len, self.skip_ptr + n)
     92  return self
     93 end
     94 
     95 function StrBuffer:reset()
     96  self.buf = {}
     97  self.skip_ptr = 0
     98  self.len = 0
     99  return self
    100 end
    101 
    102 function M.new()
    103  return setmetatable({}, StrBuffer):reset()
    104 end
    105 
    106 --- @param buf vim._core.stringbuffer
    107 function M.len(buf)
    108  return buf.len - buf.skip_ptr
    109 end
    110 
    111 return M