diff --git a/.gitignore b/.gitignore index 2949689..bfee79b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ machines/desktop/config/aichat/config.yaml +machines/desktop/config/nvim/nvim-pack-lock.json diff --git a/machines/desktop/config/foot/foot.ini b/machines/desktop/config/foot/foot.ini index 951dad3..f3a05a0 100644 --- a/machines/desktop/config/foot/foot.ini +++ b/machines/desktop/config/foot/foot.ini @@ -1,5 +1,5 @@ [main] font=Hack Nerd Font:size=10 -[colors] +[colors-dark] background=101010 diff --git a/machines/desktop/config/nvim/init.lua b/machines/desktop/config/nvim/init.lua index f3b9df7..bd7f00e 100644 --- a/machines/desktop/config/nvim/init.lua +++ b/machines/desktop/config/nvim/init.lua @@ -1,534 +1,749 @@ --- Leaders / globals +if vim.fn.has("nvim-0.12") == 0 then + vim.notify("This config expects Neovim nightly / 0.12+", vim.log.levels.WARN) +end + vim.g.mapleader = " " vim.g.maplocalleader = " " --- Options -vim.opt.termguicolors = true -vim.opt.number = true -vim.opt.relativenumber = true -vim.opt.signcolumn = "yes" -vim.opt.cursorline = true -vim.opt.laststatus = 2 +local opt = vim.opt +local map = vim.keymap.set -vim.opt.splitbelow = true -vim.opt.splitright = true +-- ============================================================================ +-- Core options +-- ============================================================================ -vim.opt.ignorecase = true -vim.opt.smartcase = true -vim.opt.incsearch = true -vim.opt.hlsearch = true -vim.opt.expandtab = true -vim.opt.tabstop = 2 -vim.opt.shiftwidth = 2 -vim.opt.softtabstop = 2 -vim.opt.smartindent = true -vim.opt.breakindent = true +opt.number = true +opt.relativenumber = true +opt.mouse = "a" +opt.clipboard = "unnamedplus" -vim.opt.undofile = true -vim.opt.swapfile = false -vim.opt.backup = false -vim.opt.confirm = true +opt.swapfile = false +opt.backup = false +opt.writebackup = false +opt.undofile = true -vim.opt.clipboard = "unnamedplus" +opt.ignorecase = true +opt.smartcase = true +opt.incsearch = true +opt.hlsearch = false -vim.opt.scrolloff = 8 +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.expandtab = true +opt.smartindent = true +opt.shiftround = true +opt.tabstop = 2 +opt.softtabstop = 2 +opt.shiftwidth = 2 --- Keymaps -vim.keymap.set("n", "", "nohlsearch", { desc = "Clear search highlight" }) +opt.list = true +opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } +opt.fillchars = { eob = " " } -vim.keymap.set("n", "j", "gj", { silent = true }) -vim.keymap.set("n", "k", "gk", { silent = true }) -vim.keymap.set("v", "<", "", ">gv") +opt.completeopt = { "menu", "menuone", "noselect", "popup", "fuzzy" } +opt.winborder = "single" +opt.pumborder = "single" -vim.keymap.set("n", "", function() - vim.lsp.buf.format({ timeout_ms = 2000 }) - vim.cmd("w") -end, { desc = "Format + Write" }) +opt.winbar = "%=%m %t %=" +opt.showtabline = 0 -vim.keymap.set("i", "", function() - vim.cmd("stopinsert") - vim.lsp.buf.format({ timeout_ms = 2000 }) - vim.cmd("w") -end, { desc = "Format + Write" }) +-- ============================================================================ +-- Basic keymaps +-- ============================================================================ -vim.keymap.set("n", "", "h", { desc = "Window left" }) -vim.keymap.set("n", "", "j", { desc = "Window down" }) -vim.keymap.set("n", "", "k", { desc = "Window up" }) -vim.keymap.set("n", "", "l", { desc = "Window right" }) +map("n", "", "nohlsearch", { silent = true, desc = "Clear search highlight" }) -vim.keymap.set("t", "", [[h]], { desc = "Terminal window left" }) -vim.keymap.set("t", "", [[j]], { desc = "Terminal window down" }) -vim.keymap.set("t", "", [[k]], { desc = "Terminal window up" }) -vim.keymap.set("t", "", [[l]], { desc = "Terminal window right" }) +-- 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)", +}) -vim.keymap.set("n", "bb", "buffers", { desc = "List buffers" }) -vim.keymap.set("n", "bl", "b#", { desc = "Last 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", "bwipeout", { desc = "Wipe buffer" }) -vim.keymap.set("n", "bo", "%bdelete|edit#|bdelete#", { desc = "Delete other buffers" }) -vim.keymap.set("n", "ba", "%bdelete", { desc = "Delete all buffers" }) +-- 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" }) -vim.keymap.set('n', 'H', ':bprevious', { silent = true }) -vim.keymap.set('n', 'L', ':bnext', { silent = true }) +-- 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" }) -vim.keymap.set('t', '', '', { noremap = true, silent = true }) +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" }) --- lazy.nvim bootstrap -local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" -if not (vim.uv or vim.loop).fs_stat(lazypath) then - local lazyrepo = "https://github.com/folke/lazy.nvim.git" - local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) - if vim.v.shell_error ~= 0 then - vim.api.nvim_echo({ - { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, - { out, "WarningMsg" }, - { "\nPress any key to exit..." }, - }, true, {}) - vim.fn.getchar() - os.exit(1) +-- ============================================================================ +-- 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 -vim.opt.rtp:prepend(lazypath) --- Plugins -require("lazy").setup({ +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/nvim-lua/plenary.nvim" }, + { src = "https://github.com/MunifTanjim/nui.nvim" }, + { src = "https://github.com/nvim-tree/nvim-web-devicons" }, + -- Themes - { - "vague-theme/vague.nvim", - lazy = false, - priority = 1000, - config = function() - vim.cmd("colorscheme koda") - end, - }, - { "rebelot/kanagawa.nvim" }, - { "oskarnurm/koda.nvim" }, - { "datsfilipe/vesper.nvim" }, - { "metalelf0/base16-black-metal-scheme" }, + { 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" }, - -- LSP / Completion - { "neovim/nvim-lspconfig" }, - { - "saghen/blink.cmp", - version = "1.*", - opts = { - keymap = { - preset = "none", - [""] = { "show", "show_documentation", "hide_documentation" }, - [""] = { "hide" }, + -- Editing / syntax / completion + { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, - [""] = { "scroll_documentation_up" }, - [""] = { "scroll_documentation_down" }, + { src = "https://github.com/saghen/blink.cmp" }, - [""] = { "accept", "fallback" }, + { src = "https://github.com/L3MON4D3/LuaSnip" }, + { src = "https://github.com/rafamadriz/friendly-snippets" }, + { src = "https://gitlab.com/repetitivesin/madol.nvim" }, - [""] = { "select_next", "fallback" }, - [""] = { "select_prev", "fallback" }, + -- LSP configs (for vim.lsp.enable) + { src = "https://github.com/neovim/nvim-lspconfig" }, - [""] = { "select_next", "fallback" }, - [""] = { "select_prev", "fallback" }, - - [""] = { "snippet_forward", "fallback" }, - [""] = { "snippet_backward", "fallback" }, - }, - completion = { - documentation = { - auto_show = true, - }, - list = { - selection = { - auto_insert = false, - preselect = false - } - } - }, - sources = { - default = { "lsp", "path", "buffer", "snippets" }, - }, - snippets = { - preset = "luasnip", - } - }, - }, - { - "L3MON4D3/LuaSnip", - version = "v2.*", - build = "make install_jsregexp", - dependencies = { "rafamadriz/friendly-snippets" }, - config = function() - local luasnip = require("luasnip") - luasnip.config.setup({ - history = true, - updateevents = "TextChanged, TextChangedI", - enable_autosnippets = false, - }) - require("luasnip.loaders.from_vscode").lazy_load() - - local autosnips_enabled = false - - vim.keymap.set("n", "sa", function() - autosnips_enabled = not autosnips_enabled - luasnip.config.set_config({ enable_autosnippets = autosnips_enabled }) - vim.notify("Autosnippets: " .. (autosnips_enabled and "ON" or "OFF")) - end, { desc = "Toggle autosnippets" }) - end, - }, - { - "lervag/vimtex", - lazy = false, - init = function() - vim.g.vimtex_view_method = "zathura" - vim.g.vimtex_quickfix_mode = 0 - end - }, - { - "chomosuke/typst-preview.nvim", - lazy = false, - version = "1.*", - opts = {} - }, - { - "NickvanDyke/opencode.nvim", - config = function() - vim.g.opencode_opts = { - provider = { - enabled = "tmux", - tmux = {} - } - } - vim.o.autoread = true - - vim.keymap.set({ "n", "x" }, "aa", function() require("opencode").ask("@this: ", { submit = true }) end, - { desc = "AI Ask" }) - vim.keymap.set({ "n", "x" }, "as", function() require("opencode").select() end, - { desc = "AI Select action" }) - vim.keymap.set({ "n", "x" }, "at", function() require("opencode").toggle() end, - { desc = "AI Toggle panel" }) - vim.keymap.set({ "n", "x" }, "ar", function() return require("opencode").operator("@this ") end, - { desc = "AI Add range", expr = true }) - vim.keymap.set("n", "al", function() return require("opencode").operator("@this ") .. "_" end, - { desc = "AI Add line", expr = true }) - - vim.keymap.set("n", "au", function() require("opencode").command("session.half.page.up") end, - { desc = "AI Scroll up" }) - vim.keymap.set("n", "ad", function() require("opencode").command("session.half.page.down") end, - { desc = "AI Scroll down" }) - end, - }, - { - "github/copilot.vim", - init = function() - vim.g.copilot_no_tab_map = true - vim.g.copilot_assume_mapped = true - end, - config = function() - vim.keymap.set("i", "", 'copilot#Accept("\\")', { - expr = true, - replace_keycodes = false, - silent = true - }) - - vim.keymap.set("i", "", 'copilot#AcceptWord()', { expr = true, silent = true }) - vim.keymap.set("i", "", 'copilot#AcceptLine()', { expr = true, silent = true }) - vim.keymap.set("n", "ac", "Copilot toggle", { desc = "Toggle Copilot" }) - end - }, - -- File explorer / Search - { - "nvim-neo-tree/neo-tree.nvim", - branch = "v3.x", - dependencies = { - "nvim-lua/plenary.nvim", - "MunifTanjim/nui.nvim", - "nvim-tree/nvim-web-devicons", - }, - lazy = false, - opts = { - window = { - width = 80, - }, - filesystem = { - filtered_items = { - hide_dotfiles = false, - }, - follow_current_file = { - enabled = true, - }, - group_empty_dirs = true, - }, - default_component_configs = { - indent = { - indent_size = 2, - with_markers = true, - }, - }, - }, - keys = { - { - "e", - function() - vim.cmd("Neotree position=right toggle") - end, - desc = "Neo-tree (right)", - }, - }, - }, - { - "stevearc/oil.nvim", - dependencies = { "nvim-tree/nvim-web-devicons" }, - opts = {}, - keys = { - { "E", "Oil", desc = "Oil" }, - }, - }, - { - "ibhagwan/fzf-lua", - dependencies = { "nvim-tree/nvim-web-devicons" }, - opts = function() - local actions = require("fzf-lua.actions") - return { - files = { - actions = { - ["default"] = actions.file_edit, - }, - }, - } - end, - keys = { - { "ff", function() require("fzf-lua").files() end, desc = "Find files" }, - { "fb", function() require("fzf-lua").buffers() end, desc = "Find buffers" }, - { "fo", function() require("fzf-lua").oldfiles() end, desc = "Find recent files" }, - { "ft", function() require("fzf-lua").live_grep() end, desc = "Find text in project" }, - { "fs", function() require("fzf-lua").lsp_document_symbols() end, desc = "Find document symbols" }, - - { "", function() require("fzf-lua").grep_curbuf() end, desc = "Find text in buffer" }, - { "/", function() require("fzf-lua").grep_curbuf() end, desc = "Find text in buffer" }, - - { "fh", function() require("fzf-lua").helptags() end, desc = "Find help tags" }, - }, - }, + -- 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" }, -- Git - { - "tpope/vim-fugitive", - cmd = { "Git", "G" }, - }, - { "lewis6991/gitsigns.nvim" }, - { - "kdheepak/lazygit.nvim", - lazy = true, - cmd = { - "LazyGit", - "LazyGitConfig", - "LazyGitCurrentFile", - "LazyGitFilter", - "LazyGitFilterCurrentFile", - }, - dependencies = { - "nvim-lua/plenary.nvim", - }, - keys = { - { "gg", "LazyGit", desc = "LazyGit" }, - }, - }, + { src = "https://github.com/tpope/vim-fugitive" }, + { src = "https://github.com/lewis6991/gitsigns.nvim" }, + { src = "https://github.com/kdheepak/lazygit.nvim" }, - -- Editing utilities - { "MagicDuck/grug-far.nvim" }, - { - "kylechui/nvim-surround", - event = "VeryLazy", - config = function() - require("nvim-surround").setup({}) - end, - }, - { - "windwp/nvim-autopairs", - event = "insertenter", - config = true - }, - { - 'abecodes/tabout.nvim', - lazy = false, - config = function() - require('tabout').setup { - tabkey = '', -- key to trigger tabout, set to an empty string to disable - backwards_tabkey = '', -- key to trigger backwards tabout, set to an empty string to disable - act_as_tab = true, -- shift content if tab out is not possible - act_as_shift_tab = false, -- reverse shift content if tab out is not possible (if your keyboard/terminal supports ) - default_tab = '', -- shift default action (only at the beginning of a line, otherwise is used) - default_shift_tab = '', -- reverse shift default action, - enable_backwards = true, -- well ... - completion = false, -- if the tabkey is used in a completion pum - tabouts = { - { open = "'", close = "'" }, - { open = '"', close = '"' }, - { open = '`', close = '`' }, - { open = '(', close = ')' }, - { open = '[', close = ']' }, - { open = '{', close = '}' }, - { open = ',', close = ',' } - }, - ignore_beginning = true, --[[ if the cursor is at the beginning of a filled element it will rather tab out than shift the content ]] - exclude = {} -- tabout will ignore these filetypes - } - end, - dependencies = { -- These are optional - "nvim-treesitter/nvim-treesitter", - "L3MON4D3/LuaSnip", - }, - event = 'InsertCharPre', -- Set the event to 'InsertCharPre' for better compatibility - priority = 1000, - }, + -- Text objects / editing + { src = "https://github.com/kylechui/nvim-surround" }, + { src = "https://github.com/windwp/nvim-autopairs" }, + { src = "https://github.com/abecodes/tabout.nvim" }, - -- Motion / UI - { - "folke/flash.nvim", - event = "VeryLazy", - opts = { - modes = { - treesitter = { - jump = { pos = "start" }, -- or "end" - }, - }, - }, - keys = { - { "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash" }, - { "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" }, - }, - }, - { - "nvim-treesitter/nvim-treesitter", - lazy = false, - build = ":TSUpdate", - config = function() - require('nvim-treesitter').setup({ - ensure_installed = { "go", "latex", "typst" }, - highlight = { enable = true } - }) - end - }, - { - "wellle/targets.vim", - event = "VeryLazy", - }, - { - 'nvim-lualine/lualine.nvim', - dependencies = { 'nvim-tree/nvim-web-devicons' }, - opts = function() - local function pretty_path() - local name = vim.api.nvim_buf_get_name(0) - if name == '' then return '[No Name]' end - -- Relative to current working directory, nicely normalized - return vim.fn.fnamemodify(name, ':.') - end + -- UI + { src = "https://github.com/nvim-lualine/lualine.nvim" }, + { src = "https://github.com/chentoast/marks.nvim" }, - return { - options = { - section_separators = '', - component_separators = '', - globalstatus = true, - }, + -- 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" }, - sections = { - lualine_a = { 'mode' }, - lualine_b = { { 'branch', icon = '' }, 'diff' }, - lualine_c = { - { 'diagnostics' }, -- uses vim.diagnostic by default - { 'filename', path = 1, symbols = { modified = ' ●', readonly = ' ' } }, - }, - lualine_x = { 'encoding', 'fileformat', 'filetype', require("opencode").statusline }, - lualine_y = { 'progress' }, - lualine_z = { 'location' }, - }, + -- AI + { src = "https://github.com/nickjvandyke/opencode.nvim" }, + { src = "https://github.com/zbirenbaum/copilot.lua" }, - -- Global list (best place for buffers) - tabline = { - lualine_a = { - { - 'buffers', - show_filename_only = true, - show_modified_status = true, - mode = 2, - max_length = vim.o.columns * 8 / 10, - use_mode_colors = true, - buffers_color = { - active = 'lualine_a_normal', - inactive = 'lualine_b_inactive', - } - }, - }, - lualine_z = { 'tabs' }, - }, - } - end +}, { 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, }, - { - "goolord/alpha-nvim", - dependencies = { - "nvim-tree/nvim-web-devicons", - "nvim-lua/plenary.nvim", - }, - config = function() - require("alpha").setup(require("alpha.themes.theta").config) - end +} + +vim.o.autoread = true + +-- ============================================================================ +-- Themes +-- ============================================================================ + +require("koda").setup({}) +require("vague").setup({}) +require("kanagawa").setup({ + compile = false, + background = { + dark = "wave", + light = "lotus", }, - { - "chentoast/marks.nvim", - event = "VeryLazy", - opts = {}, +}) +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" }, +}) + +-- ============================================================================ +-- 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", }, - { - "leath-dub/snipe.nvim", - keys = { - { "", function() require("snipe").open_buffer_menu() end, desc = "Open Snipe buffer menu" } - }, - opts = {} - }, - { - "folke/which-key.nvim", - event = "VeryLazy", - opts = { - preset = "helix" - }, - keys = { - { - "?", - function() - require("which-key").show({ global = false }) - end, - desc = "Buffer Local Keymaps (which-key)", - }, - }, - }, - { - "j-hui/fidget.nvim", - opts = {}, - }, - { - "christoomey/vim-tmux-navigator", - cmd = { - "TmuxNavigateLeft", - "TmuxNavigateDown", - "TmuxNavigateUp", - "TmuxNavigateRight", - "TmuxNavigatePrevious", - "TmuxNavigatorProcessList", - }, - keys = { - { "", "TmuxNavigateLeft" }, - { "", "TmuxNavigateDown" }, - { "", "TmuxNavigateUp" }, - { "", "TmuxNavigateRight" }, - { "", "TmuxNavigatePrevious" }, - }, + 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 + } } }) --- LSP +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" }) + +map({ "i", "s" }, "", function() + if ls.expand_or_jumpable() then + ls.expand_or_jump() + end +end, { desc = "LuaSnip expand/jump" }) + +map({ "i", "s" }, "", function() + if ls.jumpable(-1) then + ls.jump(-1) + end +end, { desc = "LuaSnip jump back" }) + +-- ============================================================================ +-- blink.cmp +-- ============================================================================ + +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 = true, + 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" }, + + }, + sources = { + default = { "lsp", "path", "snippets", "buffer" }, + }, + fuzzy = { + implementation = "prefer_rust_with_warning", + prebuilt_binaries = { + force_version = "v1.9.1", + } + }, +}) + +-- ============================================================================ +-- 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 = false, + 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 = "}" }, + }, +}) + +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", "RenderMarkdownToggle", { 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 = { @@ -538,41 +753,82 @@ vim.lsp.config("lua_ls", { workspace = { checkThirdParty = false, }, + telemetry = { + enable = false, + }, }, }, }) -vim.lsp.enable({ +-- Adjust this list to the servers you actually have installed. +local servers = { + "gopls", "lua_ls", "tinymist", - "gopls", + "marksman", +} + +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, }) -vim.keymap.set("n", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) -vim.keymap.set("v", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) -vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Goto definition" }) -vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { desc = "Goto declaration" }) -vim.keymap.set("n", "gi", vim.lsp.buf.implementation, { desc = "Goto implementation" }) -vim.keymap.set("n", "gr", vim.lsp.buf.references, { desc = "References" }) -vim.keymap.set("n", "gy", vim.lsp.buf.type_definition, { desc = "Goto type definition" }) +-- ============================================================================ +-- lualine +-- ============================================================================ -vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover" }) -vim.keymap.set("i", "", vim.lsp.buf.signature_help, { desc = "Signature help" }) +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", "cs", vim.lsp.buf.document_symbol, { desc = "Document symbols" }) -vim.keymap.set("n", "cS", vim.lsp.buf.workspace_symbol, { desc = "Workspace symbols" }) +require("lualine").setup({ + options = { + section_separators = "", + component_separators = "", + globalstatus = true, + theme = "auto", + }, -vim.keymap.set("n", "cf", function() - vim.lsp.buf.format({ async = true }) -end, { desc = "Format buffer" }) - -vim.keymap.set("n", "cr", vim.lsp.buf.rename, { desc = "Rename" }) - -vim.diagnostic.config({ - virtual_text = true, - signs = true, - underline = true, - update_in_insert = false, - severity_sort = true, - float = { border = "rounded", source = "if_many" }, + 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/nvim/init.lua.bak b/machines/desktop/config/nvim/init.lua.bak new file mode 100644 index 0000000..e225ef3 --- /dev/null +++ b/machines/desktop/config/nvim/init.lua.bak @@ -0,0 +1,606 @@ +-- Leaders / globals +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +-- Options +vim.opt.termguicolors = true +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.signcolumn = "yes" +vim.opt.cursorline = true +vim.opt.laststatus = 2 + +vim.opt.splitbelow = true +vim.opt.splitright = true + +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.incsearch = true +vim.opt.hlsearch = true +vim.opt.expandtab = true +vim.opt.tabstop = 2 +vim.opt.shiftwidth = 2 +vim.opt.softtabstop = 2 +vim.opt.smartindent = true +vim.opt.breakindent = true + +vim.opt.undofile = true +vim.opt.swapfile = false +vim.opt.backup = false +vim.opt.confirm = true + +vim.opt.clipboard = "unnamedplus" + +vim.opt.scrolloff = 8 + + +-- Keymaps +vim.keymap.set("n", "", "nohlsearch", { desc = "Clear search highlight" }) + +vim.keymap.set("n", "j", "gj", { silent = true }) +vim.keymap.set("n", "k", "gk", { silent = true }) +vim.keymap.set("v", "<", "", ">gv") + +vim.keymap.set("n", "", function() + vim.lsp.buf.format({ timeout_ms = 2000 }) + vim.cmd("w") +end, { desc = "Format + Write" }) + +vim.keymap.set("i", "", function() + vim.cmd("stopinsert") + vim.lsp.buf.format({ timeout_ms = 2000 }) + vim.cmd("w") +end, { desc = "Format + Write" }) + +vim.keymap.set("n", "", "h", { desc = "Window left" }) +vim.keymap.set("n", "", "j", { desc = "Window down" }) +vim.keymap.set("n", "", "k", { desc = "Window up" }) +vim.keymap.set("n", "", "l", { desc = "Window right" }) + +vim.keymap.set("t", "", [[h]], { desc = "Terminal window left" }) +vim.keymap.set("t", "", [[j]], { desc = "Terminal window down" }) +vim.keymap.set("t", "", [[k]], { desc = "Terminal window up" }) +vim.keymap.set("t", "", [[l]], { desc = "Terminal window right" }) + +vim.keymap.set("n", "bb", "buffers", { desc = "List buffers" }) +vim.keymap.set("n", "bl", "b#", { desc = "Last 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", "bwipeout", { desc = "Wipe buffer" }) +vim.keymap.set("n", "bo", "%bdelete|edit#|bdelete#", { desc = "Delete other buffers" }) +vim.keymap.set("n", "ba", "%bdelete", { desc = "Delete all buffers" }) + +vim.keymap.set('n', 'H', ':bprevious', { silent = true }) +vim.keymap.set('n', 'L', ':bnext', { silent = true }) + +vim.keymap.set('t', '', '', { noremap = true, silent = true }) + + +-- lazy.nvim bootstrap +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + { "\nPress any key to exit..." }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +-- Plugins +require("lazy").setup({ + -- Themes + { + "vague-theme/vague.nvim", + lazy = false, + priority = 1000, + config = function() + vim.cmd("colorscheme koda") + end, + }, + { "rebelot/kanagawa.nvim" }, + { "nendix/zen.nvim"}, + { "oskarnurm/koda.nvim" }, + { "datsfilipe/vesper.nvim" }, + { "metalelf0/base16-black-metal-scheme" }, + + -- LSP / Completion + { "neovim/nvim-lspconfig" }, + { + "saghen/blink.cmp", + version = "1.*", + opts = { + keymap = { + preset = "none", + [""] = { "show", "show_documentation", "hide_documentation" }, + [""] = { "hide" }, + + [""] = { "scroll_documentation_up" }, + [""] = { "scroll_documentation_down" }, + + [""] = { "accept", "fallback" }, + + [""] = { "snippet_forward", "fallback" }, + [""] = { "snippet_backward", "fallback" }, + + [""] = { "select_next", "fallback" }, + [""] = { "select_prev", "fallback" }, + + }, + completion = { + documentation = { + auto_show = true, + }, + list = { + selection = { + auto_insert = false, + preselect = true + } + } + }, + sources = { + default = { "lsp", "path", "buffer", "snippets" }, + }, + snippets = { + preset = "luasnip", + } + }, + }, + { + "L3MON4D3/LuaSnip", + version = "v2.*", + build = "make install_jsregexp", + dependencies = { "rafamadriz/friendly-snippets" }, + config = function() + local luasnip = require("luasnip") + luasnip.config.setup({ + history = true, + update_events = { "TextChanged", "TextChangedI" }, + region_check_events = { "CursorMoved", "CursorHold", "InsertEnter" }, + delete_check_events = { "TextChanged", "InsertLeave" }, + enable_autosnippets = true, + store_selection_keys = "", + }) + + require("luasnip.loaders.from_vscode").lazy_load() + + end, + }, + { + "lervag/vimtex", + lazy = false, + init = function() + vim.g.vimtex_view_method = "zathura" + vim.g.vimtex_quickfix_mode = 0 + end + }, + { + "iurimateus/luasnip-latex-snippets.nvim", + dependencies = { "L3MON4D3/LuaSnip", "lervag/vimtex" }, + config = function() + require('luasnip-latex-snippets').setup({ + use_treesitter = true + }) + end, + }, + { + "chomosuke/typst-preview.nvim", + lazy = false, + version = "1.*", + opts = {} + }, + { + "selimacerbas/markdown-preview.nvim", + dependencies = { "selimacerbas/live-server.nvim" }, + config = function() + require("markdown_preview").setup({ + port = 8421, + open_browser = false, + debounce_ms = 0, + mermaid_renderer = "rust" + }) + end, + }, + { + 'MeanderingProgrammer/render-markdown.nvim', + dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons + ---@module 'render-markdown' + ---@type render.md.UserConfig + opts = {}, + }, + { + "NickvanDyke/opencode.nvim", + config = function() + vim.g.opencode_opts = {} + vim.o.autoread = true + + vim.keymap.set({ "n", "x" }, "aa", function() require("opencode").ask("@this: ", { submit = true }) end, + { desc = "AI Ask" }) + vim.keymap.set({ "n", "x" }, "as", function() require("opencode").select() end, + { desc = "AI Select action" }) + vim.keymap.set({ "n", "x" }, "at", function() require("opencode").toggle() end, + { desc = "AI Toggle panel" }) + vim.keymap.set({ "n", "x" }, "ar", function() return require("opencode").operator("@this ") end, + { desc = "AI Add range", expr = true }) + vim.keymap.set("n", "al", function() return require("opencode").operator("@this ") .. "_" end, + { desc = "AI Add line", expr = true }) + + vim.keymap.set("n", "au", function() require("opencode").command("session.half.page.up") end, + { desc = "AI Scroll up" }) + vim.keymap.set("n", "ad", function() require("opencode").command("session.half.page.down") end, + { desc = "AI Scroll down" }) + end, + }, + { + "github/copilot.vim", + init = function() + vim.g.copilot_no_tab_map = true + vim.g.copilot_assume_mapped = true + end, + config = function() + vim.keymap.set("i", "", 'copilot#Accept("\\")', { + expr = true, + replace_keycodes = false, + silent = true + }) + + vim.keymap.set("i", "", 'copilot#AcceptWord()', { expr = true, silent = true }) + vim.keymap.set("i", "", 'copilot#AcceptLine()', { expr = true, silent = true }) + vim.keymap.set("n", "ac", "Copilot toggle", { desc = "Toggle Copilot" }) + end + }, + -- File explorer / Search + { + "nvim-neo-tree/neo-tree.nvim", + branch = "v3.x", + dependencies = { + "nvim-lua/plenary.nvim", + "MunifTanjim/nui.nvim", + "nvim-tree/nvim-web-devicons", + }, + lazy = false, + opts = { + window = { + width = 80, + }, + filesystem = { + filtered_items = { + hide_dotfiles = false, + }, + follow_current_file = { + enabled = true, + }, + group_empty_dirs = true, + }, + default_component_configs = { + indent = { + indent_size = 2, + with_markers = true, + }, + }, + }, + keys = { + { + "e", + function() + vim.cmd("Neotree position=right toggle") + end, + desc = "Neo-tree (right)", + }, + }, + }, + { + "stevearc/oil.nvim", + dependencies = { "nvim-tree/nvim-web-devicons" }, + opts = {}, + keys = { + { "E", "Oil", desc = "Oil" }, + }, + }, + { + "ibhagwan/fzf-lua", + dependencies = { "nvim-tree/nvim-web-devicons" }, + opts = function() + local actions = require("fzf-lua.actions") + return { + files = { + actions = { + ["default"] = actions.file_edit, + }, + }, + } + end, + keys = { + { "ff", function() require("fzf-lua").files() end, desc = "Find files" }, + { "fb", function() require("fzf-lua").buffers() end, desc = "Find buffers" }, + { "fo", function() require("fzf-lua").oldfiles() end, desc = "Find recent files" }, + { "ft", function() require("fzf-lua").live_grep() end, desc = "Find text in project" }, + { "fs", function() require("fzf-lua").lsp_document_symbols() end, desc = "Find document symbols" }, + + { "", function() require("fzf-lua").grep_curbuf() end, desc = "Find text in buffer" }, + { "/", function() require("fzf-lua").grep_curbuf() end, desc = "Find text in buffer" }, + + { "fh", function() require("fzf-lua").helptags() end, desc = "Find help tags" }, + }, + }, + + -- Git + { + "tpope/vim-fugitive", + cmd = { "Git", "G" }, + }, + { "lewis6991/gitsigns.nvim" }, + { + "kdheepak/lazygit.nvim", + lazy = true, + cmd = { + "LazyGit", + "LazyGitConfig", + "LazyGitCurrentFile", + "LazyGitFilter", + "LazyGitFilterCurrentFile", + }, + dependencies = { + "nvim-lua/plenary.nvim", + }, + keys = { + { "gg", "LazyGit", desc = "LazyGit" }, + }, + }, + + -- Editing utilities + { "MagicDuck/grug-far.nvim" }, + { + "kylechui/nvim-surround", + event = "VeryLazy", + config = function() + require("nvim-surround").setup({}) + end, + }, + { + "windwp/nvim-autopairs", + event = "InsertEnter", + config = true + }, + { + 'abecodes/tabout.nvim', + lazy = false, + config = function() + require('tabout').setup { + tabkey = '', -- key to trigger tabout, set to an empty string to disable + backwards_tabkey = '', -- key to trigger backwards tabout, set to an empty string to disable + act_as_tab = true, -- shift content if tab out is not possible + act_as_shift_tab = false, -- reverse shift content if tab out is not possible (if your keyboard/terminal supports ) + default_tab = '', -- shift default action (only at the beginning of a line, otherwise is used) + default_shift_tab = '', -- reverse shift default action, + enable_backwards = true, -- well ... + completion = false, -- if the tabkey is used in a completion pum + tabouts = { + { open = "'", close = "'" }, + { open = '"', close = '"' }, + { open = '`', close = '`' }, + { open = '(', close = ')' }, + { open = '[', close = ']' }, + { open = '{', close = '}' }, + { open = ',', close = ',' } + }, + ignore_beginning = true, --[[ if the cursor is at the beginning of a filled element it will rather tab out than shift the content ]] + exclude = {} -- tabout will ignore these filetypes + } + end, + dependencies = { -- These are optional + "nvim-treesitter/nvim-treesitter", + "L3MON4D3/LuaSnip", + }, + event = 'InsertCharPre', -- Set the event to 'InsertCharPre' for better compatibility + priority = 1000, + }, + + -- Motion / UI + { + "folke/flash.nvim", + event = "VeryLazy", + opts = { + modes = { + treesitter = { + jump = { pos = "start" }, -- or "end" + }, + }, + }, + keys = { + { "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash" }, + { "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" }, + }, + }, + { + "nvim-treesitter/nvim-treesitter", + event = { "BufReadPost", "BufNewFile" }, + build = ":TSUpdate", + config = function() + require("nvim-treesitter").setup({ + ensure_installed = { + "markdown", + "markdown_inline", + "go", + "latex", + "typst", + "lua", + }, + highlight = { + enable = true, + }, + }) + end, + }, + { + "wellle/targets.vim", + event = "VeryLazy", + }, + { + 'nvim-lualine/lualine.nvim', + dependencies = { 'nvim-tree/nvim-web-devicons' }, + opts = function() + local function pretty_path() + local name = vim.api.nvim_buf_get_name(0) + if name == '' then return '[No Name]' end + -- Relative to current working directory, nicely normalized + return vim.fn.fnamemodify(name, ':.') + end + + return { + options = { + section_separators = '', + component_separators = '', + globalstatus = true, + }, + + sections = { + lualine_a = { 'mode' }, + lualine_b = { { 'branch', icon = '' }, 'diff' }, + lualine_c = { + { 'diagnostics' }, -- uses vim.diagnostic by default + { 'filename', path = 1, symbols = { modified = ' ●', readonly = ' ' } }, + }, + lualine_x = { 'encoding', 'fileformat', 'filetype', require("opencode").statusline }, + lualine_y = { 'progress' }, + lualine_z = { 'location' }, + }, + + -- Global list (best place for buffers) + tabline = { + lualine_a = { + { + 'buffers', + show_filename_only = true, + show_modified_status = true, + mode = 2, + max_length = vim.o.columns * 8 / 10, + use_mode_colors = true, + buffers_color = { + active = 'lualine_a_normal', + inactive = 'lualine_b_inactive', + } + }, + }, + lualine_z = { 'tabs' }, + }, + } + end + }, + { + "goolord/alpha-nvim", + dependencies = { + "nvim-tree/nvim-web-devicons", + "nvim-lua/plenary.nvim", + }, + config = function() + require("alpha").setup(require("alpha.themes.theta").config) + end + }, + { + "chentoast/marks.nvim", + event = "VeryLazy", + opts = {}, + }, + { + "leath-dub/snipe.nvim", + keys = { + { "", function() require("snipe").open_buffer_menu() end, desc = "Open Snipe buffer menu" } + }, + opts = {} + }, + { + "folke/which-key.nvim", + event = "VeryLazy", + opts = { + preset = "helix" + }, + keys = { + { + "?", + function() + require("which-key").show({ global = false }) + end, + desc = "Buffer Local Keymaps (which-key)", + }, + }, + }, + { + "j-hui/fidget.nvim", + opts = {}, + }, + { + "christoomey/vim-tmux-navigator", + cmd = { + "TmuxNavigateLeft", + "TmuxNavigateDown", + "TmuxNavigateUp", + "TmuxNavigateRight", + "TmuxNavigatePrevious", + "TmuxNavigatorProcessList", + }, + keys = { + { "", "TmuxNavigateLeft" }, + { "", "TmuxNavigateDown" }, + { "", "TmuxNavigateUp" }, + { "", "TmuxNavigateRight" }, + { "", "TmuxNavigatePrevious" }, + }, + } +}) + +-- LSP +vim.lsp.config("lua_ls", { + settings = { + Lua = { + diagnostics = { + globals = { "vim" }, + }, + workspace = { + checkThirdParty = false, + }, + }, + }, +}) + +vim.lsp.enable({ + "lua_ls", + "tinymist", + "gopls", +}) + +vim.keymap.set("n", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) +vim.keymap.set("v", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) +vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Goto definition" }) +vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { desc = "Goto declaration" }) +vim.keymap.set("n", "gi", vim.lsp.buf.implementation, { desc = "Goto implementation" }) +vim.keymap.set("n", "gr", vim.lsp.buf.references, { desc = "References" }) +vim.keymap.set("n", "gy", vim.lsp.buf.type_definition, { desc = "Goto type definition" }) + +vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover" }) +vim.keymap.set("i", "", vim.lsp.buf.signature_help, { desc = "Signature help" }) + +vim.keymap.set("n", "cs", vim.lsp.buf.document_symbol, { desc = "Document symbols" }) +vim.keymap.set("n", "cS", vim.lsp.buf.workspace_symbol, { desc = "Workspace symbols" }) + +vim.keymap.set("n", "cf", function() + vim.lsp.buf.format({ async = true }) +end, { desc = "Format buffer" }) + +vim.keymap.set("n", "cr", vim.lsp.buf.rename, { desc = "Rename" }) + +vim.diagnostic.config({ + virtual_text = true, + signs = true, + underline = true, + update_in_insert = false, + severity_sort = true, + float = { border = "rounded", source = "if_many" }, +}) diff --git a/machines/desktop/config/nvim/lazy-lock.json b/machines/desktop/config/nvim/lazy-lock.json deleted file mode 100644 index b867757..0000000 --- a/machines/desktop/config/nvim/lazy-lock.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "LuaSnip": { "branch": "master", "commit": "5a1e39223db9a0498024a77b8441169d260c8c25" }, - "alpha-nvim": { "branch": "main", "commit": "a9d8fb72213c8b461e791409e7feabb74eb6ce73" }, - "base16-black-metal-scheme": { "branch": "master", "commit": "c7a32bec8105a1ceddb9fcc90b713dabde5e7e5e" }, - "blink.cmp": { "branch": "main", "commit": "4b18c32adef2898f95cdef6192cbd5796c1a332d" }, - "copilot.vim": { "branch": "release", "commit": "a12fd5672110c8aa7e3c8419e28c96943ca179be" }, - "fidget.nvim": { "branch": "main", "commit": "7fa433a83118a70fe24c1ce88d5f0bd3453c0970" }, - "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" }, - "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, - "fzf-lua": { "branch": "main", "commit": "5921997472574fca3880b62949eb8679dc6f5afc" }, - "gitsigns.nvim": { "branch": "main", "commit": "9f3c6dd7868bcc116e9c1c1929ce063b978fa519" }, - "grug-far.nvim": { "branch": "main", "commit": "275dbedc96e61a6b8d1dfb28ba51586ddd233dcf" }, - "kanagawa.nvim": { "branch": "master", "commit": "aef7f5cec0a40dbe7f3304214850c472e2264b10" }, - "koda.nvim": { "branch": "main", "commit": "25c52c710a5083cf6f3ac533d57fefecce7e2021" }, - "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, - "lazygit.nvim": { "branch": "main", "commit": "a04ad0dbc725134edbee3a5eea29290976695357" }, - "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, - "marks.nvim": { "branch": "master", "commit": "f353e8c08c50f39e99a9ed474172df7eddd89b72" }, - "neo-tree.nvim": { "branch": "v3.x", "commit": "f3df514fff2bdd4318127c40470984137f87b62e" }, - "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, - "nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" }, - "nvim-lspconfig": { "branch": "master", "commit": "44acfe887d4056f704ccc4f17513ed41c9e2b2e6" }, - "nvim-surround": { "branch": "main", "commit": "1098d7b3c34adcfa7feb3289ee434529abd4afd1" }, - "nvim-treesitter": { "branch": "main", "commit": "4d9466677a5ceadef104eaa0fe08d60d91c4e9a7" }, - "nvim-web-devicons": { "branch": "master", "commit": "746ffbb17975ebd6c40142362eee1b0249969c5c" }, - "oil.nvim": { "branch": "master", "commit": "f55b25e493a7df76371cfadd0ded5004cb9cd48a" }, - "opencode.nvim": { "branch": "main", "commit": "d080eb4e4f03cfdcb3c5eacc88cc4e17bd8c1980" }, - "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "snipe.nvim": { "branch": "main", "commit": "d2d196c335919767803f905d573ce66340e33ee6" }, - "tabout.nvim": { "branch": "master", "commit": "9a3499480a8e53dcaa665e2836f287e3b7764009" }, - "targets.vim": { "branch": "master", "commit": "6325416da8f89992b005db3e4517aaef0242602e" }, - "typst-preview.nvim": { "branch": "master", "commit": "e123a7ab64e52d836e00dea9251e85b201f38966" }, - "vague.nvim": { "branch": "main", "commit": "c1ab4d4891ff3a27deba6a80222d895ac8ffb2e5" }, - "vesper.nvim": { "branch": "main", "commit": "1717b1ad657c94bec3fc2bdebb0c55452d9fe46d" }, - "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" }, - "vim-tmux-navigator": { "branch": "master", "commit": "e41c431a0c7b7388ae7ba341f01a0d217eb3a432" }, - "vimtex": { "branch": "master", "commit": "95b93a24740f7b89dd8331326b41bdd1337d79f6" }, - "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } -} diff --git a/machines/desktop/config/sway/config b/machines/desktop/config/sway/config index 4d99436..1205948 100644 --- a/machines/desktop/config/sway/config +++ b/machines/desktop/config/sway/config @@ -118,8 +118,8 @@ bindsym --locked XF86AudioMicMute exec pactl set-source-mute @DEFAULT_SOURC bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%- bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+ -bindsym Print exec grim -g "$(slurp)" - | wl-copy -bindsym $mod+Print exec grim - | wl-copy +bindsym $mod+Shift+p exec grim -g "$(slurp)" - | wl-copy +bindsym $mod+p exec grim - | wl-copy exec_always dbus-update-activation-environment --systemd WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP=sway