---@type LazySpec return { -- snippets { "L3MON4D3/LuaSnip", -- disable luasnip bindings for and dependencies = { { "honza/vim-snippets", config = function() require("luasnip.loaders.from_snipmate").lazy_load() require("luasnip.loaders.from_lua").load({ paths = vim.fn.stdpath("config") .. "/lua/snippets" }) end, }, }, keys = function() return {} end, opts = { store_selection_keys = "", }, }, { "echasnovski/mini.pairs", event = "VeryLazy", opts = { modes = { insert = true, command = true, terminal = false }, -- skip autopair when next character is one of these skip_next = [=[[%w%%%'%[%"%.%`%$]]=], -- skip autopair when the cursor is inside these treesitter nodes skip_ts = { "string" }, -- skip autopair when next character is closing pair -- and there are more closing pairs than opening pairs skip_unbalanced = true, -- better deal with markdown code blocks markdown = true, }, config = function(_, opts) Snacks.toggle({ name = "Mini Pairs", get = function() return not vim.g.minipairs_disable end, set = function(state) vim.g.minipairs_disable = not state end, }):map("up") local pairs = require("mini.pairs") pairs.setup(opts) local open = pairs.open --- Custom open command with extensions from LazyVim ---@diagnostic disable-next-line: duplicate-set-field pairs.open = function(pair, neigh_pattern) if vim.fn.getcmdline() ~= "" then return open(pair, neigh_pattern) end local o, c = pair:sub(1, 1), pair:sub(2, 2) local line = vim.api.nvim_get_current_line() local cursor = vim.api.nvim_win_get_cursor(0) local next = line:sub(cursor[2] + 1, cursor[2] + 1) local before = line:sub(1, cursor[2]) -- don't add fourth ` in markdown ``` if opts.markdown and o == "`" and vim.bo.filetype == "markdown" and before:match("^%s*``") then return "`\n```" .. vim.api.nvim_replace_termcodes("", true, true, true) end if opts.skip_next and next ~= "" and next:match(opts.skip_next) then return o end if opts.skip_ts and #opts.skip_ts > 0 then local ok, captures = pcall(vim.treesitter.get_captures_at_pos, 0, cursor[1] - 1, math.max(cursor[2] - 1, 0)) for _, capture in ipairs(ok and captures or {}) do if vim.tbl_contains(opts.skip_ts, capture.capture) then return o end end end if opts.skip_unbalanced and next == c and c ~= o then local _, count_open = line:gsub(vim.pesc(pair:sub(1, 1)), "") local _, count_close = line:gsub(vim.pesc(pair:sub(2, 2)), "") if count_close > count_open then return o end end return open(pair, neigh_pattern) end end, }, { "echasnovski/mini.surround", keys = function() -- HACK: use function to disable merging with LazyVim's keys definition return { { "ys", desc = "Add surrounding", "n" }, { "S", desc = "Add surrounding", "x" }, { "ds", desc = "Delete surrounding" }, { "cs", desc = "Change surrounding" }, { "yss", "ys_", remap = true }, } end, opts = { mappings = { -- TODO: this is tpope/surround like, but should consider using vim-sandwich mappings -- see: :h MiniSurround-vim-surround-config add = "ys", delete = "ds", find = "", find_left = "", highlight = "", replace = "cs", update_n_lines = "", }, }, config = function(_, opts) require("mini.surround").setup(opts) -- remap visual vim.keymap.del("x", "ys", { silent = true }) vim.keymap.set("x", "S", [[:lua MiniSurround.add('visual')]], { silent = true }) end, }, { "echasnovski/mini.ai", -- TODO: port vim text objects over event = "VeryLazy", opts = function() local ai = require("mini.ai") return { n_lines = 500, custom_textobjects = { o = ai.gen_spec.treesitter({ -- code block 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" }), -- function c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }), -- class t = { "<([%p%w]-)%f[^<%w][^<>]->.-", "^<.->().*()$" }, -- tags 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]" }, "^().*()$", }, 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) LazyVim.on_load("which-key.nvim", function() vim.schedule(function() LazyVim.mini.ai_whichkey(opts) end) end) end, }, -- comments { "numToStr/Comment.nvim", -- used to be what I use, but nvim will include commenting based on mini.comment enabled = false , opts = { toggler = { line = "gcc", block = "gbb", }, mappings = { basic = true, extra = true, }, }, }, { "echasnovski/mini.comment", enabled = false }, { "folke/lazydev.nvim", ft = "lua", cmd = "LazyDev", opts = { library = { { path = "${3rd}/luv/library", words = { "vim%.uv" } }, { path = "LazyVim", words = { "LazyVim" } }, { path = "snacks.nvim", words = { "Snacks" } }, { path = "lazy.nvim", words = { "LazyVim" } }, }, }, }, }