return { -- auto completion { "hrsh7th/nvim-cmp", version = false, -- last release is way too old event = "InsertEnter", dependencies = { "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-buffer", "hrsh7th/cmp-path", }, opts = function() vim.api.nvim_set_hl(0, "CmpGhostText", { link = "Comment", default = true }) local cmp = require("cmp") local defaults = require("cmp.config.default")() return { completion = { completeopt = "menu,menuone,noinsert", }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.complete(), [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. [""] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true, }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. [""] = function(fallback) cmp.abort() fallback() end, }), sources = cmp.config.sources({ { name = "nvim_lsp" }, { name = "path" }, }, { { name = "buffer" }, }), formatting = { format = function(_, item) local icons = require("lazyvim.config").icons.kinds if icons[item.kind] then item.kind = icons[item.kind] .. item.kind end return item end, }, experimental = { ghost_text = { hl_group = "CmpGhostText", }, }, sorting = defaults.sorting, } end, ---@param opts cmp.ConfigSchema config = function(_, opts) for _, source in ipairs(opts.sources) do source.group_index = source.group_index or 1 end require("cmp").setup(opts) end, }, -- snippets { "L3MON4D3/LuaSnip", build = (not LazyVim.is_win()) and "echo 'NOTE: jsregexp is optional, so not a big deal if it fails to build'; make install_jsregexp" or nil, dependencies = { { "rafamadriz/friendly-snippets", config = function() require("luasnip.loaders.from_vscode").lazy_load() end, }, { "nvim-cmp", dependencies = { "saadparwaiz1/cmp_luasnip", }, opts = function(_, opts) opts.snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end, } table.insert(opts.sources, { name = "luasnip" }) end, }, }, opts = { history = true, delete_check_events = "TextChanged", }, -- stylua: ignore keys = { { "", function() return require("luasnip").jumpable(1) and "luasnip-jump-next" or "" end, expr = true, silent = true, mode = "i", }, { "", function() require("luasnip").jump(1) end, mode = "s" }, { "", function() require("luasnip").jump(-1) end, mode = { "i", "s" } }, }, }, -- auto pairs { "echasnovski/mini.pairs", event = "VeryLazy", opts = {}, keys = { { "up", function() vim.g.minipairs_disable = not vim.g.minipairs_disable if vim.g.minipairs_disable then LazyVim.warn("Disabled auto pairs", { title = "Option" }) else LazyVim.info("Enabled auto pairs", { title = "Option" }) end end, desc = "Toggle auto pairs", }, }, }, -- Fast and feature-rich surround actions. For text that includes -- surrounding characters like brackets or quotes, this allows you -- to select the text inside, change or modify the surrounding characters, -- and more. { "echasnovski/mini.surround", keys = function(_, keys) -- Populate the keys based on the user's options local plugin = require("lazy.core.config").spec.plugins["mini.surround"] local opts = require("lazy.core.plugin").values(plugin, "opts", false) local mappings = { { opts.mappings.add, desc = "Add surrounding", mode = { "n", "v" } }, { opts.mappings.delete, desc = "Delete surrounding" }, { opts.mappings.find, desc = "Find right surrounding" }, { opts.mappings.find_left, desc = "Find left surrounding" }, { opts.mappings.highlight, desc = "Highlight surrounding" }, { opts.mappings.replace, desc = "Replace surrounding" }, { opts.mappings.update_n_lines, desc = "Update `MiniSurround.config.n_lines`" }, } mappings = vim.tbl_filter(function(m) return m[1] and #m[1] > 0 end, mappings) return vim.list_extend(mappings, keys) end, opts = { mappings = { add = "gsa", -- Add surrounding in Normal and Visual modes delete = "gsd", -- Delete surrounding find = "gsf", -- Find surrounding (to the right) find_left = "gsF", -- Find surrounding (to the left) highlight = "gsh", -- Highlight surrounding replace = "gsr", -- Replace surrounding update_n_lines = "gsn", -- Update `n_lines` }, }, }, -- comments { "JoosepAlviste/nvim-ts-context-commentstring", lazy = true, opts = { enable_autocmd = false, }, }, { "echasnovski/mini.comment", event = "VeryLazy", opts = { options = { custom_commentstring = function() return require("ts_context_commentstring.internal").calculate_commentstring() or vim.bo.commentstring end, }, }, }, -- Better text-objects { "echasnovski/mini.ai", -- keys = { -- { "a", mode = { "x", "o" } }, -- { "i", mode = { "x", "o" } }, -- }, event = "VeryLazy", opts = function() local ai = require("mini.ai") return { n_lines = 500, custom_textobjects = { o = ai.gen_spec.treesitter({ a = { "@block.outer", "@conditional.outer", "@loop.outer" }, i = { "@block.inner", "@conditional.inner", "@loop.inner" }, }, {}), f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }, {}), c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }, {}), t = { "<([%p%w]-)%f[^<%w][^<>]->.-", "^<.->().*()$" }, d = { "%f[%d]%d+" }, -- digits e = { -- Word with case { "%u[%l%d]+%f[^%l%d]", "%f[%S][%l%d]+%f[^%l%d]", "%f[%P][%l%d]+%f[^%l%d]", "^[%l%d]+%f[^%l%d]", }, "^().*()$", }, g = function() -- Whole buffer, similar to `gg` and 'G' motion local from = { line = 1, col = 1 } local to = { line = vim.fn.line("$"), col = math.max(vim.fn.getline("$"):len(), 1), } return { from = from, to = to } end, u = ai.gen_spec.function_call(), -- u for "Usage" U = ai.gen_spec.function_call({ name_pattern = "[%w_]" }), -- without dot in function name }, } end, config = function(_, opts) require("mini.ai").setup(opts) -- register all text objects with which-key LazyVim.on_load("which-key.nvim", function() ---@type table local i = { [" "] = "Whitespace", ['"'] = 'Balanced "', ["'"] = "Balanced '", ["`"] = "Balanced `", ["("] = "Balanced (", [")"] = "Balanced ) including white-space", [">"] = "Balanced > including white-space", [""] = "Balanced <", ["]"] = "Balanced ] including white-space", ["["] = "Balanced [", ["}"] = "Balanced } including white-space", ["{"] = "Balanced {", ["?"] = "User Prompt", _ = "Underscore", a = "Argument", b = "Balanced ), ], }", c = "Class", d = "Digit(s)", e = "Word in CamelCase & snake_case", f = "Function", g = "Entire file", o = "Block, conditional, loop", q = "Quote `, \", '", t = "Tag", u = "Use/call function & method", U = "Use/call without dot in name", } local a = vim.deepcopy(i) for k, v in pairs(a) do a[k] = v:gsub(" including.*", "") end local ic = vim.deepcopy(i) local ac = vim.deepcopy(a) for key, name in pairs({ n = "Next", l = "Last" }) do i[key] = vim.tbl_extend("force", { name = "Inside " .. name .. " textobject" }, ic) a[key] = vim.tbl_extend("force", { name = "Around " .. name .. " textobject" }, ac) end require("which-key").register({ mode = { "o", "x" }, i = i, a = a, }) end) end, }, }