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