
## Description The whole completion / snippets / AI is very tricky: - multiple snippet engines - native snippets on > 0.11 set their own keymaps, but not on 0.10 - multiple completion engines, like `nvim-cmp` and `blink.cmp` - multiple ai completion engines that have a different API - user's preference of showing ai suggestions as completion or not - none of the ai completion engines currently set undo points, which is bad Solution: - [x] added `LazyVim.cmp.actions`, where snippet engines and ai engines can register their action. - [x] an action returns `true` if it succeeded, or `false|nil` otherwise - [x] in a completion engine, we then try running multiple actions and use the fallback if needed - [x] so `<tab>` runs `{"snippet_forward", "ai_accept", "fallback"}` - [x] added `vim.g.ai_cmp`. When `true` we try to integrate the AI source in the completion engine. - [x] when `false`, `<tab>` should be used to insert the AI suggestion - [x] when `false`, the completion engine's ghost text is disabled - [x] luasnip support for blink (only works with blink `main`) - [x] create undo points when accepting AI suggestions ## Test Matrix | completion | snippets | ai | ai_cmp | tested? | |--------------|--------------|-------------|--------|---------| | nvim-cmp | native | copilot | true | ✅ | | nvim-cmp | native | copilot | false | ✅ | | nvim-cmp | native | codeium | true | ✅ | | nvim-cmp | native | codeium | false | ✅ | | nvim-cmp | luasnip | copilot | true | ✅ | | nvim-cmp | luasnip | copilot | false | ✅ | | nvim-cmp | luasnip | codeium | true | ✅ | | nvim-cmp | luasnip | codeium | false | ✅ | | blink.cmp | native | copilot | true | ✅ | | blink.cmp | native | copilot | false | ✅ | | blink.cmp | native | codeium | true | ✅ | | blink.cmp | native | codeium | false | ✅ | | blink.cmp | luasnip | copilot | true | ✅ | | blink.cmp | luasnip | copilot | false | ✅ | | blink.cmp | luasnip | codeium | true | ✅ | | blink.cmp | luasnip | codeium | false | ✅ | ## Related Issue(s) - [ ] Closes #4702 ## Screenshots <!-- Add screenshots of the changes if applicable. --> ## Checklist - [ ] I've read the [CONTRIBUTING](https://github.com/LazyVim/LazyVim/blob/main/CONTRIBUTING.md) guidelines.
193 lines
9.0 KiB
Lua
193 lines
9.0 KiB
Lua
-- This file is automatically loaded by lazyvim.config.init
|
|
|
|
-- DO NOT USE `LazyVim.safe_keymap_set` IN YOUR OWN CONFIG!!
|
|
-- use `vim.keymap.set` instead
|
|
local map = LazyVim.safe_keymap_set
|
|
|
|
-- better up/down
|
|
map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true })
|
|
map({ "n", "x" }, "<Down>", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true })
|
|
map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true, silent = true })
|
|
map({ "n", "x" }, "<Up>", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true, silent = true })
|
|
|
|
-- Move to window using the <ctrl> hjkl keys
|
|
map("n", "<C-h>", "<C-w>h", { desc = "Go to Left Window", remap = true })
|
|
map("n", "<C-j>", "<C-w>j", { desc = "Go to Lower Window", remap = true })
|
|
map("n", "<C-k>", "<C-w>k", { desc = "Go to Upper Window", remap = true })
|
|
map("n", "<C-l>", "<C-w>l", { desc = "Go to Right Window", remap = true })
|
|
|
|
-- Resize window using <ctrl> arrow keys
|
|
map("n", "<C-Up>", "<cmd>resize +2<cr>", { desc = "Increase Window Height" })
|
|
map("n", "<C-Down>", "<cmd>resize -2<cr>", { desc = "Decrease Window Height" })
|
|
map("n", "<C-Left>", "<cmd>vertical resize -2<cr>", { desc = "Decrease Window Width" })
|
|
map("n", "<C-Right>", "<cmd>vertical resize +2<cr>", { desc = "Increase Window Width" })
|
|
|
|
-- Move Lines
|
|
map("n", "<A-j>", "<cmd>execute 'move .+' . v:count1<cr>==", { desc = "Move Down" })
|
|
map("n", "<A-k>", "<cmd>execute 'move .-' . (v:count1 + 1)<cr>==", { desc = "Move Up" })
|
|
map("i", "<A-j>", "<esc><cmd>m .+1<cr>==gi", { desc = "Move Down" })
|
|
map("i", "<A-k>", "<esc><cmd>m .-2<cr>==gi", { desc = "Move Up" })
|
|
map("v", "<A-j>", ":<C-u>execute \"'<,'>move '>+\" . v:count1<cr>gv=gv", { desc = "Move Down" })
|
|
map("v", "<A-k>", ":<C-u>execute \"'<,'>move '<-\" . (v:count1 + 1)<cr>gv=gv", { desc = "Move Up" })
|
|
|
|
-- buffers
|
|
map("n", "<S-h>", "<cmd>bprevious<cr>", { desc = "Prev Buffer" })
|
|
map("n", "<S-l>", "<cmd>bnext<cr>", { desc = "Next Buffer" })
|
|
map("n", "[b", "<cmd>bprevious<cr>", { desc = "Prev Buffer" })
|
|
map("n", "]b", "<cmd>bnext<cr>", { desc = "Next Buffer" })
|
|
map("n", "<leader>bb", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
|
|
map("n", "<leader>`", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
|
|
map("n", "<leader>bd", function()
|
|
Snacks.bufdelete()
|
|
end, { desc = "Delete Buffer" })
|
|
map("n", "<leader>bo", function()
|
|
Snacks.bufdelete.other()
|
|
end, { desc = "Delete Other Buffers" })
|
|
map("n", "<leader>bD", "<cmd>:bd<cr>", { desc = "Delete Buffer and Window" })
|
|
|
|
-- Clear search with <esc>
|
|
map({ "i", "n" }, "<esc>", "<cmd>noh<cr><esc>", { desc = "Escape and Clear hlsearch" })
|
|
|
|
-- Clear search, diff update and redraw
|
|
-- taken from runtime/lua/_editor.lua
|
|
map(
|
|
"n",
|
|
"<leader>ur",
|
|
"<Cmd>nohlsearch<Bar>diffupdate<Bar>normal! <C-L><CR>",
|
|
{ desc = "Redraw / Clear hlsearch / Diff Update" }
|
|
)
|
|
|
|
-- https://github.com/mhinz/vim-galore#saner-behavior-of-n-and-n
|
|
map("n", "n", "'Nn'[v:searchforward].'zv'", { expr = true, desc = "Next Search Result" })
|
|
map("x", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next Search Result" })
|
|
map("o", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next Search Result" })
|
|
map("n", "N", "'nN'[v:searchforward].'zv'", { expr = true, desc = "Prev Search Result" })
|
|
map("x", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev Search Result" })
|
|
map("o", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev Search Result" })
|
|
|
|
-- Add undo break-points
|
|
map("i", ",", ",<c-g>u")
|
|
map("i", ".", ".<c-g>u")
|
|
map("i", ";", ";<c-g>u")
|
|
|
|
-- save file
|
|
map({ "i", "x", "n", "s" }, "<C-s>", "<cmd>w<cr><esc>", { desc = "Save File" })
|
|
|
|
--keywordprg
|
|
map("n", "<leader>K", "<cmd>norm! K<cr>", { desc = "Keywordprg" })
|
|
|
|
-- better indenting
|
|
map("v", "<", "<gv")
|
|
map("v", ">", ">gv")
|
|
|
|
-- commenting
|
|
map("n", "gco", "o<esc>Vcx<esc><cmd>normal gcc<cr>fxa<bs>", { desc = "Add Comment Below" })
|
|
map("n", "gcO", "O<esc>Vcx<esc><cmd>normal gcc<cr>fxa<bs>", { desc = "Add Comment Above" })
|
|
|
|
-- lazy
|
|
map("n", "<leader>l", "<cmd>Lazy<cr>", { desc = "Lazy" })
|
|
|
|
-- new file
|
|
map("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
|
|
|
|
map("n", "<leader>xl", "<cmd>lopen<cr>", { desc = "Location List" })
|
|
map("n", "<leader>xq", "<cmd>copen<cr>", { desc = "Quickfix List" })
|
|
|
|
map("n", "[q", vim.cmd.cprev, { desc = "Previous Quickfix" })
|
|
map("n", "]q", vim.cmd.cnext, { desc = "Next Quickfix" })
|
|
|
|
-- formatting
|
|
map({ "n", "v" }, "<leader>cf", function()
|
|
LazyVim.format({ force = true })
|
|
end, { desc = "Format" })
|
|
|
|
-- diagnostic
|
|
local diagnostic_goto = function(next, severity)
|
|
local go = next and vim.diagnostic.goto_next or vim.diagnostic.goto_prev
|
|
severity = severity and vim.diagnostic.severity[severity] or nil
|
|
return function()
|
|
go({ severity = severity })
|
|
end
|
|
end
|
|
map("n", "<leader>cd", vim.diagnostic.open_float, { desc = "Line Diagnostics" })
|
|
map("n", "]d", diagnostic_goto(true), { desc = "Next Diagnostic" })
|
|
map("n", "[d", diagnostic_goto(false), { desc = "Prev Diagnostic" })
|
|
map("n", "]e", diagnostic_goto(true, "ERROR"), { desc = "Next Error" })
|
|
map("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "Prev Error" })
|
|
map("n", "]w", diagnostic_goto(true, "WARN"), { desc = "Next Warning" })
|
|
map("n", "[w", diagnostic_goto(false, "WARN"), { desc = "Prev Warning" })
|
|
|
|
-- stylua: ignore start
|
|
|
|
-- toggle options
|
|
LazyVim.format.snacks_toggle():map("<leader>uf")
|
|
LazyVim.format.snacks_toggle(true):map("<leader>uF")
|
|
Snacks.toggle.option("spell", { name = "Spelling"}):map("<leader>us")
|
|
Snacks.toggle.option("wrap", {name = "Wrap"}):map("<leader>uw")
|
|
Snacks.toggle.option("relativenumber", { name = "Relative Number"}):map("<leader>uL")
|
|
Snacks.toggle.diagnostics():map("<leader>ud")
|
|
Snacks.toggle.line_number():map("<leader>ul")
|
|
Snacks.toggle.option("conceallevel", {off = 0, on = vim.o.conceallevel > 0 and vim.o.conceallevel or 2}):map("<leader>uc")
|
|
Snacks.toggle.treesitter():map("<leader>uT")
|
|
Snacks.toggle.option("background", { off = "light", on = "dark" , name = "Dark Background"}):map("<leader>ub")
|
|
if vim.lsp.inlay_hint then
|
|
Snacks.toggle.inlay_hints():map("<leader>uh")
|
|
end
|
|
|
|
-- lazygit
|
|
if vim.fn.executable("lazygit") == 1 then
|
|
map("n", "<leader>gg", function() Snacks.lazygit( { cwd = LazyVim.root.git() }) end, { desc = "Lazygit (Root Dir)" })
|
|
map("n", "<leader>gG", function() Snacks.lazygit() end, { desc = "Lazygit (cwd)" })
|
|
map("n", "<leader>gb", function() Snacks.git.blame_line() end, { desc = "Git Blame Line" })
|
|
map("n", "<leader>gB", function() Snacks.gitbrowse() end, { desc = "Git Browse" })
|
|
map("n", "<leader>gf", function() Snacks.lazygit.log_file() end, { desc = "Lazygit Current File History" })
|
|
map("n", "<leader>gl", function() Snacks.lazygit.log({ cwd = LazyVim.root.git() }) end, { desc = "Lazygit Log" })
|
|
map("n", "<leader>gL", function() Snacks.lazygit.log() end, { desc = "Lazygit Log (cwd)" })
|
|
end
|
|
|
|
-- quit
|
|
map("n", "<leader>qq", "<cmd>qa<cr>", { desc = "Quit All" })
|
|
|
|
-- highlights under cursor
|
|
map("n", "<leader>ui", vim.show_pos, { desc = "Inspect Pos" })
|
|
map("n", "<leader>uI", "<cmd>InspectTree<cr>", { desc = "Inspect Tree" })
|
|
|
|
-- LazyVim Changelog
|
|
map("n", "<leader>L", function() LazyVim.news.changelog() end, { desc = "LazyVim Changelog" })
|
|
|
|
-- floating terminal
|
|
map("n", "<leader>fT", function() Snacks.terminal() end, { desc = "Terminal (cwd)" })
|
|
map("n", "<leader>ft", function() Snacks.terminal(nil, { cwd = LazyVim.root() }) end, { desc = "Terminal (Root Dir)" })
|
|
map("n", "<c-/>", function() Snacks.terminal(nil, { cwd = LazyVim.root() }) end, { desc = "Terminal (Root Dir)" })
|
|
map("n", "<c-_>", function() Snacks.terminal(nil, { cwd = LazyVim.root() }) end, { desc = "which_key_ignore" })
|
|
|
|
-- Terminal Mappings
|
|
map("t", "<C-/>", "<cmd>close<cr>", { desc = "Hide Terminal" })
|
|
map("t", "<c-_>", "<cmd>close<cr>", { desc = "which_key_ignore" })
|
|
|
|
-- windows
|
|
map("n", "<leader>w", "<c-w>", { desc = "Windows", remap = true })
|
|
map("n", "<leader>-", "<C-W>s", { desc = "Split Window Below", remap = true })
|
|
map("n", "<leader>|", "<C-W>v", { desc = "Split Window Right", remap = true })
|
|
map("n", "<leader>wd", "<C-W>c", { desc = "Delete Window", remap = true })
|
|
LazyVim.ui.maximize():map("<leader>wm")
|
|
|
|
-- tabs
|
|
map("n", "<leader><tab>l", "<cmd>tablast<cr>", { desc = "Last Tab" })
|
|
map("n", "<leader><tab>o", "<cmd>tabonly<cr>", { desc = "Close Other Tabs" })
|
|
map("n", "<leader><tab>f", "<cmd>tabfirst<cr>", { desc = "First Tab" })
|
|
map("n", "<leader><tab><tab>", "<cmd>tabnew<cr>", { desc = "New Tab" })
|
|
map("n", "<leader><tab>]", "<cmd>tabnext<cr>", { desc = "Next Tab" })
|
|
map("n", "<leader><tab>d", "<cmd>tabclose<cr>", { desc = "Close Tab" })
|
|
map("n", "<leader><tab>[", "<cmd>tabprevious<cr>", { desc = "Previous Tab" })
|
|
|
|
-- native snippets. only needed on < 0.11, as 0.11 creates these by default
|
|
if vim.fn.has("nvim-0.11") == 0 then
|
|
map("s", "<Tab>", function()
|
|
return vim.snippet.active({ direction = 1 }) and "<cmd>lua vim.snippet.jump(1)<cr>" or "<Tab>"
|
|
end, { expr = true, desc = "Jump Next" })
|
|
map({ "i", "s" }, "<S-Tab>", function()
|
|
return vim.snippet.active({ direction = -1 }) and "<cmd>lua vim.snippet.jump(-1)<cr>" or "<S-Tab>"
|
|
end, { expr = true, desc = "Jump Previous" })
|
|
end
|