Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(luasnip): add extended configuration #3525

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 0 additions & 6 deletions lua/lvim/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ function M:init()
local lvim_lsp_config = require "lvim.lsp.config"
lvim.lsp = vim.deepcopy(lvim_lsp_config)

lvim.builtin.luasnip = {
sources = {
friendly_snippets = true,
},
}

lvim.builtin.bigfile = {
active = true,
config = {},
Expand Down
1 change: 1 addition & 0 deletions lua/lvim/core/builtins/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ local builtins = {
"lvim.core.lualine",
"lvim.core.alpha",
"lvim.core.mason",
"lvim.core.luasnip",
}

function M.config(config)
Expand Down
100 changes: 4 additions & 96 deletions lua/lvim/core/cmp.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local M = {}

M.methods = {}

local has_words_before = function()
Expand All @@ -22,100 +23,7 @@ end

M.methods.feedkeys = feedkeys

---when inside a snippet, seeks to the nearest luasnip field if possible, and checks if it is jumpable
---@param dir number 1 for forward, -1 for backward; defaults to 1
---@return boolean true if a jumpable luasnip field is found while inside a snippet
local function jumpable(dir)
local luasnip_ok, luasnip = pcall(require, "luasnip")
if not luasnip_ok then
return false
end

local win_get_cursor = vim.api.nvim_win_get_cursor
local get_current_buf = vim.api.nvim_get_current_buf

---sets the current buffer's luasnip to the one nearest the cursor
---@return boolean true if a node is found, false otherwise
local function seek_luasnip_cursor_node()
-- TODO(kylo252): upstream this
-- for outdated versions of luasnip
if not luasnip.session.current_nodes then
return false
end

local node = luasnip.session.current_nodes[get_current_buf()]
if not node then
return false
end

local snippet = node.parent.snippet
local exit_node = snippet.insert_nodes[0]

local pos = win_get_cursor(0)
pos[1] = pos[1] - 1

-- exit early if we're past the exit node
if exit_node then
local exit_pos_end = exit_node.mark:pos_end()
if (pos[1] > exit_pos_end[1]) or (pos[1] == exit_pos_end[1] and pos[2] > exit_pos_end[2]) then
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil

return false
end
end

node = snippet.inner_first:jump_into(1, true)
while node ~= nil and node.next ~= nil and node ~= snippet do
local n_next = node.next
local next_pos = n_next and n_next.mark:pos_begin()
local candidate = n_next ~= snippet and next_pos and (pos[1] < next_pos[1])
or (pos[1] == next_pos[1] and pos[2] < next_pos[2])

-- Past unmarked exit node, exit early
if n_next == nil or n_next == snippet.next then
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil

return false
end

if candidate then
luasnip.session.current_nodes[get_current_buf()] = node
return true
end

local ok
ok, node = pcall(node.jump_from, node, 1, true) -- no_move until last stop
if not ok then
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil

return false
end
end

-- No candidate, but have an exit node
if exit_node then
-- to jump to the exit node, seek to snippet
luasnip.session.current_nodes[get_current_buf()] = snippet
return true
end

-- No exit node, exit from snippet
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil
return false
end

if dir == -1 then
return luasnip.in_snippet() and luasnip.jumpable(-1)
else
return luasnip.in_snippet() and seek_luasnip_cursor_node() and luasnip.jumpable(1)
end
end

M.methods.jumpable = jumpable
M.methods.jumpable = require("lvim.core.luasnip").methods.jumpable

M.config = function()
local status_cmp_ok, cmp_types = pcall(require, "cmp.types.cmp")
Expand Down Expand Up @@ -302,9 +210,9 @@ M.config = function()
cmp.select_next_item()
elseif luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
elseif jumpable(1) then
elseif M.methods.jumpable(1) then
luasnip.jump(1)
elseif has_words_before() then
elseif M.methods.has_words_before() then
-- cmp.complete()
fallback()
else
Expand Down
163 changes: 163 additions & 0 deletions lua/lvim/core/luasnip.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
local M = {}

-- see luasnip/util/types.lua
local types = {
textNode = 1,
insertNode = 2,
functionNode = 3,
snippetNode = 4,
choiceNode = 5,
dynamicNode = 6,
snippet = 7,
exitNode = 8,
restoreNode = 9,
node_types = { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
}

function M.config()
lvim.builtin.luasnip = {
opalmay marked this conversation as resolved.
Show resolved Hide resolved
active = true,
sources = {
friendly_snippets = true,
},
opts = {
history = false,
update_events = "InsertLeave",
enable_autosnippets = false,
ext_opts = {
-- Show virtual text to signal when you are inside an sippets
[types.insertNode] = {
active = {
virt_text = { { "<-- snip", "BufferInactiveIndex" } },
},
},
-- Helps to notice when you are within a choice node
[types.choiceNode] = {
active = {
virt_text = { { "<-- choice", "BufferInactiveIndex" } },
},
},
},
},
}
end

function M.setup()
local utils = require "lvim.utils"
local paths = {}
if lvim.builtin.luasnip.sources.friendly_snippets then
paths[#paths + 1] = utils.join_paths(get_runtime_dir(), "site", "pack", "lazy", "opt", "friendly-snippets")
end

local user_snippets = utils.join_paths(get_config_dir(), "snippets")
if utils.is_directory(user_snippets) then
paths[#paths + 1] = user_snippets
end

local luasnip = require "luasnip"
luasnip.config.set_config(lvim.builtin.luasnip.opts)

-- When no paths are provided, luasnip will search in the runtimepath
require("luasnip.loaders.from_lua").lazy_load()
require("luasnip.loaders.from_vscode").lazy_load { paths = paths }
require("luasnip.loaders.from_snipmate").lazy_load()
end

---when inside a snippet, seeks to the nearest luasnip field if possible, and checks if it is jumpable
---@param dir number 1 for forward, -1 for backward; defaults to 1
---@return boolean|nil true if a jumpable luasnip field is found while inside a snippet
local function jumpable(dir)
local luasnip_ok, luasnip = pcall(require, "luasnip")
if not luasnip_ok then
return false
end

local win_get_cursor = vim.api.nvim_win_get_cursor
local get_current_buf = vim.api.nvim_get_current_buf

---sets the current buffer's luasnip to the one nearest the cursor
---@return boolean true if a node is found, false otherwise
local function seek_luasnip_cursor_node()
-- TODO(kylo252): upstream this
-- for outdated versions of luasnip
if not luasnip.session.current_nodes then
return false
end

local node = luasnip.session.current_nodes[get_current_buf()]
if not node then
return false
end

local snippet = node.parent.snippet
local exit_node = snippet.insert_nodes[0]

local pos = win_get_cursor(0)
pos[1] = pos[1] - 1

-- exit early if we're past the exit node
if exit_node then
local exit_pos_end = exit_node.mark:pos_end()
if (pos[1] > exit_pos_end[1]) or (pos[1] == exit_pos_end[1] and pos[2] > exit_pos_end[2]) then
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil

return false
end
end

node = snippet.inner_first:jump_into(1, true)
while node ~= nil and node.next ~= nil and node ~= snippet do
local n_next = node.next
local next_pos = n_next and n_next.mark:pos_begin()
local candidate = n_next ~= snippet and next_pos and (pos[1] < next_pos[1])
or (pos[1] == next_pos[1] and pos[2] < next_pos[2])

-- Past unmarked exit node, exit early
if n_next == nil or n_next == snippet.next then
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil

return false
end

if candidate then
luasnip.session.current_nodes[get_current_buf()] = node
return true
end

local ok
ok, node = pcall(node.jump_from, node, 1, true) -- no_move until last stop
if not ok then
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil

return false
end
end

-- No candidate, but have an exit node
if exit_node then
-- to jump to the exit node, seek to snippet
luasnip.session.current_nodes[get_current_buf()] = snippet
return true
end

-- No exit node, exit from snippet
snippet:remove_from_jumplist()
luasnip.session.current_nodes[get_current_buf()] = nil
return false
end

if dir == -1 then
return luasnip.in_snippet() and luasnip.jumpable(-1)
else
return luasnip.in_snippet() and seek_luasnip_cursor_node() and luasnip.jumpable(1)
end
end

M.methods = {}

M.methods.jumpable = jumpable

return M
22 changes: 7 additions & 15 deletions lua/lvim/plugins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ local core_plugins = {
},
},
{ "hrsh7th/cmp-nvim-lsp", lazy = true },
{ "saadparwaiz1/cmp_luasnip", lazy = true },
{ "hrsh7th/cmp-buffer", lazy = true },
{ "hrsh7th/cmp-path", lazy = true },
{
"saadparwaiz1/cmp_luasnip",
lazy = true,
enabled = lvim.builtin.luasnip.active,
},
{
"hrsh7th/cmp-cmdline",
lazy = true,
Expand All @@ -76,25 +80,13 @@ local core_plugins = {
{
"L3MON4D3/LuaSnip",
config = function()
local utils = require "lvim.utils"
local paths = {}
if lvim.builtin.luasnip.sources.friendly_snippets then
paths[#paths + 1] = utils.join_paths(get_runtime_dir(), "site", "pack", "lazy", "opt", "friendly-snippets")
end
local user_snippets = utils.join_paths(get_config_dir(), "snippets")
if utils.is_directory(user_snippets) then
paths[#paths + 1] = user_snippets
end
require("luasnip.loaders.from_lua").lazy_load()
require("luasnip.loaders.from_vscode").lazy_load {
paths = paths,
}
require("luasnip.loaders.from_snipmate").lazy_load()
require("lvim.core.luasnip").setup()
end,
event = "InsertEnter",
dependencies = {
"friendly-snippets",
},
enabled = lvim.builtin.luasnip.active,
},
{ "rafamadriz/friendly-snippets", lazy = true, cond = lvim.builtin.luasnip.sources.friendly_snippets },
{
Expand Down