From 214d145faf4c84e9fcd6ea8ee711869ce50ff6d9 Mon Sep 17 00:00:00 2001 From: L3MON4D3 Date: Sat, 23 Sep 2023 19:26:41 +0200 Subject: [PATCH] split history=false/true into more specific options. keep_roots=true stores all snippet-roots, while false will only keep the most recently expanded root. link_roots makes it possible to jump between roots, link_children makes it possible to jump back into, and between, children of one snippet. --- Examples/snippets.lua | 5 +- lua/luasnip/config.lua | 16 ++++- lua/luasnip/init.lua | 9 ++- lua/luasnip/nodes/insertNode.lua | 4 -- lua/luasnip/nodes/snippet.lua | 112 +++++++++++++++---------------- 5 files changed, 81 insertions(+), 65 deletions(-) diff --git a/Examples/snippets.lua b/Examples/snippets.lua index 512716ad2..c8cfa9c1f 100644 --- a/Examples/snippets.lua +++ b/Examples/snippets.lua @@ -25,7 +25,10 @@ local conds_expand = require("luasnip.extras.conditions.expand") -- Every unspecified option will be set to the default. ls.setup({ - history = true, + keep_roots = true, + link_roots = true, + link_children = true, + -- Update more often, :h events for more info. update_events = "TextChanged,TextChangedI", -- Snippets aren't automatically removed if their text is deleted. diff --git a/lua/luasnip/config.lua b/lua/luasnip/config.lua index f55aa2cc8..50ccddf3b 100644 --- a/lua/luasnip/config.lua +++ b/lua/luasnip/config.lua @@ -48,7 +48,11 @@ local lazy_snip_env = { } local defaults = { - history = false, + -- corresponds to legacy "history=false". + keep_roots = false, + link_roots = false, + link_children = false, + update_events = "InsertLeave", -- see :h User, event should never be triggered(except if it is `doautocmd`'d) region_check_events = nil, @@ -208,6 +212,16 @@ c = { set_snip_env(conf, user_config) + -- handle legacy-key history. + if user_config.history ~= nil then + conf.keep_roots = user_config.history + conf.link_roots = user_config.history + conf.link_children = user_config.history + + -- unset key to prevent handling twice. + conf.history = nil + end + for k, v in pairs(user_config) do conf[k] = v end diff --git a/lua/luasnip/init.lua b/lua/luasnip/init.lua index 478697dc4..3ce1e9a18 100644 --- a/lua/luasnip/init.lua +++ b/lua/luasnip/init.lua @@ -253,7 +253,7 @@ local function snip_expand(snippet, opts) opts.jump_into_func(snip) local buf_snippet_roots = session.snippet_roots[vim.api.nvim_get_current_buf()] - if not session.config.history and #buf_snippet_roots > 1 then + if not session.config.keep_roots and #buf_snippet_roots > 1 then -- if history is not set, and there is more than one snippet-root, -- remove the other one. -- The nice thing is: since we maintain that #buf_snippet_roots == 1 @@ -730,10 +730,15 @@ local function activate_node(pos) snippet_preference = node_util.binarysearch_preference.interactive }) + if not node then + error("Could not find a node at that position.") + return + end + -- only activate interactive nodes, or nodes that are immediately nested -- inside a choiceNode. if not node_util.interactive_node(node) and rawget(node, "choice") == nil then - print("Refusing to activate a non-interactive node.") + error("Refusing to activate a non-interactive node.") return end diff --git a/lua/luasnip/nodes/insertNode.lua b/lua/luasnip/nodes/insertNode.lua index 3fd0b3070..bd1cae1f4 100644 --- a/lua/luasnip/nodes/insertNode.lua +++ b/lua/luasnip/nodes/insertNode.lua @@ -245,10 +245,6 @@ function InsertNode:input_leave_children(dry_run) dry_run.active[self] = false else self.inner_active = false - if not session.config.history then - self.inner_first = nil - self.inner_last = nil - end end end diff --git a/lua/luasnip/nodes/snippet.lua b/lua/luasnip/nodes/snippet.lua index 13a1b54d3..c3271cdaf 100644 --- a/lua/luasnip/nodes/snippet.lua +++ b/lua/luasnip/nodes/snippet.lua @@ -536,73 +536,71 @@ local function insert_into_jumplist(snippet, start_node, current_node, parent_no next = next_snippet end - if session.config.history then - if parent_node then - local can_link_parent_node = node_util.linkable_node(parent_node) - -- snippetNode (which has to be empty to be viable here) and - -- insertNode can both deal with inserting a snippet inside them - -- (ie. hooking it up st. it can be visited after jumping back to - -- the snippet of parent). - -- in all cases - if prev ~= nil then - -- if we have a previous snippet we can link to, just do that. - prev.next.next = snippet - start_node.prev = prev.insert_nodes[0] - else - if can_link_parent_node then + -- whether roots should be linked together. + local link_roots = session.config.link_roots + + -- whether children of the same snippet should be linked to their parent + -- and eachother. + local link_children = session.config.link_children + + if parent_node then + local can_link_parent_node = node_util.linkable_node(parent_node) + -- snippetNode (which has to be empty to be viable here) and + -- insertNode can both deal with inserting a snippet inside them + -- (ie. hooking it up st. it can be visited after jumping back to + -- the snippet of parent). + -- in all cases + if link_children and prev ~= nil then + -- if we have a previous snippet we can link to, just do that. + prev.next.next = snippet + start_node.prev = prev.insert_nodes[0] + else + if can_link_parent_node then + -- only jump from parent to child if link_children is set. + if link_children then -- prev is nil, but we can link up using the parent. parent_node.inner_first = snippet - start_node.prev = parent_node - else - -- no way to link up, just jump back to current_node, but - -- don't jump from current_node to this snippet (I feel - -- like that should be good: one can still get back to ones - -- previous history, and we don't mess up whatever jumps - -- are set up around current_node) - start_node.prev = current_node end - end - - -- exact same reasoning here as in prev-case above, omitting comments. - if next ~= nil then - -- jump from next snippets start_node to $0. - next.prev.prev = snippet.insert_nodes[0] - -- jump from $0 to next snippet (skip its start_node) - snippet.insert_nodes[0].next = next + -- make sure we can jump back to the parent. + start_node.prev = parent_node else - if can_link_parent_node then - parent_node.inner_last = snippet.insert_nodes[0] - snippet.insert_nodes[0].next = parent_node - else - snippet.insert_nodes[0].next = current_node - end - end - else - -- inserted into top-level snippet-forest, just hook up with prev, next. - -- prev and next have to be snippets or nil, in this case. - if prev ~= nil then - prev.next.next = snippet - start_node.prev = prev.insert_nodes[0] - end - if next ~= nil then - snippet.insert_nodes[0].next = next - next.prev.prev = snippet.insert_nodes[0] + -- no way to link up, just jump back to current_node, but + -- don't jump from current_node to this snippet (I feel + -- like that should be good: one can still get back to ones + -- previous history, and we don't mess up whatever jumps + -- are set up around current_node) + start_node.prev = current_node end end - else - -- don't store history! - -- Implement by only linking if this is expanded inside another node, and then only the outgoing jumps. - -- As soon as the i0/start_node is jumped from, this snippet will not be jumped into again. - -- (although, it is possible to enter it again, after leaving, by - -- expanding a snippet inside it. Not sure if this is undesirable, if - -- it is, we'll need to do cleanup, somehow) - if parent_node then - local can_link_parent_node = node_util.linkable_node(parent_node) + + -- exact same reasoning here as in prev-case above, omitting comments. + if link_children and next ~= nil then + -- jump from next snippets start_node to $0. + next.prev.prev = snippet.insert_nodes[0] + -- jump from $0 to next snippet (skip its start_node) + snippet.insert_nodes[0].next = next + else if can_link_parent_node then - start_node.prev = parent_node + if link_children then + parent_node.inner_last = snippet.insert_nodes[0] + end snippet.insert_nodes[0].next = parent_node + else + snippet.insert_nodes[0].next = current_node end end + -- don't link different root-nodes for unlinked_roots. + elseif link_roots then + -- inserted into top-level snippet-forest, just hook up with prev, next. + -- prev and next have to be snippets or nil, in this case. + if prev ~= nil then + prev.next.next = snippet + start_node.prev = prev.insert_nodes[0] + end + if next ~= nil then + snippet.insert_nodes[0].next = next + next.prev.prev = snippet.insert_nodes[0] + end end table.insert(sibling_snippets, own_indx, snippet)