-- 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" }, })