From 96570086ae9fefaa6d532c00ce1540c391ba6257 Mon Sep 17 00:00:00 2001 From: n3wborn Date: Sat, 3 Oct 2026 16:01:17 +0200 Subject: [PATCH 01/12] feat: add review.nvim --- lua/plugin/review.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 lua/plugin/review.lua diff --git a/lua/plugin/review.lua b/lua/plugin/review.lua new file mode 100644 index 00000000..b09a6736 --- /dev/null +++ b/lua/plugin/review.lua @@ -0,0 +1,11 @@ +local add = require('vim-pack').add + +add({ + { + src = 'vuki656/review.nvim', + opts = {}, + on_setup = function() + vim.keymap.set({ 'n', 'v' }, 'rv', 'Review', { desc = 'Start a review' }) + end, + }, +}) From 8b8b738cac7ae1b09207522650e54a98a46d0631 Mon Sep 17 00:00:00 2001 From: n3wborn Date: Sat, 3 Oct 2026 16:01:35 +0200 Subject: [PATCH 02/12] feat: add conform.nvim --- lua/plugin/conform.lua | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 lua/plugin/conform.lua diff --git a/lua/plugin/conform.lua b/lua/plugin/conform.lua new file mode 100644 index 00000000..80269667 --- /dev/null +++ b/lua/plugin/conform.lua @@ -0,0 +1,100 @@ +local add_on_event = require('vim-pack').add_on_event + +add_on_event('BufWritePre', { + { + src = 'stevearc/conform.nvim', + opts = { + exclude_path_patterns = { + '/node_modules/', + '/vendor/', + }, + formatters_by_ft = { + go = { 'gofmt' }, + lua = { 'stylua' }, + markdown = { 'rumdl' }, + php = { 'php_cs_fixer' }, + python = { + -- To fix auto-fixable lint errors. + 'ruff_fix', + -- To run the Ruff formatter. + 'ruff_format', + -- To organize the imports. + 'ruff_organize_imports', + }, + rust = { 'rustfmt' }, + sh = { 'shfmt', 'shellcheck' }, + sql = { 'sql_formatter' }, + twig = { 'twig-cs-fixer' }, + v = { 'v' }, + + -- https://oxc.rs/ + javascript = { 'oxfmt' }, + javascriptreact = { 'oxfmt' }, + typescript = { 'oxfmt' }, + typescriptreact = { 'oxfmt' }, + json = { 'oxfmt' }, + jsonc = { 'oxfmt' }, + vue = { 'oxfmt' }, + + ['*'] = { 'trim_whitespace', 'squeeze_blanks', 'trim_newlines' }, + }, + format_on_save = function(bufnr) + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + return { async = false, timeout_ms = 2000, lsp_format = 'never' } + end, + formatters = { + oxfmt = { + command = function(_, ctx) + local local_oxfmt = vim.fs.find('node_modules/.bin/oxfmt', { + upward = true, + path = ctx.dirname, + type = 'file', + })[1] + + return local_oxfmt or 'oxfmt' + end, + }, + php_cs_fixer = { + env = { PHP_CS_FIXER_IGNORE_ENV = 1 }, + args = function(_, ctx) + local args = { 'fix', '$FILENAME', '--quiet', '--no-interaction', '--using-cache=no' } + local found = nil + local core_dir = os.getenv('CORE_DIR') + local root_dir = nil + + if core_dir then + root_dir = + vim.fs.find(core_dir, { type = 'directory', upward = true, path = ctx.dirname })[1] + if root_dir then + found = vim.fs.find('.php-cs-fixer.php.dist', { path = root_dir, type = 'file' })[1] + vim.api.nvim_echo({ { 'Found corePlugin at:\n' }, { root_dir } }, true, {}) + end + end + + if not found then + found = vim.fs.find('.php-cs-fixer.php.dist', { upward = true, path = ctx.dirname })[1] + if found then + vim.api.nvim_echo({ { 'Using fallback php-cs-fixer config:\n' }, { found } }, true, {}) + end + end + + if found then + vim.list_extend(args, { '--config=' .. found }) + else + vim.list_extend(args, { '--rules=@PSR12,@Symfony' }) + end + + return args + end, + }, + }, + }, + }, +}) +-- Use conform for gq. +vim.o.formatexpr = "v:lua.require'conform'.formatexpr()" + +-- Start auto-formatting by default (and disable with my ToggleFormat command). +vim.g.autoformat = true From 99d7a89680a1e346c07057914a46ac2b66ea7e00 Mon Sep 17 00:00:00 2001 From: n3wborn Date: Sat, 3 Oct 2026 16:02:01 +0200 Subject: [PATCH 03/12] feat: add blink.cmp and blink.lib --- lua/plugin/blink.lua | 88 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 lua/plugin/blink.lua diff --git a/lua/plugin/blink.lua b/lua/plugin/blink.lua new file mode 100644 index 00000000..20f7eded --- /dev/null +++ b/lua/plugin/blink.lua @@ -0,0 +1,88 @@ +--- @diagnostic disable: unresolved-require +local add = require('vim-pack').add + +-- Auto-completion and snippets. +add({ + { src = 'saghen/blink.lib', setup = false }, + { + src = 'saghen/blink.cmp', + opts = { + appearance = { + nerd_font_variant = 'mono', + }, + completion = { + list = { + -- Insert items while navigating the completion list. + selection = { preselect = false, auto_insert = true }, + max_items = 20, + }, + documentation = { auto_show = true }, + menu = { + scrollbar = false, + draw = { + columns = { + { 'label', 'label_description', gap = 1 }, + { 'kind_icon' }, + { 'kind' }, + { 'source_name', gap = 1 }, + }, + }, + }, + }, + keymap = { + [''] = { 'select_next', 'fallback' }, + [''] = { 'select_prev', 'fallback' }, + [''] = { 'select_next', 'fallback_to_mappings' }, + [''] = { 'select_prev', 'fallback_to_mappings' }, + [''] = { 'select_and_accept', 'fallback' }, + [''] = { 'cancel', 'fallback' }, + + [''] = { 'snippet_forward', 'select_next', 'fallback' }, + [''] = { 'snippet_backward', 'select_prev', 'fallback' }, + [''] = { 'select_and_accept', 'fallback' }, + + [''] = { 'show', 'show_documentation', 'hide_documentation' }, + + [''] = { 'scroll_documentation_up', 'fallback' }, + [''] = { 'scroll_documentation_down', 'fallback' }, + + [''] = { 'show_signature', 'hide_signature', 'fallback' }, + }, + sources = { + default = { 'lsp', 'path', 'buffer', 'snippets' }, + min_keyword_length = 0, + providers = { + snippets = { + max_items = 3, + }, + -- lazydev = { + -- name = 'LazyDev', + -- module = 'lazydev.integrations.blink', + -- score_offset = 100, + -- }, + buffer = { + -- default to all visible buffers + get_bufnrs = function() + return vim.iter(vim.api.nvim_list_wins()) + :map(function(win) + return vim.api.nvim_win_get_buf(win) + end) + :filter(function(buf) + return vim.bo[buf].buftype ~= 'nofile' + end) + :totable() + end, + }, + }, + }, + signature = { enabled = true }, + fuzzy = { + implementation = 'prefer_rust', + }, + }, + on_setup = function() + -- TODO: Fix the Task type below. + require('blink.cmp').build():pwait(60000) + end, + }, +}) From efe8e5d252355c8bcd218ab20706f38815ab58ea Mon Sep 17 00:00:00 2001 From: n3wborn Date: Sat, 3 Oct 2026 16:02:21 +0200 Subject: [PATCH 04/12] feat: add vim-pack.lua --- lua/vim-pack.lua | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 lua/vim-pack.lua diff --git a/lua/vim-pack.lua b/lua/vim-pack.lua new file mode 100644 index 00000000..ab5e9caa --- /dev/null +++ b/lua/vim-pack.lua @@ -0,0 +1,92 @@ +local M = {} + +---@class PluginSpec +---@field src string The GitHub repository of the plugin +---@field module_name? string Optional module name for configuration (defaults to the repo name) +---@field opts? table|fun():table Optional configuration options for the plugin +---@field on_setup? fun():nil Optional function to run after the plugin is loaded and configured +---@field setup? false Set to false to skip require/setup entirely (for vimscript-only or data-only plugins) + +---@param plugins PluginSpec[] +local function configure(plugins) + local sources = vim.iter(plugins) + :map(function(plugin) + -- Ensure we use GitHub urls. + return string.format('https://github.com/%s', plugin.src) + end) + :totable() + + vim.pack.add(sources) + + -- Configure each plugin after loading. + for _, plugin in ipairs(plugins) do + if plugin.setup ~= false then + local module_name = plugin.module_name or (plugin.src:match('.+/(.+)'):gsub('%.nvim$', '')) + local mod = require(module_name) + if type(mod.setup) == 'function' then + local opts = type(plugin.opts) == 'function' and plugin.opts() or plugin.opts + mod.setup(opts or {}) + end + end + + if plugin.on_setup then + plugin.on_setup() + end + end +end + +---@param event vim.api.keyset.events|vim.api.keyset.events[] +---@param pattern? string|string[] +---@param plugins PluginSpec[] +local add_on_event = function(event, pattern, plugins) + vim.api.nvim_create_autocmd(event, { + pattern = pattern, + once = true, + callback = function() + configure(plugins) + end, + }) +end + +--- Helper function for adding and configuring plugins eagerly, with no lazy-loading. +--- +---@param plugins PluginSpec[] +function M.add(plugins) + configure(plugins) +end + +--- Helper function for adding and configuring plugins to the current session on a specific event. +--- +---@param event vim.api.keyset.events|vim.api.keyset.events[] +---@param plugins PluginSpec[] +function M.add_on_event(event, plugins) + add_on_event(event, nil, plugins) +end + +--- Helper function for adding and configuring plugins to the current session when a file of a specific type is first opened. +--- +---@param patterns string|string[] +---@param plugins PluginSpec[] +function M.add_on_file_type(patterns, plugins) + add_on_event('FileType', patterns, plugins) +end + +--- Runs the given command inside the plugin's directory when the plugin is updated. +--- +---@param plugin_name string Plugin name +---@param cmd string|fun():nil Command to run +function M.on_plugin_update(plugin_name, cmd) + vim.api.nvim_create_autocmd('PackChanged', { + callback = function(args) + if args.data.spec.name == plugin_name and (args.data.kind == 'install' or args.data.kind == 'update') then + if type(cmd) == 'string' then + vim.system({ cmd }, { cwd = args.data.path }) + else + cmd() + end + end + end, + }) +end + +return M From 469be8360e5047e93a3e25148f83ef849b57f45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Pluchart?= Date: Mon, 5 Oct 2026 20:17:01 +0200 Subject: [PATCH 05/12] feat(plugins): port remaining plugin to vim.pack - vim-pack.lua: add `name` and `version` spec fields, allow a list or a function (receiving the PackChanged data) in on_plugin_update - blink: enable lazydev and dadbod sources - add lua/plugin/* for every remaining lazy.nvim spec - dap: ported but disabled (nvim-dap was optional/never installed, keymaps clash with dadbod-grip) --- lua/plugin/blink.lua | 15 +- lua/plugin/blink_indent.lua | 22 +++ lua/plugin/blink_pairs.lua | 44 ++++++ lua/plugin/celeste_comment.lua | 98 +++++++++++++ lua/plugin/colorscheme.lua | 53 +++++++ lua/plugin/dadbod.lua | 23 +++ lua/plugin/dap.lua | 102 ++++++++++++++ lua/plugin/differ.lua | 47 +++++++ lua/plugin/diffview.lua | 84 +++++++++++ lua/plugin/fff.lua | 90 ++++++++++++ lua/plugin/fzf_lua.lua | 223 ++++++++++++++++++++++++++++++ lua/plugin/gitgraph.lua | 64 +++++++++ lua/plugin/gitsigns.lua | 81 +++++++++++ lua/plugin/gopher.lua | 10 ++ lua/plugin/grug_far.lua | 13 ++ lua/plugin/hexinspector.lua | 43 ++++++ lua/plugin/lazydev.lua | 15 ++ lua/plugin/lspconfig.lua | 7 + lua/plugin/lualine.lua | 101 ++++++++++++++ lua/plugin/mini.lua | 5 + lua/plugin/neogit.lua | 36 +++++ lua/plugin/neotest.lua | 18 +++ lua/plugin/nvim-lint.lua | 166 ++++++++++++++++++++++ lua/plugin/nvim_rip_substitue.lua | 29 ++++ lua/plugin/outline.lua | 19 +++ lua/plugin/rest.lua | 6 + lua/plugin/rustaceanvim.lua | 30 ++++ lua/plugin/snacks.lua | 118 ++++++++++++++++ lua/plugin/surround.lua | 5 + lua/plugin/treesitter.lua | 91 ++++++++++++ lua/plugin/ts-context.lua | 20 +++ lua/plugin/ts-textobject.lua | 14 ++ lua/plugin/typr.lua | 6 + lua/plugin/yazi.lua | 34 +++++ lua/vim-pack.lua | 16 ++- 35 files changed, 1738 insertions(+), 10 deletions(-) create mode 100644 lua/plugin/blink_indent.lua create mode 100644 lua/plugin/blink_pairs.lua create mode 100644 lua/plugin/celeste_comment.lua create mode 100644 lua/plugin/colorscheme.lua create mode 100644 lua/plugin/dadbod.lua create mode 100644 lua/plugin/dap.lua create mode 100644 lua/plugin/differ.lua create mode 100644 lua/plugin/diffview.lua create mode 100644 lua/plugin/fff.lua create mode 100644 lua/plugin/fzf_lua.lua create mode 100644 lua/plugin/gitgraph.lua create mode 100644 lua/plugin/gitsigns.lua create mode 100644 lua/plugin/gopher.lua create mode 100644 lua/plugin/grug_far.lua create mode 100644 lua/plugin/hexinspector.lua create mode 100644 lua/plugin/lazydev.lua create mode 100644 lua/plugin/lspconfig.lua create mode 100644 lua/plugin/lualine.lua create mode 100644 lua/plugin/mini.lua create mode 100644 lua/plugin/neogit.lua create mode 100644 lua/plugin/neotest.lua create mode 100644 lua/plugin/nvim-lint.lua create mode 100644 lua/plugin/nvim_rip_substitue.lua create mode 100644 lua/plugin/outline.lua create mode 100644 lua/plugin/rest.lua create mode 100644 lua/plugin/rustaceanvim.lua create mode 100644 lua/plugin/snacks.lua create mode 100644 lua/plugin/surround.lua create mode 100644 lua/plugin/treesitter.lua create mode 100644 lua/plugin/ts-context.lua create mode 100644 lua/plugin/ts-textobject.lua create mode 100644 lua/plugin/typr.lua create mode 100644 lua/plugin/yazi.lua diff --git a/lua/plugin/blink.lua b/lua/plugin/blink.lua index 20f7eded..9a81ee18 100644 --- a/lua/plugin/blink.lua +++ b/lua/plugin/blink.lua @@ -50,16 +50,21 @@ add({ }, sources = { default = { 'lsp', 'path', 'buffer', 'snippets' }, + per_filetype = { + lua = { inherit_defaults = true, 'lazydev' }, + sql = { 'dadbod', 'buffer' }, + }, min_keyword_length = 0, providers = { snippets = { max_items = 3, }, - -- lazydev = { - -- name = 'LazyDev', - -- module = 'lazydev.integrations.blink', - -- score_offset = 100, - -- }, + lazydev = { + name = 'LazyDev', + module = 'lazydev.integrations.blink', + score_offset = 100, + }, + dadbod = { name = 'Dadbod', module = 'vim_dadbod_completion.blink' }, buffer = { -- default to all visible buffers get_bufnrs = function() diff --git a/lua/plugin/blink_indent.lua b/lua/plugin/blink_indent.lua new file mode 100644 index 00000000..6c61a895 --- /dev/null +++ b/lua/plugin/blink_indent.lua @@ -0,0 +1,22 @@ +local add_on_event = require('vim-pack').add_on_event + +-- Indent guides. +add_on_event('BufWinEnter', { + { + src = 'saghen/blink.indent', + opts = { + blocked = { buftypes = { include_defaults = true }, filetypes = { include_defaults = true } }, + scope = { + char = '▏', + enabled = true, + indent_at_cursor = false, + priority = 1000, + underline = { enabled = true }, + }, + static = { + char = '▏', + enabled = true, + }, + }, + }, +}) diff --git a/lua/plugin/blink_pairs.lua b/lua/plugin/blink_pairs.lua new file mode 100644 index 00000000..71a99dda --- /dev/null +++ b/lua/plugin/blink_pairs.lua @@ -0,0 +1,44 @@ +local add_on_event = require('vim-pack').add_on_event + +-- Auto-pairs and rainbow delimiters. +add_on_event({ 'BufEnter', 'BufNewFile' }, { + { src = 'saghen/blink.lib', setup = false }, + { + src = 'saghen/blink.pairs', + opts = { + mappings = { + enabled = true, + cmdline = true, + -- or disable with `vim.g.pairs = false` (global) and `vim.b.pairs = false` (per-buffer) + -- and/or with `vim.g.blink_pairs = false` and `vim.b.blink_pairs = false` + disabled_filetypes = {}, + pairs = {}, + }, + highlights = { + enabled = true, + -- requires require('vim._core.ui2').enable() (see init.lua), otherwise has no effect + cmdline = true, + groups = { + 'BlinkPairsPurple', + 'BlinkPairsBlue', + 'BlinkPairsOrange', + }, + unmatched_group = 'BlinkPairsUnmatched', + matchparen = { + enabled = true, + -- known issue where typing won't update matchparen highlight, disabled by default + cmdline = false, + -- also include pairs not on top of the cursor, but surrounding the cursor + include_surrounding = false, + group = 'BlinkPairsMatchParen', + priority = 250, + }, + }, + debug = false, + }, + on_setup = function() + -- TODO: Fix the Task type below. + require('blink.pairs').build():pwait(60000) + end, + }, +}) diff --git a/lua/plugin/celeste_comment.lua b/lua/plugin/celeste_comment.lua new file mode 100644 index 00000000..afdf9cf0 --- /dev/null +++ b/lua/plugin/celeste_comment.lua @@ -0,0 +1,98 @@ +local add_on_event = require('vim-pack').add_on_event + +add_on_event({ 'BufReadPost', 'BufNewFile' }, { + { + src = 'celeste3z/celeste_comment.nvim', + ---@type Celeste.Comment.Opts + opts = { + -- Restore cursor position after commenting. + keep_cursor = true, + + -- Restore selection after commenting. + -- See `:help celeste_comment-config-keep_selection` + -- Possible values: "never" | "accurate" | "expand_block" + keep_selection = 'never', + + -- Insert space between comment marker and text. + insert_space = true, + + -- Place comment at start of line, skip indent alignment + line_comment_no_indent = false, + + -- Match comment markers case-insensitively (e.g. `@REM` vs `@rem` vs `@rEm`) + case_insensitive = false, + + -- Trim whitespace before detecting block tokens. + block_relaxed_detect = true, + + -- Max lines to search for block comment pairs. + block_textobj_nlines = 200, + + -- How to handle empty lines during comment toggle. + -- See `:help celeste_comment-config-ignore_empty_lines` for more details + -- Possible values: "never" | "mixed" | "always" + ignore_empty_lines = 'mixed', + + -- Fallback to block comment when line comment wraps. + -- See `:help celeste_comment-config-fallback_to_block` for more details + -- Possible values: "never" | "if_line_cms_wrapped" + fallback_to_block = 'if_line_cms_wrapped', + + -- Log level (nvim-0.13+). Ignored on older versions. + log_level = vim.log.levels.OFF, + + -- Comment string configuration. + cms_confs = nil, + + mappings = { + -- Line comment by motion (n) + line_toggle = 'gc', + -- Line comment current line (n) + line_toggle_cur = 'gcc', + -- Line comment visual selection (x) + line_toggle_visual = 'gc', + -- Insert mode line toggle (i), example `{"", ""}` + line_toggle_insert = '', + + block_toggle = '', + block_toggle_cur = '', + block_toggle_visual = '', + + -- Linewise textobject (o) + line_textobject = 'gc', + -- Blockwise textobject (o) + block_textobject = 'gcb', + -- Auto textobject (o, x), example 'ga' + auto_textobject = '', + -- Auto uncomment (n), example `gcu` + uncomment_auto = '', + + -- Insert comment below (n), example `gco` + line_add_below = 'gco', + -- Insert comment above (n), example `gcO` + line_add_above = 'gcO', + -- Insert comment at end of line (n), example `gcA` + line_add_eol = 'gcA', + + -- Invert comment per line (n, x), example `gcI` + line_invert = 'gcI', + -- Force add line comment (n, x), example `gCC` + line_force_add = '', + -- Force remove line comment (n, x), example `gCU` + line_force_remove = '', + + -- Cursor sticky dot-repeat + dot_repeat = '.', + }, + + hooks = { + -- Called before commit edits, receives context + pre_commit_edits = nil, + -- Called after commit edits, receives context + post_commit_edits = nil, + -- Custom comment string resolver function + cms_conf_resolver = nil, + }, + }, + }, +}) diff --git a/lua/plugin/colorscheme.lua b/lua/plugin/colorscheme.lua new file mode 100644 index 00000000..9b77521f --- /dev/null +++ b/lua/plugin/colorscheme.lua @@ -0,0 +1,53 @@ +local add = require('vim-pack').add + +add({ + { + src = 'catppuccin/nvim', + name = 'catppuccin', + module_name = 'catppuccin', + opts = { + compile = { + enabled = true, + }, + transparent_background = true, + float = { + transparent = false, + }, + auto_integrations = false, + integrations = { + alpha = false, + blink_cmp = { + style = 'bordered', + }, + blink_indent = true, + blink_pairs = true, + dashboard = false, + diffview = true, + flash = false, + fzf = true, + gitgraph = true, + gitsigns = true, + grug_far = true, + indent_blankline = { enabled = false }, + mini = { + enabled = true, + indentscope_color = false, + }, + cmp = false, + neogit = true, + dap = true, + dap_ui = true, + nvimtree = false, + treesitter_context = true, + ufo = false, + rainbow_delimiters = false, + snacks = { + enabled = true, + indent_scope_color = false, + }, + telescope = { enabled = false }, + illuminate = { enabled = false }, + }, + }, + }, +}) diff --git a/lua/plugin/dadbod.lua b/lua/plugin/dadbod.lua new file mode 100644 index 00000000..b5598672 --- /dev/null +++ b/lua/plugin/dadbod.lua @@ -0,0 +1,23 @@ +local add = require('vim-pack').add + +-- Set before loading vim-dadbod-ui. +vim.g.db_ui_use_nerd_fonts = 1 + +-- The blink.cmp source for sql files is configured in lua/plugin/blink.lua. +add({ + { src = 'tpope/vim-dadbod', setup = false }, + { src = 'kristijanhusak/vim-dadbod-completion', setup = false }, + { src = 'kristijanhusak/vim-dadbod-ui', setup = false }, + { + src = 'joryeugene/dadbod-grip.nvim', + opts = {}, + on_setup = function() + vim.keymap.set('n', 'db', 'GripConnect', { desc = 'DB connect' }) + vim.keymap.set('n', 'dg', 'Grip', { desc = 'DB grid' }) + vim.keymap.set('n', 'dt', 'GripTables', { desc = 'DB tables' }) + vim.keymap.set('n', 'dq', 'GripQuery', { desc = 'DB query pad' }) + vim.keymap.set('n', 'ds', 'GripSchema', { desc = 'DB schema' }) + vim.keymap.set('n', 'dh', 'GripHistory', { desc = 'DB history' }) + end, + }, +}) diff --git a/lua/plugin/dap.lua b/lua/plugin/dap.lua new file mode 100644 index 00000000..1da74383 --- /dev/null +++ b/lua/plugin/dap.lua @@ -0,0 +1,102 @@ +-- NOTE: nvim-dap was marked `optional = true` in the lazy.nvim spec, so it was never installed +-- and this whole debug setup was inactive. Its d* keymaps also clash with dadbod-grip +-- (db, dg, ds, dt). Remove this guard once the keymaps are sorted out. +do + return +end + +local add = require('vim-pack').add + +add({ + { src = 'nvim-lua/plenary.nvim', setup = false }, + { src = 'nvim-neotest/nvim-nio', setup = false }, + { src = 'williamboman/mason.nvim' }, + { + src = 'jay-babu/mason-nvim-dap.nvim', + module_name = 'mason-nvim-dap', + opts = { + automatic_installation = true, + ensure_installed = { + 'php', + }, + }, + }, + { + src = 'mfussenegger/nvim-dap', + setup = false, + on_setup = function() + local dap = require('dap') + dap.adapters.php = { + type = 'executable', + command = 'node', + args = { vim.env.HOME .. '/div/bin/vscode-php-debug/out/phpDebug.js' }, + } + + vim.api.nvim_set_hl(0, 'DapStoppedLine', { default = true, link = 'Visual' }) + local icons = { + Stopped = { '󰁕 ', 'DiagnosticWarn', 'DapStoppedLine' }, + Breakpoint = ' ', + BreakpointCondition = ' ', + BreakpointRejected = { ' ', 'DiagnosticError' }, + LogPoint = '.>', + } + for name, sign in pairs(icons) do + sign = type(sign) == 'table' and sign or { sign } + vim.fn.sign_define( + 'Dap' .. name, + { text = sign[1], texthl = sign[2] or 'DiagnosticInfo', linehl = sign[3], numhl = sign[3] } + ) + end + + -- setup dap config by VsCode launch.json file + local vscode = require('dap.ext.vscode') + local json = require('plenary.json') + vscode.json_decode = function(str) + return vim.json.decode(json.json_strip_comments(str)) + end + + -- stylua: ignore start + vim.keymap.set('n', 'dB', function() dap.set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, { desc = 'Breakpoint Condition' }) + vim.keymap.set('n', 'db', function() dap.toggle_breakpoint() end, { desc = 'Toggle Breakpoint' }) + vim.keymap.set('n', 'dc', function() dap.continue() end, { desc = 'Run/Continue' }) + vim.keymap.set('n', 'dC', function() dap.run_to_cursor() end, { desc = 'Run to Cursor' }) + vim.keymap.set('n', 'dg', function() dap.goto_() end, { desc = 'Go to Line (No Execute)' }) + vim.keymap.set('n', 'di', function() dap.step_into() end, { desc = 'Step Into' }) + vim.keymap.set('n', 'dj', function() dap.down() end, { desc = 'Down' }) + vim.keymap.set('n', 'dk', function() dap.up() end, { desc = 'Up' }) + vim.keymap.set('n', 'dl', function() dap.run_last() end, { desc = 'Run Last' }) + vim.keymap.set('n', 'do', function() dap.step_out() end, { desc = 'Step Out' }) + vim.keymap.set('n', 'dO', function() dap.step_over() end, { desc = 'Step Over' }) + vim.keymap.set('n', 'dP', function() dap.pause() end, { desc = 'Pause' }) + vim.keymap.set('n', 'dr', function() dap.repl.toggle() end, { desc = 'Toggle REPL' }) + vim.keymap.set('n', 'ds', function() dap.session() end, { desc = 'Session' }) + vim.keymap.set('n', 'dt', function() dap.terminate() end, { desc = 'Terminate' }) + vim.keymap.set('n', 'dw', function() require('dap.ui.widgets').hover() end, { desc = 'Widgets' }) + -- stylua: ignore end + end, + }, + { src = 'theHamsta/nvim-dap-virtual-text', opts = {} }, + { + src = 'rcarriga/nvim-dap-ui', + module_name = 'dapui', + opts = {}, + on_setup = function() + local dap = require('dap') + local dapui = require('dapui') + dap.listeners.after.event_initialized['dapui_config'] = function() + dapui.open({}) + end + dap.listeners.before.event_terminated['dapui_config'] = function() + dapui.close({}) + end + dap.listeners.before.event_exited['dapui_config'] = function() + dapui.close({}) + end + + -- stylua: ignore start + vim.keymap.set('n', 'du', function() dapui.toggle({}) end, { desc = 'Dap UI' }) + vim.keymap.set({ 'n', 'v' }, 'de', function() dapui.eval() end, { desc = 'Eval' }) + -- stylua: ignore end + end, + }, +}) diff --git a/lua/plugin/differ.lua b/lua/plugin/differ.lua new file mode 100644 index 00000000..c3ff693d --- /dev/null +++ b/lua/plugin/differ.lua @@ -0,0 +1,47 @@ +local vim_pack = require('vim-pack') + +vim_pack.on_plugin_update('differ.nvim', { 'make', 'go-build' }) + +vim_pack.add({ + { + src = 'undont/differ.nvim', + opts = {}, + on_setup = function() + local function map(lhs, rhs, desc) + vim.keymap.set('n', lhs, rhs, { desc = desc }) + end + + -- local diff / history + map('do', 'Differ HEAD', 'Diff: open (vs index)') + map('dc', 'Differ close', 'Diff: close') + map('dt', 'Differ base', 'Diff: branch total (vs base)') + map('de', 'Differ gofile', 'Diff: open the real file') + map('dd', 'Differ panel', 'Diff: panel toggle') + map('dh', 'Differ log', 'Diff: file history') + map('dp', 'Differ log origin/HEAD...HEAD', 'Diff: PR range (local, no API)') + map('dl', 'Differ layout', 'Diff: toggle layout') + -- pr review (sidecar + github) + map('pl', 'Differ pr list', 'PR: list') + map('po', function() + vim.ui.input({ prompt = 'PR number: ' }, function(input) + if input and input ~= '' then + vim.cmd('Differ pr ' .. input) + end + end) + end, 'PR: open by number') + map('pr', 'Differ pr review', 'PR: review start') + map('pe', 'Differ pr review resume', 'PR: review resume') + map('pm', 'Differ pr review submit', 'PR: review submit') + map('pd', 'Differ pr review discard', 'PR: review discard') + map('psm', 'Differ pr merge squash', 'PR: squash merge') + map('pk', 'Differ pr checks', 'PR: checks') + map('pO', 'Differ pr checkout', 'PR: checkout') + map('pR', 'Differ pr ready', 'PR: mark ready') + map('pD', 'Differ pr draft', 'PR: mark draft') + map('pX', 'Differ pr close', 'PR: close') + map('pb', 'Differ pr browser', 'PR: open in browser') + map('py', 'Differ pr url', 'PR: yank URL') + map('pq', 'Differ close', 'PR: quit') + end, + }, +}) diff --git a/lua/plugin/diffview.lua b/lua/plugin/diffview.lua new file mode 100644 index 00000000..76294e52 --- /dev/null +++ b/lua/plugin/diffview.lua @@ -0,0 +1,84 @@ +local add = require('vim-pack').add + +--- Toggle Diffview: close it when open, otherwise open the file history (or the diff on an unnamed buffer). +---@param current_file boolean Restrict the file history to the current file +local function toggle_file_history(current_file) + local ok, lib = pcall(require, 'diffview.lib') + if not ok then + vim.notify('diffview.nvim not installed', vim.log.levels.WARN) + return + end + + local view = lib.get_current_view() + if view then + vim.cmd('DiffviewClose') + return + end + + local file = vim.api.nvim_buf_get_name(0) + if file == '' then + vim.cmd('DiffviewOpen') + elseif current_file then + vim.cmd('DiffviewFileHistory ' .. vim.fn.fnameescape(file)) + else + vim.cmd('DiffviewFileHistory') + end +end + +add({ + { + src = 'dlyongemallo/diffview-plus.nvim', + module_name = 'diffview', + opts = { + auto_close_on_empty = true, + hide_merge_artifacts = true, + clean_up_buffers = true, + default_args = { + DiffviewOpen = { '--imply-local' }, + }, + use_icons = false, + keymaps = { + file_panel = { + { + 'n', + 'cc', + function() + vim.ui.input({ prompt = 'Commit message: ' }, function(msg) + if not msg then + return + end + local results = vim.system({ 'git', 'commit', '-m', msg }, { text = true }):wait() + + if results.code ~= 0 then + vim.notify( + 'Commit failed with the message: \n' + .. vim.trim(results.stdout .. '\n' .. results.stderr), + vim.log.levels.ERROR, + { title = 'Commit' } + ) + else + vim.notify(results.stdout, vim.log.levels.INFO, { title = 'Commit' }) + end + end) + end, + }, + }, + }, + }, + on_setup = function() + vim.keymap.set('n', 'v', function() + if next(require('diffview.lib').views) == nil then + vim.cmd('DiffviewOpen') + else + vim.cmd('DiffviewClose') + end + end, { desc = require('config.icons').git.git .. ' Diff This' }) + vim.keymap.set('n', 'hd', function() + toggle_file_history(false) + end, { desc = 'Toggle DiffviewFileHistory' }) + vim.keymap.set('n', 'hD', function() + toggle_file_history(true) + end, { desc = 'Toggle DiffviewFileHistory on current file' }) + end, + }, +}) diff --git a/lua/plugin/fff.lua b/lua/plugin/fff.lua new file mode 100644 index 00000000..1b75820e --- /dev/null +++ b/lua/plugin/fff.lua @@ -0,0 +1,90 @@ +local vim_pack = require('vim-pack') + +vim_pack.on_plugin_update('fff.nvim', function(data) + if not data.active then + vim.cmd.packadd('fff.nvim') + end + require('fff.download').download_or_build_binary() +end) + +vim_pack.add({ + { + src = 'dmtrKovalenko/fff.nvim', + ---@type FffConfig + ---@diagnostic disable: missing-fields + opts = { + layout = { + height = 0.9, + width = 0.9, + prompt_position = 'top', + preview_size = 0.6, + }, + preview = { + enabled = true, + line_numbers = true, + }, + debug = { + enabled = true, -- show the file info panel next to the preview + show_scores = true, + show_file_info = { + file_info = true, -- size, type, git status, frecency + score_breakdown = true, -- total + match type, bonuses, modifiers, penalty + -- modified + accessed timestamps; pass a table to hide individual rows: + -- timings = { modified = false, accessed = true } + timings = false, + full_path = true, -- relative path at the bottom (wraps if too long) + }, + }, + grep = { + max_matches_per_file = 0, -- 0 to unlimited + time_budget_ms = 100, -- prevents UI freeze, 0 = no limit + }, + keymaps = { + close = '', + select = '', + select_split = '', + select_vsplit = '', + select_tab = '', + -- you can assign multiple keys to any action + move_up = { '', '' }, + move_down = { '', '' }, + preview_scroll_up = '', + preview_scroll_down = '', + toggle_debug = '', + -- grep mode: cycle between plain text, regex, and fuzzy search + cycle_grep_modes = '', + grep_jump_to_next_file = { '' }, + grep_jump_to_prev_file = { '' }, + -- goes to the previous query in history + cycle_previous_query = '', + -- multi-select keymaps for quickfix + toggle_select = '', + send_to_quickfix = '', + -- this are specific for the normal mode (you can exit it using any other keybind like jj) + focus_list = 'l', + focus_preview = 'p', + }, + file_picker = { + current_file_label = '[Current File]', + }, + }, + on_setup = function() + local fff = require('fff') + + vim.keymap.set('n', 'ff', function() + fff.find_files() + end, { desc = '[FFF] Find Files' }) + vim.keymap.set('n', 'sp', function() + fff.live_grep() + end, { desc = '[FFF] Live grep' }) + vim.keymap.set('n', 'sd', function() + local word = vim.fn.expand('') + if word == '' then + word = vim.fn.expand('') + end + + fff.live_grep({ query = word }) + end, { desc = '[FFF] Search Current Word' }) + end, + }, +}) diff --git a/lua/plugin/fzf_lua.lua b/lua/plugin/fzf_lua.lua new file mode 100644 index 00000000..9aa7f96f --- /dev/null +++ b/lua/plugin/fzf_lua.lua @@ -0,0 +1,223 @@ +local add = require('vim-pack').add + +--- Run git from the repository (project or submodule) that owns `file`. +--- Starts from the parent dir so a submodule entry targets the superproject. +local function git_owner_exec(root, file, args) + local abs = file:sub(1, 1) == '/' and file or vim.fs.joinpath(root, file) + local dir = vim.fs.dirname(abs) + while not vim.uv.fs_stat(dir) do + dir = vim.fs.dirname(dir) + end + local cmd = vim.list_extend({ 'git', '-C', dir }, args) + table.insert(cmd, abs) + return vim.system(cmd, { text = true }):wait() +end + +--- Same as git_owner_exec, as a shell command for fzf previews ({file} is substituted by fzf-lua). +local function git_owner_preview(root, args) + return ( + [[cd %s && sh -c 'f=$(realpath -m -- "$1"); d=$(dirname -- "$f"); ]] + .. [[while [ ! -d "$d" ]; do d=$(dirname -- "$d"); done; git -C "$d" %s "$f"' _ {file}]] + ):format(vim.fn.shellescape(root), args) +end + +--- git status including the files changed inside (nested) submodules. +local function git_status_recursive() + local fzf_lua = require('fzf-lua') + local res = vim.system({ 'git', 'rev-parse', '--show-toplevel' }, { text = true }):wait() + if res.code ~= 0 then + return fzf_lua.utils.warn('not a git repository') + end + local root = vim.trim(res.stdout) + local status = '-c color.status=false --no-optional-locks status --porcelain=v1 -u --no-renames' + + -- submodule files are displayed as `[name] path/in/submodule`, + -- the path from the root is used instead when a name is not unique + local subs = vim.system( + { 'git', 'submodule', 'foreach', '--recursive', '--quiet', 'printf "%s\\t%s\\n" "$name" "$displaypath"' }, + { cwd = root, text = true } + ):wait() + local list, count, paths = {}, {}, {} + for name, path in (subs.stdout or ''):gmatch('([^\t\n]+)\t([^\n]+)') do + list[#list + 1] = { name = name, path = path } + count[name] = (count[name] or 0) + 1 + end + local cmds = { ('git -C %s %s'):format(vim.fn.shellescape(root), status) } + for _, sub in ipairs(list) do + local label = count[sub.name] == 1 and sub.name or sub.path + paths[label] = sub.path + cmds[#cmds + 1] = ('git -C %s %s | sed %s'):format( + vim.fn.shellescape(vim.fs.joinpath(root, sub.path)), + status, + vim.fn.shellescape(('s|^\\(...\\)|\\1[%s] |'):format(label:gsub('[\\&|]', '\\%0'))) + ) + end + + local function run(selected, opts, args, skip) + for _, s in ipairs(selected) do + if not (skip and skip(s)) then + local r = git_owner_exec(root, fzf_lua.path.entry_to_file(s, opts).path, args) + if r.code ~= 0 then + fzf_lua.utils.error(r.stderr) + end + end + end + end + + fzf_lua.git_status({ + prompt = 'Git Status (submodules)> ', + cwd = root, + _fmt = { + from = function(entry) + return ( + entry:gsub('%[([^%[%]]-)%] ', function(label) + return paths[label] and paths[label] .. '/' + end, 1) + ) + end, + }, + cmd = table.concat(cmds, '; '), + previewer = vim.tbl_extend('force', fzf_lua.config.globals.previewers.git_diff, { + cmd_modified = git_owner_preview(root, 'diff --color HEAD --'), + cmd_deleted = git_owner_preview(root, 'diff --color HEAD --'), + }), + actions = { + ['left'] = { + fn = function(selected, opts) + -- staging an already staged deletion errs, like fzf-lua's own git_stage + run(selected, opts, { 'add', '--' }, function(s) + return s:byte(1) == 68 + end) + end, + reload = true, + }, + ['right'] = { + fn = function(selected, opts) + run(selected, opts, { 'reset', '--' }) + end, + reload = true, + }, + ['ctrl-x'] = { + fn = function(selected, opts) + if fzf_lua.utils.confirm('Reset ' .. #selected .. ' file(s)?', '&Yes\n&No') ~= 1 then + return + end + for _, s in ipairs(selected) do + local file = fzf_lua.path.entry_to_file(s, opts).path + local tracked = git_owner_exec(root, file, { 'ls-files', '--error-unmatch', '--' }).code == 0 + run({ s }, opts, tracked and { 'checkout', 'HEAD', '--' } or { 'clean', '-f', '--' }) + end + vim.cmd('checktime') + end, + reload = true, + }, + }, + }) +end + +add({ + { src = 'nvim-mini/mini.icons', setup = false }, + { + src = 'ibhagwan/fzf-lua', + ---@type fun():fzf-lua.Config + opts = function() + local fzf_lua = require('fzf-lua') + + return { + 'skim', + defaults = { formatter = { 'path.dirname_first', v = 2 } }, + grep = { + fzf_opts = { ['--history'] = vim.fs.joinpath(vim.fn.stdpath('data'), 'fzf_search_hist') }, + }, + winopts = { + fullscreen = true, + }, + keymap = { + fzf = { + ['ctrl-u'] = 'half-page-up', + ['ctrl-d'] = 'half-page-down', + ['ctrl-x'] = 'jump', + ['ctrl-f'] = 'preview-page-down', + ['ctrl-b'] = 'preview-page-up', + ['ctrl-s down'] = 'preview-page-down', + ['ctrl-up'] = 'preview-page-up', + }, + builtin = { + [''] = 'preview-page-down', + [''] = 'preview-page-up', + }, + }, + -- buffers = { + -- formatter = 'path.filename_first', + -- }, + actions = { + files = { + ['enter'] = fzf_lua.actions.file_edit_or_qf, + ['ctrl-s'] = fzf_lua.actions.file_split, + ['ctrl-v'] = fzf_lua.actions.file_vsplit, + ['ctrl-t'] = fzf_lua.actions.file_tabedit, + ['alt-q'] = fzf_lua.actions.file_sel_to_qf, + ['alt-Q'] = fzf_lua.actions.file_sel_to_ll, + ['alt-i'] = fzf_lua.actions.toggle_ignore, + ['alt-h'] = fzf_lua.actions.toggle_hidden, + ['alt-f'] = fzf_lua.actions.toggle_follow, + -- Select all + send to quickfix (works with both fzf and skim, + -- unlike a hand-written `select-all+accept` bind in keymap.fzf). + ['ctrl-q'] = { fn = fzf_lua.actions.file_sel_to_qf, prefix = 'select-all' }, + }, + }, + helptags = { + actions = { + -- Open help pages in a vertical split. + ['enter'] = require('fzf-lua.actions').help_vert, + }, + }, + lsp = { + includeDeclaration = false, -- include current declaration in LSP context + symbols = { + -- lsp_query = "foo" -- query passed to the LSP directly + -- query = "bar" -- query passed to fzf prompt for fuzzy matching + locate = false, -- attempt to position cursor at current symbol + symbol_style = 1, -- symbols style. false: disable, 1: icon+kind, 2: icon only, 3: kind only + fzf_opts = { ['--tiebreak'] = 'begin' }, + }, + code_actions = { + previewer = vim.fn.executable('delta') == 1 and 'codeaction_native' or nil, + }, + finder = { + { 'skim' }, + providers = { + { 'definitions', prefix = fzf_lua.utils.ansi_codes.green('def ') }, + { 'declarations', prefix = fzf_lua.utils.ansi_codes.magenta('decl') }, + { 'implementations', prefix = fzf_lua.utils.ansi_codes.green('impl') }, + { 'typedefs', prefix = fzf_lua.utils.ansi_codes.red('tdef') }, + { 'references', prefix = fzf_lua.utils.ansi_codes.blue('ref ') }, + { 'incoming_calls', prefix = fzf_lua.utils.ansi_codes.cyan('in ') }, + { 'outgoing_calls', prefix = fzf_lua.utils.ansi_codes.yellow('out ') }, + { 'type_sub', prefix = fzf_lua.utils.ansi_codes.cyan('sub ') }, + { 'type_super', prefix = fzf_lua.utils.ansi_codes.yellow('supr') }, + }, + }, + }, + } + end, + on_setup = function() + local fzf_lua = require('fzf-lua') + + vim.keymap.set('n', 'F', ':FzfLua') + vim.keymap.set('n', 'gi', function() + fzf_lua.lsp_implementations() + end, { desc = 'List Implementation' }) + vim.keymap.set('n', 'gb', function() + fzf_lua.buffers({ cwd_only = true }) + end, { desc = 'Buffers (cwd)' }) + vim.keymap.set('n', 'gB', function() + fzf_lua.buffers({ cwd_only = false }) + end, { desc = 'Buffers (all)' }) + vim.keymap.set('n', 'ff', function() + fzf_lua.files() + end, { desc = 'Find Files' }) + vim.keymap.set('n', 'gS', git_status_recursive, { desc = 'Git Status + submodules' }) + end, + }, +}) diff --git a/lua/plugin/gitgraph.lua b/lua/plugin/gitgraph.lua new file mode 100644 index 00000000..4fc569aa --- /dev/null +++ b/lua/plugin/gitgraph.lua @@ -0,0 +1,64 @@ +local add = require('vim-pack').add + +add({ + { src = 'dlyongemallo/diffview-plus.nvim', setup = false }, + { + src = 'isakbm/gitgraph.nvim', + ---@module "gitgraph" + ---@type I.GGConfig + ---@diagnostic disable-next-line: missing-fields + opts = { + git_cmd = 'git', + symbols = { + merge_commit = '', + commit = '', + merge_commit_end = '', + commit_end = '', + + -- Advanced symbols + GVER = '', + GHOR = '', + GCLD = '', + GCRD = '╭', + GCLU = '', + GCRU = '', + GLRU = '', + GLRD = '', + GLUD = '', + GRUD = '', + GFORKU = '', + GFORKD = '', + GRUDCD = '', + GRUDCU = '', + GLUDCD = '', + GLUDCU = '', + GLRDCL = '', + GLRDCR = '', + GLRUCL = '', + GLRUCR = '', + }, + format = { + timestamp = '%H:%M:%S %d-%m-%Y', + fields = { 'hash', 'timestamp', 'author', 'branch_name', 'tag' }, + }, + hooks = { + -- Check diff of a commit + on_select_commit = function(commit) + vim.cmd(':DiffviewOpen ' .. commit.hash .. '^!') + vim.notify('DiffviewOpen ' .. commit.hash .. '^!') + end, + -- Check diff from commit a -> commit b + on_select_range_commit = function(from, to) + vim.cmd(':DiffviewOpen ' .. from.hash .. '~1..' .. to.hash) + vim.notify('DiffviewOpen ' .. from.hash .. '~1..' .. to.hash) + end, + }, + }, + on_setup = function() + vim.keymap.set('n', 'gl', function() + vim.cmd('tabnew') + require('gitgraph').draw({}, { all = true, max_count = 5000 }) + end, { desc = 'GitGraph - Draw' }) + end, + }, +}) diff --git a/lua/plugin/gitsigns.lua b/lua/plugin/gitsigns.lua new file mode 100644 index 00000000..9b89e30b --- /dev/null +++ b/lua/plugin/gitsigns.lua @@ -0,0 +1,81 @@ +local add_on_event = require('vim-pack').add_on_event + +add_on_event({ 'BufReadPost', 'BufNewFile', 'BufWritePre' }, { + { + src = 'lewis6991/gitsigns.nvim', + ---@diagnostic disable: missing-fields + ---@type Gitsigns.Config + opts = { + signs = { + add = { text = '▏' }, + change = { text = '▏' }, + delete = { text = '▏' }, + topdelete = { text = '▏' }, + changedelete = { text = '▏' }, + untracked = { text = '▏' }, + }, + signs_staged = { + add = { text = '▏' }, + change = { text = '▏' }, + delete = { text = '▏' }, + topdelete = { text = '▏' }, + changedelete = { text = '▏' }, + }, + current_line_blame = true, + attach_to_untracked = true, + preview_config = { + border = 'rounded', + style = 'minimal', + }, + current_line_blame_opts = { + virt_text = true, + virt_text_pos = 'eol', -- 'eol' | 'overlay' | 'right_align + delay = 999, + ignore_whitespace = false, + virt_text_priority = 99, + }, + gh = true, + on_attach = function(buffer) + local gs = require('gitsigns') + local icons = require('config.icons').git + local nav_hunk_opts = { preview = true, greedy = false, target = 'all' } + local center = function() + vim.cmd.normal({ 'zz', bang = true }) + end + local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { buf = buffer, desc = desc, silent = true }) + end + + map('n', 'hn', function() + if vim.wo.diff then + vim.cmd.normal({ ']c', bang = true }) + else + gs.nav_hunk('next', nav_hunk_opts) + end + center() + end, 'Next Hunk') + map('n', 'hN', function() + if vim.wo.diff then + vim.cmd.normal({ '[c', bang = true }) + else + gs.nav_hunk('prev', nav_hunk_opts) + end + center() + end, 'Prev Hunk') + map({ 'n', 'v' }, 'hs', ':Gitsigns stage_hunk', icons.git .. ' (Un)Stage Hunk') + map({ 'n', 'v' }, 'hr', ':Gitsigns reset_hunk', icons.git .. ' Reset Hunk') + map('n', 'hS', gs.stage_buffer, icons.git .. ' Stage/Unstage Buffer') + map('n', 'hR', gs.reset_buffer, icons.git .. ' Reset Buffer') + map('n', 'hp', gs.preview_hunk_inline, icons.git .. ' Preview Hunk Inline') + map('n', 'hb', function() + gs.blame_line({ full = true }) + end, icons.git .. ' Blame Line') + map('n', 'hB', function() + gs.blame() + end, icons.git .. ' Blame Buffer') + map('n', 'tb', gs.toggle_current_line_blame, icons.git .. ' Toogle Current Line Blame') + map({ 'o', 'x' }, 'ih', ':Gitsigns select_hunk', icons.git .. ' GitSigns Select Hunk') + end, + }, + }, +}) diff --git a/lua/plugin/gopher.lua b/lua/plugin/gopher.lua new file mode 100644 index 00000000..7a86cc51 --- /dev/null +++ b/lua/plugin/gopher.lua @@ -0,0 +1,10 @@ +local add_on_file_type = require('vim-pack').add_on_file_type + +add_on_file_type('go', { + { + src = 'olexsmir/gopher.nvim', + ---@module "gopher" + ---@type gopher.Config + opts = {}, + }, +}) diff --git a/lua/plugin/grug_far.lua b/lua/plugin/grug_far.lua new file mode 100644 index 00000000..dae14f31 --- /dev/null +++ b/lua/plugin/grug_far.lua @@ -0,0 +1,13 @@ +local add = require('vim-pack').add + +add({ + { + src = 'MagicDuck/grug-far.nvim', + opts = {}, + on_setup = function() + vim.keymap.set({ 'n', 'x' }, 'rs', function() + require('grug-far').open({ prefills = { search = vim.fn.expand('') } }) + end, { desc = ' Search and Replace' }) + end, + }, +}) diff --git a/lua/plugin/hexinspector.lua b/lua/plugin/hexinspector.lua new file mode 100644 index 00000000..5741d406 --- /dev/null +++ b/lua/plugin/hexinspector.lua @@ -0,0 +1,43 @@ +local add = require('vim-pack').add + +add({ + { + src = 'Punity122333/hexinspector.nvim', + opts = { + -- All options are optional. Shown below are the defaults. + -- bytes_per_line = 24, + -- max_undo = 200, + -- max_memory_file = 64 * 1024 * 1024, + -- colors = { + -- bg = "#1a1b26", + -- info_bg = "#1a1b26", + -- border = "#115e72", + -- addr = "#565f89", + -- hex = "#c0caf5", + -- ascii = "#9ece6a", + -- null = "#3b4261", + -- cursor_bg = "#28344a", + -- cursor_line_bg = "#1e2030", + -- float = "#ff9e64", + -- int = "#bb9af7", + -- uint = "#7dcfff", + -- title = "#7aa2f7", + -- search = "#f7768e", + -- modified = "#f7768e", + -- selection_bg = "#2d4f67", + -- }, + }, + on_setup = function() + vim.keymap.set('n', 'x', function() + require('hexinspector').open() + end, { desc = 'Hex Editor' }) + vim.keymap.set('n', 'X', function() + vim.ui.input({ prompt = 'File path: ', default = vim.fn.expand('%:p') }, function(input) + if input and input ~= '' then + require('hexinspector').open(input) + end + end) + end, { desc = 'Hex Editor (Pick File)' }) + end, + }, +}) diff --git a/lua/plugin/lazydev.lua b/lua/plugin/lazydev.lua new file mode 100644 index 00000000..8648b37c --- /dev/null +++ b/lua/plugin/lazydev.lua @@ -0,0 +1,15 @@ +local add_on_file_type = require('vim-pack').add_on_file_type + +-- The blink.cmp source is configured in lua/plugin/blink.lua. +add_on_file_type('lua', { + { + src = 'folke/lazydev.nvim', + opts = { + library = { + { path = 'snacks.nvim', words = { 'Snacks' } }, + { path = 'nvim-lspconfig', words = { 'lspconfig' } }, + { path = 'celeste_comment.nvim', words = { 'Celeste' } }, + }, + }, + }, +}) diff --git a/lua/plugin/lspconfig.lua b/lua/plugin/lspconfig.lua new file mode 100644 index 00000000..f03c7757 --- /dev/null +++ b/lua/plugin/lspconfig.lua @@ -0,0 +1,7 @@ +local add_on_event = require('vim-pack').add_on_event + +-- Only provides the lsp/ configs (servers are enabled in lua/config/lsp). +add_on_event({ 'BufReadPre', 'BufNewFile' }, { + { src = 'b0o/SchemaStore.nvim', setup = false }, + { src = 'neovim/nvim-lspconfig', setup = false }, +}) diff --git a/lua/plugin/lualine.lua b/lua/plugin/lualine.lua new file mode 100644 index 00000000..0effaa5a --- /dev/null +++ b/lua/plugin/lualine.lua @@ -0,0 +1,101 @@ +-- From BrendonJL/dotfiles +local add_on_event = require('vim-pack').add_on_event + +add_on_event('UIEnter', { + { + src = 'nvim-lualine/lualine.nvim', + opts = function() + local opts = {} + + -- Custom components + local icons = require('config.icons') + + opts.options = opts.options or {} + opts.options.component_separators = { left = '│', right = '│' } + opts.options.section_separators = { left = '', right = '' } + opts.options.globalstatus = false -- default + opts.options.refresh = { + statusline = 200, + refresh_time = 16, -- ~60fps + events = { + 'WinEnter', + 'BufEnter', + 'BufWritePost', + 'SessionLoadPost', + 'FileChangedShellPost', + 'VimResized', + 'Filetype', + 'CursorMoved', + 'CursorMovedI', + 'ModeChanged', + }, + } + + -- Left sections + opts.sections = opts.sections or {} + opts.sections.lualine_a = {} + opts.sections.lualine_b = { + { + 'branch', + icon = icons.git.git, + padding = { left = 1, right = 1 }, + }, + { + 'diff', + symbols = { + added = icons.git.added, + modified = icons.git.modified, + removed = icons.git.removed, + }, + padding = { left = 1, right = 1 }, + }, + } + opts.sections.lualine_c = { + { + 'diagnostics', + symbols = { + error = icons.diagnostics.Error, + warn = icons.diagnostics.Warn, + info = icons.diagnostics.Info, + hint = icons.diagnostics.Hint, + }, + }, + { + 'filename', + path = 1, + symbols = { + modified = ' ', + readonly = '[Readonly]', + unnamed = '[No Name]', + }, + }, + } + + -- Right sections + opts.sections.lualine_x = { + { + 'lsp_status', + icon = '󰒋 ', + symbols = { + spinner = require('config.icons').spinner.circle, + done = '✓', + separator = ' ', + }, + ignore_lsp = {}, + show_name = true, + always_visible = false, + }, + } + + opts.sections.lualine_y = {} + opts.sections.lualine_z = { + { + 'location', + padding = { left = 1, right = 1 }, + }, + } + + return opts + end, + }, +}) diff --git a/lua/plugin/mini.lua b/lua/plugin/mini.lua new file mode 100644 index 00000000..ec3b7231 --- /dev/null +++ b/lua/plugin/mini.lua @@ -0,0 +1,5 @@ +local add = require('vim-pack').add + +add({ + { src = 'nvim-mini/mini.icons', opts = {} }, +}) diff --git a/lua/plugin/neogit.lua b/lua/plugin/neogit.lua new file mode 100644 index 00000000..1cd0d66b --- /dev/null +++ b/lua/plugin/neogit.lua @@ -0,0 +1,36 @@ +local add = require('vim-pack').add + +add({ + { src = 'nvim-lua/plenary.nvim', setup = false }, + { src = 'dlyongemallo/diffview-plus.nvim', setup = false }, + { + src = 'NeogitOrg/neogit', + opts = { + graph_style = 'kitty', + -- Each Integration is auto-detected through plugin presence, however, it can be disabled by setting to `false` + integrations = { + codediff = false, + telescope = false, + fzf_lua = true, + mini_pick = false, + diffview = true, + snacks = true, + }, + diff_viewer = 'diffview', + sections = { + recent = { + folded = false, + }, + }, + signs = { + -- { CLOSED, OPENED } + hunk = { '', '' }, + item = { '', '' }, + section = { '', '' }, + }, + }, + on_setup = function() + vim.keymap.set('n', 'gg', ':Neogit', { desc = 'Open Neogit' }) + end, + }, +}) diff --git a/lua/plugin/neotest.lua b/lua/plugin/neotest.lua new file mode 100644 index 00000000..131b1dfc --- /dev/null +++ b/lua/plugin/neotest.lua @@ -0,0 +1,18 @@ +local add_on_file_type = require('vim-pack').add_on_file_type + +-- Was never loaded with lazy.nvim (no trigger), now loaded with the only adapter's filetype. +add_on_file_type('php', { + { src = 'nvim-lua/plenary.nvim', setup = false }, + { src = 'nvim-neotest/nvim-nio', setup = false }, + { src = 'olimorris/neotest-phpunit', setup = false }, + { + src = 'nvim-neotest/neotest', + opts = { + adapters = { + ['neotest-phpunit'] = { + root_ignore_files = { 'tests/Pest.php' }, + }, + }, + }, + }, +}) diff --git a/lua/plugin/nvim-lint.lua b/lua/plugin/nvim-lint.lua new file mode 100644 index 00000000..8f187a06 --- /dev/null +++ b/lua/plugin/nvim-lint.lua @@ -0,0 +1,166 @@ +---@diagnostic disable: need-check-nil +local add_on_event = require('vim-pack').add_on_event + +local opts = { + events = { 'BufWritePost', 'BufReadPost', 'InsertLeave' }, + linters_by_ft = { + gitcommit = { 'gitlint' }, + php = { 'php' }, + python = { 'ruff' }, + zig = { 'zlint' }, + }, + linters = {}, +} + +add_on_event({ 'BufReadPre', 'BufNewFile' }, { + { + src = 'mfussenegger/nvim-lint', + module_name = 'lint', + on_setup = function() + local lint = require('lint') + local M = {} + + function M.debounce(ms, fn) + local timer = vim.uv.new_timer() + + return function(...) + local argv = { ... } + + timer:start(ms, 0, function() + timer:stop() + vim.schedule_wrap(fn)(unpack(argv)) + end) + end + end + + do + local native_phpcs = lint.linters.phpcs + + if native_phpcs then + local phpcs = vim.deepcopy(native_phpcs) + + phpcs.cmd = function() + local filename = vim.api.nvim_buf_get_name(0) + local dirname = vim.fs.dirname(filename) + + local local_phpcs = vim.fs.find('vendor/bin/phpcs', { + upward = true, + path = dirname, + type = 'file', + })[1] + + if local_phpcs then + return local_phpcs + end + + return 'phpcs' + end + + phpcs.args = { + '-q', + '--report=json', + + function() + local filename = vim.api.nvim_buf_get_name(0) + + return '--stdin-path=' .. vim.fn.fnamemodify(filename, ':p:.') + end, + + function() + local filename = vim.api.nvim_buf_get_name(0) + local dirname = vim.fs.dirname(filename) + + local config = vim.fs.find({ + 'phpcs.xml', + 'phpcs.xml.dist', + '.phpcs.xml', + '.phpcs.xml.dist', + }, { + upward = true, + path = dirname, + type = 'file', + })[1] + + if config then + return '--standard=' .. config + end + + return '--standard=PSR12' + end, + + '-', + } + + lint.linters.phpcs = phpcs + end + end + + for name, linter in pairs(opts.linters) do + if name ~= 'phpcs' then + if type(linter) == 'table' and type(lint.linters[name]) == 'table' then + lint.linters[name] = vim.tbl_deep_extend('force', lint.linters[name], linter) + + if type(linter.prepend_args) == 'table' then + lint.linters[name].args = lint.linters[name].args or {} + + vim.list_extend(lint.linters[name].args, linter.prepend_args) + end + else + lint.linters[name] = linter + end + end + end + + lint.linters_by_ft = opts.linters_by_ft + + function M.lint() + -- Use nvim-lint's logic first: + -- * checks if linters exist for the full filetype first + -- * otherwise will split filetype by "." and add all those linters + -- * this differs from conform.nvim which only uses the first + -- filetype that has a formatter + local names = lint._resolve_linter_by_ft(vim.bo.filetype) + + -- Create a copy of the names table to avoid modifying the original. + names = vim.list_extend({}, names) + + -- Add fallback linters. + if #names == 0 then + vim.list_extend(names, lint.linters_by_ft['_'] or {}) + end + + -- Add global linters. + vim.list_extend(names, lint.linters_by_ft['*'] or {}) + + -- Filter out linters that don't exist or don't match the condition. + local ctx = { + filename = vim.api.nvim_buf_get_name(0), + } + + ctx.dirname = vim.fn.fnamemodify(ctx.filename, ':h') + + names = vim.tbl_filter(function(name) + local linter = lint.linters[name] + + if not linter then + vim.notify('Linter not found: ' .. name, { title = 'nvim-lint' }) + end + + return linter and not (type(linter) == 'table' and linter.condition and not linter.condition(ctx)) + end, names) + + -- Run linters. + if #names > 0 then + lint.try_lint(names) + end + end + + vim.api.nvim_create_autocmd(opts.events, { + group = vim.api.nvim_create_augroup('nvim-lint', { + clear = true, + }), + callback = M.debounce(100, M.lint), + }) + end, + }, +}) diff --git a/lua/plugin/nvim_rip_substitue.lua b/lua/plugin/nvim_rip_substitue.lua new file mode 100644 index 00000000..e56ffead --- /dev/null +++ b/lua/plugin/nvim_rip_substitue.lua @@ -0,0 +1,29 @@ +local add = require('vim-pack').add + +add({ + { + src = 'chrisgrieser/nvim-rip-substitute', + module_name = 'rip-substitute', + opts = { + keymaps = { -- normal mode (if not stated otherwise) + abort = 'q', + confirmAndSubstituteInBuffer = '', + insertModeConfirmAndSubstituteInBuffer = '', + prevSubstitutionInHistory = '', + nextSubstitutionInHistory = '', + toggleFixedStrings = '', -- ripgrep's `--fixed-strings` + toggleIgnoreCase = '', -- ripgrep's `--ignore-case` + openAtRegex101 = 'R', + showHelp = '?', + }, + }, + on_setup = function() + vim.keymap.set({ 'n', 'x' }, 'fs', function() + require('rip-substitute').sub() + end, { desc = ' rip substitute' }) + vim.keymap.set('v', 'fs', function() + require('rip-substitute').sub() + end, { desc = ' rip substitute selected range' }) + end, + }, +}) diff --git a/lua/plugin/outline.lua b/lua/plugin/outline.lua new file mode 100644 index 00000000..2ef6c703 --- /dev/null +++ b/lua/plugin/outline.lua @@ -0,0 +1,19 @@ +local add = require('vim-pack').add + +add({ + { + src = 'hedyhli/outline.nvim', + ---@module "outline" + ---@type outline.SetupOpts + opts = { + outline_window = { + center_on_jump = true, + relative_width = true, + show_cursorline = true, + }, + }, + on_setup = function() + vim.keymap.set('n', 'o', ':Outline', { desc = 'Outline' }) + end, + }, +}) diff --git a/lua/plugin/rest.lua b/lua/plugin/rest.lua new file mode 100644 index 00000000..4aa562f2 --- /dev/null +++ b/lua/plugin/rest.lua @@ -0,0 +1,6 @@ +local add_on_file_type = require('vim-pack').add_on_file_type + +-- Configured through vim.g.rest_nvim, the `http` treesitter parser is installed in lua/plugin/treesitter.lua. +add_on_file_type('http', { + { src = 'rest-nvim/rest.nvim', setup = false }, +}) diff --git a/lua/plugin/rustaceanvim.lua b/lua/plugin/rustaceanvim.lua new file mode 100644 index 00000000..25f8c3b4 --- /dev/null +++ b/lua/plugin/rustaceanvim.lua @@ -0,0 +1,30 @@ +local add = require('vim-pack').add + +-- Must be set before the plugin is loaded (rustaceanvim is not meant to be lazy-loaded). +vim.g.rustaceanvim = { + server = { + settings = { + ---@type lspconfig.settings.rust_analyzer + ['rust-analyzer'] = { + cargo = { + allFeatures = true, + loadOutDirsFromCheck = true, + runBuildScripts = true, + }, + checkOnSave = true, + procMacro = { + enable = true, + ignored = { + ['async-trait'] = { 'async_trait' }, + ['napi-derive'] = { 'napi' }, + ['async-recursion'] = { 'async_recursion' }, + }, + }, + }, + }, + }, +} + +add({ + { src = 'mrcjkb/rustaceanvim', version = vim.version.range('^9'), setup = false }, +}) diff --git a/lua/plugin/snacks.lua b/lua/plugin/snacks.lua new file mode 100644 index 00000000..4193d92a --- /dev/null +++ b/lua/plugin/snacks.lua @@ -0,0 +1,118 @@ +local add = require('vim-pack').add + +add({ + { + src = 'folke/snacks.nvim', + ---@type snacks.Config + opts = { + animate = { enabled = false }, + bigfile = { enabled = true }, + dashboard = { enabled = false }, + image = { enabled = true }, + indent = { enabled = false }, + input = { enabled = false }, + lazygit = { enabled = false }, + notifier = { enabled = true }, + quickfile = { enabled = true }, + scroll = { enabled = false }, + statuscolumn = { enabled = true }, + scope = { enabled = false }, -- already handled blink indent + picker = { + layout = { fullscreen = true }, + previewers = { diff = { builtin = false }, git = { builtin = false } }, + sources = { files = { hidden = true }, grep = { hidden = true } }, + }, + }, + on_setup = function() + -- Setup some globals for debugging + _G.dd = function(...) + Snacks.debug.inspect(...) + end + _G.bt = function() + Snacks.debug.backtrace() + end + vim.print = _G.dd -- Override print to use snacks for `:=` command + + -- Create some toggle mappings + Snacks.toggle.option('spell', { name = 'Spelling' }):map('us') + Snacks.toggle.option('wrap', { name = 'Wrap' }):map('uw') + Snacks.toggle.option('relativenumber', { name = 'Relative Number' }):map('uL') + Snacks.toggle.diagnostics():map('ud') + Snacks.toggle.line_number():map('ul') + Snacks.toggle.treesitter():map('T') + Snacks.toggle + .option('background', { off = 'light', on = 'dark', name = 'Dark Background' }) + :map('ub') + Snacks.toggle.inlay_hints():map('P') + -- Indent guides are drawn by blink.indent, not Snacks + Snacks.toggle + .new({ + name = 'Indent Guides', + get = function() + return require('blink.indent').is_enabled() + end, + set = function(state) + require('blink.indent').enable(state) + end, + }) + :map('ug') + Snacks.toggle.dim():map('uD') + + -- stylua: ignore start + -- LSP + vim.keymap.set('n', 's', function() Snacks.picker.lsp_symbols() end, { desc = 'List Symbols' }) + + -- search pickers + vim.keymap.set('n', 'sd', function() Snacks.picker.grep_word() end, { desc = 'Search current word' }) + vim.keymap.set('n', 'sD', function() Snacks.picker.grep_word({ hidden = true, ignored = true, }) end, { desc = 'Search current word' }) + vim.keymap.set('n', 'sp', function() Snacks.picker.grep() end, { desc = 'Grep' }) + vim.keymap.set('n', 'sP', function() Snacks.picker.grep({ hidden = true, ignored = true }) end, { desc = 'git grep' }) + vim.keymap.set('n', 'ff', function() Snacks.picker.files() end, { desc = 'List Files' }) + vim.keymap.set('n', 'fF', function() Snacks.picker.files({ hidden = true, ignored = true }) end, { desc = 'List Files' }) + vim.keymap.set('n', 'fr', function() Snacks.picker.recent() end, { desc = 'List Recent Files' }) + vim.keymap.set('n', 'S', function() Snacks.picker.smart({ multi = { 'recent', 'files' } }) end, { desc = 'Smart Picker' }) + + -- buffer / marks / registers /mappings + vim.keymap.set('n', 'gj', function() Snacks.picker.jumps() end, { desc = 'List Jumps' }) + vim.keymap.set('n', 'gm', function() Snacks.picker.marks() end, { desc = 'List Marks' }) + vim.keymap.set('n', 'gr', function() Snacks.picker.registers() end, { desc = 'List Registers' }) + vim.keymap.set('n', 'k', function() Snacks.picker.keymaps() end, { desc = 'List mappings' }) + + -- zen + vim.keymap.set('n', 'z', function() Snacks.zen() end, { desc = 'Toggle Zen Mode' }) + vim.keymap.set('n', 'Z', function() Snacks.zen.zoom() end, { desc = 'Toggle Zoom' }) + + vim.keymap.set('n', 'bd', function() Snacks.bufdelete() end, { desc = 'Delete Buffer' }) + vim.keymap.set('n', 'cR', function() Snacks.rename.rename_file() end, { desc = 'Rename File' }) + + -- git + vim.keymap.set('n', 'gs', function() Snacks.picker.git_status() end, { desc = 'Git Status' }) + vim.keymap.set('n', 'gb', function() Snacks.picker.git_branches() end, { desc = 'Git Branches' }) + vim.keymap.set('n', 'gl', function() Snacks.picker.git_log() end, { desc = 'git log' }) + vim.keymap.set('n', 'gL', function() Snacks.picker.git_log_line() end, { desc = 'git log line' }) + vim.keymap.set('n', 'gF', function() Snacks.picker.git_log_file() end, { desc = 'git log file' }) + vim.keymap.set('n', 'gB', function() Snacks.gitbrowse() end, { desc = 'Git Browse' }) + + -- scratch + vim.keymap.set('n', '.', function() Snacks.scratch() end, { desc = 'Toggle Scratch Buffer' }) + vim.keymap.set('n', 'S', function() Snacks.scratch.select() end, { desc = 'Select Scratch Buffer' }) + vim.keymap.set('n', 'dps', function() Snacks.profiler.scratch() end, { desc = 'Profiler Scratch Buffer' }) + + -- notifier + vim.keymap.set('n', 'n', function() Snacks.notifier.show_history() end, { desc = 'Notification History' }) + vim.keymap.set('n', 'un', function() Snacks.notifier.hide() end, { desc = 'Dismiss All Notifications' }) + + vim.keymap.set('n', 'sa', function() + Snacks.picker.grep({ + search = vim.fn.expand(''), + args = { + '--fixed-strings', + '--glob', + '*lock.json', + }, + }) + end, { desc = 'Search current word' }) + -- stylua: ignore end + end, + }, +}) diff --git a/lua/plugin/surround.lua b/lua/plugin/surround.lua new file mode 100644 index 00000000..c5904b33 --- /dev/null +++ b/lua/plugin/surround.lua @@ -0,0 +1,5 @@ +local add_on_event = require('vim-pack').add_on_event + +add_on_event('UIEnter', { + { src = 'kylechui/nvim-surround' }, +}) diff --git a/lua/plugin/treesitter.lua b/lua/plugin/treesitter.lua new file mode 100644 index 00000000..8f07e05e --- /dev/null +++ b/lua/plugin/treesitter.lua @@ -0,0 +1,91 @@ +-- https://github.com/nvim-treesitter/nvim-treesitter-context +-- +-- To recompile everything, delete all from these 2 directories: +-- * ~/.local/share/nvim/site/parser/ +-- * ~/.local/share/nvim/site/queries/ +-- +-- Additional Refs: +-- * https://github.com/ThorstenRhau/neovim/blob/main/lua/optional/treesitter.lua + +local vim_pack = require('vim-pack') + +vim_pack.on_plugin_update('nvim-treesitter', function(data) + if not data.active then + vim.cmd.packadd('nvim-treesitter') + end + vim.cmd('TSUpdate') +end) + +vim_pack.add_on_event({ 'BufReadPost', 'BufNewFile' }, { + { + src = 'nvim-treesitter/nvim-treesitter', + version = 'main', + setup = false, + on_setup = function() + local languages = { + 'awk', + 'bash', + 'c', + 'cmake', + 'css', + 'diff', + 'dockerfile', + 'dot', + 'gitattributes', + 'gitcommit', + 'gitignore', + 'git_config', + 'go', + 'html', + 'http', + 'java', + 'javascript', + 'jq', + 'jsdoc', + 'json', + 'lua', + 'make', + 'markdown', + 'markdown_inline', + 'perl', + 'php', + 'phpdoc', + 'php_only', + 'python', + 'query', + 'regex', + 'ron', + 'ruby', + 'rust', + 'scss', + 'solidity', + 'sql', + 'styled', + 'svelte', + 'toml', + 'tsx', + 'twig', + 'typescript', + 'vim', + 'vimdoc', + 'vue', + 'xml', + 'yaml', + 'zig', + } + + -- Async: already installed parsers are skipped, missing ones are installed in background + require('nvim-treesitter').install(languages, { max_jobs = 8 }) + + -- Folding is handled in config/folding.lua + vim.api.nvim_create_autocmd('FileType', { + group = vim.api.nvim_create_augroup('TreesitterSetup', { clear = true }), + callback = function(args) + local buf = args.buf + local lang = vim.treesitter.language.get_lang(vim.bo[buf].filetype) or vim.bo[buf].filetype + pcall(vim.treesitter.start, buf, lang) + end, + }) + end, + }, +}) diff --git a/lua/plugin/ts-context.lua b/lua/plugin/ts-context.lua new file mode 100644 index 00000000..c20b8a50 --- /dev/null +++ b/lua/plugin/ts-context.lua @@ -0,0 +1,20 @@ +local add_on_event = require('vim-pack').add_on_event + +add_on_event({ 'BufReadPost', 'BufNewFile' }, { + { + src = 'nvim-treesitter/nvim-treesitter-context', + module_name = 'treesitter-context', + ---@module "treesitter-context" + ---@type TSContext.Config + ---@diagnostic disable-next-line: missing-fields + opts = { + max_lines = 4, + multiline_threshold = 2, + }, + on_setup = function() + vim.keymap.set('n', '[x', function() + require('treesitter-context').go_to_context(vim.v.count1) + end, { desc = 'TS: go to context' }) + end, + }, +}) diff --git a/lua/plugin/ts-textobject.lua b/lua/plugin/ts-textobject.lua new file mode 100644 index 00000000..a5a31c0b --- /dev/null +++ b/lua/plugin/ts-textobject.lua @@ -0,0 +1,14 @@ +local add_on_event = require('vim-pack').add_on_event + +-- Must be set before the plugin is loaded. +vim.g.no_plugin_maps = true + +add_on_event({ 'BufReadPre', 'BufNewFile' }, { + { + src = 'nvim-treesitter/nvim-treesitter-textobjects', + version = 'main', + on_setup = function() + require('config.textobjects_keymaps').setup() + end, + }, +}) diff --git a/lua/plugin/typr.lua b/lua/plugin/typr.lua new file mode 100644 index 00000000..1aec8b28 --- /dev/null +++ b/lua/plugin/typr.lua @@ -0,0 +1,6 @@ +local add = require('vim-pack').add + +add({ + { src = 'nvzone/volt', setup = false }, + { src = 'nvzone/typr', opts = {} }, +}) diff --git a/lua/plugin/yazi.lua b/lua/plugin/yazi.lua new file mode 100644 index 00000000..191aab76 --- /dev/null +++ b/lua/plugin/yazi.lua @@ -0,0 +1,34 @@ +local add = require('vim-pack').add + +add({ + { src = 'nvim-lua/plenary.nvim', setup = false }, + { + src = 'mikavilpas/yazi.nvim', + ---@module 'yazi' + ---@type YaziConfig + opts = { + -- if you want to open yazi instead of netrw, see below for more info + open_for_directories = true, + integrations = { + bufdelete_implementation = 'bundled-snacks', + grep_in_directory = 'fzf-lua', + }, + keymaps = { + show_help = '', + open_file_in_vertical_split = '', + open_file_in_horizontal_split = '', + open_file_in_tab = '', + grep_in_directory = '', + cycle_open_buffers = '', + copy_relative_path_to_selected_files = '', + send_to_quickfix_list = '', + change_working_directory = '', + open_and_pick_window = '', + }, + }, + on_setup = function() + vim.keymap.set('n', '-', 'Yazi', { desc = 'Open yazi at the current file' }) + vim.keymap.set({ 'n', 'v' }, 'e', 'Yazi', { desc = 'Open yazi at the current file' }) + end, + }, +}) diff --git a/lua/vim-pack.lua b/lua/vim-pack.lua index ab5e9caa..9e72f6f5 100644 --- a/lua/vim-pack.lua +++ b/lua/vim-pack.lua @@ -2,6 +2,8 @@ local M = {} ---@class PluginSpec ---@field src string The GitHub repository of the plugin +---@field name? string Optional plugin directory name (defaults to the repo name) +---@field version? string|vim.VersionRange Optional branch, tag, commit or version range ---@field module_name? string Optional module name for configuration (defaults to the repo name) ---@field opts? table|fun():table Optional configuration options for the plugin ---@field on_setup? fun():nil Optional function to run after the plugin is loaded and configured @@ -12,7 +14,11 @@ local function configure(plugins) local sources = vim.iter(plugins) :map(function(plugin) -- Ensure we use GitHub urls. - return string.format('https://github.com/%s', plugin.src) + return { + src = string.format('https://github.com/%s', plugin.src), + name = plugin.name, + version = plugin.version, + } end) :totable() @@ -74,15 +80,15 @@ end --- Runs the given command inside the plugin's directory when the plugin is updated. --- ---@param plugin_name string Plugin name ----@param cmd string|fun():nil Command to run +---@param cmd string|string[]|fun(data: table):nil Command to run (a function receives the PackChanged event data) function M.on_plugin_update(plugin_name, cmd) vim.api.nvim_create_autocmd('PackChanged', { callback = function(args) if args.data.spec.name == plugin_name and (args.data.kind == 'install' or args.data.kind == 'update') then - if type(cmd) == 'string' then - vim.system({ cmd }, { cwd = args.data.path }) + if type(cmd) == 'function' then + cmd(args.data) else - cmd() + vim.system(type(cmd) == 'string' and { cmd } or cmd, { cwd = args.data.path }) end end end, From 96ed500305eff369dd5c158d0418b76e2953b201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Pluchart?= Date: Wed, 7 Oct 2026 14:22:12 +0200 Subject: [PATCH 06/12] feat(lsp): replace lazy with vim.pack in emmylua --- after/lsp/emmylua_ls.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/after/lsp/emmylua_ls.lua b/after/lsp/emmylua_ls.lua index 0f805f5b..dd264a9e 100644 --- a/after/lsp/emmylua_ls.lua +++ b/after/lsp/emmylua_ls.lua @@ -21,7 +21,7 @@ return { workspace = { library = { '$VIMRUNTIME', - '$HOME/.local/share/nvim/lazy', + '$HOME/.local/share/nvim/site/pack/core/opt', }, ignoreGlobs = { '**/*_spec.lua' }, }, From edbbb14eba384c21b76a563b02858b87bc29c32b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Pluchart?= Date: Wed, 7 Oct 2026 14:23:00 +0200 Subject: [PATCH 07/12] feat(keymaps): replace User/VeryLazy event with VimEnter --- lua/config/autocommands.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/config/autocommands.lua b/lua/config/autocommands.lua index 9cd69a95..b17f0459 100644 --- a/lua/config/autocommands.lua +++ b/lua/config/autocommands.lua @@ -72,8 +72,7 @@ vim.api.nvim_create_autocmd('TextYankPost', { end, }) -vim.api.nvim_create_autocmd('User', { - pattern = 'VeryLazy', +vim.api.nvim_create_autocmd('VimEnter', { callback = function() if vim.fn.argc() > 0 or vim.env.NVIM_SKIP_SESSION then return From a51778264d2229d0ab53c42bcde512d9f0078eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Pluchart?= Date: Wed, 7 Oct 2026 14:23:35 +0200 Subject: [PATCH 08/12] feat(keymaps): use pack.update() instead of Lazy --- lua/config/keymaps.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua index ae61f1c2..09bfcad3 100644 --- a/lua/config/keymaps.lua +++ b/lua/config/keymaps.lua @@ -34,8 +34,10 @@ u.map('n', 'FF', '!docker compose exec php php-cs-fixer fix %') u.map('n', 'gh', ':diffget //3') u.map('n', 'gu', ':diffget //2') --- Lazy UI -u.map('n', 'L', 'Lazy') +-- Plugins update (vim.pack) +u.map('n', 'L', function() + vim.pack.update() +end) --- Sessions if vim.g.sessions_enabled then From bf34670c409f20677536d6a7a5b7173322754c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Pluchart?= Date: Wed, 7 Oct 2026 14:24:36 +0200 Subject: [PATCH 09/12] fix(conform): add_on_event events --- lua/plugin/conform.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/plugin/conform.lua b/lua/plugin/conform.lua index 80269667..76c8b0a8 100644 --- a/lua/plugin/conform.lua +++ b/lua/plugin/conform.lua @@ -1,6 +1,7 @@ local add_on_event = require('vim-pack').add_on_event -add_on_event('BufWritePre', { +-- Loaded before the first write: an autocmd created during BufWritePre would not run for that write. +add_on_event({ 'BufReadPre', 'BufNewFile' }, { { src = 'stevearc/conform.nvim', opts = { From 0bc03fd989692225fcaeb41be9df08fdb7ab77b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Pluchart?= Date: Wed, 7 Oct 2026 14:25:02 +0200 Subject: [PATCH 10/12] feat: remove lazy from init --- init.lua | 63 +++++++++++++++++--------------------------------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/init.lua b/init.lua index 208facdd..04f7dd83 100644 --- a/init.lua +++ b/init.lua @@ -1,3 +1,5 @@ +vim.loader.enable() + _G.global = {} _G.global.float_border_opts = { border = 'rounded', focusable = false, scope = 'line' } @@ -5,51 +7,24 @@ vim.g.mapleader = ',' vim.g.maplocalleader = ',' vim.g.sessions_enabled = true -local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim' -if not vim.uv.fs_stat(lazypath) then - vim.fn.system({ - 'git', - 'clone', - '--filter=blob:none', - '--single-branch', - 'https://github.com/folke/lazy.nvim.git', - lazypath, - }) +-- Disable some builtin plugins (was handled by lazy.nvim's performance.rtp.disabled_plugins). +for _, plugin in ipairs({ 'gzip', 'tarPlugin', 'tohtml', 'zipPlugin', 'netrwPlugin', 'matchit', 'matchparen', 'tutor' }) do + vim.g['loaded_' .. plugin] = 1 +end +vim.g.loaded_netrw = 1 + +-- Load every plugin spec from lua/plugin/, in alphabetical order. +local plugin_dir = vim.fs.joinpath(vim.fn.stdpath('config'), 'lua', 'plugin') +local plugin_files = {} +for name, type in vim.fs.dir(plugin_dir) do + if type == 'file' and name:match('%.lua$') then + plugin_files[#plugin_files + 1] = name:gsub('%.lua$', '') + end +end +table.sort(plugin_files) +for _, name in ipairs(plugin_files) do + require('plugin.' .. name) end -vim.opt.runtimepath:prepend(lazypath) - -require('lazy').setup({ - performance = { - cache = { - enabled = true, - }, - rtp = { - disabled_plugins = { - 'gzip', - 'tarPlugin', - 'tohtml', - 'zipPlugin', - 'netrwPlugin', - 'matchit', - 'matchparen', - 'tutor', - }, - }, - }, - spec = { - { import = 'plugins' }, - }, - defaults = { - lazy = true, - version = false, - }, - install = { - missing = true, - colorscheme = { 'catppuccin' }, - }, - checker = { enabled = false }, - rocks = { enabled = false }, -}) vim.cmd.colorscheme('catppuccin-mocha') From 97d1d86c4b83edeb5a621d0a6949d25e215ec960 Mon Sep 17 00:00:00 2001 From: n3wborn Date: Wed, 7 Oct 2026 20:34:57 +0200 Subject: [PATCH 11/12] fix: fff vim.pack config --- lua/plugin/fff.lua | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lua/plugin/fff.lua b/lua/plugin/fff.lua index 1b75820e..df224f49 100644 --- a/lua/plugin/fff.lua +++ b/lua/plugin/fff.lua @@ -1,17 +1,8 @@ -local vim_pack = require('vim-pack') +local add = require('vim-pack').add -vim_pack.on_plugin_update('fff.nvim', function(data) - if not data.active then - vim.cmd.packadd('fff.nvim') - end - require('fff.download').download_or_build_binary() -end) - -vim_pack.add({ +add({ { - src = 'dmtrKovalenko/fff.nvim', - ---@type FffConfig - ---@diagnostic disable: missing-fields + src = 'dmtrKovalenko/fff', opts = { layout = { height = 0.9, @@ -70,7 +61,6 @@ vim_pack.add({ }, on_setup = function() local fff = require('fff') - vim.keymap.set('n', 'ff', function() fff.find_files() end, { desc = '[FFF] Find Files' }) @@ -88,3 +78,15 @@ vim_pack.add({ end, }, }) + +vim.api.nvim_create_autocmd('PackChanged', { + callback = function(ev) + local name, kind = ev.data.spec.name, ev.data.kind + if name == 'fff' and (kind == 'install' or kind == 'update') then + if not ev.data.active then + vim.cmd.packadd('fff') + end + require('fff.download').download_or_build_binary() + end + end, +}) From be8efb8255dc49b3b44146c78a505c563a04ef4c Mon Sep 17 00:00:00 2001 From: n3wborn Date: Thu, 22 Oct 2026 23:37:15 +0200 Subject: [PATCH 12/12] refactor: treesitter, remove ts-textobject --- lua/config/textobjects_keymaps.lua | 147 ---------------------- lua/plugin/treesitter.lua | 194 ++++++++++++++++++----------- lua/plugin/ts-context.lua | 20 --- lua/plugin/ts-textobject.lua | 14 --- 4 files changed, 123 insertions(+), 252 deletions(-) delete mode 100644 lua/config/textobjects_keymaps.lua delete mode 100644 lua/plugin/ts-context.lua delete mode 100644 lua/plugin/ts-textobject.lua diff --git a/lua/config/textobjects_keymaps.lua b/lua/config/textobjects_keymaps.lua deleted file mode 100644 index 0e86b9af..00000000 --- a/lua/config/textobjects_keymaps.lua +++ /dev/null @@ -1,147 +0,0 @@ --- https://github.com/saikocat/dotfiles/blob/master/neovim/.config/nvim/lua/plugins/code/treesitter_textobjects_keymaps.lua -local M = {} -local u = require('utils') - -function M.setup() - local map = function(modes, lhs, rhs, opts) - opts = vim.tbl_extend('force', { silent = true, noremap = true }, opts or {}) - vim.keymap.set(modes, lhs, rhs, opts) - end - - -- Require once (assumes this runs after the plugin is loaded) - local select = require('nvim-treesitter-textobjects.select') - local move = require('nvim-treesitter-textobjects.move') - local rep = require('nvim-treesitter-textobjects.repeatable_move') - - -- Factories (return a function for vim.keymap.set) - local sel = function(capture, group) - return function() - select.select_textobject(capture, group or 'textobjects') - end - end - - local mv = function(method, capture, group) - return u.center(function() - move[method](capture, group or 'textobjects') - end) - end - - local mv_any = function(method, captures, group) - return u.center(function() - move[method](captures, group or 'textobjects') - end) - end - - -- Keep the native motion (e.g. ]c / [c: next/prev change) in diff mode - local diff_or = function(native, fn) - return function() - if vim.wo.diff then - vim.cmd.normal({ vim.v.count1 .. native, bang = true }) - else - fn() - end - end - end - - -- Select - local select_maps = { - { { 'x', 'o' }, 'af', sel('@function.outer'), { desc = 'TS: around function' } }, - { { 'x', 'o' }, 'if', sel('@function.inner'), { desc = 'TS: inside function' } }, - { { 'x', 'o' }, 'ac', sel('@class.outer'), { desc = 'TS: around class' } }, - { { 'x', 'o' }, 'ic', sel('@class.inner'), { desc = 'TS: inside class' } }, - { { 'x', 'o' }, 'as', sel('@local.scope', 'locals'), { desc = 'TS: around scope' } }, - } - - -- Move - local move_maps = { - { { 'n', 'x', 'o' }, ']m', mv('goto_next_start', '@function.outer'), { desc = 'TS: next function start' } }, - { { 'n', 'x', 'o' }, ']]', mv('goto_next_start', '@class.outer'), { desc = 'TS: next class start' } }, - { { 'n', 'x', 'o' }, ']s', mv('goto_next_start', '@local.scope', 'locals'), { desc = 'TS: next scope start' } }, - { { 'n', 'x', 'o' }, ']z', mv('goto_next_start', '@fold', 'folds'), { desc = 'TS: next fold start' } }, - - { { 'n', 'x', 'o' }, ']M', mv('goto_next_end', '@function.outer'), { desc = 'TS: next function end' } }, - { { 'n', 'x', 'o' }, '][', mv('goto_next_end', '@class.outer'), { desc = 'TS: next class end' } }, - - { { 'n', 'x', 'o' }, '[m', mv('goto_previous_start', '@function.outer'), { desc = 'TS: prev function start' } }, - { { 'n', 'x', 'o' }, '[[', mv('goto_previous_start', '@class.outer'), { desc = 'TS: prev class start' } }, - - { { 'n', 'x', 'o' }, '[M', mv('goto_previous_end', '@function.outer'), { desc = 'TS: prev function end' } }, - { { 'n', 'x', 'o' }, '[]', mv('goto_previous_end', '@class.outer'), { desc = 'TS: prev class end' } }, - - -- "nearest of start/end" - { - { 'n', 'x', 'o' }, - ']c', - diff_or(']c', mv('goto_next', '@conditional.outer')), - { desc = 'TS: next conditional (next change in diff)' }, - }, - { - { 'n', 'x', 'o' }, - '[c', - diff_or('[c', mv('goto_previous', '@conditional.outer')), - { desc = 'TS: prev conditional (prev change in diff)' }, - }, - - -- Grouped captures example - { - { 'n', 'x', 'o' }, - ']o', - mv_any('goto_next_start', { '@loop.inner', '@loop.outer' }), - { desc = 'TS: next loop start' }, - }, - } - - require('nvim-treesitter-textobjects').setup({ - move = { - -- whether to set jumps in the jumplist - set_jumps = true, - }, - - select = { - -- Automatically jump forward to textobj, similar to targets.vim - lookahead = true, - -- You can choose the select mode (default is charwise 'v') - -- - -- Can also be a function which gets passed a table with the keys - -- * query_string: eg '@function.inner' - -- * method: eg 'v' or 'o' - -- and should return the mode ('v', 'V', or '') or a table - -- mapping query_strings to modes. - selection_modes = { - ['@parameter.outer'] = 'v', -- charwise - ['@function.outer'] = 'V', -- linewise - ['@class.outer'] = '', -- blockwise - }, - -- If you set this to `true` (default is `false`) then any textobject is - -- extended to include preceding or succeeding whitespace. Succeeding - -- whitespace has priority in order to act similarly to eg the built-in - -- `ap`. - -- - -- Can also be a function which gets passed a table with the keys - -- * query_string: eg '@function.inner' - -- * selection_mode: eg 'v' - -- and should return true of false - include_surrounding_whitespace = false, - }, - }) - - -- Apply all the maps - for _, m in ipairs(select_maps) do - map(m[1], m[2], m[3], m[4]) - end - - for _, m in ipairs(move_maps) do - map(m[1], m[2], m[3], m[4]) - end - - -- Repeatable ; only: ',' is the mapleader - map({ 'n', 'x', 'o' }, ';', rep.repeat_last_move_next, { desc = 'TS: repeat last move next' }) - - -- Optional: make f/F/t/T repeatable too (expr mappings) - map({ 'n', 'x', 'o' }, 'f', rep.builtin_f_expr, { expr = true, desc = 'TS: repeatable f' }) - map({ 'n', 'x', 'o' }, 'F', rep.builtin_F_expr, { expr = true, desc = 'TS: repeatable F' }) - map({ 'n', 'x', 'o' }, 't', rep.builtin_t_expr, { expr = true, desc = 'TS: repeatable t' }) - map({ 'n', 'x', 'o' }, 'T', rep.builtin_T_expr, { expr = true, desc = 'TS: repeatable T' }) -end - -return M diff --git a/lua/plugin/treesitter.lua b/lua/plugin/treesitter.lua index 8f07e05e..dd6dcc25 100644 --- a/lua/plugin/treesitter.lua +++ b/lua/plugin/treesitter.lua @@ -9,83 +9,135 @@ local vim_pack = require('vim-pack') -vim_pack.on_plugin_update('nvim-treesitter', function(data) - if not data.active then - vim.cmd.packadd('nvim-treesitter') +local function install_list() + local parsers = { + 'awk', + 'bash', + 'c', + 'cmake', + 'css', + 'diff', + 'dockerfile', + 'dot', + 'gitattributes', + 'gitcommit', + 'gitignore', + 'git_config', + 'go', + 'html', + 'http', + 'java', + 'javascript', + 'jq', + 'jsdoc', + 'json', + 'lua', + 'make', + 'markdown', + 'markdown_inline', + 'perl', + 'php', + 'phpdoc', + 'php_only', + 'python', + 'query', + 'regex', + 'ron', + 'ruby', + 'rust', + 'scss', + 'solidity', + 'sql', + 'styled', + 'svelte', + 'toml', + 'tsx', + 'twig', + 'typescript', + 'vim', + 'vimdoc', + 'vue', + 'xml', + 'yaml', + 'zig', + } + + local set = {} + for _, parser in ipairs(parsers) do + set[parser] = true + end + + local site = vim.fn.stdpath('data') + for _, path in ipairs(vim.api.nvim_get_runtime_file('parser/*', true)) do + -- Skip the parsers nvim-treesitter already installed under `site/`. + if not vim.startswith(path, site) then + set[vim.fn.fnamemodify(path, ':t:r')] = true + end end - vim.cmd('TSUpdate') -end) -vim_pack.add_on_event({ 'BufReadPost', 'BufNewFile' }, { + return vim.tbl_keys(set) +end + +vim.api.nvim_create_autocmd('PackChanged', { + callback = function(args) + if args.data.spec.name == 'nvim-treesitter' and (args.data.kind == 'install' or args.data.kind == 'update') then + -- Re-install and update parsers. + require('nvim-treesitter').install(install_list()):wait(300001) + require('nvim-treesitter').update():wait(300000) + end + end, +}) + +local add = require('vim-pack').add + +add({ { src = 'nvim-treesitter/nvim-treesitter', - version = 'main', - setup = false, on_setup = function() - local languages = { - 'awk', - 'bash', - 'c', - 'cmake', - 'css', - 'diff', - 'dockerfile', - 'dot', - 'gitattributes', - 'gitcommit', - 'gitignore', - 'git_config', - 'go', - 'html', - 'http', - 'java', - 'javascript', - 'jq', - 'jsdoc', - 'json', - 'lua', - 'make', - 'markdown', - 'markdown_inline', - 'perl', - 'php', - 'phpdoc', - 'php_only', - 'python', - 'query', - 'regex', - 'ron', - 'ruby', - 'rust', - 'scss', - 'solidity', - 'sql', - 'styled', - 'svelte', - 'toml', - 'tsx', - 'twig', - 'typescript', - 'vim', - 'vimdoc', - 'vue', - 'xml', - 'yaml', - 'zig', - } + -- Main-branch nvim-treesitter ships queries under `runtime/queries/`, + -- which isn't on rtp by default. Prepend it so highlights/folds/indents + -- are visible to `vim.treesitter.start`. + local init = vim.api.nvim_get_runtime_file('lua/nvim-treesitter/init.lua', false)[1] + if init then + vim.opt.runtimepath:prepend(vim.fn.fnamemodify(init, ':h:h:h') .. '/runtime') + end - -- Async: already installed parsers are skipped, missing ones are installed in background - require('nvim-treesitter').install(languages, { max_jobs = 8 }) - - -- Folding is handled in config/folding.lua - vim.api.nvim_create_autocmd('FileType', { - group = vim.api.nvim_create_augroup('TreesitterSetup', { clear = true }), - callback = function(args) - local buf = args.buf - local lang = vim.treesitter.language.get_lang(vim.bo[buf].filetype) or vim.bo[buf].filetype - pcall(vim.treesitter.start, buf, lang) - end, - }) + require('nvim-treesitter').install(install_list()):wait(300000) end, }, + { + src = 'nvim-treesitter/nvim-treesitter-context', + module_name = 'treesitter-context', + opts = { + -- Avoid the sticky context from growing a lot. + max_lines = 3, + -- Match the context lines to the source code. + multiline_threshold = 1, + -- Disable it when the window is too small. + min_window_height = 20, + }, + on_setup = function() + vim.keymap.set('n', '[c', function() + -- Jump to previous change when in diffview. + if vim.wo.diff then + return '[c' + else + vim.schedule(function() + require('treesitter-context').go_to_context() + end) + return '' + end + end, { desc = 'Jump to upper context', expr = true }) + end, + }, +}) + +vim.api.nvim_create_autocmd('PackChanged', { + callback = function(args) + if args.data.spec.name == 'nvim-treesitter' and (args.data.kind == 'install' or args.data.kind == 'update') then + -- Re-install and update parsers. + require('nvim-treesitter').install(install_list()):wait(300000) + require('nvim-treesitter').update():wait(300000) + end + end, }) diff --git a/lua/plugin/ts-context.lua b/lua/plugin/ts-context.lua deleted file mode 100644 index c20b8a50..00000000 --- a/lua/plugin/ts-context.lua +++ /dev/null @@ -1,20 +0,0 @@ -local add_on_event = require('vim-pack').add_on_event - -add_on_event({ 'BufReadPost', 'BufNewFile' }, { - { - src = 'nvim-treesitter/nvim-treesitter-context', - module_name = 'treesitter-context', - ---@module "treesitter-context" - ---@type TSContext.Config - ---@diagnostic disable-next-line: missing-fields - opts = { - max_lines = 4, - multiline_threshold = 2, - }, - on_setup = function() - vim.keymap.set('n', '[x', function() - require('treesitter-context').go_to_context(vim.v.count1) - end, { desc = 'TS: go to context' }) - end, - }, -}) diff --git a/lua/plugin/ts-textobject.lua b/lua/plugin/ts-textobject.lua deleted file mode 100644 index a5a31c0b..00000000 --- a/lua/plugin/ts-textobject.lua +++ /dev/null @@ -1,14 +0,0 @@ -local add_on_event = require('vim-pack').add_on_event - --- Must be set before the plugin is loaded. -vim.g.no_plugin_maps = true - -add_on_event({ 'BufReadPre', 'BufNewFile' }, { - { - src = 'nvim-treesitter/nvim-treesitter-textobjects', - version = 'main', - on_setup = function() - require('config.textobjects_keymaps').setup() - end, - }, -})