From 072e6ae564cf5402646028d14c63d44b42a40060 Mon Sep 17 00:00:00 2001 From: Phillip Michelsen Date: Sat, 6 Jun 2026 23:05:31 +0800 Subject: [PATCH] Nvim change and sway update --- machines/desktop/config/nvim/init.lua | 951 ++++++--------------- machines/desktop/config/nvim/init2.lua.bak | 843 ++++++++++++++++++ machines/desktop/config/sway/config | 1 + 3 files changed, 1104 insertions(+), 691 deletions(-) create mode 100644 machines/desktop/config/nvim/init2.lua.bak diff --git a/machines/desktop/config/nvim/init.lua b/machines/desktop/config/nvim/init.lua index 18de098..af8551c 100644 --- a/machines/desktop/config/nvim/init.lua +++ b/machines/desktop/config/nvim/init.lua @@ -1,409 +1,105 @@ --- phill Neovim config (nightly) +-- ~/.config/nvim/init.lua + +-- ============================================================================ +-- Leader +-- ============================================================================ vim.g.mapleader = " " vim.g.maplocalleader = " " -local opt = vim.opt -local map = vim.keymap.set - -- ============================================================================ --- Core options +-- Options -- ============================================================================ -opt.number = true -opt.relativenumber = true -opt.mouse = "a" -opt.clipboard = "unnamedplus" +vim.o.number = true +vim.o.relativenumber = true +vim.o.mouse = "a" +vim.opt.cursorline = true +vim.o.clipboard = "unnamedplus" +vim.o.swapfile = false +vim.o.backup = false +vim.o.writebackup = false +vim.o.undofile = true -opt.swapfile = false -opt.backup = false -opt.writebackup = false -opt.undofile = true +vim.o.ignorecase = true +vim.o.smartcase = true -opt.ignorecase = true -opt.smartcase = true -opt.incsearch = true -opt.hlsearch = false +vim.o.signcolumn = "yes" +vim.o.splitright = true +vim.o.splitbelow = true -opt.termguicolors = true -opt.signcolumn = "yes" -opt.cursorline = true -opt.splitbelow = true -opt.splitright = true -opt.wrap = false -opt.linebreak = true -opt.breakindent = true -opt.scrolloff = 8 -opt.sidescrolloff = 8 -opt.updatetime = 200 -opt.timeoutlen = 300 -opt.confirm = true -opt.showmode = false -opt.laststatus = 3 -opt.pumheight = 12 --- opt.cmdheight = 0 +vim.o.termguicolors = true +vim.o.winborder = "rounded" -opt.expandtab = true -opt.smartindent = true -opt.shiftround = true -opt.tabstop = 2 -opt.softtabstop = 2 -opt.shiftwidth = 2 +vim.o.updatetime = 250 +vim.o.timeoutlen = 1000 -opt.list = true -opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } -opt.fillchars = { eob = " " } +vim.o.expandtab = true +vim.o.shiftwidth = 2 +vim.o.tabstop = 2 +vim.o.softtabstop = 2 -opt.completeopt = { "menu", "menuone", "noselect", "popup", "fuzzy" } -opt.winborder = "single" -opt.pumborder = "single" +vim.o.showmode = false -opt.winbar = "%=%m %t %=" -opt.showtabline = 0 +vim.o.completeopt = "menu,menuone,noselect" -- ============================================================================ --- Basic keymaps +-- Plugins -- ============================================================================ -map("n", "", "nohlsearch", { silent = true, desc = "Clear search highlight" }) - --- j/k over display lines when no count is given -map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { - expr = true, - silent = true, - desc = "Down (display line)", -}) -map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { - expr = true, - silent = true, - desc = "Up (display line)", -}) - --- Save on Ctrl-s -map("n", "", "update", { silent = true, desc = "Save" }) -map("i", "", "updategi", { silent = true, desc = "Save" }) -map("v", "", "updategv", { silent = true, desc = "Save" }) - --- Window navigation on Ctrl-hjkl -map("n", "", "h", { silent = true, desc = "Window left" }) -map("n", "", "j", { silent = true, desc = "Window down" }) -map("n", "", "k", { silent = true, desc = "Window up" }) -map("n", "", "l", { silent = true, desc = "Window right" }) - -map("t", "", [[h]], { silent = true, desc = "Window left" }) -map("t", "", [[j]], { silent = true, desc = "Window down" }) -map("t", "", [[k]], { silent = true, desc = "Window up" }) -map("t", "", [[l]], { silent = true, desc = "Window right" }) - --- Buffer cycling -map("n", "H", "bprevious", { silent = true, desc = "Previous buffer" }) -map("n", "L", "bnext", { silent = true, desc = "Next buffer" }) - --- ============================================================================ --- Buffer helpers --- ============================================================================ - -local function listed_buffers() - return vim.tbl_filter(function(buf) - return vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buflisted - end, vim.api.nvim_list_bufs()) -end - -local function delete_buffer(buf, opts) - opts = opts or {} - if not buf or buf == 0 then - buf = vim.api.nvim_get_current_buf() - end - - local cmd = opts.wipe - and (opts.force and "bwipeout!" or "bwipeout") - or (opts.force and "bdelete!" or "bdelete") - - pcall(vim.cmd, cmd .. " " .. buf) -end - -local function delete_other_buffers(force) - local current = vim.api.nvim_get_current_buf() - for _, buf in ipairs(listed_buffers()) do - if buf ~= current then - delete_buffer(buf, { force = force }) - end - end -end - -local function delete_all_buffers(force) - for _, buf in ipairs(listed_buffers()) do - delete_buffer(buf, { force = force }) - end -end - -map("n", "bb", "buffer #", { silent = true, desc = "Last buffer" }) -map("n", "bd", function() delete_buffer(0, { force = false }) end, { desc = "Delete buffer" }) -map("n", "bD", function() delete_buffer(0, { force = true }) end, { desc = "Force delete buffer" }) -map("n", "bw", function() delete_buffer(0, { wipe = true }) end, { desc = "Wipe buffer" }) -map("n", "bo", function() delete_other_buffers(false) end, { desc = "Delete other buffers" }) -map("n", "ba", function() delete_all_buffers(false) end, { desc = "Delete all buffers" }) - --- ============================================================================ --- netrw stays the default file browser --- ============================================================================ - -vim.g.netrw_banner = 1 -vim.g.netrw_liststyle = 3 -vim.g.netrw_winsize = 30 -vim.g.netrw_keepdir = 0 - -map("n", "E", "Ex", { silent = true, desc = "Open netrw" }) - -vim.api.nvim_create_autocmd("VimEnter", { - callback = function() - if vim.fn.argc() == 0 then - vim.cmd("Explore") - end - end, -}) - --- ============================================================================ --- Built-in package manager (nightly) --- ============================================================================ - --- Optional post-install hooks for plugins that usually need one-time setup. -vim.api.nvim_create_autocmd("PackChanged", { - callback = function(ev) - local data = ev.data or {} - local spec = data.spec or {} - local name = spec.name - local kind = data.kind - - if kind ~= "install" and kind ~= "update" then - return - end - - if name == "nvim-treesitter" then - vim.schedule(function() - pcall(vim.cmd.packadd, "nvim-treesitter") - pcall(function() - require("nvim-treesitter.install").update({ with_sync = true })() - end) - end) - end - - if name == "markdown-preview.nvim" then - vim.schedule(function() - pcall(vim.cmd.packadd, "markdown-preview.nvim") - pcall(function() - vim.fn["mkdp#util#install"]() - end) - end) - end - end, -}) - vim.pack.add({ - + { src = "https://github.com/vague-theme/vague.nvim" }, + { src = "https://github.com/neovim/nvim-lspconfig" }, + { src = "https://github.com/saghen/blink.lib" }, + { src = "https://github.com/saghen/blink.cmp" }, + { src = "https://github.com/nvim-treesitter/nvim-treesitter", version = "main" }, + { src = "https://github.com/echasnovski/mini.nvim" }, + { src = "https://github.com/nvim-neo-tree/neo-tree.nvim", version = vim.version.range("3") }, { src = "https://github.com/nvim-lua/plenary.nvim" }, { src = "https://github.com/MunifTanjim/nui.nvim" }, - { src = "https://github.com/nvim-tree/nvim-web-devicons" }, - - -- Themes - { src = "https://github.com/oskarnurm/koda.nvim" }, - { src = "https://github.com/vague-theme/vague.nvim" }, - { src = "https://github.com/nendix/zen.nvim" }, - { src = "https://github.com/rebelot/kanagawa.nvim" }, - - -- Editing / syntax / completion - { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, - - { src = "https://github.com/saghen/blink.cmp" }, - - { src = "https://github.com/L3MON4D3/LuaSnip" }, - { src = "https://github.com/rafamadriz/friendly-snippets" }, - { src = "https://gitlab.com/repetitivesin/madol.nvim" }, - - -- LSP configs (for vim.lsp.enable) - { src = "https://github.com/neovim/nvim-lspconfig" }, - - -- Navigation / search { src = "https://github.com/ibhagwan/fzf-lua" }, - { src = "https://github.com/nvim-neo-tree/neo-tree.nvim" }, - { src = "https://github.com/folke/flash.nvim" }, - { src = "https://github.com/leath-dub/snipe.nvim" }, - { src = "https://github.com/folke/which-key.nvim" }, - { src = "https://github.com/mikavilpas/yazi.nvim" }, - { src = "https://github.com/christoomey/vim-tmux-navigator"}, - - -- Git - { src = "https://github.com/tpope/vim-fugitive" }, { src = "https://github.com/lewis6991/gitsigns.nvim" }, - { src = "https://github.com/kdheepak/lazygit.nvim" }, - - -- Text objects / editing - { src = "https://github.com/kylechui/nvim-surround" }, - { src = "https://github.com/windwp/nvim-autopairs" }, - { src = "https://github.com/abecodes/tabout.nvim" }, - - -- UI - { src = "https://github.com/nvim-lualine/lualine.nvim" }, - { src = "https://github.com/chentoast/marks.nvim" }, - - -- Writing / docs - { src = "https://github.com/chomosuke/typst-preview.nvim" }, - { src = "https://github.com/iamcco/markdown-preview.nvim" }, - { src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" }, - - -- AI - { src = "https://github.com/nickjvandyke/opencode.nvim" }, - { src = "https://github.com/zbirenbaum/copilot.lua" }, - -}, { confirm = false, load = true }) - --- ============================================================================ --- Plugin globals before setup --- ============================================================================ - -vim.g.mkdp_auto_start = 0 -vim.g.mkdp_auto_close = 1 -vim.g.mkdp_filetypes = { "markdown" } - --- Let native LSP own LSP features; opencode still works for its own UI/actions. -vim.g.opencode_opts = { - lsp = { - enabled = false, - }, -} - -vim.o.autoread = true - --- ============================================================================ --- Themes --- ============================================================================ - -require("koda").setup({}) -require("vague").setup({}) -require("kanagawa").setup({ - compile = false, - background = { - dark = "wave", - light = "lotus", - }, + { src = "https://github.com/folke/which-key.nvim" }, + { src = "https://github.com/goolord/alpha-nvim" }, + { src = "https://github.com/nvim-tree/nvim-web-devicons" }, + { src = "https://github.com/christoomey/vim-tmux-navigator" }, + { src = "https://github.com/folke/todo-comments.nvim" }, }) -require("zen").setup({}) + +-- ============================================================================ +-- Theme +-- ============================================================================ vim.cmd.colorscheme("vague") -- ============================================================================ --- which-key +-- Diagnostics -- ============================================================================ -local wk = require("which-key") -wk.setup({ preset = "helix" }) - -wk.add({ - { "b", group = "buffer" }, - { "f", group = "find" }, - { "g", group = "git" }, - { "h", group = "hunks" }, - { "l", group = "lsp" }, - { "m", group = "marks" }, - { "o", group = "opencode" }, - { "t", group = "tree" }, - { "p", group = "preview" }, - { "u", group = "toggles" }, -}) - --- ============================================================================ --- vim-tmux-navigator --- ============================================================================ - -map("n", "", "TmuxNavigateLeft", { silent = true }) -map("n", "", "TmuxNavigateDown", { silent = true }) -map("n", "", "TmuxNavigateUp", { silent = true }) -map("n", "", "TmuxNavigateRight", { silent = true }) - - --- ============================================================================ --- Treesitter --- ============================================================================ - -require("nvim-treesitter").setup({ - ensure_installed = { - "bash", - "c", - "cpp", - "css", - "diff", - "html", - "javascript", - "json", - "json5", - "latex", - "lua", - "luadoc", - "markdown", - "markdown_inline", - "python", - "query", - "regex", - "rust", - "toml", - "tsx", - "typst", - "typescript", - "vim", - "vimdoc", - "yaml", +vim.diagnostic.config({ + virtual_text = true, + underline = true, + severity_sort = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = "E", + [vim.diagnostic.severity.WARN] = "W", + [vim.diagnostic.severity.INFO] = "I", + [vim.diagnostic.severity.HINT] = "H", + }, }, - auto_install = true, - highlight = { enable = true }, - indent = { enable = true }, }) -- ============================================================================ --- LuaSnip +-- Completion -- ============================================================================ -local ls = require("luasnip") - -ls.config.setup({ - history = true, - update_events = "TextChanged,TextChangedI", - delete_check_events = "TextChanged", - enable_autosnippets = true, -}) - -require("luasnip.loaders.from_vscode").lazy_load() - -require("madol").setup({ - rmarkdown = { - snippets = { - ["greek-tex"] = true, - ["greek-unicode"] = false - } - } -}) - -map({ "i", "s" }, "", function() - if ls.choice_active() then - ls.change_choice(1) - end -end, { desc = "LuaSnip next choice" }) - -map({ "i", "s" }, "", function() - if ls.choice_active() then - ls.change_choice(-1) - end -end, { desc = "LuaSnip previous choice" }) - --- ============================================================================ --- blink.cmp --- ============================================================================ +require("blink.cmp").build():pwait() require("blink.cmp").setup({ - snippets = { - preset = "luasnip", - }, completion = { menu = { auto_show = true }, + trigger = { show_on_trigger_character = true }, ghost_text = { enabled = false }, documentation = { auto_show = true, @@ -411,7 +107,7 @@ require("blink.cmp").setup({ }, list = { selection = { - preselect = true, + preselect = false, auto_insert = false, }, }, @@ -426,335 +122,194 @@ require("blink.cmp").setup({ [""] = { "accept", "fallback" }, - [""] = { "select_next", "fallback" }, - [""] = { "select_prev", "fallback" }, - - [""] = { "snippet_forward", "fallback" }, - [""] = { "snippet_backward", "fallback" }, - - + [""] = { "select_next", "fallback" }, + [""] = { "select_prev", "fallback" }, }, sources = { default = { "lsp", "path", "snippets", "buffer" }, }, fuzzy = { - implementation = "prefer_rust_with_warning", - prebuilt_binaries = { - force_version = "v1.9.1", - } + implementation = "rust", }, }) -- ============================================================================ --- Copilot --- Included, but practically "off by default" because auto_trigger = false. --- Toggle it on/off with uc. +-- Treesitter -- ============================================================================ -vim.api.nvim_create_autocmd("User", { - pattern = "BlinkCmpMenuOpen", - callback = function() - vim.b.copilot_suggestion_hidden = true +require("nvim-treesitter").setup({ + install_dir = vim.fn.stdpath("data") .. "/site", +}) + +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("treesitter_start", { clear = true }), + callback = function(args) + pcall(vim.treesitter.start, args.buf) end, }) -vim.api.nvim_create_autocmd("User", { - pattern = "BlinkCmpMenuClose", - callback = function() - vim.b.copilot_suggestion_hidden = false - end, -}) - -require("copilot").setup({ - panel = { - enabled = false, - }, - suggestion = { - enabled = true, - auto_trigger = false, - hide_during_completion = true, - keymap = { - accept = "", - next = "", - prev = "", - dismiss = "", - toggle_auto_trigger = false, - }, - }, -}) - -map("n", "ac", function() - require("copilot.suggestion").toggle_auto_trigger() -end, { desc = "Toggle Copilot auto-trigger" }) - -map("n", "ap", function() - require("copilot.panel").toggle() -end, { desc = "Toggle Copilot panel" }) - -- ============================================================================ --- autopairs / tabout / surround +-- mini.nvim -- ============================================================================ -require("nvim-autopairs").setup({ - check_ts = true, -}) +require("mini.ai").setup() +require("mini.surround").setup() +require("mini.pairs").setup() +require("mini.comment").setup() +require("mini.statusline").setup() +require("mini.tabline").setup() +require("mini.bracketed").setup() +require("mini.icons").setup() -require("tabout").setup({ - tabkey = "", - backwards_tabkey = "", - act_as_tab = true, - act_as_shift_tab = true, - default_tab = "", - default_shift_tab = "", - enable_backwards = true, - completion = false, - ignore_beginning = true, - tabouts = { - { open = "'", close = "'" }, - { open = '"', close = '"' }, - { open = "`", close = "`" }, - { open = "(", close = ")" }, - { open = "[", close = "]" }, - { open = "{", close = "}" }, - { open = "$", close = "$" }, - }, -}) +vim.api.nvim_set_hl(0, "MiniTablineCurrent", { link = "Search" }) +vim.api.nvim_set_hl(0, "MiniTablineModifiedCurrent", { link = "Search" }) + +vim.api.nvim_set_hl(0, "MiniTablineModifiedVisible", { link = "DiagnosticWarn" }) +vim.api.nvim_set_hl(0, "MiniTablineModifiedHidden", { link = "DiagnosticWarn" }) -require("nvim-surround").setup({}) -- ============================================================================ --- flash.nvim +-- Icons -- ============================================================================ -require("flash").setup({}) +require("nvim-web-devicons").setup() -map({ "n", "x", "o" }, "s", function() require("flash").jump() end, { desc = "Flash" }) -map({ "n", "x", "o" }, "S", function() require("flash").treesitter() end, { desc = "Flash Treesitter" }) -map("o", "r", function() require("flash").remote() end, { desc = "Remote Flash" }) -map({ "o", "x" }, "R", function() require("flash").treesitter_search() end, { desc = "Treesitter Search" }) -map("c", "", function() require("flash").toggle() end, { desc = "Toggle Flash Search" }) -- ============================================================================ --- marks.nvim +-- Todo comments -- ============================================================================ -require("marks").setup({ - default_mappings = true, - builtin_marks = { ".", "<", ">", "^" }, - cyclic = true, - force_write_shada = false, - refresh_interval = 250, -}) +require("todo-comments").setup() -map("n", "mb", "MarksListBuf", { silent = true, desc = "Marks in buffer" }) -map("n", "ma", "MarksListAll", { silent = true, desc = "All marks" }) -- ============================================================================ --- snipe.nvim --- ============================================================================ - -require("snipe").setup({ - ui = { - position = "center", - preselect_current = true, - text_align = "file-first", - }, - hints = { - dictionary = "sadflewcmpghio", - }, - navigate = { - cancel_snipe = "", - close_buffer = "D", - open_vsplit = "V", - open_split = "H", - }, - sort = "last", -}) - -map("n", "", function() require("snipe").open_buffer_menu() end, { desc = "Snipe buffers" }) - --- ============================================================================ --- Markdown / Typst --- ============================================================================ - -require("render-markdown").setup({ - file_types = { "markdown" }, - render_modes = { "n", "c", "t" }, -}) - -require("typst-preview").setup({ - follow_cursor = true, -}) - --- Typst -map("n", "ptp", "TypstPreview", { silent = true, desc = "Typst preview" }) -map("n", "ptP", "TypstPreviewToggle", { silent = true, desc = "Toggle Typst preview" }) - --- Markdown -map("n", "pmp", "MarkdownPreview", { silent = true, desc = "Markdown preview" }) -map("n", "pmr", "RenderMarkdown toggle", { silent = true, desc = "Toggle render-markdown" }) - --- ============================================================================ --- fzf-lua --- ============================================================================ - -require("fzf-lua").setup({ - actions = { - files = { - ["enter"] = require("fzf-lua.actions").file_edit, - } - } -}) - -map("n", "ff", function() require("fzf-lua").files() end, { desc = "Files" }) -map("n", "db", function() require("fzf-lua").buffers() end, { desc = "Buffers" }) -map("n", "bl", function() require("fzf-lua").buffers() end, { desc = "List buffers" }) -map("n", "ft", function() require("fzf-lua").live_grep() end, { desc = "Live grep" }) -map("n", "fs", function() require("fzf-lua").lsp_document_symbols() end, { desc = "Document symbols" }) -map("n", "/", function() require("fzf-lua").grep_curbuf() end, { desc = "Grep current buffer" }) -map("n", "fh", function() require("fzf-lua").help_tags() end, { desc = "Help tags" }) - --- useful extras -map("n", "fr", function() require("fzf-lua").oldfiles() end, { desc = "Recent files" }) -map("n", "fg", function() require("fzf-lua").git_files() end, { desc = "Git files" }) -map("n", "fc", function() require("fzf-lua").commands() end, { desc = "Commands" }) -map("n", "fk", function() require("fzf-lua").keymaps() end, { desc = "Keymaps" }) -map("n", "fd", function() require("fzf-lua").diagnostics_document() end, { desc = "Document diagnostics" }) -map("n", "fD", function() require("fzf-lua").diagnostics_workspace() end, { desc = "Workspace diagnostics" }) -map("n", "fw", function() require("fzf-lua").grep_cword() end, { desc = "Grep word under cursor" }) - --- ============================================================================ --- neo-tree --- netrw remains default; neo-tree is opt-in on n +-- File explorer -- ============================================================================ require("neo-tree").setup({ close_if_last_window = true, + popup_border_style = "", -- use vim.o.winborder on modern Neovim enable_git_status = true, enable_diagnostics = true, filesystem = { - hijack_netrw_behavior = "disabled", - follow_current_file = { enabled = true }, + follow_current_file = { + enabled = true, + }, use_libuv_file_watcher = true, }, window = { - width = 80, + width = 63, }, }) -map("n", "e", "Neotree position=right toggle", { - silent = true, - desc = "Neo-tree", +vim.keymap.set("n", "e", "Neotree filesystem reveal right toggle", { + desc = "File explorer", }) +vim.keymap.set("n", "E", "Neotree filesystem reveal current", { + desc = "File explorer full screen", +}) + +-- ============================================================================ +-- Picker +-- ============================================================================ + +require("fzf-lua").setup({ + { "fzf-native", "hide" }, + actions = { + files = { ["enter"] = require("fzf-lua.actions").file_edit } + }, + files = { + formatter = "path.filename_first", + }, + oldfiles = { + formatter = "path.filename_first", + }, + grep = { + rg_opts = "--column --line-number --no-heading --color=always --smart-case --max-columns=4096", + }, + winopts = { + width = 0.56, + height = 0.82, + row = 0.50, + col = 0.50, + preview = { + layout = "horizontal", + horizontal = "right:45%", + }, + }, +}) + +vim.keymap.set("n", "ff", function() + require("fzf-lua").files() +end, { desc = "Find files" }) + +vim.keymap.set("n", "fg", function() + require("fzf-lua").live_grep() +end, { desc = "Live grep" }) + +vim.keymap.set("n", "fb", function() + require("fzf-lua").buffers() +end, { desc = "Buffers" }) + +vim.keymap.set("n", "fh", function() + require("fzf-lua").helptags() +end, { desc = "Help tags" }) + +vim.keymap.set("n", "fr", function() + require("fzf-lua").resume() +end, { desc = "Resume picker" }) + +vim.keymap.set("n", "fd", function() + require("fzf-lua").diagnostics_document() +end, { desc = "Buffer diagnostics" }) + +vim.keymap.set("n", "fD", function() + require("fzf-lua").diagnostics_workspace() +end, { desc = "Workspace diagnostics" }) + +vim.keymap.set("n", "fo", function() + require("fzf-lua").oldfiles() +end, { desc = "Recent files" }) + +vim.keymap.set("n", "fc", function() + require("fzf-lua").git_status() +end, { desc = "Git status" }) + +-- ============================================================================ +-- Dashboard +-- ============================================================================ + +require("alpha").setup(require("alpha.themes.theta").config) + + -- ============================================================================ -- Git -- ============================================================================ -require("gitsigns").setup({ - signs = { - add = { text = "▎" }, - change = { text = "▎" }, - delete = { text = "" }, - topdelete = { text = "" }, - changedelete = { text = "▎" }, - untracked = { text = "▎" }, - }, - on_attach = function(bufnr) - local gs = package.loaded.gitsigns - - local function bufmap(mode, lhs, rhs, desc) - vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, desc = desc }) - end - - bufmap("n", "]h", gs.next_hunk, "Next hunk") - bufmap("n", "[h", gs.prev_hunk, "Prev hunk") - bufmap("n", "hs", gs.stage_hunk, "Stage hunk") - bufmap("n", "hr", gs.reset_hunk, "Reset hunk") - bufmap("n", "hS", gs.stage_buffer, "Stage buffer") - bufmap("n", "hR", gs.reset_buffer, "Reset buffer") - bufmap("n", "hp", gs.preview_hunk, "Preview hunk") - bufmap("n", "hb", function() gs.blame_line({ full = true }) end, "Blame line") - bufmap("n", "hd", gs.diffthis, "Diff this") - bufmap("n", "hQ", gs.setqflist, "Hunks to quickfix") - end, -}) - -map("n", "gg", "LazyGit", { silent = true, desc = "LazyGit" }) -map("n", "gs", "Git", { silent = true, desc = "Git status" }) -map("n", "gb", "Git blame", { silent = true, desc = "Git blame" }) -map("n", "gp", "Git push", { silent = true, desc = "Git push" }) -map("n", "gl", "Git pull", { silent = true, desc = "Git pull" }) -map("n", "gc", "Git commit", { silent = true, desc = "Git commit" }) +require("gitsigns").setup() -- ============================================================================ --- opencode.nvim +-- LSP -- ============================================================================ -map({ "n", "x" }, "oa", function() - require("opencode").ask("@this: ", { submit = true }) -end, { desc = "Ask opencode" }) +-- nvim-lspconfig supplies default configs for these. +-- Install the actual language server binaries separately: +-- lua-language-server +-- pyright +-- gopls -map({ "n", "x" }, "os", function() - require("opencode").select() -end, { desc = "Select opencode action" }) - -map({ "n", "t" }, "oo", function() - require("opencode").toggle() -end, { desc = "Toggle opencode" }) - -map({ "n", "x" }, "or", function() - return require("opencode").operator("@this ") -end, { expr = true, desc = "Send range to opencode" }) - -map("n", "ol", function() - return require("opencode").operator("@this ") .. "_" -end, { expr = true, desc = "Send line to opencode" }) - -map("n", "ou", function() - require("opencode").command("session.half.page.up") -end, { desc = "Opencode scroll up" }) - -map("n", "od", function() - require("opencode").command("session.half.page.down") -end, { desc = "Opencode scroll down" }) - --- ============================================================================ --- LSP (native nightly flow) --- No Mason. Install server binaries yourself and keep them on PATH. --- ============================================================================ - -local capabilities = require("blink.cmp").get_lsp_capabilities() - -vim.diagnostic.config({ - underline = true, - severity_sort = true, - update_in_insert = false, - virtual_text = { - spacing = 2, - source = "if_many", - }, - float = { - border = "rounded", - source = "if_many", - }, -}) - --- Global defaults for all enabled servers -vim.lsp.config("*", { - capabilities = capabilities, - root_markers = { ".git" }, -}) - --- Per-server overrides vim.lsp.config("lua_ls", { settings = { Lua = { + runtime = { + version = "LuaJIT", + }, diagnostics = { globals = { "vim" }, }, workspace = { - checkThirdParty = false, + library = vim.api.nvim_get_runtime_file("", true), }, telemetry = { enable = false, @@ -763,76 +318,90 @@ vim.lsp.config("lua_ls", { }, }) --- Adjust this list to the servers you actually have installed. -local servers = { - "gopls", +vim.lsp.enable({ "lua_ls", - "tinymist", - "marksman", "pyright", -} - -for _, server in ipairs(servers) do - vim.lsp.enable(server) -end + "gopls", +}) vim.api.nvim_create_autocmd("LspAttach", { - callback = function(ev) - local bufnr = ev.buf - - local function lmap(lhs, rhs, desc, mode) - vim.keymap.set(mode or "n", lhs, rhs, { buffer = bufnr, silent = true, desc = desc }) + group = vim.api.nvim_create_augroup("lsp_attach", { clear = true }), + callback = function(event) + local map = function(lhs, rhs, desc) + vim.keymap.set("n", lhs, rhs, { + buffer = event.buf, + desc = desc, + }) end - lmap("gd", vim.lsp.buf.definition, "Goto definition") - lmap("gD", vim.lsp.buf.declaration, "Goto declaration") - lmap("gi", vim.lsp.buf.implementation, "Goto implementation") - lmap("gt", vim.lsp.buf.type_definition, "Goto type definition") - lmap("gr", function() require("fzf-lua").lsp_references() end, "References") - lmap("K", vim.lsp.buf.hover, "Hover") - lmap("gK", vim.lsp.buf.signature_help, "Signature help") + -- Navigation + map("gd", vim.lsp.buf.definition, "Go to definition") + map("gD", vim.lsp.buf.declaration, "Go to declaration") + map("gi", vim.lsp.buf.implementation, "Go to implementation") - lmap("la", vim.lsp.buf.code_action, "Code action", { "n", "x" }) - lmap("lr", vim.lsp.buf.rename, "Rename") - lmap("lf", function() vim.lsp.buf.format({ async = true }) end, "Format") - lmap("ld", vim.diagnostic.open_float, "Line diagnostics") - lmap("ls", function() require("fzf-lua").lsp_document_symbols() end, "Document symbols") - lmap("lS", function() require("fzf-lua").lsp_live_workspace_symbols() end, "Workspace symbols") - - lmap("[d", function() vim.diagnostic.jump({ count = -1, float = true }) end, "Prev diagnostic") - lmap("]d", function() vim.diagnostic.jump({ count = 1, float = true }) end, "Next diagnostic") + -- Language / LSP actions + map("lr", vim.lsp.buf.rename, "LSP rename") + map("lf", function() + vim.lsp.buf.format({ async = true }) + end, "LSP format") + map("la", vim.lsp.buf.code_action, "LSP code action") + map("lh", vim.lsp.buf.hover, "LSP hover") + map("ls", vim.lsp.buf.signature_help, "LSP signature help") + map("ld", vim.diagnostic.open_float, "Line diagnostics") + map("lq", vim.diagnostic.setloclist, "Diagnostics to loclist") end, }) -- ============================================================================ --- lualine +-- General keymaps -- ============================================================================ -local function opencode_statusline() - local ok, opencode = pcall(require, "opencode") - if ok and opencode.statusline then - return opencode.statusline() - end - return "" -end +vim.keymap.set("n", "", "TmuxNavigateLeft", { silent = true }) +vim.keymap.set("n", "", "TmuxNavigateDown", { silent = true }) +vim.keymap.set("n", "", "TmuxNavigateUp", { silent = true }) +vim.keymap.set("n", "", "TmuxNavigateRight", { silent = true }) -require("lualine").setup({ - options = { - section_separators = "", - component_separators = "", - globalstatus = true, - theme = "auto", - }, - sections = { - lualine_a = { "mode" }, - lualine_b = { { "branch", icon = "" }, "diff" }, - lualine_c = { - { "diagnostics" }, - { "filename", path = 1, symbols = { modified = " ●", readonly = " " } }, - }, - lualine_x = { "encoding", "fileformat", "filetype", opencode_statusline }, - lualine_y = { "progress" }, - lualine_z = { "location" }, - }, +vim.keymap.set("n", "", "nohlsearch", { desc = "Clear search highlight" }) + +vim.keymap.set("n", "", "bprevious", { desc = "Previous buffer" }) +vim.keymap.set("n", "", "bnext", { desc = "Next buffer" }) + +vim.keymap.set("n", "bd", "bdelete", { desc = "Delete buffer" }) +vim.keymap.set("n", "bD", "bdelete!", { desc = "Force delete buffer" }) +vim.keymap.set("n", "bw", "bwipe", { desc = "Wipe buffers" }) +vim.keymap.set("n", "bW", "bwipe!", { desc = "Force wipe buffers" }) +vim.keymap.set("n", "bl", "ls", { desc = "List buffers" }) +vim.keymap.set("n", "bb", "buffer #", { desc = "Switch to last buffer" }) +vim.keymap.set("n", "bf", "bfirst", { desc = "First buffer" }) +vim.keymap.set("n", "bL", "blast", { desc = "Last buffer" }) + +vim.keymap.set("n", "[d", function() + vim.diagnostic.jump({ count = -1 }) +end, { + desc = "Previous diagnostic", +}) + +vim.keymap.set("n", "]d", function() + vim.diagnostic.jump({ count = 1 }) +end, { + desc = "Next diagnostic", +}) + + +-- ============================================================================ +-- Keymap help +-- ============================================================================ + +require("which-key").setup({ + preset = "helix", +}) + +require("which-key").add({ + { "e", desc = "File explorer" }, + { "E", desc = "File explorer full screen" }, + { "f", group = "find" }, + { "l", group = "language/lsp" }, + { "g", group = "git" }, + { "b", group = "buffer" }, }) diff --git a/machines/desktop/config/nvim/init2.lua.bak b/machines/desktop/config/nvim/init2.lua.bak new file mode 100644 index 0000000..4f166f4 --- /dev/null +++ b/machines/desktop/config/nvim/init2.lua.bak @@ -0,0 +1,843 @@ +-- phill Neovim config (nightly) + +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +local opt = vim.opt +local map = vim.keymap.set + +-- ============================================================================ +-- Core options +-- ============================================================================ + +opt.number = true +opt.relativenumber = true +opt.mouse = "a" +opt.clipboard = "unnamedplus" + +opt.swapfile = false +opt.backup = false +opt.writebackup = false +opt.undofile = true + +opt.ignorecase = true +opt.smartcase = true +opt.incsearch = true +opt.hlsearch = false + +opt.termguicolors = true +opt.signcolumn = "yes" +opt.cursorline = true +opt.splitbelow = true +opt.splitright = true +opt.wrap = false +opt.linebreak = true +opt.breakindent = true +opt.scrolloff = 8 +opt.sidescrolloff = 8 +opt.updatetime = 200 +opt.timeoutlen = 300 +opt.confirm = true +opt.showmode = false +opt.laststatus = 3 +opt.pumheight = 12 +-- opt.cmdheight = 0 + +opt.expandtab = true +opt.smartindent = true +opt.shiftround = true +opt.tabstop = 2 +opt.softtabstop = 2 +opt.shiftwidth = 2 + +opt.list = true +opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } +opt.fillchars = { eob = " " } + +opt.completeopt = { "menu", "menuone", "noselect", "popup", "fuzzy" } +opt.winborder = "single" +opt.pumborder = "single" + +opt.winbar = "%=%m %t %=" +opt.showtabline = 0 + +-- ============================================================================ +-- Basic keymaps +-- ============================================================================ + +map("n", "", "nohlsearch", { silent = true, desc = "Clear search highlight" }) + +-- j/k over display lines when no count is given +map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { + expr = true, + silent = true, + desc = "Down (display line)", +}) +map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { + expr = true, + silent = true, + desc = "Up (display line)", +}) + +-- Save on Ctrl-s +map("n", "", "update", { silent = true, desc = "Save" }) +map("i", "", "updategi", { silent = true, desc = "Save" }) +map("v", "", "updategv", { silent = true, desc = "Save" }) + +-- Window navigation on Ctrl-hjkl +map("n", "", "h", { silent = true, desc = "Window left" }) +map("n", "", "j", { silent = true, desc = "Window down" }) +map("n", "", "k", { silent = true, desc = "Window up" }) +map("n", "", "l", { silent = true, desc = "Window right" }) + +map("t", "", [[h]], { silent = true, desc = "Window left" }) +map("t", "", [[j]], { silent = true, desc = "Window down" }) +map("t", "", [[k]], { silent = true, desc = "Window up" }) +map("t", "", [[l]], { silent = true, desc = "Window right" }) + +-- Buffer cycling +map("n", "H", "bprevious", { silent = true, desc = "Previous buffer" }) +map("n", "L", "bnext", { silent = true, desc = "Next buffer" }) + +-- ============================================================================ +-- Buffer helpers +-- ============================================================================ + +local function listed_buffers() + return vim.tbl_filter(function(buf) + return vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buflisted + end, vim.api.nvim_list_bufs()) +end + +local function delete_buffer(buf, opts) + opts = opts or {} + if not buf or buf == 0 then + buf = vim.api.nvim_get_current_buf() + end + + local cmd = opts.wipe + and (opts.force and "bwipeout!" or "bwipeout") + or (opts.force and "bdelete!" or "bdelete") + + pcall(vim.cmd, cmd .. " " .. buf) +end + +local function delete_other_buffers(force) + local current = vim.api.nvim_get_current_buf() + for _, buf in ipairs(listed_buffers()) do + if buf ~= current then + delete_buffer(buf, { force = force }) + end + end +end + +local function delete_all_buffers(force) + for _, buf in ipairs(listed_buffers()) do + delete_buffer(buf, { force = force }) + end +end + +map("n", "bb", "buffer #", { silent = true, desc = "Last buffer" }) +map("n", "bd", function() delete_buffer(0, { force = false }) end, { desc = "Delete buffer" }) +map("n", "bD", function() delete_buffer(0, { force = true }) end, { desc = "Force delete buffer" }) +map("n", "bw", function() delete_buffer(0, { wipe = true }) end, { desc = "Wipe buffer" }) +map("n", "bo", function() delete_other_buffers(false) end, { desc = "Delete other buffers" }) +map("n", "ba", function() delete_all_buffers(false) end, { desc = "Delete all buffers" }) + +-- ============================================================================ +-- netrw stays the default file browser +-- ============================================================================ + +vim.g.netrw_banner = 1 +vim.g.netrw_liststyle = 3 +vim.g.netrw_winsize = 30 +vim.g.netrw_keepdir = 0 + +map("n", "E", "Ex", { silent = true, desc = "Open netrw" }) + +vim.api.nvim_create_autocmd("VimEnter", { + callback = function() + if vim.fn.argc() == 0 then + vim.cmd("Neotree position=current") + end + end, +}) + +-- ============================================================================ +-- Built-in package manager (nightly) +-- ============================================================================ + +-- Optional post-install hooks for plugins that usually need one-time setup. +vim.api.nvim_create_autocmd("PackChanged", { + callback = function(ev) + local data = ev.data or {} + local spec = data.spec or {} + local name = spec.name + local kind = data.kind + + if kind ~= "install" and kind ~= "update" then + return + end + + if name == "nvim-treesitter" then + vim.schedule(function() + pcall(vim.cmd.packadd, "nvim-treesitter") + pcall(function() + require("nvim-treesitter.install").update({ with_sync = true })() + end) + end) + end + + if name == "markdown-preview.nvim" then + vim.schedule(function() + pcall(vim.cmd.packadd, "markdown-preview.nvim") + pcall(function() + vim.fn["mkdp#util#install"]() + end) + end) + end + end, +}) + +vim.pack.add({ + + { src = "https://github.com/nvim-lua/plenary.nvim" }, + { src = "https://github.com/MunifTanjim/nui.nvim" }, + { src = "https://github.com/nvim-tree/nvim-web-devicons" }, + + -- Themes + { src = "https://github.com/oskarnurm/koda.nvim" }, + { src = "https://github.com/vague-theme/vague.nvim" }, + { src = "https://github.com/nendix/zen.nvim" }, + { src = "https://github.com/rebelot/kanagawa.nvim" }, + + -- Editing / syntax / completion + { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, + + { src = "https://github.com/saghen/blink.lib" }, + { src = "https://github.com/saghen/blink.cmp" }, + + { src = "https://github.com/L3MON4D3/LuaSnip" }, + { src = "https://github.com/rafamadriz/friendly-snippets" }, + { src = "https://gitlab.com/repetitivesin/madol.nvim" }, + + -- LSP configs (for vim.lsp.enable) + { src = "https://github.com/neovim/nvim-lspconfig" }, + + -- Navigation / search + { src = "https://github.com/ibhagwan/fzf-lua" }, + { src = "https://github.com/nvim-neo-tree/neo-tree.nvim" }, + { src = "https://github.com/folke/flash.nvim" }, + { src = "https://github.com/leath-dub/snipe.nvim" }, + { src = "https://github.com/folke/which-key.nvim" }, + { src = "https://github.com/mikavilpas/yazi.nvim" }, + { src = "https://github.com/christoomey/vim-tmux-navigator"}, + + -- Git + { src = "https://github.com/tpope/vim-fugitive" }, + { src = "https://github.com/lewis6991/gitsigns.nvim" }, + { src = "https://github.com/kdheepak/lazygit.nvim" }, + + -- Text objects / editing + { src = "https://github.com/kylechui/nvim-surround" }, + { src = "https://github.com/windwp/nvim-autopairs" }, + { src = "https://github.com/abecodes/tabout.nvim" }, + + -- UI + { src = "https://github.com/nvim-lualine/lualine.nvim" }, + { src = "https://github.com/chentoast/marks.nvim" }, + + -- Writing / docs + { src = "https://github.com/chomosuke/typst-preview.nvim" }, + { src = "https://github.com/iamcco/markdown-preview.nvim" }, + { src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" }, + + -- AI + { src = "https://github.com/nickjvandyke/opencode.nvim" }, + { src = "https://github.com/zbirenbaum/copilot.lua" }, + +}, { confirm = false, load = true }) + +-- ============================================================================ +-- Plugin globals before setup +-- ============================================================================ + +vim.g.mkdp_auto_start = 0 +vim.g.mkdp_auto_close = 1 +vim.g.mkdp_filetypes = { "markdown" } + +-- Let native LSP own LSP features; opencode still works for its own UI/actions. +vim.g.opencode_opts = { + lsp = { + enabled = false, + }, +} + +vim.o.autoread = true + +-- ============================================================================ +-- Themes +-- ============================================================================ + +require("koda").setup({}) +require("vague").setup({}) +require("kanagawa").setup({ + compile = false, + background = { + dark = "wave", + light = "lotus", + }, +}) +require("zen").setup({}) + +vim.cmd.colorscheme("vague") + +-- ============================================================================ +-- which-key +-- ============================================================================ + +local wk = require("which-key") +wk.setup({ preset = "helix" }) + +wk.add({ + { "b", group = "buffer" }, + { "f", group = "find" }, + { "g", group = "git" }, + { "h", group = "hunks" }, + { "l", group = "lsp" }, + { "m", group = "marks" }, + { "o", group = "opencode" }, + { "t", group = "tree" }, + { "p", group = "preview" }, + { "u", group = "toggles" }, +}) + +-- ============================================================================ +-- vim-tmux-navigator +-- ============================================================================ + +map("n", "", "TmuxNavigateLeft", { silent = true }) +map("n", "", "TmuxNavigateDown", { silent = true }) +map("n", "", "TmuxNavigateUp", { silent = true }) +map("n", "", "TmuxNavigateRight", { silent = true }) + + +-- ============================================================================ +-- Treesitter +-- ============================================================================ + +require("nvim-treesitter.configs").setup({ + ensure_installed = { + "go", + "gomod", + "gowork", + "gosum", + "bash", + "c", + "cpp", + "css", + "diff", + "html", + "javascript", + "json", + "json5", + "latex", + "lua", + "luadoc", + "markdown", + "markdown_inline", + "python", + "query", + "regex", + "rust", + "toml", + "tsx", + "typst", + "typescript", + "vim", + "vimdoc", + "yaml", + }, + auto_install = true, + highlight = { enable = true }, + indent = { enable = true }, +}) + +-- ============================================================================ +-- LuaSnip +-- ============================================================================ + +local ls = require("luasnip") + +ls.config.setup({ + history = true, + update_events = "TextChanged,TextChangedI", + delete_check_events = "TextChanged", + enable_autosnippets = true, +}) + +require("luasnip.loaders.from_vscode").lazy_load() + +require("madol").setup({ + rmarkdown = { + snippets = { + ["greek-tex"] = true, + ["greek-unicode"] = false + } + } +}) + +map({ "i", "s" }, "", function() + if ls.choice_active() then + ls.change_choice(1) + end +end, { desc = "LuaSnip next choice" }) + +map({ "i", "s" }, "", function() + if ls.choice_active() then + ls.change_choice(-1) + end +end, { desc = "LuaSnip previous choice" }) + +-- ============================================================================ +-- blink.cmp +-- ============================================================================ +-- + +require("blink.cmp").build():pwait() + +require("blink.cmp").setup({ + snippets = { + preset = "luasnip", + }, + completion = { + menu = { auto_show = true }, + ghost_text = { enabled = false }, + documentation = { + auto_show = true, + auto_show_delay_ms = 200, + }, + list = { + selection = { + preselect = false, + auto_insert = false, + }, + }, + }, + keymap = { + preset = "none", + [""] = { "show", "show_documentation", "hide_documentation" }, + [""] = { "hide" }, + + [""] = { "scroll_documentation_up" }, + [""] = { "scroll_documentation_down" }, + + [""] = { "accept", "fallback" }, + + [""] = { "select_next", "fallback" }, + [""] = { "select_prev", "fallback" }, + + [""] = { "snippet_forward", "fallback" }, + [""] = { "snippet_backward", "fallback" }, + + + }, + sources = { + default = { "lsp", "path", "snippets", "buffer" }, + }, + fuzzy = { + implementation = "rust" + }, +}) + +-- ============================================================================ +-- Copilot +-- Included, but practically "off by default" because auto_trigger = false. +-- Toggle it on/off with uc. +-- ============================================================================ + +vim.api.nvim_create_autocmd("User", { + pattern = "BlinkCmpMenuOpen", + callback = function() + vim.b.copilot_suggestion_hidden = true + end, +}) + +vim.api.nvim_create_autocmd("User", { + pattern = "BlinkCmpMenuClose", + callback = function() + vim.b.copilot_suggestion_hidden = false + end, +}) + +require("copilot").setup({ + panel = { + enabled = false, + }, + suggestion = { + enabled = true, + auto_trigger = false, + hide_during_completion = true, + keymap = { + accept = "", + next = "", + prev = "", + dismiss = "", + toggle_auto_trigger = false, + }, + }, +}) + +map("n", "ac", function() + require("copilot.suggestion").toggle_auto_trigger() +end, { desc = "Toggle Copilot auto-trigger" }) + +map("n", "ap", function() + require("copilot.panel").toggle() +end, { desc = "Toggle Copilot panel" }) + +-- ============================================================================ +-- autopairs / tabout / surround +-- ============================================================================ + +require("nvim-autopairs").setup({ + check_ts = true, +}) + +require("tabout").setup({ + tabkey = "", + backwards_tabkey = "", + act_as_tab = true, + act_as_shift_tab = true, + default_tab = "", + default_shift_tab = "", + enable_backwards = true, + completion = false, + ignore_beginning = true, + tabouts = { + { open = "'", close = "'" }, + { open = '"', close = '"' }, + { open = "`", close = "`" }, + { open = "(", close = ")" }, + { open = "[", close = "]" }, + { open = "{", close = "}" }, + { open = "$", close = "$" }, + }, +}) + +require("nvim-surround").setup({}) + +-- ============================================================================ +-- flash.nvim +-- ============================================================================ + +require("flash").setup({}) + +map({ "n", "x", "o" }, "s", function() require("flash").jump() end, { desc = "Flash" }) +map({ "n", "x", "o" }, "S", function() require("flash").treesitter() end, { desc = "Flash Treesitter" }) +map("o", "r", function() require("flash").remote() end, { desc = "Remote Flash" }) +map({ "o", "x" }, "R", function() require("flash").treesitter_search() end, { desc = "Treesitter Search" }) +map("c", "", function() require("flash").toggle() end, { desc = "Toggle Flash Search" }) + +-- ============================================================================ +-- marks.nvim +-- ============================================================================ + +require("marks").setup({ + default_mappings = true, + builtin_marks = { ".", "<", ">", "^" }, + cyclic = true, + force_write_shada = false, + refresh_interval = 250, +}) + +map("n", "mb", "MarksListBuf", { silent = true, desc = "Marks in buffer" }) +map("n", "ma", "MarksListAll", { silent = true, desc = "All marks" }) + +-- ============================================================================ +-- snipe.nvim +-- ============================================================================ + +require("snipe").setup({ + ui = { + position = "center", + preselect_current = true, + text_align = "file-first", + }, + hints = { + dictionary = "sadflewcmpghio", + }, + navigate = { + cancel_snipe = "", + close_buffer = "D", + open_vsplit = "V", + open_split = "H", + }, + sort = "last", +}) + +map("n", "", function() require("snipe").open_buffer_menu() end, { desc = "Snipe buffers" }) + +-- ============================================================================ +-- Markdown / Typst +-- ============================================================================ + +require("render-markdown").setup({ + file_types = { "markdown" }, + render_modes = { "n", "c", "t" }, +}) + +require("typst-preview").setup({ + follow_cursor = true, +}) + +-- Typst +map("n", "ptp", "TypstPreview", { silent = true, desc = "Typst preview" }) +map("n", "ptP", "TypstPreviewToggle", { silent = true, desc = "Toggle Typst preview" }) + +-- Markdown +map("n", "pmp", "MarkdownPreview", { silent = true, desc = "Markdown preview" }) +map("n", "pmr", "RenderMarkdown toggle", { silent = true, desc = "Toggle render-markdown" }) + +-- ============================================================================ +-- fzf-lua +-- ============================================================================ + +require("fzf-lua").setup({ + actions = { + files = { + ["enter"] = require("fzf-lua.actions").file_edit, + } + } +}) + +map("n", "ff", function() require("fzf-lua").files() end, { desc = "Files" }) +map("n", "db", function() require("fzf-lua").buffers() end, { desc = "Buffers" }) +map("n", "bl", function() require("fzf-lua").buffers() end, { desc = "List buffers" }) +map("n", "ft", function() require("fzf-lua").live_grep() end, { desc = "Live grep" }) +map("n", "fs", function() require("fzf-lua").lsp_document_symbols() end, { desc = "Document symbols" }) +map("n", "/", function() require("fzf-lua").grep_curbuf() end, { desc = "Grep current buffer" }) +map("n", "fh", function() require("fzf-lua").help_tags() end, { desc = "Help tags" }) + +-- useful extras +map("n", "fr", function() require("fzf-lua").oldfiles() end, { desc = "Recent files" }) +map("n", "fg", function() require("fzf-lua").git_files() end, { desc = "Git files" }) +map("n", "fc", function() require("fzf-lua").commands() end, { desc = "Commands" }) +map("n", "fk", function() require("fzf-lua").keymaps() end, { desc = "Keymaps" }) +map("n", "fd", function() require("fzf-lua").diagnostics_document() end, { desc = "Document diagnostics" }) +map("n", "fD", function() require("fzf-lua").diagnostics_workspace() end, { desc = "Workspace diagnostics" }) +map("n", "fw", function() require("fzf-lua").grep_cword() end, { desc = "Grep word under cursor" }) + +-- ============================================================================ +-- neo-tree +-- netrw remains default; neo-tree is opt-in on n +-- ============================================================================ + +require("neo-tree").setup({ + close_if_last_window = true, + enable_git_status = true, + enable_diagnostics = true, + filesystem = { + hijack_netrw_behavior = "disabled", + follow_current_file = { enabled = true }, + use_libuv_file_watcher = true, + }, + window = { + width = 80, + }, +}) + +map("n", "e", "Neotree position=right toggle", { + silent = true, + desc = "Neo-tree", +}) + +-- ============================================================================ +-- Git +-- ============================================================================ + +require("gitsigns").setup({ + signs = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "" }, + topdelete = { text = "" }, + changedelete = { text = "▎" }, + untracked = { text = "▎" }, + }, + on_attach = function(bufnr) + local gs = package.loaded.gitsigns + + local function bufmap(mode, lhs, rhs, desc) + vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, desc = desc }) + end + + bufmap("n", "]h", gs.next_hunk, "Next hunk") + bufmap("n", "[h", gs.prev_hunk, "Prev hunk") + bufmap("n", "hs", gs.stage_hunk, "Stage hunk") + bufmap("n", "hr", gs.reset_hunk, "Reset hunk") + bufmap("n", "hS", gs.stage_buffer, "Stage buffer") + bufmap("n", "hR", gs.reset_buffer, "Reset buffer") + bufmap("n", "hp", gs.preview_hunk, "Preview hunk") + bufmap("n", "hb", function() gs.blame_line({ full = true }) end, "Blame line") + bufmap("n", "hd", gs.diffthis, "Diff this") + bufmap("n", "hQ", gs.setqflist, "Hunks to quickfix") + end, +}) + +map("n", "gg", "LazyGit", { silent = true, desc = "LazyGit" }) +map("n", "gs", "Git", { silent = true, desc = "Git status" }) +map("n", "gb", "Git blame", { silent = true, desc = "Git blame" }) +map("n", "gp", "Git push", { silent = true, desc = "Git push" }) +map("n", "gl", "Git pull", { silent = true, desc = "Git pull" }) +map("n", "gc", "Git commit", { silent = true, desc = "Git commit" }) + +-- ============================================================================ +-- opencode.nvim +-- ============================================================================ + +map({ "n", "x" }, "oa", function() + require("opencode").ask("@this: ", { submit = true }) +end, { desc = "Ask opencode" }) + +map({ "n", "x" }, "os", function() + require("opencode").select() +end, { desc = "Select opencode action" }) + +map({ "n", "t" }, "oo", function() + require("opencode").toggle() +end, { desc = "Toggle opencode" }) + +map({ "n", "x" }, "or", function() + return require("opencode").operator("@this ") +end, { expr = true, desc = "Send range to opencode" }) + +map("n", "ol", function() + return require("opencode").operator("@this ") .. "_" +end, { expr = true, desc = "Send line to opencode" }) + +map("n", "ou", function() + require("opencode").command("session.half.page.up") +end, { desc = "Opencode scroll up" }) + +map("n", "od", function() + require("opencode").command("session.half.page.down") +end, { desc = "Opencode scroll down" }) + +-- ============================================================================ +-- LSP (native nightly flow) +-- No Mason. Install server binaries yourself and keep them on PATH. +-- ============================================================================ + +local capabilities = require("blink.cmp").get_lsp_capabilities() + +vim.diagnostic.config({ + underline = true, + severity_sort = true, + update_in_insert = false, + virtual_text = { + spacing = 2, + source = "if_many", + }, + float = { + border = "rounded", + source = "if_many", + }, +}) + +-- Global defaults for all enabled servers +vim.lsp.config("*", { + capabilities = capabilities, + root_markers = { ".git" }, +}) + +-- Per-server overrides +vim.lsp.config("lua_ls", { + settings = { + Lua = { + diagnostics = { + globals = { "vim" }, + }, + workspace = { + checkThirdParty = false, + }, + telemetry = { + enable = false, + }, + }, + }, +}) + +-- Adjust this list to the servers you actually have installed. +local servers = { + "gopls", + "lua_ls", + "tinymist", + "marksman", + "pyright", +} + +for _, server in ipairs(servers) do + vim.lsp.enable(server) +end + +vim.api.nvim_create_autocmd("LspAttach", { + callback = function(ev) + local bufnr = ev.buf + + local function lmap(lhs, rhs, desc, mode) + vim.keymap.set(mode or "n", lhs, rhs, { buffer = bufnr, silent = true, desc = desc }) + end + + lmap("gd", vim.lsp.buf.definition, "Goto definition") + lmap("gD", vim.lsp.buf.declaration, "Goto declaration") + lmap("gi", vim.lsp.buf.implementation, "Goto implementation") + lmap("gt", vim.lsp.buf.type_definition, "Goto type definition") + lmap("gr", function() require("fzf-lua").lsp_references() end, "References") + lmap("K", vim.lsp.buf.hover, "Hover") + lmap("gK", vim.lsp.buf.signature_help, "Signature help") + + lmap("la", vim.lsp.buf.code_action, "Code action", { "n", "x" }) + lmap("lr", vim.lsp.buf.rename, "Rename") + lmap("lf", function() vim.lsp.buf.format({ async = true }) end, "Format") + lmap("ld", vim.diagnostic.open_float, "Line diagnostics") + lmap("ls", function() require("fzf-lua").lsp_document_symbols() end, "Document symbols") + lmap("lS", function() require("fzf-lua").lsp_live_workspace_symbols() end, "Workspace symbols") + + lmap("[d", function() vim.diagnostic.jump({ count = -1, float = true }) end, "Prev diagnostic") + lmap("]d", function() vim.diagnostic.jump({ count = 1, float = true }) end, "Next diagnostic") + end, +}) + +-- ============================================================================ +-- lualine +-- ============================================================================ + +local function opencode_statusline() + local ok, opencode = pcall(require, "opencode") + if ok and opencode.statusline then + return opencode.statusline() + end + return "" +end + +require("lualine").setup({ + options = { + section_separators = "", + component_separators = "", + globalstatus = true, + theme = "auto", + }, + + sections = { + lualine_a = { "mode" }, + lualine_b = { { "branch", icon = "" }, "diff" }, + lualine_c = { + { "diagnostics" }, + { "filename", path = 1, symbols = { modified = " ●", readonly = " " } }, + }, + lualine_x = { "encoding", "fileformat", "filetype", opencode_statusline }, + lualine_y = { "progress" }, + lualine_z = { "location" }, + }, +}) diff --git a/machines/desktop/config/sway/config b/machines/desktop/config/sway/config index 1205948..4fc45e3 100644 --- a/machines/desktop/config/sway/config +++ b/machines/desktop/config/sway/config @@ -60,6 +60,7 @@ workspace_auto_back_and_forth yes bindsym $mod+Tab workspace back_and_forth bindsym $mod+Shift+m exec ~/.config/sway/toggle-hdmi.sh +output * adaptive_sync off ### Key bindings bindsym $mod+Return exec $term