X-Git-Url: https://git.rmz.io/dotfiles.git/blobdiff_plain/2366af6c6e702d69c4e4d8260ebd0082bb717a14..3b5e99b9e0c217919225b705e6fb2b7095341b4d:/nvim/lua/plugins/coding.lua diff --git a/nvim/lua/plugins/coding.lua b/nvim/lua/plugins/coding.lua index a765a79..77d4955 100644 --- a/nvim/lua/plugins/coding.lua +++ b/nvim/lua/plugins/coding.lua @@ -1,54 +1,234 @@ ----@type LazyPluginSpec +---@type LazySpec return { -- snippets - { - "L3MON4D3/LuaSnip", - -- disable luasnip bindings for and + { "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 = "", + }, }, - -- auto completion - { - "hrsh7th/nvim-cmp", - ---@param opts cmp.ConfigSchema - opts = function(_, opts) - local has_words_before = function() - unpack = unpack or table.unpack - local line, col = unpack(vim.api.nvim_win_get_cursor(0)) - return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil - end - - local cmp = require("cmp") - local luasnip = require("luasnip") + { "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") - opts.completion = vim.tbl_extend("force", opts.completion, { - completeopt = "menu,menuone,noselect", - }) - --TODO: review if I want to keep any of LazyVim's mappings - opts.mapping = vim.tbl_extend("force", opts.mapping, { - [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_next_item() - elseif luasnip.expand_or_jumpable() then - luasnip.expand_or_jump() - elseif has_words_before() then - cmp.complete() - else - fallback() + 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, { "i", "s" }), - [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_prev_item() - elseif luasnip.jumpable(-1) then - luasnip.jump(-1) - else - fallback() + 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, { "i", "s" }), + 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 = { } + } }