diff options
Diffstat (limited to 'lua/core')
-rw-r--r-- | lua/core/autopairs.lua | 12 | ||||
-rw-r--r-- | lua/core/cmp.lua | 128 |
2 files changed, 116 insertions, 24 deletions
diff --git a/lua/core/autopairs.lua b/lua/core/autopairs.lua index a67f3b07..eb080fb1 100644 --- a/lua/core/autopairs.lua +++ b/lua/core/autopairs.lua @@ -4,14 +4,8 @@ function M.config() lvim.builtin.autopairs = { active = true, on_config_done = nil, - ---@usage map <CR> on insert mode - map_cr = true, ---@usage auto insert after select function or method item map_complete = true, - ---@usage automatically select the first item - auto_select = true, - ---@usage use insert confirm behavior instead of replace - insert = false, ---@usage -- modifies the function or method delimiter by filetypes map_char = { all = "(", @@ -60,12 +54,12 @@ M.setup = function() if package.loaded["cmp"] then require("nvim-autopairs.completion.cmp").setup { - map_cr = lvim.builtin.autopairs.map_cr, + map_cr = false, map_complete = lvim.builtin.autopairs.map_complete, - auto_select = lvim.builtin.autopairs.auto_select, - insert = lvim.builtin.autopairs.insert, map_char = lvim.builtin.autopairs.map_char, } + -- we map CR explicitly in cmp.lua but we still need to setup the autopairs CR keymap + vim.api.nvim_set_keymap("i", "<CR>", "v:lua.MPairs.autopairs_cr()", { expr = true, noremap = true }) end require("nvim-treesitter.configs").setup { autopairs = { enable = true } } diff --git a/lua/core/cmp.lua b/lua/core/cmp.lua index b058bd6a..d5d92314 100644 --- a/lua/core/cmp.lua +++ b/lua/core/cmp.lua @@ -29,14 +29,106 @@ M.config = function() if not status_luasnip_ok then return end + local win_get_cursor = vim.api.nvim_win_get_cursor + local get_current_buf = vim.api.nvim_get_current_buf + + local function inside_snippet() + -- 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 snip_begin_pos, snip_end_pos = node.parent.snippet.mark:pos_begin_end() + local pos = win_get_cursor(0) + pos[1] = pos[1] - 1 -- LuaSnip is 0-based not 1-based like nvim for rows + return pos[1] >= snip_begin_pos[1] and pos[1] <= snip_end_pos[1] + end + + ---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() + -- for outdated versions of luasnip + if not luasnip.session.current_nodes then + return false + end + + local pos = win_get_cursor(0) + pos[1] = pos[1] - 1 + 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] + + -- 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 + lvim.builtin.cmp = { confirm_opts = { behavior = cmp.ConfirmBehavior.Replace, - select = true, + select = false, }, experimental = { - ghost_text = false, - native_menu = true, + ghost_text = true, + native_menu = false, }, formatting = { kind_icons = { @@ -111,10 +203,12 @@ M.config = function() ["<C-f>"] = cmp.mapping.scroll_docs(4), -- TODO: potentially fix emmet nonsense ["<Tab>"] = cmp.mapping(function() - if vim.fn.pumvisible() == 1 then - vim.fn.feedkeys(T "<down>", "n") - elseif luasnip.expand_or_jumpable() then - vim.fn.feedkeys(T "<Plug>luasnip-expand-or-jump", "") + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expandable() then + luasnip.expand() + elseif inside_snippet() and seek_luasnip_cursor_node() and luasnip.jumpable() then + luasnip.jump(1) elseif check_backspace() then vim.fn.feedkeys(T "<Tab>", "n") elseif is_emmet_active() then @@ -127,10 +221,10 @@ M.config = function() "s", }), ["<S-Tab>"] = cmp.mapping(function(fallback) - if vim.fn.pumvisible() == 1 then - vim.fn.feedkeys(T "<up>", "n") - elseif luasnip.jumpable(-1) then - vim.fn.feedkeys(T "<Plug>luasnip-jump-prev", "") + if cmp.visible() then + cmp.select_prev_item() + elseif inside_snippet() and luasnip.jumpable(-1) then + luasnip.jump(-1) else fallback() end @@ -142,12 +236,16 @@ M.config = function() ["<C-Space>"] = cmp.mapping.complete(), ["<C-e>"] = cmp.mapping.close(), ["<CR>"] = cmp.mapping(function(fallback) - if not require("cmp").confirm(lvim.builtin.cmp.confirm_opts) then - if luasnip.jumpable() then - vim.fn.feedkeys(T "<Plug>luasnip-jump-next", "") - else + if cmp.visible() and cmp.confirm(lvim.builtin.cmp.confirm_opts) then + return + end + + if inside_snippet() and seek_luasnip_cursor_node() and luasnip.jumpable() then + if not luasnip.jump(1) then fallback() end + else + fallback() end end), }, |