local ls = require('luasnip') local types = require('luasnip.util.types') -- configure luasnip ls.config.set_config({ enable_autosnippets = true, history = true, updateevents = 'TextChanged,TextChangedI', override_builtin = true, ext_opts = { [types.choiceNode] = { active = { virt_text = { { '◂ 󰬊 ', 'NonText' } }, }, }, [types.insertNode] = { active = { virt_text = { { '◂ 󰬐 ', 'NonText' } }, }, }, }, snip_env = vim.tbl_deep_extend('error', ls.session.config.snip_env, { -- snippet helpers nl = function() return ls.t({ '', '' }) end, exec = function(command) return ls.f(function(_, _, ...) local job = require('plenary.job'):new({ command = vim.env.SHELL, args = { '-c', ... }, enable_recording = true, }) local res, exitcode = job:sync() if not exitcode == 0 or #res == 0 then error(string.format('exec "%s" failed', ...)) end return res end, {}, { user_args = { command } }) end, -- condition helpers cond = { ts = function(capture) return function() return vim.tbl_contains(vim.treesitter.get_captures_at_cursor(), capture) end end, }, }), }) -- snippet loaders require('luasnip.loaders.from_lua').lazy_load() require('luasnip.loaders.from_vscode').lazy_load({ include = {} }) -- keymaps vim.keymap.set({ 'i', 's' }, '', function() return vim.snippet.active({ direction = 1 }) and vim.snippet.jump(1) end, { silent = true, desc = 'snippet: jump next' }) vim.keymap.set({ 'i', 's' }, '', function() return vim.snippet.active({ direction = -1 }) and vim.snippet.jump(-1) end, { silent = true, desc = 'snippet: jump prev' }) vim.keymap.set({ 'i', 's' }, '', function() if ls.choice_active() then ls.change_choice(1) end end, { silent = true, desc = 'snippet: next choice' }) vim.keymap.set({ 'i', 's' }, '', function() if ls.choice_active() then ls.change_choice(-1) end end, { silent = true, desc = 'snippet: prev choice' }) -- usercmds vim.api.nvim_create_user_command('EditSnippets', require('luasnip.loaders').edit_snippet_files, {}) -- autocmds -- vim.api.nvim_create_autocmd('User', { -- pattern = 'LuasnipChoiceNodeEnter', -- callback = function() -- vim.schedule(function() -- assert(ls.session.active_choice_nodes[vim.api.nvim_get_current_buf()], 'No active choiceNode') -- vim.ui.select( -- ls.get_current_choices(), -- -- TODO: patch luasnip.extras.select_choice to fix missing prompt -- { prompt = 'LuaSnip: choice node', kind = 'luasnip' }, -- function(_, idx) -- if not idx then -- return -- end -- -- feed+immediately execute i to enter INSERT after vim.ui.input closes. -- vim.api.nvim_feedkeys('i', 'x', false) -- ls.set_choice(idx) -- ls.unlink_current() -- end -- ) -- end) -- end, -- }) -- unlink luasnip session on vim.api.nvim_create_autocmd('ModeChanged', { pattern = '*', callback = function() if ((vim.v.event.old_mode == 's' and vim.v.event.new_mode == 'n') or vim.v.event.old_mode == 'i') and ls.session.current_nodes[vim.api.nvim_get_current_buf()] and not ls.session.jump_active and not require("blink.cmp").is_visible() then ls.unlink_current() end end }) -- attach to builtin snippet hooks vim.snippet.expand = ls.lsp_expand vim.snippet.active = function(filter) filter = filter or {} filter.direction = filter.direction or 1 if filter.direction == 1 then return ls.expand_or_jumpable() else return ls.jumpable(filter.direction) end end vim.snippet.jump = function(direction) if direction == 1 then if ls.expandable() then return ls.expand_or_jump() else return ls.jumpable(1) and ls.jump(1) end else return ls.jumpable(-1) and ls.jump(-1) end end vim.snippet.stop = ls.unlink_current