return { -- snippets { "L3MON4D3/LuaSnip", dependencies = { "rafamadriz/friendly-snippets", config = function() require("luasnip.loaders.from_vscode").lazy_load() 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 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", "saadparwaiz1/cmp_luasnip", }, opts = function() local cmp = require("cmp") return { completion = { completeopt = "menu,menuone,noinsert", }, snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.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. }), sources = cmp.config.sources({ { name = "nvim_lsp" }, { name = "luasnip" }, { name = "buffer" }, { name = "path" }, }), 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 = "LspCodeLens", }, }, } end, }, -- auto pairs { "echasnovski/mini.pairs", event = "VeryLazy", config = function(_, opts) require("mini.pairs").setup(opts) end, }, -- surround { "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`" }, } return vim.list_extend(mappings, keys) end, opts = { mappings = { add = "gza", -- Add surrounding in Normal and Visual modes delete = "gzd", -- Delete surrounding find = "gzf", -- Find surrounding (to the right) find_left = "gzF", -- Find surrounding (to the left) highlight = "gzh", -- Highlight surrounding replace = "gzr", -- Replace surrounding update_n_lines = "gzn", -- Update `n_lines` }, }, config = function(_, opts) -- use gz mappings instead of s to prevent conflict with leap require("mini.surround").setup(opts) end, }, -- comments { "JoosepAlviste/nvim-ts-context-commentstring", lazy = true }, { "echasnovski/mini.comment", event = "VeryLazy", opts = { hooks = { pre = function() require("ts_context_commentstring.internal").update_commentstring({}) end, }, }, config = function(_, opts) require("mini.comment").setup(opts) end, }, -- better text-objects { "echasnovski/mini.ai", -- keys = { -- { "a", mode = { "x", "o" } }, -- { "i", mode = { "x", "o" } }, -- }, event = "VeryLazy", dependencies = { { "nvim-treesitter/nvim-treesitter-textobjects", init = function() -- no need to load the plugin, since we only need its queries require("lazy.core.loader").disable_rtp_plugin("nvim-treesitter-textobjects") end, }, }, 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" }, {}), }, } end, config = function(_, opts) -- register all text objects with which-key if require("lazyvim.util").has("which-key.nvim") then local text_objects = { t = "tag", b = "balanced ), ], }", f = "function", c = "class", o = "block, conditional, loop", a = "argument", q = "quote `, \", '", ["?"] = "user Prompt", ["_"] = "underscore", [" "] = "whitespace", } for _, o in ipairs({ "(", ")", "[", "]", "{", "}", ">", "<", "'", "`", '"' }) do local desc = "balanced " .. o if vim.tbl_contains({ ")", "]", "}", ">" }, o) then desc = desc .. " with inner space" end text_objects[o == "<" and "" or o] = desc end local text_objects_copy = vim.deepcopy(text_objects) for key, name in pairs({ n = "Next", l = "Last" }) do ---@diagnostic disable-next-line: assign-type-mismatch text_objects[key] = vim.tbl_extend("force", { name = name }, text_objects_copy) end require("which-key").register({ mode = { "o", "x" }, i = text_objects, a = text_objects, }) end require("mini.ai").setup(opts) end, }, }