123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- 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 = {
- 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
|