if vim.env.DOTFILES_DIR == nil then vim.notify("DOTFILES_DIR is not set!", vim.log.levels.WARN) end vim.g.dotfiles = { augroup = vim.api.nvim_create_augroup("dotfiles", {}), -- Single source of truth for per-filetype formatting width -- (textwidth → gw, mdformat --wrap, render-markdown block widths). textwidth = { sh = 80, lua = 100, markdown = 120, gitcommit = 72, python = 88 }, } -- Sets the window bar content and style (custom hl-groups WinBarCwd and WinBarFilePath) -- Note that this will usually be cleared when loading a colorscheme (which do the equivalent of :hi clear) vim.api.nvim_set_hl(0, "WinBarCwd", { bold = true }) vim.api.nvim_set_hl(0, "WinBarFilePath", { link = "Normal" }) vim.opt.winbar = "%#WinBarCwd#%{fnamemodify(getcwd(),':~')}%* | %#WinBarFilePath#%f%*" ------------------------------------------------------------------------------------------------------------------------ -- Local functions ------------------------------------------------------------------------------------------------------------------------ -- Show the diff between the current buffer and the file it was loaded from local function show_buf_diff_orig() local bname = vim.api.nvim_buf_get_name(0) if not vim.uv.fs_stat(bname) then vim.notify("Cannot diff with original because " .. bname .. " doesn't exist", vim.log.levels.WARN) return end local cwin = vim.api.nvim_get_current_win() vim.cmd.diffthis() local temp = vim.fn.tempname() local ok, err = vim.uv.fs_copyfile(bname, temp) if not ok then vim.notify("Could not copy file: " .. err, vim.log.levels.ERROR) return end vim.cmd.split({ temp, mods = { vertical = vim.api.nvim_win_get_width(0) >= vim.o.textwidth * 2, keepalt = true } }) vim.cmd.diffthis() vim.opt_local.bufhidden = "wipe" vim.opt_local.buftype = "nofile" vim.opt_local.swapfile = false vim.opt_local.readonly = true vim.api.nvim_set_current_win(cwin) end local function reload_buffer() if vim.o.filetype == "netrw" then vim.cmd.edit(".") else -- `:edit` resets fold state; preserve it via `:mkview`/`:loadview`. vim.cmd.mkview() vim.cmd.edit() vim.cmd.loadview() end end local function toggle_wrap() vim.o.wrap = not vim.o.wrap end ------------------------------------------------------------------------------------------------------------------------ -- Miscellaneous ------------------------------------------------------------------------------------------------------------------------ vim.g.mapleader = " " -- Set before any `vim.keymap.set()` call -- Highlight on yank vim.api.nvim_create_autocmd("TextYankPost", { desc = "Highlight on yank", group = vim.g.dotfiles.augroup, callback = function() vim.hl.on_yank() end, }) -- Reload file when changed outside of nvim vim.opt.autoread = false -- Must be false for FileChangedShell to trigger when the buffer was not changed -- The manual says that FileChangedShell is triggered on FocusGained but it's not true. This function actually triggers -- the next FileChangedShell when the buffer has unsaved changes and the file was modified outside of nvim. vim.api.nvim_create_autocmd({ "FocusGained" }, { desc = "Trigger buffer reload when file is edited outside of nvim", group = vim.g.dotfiles.augroup, callback = function() vim.cmd.checktime() end, }) vim.api.nvim_create_autocmd({ "FileChangedShell" }, { desc = "Prompt user to reload buffer when modified outside of nvim", group = vim.g.dotfiles.augroup, pattern = "*", callback = function() if vim.v.fcs_reason == "conflict" or vim.v.fcs_reason == "changed" then vim.v.fcs_choice = "ask" end end, }) ------------------------------------------------------------------------------------------------------------------------ -- Commands (there's more in the different plugins) ------------------------------------------------------------------------------------------------------------------------ vim.api.nvim_create_user_command("DiffOrig", show_buf_diff_orig, { desc = "Show diff between current buffer and file" }) ------------------------------------------------------------------------------------------------------------------------ -- Keymaps (there's more in the different plugins) ------------------------------------------------------------------------------------------------------------------------ -- See `:help key-notation` and `:help ` -- `:map \ ` to see (most) user set keymaps (those starting with the `` key) -- Miscellaneous vim.keymap.set("n", "", "zA", { desc = "Toggle fold (recursively) under cursor" }) vim.keymap.set("n", "ZR", vim.cmd.SessionRestart, { desc = "Save and load default session and restart" }) vim.keymap.set("n", "ZZ", vim.cmd.SessionExitSave, { desc = "Save to default session and exit" }) vim.keymap.set("n", "ZQ", vim.cmd.SessionExitNoSave, { desc = "Quit without saving session" }) vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) vim.keymap.set("n", "mm", "messages", { desc = "Show all messages" }) vim.keymap.set("n", "mc", "messages clear", { desc = "Clear all messages" }) vim.keymap.set("n", "lh", vim.cmd.LspHintToggle, { desc = "Toggle inlay hints (LSP)" }) vim.keymap.set("n", "y+", "let @+ = expand('%:p')", { desc = "Copy file path to clipboard" }) -- These two mappings work well together to start command mode and insert from history in two keystrokes. vim.keymap.set("n", "", ":", { desc = "Enter command mode" }) vim.keymap.set("c", "", "", { desc = "Insert previous history entry" }) -- Navigate files vim.keymap.set("n", "", vim.cmd.GotoExplorer, { desc = "Open/close/focus netrw window" }) -- Buffers vim.keymap.set("n", "s", "update", { desc = "Save buffer" }) vim.keymap.set("n", "be", reload_buffer, { desc = "Reload buffer" }) vim.keymap.set("n", "bw", toggle_wrap, { desc = "Toggle text wrap" }) vim.keymap.set("n", "bd", "bdelete", { desc = "Delete buffer" }) vim.keymap.set("n", "bn", "enew", { desc = "Edit new buffer in current window" }) vim.keymap.set("n", "bs", "new", { desc = "Edit new buffer in split" }) vim.keymap.set("n", "bv", "vnew", { desc = "Edit new buffer in vertical split" }) -- Windows vim.keymap.set("n", "", "h", { desc = "Move left a window" }) vim.keymap.set("n", "", "j", { desc = "Move down a window" }) vim.keymap.set("n", "", "k", { desc = "Move up a window" }) vim.keymap.set("n", "", "l", { desc = "Move right a window" }) vim.keymap.set("t", "", "h", { desc = "Move left a window" }) vim.keymap.set("t", "", "j", { desc = "Move down a window" }) vim.keymap.set("t", "", "k", { desc = "Move up a window" }) vim.keymap.set("t", "", "l", { desc = "Move right a window" }) vim.keymap.set("n", "wc", "close", { desc = "Close window" }) vim.keymap.set("n", "ws", "split", { desc = "Split window" }) vim.keymap.set("n", "wv", "vsplit", { desc = "Split window vertically" }) vim.keymap.set("n", "wh", "H", { desc = "Move window far left" }) vim.keymap.set("n", "wj", "J", { desc = "Move window far down" }) vim.keymap.set("n", "wk", "K", { desc = "Move window far up" }) vim.keymap.set("n", "wl", "L", { desc = "Move window far right" }) vim.keymap.set("n", "wr", "r", { desc = "Rotate windows down/right" }) vim.keymap.set("n", "wR", "R", { desc = "Rotate windows up/left" }) vim.keymap.set("n", "wx", "x", { desc = "Exchange window with next one" }) vim.keymap.set("n", "w=", "=", { desc = "Equalize windows" }) vim.keymap.set("n", "w+", "+", { desc = "Increase window height" }) vim.keymap.set("n", "w-", "-", { desc = "Decrease window height" }) vim.keymap.set("n", "w>", ">", { desc = "Increase window width" }) vim.keymap.set("n", "w<", "<", { desc = "Decrease window width" }) vim.keymap.set("n", "w_", "_", { desc = "Set window height" }) vim.keymap.set("n", "w|", "|", { desc = "Set window width" }) -- Tabpages vim.keymap.set("n", "", "tabnew", { desc = "Create new tabpage" }) vim.keymap.set("n", "t", "tabclose", { desc = "Delete current tabpage" }) vim.keymap.set({ "n", "i", "t" }, "", "tabnext #", { desc = "Move to last accessed tab page" }) vim.keymap.set({ "n", "i", "t" }, "", "tabnext", { desc = "Move to next tab page" }) vim.keymap.set({ "n", "i", "t" }, "", "tabprevious", { desc = "Move to previous tab page" }) vim.keymap.set("n", ">", "tabmove +1", { desc = "Move tab to next position" }) vim.keymap.set("n", "<", "tabmove -1", { desc = "Move tab to next position" }) -- Scrolling vim.keymap.set("n", "", vim.cmd.ScrollSmoothUp, { desc = "Scroll up smoothly" }) vim.keymap.set("n", "", vim.cmd.ScrollSmoothDown, { desc = "Scroll down smoothly" }) -- Navigate in command/insert mode vim.keymap.set({ "c", "i" }, "", "") vim.keymap.set({ "c", "i" }, "", "") vim.keymap.set("c", "", "") vim.keymap.set("c", "", "") -- Kill text from cursor to end of line, akin to Readline's kill-line vim.keymap.set("c", "", function() local pos = vim.fn.getcmdpos() -- 1-based byte index of the cursor vim.fn.setcmdline(vim.fn.getcmdline():sub(1, pos - 1), pos) end, { desc = "Kill from cursor to end of line" }) -- Non incremental history search, works when the completion menu is active vim.keymap.set("c", "", function() return vim.fn.pumvisible() == 1 and "" or "" end, { expr = true }) vim.keymap.set("c", "", function() return vim.fn.pumvisible() == 1 and "" or "" end, { expr = true }) -- Simulate `i_CTRL-R` in terminal mode vim.keymap.set("t", "", function() local input = vim.fn.getchar() assert(type(input) == "number") local register = vim.fn.nr2char(input) local value = vim.fn.getreg(register) vim.api.nvim_put({ value }, "c", true, true) end) ------------------------------------------------------------------------------------------------------------------------ -- Options ------------------------------------------------------------------------------------------------------------------------ vim.opt.shell = "/usr/bin/bash" vim.opt.foldenable = true -- Folds are closed by default vim.opt.pumheight = 16 -- Popup menu height to 16 lines vim.opt.confirm = true -- Confirm before losing buffer unsaved changes vim.opt.splitbelow = false vim.opt.splitright = false vim.opt.clipboard = "unnamedplus" -- Sync clipboard vim.opt.cursorline = true -- Highlight the line where the cursor is on vim.opt.scrolloff = 2 -- Keep this many visible screen lines above/below the cursor vim.opt.ignorecase = true -- Search ignores case by default vim.opt.smartcase = true -- Search is case-sensitive if searching for uppercase characters vim.opt.conceallevel = 2 -- Hide text with the "conceal" syntax attribute vim.opt.showtabline = 2 -- Always show tabline vim.opt.winborder = "rounded" -- Rounded outline for floating windows vim.opt.updatetime = 1000 -- Swap file save frequency; also how often GitGutter signs update in ms vim.opt.list = true -- Display and other non-printables vim.opt.listchars = { -- Characters used by 'list' tab = "> ", -- Tab trail = "-", -- Trailing space nbsp = "+", -- Non-breakable space extends = "→", -- Last column when 'wrap' is off precedes = "←", -- First column when there is text before it } -- See `'cpoptions'` -- Use a `\` like `CTRL_V` in mappings, abbreviations, user commands and the "to" part of menu commands -- Useful for example for matching mappings that start with space: `:map \ ` vim.opt.cpoptions:remove("B") -- Backup vim.opt.swapfile = true -- Store a swap file, see `:help swap-file` vim.opt.undofile = true -- Save buffer undo history vim.opt.backup = true -- Backup file before overwriting vim.opt.backupdir = { vim.fn.stdpath("state") .. "/backup//" } vim.opt.writebackup = true -- Keep backup after writing file -- Gutter vim.opt.number = true -- Show line number vim.opt.relativenumber = true -- Show relative line number vim.opt.numberwidth = 4 -- Minimal number of columns for line number (includes the space before the text) vim.opt.signcolumn = "auto" -- Show sign column when there is a sign to display vim.opt.foldcolumn = "0" -- Disable foldcolumn -- Wrapping vim.opt.wrap = false -- Don't wrap text by default vim.opt.showbreak = "+++ " -- String to show wrapped lines vim.opt.linebreak = true -- Wrap at characters in 'breakat' vim.opt.breakindent = true -- Indent wrapped lines -- Tab and backspace (See `help 30.5`) vim.opt.tabstop = 4 -- and visually expand at columns multiple of 'tabstop' vim.opt.shiftwidth = 0 -- Number of space in first indendation. If 0 use 'tabstop' value. vim.opt.softtabstop = -1 -- and stop at columns multiple of 'softtabstop'. If <0 use 'shiftwidth' value. vim.opt.expandtab = false -- Don't turn tabs into spaces