repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/pivi/partial.lua
Rawlocal ESCAPES = {
n = '\n',
t = '\t',
r = '\r',
b = '\b',
f = '\f',
['"'] = '"',
['\\'] = '\\',
['/'] = '/',
}
local read_string = function( text, start )
local pieces = {}
local index = start
local length = #text
while index <= length do
local char = text:sub( index, index )
if char == '"' then
return table.concat( pieces ), index + 1, true
elseif char == '\\' then
local escape = text:sub( index + 1, index + 1 )
if escape == '' then break end
if escape == 'u' then
local code = text:sub( index + 2, index + 5 )
if #code < 4 then break end
local number = tonumber( code, 16 )
if number then table.insert( pieces, vim.fn.nr2char( number ) ) end
index = index + 6
else
table.insert( pieces, ESCAPES[escape] or escape )
index = index + 2
end
else
table.insert( pieces, char )
index = index + 1
end
end
return table.concat( pieces ), length + 1, false
end
--- Tolerantly reads string valued fields out of streaming tool arguments.
--- The result is presentation only: an incomplete value never describes a
--- validated edit, so callers must not mutate a buffer from it.
--- @param text string accumulated argument bytes, possibly truncated mid token
--- @return table result complete flag, decoded value when parseable, and partial fields
local parse = function( text )
if type( text ) ~= 'string' or text == '' then
return { complete = false, value = nil, fields = {}, }
end
local ok, value = pcall( vim.json.decode, text, { luanil = { object = true, array = true, }, } )
if ok and type( value ) == 'table' then
local fields = {}
for key, item in pairs( value ) do
if type( item ) == 'string' then fields[key] = item end
end
return { complete = true, value = value, fields = fields, }
end
local fields = {}
local index = 1
local length = #text
while index <= length do
local key_start = text:find( '"', index, true )
if not key_start then break end
local key, after_key, closed = read_string( text, key_start + 1 )
if not closed then break end
local separator = text:find( '^%s*:%s*', after_key )
if separator then
local _, value_start = text:find( '^%s*:%s*', after_key )
local first = text:sub( value_start + 1, value_start + 1 )
if first == '"' then
local item, after_value = read_string( text, value_start + 2 )
fields[key] = item
index = after_value
else
index = value_start + 1
end
else
index = after_key
end
end
return { complete = false, value = nil, fields = fields, }
end
--- Describes streaming edit intent for ghost presentation.
local intent = function( tool_name, arguments_text )
local result = parse( arguments_text )
local fields = result.fields
local path = fields.path or fields.file_path or fields.filePath
local body = fields.new_text or fields.newText or fields.content or fields.text
return {
complete = result.complete,
tool = tool_name,
path = path,
text = body,
value = result.value,
}
end
return {
parse = parse,
intent = intent,
}