summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authorJosh Rahm <rahm@josher.dev>2026-10-18 15:54:35 -0600
committerJosh Rahm <rahm@josher.dev>2026-10-18 15:54:35 -0600
commit457674c5b25b9f4be84f0f0ddf0cea7c1811174a (patch)
tree69ce27a62afabd7a3d66830201c4d2d40a28e500 /lua
parent715fd8b957d7c553f2df3070b430784517fc78ae (diff)
downloadconfig.vim-457674c5b25b9f4be84f0f0ddf0cea7c1811174a.tar.gz
config.vim-457674c5b25b9f4be84f0f0ddf0cea7c1811174a.tar.bz2
config.vim-457674c5b25b9f4be84f0f0ddf0cea7c1811174a.zip
Redesign my vim config.
Now uses Lua primarily Breaks apart the configuration into rc-service style configuration files. Deletes a ton of the cruft with old LSP settings.
Diffstat (limited to 'lua')
-rw-r--r--lua/config/00-options.lua42
-rw-r--r--lua/config/01-plugins.lua56
-rw-r--r--lua/config/02-mappings.lua148
-rw-r--r--lua/config/03-commands.lua85
-rw-r--r--lua/config/04-autocmds.lua67
-rw-r--r--lua/config/05-lsp.lua141
-rw-r--r--lua/config/99-extregs-config.lua17
-rw-r--r--lua/config/99-gitsigns-config.lua27
-rw-r--r--lua/config/99-hop-config.lua2
-rw-r--r--lua/config/99-lualine-config.lua32
-rw-r--r--lua/config/99-nvim-surround-config.lua2
-rw-r--r--lua/config/99-nvim-treesitter-config.lua86
-rw-r--r--lua/config/99-nvim-web-devicons-config.lua2
-rw-r--r--lua/config/99-telescope-config.lua19
-rw-r--r--lua/config/99-treesitter-config.lua87
-rw-r--r--lua/diagnostics.lua55
-rw-r--r--lua/lsp.lua308
-rw-r--r--lua/lualinesetup.lua47
-rw-r--r--lua/tabby.lua32
-rw-r--r--lua/treesitter-textobjects-setup.lua52
-rw-r--r--lua/treesitter.lua45
-rw-r--r--lua/windownav.lua76
22 files changed, 813 insertions, 615 deletions
diff --git a/lua/config/00-options.lua b/lua/config/00-options.lua
new file mode 100644
index 0000000..629c14d
--- /dev/null
+++ b/lua/config/00-options.lua
@@ -0,0 +1,42 @@
+-- Editor options extracted from the original init.vim.
+-- Load before plugin setup where possible (especially netrw and mapleader).
+
+local opt = vim.opt
+local g = vim.g
+
+g.loaded_netrw = 1
+g.loaded_netrwPlugin = 1
+g.mapleader = ' '
+
+
+-- Display and navigation.
+opt.termguicolors = true
+opt.number = true
+opt.relativenumber = true
+opt.wrap = false
+opt.scrolloff = 8
+opt.title = true
+opt.colorcolumn = '+1'
+
+-- Indentation and text layout.
+opt.shiftwidth = 2
+opt.tabstop = 2
+opt.expandtab = true
+opt.textwidth = 80
+
+-- Splits and completion.
+opt.splitright = true
+opt.splitbelow = true
+opt.wildmode = { 'longest', 'list', 'full' }
+opt.pumheight = 20
+opt.completeopt = { 'menu', 'menuone', 'noselect' }
+
+-- Performance, responsiveness, and matching pairs.
+opt.updatetime = 1000
+opt.matchpairs:append('<:>')
+
+-- Global configuration for plugins.
+g.vsnip_snippet_dir = vim.fn.expand('~/.config/nvim/snippets')
+g.vsnip_snippet_dirs = { vim.fn.expand('~/.config/nvim/local/snippets') }
+g.jq_highlight_objects = 1
+g.jq_highlight_function_calls = 1
diff --git a/lua/config/01-plugins.lua b/lua/config/01-plugins.lua
new file mode 100644
index 0000000..e0acdd0
--- /dev/null
+++ b/lua/config/01-plugins.lua
@@ -0,0 +1,56 @@
+-- Core plugin list: Neovim 0.12+ built-in package manager.
+-- GitHub shorthand (owner/repo) is not supported by vim.pack.
+local github = function(repo)
+ return 'https://github.com/' .. repo .. '.git'
+end
+
+-- Josher projects: local working checkout takes precedence over Git.
+-- Change the root on each machine or override this helper locally.
+local projects = vim.fn.expand('~/Projects')
+local function josher(repo)
+ local path = projects .. '/' .. repo
+ if vim.fn.isdirectory(path) == 1 then
+ -- Place local checkout on runtimepath instead of downloading it.
+ vim.opt.rtp:prepend(path)
+ return nil
+ end
+ return 'git@git.josher.dev:' .. repo .. '.git'
+end
+
+local plugins = {
+ -- Searching
+ github('nvim-lua/plenary.nvim'),
+ github('nvim-telescope/telescope.nvim'),
+
+ -- Syntax / structural editing
+ github('nvim-treesitter/nvim-treesitter'),
+ github('nvim-treesitter/nvim-treesitter-textobjects'),
+
+ -- Editing and navigation
+ github('lewis6991/gitsigns.nvim'),
+ github('kylechui/nvim-surround'),
+ github('smoka7/hop.nvim'),
+
+ -- UI
+ github('nvim-lualine/lualine.nvim'),
+ github('nvim-tree/nvim-web-devicons'),
+
+ -- LSP server presets only; native vim.lsp.enable/config is used elsewhere.
+ github('neovim/nvim-lspconfig'),
+
+ -- Existing personal plugins; delete entries you no longer want.
+ josher('bulletjava.vim'),
+ josher('fieldmarshal.vim'),
+ josher('nvim-color-picker'),
+ josher('nvim-warp'),
+ josher('meltdown'),
+ josher('extregs.nvim'),
+ -- josher('rneovim-userregs'), -- Optional experimental branch/plugin.
+}
+
+-- Local projects return nil; remove holes before calling vim.pack.
+local install = {}
+for _, plugin in pairs(plugins) do
+ if plugin then install[#install + 1] = plugin end
+end
+vim.pack.add(install)
diff --git a/lua/config/02-mappings.lua b/lua/config/02-mappings.lua
new file mode 100644
index 0000000..8c4f6e3
--- /dev/null
+++ b/lua/config/02-mappings.lua
@@ -0,0 +1,148 @@
+-- Global mappings migrated from the original init.vim.
+-- Load after setting vim.g.mapleader = " " and after defining required commands.
+-- Plugin-owned mappings (LSP, Gitsigns, Tree-sitter, Trouble) remain in their setup files.
+
+vim.g.mapleader = vim.g.mapleader or " "
+
+local map = vim.keymap.set
+local all = { "n", "x", "s", "o" } -- Vimscript :noremap modes
+
+local function find_in_dir()
+ local dir = vim.fn.resolve(vim.fn.expand("%:p:h"))
+ require("telescope.builtin").find_files({
+ search_dirs = { dir },
+ path_display = { "shorten" },
+ hidden = true,
+ })
+end
+
+local function shift_char(delta)
+ local pos = vim.api.nvim_win_get_cursor(0)
+ local line = vim.api.nvim_get_current_line()
+ local col = pos[2] + 1
+ local char_index = vim.fn.strchars(line:sub(1, col - 1))
+ local char = vim.fn.strcharpart(line, char_index, 1)
+ if char == "" then return end
+ local code = vim.fn.char2nr(char)
+ local replacement = vim.fn.nr2char(code + delta)
+ vim.api.nvim_set_current_line(line:sub(1, col - 1) .. replacement .. line:sub(col + #char))
+end
+
+vim.go.operatorfunc = "v:lua.JumpToLastChange"
+_G.JumpToLastChange = function()
+ vim.cmd.normal({ "`[", bang = true })
+end
+
+map(all, "g.", "<cmd>set operatorfunc=v:lua.JumpToLastChange<cr>g@", { silent = true })
+map(all, "<C-w>%", "<C-w>v")
+map(all, "<C-w>\"", "<C-w>s")
+map(all, "<C-w><C-t>", "<C-w>s<cmd>term<cr>")
+map(all, "<C-w><C-S-t>", "<C-w>s<cmd>TERM<cr>")
+map(all, "Y", "y$")
+map("x", "ú", ":FormatLines<cr>")
+map(all, "ú", "<cmd>lua run_format_code()<cr>")
+map(all, "<leader>p", "<plug>(SynStack)")
+map(all, "<leader>ff", "<cmd>Telescope find_files<cr>")
+map(all, "<M-f>", "<cmd>Telescope find_files<cr>")
+map(all, "<M-r>", "<cmd>Telescope find_files<cr>")
+map(all, "<M-F>", find_in_dir)
+map("i", "<C-+>", "<Plug>(vsnip-expand)")
+map(all, "^", "^zH")
+map(all, "<leader>to", "<cmd>Telescope oldfiles<cr>")
+map(all, "<leader>ta", "<cmd>Telescope autocommands<cr>")
+map(all, "<leader>tbu", "<cmd>Telescope buffers<cr><cr>")
+map(all, "<leader>T", "<cmd>Telescope builtin<cr>")
+map(all, "<leader>tcs", "<cmd>Telescope colorscheme<cr>")
+map(all, "<leader>tch", "<cmd>Telescope command_history<cr>")
+map(all, "<leader>tco", "<cmd>Telescope commands<cr>")
+map(all, "<leader>t/", "<cmd>Telescope current_buffer_fuzzy_find<cr>")
+map(all, "<leader>tcbt", "<cmd>Telescope current_buffer_tags<cr>")
+map(all, "<leader>td", "<cmd>Telescope diagnostics<cr>")
+map(all, "<leader>tf", "<cmd>Telescope find_files<cr>")
+map(all, "<leader>tgb", "<cmd>Telescope git_branches<cr>")
+map(all, "<leader>tgc", "<cmd>Telescope git_commits<cr>")
+map(all, "<leader>tgf", "<cmd>Telescope git_files<cr>")
+map(all, "<leader>tgs", "<cmd>Telescope git_stash<cr>")
+map(all, "<leader>tgr", "<cmd>Telescope grep_string<cr>")
+map(all, "<leader>thi", "<cmd>Telescope highlights<cr>")
+map(all, "<leader>tjl", "<cmd>Telescope jumplist<cr>")
+map(all, "<leader>tlg", "<cmd>Telescope live_grep<cr>")
+map(all, "<leader>tll", "<cmd>Telescope loclist<cr>")
+map(all, "<leader>t[d", "<cmd>Telescope lsp_definitions<cr>")
+map(all, "<leader>t[s", "<cmd>Telescope lsp_document_symbols<cr>")
+map(all, "<leader>t[w", "<cmd>Telescope lsp_dynamic_workspace_symbols<cr>")
+map(all, "<leader>t[i", "<cmd>Telescope lsp_implementations<cr>")
+map(all, "<leader>t[r", "<cmd>Telescope lsp_incoming_calls<cr>")
+map(all, "<leader>t[n", "<cmd>Telescope lsp_outgoing_calls<cr>")
+map(all, "<leader>t[e", "<cmd>Telescope lsp_references<cr>")
+map(all, "<leader>t[t", "<cmd>Telescope lsp_type_definitions<cr>")
+map(all, "<leader>t?", "<cmd>Telescope man_pages<cr>")
+map(all, "<leader>t'", "<cmd>Telescope marks<cr>")
+map(all, "<leader>tp", "<cmd>Telescope pickers<cr>")
+map(all, "<leader>tqf", "<cmd>Telescope quickfix<cr>")
+map(all, "<leader>tqh", "<cmd>Telescope quickfixhistory<cr>")
+map(all, "<leader>t\"", "<cmd>Telescope registers<cr>")
+map(all, "<leader>th/", "<cmd>Telescope search_history<cr>")
+map(all, "<leader>tz", "<cmd>Telescope spell_suggest<cr>")
+map(all, "<leader>ty", "<cmd>Telescope symbols<cr>")
+map(all, "<leader>tt", "<cmd>Telescope tags<cr>")
+map(all, "<leader>tst", "<cmd>Telescope tagstack<cr>")
+map(all, "<leader>tsit", "<cmd>Telescope treesitter<cr>")
+map(all, "<leader>tv", "<cmd>Telescope vim_options<cr>")
+map("n", "n", "<cmd>set hlsearch<CR>n", { silent = true })
+map("n", "N", "<cmd>set hlsearch<CR>N", { silent = true })
+map(all, "<leader>nt", "<cmd>NvimTreeToggle<cr>")
+map(all, "<C-n><C-e>", [[:<C-u>e <C-r>=escape(expand('%:h'), ' \')<cr>/]])
+map(all, "<C-w>.", "<cmd>lua require('windownav').goto_terminal()<cr>")
+map(all, "<C-w>I", "<cmd>lua require('windownav').goto_initvim()<cr>")
+map(all, "<C-w>'", "<cmd>lua require('windownav').goto_lastwin()<cr>")
+map("n", "<M-t>", "<cmd>term<cr><cmd>startinsert<cr>")
+map("n", "<M-S-T>", "<cmd>TERM<cr><cmd>startinsert<cr>")
+map("n", "<C-Space>", "<C-^>")
+map("n", "<M-b>", "<cmd>Telescope buffers<cr>")
+map("n", "<M-l>", "<cmd>bnext<cr>")
+map("n", "<M-h>", "<cmd>bprev<cr>")
+map(all, "<C-g>", "<cmd>lua vim.diagnostic.open_float()<cr>")
+map(all, "<leader><C-f>", "<cmd>WarpFull<cr>")
+map(all, "<C-f>", "<cmd>WarpGrid<cr>")
+map("o", "<C-f>", "v<cmd>WarpGrid<cr>")
+map(all, "<leader>w", "<cmd>WarpWords<cr>")
+map("o", "<leader>w", "v<cmd>WarpWords<cr>")
+map(all, "<C-_>", [[/<C-u>\%V]]) -- Original <C-/> mapping (encoded as Ctrl-_)
+map("n", "œ", "<leader>k", { remap = true })
+map("n", "ï", "<leader>j", { remap = true })
+map("o", "œ", "<leader>k", { remap = true })
+map("o", "ï", "<leader>j", { remap = true })
+map("o", "aœ", "a<leader>k", { remap = true })
+map("o", "aï", "a<leader>j", { remap = true })
+map("o", "iœ", "i<leader>k", { remap = true })
+map("o", "iï", "i<leader>j", { remap = true })
+map("x", "œ", "<leader>k", { remap = true })
+map("x", "ï", "<leader>j", { remap = true })
+map(all, "<M-ñ>", "<cmd>TSNodeUnderCursor<cr>")
+map(all, "<M-©>", "<cmd>TSCaptureUnderCursor<cr>")
+map(all, "Τ", "<cmd>Inspect<cr>")
+map(all, "g[r", "<cmd>Telescope lsp_references path_display={\"shorten\"}<cr>")
+map(all, "g[d", "<cmd>Telescope lsp_definitions path_display={\"shorten\"}<cr>")
+map(all, "g[i", "<cmd>Telescope lsp_implementations path_display={\"shorten\"}<cr>")
+map(all, "g[td", "<cmd>Telescope lsp_type_definitions path_display={\"shorten\"}<cr>")
+map(all, "g[ci", "<cmd>Telescope lsp_incoming_calls path_display={\"shorten\"}<cr>")
+map(all, "g[co", "<cmd>Telescope lsp_outgoing_calls path_display={\"shorten\"}<cr>")
+map(all, "g[sd", "<cmd>Telescope lsp_document_symbols path_display={\"shorten\"}<cr>")
+map(all, "g[sw", "<cmd>Telescope lsp_workspace_symbols path_display={\"shorten\"}<cr>")
+map(all, "g[sdw", "<cmd>Telescope lsp_dynamic_workspace_symbols path_display={\"shorten\"}<cr>")
+map(all, "[e", "<cmd>lua vim.diagnostic.jump({count=-1, severity=vim.diagnostic.severity.ERROR})<cr>")
+map(all, "]e", "<cmd>lua vim.diagnostic.jump({count=1, severity=vim.diagnostic.severity.ERROR})<cr>")
+map(all, "α", function() shift_char(1) end)
+map(all, "Α", function() shift_char(-1) end)
+map(all, "€", "vib<esc>a)<esc>")
+map(all, "<X2Mouse>", "<C-I>")
+map(all, "<2-X2Mouse>", "<C-I>")
+map(all, "<3-X2Mouse>", "<C-I>")
+map(all, "<X1Mouse>", "<C-O>")
+map(all, "<2-X1Mouse>", "<C-O>")
+map(all, "<3-X1Mouse>", "<C-O>")
+map(all, "<M-S-ScrollWheelRight>", "<C-LeftMouse>")
+map(all, "<M-]>", "<cmd>Telescope tags<cr>")
+map(all, "gh", "<cmd>HopCamelCase<cr>")
+
diff --git a/lua/config/03-commands.lua b/lua/config/03-commands.lua
new file mode 100644
index 0000000..f8b0d47
--- /dev/null
+++ b/lua/config/03-commands.lua
@@ -0,0 +1,85 @@
+-- Commands and command-line abbreviations migrated from the original init.vim.
+-- This file intentionally does not register autocommands or keymaps.
+
+local api = vim.api
+local config_dir = vim.fn.stdpath('config')
+
+-- Edit the new configuration (original commands opened init.vim/local.vim).
+api.nvim_create_user_command('Config', function()
+ vim.cmd.edit(vim.fn.fnameescape(config_dir .. '/init.lua'))
+end, { desc = 'Edit Neovim init.lua' })
+
+api.nvim_create_user_command('Configl', function()
+ vim.cmd.edit(vim.fn.fnameescape(config_dir .. '/lua/config/local/00-machine.lua'))
+end, { desc = 'Edit machine-local configuration' })
+
+-- :W is an easy-to-type alias for :w. Pass through arguments and !.
+api.nvim_create_user_command('W', function(opts)
+ vim.cmd('write' .. (opts.bang and '!' or '') .. (opts.args ~= '' and ' ' .. opts.args or ''))
+end, { bang = true, nargs = '*', complete = 'file', desc = 'Write buffer' })
+
+-- Open a terminal in the specified directory, defaulting to the current
+-- buffer's directory. The original function required a directory argument or
+-- a buffer whose name was itself a directory; the default is more useful here.
+_G.open_terminal_on_directory = function(dirname)
+ dirname = dirname or vim.fn.expand('%:p:h')
+ if vim.fn.isdirectory(dirname) ~= 1 then
+ vim.notify('Not a directory: ' .. dirname, vim.log.levels.WARN)
+ return
+ end
+
+ local shell_cmd = string.format('cd %s && exec "$SHELL"', vim.fn.shellescape(dirname))
+ vim.cmd('terminal sh -c ' .. vim.fn.shellescape(shell_cmd))
+ vim.cmd.startinsert()
+ vim.cmd('silent! keepalt file ' .. vim.fn.fnameescape('TERM ' .. dirname))
+end
+
+api.nvim_create_user_command('TERM', function(opts)
+ _G.open_terminal_on_directory(opts.args ~= '' and vim.fn.expand(opts.args) or nil)
+end, { nargs = '?', complete = 'dir', desc = 'Terminal in current file directory' })
+
+-- Kept global because 01-mappings.lua invokes it with :lua run_format_code().
+_G.run_format_code = function()
+ local clients = vim.lsp.get_clients({ bufnr = 0, method = 'textDocument/formatting' })
+ if #clients > 0 then
+ vim.lsp.buf.format({ async = false })
+ elseif vim.fn.exists(':FormatCode') == 2 then
+ vim.cmd('FormatCode')
+ else
+ vim.notify('No LSP formatter or :FormatCode command available', vim.log.levels.WARN)
+ end
+end
+
+-- Developer conveniences from the original config.
+_G.remove_package = function(prefix)
+ for name in pairs(package.loaded) do
+ if name:sub(1, #prefix) == prefix then
+ package.loaded[name] = nil
+ end
+ end
+end
+
+_G.reload_package = function(name)
+ _G.remove_package(name)
+ return require(name)
+end
+
+-- Original command-line abbreviations. Limit them to a leading command-line
+-- token, so they don't unexpectedly expand inside commands or search patterns.
+local abbreviations = {
+ _config = config_dir,
+ _plugged = vim.fn.stdpath('data') .. '/plugged', -- legacy vim-plug path
+ _fm = vim.fn.stdpath('data') .. '/plugged/fieldmarshal.vim', -- legacy path
+ _home = vim.fn.stdpath('data'),
+ _projects = vim.fn.expand('~/Projects'),
+}
+
+for word, replacement in pairs(abbreviations) do
+ vim.cmd('cnoreabbrev <expr> ' .. word .. ' (getcmdtype() ==# ":" && getcmdline() ==# "' .. word .. '") ? ' .. vim.fn.string(replacement) .. ' : "' .. word .. '"')
+end
+
+vim.cmd([[cnoreabbrev <expr> _ (getcmdtype() ==# ':' && getcmdline() ==# '_') ? fnameescape(expand('%:h')) : '_']])
+
+-- The old :UpdateInitVimHook belonged to vim-plug and is intentionally omitted.
+-- Move the old InitVim/UseTerminal autocommands to a separate 04-autocmds.lua.
+
diff --git a/lua/config/04-autocmds.lua b/lua/config/04-autocmds.lua
new file mode 100644
index 0000000..aff6d27
--- /dev/null
+++ b/lua/config/04-autocmds.lua
@@ -0,0 +1,67 @@
+-- Autocommands migrated from the original init.vim.
+-- Plugin-specific autocommands (LSP, windownav, etc.) stay in their modules.
+
+local api = vim.api
+
+local init_group = api.nvim_create_augroup('InitVim', { clear = true })
+
+-- Turn search highlighting off when leaving Insert mode; mappings for n/N
+-- in 01-mappings.lua re-enable highlighting when navigating results.
+api.nvim_create_autocmd('InsertLeave', {
+ group = init_group,
+ callback = function()
+ vim.opt.hlsearch = false
+ end,
+ desc = 'Clear search highlighting after insert mode',
+})
+
+-- Highlight matches whenever entering the / or ? search command line.
+api.nvim_create_autocmd('CmdlineEnter', {
+ group = init_group,
+ pattern = { '/', '?' },
+ callback = function()
+ vim.opt.hlsearch = true
+ end,
+ desc = 'Enable search highlighting on search',
+})
+
+vim.api.nvim_create_autocmd('TextYankPost', {
+ group = vim.api.nvim_create_augroup('HighlightYank', { clear = true }),
+ callback = function()
+ vim.hl.hl_op({ higroup = 'IncSearch', timeout = 100 })
+ end,
+})
+
+vim.api.nvim_create_autocmd('TextPutPost', {
+ group = vim.api.nvim_create_augroup('HighlightPut', { clear = true }),
+ callback = function()
+ vim.hl.hl_op({ higroup = 'IncSearch', timeout = 100 })
+ end,
+})
+
+api.nvim_create_autocmd({ 'FocusGained', 'BufEnter' }, {
+ group = init_group,
+ command = 'checktime',
+ desc = 'Check for changes to files on disk',
+})
+
+-- The original UseTerminal group only opened a terminal if the entered buffer
+-- *itself* was named after a directory. Guard that explicitly: the new
+-- open_terminal_on_directory() helper defaults to the file's parent directory,
+-- which would otherwise open a terminal whenever you entered any file.
+local terminal_group = api.nvim_create_augroup('UseTerminal', { clear = true })
+api.nvim_create_autocmd({ 'BufNewFile', 'BufEnter' }, {
+ group = terminal_group,
+ callback = function(args)
+ local dirname = api.nvim_buf_get_name(args.buf)
+ if dirname ~= '' and vim.fn.isdirectory(dirname) == 1 then
+ -- Defined by 03-commands.lua. Resolve at callback time so our
+ -- numbered config loader may source this file independently.
+ if type(_G.open_terminal_on_directory) == 'function' then
+ _G.open_terminal_on_directory(dirname)
+ end
+ end
+ end,
+ desc = 'Open a terminal when editing a directory buffer',
+})
+
diff --git a/lua/config/05-lsp.lua b/lua/config/05-lsp.lua
new file mode 100644
index 0000000..64328a9
--- /dev/null
+++ b/lua/config/05-lsp.lua
@@ -0,0 +1,141 @@
+-- Native LSP and automatic completion for Neovim 0.12/0.13.
+-- Requires nvim-lspconfig only for its server presets in runtimepath.
+-- No nvim-cmp, cmp-nvim-lsp, lspkind, or vsnip required.
+
+vim.opt.autocomplete = true
+vim.opt.complete = 'o'
+vim.opt.completeopt = { 'menu', 'menuone', 'noselect', 'popup' }
+vim.opt.shortmess:append('c')
+
+-- Keep the old LSP bindings; all are buffer-local.
+local function map(buf, lhs, rhs, desc)
+ vim.keymap.set('n', lhs, rhs, { buffer = buf, silent = true, desc = desc })
+end
+
+local group = vim.api.nvim_create_augroup('UserNativeLsp', { clear = true })
+
+vim.api.nvim_create_autocmd('LspAttach', {
+ group = group,
+ callback = function(args)
+ local bufnr = args.buf
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ if not client then return end
+
+ -- Completion requests are sent automatically while typing, without cmp.
+ -- C-n/C-p move through suggestions; C-y accepts one; C-e dismisses.
+ if client:supports_method('textDocument/completion') then
+ vim.lsp.completion.enable(true, client.id, bufnr, { autotrigger = true })
+ end
+
+ map(bufnr, '<leader>rn', vim.lsp.buf.rename, 'LSP rename')
+ map(bufnr, '<leader>ca', vim.lsp.buf.code_action, 'LSP code action')
+ map(bufnr, '<M-k>', vim.lsp.buf.hover, 'LSP hover')
+ map(bufnr, 'g0', vim.lsp.buf.document_symbol, 'Document symbols')
+ map(bufnr, 'gW', vim.lsp.buf.workspace_symbol, 'Workspace symbols')
+ map(bufnr, 'gd', vim.lsp.buf.definition, 'Go to definition')
+ map(bufnr, 'gD', vim.lsp.buf.declaration, 'Go to declaration')
+ map(bufnr, 'gi', vim.lsp.buf.implementation, 'Go to implementation')
+ map(bufnr, 'gr', vim.lsp.buf.references, 'Find references')
+ map(bufnr, '<C-k>', vim.lsp.buf.signature_help, 'Signature help')
+ map(bufnr, 'g<Space>', vim.lsp.buf.type_definition, 'Type definition')
+ map(bufnr, '[d', function() vim.diagnostic.jump({ count = -1 }) end, 'Previous diagnostic')
+ map(bufnr, ']d', function() vim.diagnostic.jump({ count = 1 }) end, 'Next diagnostic')
+
+ vim.bo[bufnr].omnifunc = 'v:lua.vim.lsp.omnifunc'
+ vim.opt_local.signcolumn = 'yes'
+
+ if client:supports_method('textDocument/documentHighlight') then
+ -- Per-buffer autocommands, shared across clients to avoid duplicates.
+ local hlgroup = vim.api.nvim_create_augroup('UserLspHighlight' .. bufnr, { clear = true })
+ vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
+ group = hlgroup, buffer = bufnr, callback = vim.lsp.buf.document_highlight,
+ })
+ vim.api.nvim_create_autocmd({ 'CursorMoved', 'InsertLeave' }, {
+ group = hlgroup, buffer = bufnr, callback = vim.lsp.buf.clear_references,
+ })
+ end
+ end,
+})
+
+vim.diagnostic.config({
+ signs = {
+ text = {
+ [vim.diagnostic.severity.ERROR] = '✘',
+ [vim.diagnostic.severity.WARN] = '▲',
+ [vim.diagnostic.severity.INFO] = '●',
+ [vim.diagnostic.severity.HINT] = '◆'
+ }
+ },
+ underline = true,
+ severity_sort = true,
+})
+
+-- nvim-lspconfig's modern lsp/*.lua presets supply cmd, filetypes and root detection.
+-- Only list your desired servers and their overrides here.
+local servers = {
+ bashls = { filetypes = { 'bash', 'sh' } },
+ clangd = { filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' } },
+ mlir = {},
+ jqls = {},
+ lua_ls = {
+ settings = {
+ Lua = {
+ runtime = { version = 'LuaJIT' },
+ workspace = { checkThirdParty = false, library = { vim.env.VIMRUNTIME } },
+ },
+ },
+ },
+ ocamllsp = {},
+ perlpls = {},
+ rust_analyzer = {},
+ verible = {},
+ vimls = {},
+ zls = {},
+ texlab = {},
+ hls = { settings = { haskell = { plugin = { semanticTokens = { globalOn = true } } } } },
+ pylsp = { settings = { pylsp = { plugins = { pycodestyle = { enabled = false } } } } },
+}
+
+for name, overrides in pairs(servers) do
+ vim.lsp.config(name, overrides)
+ vim.lsp.enable(name)
+end
+
+vim.keymap.set('i', '<Tab>', function()
+ if vim.fn.pumvisible() == 1 then
+ return '<C-y>'
+ end
+ return '<Tab>'
+end, { expr = true, desc = 'Accept completion or insert Tab' })
+
+local fallbacks = {
+ Pmenu = 'NormalFloat',
+ PmenuSel = 'Visual',
+ PmenuKind = 'Type',
+ PmenuKindSel = 'Type',
+ PmenuExtra = 'Comment',
+ PmenuExtraSel = 'Comment',
+ PmenuMatch = 'Identifier',
+ PmenuMatchSel = 'Identifier',
+ PmenuBorder = 'FloatBorder',
+}
+
+local function apply_fallbacks()
+ for group, target in pairs(fallbacks) do
+ local hl = vim.api.nvim_get_hl(0, { name = group, link = true })
+
+ if vim.tbl_isempty(hl) or hl.link == 'Pmenu' then
+ vim.api.nvim_set_hl(0, group, { link = target })
+ end
+ end
+end
+
+vim.api.nvim_create_autocmd('ColorScheme', {
+ callback = apply_fallbacks,
+})
+
+apply_fallbacks()
+
+vim.opt.pumheight = 12
+vim.opt.pummaxwidth = 70
+vim.opt.pumblend = 0
diff --git a/lua/config/99-extregs-config.lua b/lua/config/99-extregs-config.lua
new file mode 100644
index 0000000..2827091
--- /dev/null
+++ b/lua/config/99-extregs-config.lua
@@ -0,0 +1,17 @@
+if vim.fn.has('extregs') ~= 1 or not (vim._extregs and vim._extregs.register) then
+ return false
+end
+
+require('extregs').setup({
+ ssh = {
+ host = "rahm@josher.dev",
+ }
+})
+
+vim._extregs.bind('$', 'file.stem')
+vim._extregs.bind('&', 'file.backed')
+vim._extregs.bind('\\', 'ssh.backed')
+vim._extregs.bind('|', 'buffer')
+vim._extregs.bind('τ', 'timestamp')
+vim._extregs.bind('θ', 'uuid')
+vim._extregs.bind(']', 'tmux')
diff --git a/lua/config/99-gitsigns-config.lua b/lua/config/99-gitsigns-config.lua
new file mode 100644
index 0000000..4687668
--- /dev/null
+++ b/lua/config/99-gitsigns-config.lua
@@ -0,0 +1,27 @@
+-- Adapted from the original init.vim; mappings are buffer-local.
+local gs = require('gitsigns')
+gs.setup({
+ on_attach = function(bufnr)
+ local function map(mode, lhs, rhs)
+ vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true })
+ end
+
+ map({ 'o', 'x' }, 'ih', ':<C-U>Gitsigns select_hunk<CR>')
+ map('n', ']h', function()
+ if vim.wo.diff then vim.cmd.normal({ ']c', bang = true })
+ else gs.nav_hunk('next') end
+ end)
+ map('n', '[h', function()
+ if vim.wo.diff then vim.cmd.normal({ '[c', bang = true })
+ else gs.nav_hunk('prev') end
+ end)
+ map('n', '<leader>hs', gs.stage_hunk)
+ map('n', '<leader>hr', gs.reset_hunk)
+ map('v', '<leader>hs', function() gs.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') }) end)
+ map('v', '<leader>hr', function() gs.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') }) end)
+ map('n', '<leader>hS', gs.stage_buffer)
+ map('n', '<leader>hR', gs.reset_buffer)
+ map('n', '<leader>hp', gs.preview_hunk)
+ map('n', '<leader>hi', gs.preview_hunk_inline)
+ end,
+})
diff --git a/lua/config/99-hop-config.lua b/lua/config/99-hop-config.lua
new file mode 100644
index 0000000..91a15f8
--- /dev/null
+++ b/lua/config/99-hop-config.lua
@@ -0,0 +1,2 @@
+-- Keep Hop's defaults. Your existing Hop mappings live in 01-mappings.lua.
+require('hop').setup({})
diff --git a/lua/config/99-lualine-config.lua b/lua/config/99-lualine-config.lua
new file mode 100644
index 0000000..37b8821
--- /dev/null
+++ b/lua/config/99-lualine-config.lua
@@ -0,0 +1,32 @@
+-- Based on the original lua/lualinesetup.lua.
+local function clients_lsp()
+ local clients = vim.lsp.get_clients({ bufnr = 0 })
+ if #clients == 0 then return '' end
+ local names = {}
+ for _, client in ipairs(clients) do names[#names + 1] = client.name end
+ return '\u{f085} ' .. table.concat(names, ',')
+end
+
+require('lualine').setup({
+ options = {
+ -- The old 'meltdown' theme needs a lualine/themes/meltdown.lua file.
+ -- 'auto' works even if that theme is absent.
+ theme = 'auto',
+ component_separators = '',
+ section_separators = { left = '', right = '' },
+ },
+ sections = {
+ lualine_a = { 'mode' },
+ lualine_b = { 'branch', 'diff', 'diagnostics' },
+ lualine_c = { 'filename' },
+ lualine_x = {},
+ lualine_y = {
+ { clients_lsp, color = { fg = '#80a0ff' } },
+ { 'encoding', color = { fg = '#80a0ff' } },
+ { 'fileformat', color = { fg = '#ffb700' } },
+ { 'filetype', color = { fg = '#80a0ff' } },
+ 'progress',
+ },
+ lualine_z = { 'location' },
+ },
+})
diff --git a/lua/config/99-nvim-surround-config.lua b/lua/config/99-nvim-surround-config.lua
new file mode 100644
index 0000000..839da9c
--- /dev/null
+++ b/lua/config/99-nvim-surround-config.lua
@@ -0,0 +1,2 @@
+-- Keep nvim-surround defaults as in the original configuration.
+require('nvim-surround').setup({})
diff --git a/lua/config/99-nvim-treesitter-config.lua b/lua/config/99-nvim-treesitter-config.lua
new file mode 100644
index 0000000..57d84a9
--- /dev/null
+++ b/lua/config/99-nvim-treesitter-config.lua
@@ -0,0 +1,86 @@
+-- Current nvim-treesitter main branch + nvim-treesitter-textobjects main branch.
+-- Requires Neovim >= 0.12, tree-sitter CLI, a C compiler, and both plugins.
+-- The old nvim-treesitter.configs module no longer exists on main.
+
+local ts = require('nvim-treesitter')
+local textobjects = require('nvim-treesitter-textobjects')
+
+-- Install parsers explicitly with :TSInstall <language> or
+-- :lua require('nvim-treesitter').install({ 'lua', 'vim', 'c' })
+-- Update installed parsers after plugin updates with :TSUpdate.
+-- Unlike the old API, there is no auto_install/sync_install option.
+
+-- Enable highlighting for buffers with installed parsers, except for large
+-- files. Core Neovim supplies highlighting; nvim-treesitter supplies parsers.
+local max_filesize = 100 * 1024
+local group = vim.api.nvim_create_augroup('UserTreesitterHighlight', { clear = true })
+vim.api.nvim_create_autocmd('FileType', {
+ group = group,
+ callback = function(args)
+ local buf = args.buf
+ local name = vim.api.nvim_buf_get_name(buf)
+ if name ~= '' then
+ local stat = vim.uv.fs_stat(name)
+ if stat and stat.size > max_filesize then
+ return
+ end
+ end
+ -- Don't error for filetypes without an installed parser.
+ pcall(vim.treesitter.start, buf)
+ end,
+})
+
+textobjects.setup({
+ select = {
+ lookahead = true,
+ selection_modes = {
+ ['@parameter.outer'] = 'v',
+ ['@function.outer'] = 'V',
+ ['@function.inner'] = 'V',
+ ['@block.inner'] = 'V',
+ ['@block.outer'] = 'V',
+ },
+ -- Corrected from the original pattern '^function', which could never
+ -- match a capture name beginning with '@'.
+ include_surrounding_whitespace = function(q)
+ return q.query_string:match('%.inner$') == nil
+ and q.query_string:match('^@function') ~= nil
+ end,
+ },
+ move = { set_jumps = true },
+})
+
+local select = require('nvim-treesitter-textobjects.select')
+local move = require('nvim-treesitter-textobjects.move')
+local selections = {
+ am = '@function.outer', im = '@function.inner',
+ af = '@function.outer', ['if'] = '@function.inner',
+ aC = '@class.outer', iC = '@class.inner',
+ aa = '@parameter.outer', ia = '@parameter.inner',
+ iq = '@block.inner', aq = '@block.outer',
+ ['a;'] = '@statement.outer', ['i;'] = '@statement.inner',
+}
+for lhs, query in pairs(selections) do
+ vim.keymap.set({ 'x', 'o' }, lhs, function()
+ select.select_textobject(query, 'textobjects')
+ end, { desc = 'Tree-sitter select ' .. query })
+end
+
+-- The original mapping references a custom capture; it only works when
+-- you provide a matching textobjects query for the current language.
+for lhs, query in pairs({
+ [']C'] = '@injectable_constructor.params.inner',
+ [']c'] = '@class.outer',
+}) do
+ vim.keymap.set({ 'n', 'x', 'o' }, lhs, function()
+ move.goto_next_start(query, 'textobjects')
+ end)
+end
+for lhs, query in pairs({
+ ['[C'] = '@injectable_constructor.params.inner',
+ ['[c'] = '@class.outer',
+}) do
+ vim.keymap.set({ 'n', 'x', 'o' }, lhs, function()
+ move.goto_previous_start(query, 'textobjects')
+ end)
+end
diff --git a/lua/config/99-nvim-web-devicons-config.lua b/lua/config/99-nvim-web-devicons-config.lua
new file mode 100644
index 0000000..6450096
--- /dev/null
+++ b/lua/config/99-nvim-web-devicons-config.lua
@@ -0,0 +1,2 @@
+-- Optional: setup isn't required for default devicons behavior.
+require('nvim-web-devicons').setup({ default = true })
diff --git a/lua/config/99-telescope-config.lua b/lua/config/99-telescope-config.lua
new file mode 100644
index 0000000..054c701
--- /dev/null
+++ b/lua/config/99-telescope-config.lua