vim.o.shell = "/bin/sh" vim.g.loaded_node_provider = false vim.g.loaded_perl_provider = false vim.g.loaded_python_provider = false vim.g.loaded_ruby_provider = false vim.o.number = true vim.o.hidden = true vim.o.expandtab = true vim.o.tabstop = 4 vim.o.softtabstop = 4 vim.o.shiftwidth = 4 vim.o.smartindent = true vim.o.foldenable = false vim.o.joinspaces = false vim.o.nrformats = vim.o.nrformats .. ",blank" -- Some ftplugin files will add 'o' back in again, so remove it again after the -- filetype has been determined. vim.opt.formatoptions = "crqnlj" vim.cmd([[ autocmd Filetype * setlocal formatoptions-=o ]]) vim.o.wrap = true vim.o.linebreak = true vim.keymap.set("", "j", "gj", { silent = true }) vim.keymap.set("", "k", "gk", { silent = true }) vim.o.list = false vim.o.wrapmargin = 0 vim.opt.listchars = { tab = ">-", extends = ">", precedes = "<", nbsp = "+", trail = "-", } vim.o.ignorecase = true vim.o.smartcase = true vim.o.cursorline = true vim.o.splitbelow = true vim.o.splitright = true vim.o.modelines = 0 vim.o.lazyredraw = true vim.o.updatetime = 250 vim.opt.shortmess:append("I") vim.opt.wildignore:append("*.swp,*~") vim.opt.completeopt = "menu,menuone,noselect" vim.o.secure = true vim.api.nvim_create_autocmd("FileType", { pattern = { "markdown", "text" }, callback = function() vim.opt_local.spell = true end, }) vim.opt.spellcapcheck = "" vim.diagnostic.config({ jump = { on_jump = function(diagnostic, bufnr) if not diagnostic then return end vim.diagnostic.show(diagnostic.namespace, bufnr, { diagnostic }, { float = true }) end, }, }) vim.keymap.set("", "w", "", { remap = true }) vim.keymap.set("", ";", ":nohlsearch") vim.keymap.set("", ",", ":nohlsearch") ------------------------------------------------------------------------------- -- Theme ------------------------------------------------------------------------------- vim.pack.add({ "https://github.com/rktjmp/lush.nvim" }) theme = "jdkaplan-temp" vim.cmd.colorscheme(theme) -- CTRL-L usually clears and redraws the screen. Might as well use it to reset -- the colorscheme too! vim.keymap.set("n", "", function() vim.cmd.colorscheme(theme) vim.cmd.redraw() end) ------------------------------------------------------------------------------- -- tpope extended universe ------------------------------------------------------------------------------- vim.pack.add({ "https://github.com/tpope/vim-abolish", "https://github.com/tpope/vim-commentary", "https://github.com/tpope/vim-repeat", "https://github.com/tpope/vim-fugitive", }) vim.pack.add({ "https://github.com/kylechui/nvim-surround" }) require("nvim-surround").setup() ------------------------------------------------------------------------------- -- Editing ------------------------------------------------------------------------------- vim.pack.add({ "https://github.com/windwp/nvim-autopairs" }) require("nvim-autopairs").setup({ opts = { map_cr = true, enable_moveright = true, enable_check_bracket_line = false, check_ts = true, }, }) ------------------------------------------------------------------------------- -- IDE ------------------------------------------------------------------------------- vim.pack.add({ "https://github.com/preservim/nerdtree" }) vim.keymap.set("n", "tt", ":NERDTreeToggle") vim.keymap.set("n", "tf", ":NERDTreeFind") vim.pack.add({ "https://github.com/lewis6991/gitsigns.nvim" }) require("gitsigns").setup({ signcolumn = false, current_line_blame = false, current_line_blame_formatter = " ", current_line_blame_opts = { virt_text = true, virt_text_pos = "eol", delay = 0, ignore_whitespace = false, }, }); (function() local gitsigns = require("gitsigns") local toggle = function(value) -- BUG: (?) If the blame delay is not zero, the setting can -- enter a race with cursor movement and leave a ghost blame in -- the buffer. show = not show gitsigns.toggle_current_line_blame(show) gitsigns.toggle_deleted(show) gitsigns.toggle_signs(show) end vim.keymap.set("n", "gg", toggle) vim.keymap.set("n", "[h", gitsigns.prev_hunk) vim.keymap.set("n", "]h", gitsigns.next_hunk) end)() ------------------------------------------------------------------------------- -- Treesitter ------------------------------------------------------------------------------- vim.pack.add({ { src = "https://github.com/nvim-treesitter/nvim-treesitter", version = "4916d6592ede8c07973490d9322f187e07dfefac", }, "https://github.com/nvim-treesitter/nvim-treesitter-textobjects", }) vim.api.nvim_create_autocmd("PackChanged", { callback = function(ev) local name, kind = ev.data.spec.name, ev.data.kind if name == "nvim-treesitter" and (kind == "install" or kind == "update") then require("nvim-treesitter").update() end end, }) require("nvim-treesitter").install({ "bash", "css", "dot", "diff", "git_config", "git_rebase", "gitattributes", "gitcommit", "gitignore", "go", "gomod", "gosum", "gowork", "html", "javascript", "jq", "json", "lua", "markdown", "markdown_inline", "proto", "python", "ruby", "rust", "scss", "sql", "toml", "tsx", "typescript", "yaml", }) require("nvim-treesitter-textobjects").setup({ enable = true, select = { enable = true, lookahead = true, include_surrounding_whitespace = false, -- https://github.com/nvim-treesitter/nvim-treesitter-textobjects#overriding-or-extending-textobjects keymaps = { ["af"] = "@function.outer", ["if"] = "@function.inner", ["ac"] = "@comment.outer", ["ic"] = "@comment.outer", }, }, move = { enable = true, set_jumps = true, goto_next_start = { ["]m"] = "@function.outer", ["]{"] = "@block.outer", }, goto_next_end = { ["]M"] = "@function.outer", ["]}"] = "@block.outer", }, goto_previous_start = { ["[m"] = "@function.outer", ["[{"] = "@block.outer", }, goto_previous_end = { ["[M"] = "@function.outer", ["[}"] = "@block.outer", }, }, }) vim.pack.add({ "https://github.com/lukas-reineke/indent-blankline.nvim" }) require("ibl").setup({ indent = { char = "┊", }, scope = { enabled = false }, }) vim.pack.add({ "https://github.com/stevearc/aerial.nvim" }) require("aerial").setup() vim.keymap.set("n", "st", "AerialNavToggle") ------------------------------------------------------------------------------- -- Telescope ------------------------------------------------------------------------------- vim.pack.add({ { src = "https://github.com/nvim-telescope/telescope.nvim", version = vim.version.range("^0.2"), }, "https://github.com/nvim-lua/plenary.nvim", "https://github.com/nvim-telescope/telescope-fzf-native.nvim", "https://github.com/nvim-telescope/telescope-ui-select.nvim", }) -- TODO: Is it possible to make this run synchronously here, but only on install/update? vim .system({ "make" }, { cwd = vim.pack.get({ "telescope-fzf-native.nvim" })[1].path, }) :wait(); (function() local telescope = require("telescope") telescope.load_extension("fzf") telescope.load_extension("aerial") telescope.load_extension("ui-select") local builtin = require("telescope.builtin") local function find_files(opts) opts = opts or {} opts["hidden"] = true return builtin.find_files(opts) end vim.keymap.set("n", "f", find_files) vim.keymap.set("n", "/", builtin.live_grep) vim.keymap.set("n", "b", builtin.buffers) vim.keymap.set("n", "*", builtin.grep_string) vim.keymap.set("n", "o", telescope.extensions.aerial.aerial) vim.keymap.set("n", "", builtin.builtin) vim.keymap.set("i", "i", builtin.symbols) local actions = require("telescope.actions") local action_state = require("telescope.actions.state") local transform_mod = require("telescope.actions.mt").transform_mod -- https://github.com/nvim-telescope/telescope.nvim/issues/1048#issuecomment-1225975038 local function multiopen(prompt_bufnr, method) local method = method or "default" local edit_file_cmd_map = { vertical = "vsplit", horizontal = "split", tab = "tabedit", default = "edit", } local edit_buf_cmd_map = { vertical = "vert sbuffer", horizontal = "sbuffer", tab = "tab sbuffer", default = "buffer", } local picker = action_state.get_current_picker(prompt_bufnr) local multi_selection = picker:get_multi_selection() if #multi_selection > 1 then require("telescope.pickers").on_close_prompt(prompt_bufnr) pcall(vim.api.nvim_set_current_win, picker.original_win_id) for i, entry in ipairs(multi_selection) do local filename, row, col if entry.path or entry.filename then filename = entry.path or entry.filename row = entry.row or entry.lnum col = vim.F.if_nil(entry.col, 1) elseif not entry.bufnr then local value = entry.value if not value then goto continue end if type(value) == "table" then value = entry.display end local sections = vim.split(value, ":") filename = sections[1] row = tonumber(sections[2]) col = tonumber(sections[3]) end local entry_bufnr = entry.bufnr if entry_bufnr then if not vim.api.nvim_buf_get_option(entry_bufnr, "buflisted") then vim.api.nvim_buf_set_option(entry_bufnr, "buflisted", true) end local command = i == 1 and "buffer" or edit_buf_cmd_map[method] pcall(vim.cmd, string.format("%s %s", command, vim.api.nvim_buf_get_name(entry_bufnr))) else local command = i == 1 and "edit" or edit_file_cmd_map[method] if vim.api.nvim_buf_get_name(0) ~= filename or command ~= "edit" then filename = require("plenary.path"):new(vim.fn.fnameescape(filename)):normalize(vim.loop.cwd()) pcall(vim.cmd, string.format("%s %s", command, filename)) end end if row and col then pcall(vim.api.nvim_win_set_cursor, 0, { row, col - 1 }) end ::continue:: end else actions["select_" .. method](prompt_bufnr) end end telescope.setup({ defaults = { mappings = { i = { [""] = multiopen, }, n = { [""] = multiopen, }, }, vimgrep_arguments = { "rg", "--color=never", "--no-heading", "--with-filename", "--line-number", "--column", "--smart-case", -- Include hidden files, but continue ignoring the .git directory itself. "--hidden", "--iglob", "!.git", }, }, pickers = {}, extensions = { aerial = {}, }, }) end)() ------------------------------------------------------------------------------- -- Completion and snippets ------------------------------------------------------------------------------- vim.pack.add({ { src = "https://github.com/L3MON4D3/LuaSnip", version = vim.version.range("^2"), }, "https://github.com/hrsh7th/cmp-nvim-lsp", "https://github.com/hrsh7th/nvim-cmp", "https://github.com/saadparwaiz1/cmp_luasnip", }) -- TODO: Is it possible to make this run synchronously here, but only on install/update? vim .system({ "make", "install_jsregexp" }, { cwd = vim.pack.get({ "LuaSnip" })[1].path, }) :wait(); (function() local luasnip = require("luasnip") luasnip.filetype_extend("typescript", { "javascript" }) luasnip.filetype_extend("typescriptreact", { "javascript", "react" }) -- Put snippets in ./snippets/.snippets require("luasnip.loaders.from_snipmate").lazy_load() require("luasnip.loaders.from_lua").lazy_load() local cmp = require("cmp") cmp.setup({ completion = { autocomplete = false, }, snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.complete(), [""] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true, }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), }), sources = { { name = "nvim_lsp" }, { name = "luasnip" }, }, }) end)() ------------------------------------------------------------------------------- -- Language-specific plugins ------------------------------------------------------------------------------- -- Rust vim.pack.add({ { src = "https://github.com/mrcjkb/rustaceanvim", version = vim.version.range("^9"), } }) -- Uiua vim.pack.add({ "https://github.com/Apeiros-46B/uiua.vim" }) ------------------------------------------------------------------------------- -- Language Server Protocol (LSP) ------------------------------------------------------------------------------- vim.pack.add({ "https://github.com/neovim/nvim-lspconfig" }) vim.lsp.inlay_hint.enable(true) vim.api.nvim_create_autocmd("LspAttach", { callback = function(args) local client = assert(vim.lsp.get_client_by_id(args.data.client_id)) if client:supports_method("textDocument/completion") then vim.lsp.completion.enable(true, client.id, args.buf, { autotrigger = false }) end -- Usually not needed if server supports "textDocument/willSaveWaitUntil". already_waits = client:supports_method("textDocument/willSaveWaitUntil") can_fmt = client:supports_method("textDocument/formatting") should_fmt = ({ -- tsserver/ts_ls seems to have no other way of disabling formatting. ["ts_ls"] = false, -- zls doesn't seem to trigger the normal way. ["zls"] = true, })[client.name] if should_fmt == nil then should_fmt = not already_waits and can_fmt end if should_fmt then vim.api.nvim_create_autocmd("BufWritePre", { buffer = args.buf, callback = function() vim.lsp.buf.format({ bufnr = args.buf, id = client.id, timeout_ms = 1000 }) end, }) end end, }) vim.lsp.enable("eslint") vim.lsp.config("eslint", { on_attach = function(client, bufnr) vim.api.nvim_create_autocmd("BufWritePre", { callback = function() client:request_sync("workspace/executeCommand", { command = "eslint.applyAllFixes", arguments = { { uri = vim.uri_from_bufnr(bufnr), version = vim.lsp.util.buf_versions[bufnr], }, }, }) end, }) end, }) vim.lsp.enable("stylua") -- rust-analyzer is already enabled and configured by rustaceanvim vim.lsp.enable("uiua") vim.lsp.enable("zls") vim.lsp.config("zls", { settings = { enable_build_on_save = true, inlay_hints_hide_redundant_param_names = true, inlay_hints_hide_redundant_param_names_last_token = true, warn_style = true, }, }) ------------------------------------------------------------------------------- -- which-key ------------------------------------------------------------------------------- vim.pack.add({ "https://github.com/folke/which-key.nvim" }) require("which-key").setup({ preset = "helix", keys = { Up = " ", Down = " ", Left = " ", Right = " ", C = "^", M = "M-", D = "W-", S = "S-", CR = "CR", Esc = "Esc", ScrollWheelDown = "⤓", ScrollWheelUp = "⤒", NL = "⏎", BS = "⇐", Space = "Space", Tab = "Tab", F1 = "F1", F2 = "F2", F3 = "F3", F4 = "F4", F5 = "F5", F6 = "F6", F7 = "F7", F8 = "F8", F9 = "F9", F10 = "F10", F11 = "F11", F12 = "F12", }, }) vim.keymap.set("", "?", function() require("which-key").show() end, { desc = "which-key" })