Skip to content

Commit

Permalink
improve adjustment of extmark-rgravs.
Browse files Browse the repository at this point in the history
Both performance-wise, by eliding many, many adjustments, and
implementation-wise.

For example, as soon as a parent does not share an endpoint with the
node we want to focus, we don't have to touch its rgravs, since they can
only be pushed away from the inserted text, no matter their gravity.
  • Loading branch information
L3MON4D3 committed May 25, 2023
1 parent fcdaa43 commit 7b35394
Show file tree
Hide file tree
Showing 10 changed files with 537 additions and 208 deletions.
4 changes: 2 additions & 2 deletions lua/luasnip/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ end

local function active_update_dependents()
local active = session.current_nodes[vim.api.nvim_get_current_buf()]
-- special case for startNode, cannot enter_node on those (and they can't
-- special case for startNode, cannot focus on those (and they can't
-- have dependents)
-- don't update if a jump/change_choice is in progress.
if not session.jump_active and active and active.pos > 0 then
Expand All @@ -440,7 +440,7 @@ local function active_update_dependents()
end

-- 'restore' orientation of extmarks, may have been changed by some set_text or similar.
ok, err = pcall(active.parent.enter_node, active.parent, active.indx)
ok, err = pcall(active.focus, active)
if not ok then
log.warn(
"Error while entering node in snippet %s: %s",
Expand Down
36 changes: 23 additions & 13 deletions lua/luasnip/nodes/choiceNode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function ChoiceNode:input_enter(_, dry_run)
end

self.mark:update_opts(self.ext_opts.active)
self.parent:enter_node(self.indx)
self:focus()

self.prev_choice_node = session.active_choice_node
session.active_choice_node = self
Expand Down Expand Up @@ -254,9 +254,9 @@ function ChoiceNode:set_choice(choice, current_node)
--
-- active_choice has to be disabled (nilled?) to prevent reading from
-- cleared mark in set_mark_rgrav (which will be called in
-- parent:set_text(self,...) a few lines below).
-- self:set_text({""}) a few lines below).
self.active_choice = nil
self.parent:set_text(self, { "" })
self:set_text({ "" })

self.active_choice = choice

Expand All @@ -269,14 +269,19 @@ function ChoiceNode:set_choice(choice, current_node)
self:init_positions(self.absolute_position)
self:init_insert_positions(self.absolute_insert_position)

-- self is still focused, from `set_text`.
self.active_choice:put_initial(self.mark:pos_begin_raw())
-- adjust gravity in left side of inserted node, such that it matches the
-- current gravity of self.
local _, to = self.mark:pos_begin_end_raw()
self.active_choice:subtree_set_pos_rgrav(to, -1, true)

self.active_choice:update_restore()
self.active_choice:update_all_dependents()
self:update_dependents()

-- Another node may have been entered in update_dependents.
self.parent:enter_node(self.indx)
self:focus()
self:event(events.change_choice)

if self.restore_cursor then
Expand Down Expand Up @@ -339,15 +344,6 @@ function ChoiceNode:exit()
self.active = false
end

-- val_begin/end may be nil, in this case that gravity won't be changed.
function ChoiceNode:set_mark_rgrav(rgrav_beg, rgrav_end)
Node.set_mark_rgrav(self, rgrav_beg, rgrav_end)
-- may be set to temporarily in change_choice.
if self.active_choice then
self.active_choice:set_mark_rgrav(rgrav_beg, rgrav_end)
end
end

function ChoiceNode:set_ext_opts(name)
Node.set_ext_opts(self, name)

Expand Down Expand Up @@ -403,6 +399,20 @@ function ChoiceNode:static_init()
self.active_choice:static_init()
end

function ChoiceNode:subtree_set_pos_rgrav(pos, direction, rgrav)
self.mark:set_rgrav(-direction, rgrav)
if self.active_choice then
self.active_choice:subtree_set_pos_rgrav(pos, direction, rgrav)
end
end

function ChoiceNode:subtree_set_rgrav(rgrav)
self.mark:set_rgravs(rgrav, rgrav)
if self.active_choice then
self.active_choice:subtree_set_rgrav(rgrav)
end
end

return {
C = C,
}
54 changes: 37 additions & 17 deletions lua/luasnip/nodes/dynamicNode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function DynamicNode:get_docstring()
return self.docstring
end

-- DynamicNode's don't have static text, nop these.
-- DynamicNode's don't have static text, only set as visible.
function DynamicNode:put_initial(_)
self.visible = true
end
Expand Down Expand Up @@ -136,10 +136,10 @@ function DynamicNode:update()
self.snip:exit()
self.snip = nil

-- enters node.
self.parent:set_text(self, { "" })
-- focuses node.
self:set_text({ "" })
else
self.parent:enter_node(self.indx)
self:focus()
if not args then
-- no snippet exists, set an empty one.
tmp = SnippetNode(nil, {})
Expand Down Expand Up @@ -184,8 +184,16 @@ function DynamicNode:update()
end
tmp:indent(self.parent.indentstr)

self.parent:enter_node(self.indx)
tmp:put_initial(self.mark:pos_begin_raw())
-- sets own extmarks false,true
self:focus()
local from, to = self.mark:pos_begin_end_raw()
-- inserts nodes with extmarks false,false
tmp:put_initial(from)
-- adjust gravity in left side of snippet, such that it matches the current
-- gravity of self.
tmp:subtree_set_pos_rgrav(to, -1, true)

self.snip = tmp

-- Update, tbh no idea how that could come in handy, but should be done.
-- Both are needed, because
Expand All @@ -194,7 +202,6 @@ function DynamicNode:update()
tmp:update()
tmp:update_all_dependents()

self.snip = tmp
self:update_dependents()
end

Expand Down Expand Up @@ -293,13 +300,6 @@ function DynamicNode:update_static()
self:update_dependents_static()
end

function DynamicNode:set_mark_rgrav(val_begin, val_end)
Node.set_mark_rgrav(self, val_begin, val_end)
if self.snip then
self.snip:set_mark_rgrav(val_begin, val_end)
end
end

function DynamicNode:exit()
self.visible = false
self.mark:clear()
Expand Down Expand Up @@ -331,7 +331,6 @@ end
function DynamicNode:update_restore()
-- only restore snippet if arg-values still match.
if self.stored_snip and vim.deep_equal(self:get_args(), self.last_args) then
-- prevent entering the uninitialized snip in enter_node in a few lines.
local tmp = self.stored_snip

tmp.mark =
Expand All @@ -347,8 +346,15 @@ function DynamicNode:update_restore()
tmp:set_dependents()
tmp:set_argnodes(self.parent.snippet.dependents_dict)

self.parent:enter_node(self.indx)
tmp:put_initial(self.mark:pos_begin_raw())
-- sets own extmarks false,true
self:focus()
-- inserts nodes with extmarks false,false
local from, to = self.mark:pos_begin_end_raw()
tmp:put_initial(from)
-- adjust gravity in left side of snippet, such that it matches the current
-- gravity of self.
tmp:subtree_set_pos_rgrav(to, -1, true)

tmp:update_restore()

self.snip = tmp
Expand Down Expand Up @@ -399,6 +405,20 @@ function DynamicNode:resolve_position(position)
return self.snip
end

function DynamicNode:subtree_set_pos_rgrav(pos, direction, rgrav)
self.mark:set_rgrav(-direction, rgrav)
if self.snip then
self.snip:subtree_set_pos_rgrav(pos, direction, rgrav)
end
end

function DynamicNode:subtree_set_rgrav(rgrav)
self.mark:set_rgravs(rgrav, rgrav)
if self.snip then
self.snip:subtree_set_rgrav(rgrav)
end
end

return {
D = D,
}
7 changes: 4 additions & 3 deletions lua/luasnip/nodes/functionNode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ function FunctionNode:update()
if vim.bo.expandtab then
util.expand_tabs(text, util.tab_width(), #self.parent.indentstr)
end

-- don't expand tabs in parent.indentstr, use it as-is.
self.parent:set_text(self, util.indent(text, self.parent.indentstr))
self:set_text(util.indent(text, self.parent.indentstr))
self:update_dependents()
end

Expand Down Expand Up @@ -89,13 +90,13 @@ end
function FunctionNode:update_restore()
-- only if args still match.
if self.static_text and vim.deep_equal(self:get_args(), self.last_args) then
self.parent:set_text(self, self.static_text)
self:set_text(self.static_text)
else
self:update()
end
end

-- FunctionNode's don't have static text, nop these.
-- FunctionNode's don't have static text, only set visibility.
function FunctionNode:put_initial(_)
self.visible = true
end
Expand Down
41 changes: 31 additions & 10 deletions lua/luasnip/nodes/insertNode.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local InsertNode = require("luasnip.nodes.node").Node:new()
local Node = require("luasnip.nodes.node")
local InsertNode = Node.Node:new()
local ExitNode = InsertNode:new()
local util = require("luasnip.util.util")
local types = require("luasnip.util.types")
Expand Down Expand Up @@ -42,26 +43,46 @@ function ExitNode:input_enter(no_move, dry_run)
InsertNode.input_enter(self, no_move, dry_run)
else
-- -1-node:
self:set_mark_rgrav(true, true)
if not no_move then
local mark_begin_pos = self.mark:pos_begin_raw()
-- set rgrav true on left side of snippet. Text inserted now pushes the
-- snippet, and is not contained in it.
local begin_pos = self.mark:pos_begin_raw()
self.parent:subtree_set_pos_rgrav(begin_pos, 1, true)

if not no_move then
if vim.fn.mode() == "i" then
util.insert_move_on(mark_begin_pos)
util.insert_move_on(begin_pos)
else
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes("<Esc>", true, false, true),
"n",
true
)
util.normal_move_on_insert(mark_begin_pos)
util.normal_move_on_insert(begin_pos)
end
end

self:event(events.enter)
end
end

function ExitNode:focus()
local lrgrav, rrgrav
local snippet = self.parent
-- if last of first node of the snippet, make inserted text move out of snippet.
if snippet.nodes[#snippet.nodes] == self then
lrgrav = false
rrgrav = false
elseif snippet.nodes[1] == self then
lrgrav = true
rrgrav = true
else
lrgrav = false
rrgrav = true
end

Node.focus_node(self, lrgrav, rrgrav)
end

function ExitNode:input_leave(no_move, dry_run)
if dry_run then
return
Expand Down Expand Up @@ -111,9 +132,11 @@ function InsertNode:input_enter(no_move, dry_run)
self.visited = true
self.mark:update_opts(self.ext_opts.active)

if not no_move then
self.parent:enter_node(self.indx)
-- no_move only prevents moving the cursor, but the active node should
-- still be focused.
self:focus()

if not no_move then
-- SELECT snippet text only when there is text to select (more oft than not there isnt).
local mark_begin_pos, mark_end_pos = self.mark:pos_begin_end_raw()
if not util.pos_equal(mark_begin_pos, mark_end_pos) then
Expand All @@ -132,8 +155,6 @@ function InsertNode:input_enter(no_move, dry_run)
util.normal_move_on_insert(mark_begin_pos)
end
end
else
self.parent:enter_node(self.indx)
end

self:event(events.enter)
Expand Down
Loading

0 comments on commit 7b35394

Please sign in to comment.