From cdabfba9747d503de4f51798a8a1edd318a6b803 Mon Sep 17 00:00:00 2001 From: Hank Hua Date: Wed, 2 Sep 2026 15:09:46 +0100 Subject: [PATCH 1/3] Add some more plugins. --- init.lua | 1 + lua/custom/keymaps.lua | 12 +++++++ lua/custom/options.lua | 12 +++++++ lua/custom/plugins/aerial.lua | 29 +++++++++++++++++ lua/custom/plugins/bqf.lua | 23 ++++++++++++++ lua/custom/plugins/clangd.lua | 4 +++ lua/custom/plugins/diagnostics.lua | 8 +++++ lua/custom/plugins/file-explorer.lua | 16 +++++++++- lua/custom/plugins/hlslens.lua | 4 +++ lua/custom/plugins/motion.lua | 9 ++++++ lua/custom/plugins/surround.lua | 1 + lua/custom/plugins/terminal.lua | 11 +++++++ lua/custom/plugins/themes.lua | 12 ++++++- lua/custom/plugins/treesitter-context.lua | 1 + nvim-pack-lock.json | 38 ++++++++++++++++++++++- 15 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 lua/custom/plugins/aerial.lua create mode 100644 lua/custom/plugins/bqf.lua create mode 100644 lua/custom/plugins/clangd.lua create mode 100644 lua/custom/plugins/diagnostics.lua create mode 100644 lua/custom/plugins/hlslens.lua create mode 100644 lua/custom/plugins/motion.lua create mode 100644 lua/custom/plugins/surround.lua create mode 100644 lua/custom/plugins/treesitter-context.lua diff --git a/init.lua b/init.lua index 84dd19d..87b6aee 100644 --- a/init.lua +++ b/init.lua @@ -983,6 +983,7 @@ do -- NOTE: You can add your own plugins, configuration, etc from `lua/custom/plugins/*.lua` -- -- Uncomment the following line and add your plugins to `lua/custom/plugins/*.lua` to get going. + require 'custom.options' require 'custom.plugins' require 'custom.keymaps' end diff --git a/lua/custom/keymaps.lua b/lua/custom/keymaps.lua index e69de29..88a9ac0 100644 --- a/lua/custom/keymaps.lua +++ b/lua/custom/keymaps.lua @@ -0,0 +1,12 @@ +-- Exit insert mode quickly +vim.keymap.set('i', 'jj', '') + +-- Split the line under the cursor (the opposite of `J`) +-- NOTE: intentionally overrides Neovim's default `K` (LSP hover) +vim.keymap.set('n', 'K', 'i') + +-- Accept the first spelling suggestion for the word under the cursor +vim.keymap.set('n', 'zn', 'z=1') + +-- Free up `` (init.lua's default duplicated `bf` from custom/plugins/buffers.lua) +vim.keymap.del('n', '') diff --git a/lua/custom/options.lua b/lua/custom/options.lua index 3cace7e..9d7775e 100644 --- a/lua/custom/options.lua +++ b/lua/custom/options.lua @@ -2,3 +2,15 @@ vim.opt.tabstop = 2 vim.opt.shiftwidth = 2 vim.opt.expandtab = true vim.opt.smartindent = true + +vim.opt.wrap = true +vim.opt.conceallevel = 2 +vim.o.cmdheight = 2 + +-- Treesitter-based folding, but don't fold on file open +vim.o.foldmethod = 'expr' +vim.o.foldexpr = 'v:lua.vim.treesitter.foldexpr()' +vim.o.foldenable = false + +-- Prefer the floating diagnostic window (see LspAttach `jump.on_jump`) over inline virtual text +vim.diagnostic.config { virtual_text = false } diff --git a/lua/custom/plugins/aerial.lua b/lua/custom/plugins/aerial.lua new file mode 100644 index 0000000..e68450b --- /dev/null +++ b/lua/custom/plugins/aerial.lua @@ -0,0 +1,29 @@ +-- Code outline / symbol navigation +vim.pack.add { 'https://github.com/stevearc/aerial.nvim' } + +require('aerial').setup { + on_attach = function(bufnr) + vim.keymap.set('n', '{', 'AerialPrev', { buffer = bufnr }) + vim.keymap.set('n', '}', 'AerialNext', { buffer = bufnr }) + end, +} + +require('telescope').load_extension 'aerial' +require('telescope').setup { + extensions = { + aerial = { + col1_width = 4, + col2_width = 30, + format_symbol = function(symbol_path, filetype) + if filetype == 'json' or filetype == 'yaml' then + return table.concat(symbol_path, '.') + else + return symbol_path[#symbol_path] + end + end, + show_columns = 'both', + }, + }, +} + +vim.keymap.set('n', 'a', function() require('telescope').extensions.aerial.aerial() end, { desc = '[A]erial symbols' }) diff --git a/lua/custom/plugins/bqf.lua b/lua/custom/plugins/bqf.lua new file mode 100644 index 0000000..b499967 --- /dev/null +++ b/lua/custom/plugins/bqf.lua @@ -0,0 +1,23 @@ +-- Better quickfix window +vim.pack.add { 'https://github.com/kevinhwang91/nvim-bqf' } + +require('bqf').setup { + auto_enable = true, + preview = { + win_height = 12, + win_vheight = 12, + delay_syntax = 80, + border_chars = { '┃', '┃', '━', '━', '┏', '┓', '┗', '┛', '█' }, + }, + func_map = { + vsplit = '', + ptogglemode = 'z,', + stoggleup = '', + }, + filter = { + fzf = { + action_for = { ['ctrl-s'] = 'split' }, + extra_opts = { '--bind', 'ctrl-o:toggle-all', '--prompt', '> ' }, + }, + }, +} diff --git a/lua/custom/plugins/clangd.lua b/lua/custom/plugins/clangd.lua new file mode 100644 index 0000000..4841ce7 --- /dev/null +++ b/lua/custom/plugins/clangd.lua @@ -0,0 +1,4 @@ +-- clangd sometimes needs utf-16 offset-encoding forced to play nicely with certain clients +vim.lsp.config('clangd', { + cmd = { 'clangd', '--offset-encoding=utf-16' }, +}) diff --git a/lua/custom/plugins/diagnostics.lua b/lua/custom/plugins/diagnostics.lua new file mode 100644 index 0000000..1c7624c --- /dev/null +++ b/lua/custom/plugins/diagnostics.lua @@ -0,0 +1,8 @@ +-- Alternative diagnostics display (native virtual_text is disabled in custom/options.lua) +vim.pack.add { 'https://github.com/casonadams/simple-diagnostics.nvim' } + +require('simple-diagnostics').setup { + virtual_text = true, + message_area = true, + signs = true, +} diff --git a/lua/custom/plugins/file-explorer.lua b/lua/custom/plugins/file-explorer.lua index 3bd9491..0783d9f 100644 --- a/lua/custom/plugins/file-explorer.lua +++ b/lua/custom/plugins/file-explorer.lua @@ -2,6 +2,20 @@ vim.g.loaded_netrw = 1 vim.g.loaded_netrwPlugin = 1 vim.pack.add { 'https://github.com/nvim-tree/nvim-tree.lua' } -require('nvim-tree').setup {} +require('nvim-tree').setup { + update_focused_file = { + enable = true, + update_root = false, + }, + on_attach = function(bufnr) + local api = require 'nvim-tree.api' + api.config.mappings.default_on_attach(bufnr) + + local opts = function(desc) return { desc = 'nvim-tree: ' .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } end + -- h/l aren't bound by nvim-tree's defaults anymore; restore the close/open behaviour + vim.keymap.set('n', 'h', api.node.navigate.parent_close, opts 'Close Directory') + vim.keymap.set('n', 'l', api.node.open.edit, opts 'Open') + end, +} vim.keymap.set('n', 'e', 'NvimTreeToggle', { desc = 'Toggle file [E]xplorer' }) diff --git a/lua/custom/plugins/hlslens.lua b/lua/custom/plugins/hlslens.lua new file mode 100644 index 0000000..4b56dcb --- /dev/null +++ b/lua/custom/plugins/hlslens.lua @@ -0,0 +1,4 @@ +-- Better search match indicators +vim.pack.add { 'https://github.com/kevinhwang91/nvim-hlslens' } + +require('hlslens').setup() diff --git a/lua/custom/plugins/motion.lua b/lua/custom/plugins/motion.lua new file mode 100644 index 0000000..05935d7 --- /dev/null +++ b/lua/custom/plugins/motion.lua @@ -0,0 +1,9 @@ +-- Fast on-screen motion +vim.pack.add { + 'https://github.com/smoka7/hop.nvim', + -- leap.nvim moved off GitHub; github.com/ggandor/leap.nvim was emptied by the author + 'https://codeberg.org/andyg/leap.nvim', +} + +require('hop').setup { keys = 'etovxqpdygfblzhckisuran', term_seq_bias = 0.5 } +require('leap').add_default_mappings() diff --git a/lua/custom/plugins/surround.lua b/lua/custom/plugins/surround.lua new file mode 100644 index 0000000..53f4afe --- /dev/null +++ b/lua/custom/plugins/surround.lua @@ -0,0 +1 @@ +vim.pack.add { 'https://github.com/tpope/vim-surround' } diff --git a/lua/custom/plugins/terminal.lua b/lua/custom/plugins/terminal.lua index 88d23ff..0a4ca79 100644 --- a/lua/custom/plugins/terminal.lua +++ b/lua/custom/plugins/terminal.lua @@ -8,3 +8,14 @@ require('toggleterm').setup { border = 'curved', }, } + +-- Lazygit in a floating terminal +local Terminal = require('toggleterm.terminal').Terminal +local lazygit = Terminal:new { + cmd = 'lazygit', + hidden = true, + direction = 'float', + float_opts = { border = 'curved' }, +} + +vim.keymap.set('n', 'gg', function() lazygit:toggle() end, { desc = '[G]it: Lazy[g]it' }) diff --git a/lua/custom/plugins/themes.lua b/lua/custom/plugins/themes.lua index 754f933..38002fa 100644 --- a/lua/custom/plugins/themes.lua +++ b/lua/custom/plugins/themes.lua @@ -1,2 +1,12 @@ -vim.pack.add { 'https://github.com/LunarVim/onedarker.nvim' } +vim.pack.add { + 'https://github.com/LunarVim/onedarker.nvim', + 'https://github.com/neanias/everforest-nvim', +} -- to switch: vim.cmd.colorscheme 'onedarker' + +require('everforest').setup { + on_highlights = function(hl, palette) hl.Conceal = { fg = palette.none, bg = palette.none, sp = palette.none } end, +} + +-- Overrides the 'tokyonight-night' default set in init.lua +vim.cmd.colorscheme 'everforest' diff --git a/lua/custom/plugins/treesitter-context.lua b/lua/custom/plugins/treesitter-context.lua new file mode 100644 index 0000000..029df15 --- /dev/null +++ b/lua/custom/plugins/treesitter-context.lua @@ -0,0 +1 @@ +vim.pack.add { 'https://github.com/nvim-treesitter/nvim-treesitter-context' } diff --git a/nvim-pack-lock.json b/nvim-pack-lock.json index be016fc..ad088d8 100644 --- a/nvim-pack-lock.json +++ b/nvim-pack-lock.json @@ -5,6 +5,10 @@ "src": "https://github.com/L3MON4D3/LuaSnip", "version": "2.0.0 - 3.0.0" }, + "aerial.nvim": { + "rev": "28fe6e822ae344544c379d60fcb13c9519a1f08a", + "src": "https://github.com/stevearc/aerial.nvim" + }, "auto-session": { "rev": "c8e6139a2e52a38101fecaba6014d7dd75489044", "src": "https://github.com/rmagatti/auto-session" @@ -26,6 +30,10 @@ "rev": "a12fd5672110c8aa7e3c8419e28c96943ca179be", "src": "https://github.com/github/copilot.vim" }, + "everforest-nvim": { + "rev": "a0e9edc57379e8feafc6ba207c26dbb12fc1b6d8", + "src": "https://github.com/neanias/everforest-nvim" + }, "fidget.nvim": { "rev": "6f793b2bcd2d35e201c09520f698bb763220908a", "src": "https://github.com/j-hui/fidget.nvim" @@ -38,6 +46,14 @@ "rev": "84a4987ff36798c2fc1169cbaff67960aed9776f", "src": "https://github.com/NMAC427/guess-indent.nvim" }, + "hop.nvim": { + "rev": "6e83486f351066e38c3ae9daad2a4f01dfb262ad", + "src": "https://github.com/smoka7/hop.nvim" + }, + "leap.nvim": { + "rev": "38af0ab56c6eb8757ee6006dd13ab79c2bc11a49", + "src": "https://codeberg.org/andyg/leap.nvim" + }, "mason-lspconfig.nvim": { "rev": "40276c4df7e6bdce6801d6c035c6227f9115a855", "src": "https://github.com/mason-org/mason-lspconfig.nvim" @@ -54,6 +70,14 @@ "rev": "fb2bbae327f3c306f3c825031345b89dd176ce60", "src": "https://github.com/nvim-mini/mini.nvim" }, + "nvim-bqf": { + "rev": "c282a62bec6c0621a1ef5132aa3f4c9fc4dcc2c7", + "src": "https://github.com/kevinhwang91/nvim-bqf" + }, + "nvim-hlslens": { + "rev": "be2d7b2be01860b5445a007ff2bc72b29896db6b", + "src": "https://github.com/kevinhwang91/nvim-hlslens" + }, "nvim-lspconfig": { "rev": "684cb45c2faa24ce463b4fe9aaf011bfe1e0fb26", "src": "https://github.com/neovim/nvim-lspconfig" @@ -67,6 +91,10 @@ "src": "https://github.com/nvim-treesitter/nvim-treesitter", "version": "'main'" }, + "nvim-treesitter-context": { + "rev": "f3061339b8eaf9fda873600bc425b8d2d8502533", + "src": "https://github.com/nvim-treesitter/nvim-treesitter-context" + }, "onedarker.nvim": { "rev": "b4f92f073ed7cdf0358ad005cee0484411232b1b", "src": "https://github.com/LunarVim/onedarker.nvim" @@ -75,6 +103,10 @@ "rev": "74b06c6c75e4eeb3108ec01852001636d85a932b", "src": "https://github.com/nvim-lua/plenary.nvim" }, + "simple-diagnostics.nvim": { + "rev": "3b662c9a2c9f979997a5156602d661da043badba", + "src": "https://github.com/casonadams/simple-diagnostics.nvim" + }, "telescope-fzf-native.nvim": { "rev": "b25b749b9db64d375d782094e2b9dce53ad53a40", "src": "https://github.com/nvim-telescope/telescope-fzf-native.nvim" @@ -103,9 +135,13 @@ "rev": "d0015a0f86150c59fb55f65b41529e6ff4469e18", "src": "https://github.com/raivivek/vim-snakemake" }, + "vim-surround": { + "rev": "3d188ed2113431cf8dac77be61b842acb64433d9", + "src": "https://github.com/tpope/vim-surround" + }, "which-key.nvim": { "rev": "3aab2147e74890957785941f0c1ad87d0a44c15a", "src": "https://github.com/folke/which-key.nvim" } } -} +} \ No newline at end of file From 161c76e64725a07376a7cfe502332e3d0058368d Mon Sep 17 00:00:00 2001 From: Hank Hua Date: Wed, 2 Sep 2026 16:20:04 +0100 Subject: [PATCH 2/3] Add vimtex. --- lua/custom/plugins/vimtex.lua | 13 +++++++++++++ nvim-pack-lock.json | 5 +++++ 2 files changed, 18 insertions(+) create mode 100644 lua/custom/plugins/vimtex.lua diff --git a/lua/custom/plugins/vimtex.lua b/lua/custom/plugins/vimtex.lua new file mode 100644 index 0000000..533bc21 --- /dev/null +++ b/lua/custom/plugins/vimtex.lua @@ -0,0 +1,13 @@ +vim.pack.add { + { src = 'https://github.com/lervag/vimtex', version = 'v2.15' }, +} + +vim.g.vimtex_fold_enabled = 1 +vim.g.vimtex_view_method = 'zathura' +vim.g.vimtex_callback_progpath = vim.v.progpath +vim.g.vimtex_compiler_latexmk = { + options = { '-shell-escape', '-verbose', '-file-line-error', '-synctex=1', '-interaction=nonstopmode' }, +} + +vim.g.vimtex_quickfix_ignore_filters = { 'Overfull \\hbox', 'Underfull \\hbox' } +vim.g.vimtex_quickfix_open_on_warning = 0 diff --git a/nvim-pack-lock.json b/nvim-pack-lock.json index ad088d8..d0de04e 100644 --- a/nvim-pack-lock.json +++ b/nvim-pack-lock.json @@ -139,6 +139,11 @@ "rev": "3d188ed2113431cf8dac77be61b842acb64433d9", "src": "https://github.com/tpope/vim-surround" }, + "vimtex": { + "rev": "9f6a5bb0a9c9f1542fe88dc07511ce8401242e2a", + "src": "https://github.com/lervag/vimtex", + "version": "'v2.15'" + }, "which-key.nvim": { "rev": "3aab2147e74890957785941f0c1ad87d0a44c15a", "src": "https://github.com/folke/which-key.nvim" From 874c15c76411e2ccec07b92c5cfa62eb595ed8b6 Mon Sep 17 00:00:00 2001 From: Yuhan Hua Date: Thu, 17 Sep 2026 09:29:06 -0700 Subject: [PATCH 3/3] Fix clipboard and improve terminal. --- lua/custom/options.lua | 21 ++++++ lua/custom/plugins/terminal.lua | 109 +++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/lua/custom/options.lua b/lua/custom/options.lua index 9d7775e..362e1ef 100644 --- a/lua/custom/options.lua +++ b/lua/custom/options.lua @@ -14,3 +14,24 @@ vim.o.foldenable = false -- Prefer the floating diagnostic window (see LspAttach `jump.on_jump`) over inline virtual text vim.diagnostic.config { virtual_text = false } + +-- Fix remote clipboard +if vim.env.SSH_TTY and not (vim.env.DISPLAY or vim.env.WAYLAND_DISPLAY) then + local osc52 = require 'vim.ui.clipboard.osc52' + + local cached = {} + local function copy(reg) + local send = osc52.copy(reg) + return function(lines, regtype) + cached = { lines, regtype } + send(lines) + end + end + local function paste() return cached end + + vim.g.clipboard = { + name = 'OSC 52', + copy = { ['+'] = copy '+', ['*'] = copy '*' }, + paste = { ['+'] = paste, ['*'] = paste }, + } +end diff --git a/lua/custom/plugins/terminal.lua b/lua/custom/plugins/terminal.lua index 0a4ca79..bcb29b7 100644 --- a/lua/custom/plugins/terminal.lua +++ b/lua/custom/plugins/terminal.lua @@ -9,13 +9,116 @@ require('toggleterm').setup { }, } --- Lazygit in a floating terminal -local Terminal = require('toggleterm.terminal').Terminal +local terms = require 'toggleterm.terminal' +local Terminal = terms.Terminal + +-- Focus terminal `id`, closing any other open toggleterm first so floats swap +-- rather than stack (NToggleTerm on its own only opens N, it does not close the +-- rest). Reachable from normal, insert and terminal mode, since a count prefix +-- like 2 can only be typed in normal mode. +local function focus_term(id) + if vim.startswith(vim.fn.mode(), 'i') then vim.cmd 'stopinsert' end + for _, term in ipairs(terms.get_all(true)) do + if term.id ~= id and term:is_open() then term:close() end + end + local term = terms.get(id) + if term and term:is_open() then + term:focus() + vim.cmd 'startinsert' + else + vim.cmd(id .. 'ToggleTerm') + end +end + +for i = 1, 5 do + vim.keymap.set({ 'n', 'i', 't' }, '', function() focus_term(i) end, { desc = 'Terminal ' .. i }) +end + +local function term_label(term) + local name = term.display_name + if not name then + local cmd = term.name and vim.split(term.name, ';')[1] or term.cmd or vim.o.shell + if type(cmd) == 'table' then cmd = table.concat(cmd, ' ') end + name = vim.fn.fnamemodify(vim.split(cmd, ' ')[1], ':t') + end + return string.format('%d: %-18s %s', term.id, name, term.dir and vim.fn.fnamemodify(term.dir, ':~') or '') +end + +-- Telescope picker over the toggleterms, previewing each one's scrollback. +-- :Telescope buffers can't do this: toggleterm sets buflisted = false on its +-- buffers and builtin.buffers only lists listed ones. +local function term_picker() + local all = terms.get_all() + if #all == 0 then return vim.notify('No toggleterms open yet', vim.log.levels.INFO) end + + local pickers = require 'telescope.pickers' + local finders = require 'telescope.finders' + local previewers = require 'telescope.previewers' + local actions = require 'telescope.actions' + local action_state = require 'telescope.actions.state' + local conf = require('telescope.config').values + + pickers + .new({}, { + prompt_title = 'Terminals', + finder = finders.new_table { + results = all, + entry_maker = function(term) + local label = term_label(term) + return { value = term, ordinal = label, display = label, bufnr = term.bufnr } + end, + }, + sorter = conf.generic_sorter {}, + previewer = previewers.new_buffer_previewer { + title = 'Terminal', + define_preview = function(self, entry) + local lines = { '(not started)' } + if entry.bufnr and vim.api.nvim_buf_is_valid(entry.bufnr) then + lines = vim.api.nvim_buf_get_lines(entry.bufnr, 0, -1, false) + -- terminal buffers are padded out to the window height with blanks + while #lines > 1 and lines[#lines]:match '^%s*$' do + table.remove(lines) + end + end + vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines) + -- park the preview on the newest output rather than the top + vim.schedule(function() + if vim.api.nvim_win_is_valid(self.state.winid) then + vim.api.nvim_win_set_cursor(self.state.winid, { #lines, 0 }) + vim.api.nvim_win_call(self.state.winid, function() vim.cmd 'normal! zb' end) + end + end) + end, + }, + attach_mappings = function(prompt_bufnr) + actions.select_default:replace(function() + local entry = action_state.get_selected_entry() + actions.close(prompt_bufnr) + if entry then focus_term(entry.value.id) end + end) + return true + end, + }) + :find() +end + +vim.keymap.set('n', 'tt', term_picker, { desc = '[T]oggle: pick [t]erminal' }) +vim.keymap.set({ 'i', 't' }, '', term_picker, { desc = 'Pick terminal' }) + +-- Lazygit in a floating terminal. Pinned to a high id: ids are handed out by +-- next_id() starting at 1, so an unpinned hidden terminal would claim id 1 and +-- / 1ToggleTerm would then toggle lazygit instead of a shell. local lazygit = Terminal:new { + id = 99, cmd = 'lazygit', hidden = true, direction = 'float', float_opts = { border = 'curved' }, } -vim.keymap.set('n', 'gg', function() lazygit:toggle() end, { desc = '[G]it: Lazy[g]it' }) +vim.keymap.set('n', 'gg', function() + -- toggleterm would termopen a missing binary, then close_on_exit tears the + -- float straight back down, so the keymap looks like it does nothing + if vim.fn.executable 'lazygit' == 0 then return vim.notify('lazygit not found on PATH', vim.log.levels.WARN) end + lazygit:toggle() +end, { desc = '[G]it: Lazy[g]it' })