vim.g.mapleader = vim.keycode("") vim.g.maplocalleader = vim.keycode("/") vim.o.langmap = "ø:" -- general options vim.o.shell = "/usr/bin/zsh" vim.g.BASH_Ctrl_j = "off" vim.g.BASH_Ctrl_l = "off" vim.opt.clipboard:append("unnamedplus") vim.o.guicursor = "n-v-c:block-CustomCursor,i:ver100-CustomICursor,n-v-c:blinkon0,i:blinkwait10" vim.o.cursorline = true vim.o.list = true vim.o.listchars = "tab:→ ,trail:·,extends:↷,precedes:↶,nbsp:+" vim.o.mouse = "a" vim.o.ruler = false vim.o.scrolloff = 4 vim.opt.shortmess:append({ W = true, I = true, c = true, C = true }) vim.o.cmdheight = 0 vim.o.showmode = false vim.o.sidescrolloff = 8 vim.o.timeoutlen = 500 vim.o.virtualedit = "block" vim.o.wildmode = "longest:full,full" vim.o.wrap = false vim.opt.diffopt:append("linematch:60") -- second stage diff to align lines vim.opt.diffopt:append("hiddenoff") vim.opt.diffopt:append("vertical") vim.opt.diffopt:append("algorithm:histogram") -- File History vim.o.undofile = true vim.o.undolevels = 100000 vim.o.undoreload = 100000 vim.o.updatetime = 200 -- Tab stop vim.o.expandtab = true vim.o.shiftround = true vim.o.shiftwidth = 2 vim.o.tabstop = 2 vim.o.smartindent = true -- Session options vim.opt.sessionoptions = { "buffers", "curdir", "tabpages", "winsize", "help", "globals", "skiprtp", "folds" } -- Completion Window/Popup settings vim.o.completeopt = "menu,menuone,popup,fuzzy" vim.o.pumblend = 10 vim.o.pumheight = 10 vim.o.winminwidth = 5 -- Fold settings vim.opt.foldlevel = 99 vim.opt.smoothscroll = true vim.opt.foldmethod = "expr" vim.opt.foldtext = "" vim.o.foldexpr = "v:lua.vim.treesitter.foldexpr()" -- Format settings vim.o.formatoptions = "jroqlnt" -- Grep settings vim.o.grepformat = "%f:%l:%c:%m" vim.o.grepprg = "rg --vimgrep" -- Search/subsitute settings vim.o.ignorecase = false vim.o.inccommand = "nosplit" vim.o.jumpoptions = "view" vim.o.smartcase = false -- Spelling vim.opt.spelllang = { "en" } -- Splits vim.o.splitbelow = true vim.o.splitkeep = "screen" vim.o.splitright = true -- Terminal vim.o.termguicolors = true -- Status Column vim.o.number = true vim.o.relativenumber = true vim.opt.termguicolors = true vim.diagnostic.config({ severity_sort = true, underline = true, virtual_text = { spacing = vim.o.shiftwidth, source = "if_many", severity = { max = vim.diagnostic.severity.WARN, }, }, signs = false, virtual_lines = { current_line = true, spacing = vim.o.shiftwidth, severity = { min = vim.diagnostic.severity.ERROR }, }, float = { source = true }, }) vim.lsp.set_log_level(2) -- ---------------------------------------- -- MAPS -- ---------------------------------------- local map = vim.keymap.set -- better esc map({ "i", "n", "s" }, "", function() vim.cmd("noh") return "" end, { expr = true, desc = "Escape and Clear hlsearch" }) -- better up/down map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true }) map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true, silent = true }) -- Move to window using the hjkl keys map("n", "", "h", { desc = "Go to Left Window", remap = true }) map("n", "", "j", { desc = "Go to Lower Window", remap = true }) map("n", "", "k", { desc = "Go to Upper Window", remap = true }) map("n", "", "l", { desc = "Go to Right Window", remap = true }) -- Resize window using hjkl keys map("n", "", "resize +2", { desc = "Increase Window Height" }) map("n", "", "resize -2", { desc = "Decrease Window Height" }) map("n", "", "vertical resize -2", { desc = "Decrease Window Width" }) map("n", "", "vertical resize +2", { desc = "Increase Window Width" }) -- Move Lines map("v", "J", ":m '>+1gv=gv", { desc = "Move Down" }) map("v", "K", ":m '<-2gv=gv", { desc = "Move Up" }) -- https://github.com/mhinz/vim-galore#tips-1 -- smarter next/prev in command line map("n", "", "wildmenumode() ? '' : ''", { expr = true, desc = "Next" }) map("n", "", "wildmenumode() ? '' : ''", { expr = true, desc = "Prev" }) -- Add undo break-points map("i", ",", ",u") map("i", ".", ".u") map("i", ";", ";u") -- save file map({ "x", "n", "s" }, "ww", "w", { desc = "Save File" }) -- quit map("n", "qq", "q", { desc = "Close Window" }) map("n", "qa", "qa", { desc = "Quit All" }) map("n", "qA", "qa!", { desc = "Quit All" }) map("n", "wq", "wq", { desc = "Write And Close Window" }) map("n", "wQ", "wqa", { desc = "Write And Quit All" }) --keywordprg map("n", "K", "norm! K", { desc = "Keywordprg" }) -- better indenting map("v", "<", "", ">gv") map("v", "", ">gv") map("v", "", "Vcxnormal gccfxa", { desc = "Add Comment Below" }) map("n", "gcO", "OVcxnormal gccfxa", { desc = "Add Comment Above" }) -- new file map("n", "n", "enew", { desc = "New File" }) -- highlights under cursor map("n", "ui", vim.show_pos, { desc = "Inspect Pos" }) map("n", "uI", function() vim.treesitter.inspect_tree() vim.api.nvim_input("I") end, { desc = "Inspect Tree" }) -- Terminal Mappings map("n", "", "terminal", { desc = "Show Terminal" }) map("t", "", "close", { desc = "Hide Terminal" }) map("n", "", "terminal", { desc = "which_key_ignore" }) map("t", "", "close", { desc = "which_key_ignore" }) -- windows map("n", "", "vsplit", { desc = "Split Window Right", remap = true }) map("n", "", "split", { desc = "Split Window Below", remap = true }) -- buffers map("n", "", "bprev") map("n", "", "bnext") -- quickfix window map("n", "", "lprev") map("n", "", "lnext") -- tabs map("n", "l", "tablast", { desc = "Last Tab" }) map("n", "f", "tabfirst", { desc = "First Tab" }) map("n", "", "tabnew", { desc = "New Tab" }) map("n", "n", "tabnext", { desc = "Next Tab" }) map("n", "d", "tabclose", { desc = "Close Tab" }) map("n", "p", "tabprevious", { desc = "Previous Tab" }) -- other map("n", "cw", [[:cd %:p:h]], { desc = "Set Workspace To Buffer Path" }) map("n", "o", "m`o``", { desc = "Insert Newline" }) map("n", "\\", "n.", { noremap = true, silent = true, desc = "Repeat And Goto Next" }) map("n", "", "Lazy", { desc = "Lazy" }) map( "n", "", "nohlsearchdiffupdatenormal! ", { desc = "Redraw / Clear hlsearch / Diff Update / Refresh Buffers" } ) -- LSP map("n", "ld", "e ~/.local/state/nvim/lsp.log") map("n", "lc", "checkhealth") local diagnostic_goto = function(count, severity) severity = severity and vim.diagnostic.severity[severity] or nil return function() vim.diagnostic.jump({ severity, count = count }) end end map("n", "", function() vim.diagnostic.open_float({ source = true }) end) map("n", "", diagnostic_goto(1), { desc = "Next Diagnostic" }) map("n", "", diagnostic_goto(-1), { desc = "Prev Diagnostic" }) map("n", "[e", diagnostic_goto(-1, "ERROR"), { desc = "Prev Error" }) map("n", "[w", diagnostic_goto(-1, "WARN"), { desc = "Prev Warning" }) map("n", "]e", diagnostic_goto(1, "ERROR"), { desc = "Next Error" }) map("n", "]w", diagnostic_goto(1, "WARN"), { desc = "Next Warning" }) map("n", "gd", vim.lsp.buf.definition, { desc = "Goto Definition" }) map("n", "gD", vim.lsp.buf.type_definition, { desc = "Goto Type Definition" }) map("n", "gi", vim.lsp.buf.declaration, { desc = "Goto Declaration" }) map("n", "gI", vim.lsp.buf.implementation, { desc = "Goto Implementation" }) map("n", "gl", vim.diagnostic.setloclist, { desc = "Diagnostics to Location List" }) map("n", "gr", function() vim.lsp.buf.references({ includeDeclaration = false }) end, { desc = "Goto References" }) map({ "n", "i" }, "", vim.lsp.buf.signature_help) map("n", "K", vim.lsp.buf.hover) map("n", "", vim.lsp.buf.rename) map({ "n", "x" }, "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) -- replaced by Trouble -- map("n", "cs", vim.lsp.buf.document_symbol, { desc = "Document Symbols" }) -- map("n", "cw", vim.lsp.buf.workspace_symbol, { desc = "Workspace Symbols" }) -- ---------------------------------------- -- AUTOCMD -- ---------------------------------------- -- auto reload files vim.api.nvim_create_autocmd("FocusGained", { desc = "Reload files from disk when we focus vim", pattern = "*", command = "if getcmdwintype() == '' | checktime | endif", }) vim.api.nvim_create_autocmd("BufEnter", { desc = "Every time we enter an unmodified buffer, check if it changed on disk", pattern = "*", command = "if &buftype == '' && !&modified && expand('%') != '' | exec 'checktime ' . expand('') | endif", }) -- Close some filetypes with vim.api.nvim_create_autocmd("FileType", { group = vim.api.nvim_create_augroup("close_with_q", { clear = true }), pattern = { "PlenaryTestPopup", "checkhealth", "floggraph", "fugitive", "git", "gitsigns-blame", "grug-far", "help", "lspinfo", "notify", "oil", "qf", }, callback = function(event) vim.bo[event.buf].buflisted = false vim.schedule(function() vim.keymap.set("n", "q", function() vim.cmd("close") pcall(vim.api.nvim_buf_delete, event.buf, { force = true }) end, { buffer = event.buf, silent = true, desc = "Quit Buffer" }) end) end, }) -- wrap and check for spell in text filetypes vim.api.nvim_create_autocmd("FileType", { group = vim.api.nvim_create_augroup("wrap_spell", { clear = true }), pattern = { "text", "plaintex", "typst", "gitcommit", "markdown" }, callback = function() vim.opt_local.wrap = true vim.opt_local.spell = true end, }) -- ---------------------------------------- -- USER COMMANDS -- ---------------------------------------- vim.api.nvim_create_user_command("ConvertEOL", function(opts) local fmt = opts.args if fmt ~= "unix" and fmt ~= "dos" and fmt ~= "mac" then vim.notify("Unsupported file format: " .. fmt, vim.log.levels.ERROR, { title = "ConvertEOL", }) end vim.bo.fileformat = fmt vim.cmd([[write]]) vim.notify("File converted to: " .. fmt, vim.log.levels.INFO, { title = "ConvertEOL", }) end, { nargs = 1 }) -- fix diff colors on some color schemes -- https://codeyarns.com/tech/2011-07-29-vim-chart-of-color-names.html vim.api.nvim_create_user_command("FixColors", function() vim.api.nvim_set_hl(0, "CustomCursor", { fg = "salmon1", bg = "cyan" }) vim.api.nvim_set_hl(0, "CustomICursor", { fg = "salmon1", bg = "cyan" }) vim.api.nvim_set_hl(0, "ColorColumn", { bg = "salmon4" }) end, {}) -- ---------------------------------------- -- SPECS -- ---------------------------------------- local function makespecs_themes() return { "NLKNguyen/papercolor-theme", "junegunn/seoul256.vim", "mcauley-penney/phobos-anomaly.nvim", { "bluz71/vim-moonfly-colors", name = "moonfly", lazy = false }, { "uloco/bluloco.nvim", lazy = false, dependencies = { "rktjmp/lush.nvim" }, opts = {}, config = function() vim.cmd("colorscheme bluloco") end, }, { "mhartington/oceanic-next", config = function() local customthemegroup = vim.api.nvim_create_augroup("customthemegroup", {}) vim.api.nvim_create_autocmd("ColorScheme", { pattern = { "OceanicNext" }, group = customthemegroup, callback = function() vim.api.nvim_set_hl(0, "DiffAdded", { default = false, link = "DiffAdd" }) vim.api.nvim_set_hl(0, "DiffRemoved", { default = false, link = "DiffDelete" }) vim.api.nvim_set_hl(0, "Normal", {}) vim.api.nvim_set_hl(0, "LineNr", {}) vim.api.nvim_set_hl(0, "SignColumn", {}) vim.api.nvim_set_hl(0, "EndOfBuffer", {}) end, }) end, }, "morhetz/gruvbox", { "catppuccin/nvim", lazy = false, name = "catppuccin", priority = 1000, }, { "Shatur/neovim-ayu", init = function() vim.g.ayu_extended_palette = 1 end, }, "tomasr/molokai", "jnurmine/Zenburn", } end local function makespec_lspconfig() return { "neovim/nvim-lspconfig", lazy = false, event = { "BufReadPost", "BufNewFile" }, cmd = { "LspInfo", "LspRestart", "LspStart", "LspStop" }, keys = { { "", "LspInfo", noremap = true } }, config = function() local lspconfig = require("lspconfig") lspconfig.tinymist.setup({}) lspconfig.bashls.setup({}) lspconfig.lua_ls.setup({ cmd = { "lua-language-server" }, settings = { Lua = { workspace = { checkThirdParty = false, library = { vim.env.VIMRUNTIME }, }, telemetry = { enable = false }, diagnostics = { globals = { "vim" } }, format = { enable = false }, runtime = { version = "LuaJIT" }, }, }, }) lspconfig.clangd.setup({ cmd = { "clangd", "--background-index", "--clang-tidy", "--header-insertion=iwyu", "--completion-style=detailed", "--function-arg-placeholders", "--fallback-style=llvm", }, filetypes = { "c", "cpp", "objc", "objcpp", "cuda", "proto" }, }) lspconfig.html.setup({ cmd = { "vscode-html-language-server", "--stdio" }, settings = { html = { format = { templating = true, wrapLineLength = 120, wrapAttributes = "auto", }, hover = { documentation = true, references = true }, }, }, }) lspconfig.yamlls.setup({ settings = { yaml = { schemas = { kubernetes = "/home/hjalmarlucius/src/hjarl/system/manifests/*.yaml" }, -- schemaStore = { enable = false, url = "" }, }, }, }) lspconfig.pyright.setup({ cmd = { "pyright-langserver", "--stdio", "--threads", "20" }, filetypes = { "python" }, settings = { python = { analysis = { -- logLevel = "Trace", autoImportCompletions = false, diagnosticMode = "openFilesOnly", useLibraryCodeForTypes = false, logTypeEvaluationTime = true, typeEvaluationTimeThreshold = 2000, }, }, }, }) lspconfig.vtsls.setup({ settings = { complete_function_calls = true, vtsls = { enableMoveToFileCodeAction = true, autoUseWorkspaceTsdk = true, experimental = { maxInlayHintLength = 30, completion = { enableServerSideFuzzyMatch = true, }, }, }, javascript = { updateImportsOnFileMove = { enabled = "always" }, suggest = { completeFunctionCalls = true, }, inlayHints = { enumMemberValues = { enabled = true }, functionLikeReturnTypes = { enabled = true }, parameterNames = { enabled = "literals" }, parameterTypes = { enabled = true }, propertyDeclarationTypes = { enabled = true }, variableTypes = { enabled = false }, }, }, typescript = { updateImportsOnFileMove = { enabled = "always" }, suggest = { completeFunctionCalls = true, }, inlayHints = { enumMemberValues = { enabled = true }, functionLikeReturnTypes = { enabled = true }, parameterNames = { enabled = "literals" }, parameterTypes = { enabled = true }, propertyDeclarationTypes = { enabled = true }, variableTypes = { enabled = false }, }, }, }, }) end, } end local function makespec_lualine() return { "nvim-lualine/lualine.nvim", dependencies = { "echasnovski/mini.icons", "folke/noice.nvim" }, opts = { options = { theme = "auto", globalstatus = false }, extensions = { "fugitive", "neo-tree", "lazy" }, sections = { lualine_a = { "mode" }, lualine_b = {}, lualine_c = { { "filename", path = 1, shorting_target = 0 } }, lualine_x = { -- { 'require("noice").api.status.message.get()', color = { fg = "#99c794" } }, -- gets too obtrusive { 'require("noice").api.status.mode.get()', color = "lualine_a_command" }, { 'require("noice").api.status.command.get()', color = "lualine_a_command" }, }, lualine_y = { "encoding", "filetype", { "location", separator = "of", padding = { left = 1, right = 1 } }, "vim.api.nvim_buf_line_count(0)", }, lualine_z = { { function() return " " .. os.date("%R") end } }, }, inactive_sections = { lualine_a = {}, lualine_b = {}, lualine_c = { { "filename", file_status = true, path = 1, shorting_target = 0 }, }, lualine_x = {}, lualine_y = { { "location", separator = "of", padding = { left = 1, right = 1 } }, "vim.api.nvim_buf_line_count(0)", }, lualine_z = {}, }, tabline = { lualine_a = { { "buffers", symbols = { alternate_file = "" }, buffers_color = { active = "lualine_a_command" }, }, }, lualine_b = {}, lualine_c = {}, lualine_x = {}, lualine_y = {}, lualine_z = { { "tabs", mode = 2, tabs_color = { active = "lualine_a_command" }, }, }, }, }, } end local function makespec_oil() return { "stevearc/oil.nvim", dependencies = { "mini.icons" }, cmd = { "Oil" }, opts = { watch_for_changes = true, view_options = { show_hidden = true }, }, keys = { { "fE", "Oil .", desc = "Oil Explorer (buffer)" }, { "fe", "Oil --float .", desc = "Oil Explorer (float)" }, }, init = function() vim.api.nvim_create_autocmd("User", { pattern = "OilActionsPost", callback = function(event) if event.data.actions.type == "move" then Snacks.rename.on_rename_file(event.data.actions.src_url, event.data.actions.dest_url) end end, }) end, } end local function makespec_neotree() return { { "nvim-neo-tree/neo-tree.nvim", version = false, cmd = { "Neotree" }, dependencies = { "nvim-lua/plenary.nvim", "mini.icons", "MunifTanjim/nui.nvim" }, opts = { hijack_netrw_behavior = "disabled", close_if_last_window = true, filesystem = { filtered_items = { hide_gitignored = false }, follow_current_file = { enabled = false }, }, commands = { system_open = function(state) local node = state.tree:get_node() local path = node:get_id() -- macOs: open file in default application in the background. -- vim.fn.jobstart({ "xdg-open", "-g", path }, { detach = true }) -- Linux: open file in default application vim.fn.jobstart({ "xdg-open", path }, { detach = true }) end, }, window = { mappings = { ["O"] = "system_open", ["h"] = function(state) local node = state.tree:get_node() if node.type == "directory" and node:is_expanded() then require("neo-tree.sources.filesystem").toggle_directory(state, node) else require("neo-tree.ui.renderer").focus_node(state, node:get_parent_id()) end end, ["l"] = function(state) local node = state.tree:get_node() if node.type == "directory" then if not node:is_expanded() then require("neo-tree.sources.filesystem").toggle_directory(state, node) elseif node:has_children() then require("neo-tree.ui.renderer").focus_node(state, node:get_child_ids()[1]) end end end, }, }, }, keys = { { "ff", "Neotree", desc = "Neotree Explorer (sidebar)" } }, }, } end local function makespecs_previewers() return { { "chomosuke/typst-preview.nvim", lazy = false, -- or ft = 'typst' version = "1.*", opts = { -- debug = true, port = 10010, dependencies_bin = { ["tinymist"] = "tinymist" }, follow_cursor = false, invert_colors = "auto", get_root = function(filename) local root = os.getenv("TYPST_ROOT") if root then return root end local dir0 = vim.fn.fnamemodify(filename, ":p:h") local dir = dir0 for _ = 1, 10 do if vim.fn.isdirectory(dir .. "/.git/") ~= 0 or vim.fn.filereadable(dir .. "/.git") ~= 0 then print("root dir: " .. dir) return dir end dir = vim.fn.fnamemodify(dir, ":p:h:h") end return dir0 end, }, }, { -- live preview of markdown files "iamcco/markdown-preview.nvim", -- requires yarn cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" }, ft = { "markdown" }, build = function() vim.fn["mkdp#util#install"]() end, init = function() vim.g.mkdp_auto_start = 0 -- auto start on moving into vim.g.mkdp_auto_close = 0 -- auto close on moving away vim.g.mkdp_open_to_the_world = 1 -- available to others vim.g.mkdp_port = 10010 vim.g.mkdp_echo_preview_url = 1 vim.g.mkdp_preview_options = { disable_sync_scroll = 1 } end, }, { "MeanderingProgrammer/render-markdown.nvim", dependencies = { "nvim-treesitter/nvim-treesitter", "echasnovski/mini.icons" }, opts = { code = { sign = false, width = "block", right_pad = 1 }, header = { sign = false, icons = {} }, checkbox = { enabled = false }, }, ft = { "markdown" }, config = function(_, opts) require("render-markdown").setup(opts) Snacks.toggle({ name = "Render Markdown", get = function() return require("render-markdown.state").enabled end, set = function(enabled) local m = require("render-markdown") if enabled then m.enable() else m.disable() end end, }):map("um") end, }, } end local function makespec_vimflog() return { { "rbong/vim-flog", dependencies = { "tpope/vim-fugitive" }, cmd = { "Flog", "Flogsplit", "Floggit" }, config = function() vim.g.flog_permanent_default_opts = { -- format = "%ad [%h] {%an}%d %s", format = "%ad [%h]%d %s", date = "short", } end, keys = { { "gf", "vertical Flogsplit -path=%", desc = "Git Flog File" }, { "gc", "vertical Flogsplit", desc = "Git Flog" }, }, }, } end local function makespec_diffview() return { "sindrets/diffview.nvim", cmd = { "DiffviewOpen", "DiffviewClose", "DiffviewToggleFiles", "DiffviewFocusFiles", "DiffviewRefresh", "DiffviewFileHistory", }, keys = { { "gd", "DiffviewOpen", desc = "DiffView Tab" }, { "gh", "DiffviewFileHistory", desc = "File History Tab" }, }, } end local function makespec_fugitive() return { "tpope/vim-fugitive", cmd = { "Git", "Gedit", "Gdiffsplit", "Gread", "Gwrite", "Ggrep", "Glgrep", "Gmove", "GRename", "GDelete", "GRemove", "Gdelete", "GUnlink", "GBrowse", }, config = function() vim.api.nvim_create_autocmd("User", { pattern = { "FugitiveCommit", "BufReadPost" }, callback = function() vim.opt_local.foldmethod = "syntax" vim.opt_local.foldlevel = 0 end, }) end, keys = { { "gg", "vertical Git", desc = "Fugitive" }, { "gp", "Git push", desc = "Git Push" }, { "gP", "Git push -f", desc = "Git Force Push" }, }, } end local function makespec_gitsigns() local function on_gitsigns_attach(bufnr) local gs = require("gitsigns") local function next_hunk() if vim.wo.diff then return "]c" end vim.schedule(function() gs.nav_hunk("next") end) return "" end local function prev_hunk() if vim.wo.diff then return "[c" end vim.schedule(function() gs.nav_hunk("prev") end) return "" end local function bmap(mode, l, r, desc) vim.keymap.set(mode, l, r, { buffer = bufnr, desc = desc }) end -- Navigation bmap("n", "", next_hunk, "Prev Hunk") bmap("n", "", prev_hunk, "Next Hunk") bmap("n", "[h", prev_hunk, "Prev Hunk") bmap("n", "]h", next_hunk, "Next Hunk") -- Blame bmap("n", "gB", gs.blame, "Blame Buffer") bmap("n", "gb", function() gs.blame_line({ full = true }) end, "Blame Line") -- Hunk bmap("n", "gI", gs.preview_hunk_inline, "Preview Hunk Inline") bmap("n", "gi", gs.preview_hunk, "Preview Hunk") bmap("n", "gq", gs.setqflist, "File Hunks to QuickFix") bmap("n", "gQ", function() gs.setqflist("all") end, "All Hunks to QuickFix") bmap("n", "gx", gs.reset_hunk, "Reset Hunk") bmap("v", "gx", function() gs.reset_hunk({ vim.fn.line("."), vim.fn.line("v") }) end, "Reset Hunk") bmap("n", "gR", gs.reset_buffer, "Reset Buffer") bmap("n", "gs", gs.stage_hunk, "Stage Hunk") bmap("v", "gs", function() gs.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) end, "Stage Hunk") bmap("n", "gS", gs.stage_buffer, "Stage Buffer") bmap("n", "gu", gs.undo_stage_hunk, "Undo Stage Hunk") bmap({ "n", "v" }, "gv", gs.select_hunk, "Select Hunk") -- Toggles bmap("n", "gtd", gs.toggle_deleted, "Toggle Show Deleted Lines") bmap("n", "gtl", gs.toggle_linehl, "Toggle Diff Line Highlight") bmap("n", "gtb", gs.toggle_current_line_blame, "Toggle Line Blame") bmap("n", "gth", gs.toggle_word_diff, "Toggle Diff Word Colors") bmap("n", "gtn", gs.toggle_numhl, "Toggle Diff Line Number Highlight") -- Text object, e.g. for dih to delete hunk bmap({ "o", "x" }, "ih", "Gitsigns select_hunk") end return { "lewis6991/gitsigns.nvim", opts = { signcolumn = true, numhl = true, linehl = false, word_diff = false, signs_staged_enable = false, on_attach = on_gitsigns_attach, -- extra thin lines signs = { add = { text = "▎" }, change = { text = "▎" }, delete = { text = "▎" }, topdelete = { text = "▎" }, changedelete = { text = "▎" }, untracked = { text = "▎" }, }, signs_staged = { add = { text = "▎" }, change = { text = "▎" }, delete = { text = "▎" }, topdelete = { text = "▎" }, changedelete = { text = "▎" }, }, }, } end local function makespec_orgmode() return { "nvim-orgmode/orgmode", event = "VeryLazy", config = function() -- Setup orgmode require("orgmode").setup({ org_agenda_files = "~/notes/orgfiles/**/*", org_default_notes_file = "~/notes/orgfiles/refile.org", }) end, } end local function makespec_whichkey() return { "folke/which-key.nvim", event = "VeryLazy", opts = { defaults = {}, spec = { { mode = { "n", "v" }, { "c", group = "code/content" }, { "f", group = "file/find" }, { "g", group = "git" }, { "gt", group = "toggles" }, { "l", group = "logs" }, { "p", group = "autoformat" }, { "q", group = "quit" }, { "s", group = "search" }, { "u", group = "ui", icon = { icon = "󰙵 ", color = "cyan" } }, { "[", group = "prev" }, { "]", group = "next" }, { "g", group = "goto" }, { "gs", group = "surround" }, { "z", group = "fold" }, { "", group = "tabs" }, { "w", group = "windows", proxy = "", expand = function() return require("which-key.extras").expand.win() end, }, -- better descriptions { "gx", desc = "Open with system app" }, }, }, }, keys = { { "?", function() require("which-key").show({ global = false }) end, desc = "Buffer Keymaps (which-key)", }, { "", function() require("which-key").show({ keys = "", loop = true }) end, desc = "Window Hydra Mode (which-key)", }, }, } end local function makespec_snacks() local function term_nav(dir) ---@param self snacks.terminal return function(self) return self:is_floating() and "" or vim.schedule(function() vim.cmd.wincmd(dir) end) end end return { "folke/snacks.nvim", priority = 1000, lazy = false, ---@type snacks.Config opts = { bigfile = { enabled = true, notify = true, -- show notification when big file detected size = 1.5 * 1024 * 1024, -- 1.5MB line_length = 1000, -- average line length (useful for minified files) -- Enable or disable features when big file detected ---@param ctx {buf: number, ft:string} setup = function(ctx) if vim.fn.exists(":NoMatchParen") ~= 0 then vim.cmd([[NoMatchParen]]) end Snacks.util.wo(0, { foldmethod = "manual", statuscolumn = "", conceallevel = 0 }) vim.schedule(function() if vim.api.nvim_buf_is_valid(ctx.buf) then vim.bo[ctx.buf].syntax = ctx.ft end end) end, }, bufdelete = { enabled = true }, debug = { enabled = true }, image = { enabled = true }, indent = { enabled = true }, lazygit = { enabled = vim.fn.has("lazygit") == 1 }, notifier = { enabled = true, style = "minimal", refresh = 500, top_down = false, }, ---@class snacks.picker picker = { formatters = { file = { filename_first = true } }, win = { preview = { wo = { statuscolumn = "" } } }, }, quickfile = { enabled = true }, rename = { enabled = true }, scope = { enabled = true }, terminal = { win = { keys = { nav_h = { "", term_nav("h"), desc = "Go to Left Window", expr = true, mode = "t" }, nav_j = { "", term_nav("j"), desc = "Go to Lower Window", expr = true, mode = "t" }, nav_k = { "", term_nav("k"), desc = "Go to Upper Window", expr = true, mode = "t" }, nav_l = { "", term_nav("l"), desc = "Go to Right Window", expr = true, mode = "t" }, }, }, }, toggle = { enabled = true }, words = { enabled = true }, styles = { lazygit = { width = 0, height = 0, }, }, }, -- stylua: ignore keys = { { "fr", function() Snacks.rename.rename_file() end, desc = "Rename File" }, { "", function() Snacks.bufdelete() end, desc = "Delete Buffer" }, { "qd", function() Snacks.bufdelete() end, desc = "Delete Buffer" }, { "gl", function() Snacks.lazygit() end, desc = "Launch Lazygit" }, { ".", function() Snacks.scratch.open() end, desc = "Scratch Buffer" }, -- find { "", function() Snacks.picker.git_files() end, desc = "Find Git Files" }, { "fg", function() Snacks.picker.git_files() end, desc = "Find Git Files" }, { "fa", function() Snacks.picker.files() end, desc = "Find Files" }, { "fc", function() Snacks.picker.files({ cwd = "/home/hjalmarlucius/dotfiles" }) end, desc = "Find Config" }, { "fn", function() Snacks.picker.files({ cwd = "/home/hjalmarlucius/notes" }) end, desc = "Find Note", }, -- logs { "ll", function() Snacks.picker.notifications() end, desc = "Notification History" }, -- code { "cS", function() Snacks.picker.lsp_symbols() end, desc = "LSP Symbols" }, -- replaced by Trouble -- { "cW", function() Snacks.picker.lsp_workspace_symbols() end, desc = "LSP Workspace Symbols" }, -- { "cd", function() Snacks.picker.diagnostics() end, desc = "Diagnostics" }, -- terminal { "", function() Snacks.terminal.toggle() end, desc = "Snacks Terminal", mode={"n", "t"} }, { "", function() Snacks.terminal.toggle() end, desc = "which_key_ignore", mode={'n', "t"} }, -- search { "", function() Snacks.picker.help() end, desc = "Help Pages" }, { "", function() Snacks.picker.colorschemes() end, desc = "Colorschemes" }, { "", function() Snacks.picker.grep() end, desc = "Grep" }, { "*", function() Snacks.picker.grep_word() end, desc = "Visual selection or word", mode = { "n", "x" }, }, { "/", function() Snacks.picker.search_history() end, desc = "Search History" }, { ";", function() Snacks.picker.command_history() end, desc = "Command History" }, { "sB", function() Snacks.picker.grep_buffers() end, desc = "Grep Buffers" }, { "sb", function() Snacks.picker.lines() end, desc = "Grep Buffer" }, { "sc", function() Snacks.picker.grep({ cwd = "/home/hjalmarlucius/dotfiles" }) end, desc = "Grep Configs" }, { "sl", function() Snacks.picker.loclist() end, desc = "Location List" }, { "sn", function() Snacks.picker.grep({ cwd = "/home/hjalmarlucius/notes" }) end, desc = "Grep Notes", }, { "sp", function() Snacks.picker.projects() end, desc = "Find Projects" }, { "sq", function() Snacks.picker.qflist() end, desc = "Quickfix List" }, { "su", function() Snacks.picker.undo() end, desc = "Undo History" }, }, init = function() -- stylua: ignore vim.api.nvim_create_autocmd("User", { pattern = "VeryLazy", callback = function() -- Setup some globals for debugging (lazy-loaded) _G.dd = function(...) Snacks.debug.inspect(...) end _G.bt = function() Snacks.debug.backtrace() end vim.print = _G.dd -- Override print to use snacks for `:=` command Snacks.toggle.indent():map("u") Snacks.toggle.option("background", { off = "light", on = "dark", name = "Dark Background" }):map("ub") Snacks.toggle.option("conceallevel", { off = 0, on = vim.o.conceallevel > 0 and vim.o.conceallevel or 2 }):map("uc") Snacks.toggle.diagnostics():map("ud") Snacks.toggle.dim():map("uD") Snacks.toggle.inlay_hints():map("ui") Snacks.toggle.line_number():map("ul") Snacks.toggle.option("relativenumber", { name = "Relative Number" }):map("uL") Snacks.toggle.option("spell", { name = "Spelling" }):map("us") Snacks.toggle.treesitter():map("ut") Snacks.toggle.option("wrap", { name = "Wrap" }):map("uw") end, }) end, } end local function makespecs_mini() return { { "echasnovski/mini.basics", opts = { options = { basic = true, extra_ui = true }, mappings = { move_with_alt = true } }, }, { "echasnovski/mini.icons", opts = {} }, { "echasnovski/mini.surround", version = false, opts = {} }, } end local function makespec_trouble() return { "folke/trouble.nvim", cmd = { "Trouble" }, opts = { modes = { lsp = { win = { position = "right", size = 100 } }, diagnostics = { win = { position = "right", size = 100 } }, symbols = { win = { position = "right", size = 100 } }, loclist = { win = { position = "right", size = 100 } }, qflist = { win = { position = "right", size = 100 } }, }, }, keys = { { "cc", "Trouble diagnostics toggle filter.buf=0", desc = "Buffer Diagnostics" }, { "cd", "Trouble diagnostics toggle", desc = "Diagnostics" }, { "cr", "Trouble lsp_references toggle", desc = "References" }, { "cs", "Trouble symbols toggle", desc = "Document Symbols" }, { "ca", "Trouble lsp toggle", desc = "LSP references/definitions/..." }, { "cl", "Trouble loclist toggle", desc = "Location List" }, { "cq", "Trouble qflist toggle", desc = "Quickfix List" }, { "[x", function() if require("trouble").is_open() then require("trouble").prev({ skip_groups = true, jump = true }) else local ok, err = pcall(vim.cmd.cprev) if not ok then vim.notify(err, vim.log.levels.ERROR) end end end, desc = "Previous Trouble/Quickfix Item", }, { "]x", function() if require("trouble").is_open() then require("trouble").next({ skip_groups = true, jump = true }) else local ok, err = pcall(vim.cmd.cnext) if not ok then vim.notify(err, vim.log.levels.ERROR) end end end, desc = "Next Trouble/Quickfix Item", }, }, } end local function makespec_todocomments() return { "folke/todo-comments.nvim", dependencies = { "nvim-lua/plenary.nvim" }, lazy = false, opts = { signs = true, -- show icons in the signs column sign_priority = 8, -- sign priority keywords = { MAYBE = { icon = " " }, PERF = { icon = " " }, FIX = { icon = " ", color = "error", alt = { "BUG" } }, TODO = { icon = " ", color = "info" }, HACK = { icon = " ", color = "warning" }, WARN = { icon = " ", color = "warning" }, NOTE = { icon = " ", color = "hint" }, TEST = { icon = "⏲ ", color = "test" }, }, merge_keywords = false, -- when true, custom keywords will be merged with the defaults highlight = { keyword = "bg", pattern = [[.*<(KEYWORDS)\s*]] }, search = { pattern = [[\b(KEYWORDS)\b]] }, colors = { error = { "#ba1a1a" }, warning = { "#FFC107" }, info = { "#91BED0" }, hint = { "#10B981" }, default = { "#91D0C1" }, }, }, keys = { { "]t", function() require("todo-comments").jump_next() end, desc = "Next Todo Comment" }, { "[t", function() require("todo-comments").jump_prev() end, desc = "Previous Todo Comment" }, { "ct", "Trouble todo toggle", desc = "Comments list" }, { "cT", "Trouble todo toggle filter = {tag = {TODO,FIX,FIXME}}", desc = "Todo/Fix/Fixme list", }, }, } end local function makespec_tmuxnav() return { -- tmux / vim interop "alexghergh/nvim-tmux-navigation", config = function() require("nvim-tmux-navigation").setup({ disable_when_zoomed = true, -- defaults to false keybindings = { left = "", down = "", up = "", right = "", last_active = "", }, }) end, } end local function makespec_mason() return { "williamboman/mason.nvim", lazy = false, opts = {}, keys = { { "", "Mason", desc = "Mason" } }, } end local function makespec_flash() return { "folke/flash.nvim", event = "VeryLazy", opts = { search = { mode = "exact", exclude = { "notify", "noice", "flash_prompt", function(win) return not vim.api.nvim_win_get_config(win).focusable end, }, }, label = { uppercase = false }, jump = { autojump = true }, modes = { search = { enabled = true }, char = { jump = { autojump = true }, char_actions = function(motion) return { [";"] = "next", -- set to `right` to always go right [","] = "prev", -- set to `left` to always go left [motion:lower()] = "next", [motion:upper()] = "prev", } end, }, }, }, -- stylua: ignore keys = { { "s", mode = { "n", "o", "x" }, function() require("flash").jump() end, desc = "Flash" }, { "S", mode = { "n", "o", "x" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" }, { "r", mode = "o", function() require("flash").remote() end, desc = "Remote Flash" }, { "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "Treesitter Search" }, { "", mode = { "c" }, function() require("flash").toggle() end, desc = "Toggle Flash Search" }, }, } end local function makespec_grugfar() return { "MagicDuck/grug-far.nvim", opts = { headerMaxWidth = 80 }, cmd = "GrugFar", keys = { { "sr", function() local grug = require("grug-far") local ext = vim.bo.buftype == "" and vim.fn.expand("%:e") grug.open({ transient = true, prefills = { filesFilter = ext and ext ~= "" and "*." .. ext or nil, }, }) end, mode = { "n", "v" }, desc = "Search and Replace", }, }, } end local function makespec_treesitter() return { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", opts = { { ensure_installed = { "bash", "c", "cpp", "git_rebase", "gitcommit", "lua", "python", "regex", "vimdoc", }, auto_install = true, highlight = { enable = true }, indent = { enable = true, disable = { "python" }, additional_vim_regex_highlighting = { "python" } }, -- incremental_selection done by flash plugin }, }, init = function() vim.opt.foldexpr = "nvim_treesitter#foldexpr()" end, } end local function makespec_hlslens() return { -- search count > 99 "kevinhwang91/nvim-hlslens", dependencies = { "haya14busa/vim-asterisk" }, cmd = { "HlSearchLensDisable", "HlSearchLensEnable", "HlSearchLensToggle" }, opts = { nearest_only = true, nearest_float_when = "never" }, keys = { { "*", [[(asterisk-z*)lua require('hlslens').start()]], mode = { "n", "x" }, {} }, { "#", [[(asterisk-z#)lua require('hlslens').start()]], mode = { "n", "x" }, {} }, { "g*", [[(asterisk-gz*)lua require('hlslens').start()]], mode = { "n", "x" }, {} }, { "g#", [[(asterisk-gz#)lua require('hlslens').start()]], mode = { "n", "x" }, {} }, { "n", [[nlua require('hlslens').start()]], mode = { "n", "x" }, noremap = true, silent = true }, { "N", [[Nlua require('hlslens').start()]], mode = { "n", "x" }, noremap = true, silent = true }, }, init = function() vim.g["asterisk#keeppos"] = 1 end, } end local function makespec_autotag() return { "windwp/nvim-ts-autotag", dependencies = { "nvim-treesitter/nvim-treesitter" }, opts = { filetypes = { "html", "xml" } }, } end local function makespec_lint() return { "mfussenegger/nvim-lint", config = function() require("lint").linters_by_ft = { javascript = { "eslint_d" }, typescript = { "eslint_d" }, html = { "tidy", "eslint_d" }, go = { "golangcilint" }, sh = { "shellcheck" }, } vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, { callback = function() require("lint").try_lint() end, }) end, } end local function makespec_conform() return { "stevearc/conform.nvim", lazy = true, cmd = { "ConformInfo" }, keys = { { "p", function() require("conform").format() end, silent = true, desc = "Autoformat" }, { "lp", "e ~/.local/state/nvim/conform.log", desc = "Conform log" }, }, opts = { formatters_by_ft = { ["_"] = { "trim_whitespace" }, css = { "prettierd", "prettier", stop_after_first = true }, go = { "gofumpt", "golines" }, html = { "prettierd", "prettier", stop_after_first = true }, javascript = { "prettierd", "prettier", stop_after_first = true }, json = { "jq" }, lua = { "stylua" }, markdown = { "prettierd", "prettier", stop_after_first = true }, python = { "ruff_format", "ruff_fix", "ruff_organize_imports" }, sh = { "shfmt" }, bash = { "shfmt" }, typescript = { "eslint_d" }, typst = { "typstyle" }, yaml = { "yamlfix", "yamlfmt" }, }, default_format_opts = { timeout_ms = 3000, lsp_format = "fallback", }, formatters = { javascript = { require_cwd = true }, stylua = { append_args = { "--indent-type", "Spaces", "--collapse-simple-statement", "Always" } }, ruff_fix = { append_args = { "--select", "I,F,UP" } }, yamlfmt = { append_args = { "-formatter", "indentless_arrays=true,retain_line_breaks=true,line_ending=lf,max_line_length=100,pad_line_comments=2", }, }, }, }, } end local function makespec_noice() return { "folke/noice.nvim", event = "VeryLazy", dependencies = { "MunifTanjim/nui.nvim", "rcarriga/nvim-notify" }, opts = { messages = { enabled = true, view = "notify", view_error = "notify", view_warn = "notify", view_history = "popup", view_search = false, }, lsp = { override = { ["vim.lsp.util.convert_input_to_markdown_lines"] = true, ["vim.lsp.util.stylize_markdown"] = true, }, signature = { enabled = true, auto_open = { enabled = false, throttle = 50 } }, }, presets = { command_palette = true, long_message_to_split = true, }, routes = { { filter = { event = "msg_show", kind = "search_count" }, opts = { skip = true } }, { filter = { kind = "", min_height = 2 }, view = "split" }, }, }, keys = { { "lx", function() require("noice").cmd("dismiss") end, desc = "Noice dismiss" }, { "lh", function() require("noice").cmd("all") end, desc = "Noice history" }, { "ls", function() require("noice").cmd("stats") end, desc = "Noice stats" }, { "un", function() require("noice").cmd("enable") end, desc = "Enable Noice" }, { "uN", function() require("noice").cmd("disable") end, desc = "Disable Noice" }, }, } end -- ---------------------------------------- -- LAZY -- ---------------------------------------- local lazyspecs = { "dhruvasagar/vim-table-mode", -- tables "itchyny/vim-qfedit", -- editable quickfix list { "ethanholz/nvim-lastplace", opts = {} }, -- keep location upon reopening "tpope/vim-eunuch", -- Move, Rename etc "tpope/vim-sleuth", -- do the right thing with tabstop and softtabstop "mbbill/undotree", } for _, spec in ipairs({ makespec_snacks(), makespec_conform(), -- autoformat makespec_lspconfig(), makespec_treesitter(), makespec_todocomments(), makespec_trouble(), makespec_autotag(), makespec_lint(), makespec_mason(), makespec_orgmode(), -- navigation makespec_whichkey(), makespec_tmuxnav(), makespec_hlslens(), makespec_flash(), makespec_grugfar(), -- visuals makespec_lualine(), makespec_noice(), -- file browsers makespec_neotree(), makespec_oil(), -- git makespec_gitsigns(), makespec_fugitive(), makespec_diffview(), makespec_vimflog(), }) do table.insert(lazyspecs, spec) end for _, specs in ipairs({ makespecs_themes(), makespecs_mini(), makespecs_previewers(), }) do for _, spec in ipairs(specs) do table.insert(lazyspecs, spec) end end local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not (vim.uv or vim.loop).fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", "https://github.com/folke/lazy.nvim.git", lazypath, }) end vim.opt.rtp:prepend(lazypath) require("lazy").setup({ spec = lazyspecs, install = { colorscheme = { "habamax" } }, checker = { enabled = true }, })