summary refs log tree commit diff
path: root/.config/nvim/lua/config/snippets.lua
blob: e0c260e214afa054c91a106d60640ef5daf47df9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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' }, '<c-j>', function()
  return vim.snippet.active({ direction = 1 }) and vim.snippet.jump(1)
end, { silent = true, desc = 'snippet: jump next' })

vim.keymap.set({ 'i', 's' }, '<c-k>', function()
  return vim.snippet.active({ direction = -1 }) and vim.snippet.jump(-1)
end, { silent = true, desc = 'snippet: jump prev' })

vim.keymap.set({ 'i', 's' }, '<c-n>', function()
  if ls.choice_active() then
    ls.change_choice(1)
  end
end, { silent = true, desc = 'snippet: next choice' })

vim.keymap.set({ 'i', 's' }, '<c-p>', 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 <esc>
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