Add luasnip and use it to load language and project specific snippets,
also add a bunch of mess to get a nice unwrap(), this is committed on purpose as a reference for future me, will be cleaned up in the next commit. It also touches a bunch of blink.cmp to achieve this.
This commit is contained in:
@@ -5,10 +5,26 @@ return {
|
||||
version = '1.*',
|
||||
dependencies = {
|
||||
{ 'Kaiser-Yang/blink-cmp-git', dependencies = { 'nvim-lua/plenary.nvim' } },
|
||||
{ 'L3MON4D3/LuaSnip', version = 'v2.*' },
|
||||
},
|
||||
---@module 'blink.cmp'
|
||||
---@type blink.cmp.Config
|
||||
opts = {
|
||||
snippets = { preset = 'luasnip' },
|
||||
-- snippets = {
|
||||
-- expand = function(snippet)
|
||||
-- require('luasnip').lsp_expand(snippet)
|
||||
-- end,
|
||||
-- active = function(filter)
|
||||
-- if filter and filter.direction then
|
||||
-- return require('luasnip').jumpable(filter.direction)
|
||||
-- end
|
||||
-- return require('luasnip').in_snippet()
|
||||
-- end,
|
||||
-- jump = function(direction)
|
||||
-- require('luasnip').jump(direction)
|
||||
-- end,
|
||||
-- },
|
||||
keymap = {
|
||||
preset = 'enter',
|
||||
['<C-e>'] = {},
|
||||
@@ -18,6 +34,36 @@ return {
|
||||
['<C-f>'] = {},
|
||||
['<C-u>'] = { 'scroll_documentation_up', 'fallback' },
|
||||
['<C-d>'] = { 'scroll_documentation_down', 'fallback' },
|
||||
['<cr>'] = {
|
||||
function(cmp)
|
||||
local item = cmp.get_selected_item()
|
||||
|
||||
if item and item.label == '.unwrap' then
|
||||
vim.schedule(function()
|
||||
local ctx = cmp.get_context()
|
||||
if not ctx or not ctx.bounds then
|
||||
return cmp.accept()
|
||||
end
|
||||
local partial = ctx.get_keyword() or ''
|
||||
local full = cmp.get_selected_item().label
|
||||
local rest = full:sub(#partial + 1 + 1)
|
||||
|
||||
local row = ctx.bounds.line_number - 1
|
||||
local col = ctx.bounds.start_col + ctx.bounds.length
|
||||
|
||||
local line = vim.api.nvim_buf_get_lines(ctx.bufnr, row, row + 1, false)[1]
|
||||
local cursor_at_eol = col > #line
|
||||
|
||||
vim.api.nvim_put({ rest }, 'c', cursor_at_eol, true)
|
||||
require('luasnip').expand()
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
||||
return cmp.accept()
|
||||
end,
|
||||
'fallback',
|
||||
},
|
||||
},
|
||||
|
||||
completion = {
|
||||
@@ -31,7 +77,16 @@ return {
|
||||
keyword = { range = 'full' },
|
||||
|
||||
-- Preselect first one, don't complete until confirmation
|
||||
list = { selection = { preselect = true, auto_insert = false } },
|
||||
list = {
|
||||
selection = {
|
||||
preselect = true,
|
||||
-- auto_insert = false,
|
||||
auto_insert = function(ctx)
|
||||
-- vim.notify()
|
||||
return ctx.get_keyword() == 'unwrap'
|
||||
end,
|
||||
},
|
||||
},
|
||||
|
||||
menu = {
|
||||
draw = {
|
||||
@@ -82,31 +137,7 @@ return {
|
||||
},
|
||||
|
||||
snippets = {
|
||||
-- score_offset = 200, -- make snippets highest priority
|
||||
transform_items = function(_, items)
|
||||
return vim.tbl_filter(function(item)
|
||||
-- vim.print(item)
|
||||
if item.kind ~= require('blink.cmp.types').CompletionItemKind.Snippet then
|
||||
return true
|
||||
end
|
||||
|
||||
local name = item.description
|
||||
-- vim.print(name)
|
||||
local parts = vim.split(name, ' ', { trimempty = false })
|
||||
local namespace = #parts > 1 and parts[1] or nil
|
||||
-- vim.print(namespace)
|
||||
if not namespace then
|
||||
return true
|
||||
end
|
||||
|
||||
-- vim.print(vim.fn.getcwd())
|
||||
local path = vim.split(vim.fn.getcwd(), '/')
|
||||
local dir = path[#path]
|
||||
-- vim.print(dir)
|
||||
|
||||
return dir == namespace
|
||||
end, items)
|
||||
end,
|
||||
score_offset = 200, -- make snippets highest priority
|
||||
},
|
||||
|
||||
lsp = {
|
||||
@@ -181,7 +212,6 @@ return {
|
||||
opts_extend = { 'sources.default' },
|
||||
|
||||
-- TODO: pressing backk (deleting), should re-show completion menu
|
||||
-- TODO: ghost text only for LLMs?
|
||||
}
|
||||
|
||||
-- From LazyVim
|
||||
|
||||
147
.config/nvim/lua/plugins/luasnip.lua
Normal file
147
.config/nvim/lua/plugins/luasnip.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
return {
|
||||
'L3MON4D3/LuaSnip',
|
||||
version = 'v2.*', -- follow latest release.
|
||||
build = 'make install_jsregexp',
|
||||
opts = {},
|
||||
config = function(_, opts)
|
||||
require('luasnip').setup(opts)
|
||||
|
||||
-- Load language specific snippets
|
||||
require('luasnip.loaders.from_vscode').load({ paths = './snippets' })
|
||||
|
||||
-- load project specific snippets
|
||||
local project = vim.fn.fnamemodify(vim.fn.getcwd(), ':t')
|
||||
local project_snippets = {
|
||||
eko = 'eko.json',
|
||||
['carbonight.nvim'] = 'carbonight.json',
|
||||
}
|
||||
local file = project_snippets[project]
|
||||
if file then
|
||||
require('luasnip.loaders.from_vscode').load_standalone({ path = './snippets/' .. file })
|
||||
end
|
||||
|
||||
-- some shorthands...
|
||||
local ls = require('luasnip')
|
||||
local s = ls.snippet
|
||||
local sn = ls.snippet_node
|
||||
local isn = ls.indent_snippet_node
|
||||
local t = ls.text_node
|
||||
local i = ls.insert_node
|
||||
local f = ls.function_node
|
||||
local c = ls.choice_node
|
||||
local d = ls.dynamic_node
|
||||
local r = ls.restore_node
|
||||
local events = require('luasnip.util.events')
|
||||
local ai = require('luasnip.nodes.absolute_indexer')
|
||||
local opt = require('luasnip.nodes.optional_arg')
|
||||
local extras = require('luasnip.extras')
|
||||
local l = extras.lambda
|
||||
local rep = extras.rep
|
||||
local p = extras.partial
|
||||
local m = extras.match
|
||||
local n = extras.nonempty
|
||||
local dl = extras.dynamic_lambda
|
||||
local fmt = require('luasnip.extras.fmt').fmt
|
||||
local fmta = require('luasnip.extras.fmt').fmta
|
||||
local conds = require('luasnip.extras.expand_conditions')
|
||||
local postfix = require('luasnip.extras.postfix').postfix
|
||||
local ts_postfix = require('luasnip.extras.treesitter_postfix').treesitter_postfix
|
||||
local types = require('luasnip.util.types')
|
||||
local parse = require('luasnip.util.parser').parse_snippet
|
||||
local ms = ls.multi_snippet
|
||||
local k = require('luasnip.nodes.key_indexer').new_key
|
||||
local postfix_builtin = require('luasnip.extras.treesitter_postfix').builtin
|
||||
|
||||
ls.add_snippets('all', {
|
||||
ts_postfix({
|
||||
matchTSNode = postfix_builtin.tsnode_matcher.find_topmost_types({
|
||||
'identifier',
|
||||
'method_invocation',
|
||||
'field_access',
|
||||
'type_identifier',
|
||||
'class_literal',
|
||||
'this',
|
||||
'scoped_type_identifier',
|
||||
}),
|
||||
trig = '.unwrap',
|
||||
}, {
|
||||
f(function(_, parent)
|
||||
-- Use POSTFIX_MATCH instead of LS_TSMATCH
|
||||
local match = parent.snippet.env.LS_TSMATCH
|
||||
-- vim.notify('postfix: "' .. vim.inspect(match) .. '"')
|
||||
|
||||
if not match then
|
||||
return { 'unwrap()' }
|
||||
end
|
||||
|
||||
-- If LuaSnip provides the match as a table, concat it
|
||||
if type(match) == 'table' then
|
||||
match = table.concat(match, '\n')
|
||||
end
|
||||
|
||||
local wrapped = string.format('unwrap(%s)', match)
|
||||
-- Split it back into a table of strings to safely handle any newlines
|
||||
return vim.split(wrapped, '\n', { plain = true })
|
||||
end),
|
||||
}),
|
||||
|
||||
-- ts_postfix({
|
||||
-- trig = 'unwrap',
|
||||
-- matchTSNode = {
|
||||
-- query = [[
|
||||
-- (field_access
|
||||
-- object: (
|
||||
-- field_access
|
||||
-- method_invocation
|
||||
-- identifier
|
||||
-- ) @my_object
|
||||
-- ) @my_field
|
||||
-- ]],
|
||||
-- query_lang = 'java',
|
||||
-- select = 'longest',
|
||||
-- },
|
||||
-- }, {
|
||||
-- f(function(_, parent)
|
||||
-- -- Use POSTFIX_MATCH instead of LS_TSMATCH
|
||||
-- local match = parent.snippet.env.POSTFIX_MATCH
|
||||
-- vim.notify('postfix: "' .. vim.inspect(match) .. '"')
|
||||
--
|
||||
-- if not match then
|
||||
-- return { 'unwrap()' }
|
||||
-- end
|
||||
--
|
||||
-- -- If LuaSnip provides the match as a table, concat it
|
||||
-- if type(match) == 'table' then
|
||||
-- match = table.concat(match, '\n')
|
||||
-- end
|
||||
--
|
||||
-- -- Format the string
|
||||
-- local wrapped = string.format('unwrap(%s)', match)
|
||||
--
|
||||
-- -- Split it back into a table of strings to safely handle any newlines
|
||||
-- return vim.split(wrapped, '\n', { plain = true })
|
||||
-- end),
|
||||
-- }, { condition = require('luasnip.util.util').yes }),
|
||||
})
|
||||
-- postfix({ trig = 'unwrap', match_pattern = [[[%w%.%_%-%"%']+$]] }, {
|
||||
-- f(function(_, parent)
|
||||
-- local match = parent.snippet.env.POSTFIX_MATCH
|
||||
-- if match == nil then
|
||||
-- return 'bunger'
|
||||
-- end
|
||||
-- -- match = match:sub(1, -2)
|
||||
-- return 'unwrap(' .. match .. ')'
|
||||
-- end, {}),
|
||||
-- }, { condition = require('luasnip.util.util').yes }),
|
||||
|
||||
-- postfix({ trig = '.unwrap', snippetType = 'snippet' }, {
|
||||
-- f(function(_, parent)
|
||||
-- local match = parent.snippet.env.POSTFIX_MATCH
|
||||
-- if match == nil then
|
||||
-- return 'bunger'
|
||||
-- end
|
||||
-- return '[' .. match .. ']'
|
||||
-- end, {}),
|
||||
-- }),
|
||||
end,
|
||||
}
|
||||
Reference in New Issue
Block a user