-- Specify the leader -- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used) vim.g.mapleader = ";" vim.g.maplocalleader = ";" -- [[ Setting options ]] -- Make line numbers default vim.opt.number = true vim.opt.relativenumber = true -- Disable mouse mode vim.opt.mouse = "" -- Don't show the mode, since it's already in status line vim.opt.showmode = false -- Case-insensitive searching UNLESS \C or capital in search vim.opt.ignorecase = true vim.opt.smartcase = true -- Keep signcolumn on by default vim.opt.signcolumn = "yes" -- Configure how new splits should be opened vim.opt.splitright = true vim.opt.splitbelow = true -- Sets how neovim will display certain whitespace in the editor. -- See :help 'list' -- and :help 'listchars' vim.opt.list = true vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } -- Preview substitutions live, as you type! vim.opt.inccommand = "split" -- Show which line your cursor is on vim.opt.cursorline = true -- Minimal number of screen lines to keep above and below the cursor. -- vim.opt.scrolloff = 10 -- General universal settings vim.opt.sw = 4 vim.opt.ts = 4 vim.opt.expandtab = true vim.opt.tw = 100 vim.opt.colorcolumn = "+1" vim.opt.termguicolors = true vim.opt.pumheight = 5 -- Disable semantic tokens vim.api.nvim_create_autocmd("LspAttach", { callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) client.server_capabilities.semanticTokensProvider = nil end, }) -- Function to get work count in status line local function getWords() -- the third string here is the string for visual-block mode (^V) if vim.fn.mode() == "v" or vim.fn.mode() == "V" or vim.fn.mode() == "" then return vim.fn.wordcount().visual_words .. "" else return vim.fn.wordcount().words .. "" end end -- [[ Basic Keymaps ]] -- See `:help vim.keymap.set()` -- Set highlight on search, but clear on pressing in normal mode vim.opt.hlsearch = true vim.keymap.set("n", "", "nohlsearch") -- Diagnostic keymaps vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Go to previous [D]iagnostic message" }) vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Go to next [D]iagnostic message" }) vim.keymap.set("n", "e", vim.diagnostic.open_float, { desc = "Show diagnostic [E]rror messages" }) vim.keymap.set("n", "q", vim.diagnostic.setloclist, { desc = "Open diagnostic [Q]uickfix list" }) -- Keybinds to make split navigation easier. -- Use CTRL+ to switch between windows -- -- See `:help wincmd` for a list of all window commands vim.keymap.set("n", "", "", { desc = "Move focus to the left window" }) vim.keymap.set("n", "", "", { desc = "Move focus to the right window" }) vim.keymap.set("n", "", "", { desc = "Move focus to the lower window" }) vim.keymap.set("n", "", "", { desc = "Move focus to the upper window" }) -- Jump to the definition of the word under your cursor. -- This is where a variable was first declared, or where a function is defined, etc. -- To jump back, press . vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "" }) -- [[ Basic Autocommands ]] -- Go back to last edited line when reopening file vim.api.nvim_create_autocmd("BufRead", { callback = function(opts) vim.api.nvim_create_autocmd("BufWinEnter", { once = true, buffer = opts.buf, callback = function() local ft = vim.bo[opts.buf].filetype local last_known_line = vim.api.nvim_buf_get_mark(opts.buf, '"')[1] if not (ft:match("gitcommit") and ft:match("gitrebase")) and last_known_line > 1 and last_known_line <= vim.api.nvim_buf_line_count(opts.buf) then vim.api.nvim_feedkeys([[g`"]], "nx", false) end end, }) end, }) -- [[ Install `lazy.nvim` plugin manager ]] -- See `:help lazy.nvim.txt` or https://github.com/folke/lazy.nvim for more info local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then local lazyrepo = "https://github.com/folke/lazy.nvim.git" vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) end ---@diagnostic disable-next-line: undefined-field vim.opt.rtp:prepend(lazypath) -- Get user dictionary local path = vim.fn.stdpath("config") .. "/spell/en.utf-8.add" local words = {} for word in io.open(path, "r"):lines() do table.insert(words, word) end -- [[ Configure and install plugins ]] -- -- To check the current status of your plugins, run -- :Lazy -- -- You can press `?` in this menu for help. Use `:q` to close the window -- -- To update plugins, you can run -- :Lazy update -- -- -- NOTE: Here is where you install your plugins. require("lazy").setup({ -- [[ Plugin Specs list ]] -- NOTE: Plugins can be added with a link (or for a github repo: 'owner/repo' link). { "windwp/nvim-autopairs", config = function() local remap = vim.api.nvim_set_keymap local npairs = require("nvim-autopairs") npairs.setup({ map_bs = false, map_cr = false }) _G.MUtils = {} MUtils.CR = function() if vim.fn.pumvisible() ~= 0 then if vim.fn.complete_info({ "selected" }).selected ~= -1 then return npairs.esc("") else return npairs.esc("") .. npairs.autopairs_cr() end else return npairs.autopairs_cr() end end remap("i", "", "v:lua.MUtils.CR()", { expr = true, noremap = true }) MUtils.BS = function() if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info({ "mode" }).mode == "eval" then return npairs.esc("") .. npairs.autopairs_bs() else return npairs.autopairs_bs() end end remap("i", "", "v:lua.MUtils.BS()", { expr = true, noremap = true }) -- put this to setup function and press to use fast_wrap npairs.setup({ fast_wrap = {}, }) -- change default fast_wrap npairs.setup({ fast_wrap = { map = "", chars = { "{", "[", "(", '"', "'" }, pattern = [=[[%'%"%>%]%)%}%,]]=], end_key = "$", before_key = "h", after_key = "l", cursor_pos_before = true, keys = "qwertyuiopzxcvbnmasdfghjkl", manual_position = true, highlight = "Search", highlight_grey = "Comment", }, }) npairs.remove_rule("`") end, }, "christoomey/vim-tmux-navigator", "kana/vim-textobj-user", { "GCBallesteros/vim-textobj-hydrogen", dependencies = { "kana/vim-textobj-user", }, }, "godlygeek/tabular", "tpope/vim-sleuth", { "Vigemus/iron.nvim", ft = { "python" }, config = function() local iron = require("iron.core") local view = require("iron.view") iron.setup({ config = { -- Whether a repl should be discarded or not scratch_repl = true, -- Your repl definitions come here repl_definition = { python = { -- Can be a table or a function that -- returns a table (see below) command = "ipython --no-autoindent", }, }, -- How the repl window will be displayed -- See below for more information repl_open_cmd = require("iron.view").bottom(20), }, -- Iron doesn't set keymaps by default anymore. -- You can set them here or manually add keymaps to the functions in iron.core keymaps = { visual_send = "sc", send_file = "sf", send_line = "sl", cr = "s", interrupt = "s", exit = "sq", clear = "cl", }, -- If the highlight is on, you can change how it looks -- For the available options, check nvim_set_hl highlight = { italic = true, }, ignore_blank_lines = true, -- ignore blank lines when sending visual select lines }) vim.keymap.set("n", ";rs", "IronRepl") vim.keymap.set("n", ";rr", "IronRestart") vim.keymap.set("n", ";rf", "IronFocus") vim.keymap.set("n", ";rh", "IronHide") repl_open_cmd = "horizontal bot 20 split" end, }, "ixru/nvim-markdown", "KeitaNakamura/tex-conceal.vim", "christoomey/vim-tmux-navigator", "skywind3000/asyncrun.vim", -- NOTE: Plugins can specify dependencies. -- -- The dependencies are proper plugin specifications as well - anything -- you do for a plugin at the top level, you can do for a dependency. -- -- Use the `dependencies` key to specify the dependencies of a particular plugin { -- Fuzzy Finder (files, lsp, etc) "nvim-telescope/telescope.nvim", event = "VeryLazy", branch = "0.1.x", dependencies = { "nvim-lua/plenary.nvim", -- Useful for getting pretty icons, but requires special font. -- If you already have a Nerd Font, or terminal set up with fallback fonts -- you can enable this { "nvim-tree/nvim-web-devicons" }, { "nvim-telescope/telescope-live-grep-args.nvim" }, }, config = function() -- Telescope is a fuzzy finder that comes with a lot of different things that -- it can fuzzy find! It's more than just a "file finder", it can search -- many different aspects of Neovim, your workspace, LSP, and more! -- -- The easiest way to use telescope, is to start by doing something like: -- :Telescope help_tags -- -- After running this command, a window will open up and you're able to -- type in the prompt window. You'll see a list of help_tags options and -- a corresponding preview of the help. -- -- Two important keymaps to use while in telescope are: -- - Insert mode: -- - Normal mode: ? -- -- This opens a window that shows you all of the keymaps for the current -- telescope picker. This is really useful to discover what Telescope can -- do as well as how to actually do it! -- [[ Configure Telescope ]] -- See `:help telescope` and `:help telescope.setup()` require("telescope").setup({ -- You can put your default mappings / updates / etc. in here -- All the info you're looking for is in `:help telescope.setup()` -- defaults = vim.tbl_extend("force", require("telescope.themes").get_ivy(), { path_display = { "smart" }, }), }) pcall(require("telescope").load_extension("live_grep_args")) local builtin = require("telescope.builtin") vim.keymap.set("n", "", require("telescope").extensions.live_grep_args.live_grep_args) vim.keymap.set( "x", "", "\"zy:lua require('telescope').extensions.live_grep_args.live_grep_args(require('telescope.themes').get_ivy({}))z" ) vim.keymap.set("n", "", builtin.find_files) end, }, { -- LSP Configuration & Plugins "neovim/nvim-lspconfig", dependencies = { -- Automatically install LSPs and related tools to stdpath for neovim "williamboman/mason.nvim", "williamboman/mason-lspconfig.nvim", "WhoIsSethDaniel/mason-tool-installer.nvim", -- Useful status updates for LSP. -- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})` { "j-hui/fidget.nvim", opts = {} }, }, config = function() vim.api.nvim_create_autocmd("LspAttach", { group = vim.api.nvim_create_augroup("kickstart-lsp-attach", { clear = true }), callback = function(event) -- NOTE: Remember that lua is a real programming language, and as such it is possible -- to define small helper and utility functions so you don't have to repeat yourself -- many times. -- -- In this case, we create a function that lets us more easily define mappings specific -- for LSP related items. It sets the mode, buffer and description for us each time. local map = function(keys, func, desc) vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP: " .. desc }) end -- Find references for the word under your cursor. map("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") -- Jump to the implementation of the word under your cursor. -- Useful when your language has ways of declaring types without an actual implementation. map("I", require("telescope.builtin").lsp_implementations, "[G]oto [I]mplementation") -- Jump to the type of the word under your cursor. -- Useful when you're not sure what type a variable is and you want to see -- the definition of its *type*, not where it was *defined*. map("D", require("telescope.builtin").lsp_type_definitions, "Type [D]efinition") -- Fuzzy find all the symbols in your current document. -- Symbols are things like variables, functions, types, etc. map("ds", require("telescope.builtin").lsp_document_symbols, "[D]ocument [S]ymbols") -- Fuzzy find all the symbols in your current workspace -- Similar to document symbols, except searches over your whole project. map( "ws", require("telescope.builtin").lsp_dynamic_workspace_symbols, "[W]orkspace [S]ymbols" ) -- Rename the variable under your cursor -- Most Language Servers support renaming across files, etc. map("rn", vim.lsp.buf.rename, "[R]e[n]ame") -- Execute a code action, usually your cursor needs to be on top of an error -- or a suggestion from your LSP for this to activate. map("ca", vim.lsp.buf.code_action, "[C]ode [A]ction") -- Opens a popup that displays documentation about the word under your cursor -- See `:help K` for why this keymap map("K", vim.lsp.buf.hover, "Hover Documentation") -- WARN: This is not Goto Definition, this is Goto Declaration. -- For example, in C this would take you to the header map("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") -- The following two autocommands are used to highlight references of the -- word under your cursor when your cursor rests there for a little while. -- See `:help CursorHold` for information about when this is executed -- -- When you move your cursor, the highlights will be cleared (the second autocommand). local client = vim.lsp.get_client_by_id(event.data.client_id) if client and client.server_capabilities.documentHighlightProvider then vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { buffer = event.buf, callback = vim.lsp.buf.document_highlight, }) vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { buffer = event.buf, callback = vim.lsp.buf.clear_references, }) end end, }) -- LSP servers and clients are able to communicate to each other what features they support. -- By default, Neovim doesn't support everything that is in the LSP Specification. -- When you add nvim-cmp, luasnip, etc. Neovim now has *more* capabilities. -- So, we create new capabilities with nvim cmp, and then broadcast that to the servers. local capabilities = vim.lsp.protocol.make_client_capabilities() capabilities = vim.tbl_deep_extend("force", capabilities, require("cmp_nvim_lsp").default_capabilities()) -- Enable the following language servers -- Feel free to add/remove any LSPs that you want here. They will automatically be installed. -- -- Add any additional override configuration in the following tables. Available keys are: -- - cmd (table): Override the default command used to start the server -- - filetypes (table): Override the default list of associated filetypes for the server -- - capabilities (table): Override fields in capabilities. Can be used to disable certain LSP features. -- - settings (table): Override the default settings passed when initializing the server. -- For example, to see the options for `lua_ls`, you could go to: https://luals.github.io/wiki/settings/ local servers = { clangd = { filetypes = { "c", "cpp", }, }, -- gopls = {}, jdtls = { filetypes = { "java" }, settings = { java = { format = { settings = { url = "~/RedTop.xml", }, }, }, }, }, pyright = {}, fortls = {}, bashls = { dependencies = "shellcheck" }, rust_analyzer = { settings = { files = { excludeDirs = { "$HOME", "$HOME/.cargo/**", "$HOME/.rustup/**" }, }, }, }, ltex = { settings = { ltex = { enabled = { "latex", "tex", "bib", "markdown" }, language = "auto", diagnosticSeverity = "information", sentenceCacheSize = 2000, latex = { commands = { ["\\hypertarget"] = "dummy", }, }, dictionary = (function() -- For dictionary, search for files in the runtime to have -- and include them as externals the format for them is -- dict/{LANG}.txt -- -- Also add dict/default.txt to all of them local files = {} for _, file in ipairs(vim.api.nvim_get_runtime_file("dict/*", true)) do local lang = vim.fn.fnamemodify(file, ":t:r") local fullpath = vim.fs.normalize(file, ":p") files[lang] = { ":" .. fullpath } end if files.default then for lang, _ in pairs(files) do if lang ~= "default" then vim.list_extend(files[lang], files.default) end end files.default = nil end return files end)(), }, }, }, lua_ls = { -- cmd = {...}, -- filetypes { ...}, -- capabilities = {}, settings = { Lua = { runtime = { version = "LuaJIT" }, workspace = { checkThirdParty = false, -- Tells lua_ls where to find all the Lua files that you have loaded -- for your neovim configuration. library = { "${3rd}/luv/library", unpack(vim.api.nvim_get_runtime_file("", true)), }, -- If lua_ls is really slow on your computer, you can try this instead: -- library = { vim.env.VIMRUNTIME }, }, -- You can toggle below to ignore Lua_LS's noisy `missing-fields` warnings -- diagnostics = { disable = { 'missing-fields' } }, }, }, }, } -- Ensure the servers and tools above are installed -- To check the current status of installed tools and/or manually install -- other tools, you can run -- :Mason -- -- You can press `g?` for help in this menu require("mason").setup() -- You can add other tools here that you want Mason to install -- for you, so that they are available from within Neovim. local ensure_installed = vim.tbl_keys(servers or {}) vim.list_extend(ensure_installed, { "stylua", -- Used to format lua code "black", "clang-format", "ormolu", "beautysh", "latexindent", }) require("mason-tool-installer").setup({ ensure_installed = ensure_installed }) require("mason-lspconfig").setup({ handlers = { function(server_name) local server = servers[server_name] or {} require("lspconfig")[server_name].setup({ cmd = server.cmd, settings = server.settings, filetypes = server.filetypes, -- This handles overriding only values explicitly passed -- by the server configuration above. Useful when disabling -- certain features of an LSP (for example, turning off formatting for tsserver) capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {}), }) end, }, }) end, }, { -- Autoformat "stevearc/conform.nvim", setup = { formatters = { black = { command = "black", prepend_args = { "--line-length", "100" }, }, }, }, opts = { notify_on_error = false, format_on_save = { timeout_ms = 500, lsp_fallback = true, }, formatters_by_ft = { lua = { "stylua" }, -- Conform can also run multiple formatters sequentially python = { "black" }, rust = { "rustfmt" }, cpp = { "clang-format" }, c = { "clang-format" }, sh = { "beautysh" }, tex = { "latexindent" }, }, }, }, { -- Autocompletion "hrsh7th/nvim-cmp", event = "InsertEnter", dependencies = { -- Snippet Engine & its associated nvim-cmp source { "L3MON4D3/LuaSnip", build = (function() -- Build Step is needed for regex support in snippets -- This step is not supported in many windows environments -- Remove the below condition to re-enable on windows if vim.fn.has("win32") == 1 or vim.fn.executable("make") == 0 then return end return "make install_jsregexp" end)(), config = function() require("luasnip.loaders.from_snipmate").lazy_load({ paths = "./snippets" }) local ls = require("luasnip") -- some shorthands... local snip = ls.snippet local node = ls.snippet_node local text = ls.text_node local insert = ls.insert_node local func = ls.function_node local choice = ls.choice_node local dynamicn = ls.dynamic_node ls.add_snippets(nil, { python = { snip({ trig = "imp", namr = "Imports", dscr = "Comments for imports", }, { text({ "# Core modules", "" }), insert(1), text({ "", "# Non-core modules", "" }), insert(2), text({ "", "# SEI modules", "" }), insert(3), }), }, tex = { snip({ trig = "input", namr = "Input Cell", dscr = "Cell for SEIInputTable", }, { text({ "\\hypertarget{" }), insert(1), text({ "}{" }), insert(2), text({ "} & \\SEICell{", "\t" }), insert(3), text({ "", "}\\\\", "" }), }), }, }) end, }, "saadparwaiz1/cmp_luasnip", "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-path", }, config = function() -- See `:help cmp` local cmp = require("cmp") local luasnip = require("luasnip") luasnip.config.setup({}) cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, completion = { completeopt = "menu,menuone,noinsert" }, -- For an understanding of why these mappings were -- chosen, you will need to read `:help ins-completion` -- -- No, but seriously. Please read `:help ins-completion`, it is really good! mapping = cmp.mapping.preset.insert({ -- Select the [n]ext item [""] = cmp.mapping.select_next_item(), -- Select the [p]revious item [""] = cmp.mapping.select_prev_item(), -- Accept ([y]es) the completion. -- This will auto-import if your LSP supports it. -- This will expand snippets if the LSP sent a snippet. [""] = cmp.mapping.confirm({ select = true }), ["j"] = cmp.mapping(function() if luasnip.expand_or_locally_jumpable() then luasnip.expand_or_jump() end end, { "i", "s" }), ["k"] = cmp.mapping(function() if luasnip.locally_jumpable(-1) then luasnip.jump(-1) end end, { "i", "s" }), }), sources = { { name = "nvim_lsp" }, { name = "luasnip" }, { name = "path" }, }, }) end, snippet = { expand = function(args) local luasnip = require("luasnip") if not luasnip then return end luasnip.lsp_expand(args.body) end, }, }, { -- You can easily change to a different colorscheme. -- Change the name of the colorscheme plugin below, and then -- change the command in the config to whatever the name of that colorscheme is -- -- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme` "morhetz/gruvbox", lazy = false, -- make sure we load this during startup if it is your main colorscheme priority = 1000, -- make sure to load this before all the other start plugins config = function() -- Load the colorscheme here vim.cmd.colorscheme("gruvbox") end, }, -- Highlight todo, notes, etc in comments { "folke/todo-comments.nvim", dependencies = { "nvim-lua/plenary.nvim" }, opts = { signs = false } }, { -- Collection of various small independent plugins/modules -- Simple and easy statusline. -- You could remove this setup call if you don't like it, -- and try some other statusline plugin "echasnovski/mini.nvim", config = function() require("mini.statusline").setup({ content = { active = function() local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 }) local git = MiniStatusline.section_git({ trunc_width = 75 }) local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 75 }) local filename = MiniStatusline.section_filename({ trunc_width = 140 }) local fileinfo = MiniStatusline.section_fileinfo({ trunc_width = 120 }) local location = MiniStatusline.section_location({ trunc_width = 75 }) local search = MiniStatusline.section_searchcount({ trunc_width = 75 }) local words = getWords() return MiniStatusline.combine_groups({ { hl = mode_hl, strings = { mode } }, { hl = "MiniStatuslineDevinfo", strings = { git, diagnostics } }, "%<", -- Mark general truncate point { hl = "MiniStatuslineFilename", strings = { filename } }, "%=", -- End left alignment { hl = "MiniStatuslineFileinfo", strings = { fileinfo } }, { hl = "MiniStatuslineFileinfo", strings = { words } }, { hl = mode_hl, strings = { search, location } }, }) end, }, }) end, }, { -- Highlight, edit, and navigate code "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", config = function() -- [[ Configure Treesitter ]] See `:help nvim-treesitter` ---@diagnostic disable-next-line: missing-fields require("nvim-treesitter.configs").setup({ ensure_installed = { "bash", "c", "html", "lua", "markdown", "vim", "vimdoc" }, -- Autoinstall languages that are not installed auto_install = true, highlight = { enable = false }, indent = { enable = true }, }) -- There are additional nvim-treesitter modules that you can use to interact -- with nvim-treesitter. You should go explore a few and see what interests you: -- -- - Incremental selection: Included, see :help nvim-treesitter-incremental-selection-mod -- - Show your current context: https://github.com/nvim-treesitter/nvim-treesitter-context -- - Treesitter + textobjects: https://github.com/nvim-treesitter/nvim-treesitter-textobjects end, }, }) --Disable semantic highlights for _, group in ipairs(vim.fn.getcompletion("@lsp", "highlight")) do vim.api.nvim_set_hl(0, group, {}) end --Testing scorch highlighting vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { pattern = "*.scorch", callback = function() vim.bo.filetype = "scorch" end, }) -- Commands to disable formatting require("conform").setup({ format_on_save = function(bufnr) -- Disable with a global or buffer-local variable if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then return end return { timeout_ms = 500, lsp_fallback = true } end, }) vim.api.nvim_create_user_command("FormatDisable", function(args) if args.bang then -- FormatDisable! will disable formatting just for this buffer vim.b.disable_autoformat = true else vim.g.disable_autoformat = true end end, { desc = "Disable autoformat-on-save", bang = true, }) vim.api.nvim_create_user_command("FormatEnable", function() vim.b.disable_autoformat = false vim.g.disable_autoformat = false end, { desc = "Re-enable autoformat-on-save", })