Luasnip?
Closed this issue ยท 8 comments
Hey, So I see all the examples both in Luasnip and Tabout, but I'm not really familiar with Lua/neovim functions/configurations yet.
I'm trying to get <Tab>
to be have properly in the following order:
- snippet expansion + jumping
- tabout
Here is what I have in Luasnip:
return {
'L3MON4D3/LuaSnip',
enabled = true,
event = 'VeryLazy',
version = '2.*',
build = 'make install_jsregexp',
config = function()
local ls = require('luasnip')
-- https://github.com/L3MON4D3/LuaSnip/blob/master/DOC.md#config-options
ls.setup({
update_events = 'TextChanged,TextChangedI',
})
require('luasnip.loaders.from_snipmate').lazy_load({
paths = '~/.config/nvim/snippets',
})
local function interp(k) vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(k, true, false, true), 'n', false) end
vim.keymap.set({'i', 's'}, '<Tab>', function()
if ls.expand_or_jumpable() then ls.expand_or_jump()
else interp('<Tab>') end
end)
vim.keymap.set({'i', 's'}, '<S-Tab>', function()
if ls.jumpable(-1) then ls.jump(-1)
else interp('<S-Tab>') end
end)
end
}
Now the problem is trying to get Tabout to work with this.
My tabout looks like this:
-- https://github.com/abecodes/tabout.nvim
return {
'abecodes/tabout.nvim',
enabled = true,
event = 'VeryLazy',
dependencies = {
'nvim-treesitter/nvim-treesitter',
'hrsh7th/nvim-cmp',
'L3MON4D3/LuaSnip',
},
config = function()
-- https://github.com/abecodes/tabout.nvim#more-complex-keybindings
require('tabout').setup({
tabkey = '',
backwards_tabkey = '',
act_as_tab = true,
act_as_shift_tab = false,
default_tab = '<C-t>',
default_shift_tab = '<C-d>',
enable_backwards = true,
completion = true,
tabouts = {
{ open = "'", close = "'" },
{ open = '"', close = '"' },
{ open = '`', close = '`' },
{ open = '(', close = ')' },
{ open = '[', close = ']' },
{ open = '{', close = '}' }
},
ignore_beginning = true,
exclude = {},
})
-- local function replace_keycodes(c)
-- return vim.api.nvim_replace_termcodes(c, true, true, true)
-- end
--
-- function _G.tab_binding()
-- if vim.fn.pumvisible() ~= 0 then
-- return replace_keycodes("<C-n>")
-- elseif vim.fn["vsnip#available"](1) ~= 0 then
-- return replace_keycodes("<Plug>(vsnip-expand-or-jump)")
-- else
-- return replace_keycodes("<Plug>(Tabout)")
-- end
-- end
--
-- function _G.s_tab_binding()
-- if vim.fn.pumvisible() ~= 0 then
-- return replace_keycodes("<C-p>")
-- elseif vim.fn["vsnip#jumpable"](-1) ~= 0 then
-- return replace_keycodes("<Plug>(vsnip-jump-prev)")
-- else
-- return replace_keycodes("<Plug>(TaboutBack)")
-- end
-- end
--
-- vim.api.nvim_set_keymap("i", "<Tab>", "v:lua.tab_binding()", {expr = true})
-- vim.api.nvim_set_keymap("i", "<S-Tab>", "v:lua.s_tab_binding()", {expr = true})
end,
}
So far I have set this:
tabkey = '',
backwards_tabkey = '',
But I'm still trying to figure out what to actually put for the tab_binding
.
Are you able to give any ideas?
I also tried this but it doesn't seem to tabout
local ls = require('luasnip')
local function replace_keycodes(c)
return vim.api.nvim_replace_termcodes(c, true, true, true)
end
function _G.tab_binding()
if not ls.expand_or_jumpable() then
return replace_keycodes('<Plug>(Tabout)')
end
end
function _G.s_tab_binding()
if not ls.jumpable(-1) then
return replace_keycodes('<Plug>(TaboutBack)')
end
end
vim.api.nvim_set_keymap('i', '<Tab>', 'v:lua.tab_binding()', { expr = true })
vim.api.nvim_set_keymap('i', '<S-Tab>', 'v:lua.s_tab_binding()', { expr = true })
but it outputs this for the snippet: v:null
UGH the problem was this... I was calling <Plug>(luasnip-expand-or-jump)
instead of <Plug>luasnip-expand-or-jump
I didn't realize the parens were a part of the name. Here's my full config if anyone else has same problem:
-- https://github.com/abecodes/tabout.nvim
return {
'abecodes/tabout.nvim',
event = 'InsertEnter',
dependencies = {
'nvim-treesitter/nvim-treesitter',
'hrsh7th/nvim-cmp',
'L3MON4D3/LuaSnip',
},
config = function()
-- https://github.com/abecodes/tabout.nvim#more-complex-keybindings
require('tabout').setup({
tabkey = '', --'<Tab>',
backwards_tabkey = '', --'<S-Tab>',
act_as_tab = true,
act_as_shift_tab = false,
default_tab = '<C-t>',
default_shift_tab = '<C-d>',
enable_backwards = true,
completion = true,
tabouts = {
{ open = "'", close = "'" },
{ open = '"', close = '"' },
{ open = '`', close = '`' },
{ open = '(', close = ')' },
{ open = '[', close = ']' },
{ open = '{', close = '}' },
},
ignore_beginning = true,
exclude = {},
})
-- handle <Tab> key to prioritize LuaSnip over Tabout
local ls = require('luasnip')
local function replace_keycodes(c)
return vim.api.nvim_replace_termcodes(c, true, true, true)
end
function _G.tab_binding()
if ls.expand_or_jumpable() then
return replace_keycodes('<Plug>luasnip-expand-or-jump')
else
return replace_keycodes('<Plug>(Tabout)')
end
end
function _G.s_tab_binding()
if ls.jumpable(-1) then
return replace_keycodes('<Plug>luasnip-jump-prev')
else
return replace_keycodes('<Plug>(TaboutBack)')
end
end
vim.api.nvim_set_keymap('i', '<Tab>', 'v:lua.tab_binding()', { expr = true })
vim.api.nvim_set_keymap('i', '<S-Tab>', 'v:lua.s_tab_binding()', { expr = true })
end,
}
Youlre welcome :D I spent way too long finding those parens
@9mm thanks~
Tks for the ideas here!
I decided to go the other way, telling luasnip to call tabout. Looking at how Lazyvim does the config to the keys for luasnip, and taking into account that lazy.nvim merges the keys table, I got this:
{
"L3MON4D3/LuaSnip",
dependencies = { "abecodes/tabout.nvim" },
keys = {
{
"<tab>",
function()
return "<Plug>(Tabout)" or (require("luasnip").jumpable(1) and "<Plug>luasnip-jump-next") or "<tab>"
end,
expr = true,
silent = true,
mode = "i",
},
},
},
{
"abecodes/tabout.nvim",
dependencies = {
"nvim-treesitter/nvim-treesitter",
"hrsh7th/nvim-cmp",
},
event = "InsertEnter",
config = true,
},
I would like to share my config which:
- Expands LuaSnip snippets using nvim-cmp (if available)
- Inserts current indentation if cursor is at the very beginning of the line (
0
motion) - Inserts indentation if the cursor is preceed by only whitespaces or tabs (
^
motion) - Tabs out of the code context
The items 2 and 3 are cases where I do not want to tab-out
but want to insert indentation.
cmp.setup({
mapping = cmp.mapping.preset.insert({
["<Tab>"] = function(fallback)
local feedkeys = vim.fn.feedkeys
local termcodes = vim.api.nvim_replace_termcodes
local get_cursor = vim.api.nvim_win_get_cursor
local get_line = vim.api.nvim_get_current_line
-- trigger the snippet engine
if luasnip.expand_or_jumpable() then
feedkeys(
termcodes("<Plug>luasnip-expand-or-jump", true, true, true),
""
)
return
end
-- We will make Vim insert correct indentation for current line
-- by pressing <TAB> if we are in the beginning of the line.
local cursor_line, cursor_col = unpack(get_cursor(0))
if cursor_col == 0 then
-- We achieve so by:
--
-- 1. Simulate backspace (delete character under cursor)
-- 2. Simulate Enter
--
-- This will:
--
-- 1. delete the current line,
-- 2. go to the previous line,
-- 3. start a new line.
--
-- Vim automatically indents new lines.
-- That is how we achieve <TAB> inserting current indentation
-- if the cursor is at the beginning of the line
feedkeys(termcodes('<BS>', true, false, true), "")
feedkeys(termcodes('<CR>', true, false, true), "")
return
end
-- cursor is preeced by whitespaces-only, so insert indentation
local line_content = get_line()
local before_cursor = line_content:sub(1, cursor_col)
if before_cursor:match("^[\t%s]+$") then
fallback()
return
end
-- finally, tabs-out of code context
require("tabout").tabout()
end,
})
})
This works best with ignore_beginning=true
and completion=false