-- Bootstrap the Packer plugin manager local fn = vim.fn local install_path = fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim" if fn.empty(fn.glob(install_path)) > 0 then packer_bootstrap = fn.system({ "git", "clone", "--depth", "1", "https://github.com/wbthomason/packer.nvim", install_path, }) end -- Packer plugin installations require("packer").startup(function(use) -- Maintain plugin manager use("wbthomason/packer.nvim") -- Startup speed hacks use({ "lewis6991/impatient.nvim", config = function() require("impatient") end, }) -- Important tweaks use("tpope/vim-surround") --- Manipulate parentheses use("tpope/vim-commentary") --- Use gc or gcc to add comments -- Convenience tweaks use("tpope/vim-eunuch") --- File manipulation in Vim use("tpope/vim-vinegar") --- Fixes netrw file explorer use("tpope/vim-fugitive") --- Git commands and syntax use("tpope/vim-repeat") --- Actually repeat using . use("christoomey/vim-tmux-navigator") --- Hotkeys for tmux panes -- Colorscheme use({ "morhetz/gruvbox", config = function() vim.g.gruvbox_italic = 1 vim.cmd([[colorscheme gruvbox]]) end, }) -- Git next to line numbers use({ "lewis6991/gitsigns.nvim", branch = "main", requires = { "nvim-lua/plenary.nvim" }, config = function() require("gitsigns").setup() end, }) -- Status bar use({ "hoob3rt/lualine.nvim", requires = { "kyazdani42/nvim-web-devicons", opt = true }, config = function() require("lualine").setup({ options = { theme = "gruvbox", icons_enabled = true, }, }) end, }) -- Improve speed and filetype detection use({ "nathom/filetype.nvim", config = function() -- Filetype for .env files local envfiletype = function() vim.bo.filetype = "text" vim.bo.syntax = "sh" end -- Force filetype patterns that Vim doesn't know about require("filetype").setup({ overrides = { extensions = { Brewfile = "brewfile", muttrc = "muttrc", tfvars = "terraform", tf = "terraform", }, literal = { Caskfile = "brewfile", [".gitignore"] = "gitignore", config = "config", }, complex = { [".*git/config"] = "gitconfig", ["tmux.conf%..*link"] = "tmux", ["gitconfig%..*link"] = "gitconfig", [".*ignore%..*link"] = "gitignore", [".*%.toml%..*link"] = "toml", }, function_extensions = {}, function_literal = { [".envrc"] = envfiletype, [".env"] = envfiletype, [".env.dev"] = envfiletype, [".env.prod"] = envfiletype, [".env.example"] = envfiletype, }, }, }) end, }) -- Alignment tool use("godlygeek/tabular") -- Markdown renderer / wiki notes use("vimwiki/vimwiki") -- Markdown pretty view use("ellisonleao/glow.nvim") -- Hex color previews use({ "norcalli/nvim-colorizer.lua", config = function() require("colorizer").setup() end, }) -- Snippet engine use("L3MON4D3/LuaSnip") -- ======================================================================= -- Language Server -- ======================================================================= -- Language server engine use({ "neovim/nvim-lspconfig", requires = { "hrsh7th/cmp-nvim-lsp" }, config = function() local capabilities = require("cmp_nvim_lsp").update_capabilities( vim.lsp.protocol.make_client_capabilities() ) require("lspconfig").rust_analyzer.setup({ capabilities = capabilities }) require("lspconfig").tflint.setup({ capabilities = capabilities }) require("lspconfig").terraformls.setup({ capabilities = capabilities }) require("lspconfig").pyright.setup({ on_attach = function() -- set keymaps (requires 0.7.0) -- vim.keymap.set("n", "", "", {buffer=0}) end, capabilities = capabilities, }) end, }) -- Pretty highlights use("folke/lsp-colors.nvim") -- Linting use({ "jose-elias-alvarez/null-ls.nvim", branch = "main", requires = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig", }, config = function() require("null-ls").setup({ sources = { require("null-ls").builtins.formatting.stylua, require("null-ls").builtins.formatting.black, require("null-ls").builtins.formatting.fish_indent, require("null-ls").builtins.formatting.nixfmt, require("null-ls").builtins.formatting.rustfmt, require("null-ls").builtins.diagnostics.shellcheck, require("null-ls").builtins.formatting.shfmt.with({ extra_args = { "-i", "4", "-ci" }, }), require("null-ls").builtins.formatting.terraform_fmt, -- require("null-ls").builtins.diagnostics.luacheck, -- require("null-ls").builtins.diagnostics.markdownlint, -- require("null-ls").builtins.diagnostics.pylint, }, -- Format on save on_attach = function(client) if client.resolved_capabilities.document_formatting then vim.cmd([[ augroup LspFormatting autocmd! * autocmd BufWritePre lua vim.lsp.buf.formatting_seq_sync() augroup END ]]) end end, }) end, }) -- ======================================================================= -- Completion System -- ======================================================================= -- Completion sources use("hrsh7th/cmp-nvim-lsp") --- Language server completion plugin use("hrsh7th/cmp-buffer") --- Generic text completion use("hrsh7th/cmp-path") --- Local file completion use("hrsh7th/cmp-cmdline") --- Command line completion use("hrsh7th/cmp-nvim-lua") --- Nvim lua api completion use("saadparwaiz1/cmp_luasnip") --- Luasnip completion use("lukas-reineke/cmp-rg") --- Ripgrep completion -- Completion engine use({ "hrsh7th/nvim-cmp", requires = { "L3MON4D3/LuaSnip" }, config = function() local cmp = require("cmp") cmp.setup({ snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end, }, mapping = { [""] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }), [""] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }), [""] = function(fallback) cmp.mapping({ i = cmp.mapping.abort(), c = cmp.mapping.close(), }) vim.cmd("stopinsert") --- Abort and leave insert mode end, -- [''] = cmp.mapping(cmp.mapping.select_next_item(), { 'i', 's' }), -- [''] = cmp.mapping(cmp.mapping.select_prev_item(), { 'i', 's' }), [""] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Insert, select = true, }), [""] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true, }), [""] = cmp.mapping(function(fallback) if require("luasnip").expand_or_jumpable() then require("luasnip").expand_or_jump() end end, { "i", "s" }), }, sources = { { name = "nvim_lua" }, { name = "nvim_lsp" }, { name = "path" }, { name = "luasnip" }, { name = "buffer", keyword_length = 3, max_item_count = 10 }, { name = "rg", keyword_length = 6, max_item_count = 10, option = { additional_arguments = "--ignore-case" }, }, }, experimental = { native_menu = false, --- Use cmp menu instead of Vim menu ghost_text = true, --- Show preview auto-completion }, }) -- Use buffer source for `/` cmp.setup.cmdline("/", { sources = { { name = "buffer", keyword_length = 5 }, }, }) -- Use cmdline & path source for ':' cmp.setup.cmdline(":", { sources = cmp.config.sources({ { name = "path" }, }, { { name = "cmdline" }, }), }) end, }) -- ======================================================================= -- Syntax -- ======================================================================= -- Syntax engine use({ "nvim-treesitter/nvim-treesitter", run = ":TSUpdate", config = function() require("nvim-treesitter.configs").setup({ ensure_installed = { "hcl", "python", "lua", "nix", "fish", "toml", "yaml", "json", }, highlight = { enable = true }, indent = { enable = true }, }) end, }) -- Additional syntax sources use("bfontaine/Brewfile.vim") --- Brewfile syntax use("chr4/nginx.vim") --- Nginx syntax use("towolf/vim-helm") --- Helm syntax use("rodjek/vim-puppet") --- Puppet syntax -- ======================================================================= -- Fuzzy Launcher -- ======================================================================= use({ "nvim-telescope/telescope.nvim", requires = { "nvim-lua/plenary.nvim" }, config = function() -- Telescope: quit instantly with escape local actions = require("telescope.actions") require("telescope").setup({ defaults = { mappings = { i = { [""] = actions.close, [""] = "which_key", }, }, }, pickers = { find_files = { theme = "ivy" }, oldfiles = { theme = "ivy" }, buffers = { theme = "dropdown" }, }, extensions = { fzy_native = {}, tmux = {}, zoxide = {}, --neoclip = {}, project = { base_dirs = { "~/dev/work" }, }, }, }) end, }) -- Faster sorting use("nvim-telescope/telescope-fzy-native.nvim") -- Jump around tmux sessions use("camgraff/telescope-tmux.nvim") -- Jump directories use({ "jvgrootveld/telescope-zoxide", requires = { "nvim-lua/popup.nvim" }, }) -- Jump projects use({ "nvim-telescope/telescope-project.nvim", requires = { "nvim-telescope/telescope.nvim" }, config = function() require("telescope").load_extension("project") end, }) -- File browser use({ "nvim-telescope/telescope-file-browser.nvim", requires = { "nvim-telescope/telescope.nvim" }, config = function() require("telescope").load_extension("file_browser") end, }) -- Clipboard history -- use({ -- "AckslD/nvim-neoclip.lua", -- branch = "main", -- requires = { -- { "tami5/sqlite.lua", module = "sqlite" }, -- { "nvim-telescope/telescope.nvim" }, -- }, -- config = function() -- require("neoclip").setup({ -- enable_persistant_history = true, -- default_register = { "+", '"' }, -- keys = { -- telescope = { -- i = { paste = "" }, -- }, -- }, -- }) -- require("telescope").load_extension("neoclip") -- end, -- }) -- Project bookmarks use({ "ThePrimeagen/harpoon", requires = { "nvim-lua/plenary.nvim", "nvim-telescope/telescope.nvim", }, }) -- TLDR Lookup use({ "mrjones2014/tldr.nvim", requires = { "nvim-telescope/telescope.nvim" }, }) -- ======================================================================= -- Install on initial bootstrap if packer_bootstrap then require("packer").sync() end end) -- =========================================================================== -- Settings -- =========================================================================== vim.o.termguicolors = true --- Set to truecolor vim.o.hidden = true --- Don't unload buffers when leaving them vim.wo.number = true --- Show line numbers vim.wo.relativenumber = true --- Relative numbers instead of absolute vim.o.list = true --- Reveal whitespace with dashes vim.o.expandtab = true --- Tabs into spaces vim.o.shiftwidth = 4 --- Amount to shift with > key vim.o.softtabstop = 4 --- Amount to shift with key vim.o.ignorecase = true --- Ignore case when searching vim.o.smartcase = true --- Check case when using capitals in search vim.o.infercase = true --- Don't match cases when completing suggestions vim.o.incsearch = true --- Search while typing vim.o.visualbell = true --- No sounds vim.o.scrolljump = 1 --- Number of lines to scroll vim.o.scrolloff = 3 --- Margin of lines to see while scrolling vim.o.splitright = true --- Vertical splits on the right side vim.o.splitbelow = true --- Horizontal splits on the bottom side vim.o.pastetoggle = "" --- Use F3 to enter raw paste mode vim.o.clipboard = "unnamedplus" --- Uses system clipboard for yanking vim.o.updatetime = 300 --- Faster diagnostics vim.o.mouse = "nv" --- Mouse interaction / scrolling -- Neovim features vim.o.inccommand = "split" --- Live preview search and replace --- Required for nvim-cmp completion vim.opt.completeopt = { "menu", "menuone", "noselect", } -- Required until 0.6.0: do not source the default filetype.vim vim.g.did_load_filetypes = 1 -- Remember last position when reopening file vim.api.nvim_exec( [[ au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal! g`\"" | endif ]], false ) -- Better backup, swap and undo storage vim.o.backup = true --- Easier to recover and more secure vim.bo.swapfile = false --- Instead of swaps, create backups vim.bo.undofile = true --- Keeps undos after quit -- Create backup directories if they don't exist -- Should be fixed in 0.6 by https://github.com/neovim/neovim/pull/15433 vim.o.backupdir = vim.fn.stdpath("cache") .. "/backup" vim.api.nvim_exec( [[ if !isdirectory(&backupdir) call mkdir(&backupdir, "p") endif ]], false ) -- LaTeX options vim.api.nvim_exec( [[ au FileType tex inoremap ;bf \textbf{}i au BufWritePost *.tex silent! execute "!pdflatex -output-directory=%:p:h % >/dev/null 2>&1" | redraw! ]], false ) -- Highlight when yanking vim.api.nvim_exec( [[ au TextYankPost * silent! lua vim.highlight.on_yank { timeout = 250 } ]], false ) -- Netrw vim.g.netrw_liststyle = 3 -- Change style to 'tree' view vim.g.netrw_banner = 0 -- Remove useless banner vim.g.netrw_winsize = 15 -- Explore window takes % of page vim.g.netrw_browse_split = 4 -- Open in previous window vim.g.netrw_altv = 1 -- Always split left -- VimWiki vim.g.vimwiki_list = { { ["path"] = "$NOTES_PATH", ["syntax"] = "markdown", ["index"] = "home", ["ext"] = ".md", }, } vim.g.vimwiki_key_mappings = { ["all_maps"] = 1, ["mouse"] = 1, } vim.g.vimwiki_auto_chdir = 1 -- Set local dir to Wiki when open vim.g.vimwiki_create_link = 0 -- Don't automatically create new links vim.g.vimwiki_listsyms = " x" -- Set checkbox symbol progression vim.g.vimwiki_table_mappings = 0 -- VimWiki table keybinds interfere with tab completion vim.api.nvim_exec( [[ au FileType markdown inoremap ;tt :AddTag function! PInsert(item) let @z=a:item norm "zpx endfunction command! AddTag call fzf#run({'source': 'rg "#[A-Za-z/]+[ |\$]" -o --no-filename --no-line-number | sort | uniq', 'sink': function('PInsert')}) ]], false ) -- =========================================================================== -- Custom Functions -- =========================================================================== grep_notes = function() local opts = { prompt_title = "Search Notes", cwd = "$NOTES_PATH", } require("telescope.builtin").live_grep(opts) end find_notes = function() local opts = { prompt_title = "Find Notes", cwd = "$NOTES_PATH", } require("telescope.builtin").find_files(opts) end find_downloads = function() local opts = { prompt_title = "Find Downloads", cwd = "~/Downloads", } require("telescope").extensions.file_browser.file_browser(opts) end choose_project = function() local opts = require("telescope.themes").get_ivy({ layout_config = { bottom_pane = { height = 10, }, }, }) require("telescope").extensions.project.project(opts) end -- clipboard_history = function() -- local opts = require("telescope.themes").get_cursor({ -- layout_config = { -- cursor = { -- width = 150, -- }, -- }, -- }) -- require("telescope").extensions.neoclip.neoclip(opts) -- end command_history = function() local opts = require("telescope.themes").get_ivy({ layout_config = { bottom_pane = { height = 15, }, }, }) require("telescope.builtin").command_history(opts) end -- =========================================================================== -- Key Mapping -- =========================================================================== -- Function to cut down config boilerplate local key = function(mode, key_sequence, action, params) params = params or {} params["noremap"] = true vim.api.nvim_set_keymap(mode, key_sequence, action, params) end -- Remap space as leader key key("", "", "", { silent = true }) vim.g.mapleader = " " vim.g.maplocalleader = " " -- Keep selection when changing indentation key("v", "<", "", ">gv") -- Clear search register key("n", "", ":noh", { silent = true }) -- Shuffle lines around key("n", "", ":m .+1==") key("n", "", ":m .-2==") key("i", "", ":m .+1==gi") key("i", "", ":m .-2==gi") key("v", "", ":m '>+1gv=gv") key("v", "", ":m '<-2gv=gv") -- Telescope (fuzzy finder) key("n", "k", ":Telescope keymaps") key("n", "/", ":Telescope live_grep") key("n", "ff", ":Telescope find_files") key("n", "fp", ":Telescope git_files") key("n", "fN", "lua find_notes()") key("n", "N", "lua grep_notes()") key("n", "fD", "lua find_downloads()") key("n", "fa", ":Telescope file_browser") key("n", "fw", ":Telescope grep_string") key("n", "wt", ":Telescope tmux sessions") key("n", "ww", ":Telescope tmux windows") key("n", "w/", ":Telescope tmux pane_contents") key("n", "fz", ":Telescope zoxide list") key("n", "b", ":Telescope buffers") key("n", "hh", ":Telescope help_tags") key("n", "fr", ":Telescope oldfiles") key("n", "cc", ":Telescope commands") key("n", "cr", "lua command_history()") key("n", "y", "lua clipboard_history()") key("i", "", "lua clipboard_history()") key("n", "s", ":Telescope current_buffer_fuzzy_find") key("n", "gc", ":Telescope git_commits") key("n", "gf", ":Telescope git_bcommits") key("n", "gb", ":Telescope git_branches") key("n", "gs", ":Telescope git_status") key("n", "", "lua choose_project()") -- Harpoon key("n", "m", "lua require('harpoon.mark').add_file()") key("n", "`", "lua require('harpoon.ui').toggle_quick_menu()") key("n", "1", "lua require('harpoon.ui').nav_file(1)") key("n", "2", "lua require('harpoon.ui').nav_file(2)") key("n", "3", "lua require('harpoon.ui').nav_file(3)") -- LSP key("n", "gd", "lua vim.lsp.buf.definition()", { silent = true }) key("n", "gT", "lua vim.lsp.buf.type_definition()", { silent = true }) key("n", "gi", "lua vim.lsp.buf.implementation()", { silent = true }) key("n", "gh", "lua vim.lsp.buf.hover()", { silent = true }) key("n", "gr", "Telescope lsp_references", { silent = true }) key("n", "R", "lua vim.lsp.buf.rename()", { silent = true }) key("n", "]e", "lua vim.diagnostic.goto_next()", { silent = true }) key("n", "[e", "lua vim.diagnostic.goto_prev()", { silent = true }) key("n", "e", "lua vim.lsp.diagnostic.show_line_diagnostics()", { silent = true }) key("n", "E", "lua vim.lsp.buf.code_action()", { silent = true }) -- File commands key("n", "q", ":quit") key("n", "Q", ":quitall") key("n", "fs", ":write") key("n", "fd", ":lcd %:p:h", { silent = true }) key("n", "fu", ":lcd ..", { silent = true }) key("n", "", ":b#", { silent = true }) key("n", "gr", ":!gh repo view -w", { silent = true }) key("n", "tt", [[exe 'edit $NOTES_PATH/journal/'.strftime("%Y-%m-%d_%a").'.md']]) key("n", "jj", ":!journal:e") -- Window commands key("n", "wv", ":vsplit") key("n", "wh", ":split") key("n", "wm", ":only") -- Tabularize key("", "ta", ":Tabularize /") key("", "t#", ":Tabularize /#") key("", "tl", ":Tabularize /---") -- Vimrc editing key("n", "fv", ":edit $DOTS/nvim.configlink/init.lua") key("n", "rr", ":luafile $MYVIMRC") key("n", "rp", ":luafile $MYVIMRC:PackerInstall:") key("n", "rc", ":luafile $MYVIMRC:PackerCompile") -- Keep cursor in place key("n", "n", "nzz") key("n", "N", "Nzz") key("n", "J", "mzJ`z") --- Mark and jump back to it -- Add undo breakpoints key("i", ",", ",u") key("i", ".", ".u") key("i", "!", "!u") key("i", "?", "?u") -- Other key("t", "", "") --- Exit terminal mode key("n", "", ":noh", { silent = true }) --- Clear search in VimWiki key("n", "Y", "y$") --- Copy to end of line key("v", "", "y:%s/+//gc") --- Substitute selected key("v", "D", "y'>gp") --- Duplicate selected