fix: properly send and apply precise changes

this was really crazy but it seems to work?? can probably be simplified
a ton but not rn
This commit is contained in:
əlemi 2024-08-14 23:48:55 +02:00
parent 9ea11d41ac
commit 84afc0a864
Signed by: alemi
GPG key ID: A4895B84D311642C
2 changed files with 57 additions and 31 deletions

View file

@ -42,11 +42,20 @@ local function attach(name, force)
on_bytes = function(_, buf, tick, start_row, start_col, start_offset, old_end_row, old_end_col, old_end_byte_len, new_end_row, new_end_col, new_byte_len) on_bytes = function(_, buf, tick, start_row, start_col, start_offset, old_end_row, old_end_col, old_end_byte_len, new_end_row, new_end_col, new_byte_len)
if tick <= ticks[buf] then return end if tick <= ticks[buf] then return end
if id_buffer_map[buf] == nil then return true end -- unregister callback handler if id_buffer_map[buf] == nil then return true end -- unregister callback handler
local content = table.concat( print(string.format(
"start(row:%s, col:%s) offset:%s end(row:%s, col:%s new(row:%s, col:%s)) len(old:%s, new:%s)",
start_row, start_col, start_offset, old_end_row, old_end_col, new_end_row, new_end_col, old_end_byte_len, new_byte_len
))
local content
if new_byte_len == 0 then
content = ""
else
content = table.concat(
vim.api.nvim_buf_get_text(buf, start_row, start_col, start_row + new_end_row, start_col + new_end_col, {}), vim.api.nvim_buf_get_text(buf, start_row, start_col, start_row + new_end_row, start_col + new_end_col, {}),
'\n' '\n'
) )
-- print(string.format("%s %s %s %s -- '%s'", start_row, start_col, start_row + new_end_row, start_col + new_end_col, content)) end
print(string.format("sending: %s %s %s %s -- '%s'", start_row, start_col, start_row + new_end_row, start_col + new_end_col, content))
controller:send(start_offset, start_offset + old_end_byte_len, content) controller:send(start_offset, start_offset + old_end_byte_len, content)
end, end,
}) })
@ -54,6 +63,8 @@ local function attach(name, force)
-- hook clientbound callbacks -- hook clientbound callbacks
async.handler(name, controller, function(event) async.handler(name, controller, function(event)
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer) ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
-- print(" ~~ applying change ~~ " .. event.first .. ".." .. event.last .. "::[" .. event.content .. "]")
utils.buffer.set_content(buffer, event.content, event.first, event.last)
if event.hash ~= nil then if event.hash ~= nil then
if utils.hash(utils.buffer.get_content(buffer)) ~= event.hash then if utils.hash(utils.buffer.get_content(buffer)) ~= event.hash then
-- OUT OF SYNC! -- OUT OF SYNC!
@ -63,8 +74,6 @@ local function attach(name, force)
return return
end end
end end
-- print(" ~~ applying change ~~ " .. event.first .. ".." .. event.last .. "::" .. event.content)
utils.buffer.set_content(buffer, event.content, event.first, event.last)
end, 20) -- wait 20ms before polling again because it overwhelms libuv? end, 20) -- wait 20ms before polling again because it overwhelms libuv?
print(" ++ attached to buffer " .. name) print(" ++ attached to buffer " .. name)

View file

@ -1,16 +1,5 @@
local native = require('codemp.loader').load() local native = require('codemp.loader').load()
local function split_without_trim(str, sep)
local res = vim.fn.split(str, sep)
if str:sub(1,1) == "\n" then
table.insert(res, 1, '')
end
if str:sub(-1) == "\n" then
table.insert(res, '')
end
return res
end
local function order_tuples(x) -- TODO send help... local function order_tuples(x) -- TODO send help...
if x[1][1] < x[2][1] then if x[1][1] < x[2][1] then
return { { x[1][1], x[1][2] }, { x[2][1], x[2][2] } } return { { x[1][1], x[1][2] }, { x[2][1], x[2][2] } }
@ -54,31 +43,60 @@ local function buffer_get_content(buf)
return table.concat(lines, '\n') return table.concat(lines, '\n')
end end
-- TODO this seems to work but i lost my sanity over it. if you want
-- to try and make it better be warned api is madness but i will
-- thank you a lot because this is an ugly mess...
--
-- edge cases to test:
-- - [x] add newline in buffer
-- - [x] append newline to buffer
-- - [x] delete multiline
-- - [x] append at end of buffer
-- - [x] delete at end of buffer
-- - [x] delete line at end of buffer
-- - [x] delete multiline at end of buffer
-- - [x] autocomplete
local function buffer_set_content(buf, content, first, last) local function buffer_set_content(buf, content, first, last)
if first == nil and last == nil then if first == nil and last == nil then
local lines = split_without_trim(content, "\n") local lines = vim.split(content, "\n", {trimempty=false})
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
else else
local first_row, first_col, last_row, last_col local first_row, first_col, last_row, last_col
vim.api.nvim_buf_call(buf, function() vim.api.nvim_buf_call(buf, function()
first_row = vim.fn.byte2line(first + 1) - 1 first_row = vim.fn.byte2line(first + 1) - 1
if first_row == -2 then if first_row == -2 then
-- print("?? clamping start_row to start")
first_row = vim.fn.line('$') - 1 first_row = vim.fn.line('$') - 1
end end
first_col = first - (vim.fn.line2byte(first_row + 1) - 1) local first_col_byte = vim.fn.line2byte(first_row + 1) - 1
if first_col_byte == -2 then
-- print("?? clamping start_col to 0")
first_col = 0
else
first_col = first - first_col_byte
end
if first == last then
last_row = first_row
last_col = first_col
else
last_row = vim.fn.byte2line(last + 1) - 1 last_row = vim.fn.byte2line(last + 1) - 1
if last_row == -2 then if last_row == -2 then
local sp = vim.split(content, "\n", {trimempty=false}) print("?? clamping end_row to end")
last_row = first_row + (#sp - 1) last_row = vim.fn.line('$') - 1
last_col = string.len(sp[#sp]) last_col = last - vim.fn.line2byte(last_row + 1)
else else
last_col = last - (vim.fn.line2byte(last_row + 1) - 1) last_col = last - (vim.fn.line2byte(last_row + 1) - 1)
end end
end
end) end)
vim.api.nvim_buf_set_text( local content_array
buf, first_row, first_col, last_row, last_col, if content == "" then
split_without_trim(content, "\n") content_array = {}
) else
content_array = vim.split(content, "\n", {trimempty=false})
end
-- print(string.format("set [%s..%s::'%s'] -> start(row:%s col:%s) end(row:%s, col:%s)", first, last, content, first_row, first_col, last_row, last_col))
vim.api.nvim_buf_set_text(buf, first_row, first_col, last_row, last_col, content_array)
end end
end end
@ -120,7 +138,6 @@ end
return { return {
split_without_trim = split_without_trim,
order_tuples = order_tuples, order_tuples = order_tuples,
multiline_highlight = multiline_highlight, multiline_highlight = multiline_highlight,
cursor = { cursor = {