---@type LazySpec return { -- snippets { "l3mon4d3/luasnip", build = "make install_jsregexp", -- optional dependencies = { { "honza/vim-snippets", }, }, config = function() local snippets = vim.fn.stdpath("config").."/snippets" require("luasnip.loaders.from_snipmate").load({ paths = { snippets }}) require("luasnip.loaders.from_lua").load({ paths = { snippets }}) end, keys = function() return {} end, opts = { history = true, delete_check_events = "TextChanged", 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, }, { "numToStr/Comment.nvim", dependencies = { { "JoosepAlviste/nvim-ts-context-commentstring", -- nested language commenting (f.ex markdown code blocks) opts = { enable_autocmd = false, }, } }, opts = function(_, opts) local tscci = require('ts_context_commentstring.integrations.comment_nvim') vim.tbl_deep_extend('force', opts, { toggler = { line = "gcc", block = "gbb", }, mappings = { basic = true, extra = true, }, pre_hook = tscci.create_pre_hook() }) return opts end, }, { "danymat/neogen", -- Generate annotations like doxygen cmd = "Neogen", keys = { { "cn", function() require("neogen").generate() end, desc = "Generate Annotations (Neogen)", }, }, opts = { snippet_engine = "luasnip", }, }, { "folke/lazydev.nvim", ft = "lua", cmd = "LazyDev", opts = { library = { { path = "${3rd}/luv/library", words = { "vim%.uv" } }, { path = "snacks.nvim", words = { "Snacks" } }, { path = "lazy.nvim", words = { "LazySpec" } }, }, }, }, { "gbprod/yanky.nvim", enabled = false, -- better yank/paste -- TODO: integrate? -- I'm not entirely convinced, it doesn't provide functionality like vim-peekaboo, -- maybe it can supplement it though? -- Also, see issues on OSC52: https://github.com/gbprod/yanky.nvim/issues/213 recommended = true, desc = "Better Yank/Paste", event = "LazyFile", opts = { highlight = { timer = 150 }, }, keys = { { "p", function() vim.cmd([[YankyRingHistory]]) end, mode = { "n", "x" }, desc = "Open Yank History", }, -- stylua: ignore { "y", "(YankyYank)", mode = { "n", "x" }, desc = "Yank Text" }, { "p", "(YankyPutAfter)", mode = { "n", "x" }, desc = "Put Text After Cursor" }, { "P", "(YankyPutBefore)", mode = { "n", "x" }, desc = "Put Text Before Cursor" }, { "gp", "(YankyGPutAfter)", mode = { "n", "x" }, desc = "Put Text After Selection" }, { "gP", "(YankyGPutBefore)", mode = { "n", "x" }, desc = "Put Text Before Selection" }, { "[y", "(YankyCycleForward)", desc = "Cycle Forward Through Yank History" }, { "]y", "(YankyCycleBackward)", desc = "Cycle Backward Through Yank History" }, { "]p", "(YankyPutIndentAfterLinewise)", desc = "Put Indented After Cursor (Linewise)" }, { "[p", "(YankyPutIndentBeforeLinewise)", desc = "Put Indented Before Cursor (Linewise)" }, { "]P", "(YankyPutIndentAfterLinewise)", desc = "Put Indented After Cursor (Linewise)" }, { "[P", "(YankyPutIndentBeforeLinewise)", desc = "Put Indented Before Cursor (Linewise)" }, { ">p", "(YankyPutIndentAfterShiftRight)", desc = "Put and Indent Right" }, { "(YankyPutIndentAfterShiftLeft)", desc = "Put and Indent Left" }, { ">P", "(YankyPutIndentBeforeShiftRight)", desc = "Put Before and Indent Right" }, { "(YankyPutIndentBeforeShiftLeft)", desc = "Put Before and Indent Left" }, { "=p", "(YankyPutAfterFilter)", desc = "Put After Applying a Filter" }, { "=P", "(YankyPutBeforeFilter)", desc = "Put Before Applying a Filter" }, }, }, { "andrewferrier/debugprint.nvim", dependencies = { "nvim-treesitter" }, -- TODO: setup debugprint (or maybe not) opts = { } } }