diff options
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/config/00-options.lua | 42 | ||||
| -rw-r--r-- | lua/config/01-plugins.lua | 56 | ||||
| -rw-r--r-- | lua/config/02-mappings.lua | 148 | ||||
| -rw-r--r-- | lua/config/03-commands.lua | 85 | ||||
| -rw-r--r-- | lua/config/04-autocmds.lua | 67 | ||||
| -rw-r--r-- | lua/config/05-lsp.lua | 141 | ||||
| -rw-r--r-- | lua/config/99-extregs-config.lua | 17 | ||||
| -rw-r--r-- | lua/config/99-gitsigns-config.lua | 27 | ||||
| -rw-r--r-- | lua/config/99-hop-config.lua | 2 | ||||
| -rw-r--r-- | lua/config/99-lualine-config.lua | 32 | ||||
| -rw-r--r-- | lua/config/99-nvim-surround-config.lua | 2 | ||||
| -rw-r--r-- | lua/config/99-nvim-treesitter-config.lua | 86 | ||||
| -rw-r--r-- | lua/config/99-nvim-web-devicons-config.lua | 2 | ||||
| -rw-r--r-- | lua/config/99-telescope-config.lua | 19 | ||||
| -rw-r--r-- | lua/config/99-treesitter-config.lua | 87 | ||||
| -rw-r--r-- | lua/diagnostics.lua | 55 | ||||
| -rw-r--r-- | lua/lsp.lua | 308 | ||||
| -rw-r--r-- | lua/lualinesetup.lua | 47 | ||||
| -rw-r--r-- | lua/tabby.lua | 32 | ||||
| -rw-r--r-- | lua/treesitter-textobjects-setup.lua | 52 | ||||
| -rw-r--r-- | lua/treesitter.lua | 45 | ||||
| -rw-r--r-- | lua/windownav.lua | 76 |
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 @@ -0,0 +1,19 @@ +-- Telescope configuration migrated from init.vim. +-- Keybindings remain in 01-mappings.lua. +require('telescope').setup({ + defaults = { + title = '', + borderchars = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, + prompt_prefix = '🞂 ', + selection_caret = '🞂 ', + layout_strategy = 'horizontal', + results_title = false, + sorting_strategy = 'ascending', + layout_config = { + horizontal = { width = 0.66, height = 0.66 }, + }, + }, + pickers = { + find_files = { hidden = true }, + }, +}) diff --git a/lua/config/99-treesitter-config.lua b/lua/config/99-treesitter-config.lua new file mode 100644 index 0000000..5b81c7e --- /dev/null +++ b/lua/config/99-treesitter-config.lua @@ -0,0 +1,87 @@ +-- 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 < |