plugin.lua
Branches > main > ee3f3d0 > files / nvim / lua / parinfer / plugin.lua
--- Modified version of https://github.com/gpanders/nvim-parinfer
--- See ./LICENSE
vim.g.parinfer_mode = "smart"
vim.g.parinfer_enabled = true
vim.g.parinfer_force_balance = false
vim.g.parinfer_comment_chars = {";"}
local api = vim.api
local diff = (vim.text.diff or vim.diff)
local parinfer = require("parinfer.parinfer")
local modes = {indent = parinfer.indentMode,
paren = parinfer.parenMode,
smart = parinfer.smartMode}
local ns = api.nvim_create_namespace("parinfer")
local state = setmetatable({}, {__index = function(t, k)
t[k] = {}
return t[k]
end})
local function normalize_bool(val)
if type(val) == "boolean" then
return val
end
if val == nil then
return nil
end
return val ~= 0
end
local function get_option(opt)
local b = vim.b[opt] or vim.g[opt]
if b == nil then
return vim.g[opt]
else
return b
end
end
local function invoke_parinfer(bufnr, text, lnum, col)
local _let_32_ = (state[bufnr]["prev-cursor"] or {})
local prev_lnum = _let_32_[1]
local prev_col = _let_32_[2]
local changes = state[bufnr].changes
local request = {commentChars = get_option("parinfer_comment_chars"), prevCursorLine = prev_lnum, prevCursorX = prev_col, cursorLine = lnum, cursorX = (col + 1), changes = changes, forceBalance = normalize_bool(get_option("parinfer_force_balance"))}
local response = modes[get_option("parinfer_mode")](text, request)
state[bufnr]["changes"] = {}
return response
end
-- Does kidna flicker
local function update_buffer(bufnr, old_contents, new_contents)
api.nvim_command("silent! undojoin")
state[bufnr]["locked"] = true
do
local new_lines = vim.split(new_contents, "\n")
local hunks = diff(old_contents, new_contents, {result_type = "indices"})
for _, _33_ in ipairs(hunks) do
local start_a = _33_[1]
local count_a = _33_[2]
local start_b = _33_[3]
local count_b = _33_[4]
local lines
do
local tbl_21_ = {}
local i_22_ = 0
for i = start_b, (start_b + count_b) do
local val_23_ = new_lines[i]
if (nil ~= val_23_) then
i_22_ = (i_22_ + 1)
tbl_21_[i_22_] = val_23_
else
end
end
lines = tbl_21_
end
api.nvim_buf_set_lines(bufnr, (start_a - 1), (start_a + count_a), false, lines)
end
end
local function _35_()
state[bufnr]["locked"] = false
return nil
end
return vim.schedule(_35_)
end
local function highlight_error(bufnr, err)
api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
if err then
local lnum,col = (err.lineNo - 1), (err.x - 1)
return vim.highlight.range(bufnr, ns, "Error", {lnum, col}, {lnum, (col + 1)}, "c")
else
return nil
end
end
local function is_undo_leaf()
local _let_37_ = vim.fn.undotree()
local seq_cur = _let_37_["seq_cur"]
local seq_last = _let_37_["seq_last"]
return (seq_cur == seq_last)
end
local function should_run(bufnr)
return (normalize_bool(get_option("parinfer_enabled")) and not state[bufnr].locked and not vim.o.paste and not vim.bo.readonly and vim.bo.modifiable and (vim.b[bufnr].changedtick ~= state[bufnr].changedtick) and is_undo_leaf())
end
local elapsed_times = setmetatable({}, {__index = function(t, k)
t[k] = {}
return rawget(t, k)
end})
local function process_buffer(bufnr)
if should_run(bufnr) then
local start = vim.loop.hrtime()
local winnr = api.nvim_get_current_win()
local _let_39_ = api.nvim_win_get_cursor(winnr)
local lnum = _let_39_[1]
local col = _let_39_[2]
local contents = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
local text = table.concat(contents, "\n")
local response = invoke_parinfer(bufnr, text, lnum, col)
local new_lnum = response["cursorLine"]
local new_col = response["cursorX"]
state[bufnr]["changedtick"] = vim.b[bufnr].changedtick
state[bufnr]["tabstops"] = response.tabStops
state[bufnr]["prev-cursor"] = {new_lnum, new_col}
if (response.text ~= text) then
vim.schedule(function ()
update_buffer(bufnr, text, response.text)
return api.nvim_win_set_cursor(winnr, {new_lnum, (new_col - 1)})
end
)
else
end
highlight_error(bufnr, response.error)
return table.insert(elapsed_times[bufnr], (vim.loop.hrtime() - start))
else
return nil
end
end
local function slice(lines, start_row, start_col, row_offset, col_offset)
local start_row0 = (start_row + 1)
local start_col0 = (start_col + 1)
local function get_offset_or_something()
if row_offset == 0 then
return start_col0 + col_offset - 1
else
return -1
end
end
local first_line = string.sub(lines[start_row0], start_col0, get_offset_or_something())
local out = {first_line}
for i = (start_row0 + 1), ((start_row0 + row_offset) - 1) do
local line = lines[i]
table.insert(out, line)
end
if (row_offset ~= 0) then
local function _45_()
if ((0 < col_offset) and lines[(start_row0 + row_offset)]) then
return string.sub(lines[(start_row0 + row_offset)], 1, col_offset)
else
return ""
end
end
table.insert(out, _45_())
end
return out
end
local function on_bytes(_, bufnr, _0, start_row, start_col, _1, old_end_row, old_end_col, _2, new_end_row, new_end_col)
if (normalize_bool(get_option("parinfer_enabled")) and not state[bufnr].locked) then
local _let_47_ = state[bufnr]
local prev_contents = _let_47_["prev-contents"]
local contents = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
if (start_row < #prev_contents) then
local old_text = slice(prev_contents, start_row, start_col, old_end_row, old_end_col)
local new_text
if (start_row < #contents) then
new_text = slice(contents, start_row, start_col, new_end_row, new_end_col)
else
new_text = {""}
end
if not state[bufnr].changes then
state[bufnr]["changes"] = {}
else
end
table.insert(state[bufnr].changes, {oldText = table.concat(old_text, "\n"), newText = table.concat(new_text, "\n"), lineNo = (start_row + 1), x = (start_col + 1)})
else
end
state[bufnr]["prev-contents"] = contents
end
end
local function enter_buffer()
local bufnr = vim.api.nvim_get_current_buf()
local contents = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
state[bufnr]["changedtick"] = -1
state[bufnr]["prev-contents"] = contents
vim.api.nvim_buf_attach(bufnr, false, {on_bytes = on_bytes})
local mode = vim.g.parinfer_mode
vim.g.parinfer_mode = "paren"
process_buffer(bufnr)
vim.g.parinfer_mode = mode
end
local function cursor_moved(bufnr)
return vim.schedule(
function()
local cursor = vim.api.nvim_win_get_cursor(0)
local lnum = cursor[1]
local col = cursor[2]
state[bufnr]["prev-cursor"] = {lnum, (col + 1)}
end
)
end
--- Setup
local function setup()
local bo = vim.bo
local wo = vim.wo
if wo.previewwindow or bo.buftype == "prompt" then
return
end
local bufnr = vim.api.nvim_get_current_buf()
vim.b.parinfer_enabled = vim.g.parinfer_enabled ~= false
enter_buffer()
vim.api.nvim_exec_autocmds("User", {
pattern = "Parinfer",
})
local aug = vim.api.nvim_create_augroup("parinfer", { clear = true })
vim.api.nvim_create_autocmd(
{ "TextChanged", "TextChangedI", "TextChangedP" },
{
buffer = bufnr,
group = aug,
callback = function()
process_buffer(bufnr)
end,
}
)
vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" },
{
buffer = bufnr,
group = aug,
callback = function()
cursor_moved(bufnr)
end,
}
)
end
return {setup = setup}