Skip to content

Commit

Permalink
Correctly handle advancing backwards
Browse files Browse the repository at this point in the history
When moving backward to a previous variable, don't replace it with its
default value if it's already been resolved. Also reset any unresolved
variables back to their placeholder values.

This commit also contains some minor refactoring and comment additions.
  • Loading branch information
gpanders committed Jul 26, 2021
1 parent f611ea5 commit f401e23
Showing 1 changed file with 90 additions and 86 deletions.
176 changes: 90 additions & 86 deletions lua/snippets/inserters/extmarks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,6 @@ M.post_transform_marker_format = "${|%s}"
M.zero_pattern = "$0"
M.hl_group = "Visual"

local function update_structure(evaluator, resolved_inputs)
local S = evaluator.evaluate_structure(resolved_inputs)

local placeholders = evaluator.evaluate_inputs(resolved_inputs)
for i, v in ipairs(evaluator.inputs) do
if not resolved_inputs[i] then
S[v.first_index] = M.marker_with_placeholder_format:format(v.id, placeholders[i])
end
end

for i, v in ipairs(evaluator.structure) do
if U.is_variable(v) and v.transform and not v.id then
S[i] = M.post_transform_marker_format:format(i)
end
end

if evaluator.zero_index then
S[evaluator.zero_index] = M.zero_pattern
end

return S
end

local function set_extmark(id, line, col, end_line, end_col, hl_group)
api.nvim_buf_set_extmark(0, ns, line, col, {
id = id,
Expand Down Expand Up @@ -63,10 +40,29 @@ end
local function entrypoint(structure)
local evaluator = U.evaluate_snippet(structure)

local S = update_structure(evaluator, {})
-- Evalute the structure and insert placeholder markers for input variables
local S = evaluator.evaluate_structure({})

local placeholders = evaluator.evaluate_inputs({})
for i, v in ipairs(evaluator.inputs) do
S[v.first_index] = M.marker_with_placeholder_format:format(v.id, placeholders[i])
end

-- Insert markers for anonymouse transformations
for i, v in ipairs(evaluator.structure) do
if U.is_variable(v) and v.transform and not v.id then
S[i] = M.post_transform_marker_format:format(i)
end
end

-- If the snippet contains a $0, insert a marker for the where the cursor will end up
if evaluator.zero_index then
S[evaluator.zero_index] = M.zero_pattern
end

local cursor_mark_id

-- Write the snippet to the buffer and create the extmarks
do
local lnum, col = unpack(api.nvim_win_get_cursor(0))

Expand All @@ -81,12 +77,11 @@ local function entrypoint(structure)

for i, v in ipairs(evaluator.structure) do
local s = S[i]
if i == evaluator.zero_index then
cursor_mark_id = i
end

if U.is_variable(v) then
set_extmark(i, lnum - 1, col, lnum - 1, col + #s)
if i == evaluator.zero_index then
cursor_mark_id = i
end
end

local tail = s:gsub("[^\n]*\n", function()
Expand All @@ -104,80 +99,89 @@ local function entrypoint(structure)
end

local current_index = 0
local current_var
local resolved_inputs = {}

local R
R = {
advance = function(offset)
offset = offset or 1
current_index = math.max(math.min(current_index + offset, #evaluator.inputs + 1), 0)
if current_index == 0 then
R.aborted = true
cleanup()
return true
end
local R = { aborted = false, finished = false }

-- User has moved past the last variable, so apply transformations and move the cursor to the
-- zero point
if current_index > #evaluator.inputs then
for i, v in pairs(evaluator.structure) do
if U.is_variable(v) and v.transform and not v.id then
set_extmark_text(i, S[i])
end
function R.advance(offset)
offset = offset or 1
current_index = math.max(math.min(current_index + offset, #evaluator.inputs + 1), 0)
if current_index == 0 then
R.aborted = true
cleanup()
return true
end

-- User has moved past the last variable, so apply transformations and move the cursor to the
-- zero point
if current_index > #evaluator.inputs then
for i, v in pairs(evaluator.structure) do
if U.is_variable(v) and v.transform and not v.id then
set_extmark_text(i, S[i])
end
end

-- Move cursor to zero point
local cur_row, cur_col, cur_end_row, cur_end_col = get_extmark_pos(cursor_mark_id)
api.nvim_buf_set_text(0, cur_row, cur_col, cur_end_row, cur_end_col, {})
api.nvim_win_set_cursor(0, { cur_row + 1, cur_col })
-- Move cursor to zero point
local cur_row, cur_col, cur_end_row, cur_end_col = get_extmark_pos(cursor_mark_id)
api.nvim_buf_set_text(0, cur_row, cur_col, cur_end_row, cur_end_col, {})
api.nvim_win_set_cursor(0, { cur_row + 1, cur_col })

cleanup()
R.finished = true
return true
end
R.finished = true
cleanup()
return true
end

local var = evaluator.inputs[current_index]
current_var = evaluator.inputs[current_index]

-- Clear highlights on all extmarks except those for current variable
for i, v in ipairs(evaluator.structure) do
if U.is_variable(v) then
local hl_group = v.order == current_index and M.hl_group or nil
local row, col, end_row, end_col = get_extmark_pos(i)
set_extmark(i, row, col, end_row, end_col, hl_group)
-- Clear highlights on all extmarks except those for current variable
for i, v in ipairs(evaluator.structure) do
if U.is_variable(v) then
local hl_group = v.order == current_index and M.hl_group or nil
local row, col, end_row, end_col = get_extmark_pos(i)
set_extmark(i, row, col, end_row, end_col, hl_group)
end
end

-- Set unresolved variables to their placeholder values
placeholders = evaluator.evaluate_inputs(resolved_inputs)
for i, v in ipairs(evaluator.structure) do
if U.is_variable(v) and v.is_input and (not resolved_inputs[v.id] or resolved_inputs[v.id] == "") then
local text = placeholders[v.id]
if v.id ~= current_var.id then
text = M.marker_with_placeholder_format:format(v.id, text)
end
set_extmark_text(i, text)
end
end

-- Move the cursor to the next variable and update the placeholder text
set_extmark_text(var.first_index, var.default)
local mark_row, mark_col, _, mark_end_col = get_extmark_pos(var.first_index)
api.nvim_win_set_cursor(0, { mark_row + 1, mark_end_col })
-- Move the cursor to the current variable
local mark_row, mark_col, _, mark_end_col = get_extmark_pos(current_var.first_index)
api.nvim_win_set_cursor(0, { mark_row + 1, mark_end_col })

vim.register_keystroke_callback(
vim.schedule_wrap(function()
if R.finished or R.aborted then
return
end
vim.register_keystroke_callback(
vim.schedule_wrap(function()
if R.finished or R.aborted then
return
end

mark_row, mark_col, _, mark_end_col = get_extmark_pos(var.first_index)
local line = api.nvim_buf_get_lines(0, mark_row, mark_row + 1, true)[1]
local mark_text = line:sub(mark_col + 1, mark_end_col)
mark_row, mark_col, _, mark_end_col = get_extmark_pos(current_var.first_index)
local line = api.nvim_buf_get_lines(0, mark_row, mark_row + 1, true)[1]
local mark_text = line:sub(mark_col + 1, mark_end_col)

resolved_inputs[var.id] = mark_text
S = evaluator.evaluate_structure(resolved_inputs)
resolved_inputs[current_var.id] = mark_text
S = evaluator.evaluate_structure(resolved_inputs)

for i = var.first_index + 1, #evaluator.structure do
local v = evaluator.structure[i]
if U.is_variable(v) and v.id == var.id then
set_extmark_text(i, S[i])
end
for i = current_var.first_index + 1, #evaluator.structure do
local v = evaluator.structure[i]
if U.is_variable(v) and v.id == current_var.id then
set_extmark_text(i, S[i])
end
end),
ns
)
end,
finished = false,
aborted = false,
}
end
end),
ns
)
end

return R
end
Expand Down

0 comments on commit f401e23

Please sign in to comment.