diff --git a/GEP b/GEP index 23fd4719..9197ddf7 160000 --- a/GEP +++ b/GEP @@ -1 +1 @@ -Subproject commit 23fd4719d88b0bceb5c3d31773ce110b5e1990c2 +Subproject commit 9197ddf747bfdebfa6af4af65a151b5b9e936bdb diff --git a/bashrc.d/030-aliases.sh b/bashrc.d/030-aliases.sh index 188a9c94..5d409953 100644 --- a/bashrc.d/030-aliases.sh +++ b/bashrc.d/030-aliases.sh @@ -23,6 +23,7 @@ alias acl='sudo apt-get autoclean' alias arem='sudo apt-get autoremove' alias readelf='readelf --wide' +alias xxd='xxd -R always' # Thin shim for man that provides primitive coloring, and help for builtins man() { diff --git a/bashrc.d/070-environment.sh b/bashrc.d/070-environment.sh index 8ecd7891..ed44727c 100644 --- a/bashrc.d/070-environment.sh +++ b/bashrc.d/070-environment.sh @@ -27,28 +27,22 @@ export FZF_CTRL_R_OPTS=" \ )\" \ " -# Use vim as my MANPAGER. Has folding, ability to follow links. -MANPAGER="vim -M +MANPAGER -" -MANWIDTH=100 +# Use nvim as my MANPAGER. Has folding, ability to follow links. +export MANPAGER='nvim +Man!' +export MANWIDTH=100 # Add local header files to gcc include path -C_INCLUDE_PATH="$HOME/.local/include${C_INCLUDE_PATH:+:${C_INCLUDE_PATH}}" -CPLUS_INCLUDE_PATH="$HOME/.local/include${CPLUS_INCLUDE_PATH:+:${CPLUS_INCLUDE_PATH}}" +export C_INCLUDE_PATH="$HOME/.local/include${C_INCLUDE_PATH:+:${C_INCLUDE_PATH}}" +export CPLUS_INCLUDE_PATH="$HOME/.local/include${CPLUS_INCLUDE_PATH:+:${CPLUS_INCLUDE_PATH}}" # Add local libraries to library path. -LIBRARY_PATH="$HOME/.local/lib${LIBRARY_PATH:+:${LIBRARY_PATH}}" +export LIBRARY_PATH="$HOME/.local/lib${LIBRARY_PATH:+:${LIBRARY_PATH}}" # Setting LIBRARY_PATH is for linking, setting LD_LIBRARY_PATH is for running -LD_LIBRARY_PATH="$LIBRARY_PATH" +export LD_LIBRARY_PATH="$LIBRARY_PATH" -export C_INCLUDE_PATH -export CPLUS_INCLUDE_PATH -export LIBRARY_PATH -export LD_LIBRARY_PATH -export MANPAGER -export MANWIDTH -export EDITOR=vim -export BAT_THEME=base16 +export EDITOR=nvim +export BAT_THEME=gruvbox-light # Fix less not rendering control characters with git-log on the Opp lab machines. export LESS=FRX diff --git a/setup b/setup index 2adbe581..450d113a 100755 --- a/setup +++ b/setup @@ -42,9 +42,20 @@ prompt_default_yes() { github_latest_release_tag() { local repo="$1" + local response + local tag - curl --silent --fail "https://api.github.com/repos/$repo/releases/latest" | - grep --only-matching --perl-regexp '"tag_name": "\K(.*)(?=")' + if ! response=$(curl --silent --show-error --fail "https://api.github.com/repos/$repo/releases/latest" 2>&1); then + error "Failed to fetch latest release for $repo: $response" + return 1 + fi + + if ! tag=$(printf '%s' "$response" | grep --only-matching --perl-regexp '"tag_name": "\K(.*)(?=")'); then + error "Could not parse tag_name from GitHub response for $repo" + return 1 + fi + + printf '%s\n' "$tag" } github_download_release() { @@ -52,11 +63,17 @@ github_download_release() { local version="$2" local artifact="$3" local output="${4:-$artifact}" + local url="https://github.com/$repo/releases/download/$version/$artifact" - curl \ + if ! curl \ + --fail \ + --show-error \ --location \ --output "$output" \ - --remote-name "https://github.com/$repo/releases/download/$version/$artifact" + --remote-name "$url"; then + error "Failed to download release artifact $artifact from $repo ($url)" + return 1 + fi } debug() { diff --git a/setup.d/020-fancy-tools.sh b/setup.d/020-fancy-tools.sh index bc89d7a4..b50b74f9 100755 --- a/setup.d/020-fancy-tools.sh +++ b/setup.d/020-fancy-tools.sh @@ -49,4 +49,41 @@ if prompt_default_yes "Install/update fancy shell tools?"; then download_and_install_delta "$latest_version" fi fi + + download_and_install_nvim() { + local -r artifact="nvim-linux-x86_64.tar.gz" + pushd /tmp || exit 1 + + debug "downloading $artifact ..." + github_download_release "neovim/neovim" "stable" "$artifact" + + debug "installing ..." + tar -C ~/.local/ --strip-components=1 -xzvf "$artifact" + + popd || exit 1 + } + + if prompt_default_yes "Install/update nvim from GitHub?"; then + latest_version=$(github_latest_release_tag "neovim/neovim") + info "Found latest version: $latest_version" + + if command -v nvim &>/dev/null; then + installed_version=$(nvim --version | sed -En 's/^NVIM (v[0-9]+\.[0-9]+\.[0-9]+).*$/\1/p') + debug "Found installed version: $installed_version" + + if [[ "$installed_version" != "$latest_version" ]]; then + info "Updating nvim..." + download_and_install_nvim + else + info "nvim $installed_version already installed." + if prompt_default_no "Reinstall nvim?"; then + info "Reinstalling nvim..." + download_and_install_nvim + fi + fi + else + info "Installing nvim for the first time..." + download_and_install_nvim + fi + fi fi diff --git a/setup.d/031-development-packages.sh b/setup.d/031-development-packages.sh index 5903f9b3..a8e426ff 100755 --- a/setup.d/031-development-packages.sh +++ b/setup.d/031-development-packages.sh @@ -3,7 +3,7 @@ if prompt_default_no "Install Python development packages?"; then if prompt_default_no "Install Pip?"; then if ! command -v pip &>/dev/null; then info "Pip not installed. Installing..." - curl https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py + curl --fail --show-error https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py python3 /tmp/get-pip.py --user else info "Pip $(pip --version | grep -o '(.*)') already installed" @@ -15,20 +15,6 @@ if prompt_default_no "Install Python development packages?"; then info "${YELLOW}Modifying $(which pylint) to use environment python instead of system python..." sed -i 's|/usr/bin/python3|/usr/bin/env python3|' "$(which pylint)" fi - - if prompt_default_yes "Install/update colout?"; then - mkdir -p "$HOME/src/" - if [[ -d "$HOME/src/colout/" ]]; then - pushd "$HOME/src/colout/" || exit 1 - git pull - else - git clone https://github.com/nojhan/colout.git "$HOME/src/colout/" - pushd "$HOME/src/colout/" || exit 1 - python setup.py install --user - fi - - popd || exit 1 - fi fi # Python download_and_install_shellcheck() { @@ -150,6 +136,7 @@ if prompt_default_no "Install/update Rust?"; then dump_syms \ minidump-stackwalk \ rustfilt \ + tree-sitter-cli \ ; fi fi # Rust @@ -214,7 +201,7 @@ if prompt_default_no "Install nvm?"; then popd || exit 1 else debug "nvm not found. Installing nvm..." - curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/$latest_version/install.sh" | bash + curl --fail --show-error -o- "https://raw.githubusercontent.com/nvm-sh/nvm/$latest_version/install.sh" | bash fi # Source nvm so we can use it in following setup steps diff --git a/setup.d/032-sysworxx-can-drivers.sh b/setup.d/032-sysworxx-can-drivers.sh index 28978c0c..3581926c 100755 --- a/setup.d/032-sysworxx-can-drivers.sh +++ b/setup.d/032-sysworxx-can-drivers.sh @@ -11,7 +11,7 @@ fi if [[ ! -f /tmp/driver.tar.bz2 ]]; then debug "Downloading driver ..." pushd /tmp/ - curl --location "$SYSWORXX_SOCKETCAN_DRIVER_DOWNLOAD_LINK" --output /tmp/driver.tar.bz2 + curl --fail --show-error --location "$SYSWORXX_SOCKETCAN_DRIVER_DOWNLOAD_LINK" --output /tmp/driver.tar.bz2 tar -xjvf /tmp/driver.tar.bz2 popd fi diff --git a/setup.d/050-apps-ubuntu.sh b/setup.d/050-apps-ubuntu.sh index b0f189e6..4b27f81a 100755 --- a/setup.d/050-apps-ubuntu.sh +++ b/setup.d/050-apps-ubuntu.sh @@ -11,17 +11,17 @@ if prompt_default_no "Install base GUI packages?"; then fi if prompt_default_no "Install VS Code?"; then - curl --location https://go.microsoft.com/fwlink/?LinkID=760868 --output /tmp/code.deb + curl --fail --show-error --location https://go.microsoft.com/fwlink/?LinkID=760868 --output /tmp/code.deb sudo apt install /tmp/code.deb fi if prompt_default_no "Install Discord?"; then - curl --location "https://discordapp.com/api/download?platform=linux&format=deb" --output /tmp/discord.deb + curl --fail --show-error --location "https://discordapp.com/api/download?platform=linux&format=deb" --output /tmp/discord.deb sudo apt install /tmp/discord.deb fi if prompt_default_no "Install Spotify?"; then - curl -sS https://download.spotify.com/debian/pubkey_0D811D58.gpg | sudo apt-key add - + curl --fail -sS https://download.spotify.com/debian/pubkey_0D811D58.gpg | sudo apt-key add - echo "deb http://repository.spotify.com stable non-free" | sudo tee /etc/apt/sources.list.d/spotify.list sudo apt update sudo apt install spotify-client diff --git a/setup.d/060-customizations.sh b/setup.d/060-customizations.sh index f464fba0..42090c3b 100755 --- a/setup.d/060-customizations.sh +++ b/setup.d/060-customizations.sh @@ -14,7 +14,7 @@ fi if prompt_default_no "Install Pointfree font?"; then # https://docs.fedoraproject.org/en-US/quick-docs/fonts/ mkdir -p ~/.local/share/fonts - curl --location --output /tmp/pointfree.zip "https://dl.dafont.com/dl/?f=pointfree" + curl --fail --show-error --location --output /tmp/pointfree.zip "https://dl.dafont.com/dl/?f=pointfree" unzip -d /tmp/ /tmp/pointfree.zip mkdir -p ~/.local/share/fonts/ mv /tmp/pointfree.ttf ~/.local/share/fonts/ diff --git a/stowdir/.config/nvim/init.lua b/stowdir/.config/nvim/init.lua new file mode 100644 index 00000000..2e3e8556 --- /dev/null +++ b/stowdir/.config/nvim/init.lua @@ -0,0 +1,34 @@ +vim.g.mapleader = "\\" +vim.g.maplocalleader = "\\" + +-- Auto-load every lua/config/*.lua module in alphabetical order +for _, path in ipairs(vim.api.nvim_get_runtime_file("lua/config/*.lua", true)) do + require("config." .. path:match("lua/config/(.+)%.lua$")) +end + +-- Bootstrap lazy.nvim +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not vim.uv.fs_stat(lazypath) then + local out = vim.fn.system({ + "git", + "clone", + "--filter=blob:none", + "--branch=stable", + "https://github.com/folke/lazy.nvim.git", + lazypath, + }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + }, true, {}) + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +require("lazy").setup({ + spec = { { import = "plugins" } }, + checker = { enabled = true }, + ui = { border = "single" }, +}) diff --git a/stowdir/.config/nvim/lazy-lock.json b/stowdir/.config/nvim/lazy-lock.json new file mode 100644 index 00000000..c6b22118 --- /dev/null +++ b/stowdir/.config/nvim/lazy-lock.json @@ -0,0 +1,31 @@ +{ + "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" }, + "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, + "conform.nvim": { "branch": "master", "commit": "dca1a190aa85f9065979ef35802fb77131911106" }, + "copilot.lua": { "branch": "master", "commit": "78c638293f0ea6a2245eca46e9933ee271792d7e" }, + "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" }, + "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, + "gitsigns.nvim": { "branch": "main", "commit": "dd3f588bacbeb041be6facf1742e42097f62165d" }, + "kanagawa.nvim": { "branch": "master", "commit": "8ad3b4cdcc804b332c32db8f9743667e1bb82b99" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, + "lualine.nvim": { "branch": "master", "commit": "131a558e13f9f28b15cd235557150ccb23f89286" }, + "marks.nvim": { "branch": "master", "commit": "f353e8c08c50f39e99a9ed474172df7eddd89b72" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "0c2823e0418f3d9230ff8b201c976e84de1cb401" }, + "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, + "mason.nvim": { "branch": "main", "commit": "cb8445f8ce85d957416c106b780efd51c6298f89" }, + "nvim-lastplace": { "branch": "main", "commit": "91b996e062affebd7fe787f57a2a3e212457e87b" }, + "nvim-lint": { "branch": "master", "commit": "eab58b48eb11d7745c11c505e0f3057165902461" }, + "nvim-lspconfig": { "branch": "master", "commit": "31026a13eefb20681124706a79fc1df6bf11ab27" }, + "nvim-surround": { "branch": "main", "commit": "2e93e154de9ff326def6480a4358bfc149d5da2c" }, + "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e" }, + "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, + "telescope-undo.nvim": { "branch": "main", "commit": "928d0c2dc9606e01e2cc547196f48d2eaecf58e5" }, + "telescope.nvim": { "branch": "master", "commit": "f04ab730b8f9c6bf3f54a206d0dcddfd70c52d59" }, + "vim-bitbake": { "branch": "master", "commit": "e75f8ea12b4a0bcfe46c564a3a78ff7361b0a1c6" }, + "vim-eunuch": { "branch": "master", "commit": "e86bb794a1c10a2edac130feb0ea590a00d03f1e" }, + "vim-flatbuffers": { "branch": "master", "commit": "ecd75c33576d982f3c83545dff7b3c9245285e75" }, + "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, + "vim-tmux-navigator": { "branch": "master", "commit": "e41c431a0c7b7388ae7ba341f01a0d217eb3a432" } +} diff --git a/stowdir/.config/nvim/lua/config/clipboard.lua b/stowdir/.config/nvim/lua/config/clipboard.lua new file mode 100644 index 00000000..8cb8817c --- /dev/null +++ b/stowdir/.config/nvim/lua/config/clipboard.lua @@ -0,0 +1,7 @@ +-- System-clipboard bindings via the `clip` script. By using `clip`, I get x11, wayland, and sshclip support +vim.keymap.set("i", "", [[=system('clip --paste')]], { silent = true }) +vim.keymap.set("i", "", [["cyy:call system('clip --copy', @c)]], { silent = true }) +vim.keymap.set("v", "", [["cy:call system('clip --copy', @c)]], { silent = true }) +vim.keymap.set("v", "", [[:let @c=system('clip --paste')gv"cP]], { silent = true }) +vim.keymap.set("n", "", [[:let @c=system('clip --paste')"cP]], { silent = true }) +vim.keymap.set("n", "", [["cyy:call system('clip --copy', @c)]], { silent = true }) diff --git a/stowdir/.config/nvim/lua/config/diagnostics.lua b/stowdir/.config/nvim/lua/config/diagnostics.lua new file mode 100644 index 00000000..cba4c84e --- /dev/null +++ b/stowdir/.config/nvim/lua/config/diagnostics.lua @@ -0,0 +1,7 @@ +vim.diagnostic.config({ + virtual_text = { current_line = true }, + severity_sort = true, + float = { border = "rounded", source = true }, +}) + +vim.keymap.set("n", "gl", vim.diagnostic.open_float, { desc = "Show line diagnostics" }) diff --git a/stowdir/.config/nvim/lua/config/editing.lua b/stowdir/.config/nvim/lua/config/editing.lua new file mode 100644 index 00000000..e82b69cd --- /dev/null +++ b/stowdir/.config/nvim/lua/config/editing.lua @@ -0,0 +1,70 @@ +vim.opt.number = true +vim.opt.cursorline = true +vim.opt.colorcolumn = "100" +vim.opt.textwidth = 100 +vim.opt.scrolloff = 6 +vim.opt.sidescrolloff = 6 +vim.opt.virtualedit = "all" +vim.opt.display = "truncate" + +vim.opt.lazyredraw = true +vim.opt.showmatch = true + +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("editing_gitcommit", { clear = true }), + pattern = "gitcommit", + callback = function() + vim.opt_local.colorcolumn = "72" + end, +}) + +-- Reselect visual block after indent. +vim.keymap.set("v", "<", "", ">gv") + +-- Move by visual line so wrapped lines feel like arrow-key movement. +vim.keymap.set("n", "j", "gj") +vim.keymap.set("n", "k", "gk") + +-- Defeat smartindent's habit of yanking `#` to column 0. +vim.keymap.set("i", "#", "X#") + +-- New empty buffer. +vim.keymap.set("n", "", "enew") + +-- Buffer and quickfix navigation (replaces vim-unimpaired's ]b/[b/]q/[q). +vim.keymap.set("n", "]b", "bnext") +vim.keymap.set("n", "[b", "bprevious") +vim.keymap.set("n", "]q", "cnext") +vim.keymap.set("n", "[q", "cprevious") + +-- :bd / :bd! delete the current buffer but keep the window open by switching to another buffer first. +vim.api.nvim_create_user_command("Bd", function(opts) + local current = vim.api.nvim_get_current_buf() + + -- Surface "no write since last change" before switching, so the user + -- stays on the modified buffer rather than ending up on the alternate. + if not opts.bang and vim.bo[current].modified then + vim.notify( + ("E89: No write since last change for buffer %d (use :Bd!)"):format(current), + vim.log.levels.ERROR + ) + return + end + + local has_others = false + for _, info in ipairs(vim.fn.getbufinfo({ buflisted = 1 })) do + if info.bufnr ~= current then + has_others = true + break + end + end + if has_others then + vim.cmd("bprevious") + else + vim.cmd("enew") + end + vim.cmd(("bdelete%s %d"):format(opts.bang and "!" or "", current)) +end, { bang = true }) + +vim.cmd([[cnoreabbrev bd getcmdtype() == ':' && getcmdline() == 'bd' ? 'Bd' : 'bdelete']]) diff --git a/stowdir/.config/nvim/lua/config/filetypes.lua b/stowdir/.config/nvim/lua/config/filetypes.lua new file mode 100644 index 00000000..f213f71a --- /dev/null +++ b/stowdir/.config/nvim/lua/config/filetypes.lua @@ -0,0 +1,49 @@ +vim.filetype.add({ + extension = { nginx = "nginx" }, + filename = { ["nginx.conf"] = "nginx" }, + pattern = { + [".*/etc/nginx/.*"] = "nginx", + [".*/usr/local/nginx/conf/.*"] = "nginx", + [".*/nginx/.*%.conf"] = "nginx", + [".*%.env"] = "sh", + [".*%.env%..*"] = "sh", + }, +}) + +local group = vim.api.nvim_create_augroup("filetype_overrides", { clear = true }) + +vim.api.nvim_create_autocmd("FileType", { + group = group, + pattern = "yaml", + callback = function() + vim.opt_local.tabstop = 4 + vim.opt_local.softtabstop = 4 + vim.opt_local.shiftwidth = 4 + vim.opt_local.expandtab = true + end, +}) + +vim.api.nvim_create_autocmd("FileType", { + group = group, + pattern = { "c", "cpp" }, + callback = function() + vim.opt_local.comments:prepend(":///,://!") + vim.opt_local.commentstring = "// %s" + end, +}) + +vim.api.nvim_create_autocmd("FileType", { + group = group, + pattern = { "nginx", "qmake" }, + callback = function() + vim.opt_local.commentstring = "# %s" + end, +}) + +vim.api.nvim_create_autocmd("FileType", { + group = group, + pattern = "rust", + callback = function() + vim.g.termdebugger = "rust-gdb" + end, +}) diff --git a/stowdir/.config/nvim/lua/config/filewatching.lua b/stowdir/.config/nvim/lua/config/filewatching.lua new file mode 100644 index 00000000..17a30552 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/filewatching.lua @@ -0,0 +1,14 @@ +vim.opt.autowrite = true +vim.opt.updatetime = 1000 + +vim.api.nvim_create_autocmd({ "BufEnter", "CursorHold", "CursorHoldI", "FocusGained" }, { + group = vim.api.nvim_create_augroup("filewatching_checktime", { clear = true }), + command = "checktime", +}) + +local checktime_timer = vim.uv.new_timer() +checktime_timer:start(2000, 2000, vim.schedule_wrap(function() + if vim.fn.getcmdwintype() == "" then + vim.cmd("checktime") + end +end)) diff --git a/stowdir/.config/nvim/lua/config/folding.lua b/stowdir/.config/nvim/lua/config/folding.lua new file mode 100644 index 00000000..ae6102f7 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/folding.lua @@ -0,0 +1,17 @@ +vim.opt.foldlevelstart = 15 +vim.opt.foldnestmax = 10 +vim.opt.foldmethod = "expr" +vim.opt.foldexpr = "v:lua.vim.treesitter.foldexpr()" + +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("folding_fallback", { clear = true }), + callback = function(args) + local ok, parser = pcall(vim.treesitter.get_parser, args.buf) + if not ok or not parser then + vim.opt_local.foldmethod = "indent" + vim.opt_local.foldexpr = "" + end + end, +}) + +vim.keymap.set("n", "", "za") diff --git a/stowdir/.config/nvim/lua/config/highlights.lua b/stowdir/.config/nvim/lua/config/highlights.lua new file mode 100644 index 00000000..cd1d7cfc --- /dev/null +++ b/stowdir/.config/nvim/lua/config/highlights.lua @@ -0,0 +1,96 @@ +vim.opt.termguicolors = true + +-- Doxygen comment recognition in C/C++. Disable doxygen's own colors so the links below take effect. +vim.g.load_doxygen_syntax = 1 +vim.g.doxygen_enhanced_color = 0 + +local function apply_highlights() + -- Comment / String style. + vim.api.nvim_set_hl(0, "Comment", { italic = true, fg = "#767676" }) + vim.api.nvim_set_hl(0, "String", { italic = true }) + + -- Match-paren and selection. + vim.api.nvim_set_hl(0, "MatchParen", { fg = "#000000", bg = "#008080" }) + -- vim.api.nvim_set_hl(0, "CursorLine", { bg = "#3a3a3a" }) + -- vim.api.nvim_set_hl(0, "Visual", { bg = "#3a3a3a" }) + + -- Spell suggestions. + vim.api.nvim_set_hl(0, "SpellBad", { fg = "#000000", bg = "#800000" }) + vim.api.nvim_set_hl(0, "SpellRare", { fg = "#808080", bg = "#808000" }) + vim.api.nvim_set_hl(0, "SpellCap", { fg = "#808080", bg = "#008000" }) + vim.api.nvim_set_hl(0, "SpellLocal", { fg = "#808080" }) + + -- Copilot ghost text. + vim.api.nvim_set_hl(0, "CopilotSuggestion", { italic = true, fg = "#808000" }) + + -- Custom doxygen comment style; link doxygen captures to it. + vim.api.nvim_set_hl(0, "CustomDoxyComment", { italic = true, fg = "#767676" }) + vim.api.nvim_set_hl(0, "doxygenComment", { link = "CustomDoxyComment" }) + vim.api.nvim_set_hl(0, "doxygenBrief", { link = "CustomDoxyComment" }) + vim.api.nvim_set_hl(0, "doxygenSpecialOnelineDesc", { link = "CustomDoxyComment" }) + vim.api.nvim_set_hl(0, "doxygenCommentL", { link = "SpecialComment" }) + vim.api.nvim_set_hl(0, "doxygenSpecialTypeOnelineDesc", { link = "SpecialComment" }) + vim.api.nvim_set_hl(0, "doxygenSpecialHeading", { link = "SpecialComment" }) + + -- Telescope panels follow the active theme's float colors instead of kanagawa's transparent override. + vim.api.nvim_set_hl(0, "TelescopeNormal", { link = "NormalFloat" }) + vim.api.nvim_set_hl(0, "TelescopeBorder", { link = "FloatBorder" }) + vim.api.nvim_set_hl(0, "TelescopePromptNormal", { link = "NormalFloat" }) + vim.api.nvim_set_hl(0, "TelescopePromptBorder", { link = "FloatBorder" }) + vim.api.nvim_set_hl(0, "TelescopeResultsNormal", { link = "NormalFloat" }) + vim.api.nvim_set_hl(0, "TelescopeResultsBorder", { link = "FloatBorder" }) + vim.api.nvim_set_hl(0, "TelescopePreviewNormal", { link = "NormalFloat" }) + vim.api.nvim_set_hl(0, "TelescopePreviewBorder", { link = "FloatBorder" }) + + -- Unified TODO/FIXME/etc. highlight. + vim.api.nvim_set_hl(0, "MyTodo", { link = "SpellRare" }) + vim.api.nvim_set_hl(0, "Todo", { link = "MyTodo" }) + -- Treesitter captures for languages with @comment.* support. + vim.api.nvim_set_hl(0, "@comment.todo", { link = "MyTodo" }) + vim.api.nvim_set_hl(0, "@comment.note", { link = "MyTodo" }) + vim.api.nvim_set_hl(0, "@comment.warning", { link = "MyTodo" }) + vim.api.nvim_set_hl(0, "@comment.error", { link = "MyTodo" }) + + -- Strip backgrounds so terminal opacity passes through; preserve fg on each group + local transparent = { + "CursorLineNr", + "DiagnosticSignError", + "DiagnosticSignHint", + "DiagnosticSignInfo", + "DiagnosticSignOk", + "DiagnosticSignWarn", + "EndOfBuffer", + "GitSignsAdd", + "GitSignsChange", + "GitSignsChangedelete", + "GitSignsDelete", + "GitSignsTopdelete", + "GitSignsUntracked", + "LineNr", + "Normal", + "NormalNC", + "Pmenu", + "PmenuSbar", + "PmenuThumb", + "SignColumn", + "StatusLine", + "StatusLineNC", + "TabLine", + "TabLineFill", + "TabLineSel", + "VertSplit", + "WinSeparator", + } + for _, group in ipairs(transparent) do + local hl = vim.api.nvim_get_hl(0, { name = group, link = false }) + hl.bg = "none" + hl.ctermbg = "none" + vim.api.nvim_set_hl(0, group, hl) + end +end + +-- Reapply on ColorScheme so theme switches don't clobber our overrides. +vim.api.nvim_create_autocmd("ColorScheme", { + group = vim.api.nvim_create_augroup("custom_highlights", { clear = true }), + callback = apply_highlights, +}) diff --git a/stowdir/.config/nvim/lua/config/history.lua b/stowdir/.config/nvim/lua/config/history.lua new file mode 100644 index 00000000..e190357f --- /dev/null +++ b/stowdir/.config/nvim/lua/config/history.lua @@ -0,0 +1,18 @@ +-- ! - save and restore global variables +-- ' - max files to remember marks from +-- / - max search-pattern history entries +-- : - max command-line history entries +-- < - max lines saved per register +-- s - max kbytes per register +-- h - don't restore hlsearch from shada +vim.opt.shada = "!,'500,/5000,:5000,<500,s1000,h" + +-- Don't restore cursor position (or anything else) for git commit / rebase +-- buffers, where the cursor should always start at the top. +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("history_disable_for_git", { clear = true }), + pattern = { "gitcommit", "gitrebase" }, + callback = function() + vim.opt_local.shada = "" + end, +}) diff --git a/stowdir/.config/nvim/lua/config/indentation.lua b/stowdir/.config/nvim/lua/config/indentation.lua new file mode 100644 index 00000000..7b4d7535 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/indentation.lua @@ -0,0 +1,5 @@ +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.expandtab = true +vim.opt.smartindent = true +vim.opt.shiftround = true diff --git a/stowdir/.config/nvim/lua/config/paths.lua b/stowdir/.config/nvim/lua/config/paths.lua new file mode 100644 index 00000000..6290d8e1 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/paths.lua @@ -0,0 +1,21 @@ +vim.opt.path:append("**") + +vim.opt.wildignore:append({ + ".git/*", + "*/node_modules/*", + "*/target/*", + "*/build/*", + "*.class", + "*.png", + "*.gif", + "*.pdf", + "*.exe", + "*.o", + "*.so", + "*.jar", + "*.war", + "*.ear", + "*.dll", + "*.swp", + "*.zip", +}) diff --git a/stowdir/.config/nvim/lua/config/search.lua b/stowdir/.config/nvim/lua/config/search.lua new file mode 100644 index 00000000..af9262e8 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/search.lua @@ -0,0 +1,6 @@ +vim.opt.ignorecase = true +vim.opt.smartcase = true + +vim.opt.grepprg = "rg --vimgrep --smart-case --follow" + +vim.keymap.set("n", "", "nohlsearch", { silent = true }) diff --git a/stowdir/.config/nvim/lua/config/spelling.lua b/stowdir/.config/nvim/lua/config/spelling.lua new file mode 100644 index 00000000..696f2246 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/spelling.lua @@ -0,0 +1,45 @@ +vim.opt.spelllang = "en_us" +vim.opt.spelloptions = "camel" +vim.opt.spellfile = vim.fn.stdpath("config") .. "/spell/en.utf-8.add" + +local spell_dir = vim.fn.stdpath("config") .. "/spell" +if vim.fn.isdirectory(spell_dir) == 0 then + vim.fn.mkdir(spell_dir, "p") +end + +vim.keymap.set({ "n", "i" }, "", "setlocal spell! spell?") + +-- Recompile *.spl from *.add when the source is newer (keeps binary .spl file out of git). +local function setup_spellfile() + for _, add in ipairs(vim.fn.glob(spell_dir .. "/*.add", true, true)) do + local spl = add .. ".spl" + if + vim.fn.filereadable(add) == 1 + and (vim.fn.filereadable(spl) == 0 or vim.fn.getftime(add) > vim.fn.getftime(spl)) + then + vim.cmd("silent mkspell! " .. vim.fn.fnameescape(add)) + end + end +end + +-- Sort/dedupe *.add on exit so the file is diff-friendly. Only write if the +-- result differs from the current contents, otherwise mtime updates would +-- confuse git rebases. +local function sort_spellfile() + for _, add in ipairs(vim.fn.glob(spell_dir .. "/*.add", true, true)) do + local current = vim.fn.readfile(add) + local sorted = vim.fn.systemlist({ "sort", "--unique", add }) + if not vim.deep_equal(current, sorted) then + vim.fn.writefile(sorted, add) + end + end +end + +vim.api.nvim_create_autocmd("VimEnter", { + group = vim.api.nvim_create_augroup("spellfile_compile", { clear = true }), + callback = setup_spellfile, +}) +vim.api.nvim_create_autocmd("VimLeave", { + group = vim.api.nvim_create_augroup("spellfile_sort", { clear = true }), + callback = sort_spellfile, +}) diff --git a/stowdir/.config/nvim/lua/config/title.lua b/stowdir/.config/nvim/lua/config/title.lua new file mode 100644 index 00000000..72c85ada --- /dev/null +++ b/stowdir/.config/nvim/lua/config/title.lua @@ -0,0 +1,10 @@ +vim.opt.title = true +vim.opt.titlestring = "%{$USER}@%{hostname()}: %F %m" +vim.opt.titleold = "" + +vim.api.nvim_create_autocmd("VimLeave", { + group = vim.api.nvim_create_augroup("title_clear_on_exit", { clear = true }), + callback = function() + vim.opt.title = false + end, +}) diff --git a/stowdir/.config/nvim/lua/config/undo.lua b/stowdir/.config/nvim/lua/config/undo.lua new file mode 100644 index 00000000..e50f64d3 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/undo.lua @@ -0,0 +1,7 @@ +local undo_dir = vim.fn.stdpath("data") .. "/undo" +if vim.fn.isdirectory(undo_dir) == 0 then + vim.fn.mkdir(undo_dir, "p") +end + +vim.opt.undodir = undo_dir +vim.opt.undofile = true diff --git a/stowdir/.config/nvim/lua/config/windowing.lua b/stowdir/.config/nvim/lua/config/windowing.lua new file mode 100644 index 00000000..b4c43798 --- /dev/null +++ b/stowdir/.config/nvim/lua/config/windowing.lua @@ -0,0 +1,15 @@ +-- Quit nvim if quickfix or netrw is the only remaining window. +vim.api.nvim_create_autocmd("WinEnter", { + group = vim.api.nvim_create_augroup("windowing_exit_if_last", { clear = true }), + callback = function() + if vim.fn.winnr("$") ~= 1 then + return + end + if vim.bo.buftype == "quickfix" then + vim.bo.buftype = "nofile" + vim.cmd("quit") + elseif vim.bo.filetype == "netrw" then + vim.cmd("quit") + end + end, +}) diff --git a/stowdir/.config/nvim/lua/plugins/colorscheme.lua b/stowdir/.config/nvim/lua/plugins/colorscheme.lua new file mode 100644 index 00000000..5ff9412b --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/colorscheme.lua @@ -0,0 +1,22 @@ +return { + { + "rebelot/kanagawa.nvim", + lazy = false, + priority = 1000, + opts = { + theme = "lotus", + transparent = true, + dimInactive = true, + keywordStyle = { italic = false }, + overrides = function(colors) + return { + -- ["@markup.raw.markdown_inline"] = { fg = colors.palette.carpYellow }, + } + end, + }, + config = function(_, opts) + require("kanagawa").setup(opts) + vim.cmd.colorscheme("kanagawa-lotus") + end, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/completion.lua b/stowdir/.config/nvim/lua/plugins/completion.lua new file mode 100644 index 00000000..d1f68aa4 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/completion.lua @@ -0,0 +1,68 @@ +return { + { + "saghen/blink.cmp", + version = "1.*", + dependencies = { "L3MON4D3/LuaSnip" }, + opts = { + snippets = { preset = "luasnip" }, + keymap = { + preset = "enter", + [""] = { + function() + local ok, copilot = pcall(require, "copilot.suggestion") + if ok and copilot.is_visible() then + copilot.accept() + return true + end + end, + "snippet_forward", + "fallback", + }, + }, + sources = { + default = { "buffer", "lsp", "path", "snippets" }, + }, + signature = { enabled = true }, + appearance = { + kind_icons = { + Class = "◇", + Color = "●", + Constant = "π", + Constructor = "⊕", + Enum = "≡", + EnumMember = "·", + Event = "!", + Field = "·", + File = "▤", + Folder = "▥", + Function = "ƒ", + Interface = "◈", + Keyword = "★", + Method = "ƒ", + Module = "▦", + Operator = "⊕", + Property = "◦", + Reference = "→", + Snippet = "◊", + Struct = "◆", + Text = "T", + TypeParameter = "τ", + Unit = "⊡", + Value = "◉", + Variable = "ν", + }, + }, + completion = { + menu = { + draw = { + columns = { + { "kind_icon" }, + { "label", "label_description", gap = 1 }, + { "kind" }, + }, + }, + }, + }, + }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/copilot.lua b/stowdir/.config/nvim/lua/plugins/copilot.lua new file mode 100644 index 00000000..8acd4435 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/copilot.lua @@ -0,0 +1,41 @@ +return { + { + "zbirenbaum/copilot.lua", + cmd = "Copilot", + event = "InsertEnter", + opts = { + suggestion = { + enabled = true, + auto_trigger = true, + keymap = { + accept_word = "", + dismiss = "", + }, + }, + panel = { enabled = false }, + filetypes = { + ["*"] = true, + text = false, + }, + should_attach = function(_, source) + local name = vim.fs.basename(source.bufname or vim.api.nvim_buf_get_name(0)) + local secret_patterns = { + "%.env$", + "%.env%.", + "%.pem$", + "%.key$", + "^id_rsa", + "^id_ed25519", + "^id_ecdsa", + "credentials", + } + for _, pat in ipairs(secret_patterns) do + if name:match(pat) then + return false + end + end + return true + end, + }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/editing.lua b/stowdir/.config/nvim/lua/plugins/editing.lua new file mode 100644 index 00000000..24bf6801 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/editing.lua @@ -0,0 +1,50 @@ +return { + { + "kylechui/nvim-surround", + version = "*", + event = "VeryLazy", + opts = {}, + }, + { + "tpope/vim-eunuch", + cmd = { "Move", "Rename", "Delete", "Chmod", "SudoWrite", "Mkdir", "Wall", "SudoEdit" }, + }, + { + "folke/flash.nvim", + event = "VeryLazy", + opts = { + modes = { + char = { + jump_labels = false, + }, + search = { enabled = false }, + }, + }, + }, + { + "chentoast/marks.nvim", + event = "VeryLazy", + opts = {}, + }, + { + "mrcjkb/nvim-lastplace", + event = "BufReadPre", + }, + { + "christoomey/vim-tmux-navigator", + cmd = { + "TmuxNavigateLeft", + "TmuxNavigateDown", + "TmuxNavigateUp", + "TmuxNavigateRight", + "TmuxNavigatePrevious", + }, + keys = { + { "", "TmuxNavigateLeft", desc = "Tmux/win left" }, + { "", "TmuxNavigateDown", desc = "Tmux/win down" }, + { "", "TmuxNavigateUp", desc = "Tmux/win up" }, + { "", "TmuxNavigateRight", desc = "Tmux/win right" }, + { "", "TmuxNavigatePrevious", desc = "Tmux/win previous" }, + }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/filetypes.lua b/stowdir/.config/nvim/lua/plugins/filetypes.lua new file mode 100644 index 00000000..29ed7f0a --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/filetypes.lua @@ -0,0 +1,10 @@ +return { + { + "dcharbon/vim-flatbuffers", + ft = "fbs", + }, + { + "kergoth/vim-bitbake", + ft = { "bitbake", "bb", "bbappend", "bbclass" }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/formatting.lua b/stowdir/.config/nvim/lua/plugins/formatting.lua new file mode 100644 index 00000000..2b1d221c --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/formatting.lua @@ -0,0 +1,51 @@ +return { + { + "stevearc/conform.nvim", + cmd = { "ConformInfo" }, + keys = { + { + "", + function() + require("conform").format({ async = true, lsp_format = "fallback" }) + end, + mode = { "n", "i" }, + desc = "Format buffer", + }, + }, + opts = { + formatters_by_ft = { + c = { "clang-format" }, + cmake = { "cmake_format" }, + cpp = { "clang-format" }, + css = { "prettier" }, + html = { "prettier" }, + javascript = { "prettier" }, + json = { "jq" }, + lua = { "stylua" }, + markdown = { "dprint" }, + python = { "ruff_format" }, + rust = { "rustfmt" }, + sh = { "shfmt" }, + toml = { "dprint" }, + ["_"] = { "trim_whitespace", "trim_newlines" }, + }, + formatters = { + jq = { prepend_args = { "--indent", "4" } }, + prettier = { + prepend_args = { + "--print-width", + "120", + "--prose-wrap", + "always", + "--tab-width", + "4", + "--html-whitespace-sensitivity", + "css", + }, + }, + ruff_format = { prepend_args = { "--line-length=100" } }, + shfmt = { prepend_args = { "--indent", "4" } }, + }, + }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/git.lua b/stowdir/.config/nvim/lua/plugins/git.lua new file mode 100644 index 00000000..1f18a57b --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/git.lua @@ -0,0 +1,24 @@ +return { + { + "lewis6991/gitsigns.nvim", + event = { "BufReadPost", "BufNewFile" }, + opts = { + signs = { + add = { text = "+" }, + change = { text = "~" }, + delete = { text = "_" }, + topdelete = { text = "‾" }, + changedelete = { text = "~" }, + }, + on_attach = function(bufnr) + local gs = require("gitsigns") + vim.keymap.set("n", "]c", function() gs.nav_hunk("next") end, { buffer = bufnr, desc = "Next hunk" }) + vim.keymap.set("n", "[c", function() gs.nav_hunk("prev") end, { buffer = bufnr, desc = "Prev hunk" }) + end, + }, + }, + { + "tpope/vim-fugitive", + cmd = { "G", "Git", "Gdiff", "Gdiffsplit", "Gvdiffsplit", "Gblame", "Gread", "Gwrite", "Gedit", "GBrowse" }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/linting.lua b/stowdir/.config/nvim/lua/plugins/linting.lua new file mode 100644 index 00000000..94cc3379 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/linting.lua @@ -0,0 +1,19 @@ +return { + { + "mfussenegger/nvim-lint", + event = { "BufReadPost", "BufWritePost", "InsertLeave" }, + config = function() + require("lint").linters_by_ft = { + dockerfile = { "hadolint" }, + gitcommit = { "gitlint" }, + } + + vim.api.nvim_create_autocmd({ "BufReadPost", "BufWritePost", "InsertLeave" }, { + group = vim.api.nvim_create_augroup("nvim_lint_trigger", { clear = true }), + callback = function() + require("lint").try_lint() + end, + }) + end, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/lsp.lua b/stowdir/.config/nvim/lua/plugins/lsp.lua new file mode 100644 index 00000000..f97c2228 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/lsp.lua @@ -0,0 +1,113 @@ +return { + { + "williamboman/mason.nvim", + opts = {}, + }, + { + "neovim/nvim-lspconfig", + dependencies = { + "williamboman/mason.nvim", + "williamboman/mason-lspconfig.nvim", + }, + event = "VeryLazy", + config = function() + vim.lsp.config("clangd", { + cmd = { + "clangd", + "--background-index", + "--header-insertion=iwyu", + "--pch-storage=memory", + "--completion-style=bundled", + "--query-driver=/opt/**/*-linux-*,/usr/bin/c++,/usr/bin/cc,/usr/bin/gcc,/usr/bin/g++", + "-j=4", + "--clang-tidy", + }, + }) + vim.lsp.config("lua_ls", { + settings = { + Lua = { + runtime = { version = "LuaJIT" }, + diagnostics = { globals = { "vim" } }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + checkThirdParty = false, + }, + telemetry = { enable = false }, + }, + }, + }) + vim.lsp.config("rust_analyzer", { + settings = { + ["rust-analyzer"] = { + cargo = { cfgs = { "test" }, features = "all" }, + procMacro = { enable = true }, + check = { command = "clippy" }, + diagnostics = { disabled = { "unresolved-proc-macro" } }, + }, + }, + }) + require("mason-lspconfig").setup({ + ensure_installed = { + "basedpyright", + "bashls", + "clangd", + "lua_ls", + "neocmake", + "ruff", + }, + }) + + vim.lsp.enable({ + "basedpyright", + "bashls", + "clangd", + "lua_ls", + "neocmake", + "ruff", + "rust_analyzer", + }) + + vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("lsp_keymaps", { clear = true }), + callback = function(args) + local buf = args.buf + local map = function(mode, lhs, rhs, desc) + vim.keymap.set(mode, lhs, rhs, { buffer = buf, desc = desc }) + end + map("n", "gd", vim.lsp.buf.definition, "LSP definition") + map("n", "gD", vim.lsp.buf.type_definition, "LSP type definition") + map("n", "gh", vim.lsp.buf.hover, "LSP hover") + map({ "n", "i" }, "", vim.lsp.buf.rename, "LSP rename") + map({ "n", "i" }, "", function() + require("telescope.builtin").lsp_references() + end, "LSP references") + map("n", "]p", function() + vim.diagnostic.jump({ count = 1 }) + end, "Next diagnostic") + map("n", "[p", function() + vim.diagnostic.jump({ count = -1 }) + end, "Prev diagnostic") + + local client = vim.lsp.get_client_by_id(args.data.client_id) + if client and client.name == "clangd" then + map({ "n", "i" }, "", "LspClangdSwitchSourceHeader", "Switch source/header") + end + end, + }) + end, + }, + { + "WhoIsSethDaniel/mason-tool-installer.nvim", + dependencies = { "williamboman/mason.nvim" }, + opts = { + ensure_installed = { + "clang-format", + "cmakelang", + "gitlint", + "hadolint", + "prettier", + "stylua", + }, + }, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/snippets.lua b/stowdir/.config/nvim/lua/plugins/snippets.lua new file mode 100644 index 00000000..60082126 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/snippets.lua @@ -0,0 +1,14 @@ +return { + { + "L3MON4D3/LuaSnip", + version = "v2.*", + build = "make install_jsregexp", + dependencies = { "rafamadriz/friendly-snippets" }, + config = function() + require("luasnip.loaders.from_vscode").lazy_load() + require("luasnip.loaders.from_snipmate").lazy_load({ + paths = { vim.fn.stdpath("config") .. "/snippets" }, + }) + end, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/statusline.lua b/stowdir/.config/nvim/lua/plugins/statusline.lua new file mode 100644 index 00000000..12a9c85a --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/statusline.lua @@ -0,0 +1,33 @@ +return { + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = { + options = { + icons_enabled = false, + theme = "ayu_dark", + component_separators = { left = "|", right = "|" }, + section_separators = { left = "", right = "" }, + }, + sections = { + lualine_a = { "mode" }, + lualine_b = { + "branch", + "diff", + { + "diagnostics", + symbols = { error = "✗ ", warn = "⚠ ", info = "ⓘ ", hint = "? " }, + }, + }, + lualine_c = { "filename" }, + lualine_x = { vim.lsp.status, "encoding", "filetype" }, + lualine_y = { "progress" }, + lualine_z = { "location" }, + }, + }, + init = function() + -- lualine shows the mode; nvim's default echo-area mode line is redundant. + vim.opt.showmode = false + end, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/telescope.lua b/stowdir/.config/nvim/lua/plugins/telescope.lua new file mode 100644 index 00000000..3512f898 --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/telescope.lua @@ -0,0 +1,74 @@ +return { + { + "nvim-telescope/telescope.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + { "nvim-telescope/telescope-fzf-native.nvim", build = "make" }, + }, + cmd = { "Telescope", "Rg" }, + keys = { + { "", "Telescope buffers", desc = "Telescope buffers" }, + { + "", + function() + require("telescope.builtin").find_files({ + find_command = { + "fd", + "--type", + "f", + "--hidden", + "--no-ignore", + "--exclude", + ".git", + }, + }) + end, + desc = "Telescope find non-VCS files", + }, + { + "", + function() + require("telescope.builtin").find_files({ + find_command = { "fd", "--type", "f", "--hidden" }, + }) + end, + desc = "Telescope find VCS files", + }, + { + "", + "Telescope command_history", + desc = "Telescope command history", + }, + { + "", + "Telescope search_history", + desc = "Telescope search history", + }, + { "", "Telescope oldfiles", desc = "Telescope file history" }, + { "", "Telescope jumplist", desc = "Telescope jumps" }, + { "", "Telescope marks", desc = "Telescope marks" }, + }, + config = function() + require("telescope").setup({ + pickers = { + colorscheme = { enable_preview = true }, + }, + }) + require("telescope").load_extension("fzf") + + vim.api.nvim_create_user_command("Rg", function(opts) + require("telescope.builtin").live_grep({ default_text = opts.args }) + end, { nargs = "*" }) + end, + }, + { + "debugloop/telescope-undo.nvim", + dependencies = "nvim-telescope/telescope.nvim", + keys = { + { "", "Telescope undo", desc = "Telescope undo history" }, + }, + config = function() + require("telescope").load_extension("undo") + end, + }, +} diff --git a/stowdir/.config/nvim/lua/plugins/treesitter.lua b/stowdir/.config/nvim/lua/plugins/treesitter.lua new file mode 100644 index 00000000..c290474f --- /dev/null +++ b/stowdir/.config/nvim/lua/plugins/treesitter.lua @@ -0,0 +1,125 @@ +local parsers = { + "bash", + "bitbake", + "c", + "cmake", + "cpp", + "css", + "diff", + "dockerfile", + "gitcommit", + "gitignore", + "html", + "htmldjango", + "javascript", + "json", + "lua", + "markdown", + "markdown_inline", + "proto", + "python", + "rust", + "toml", + "tsx", + "typescript", + "vim", + "vimdoc", + "xml", + "yaml", +} + +local filetypes = { + "bash", + "bitbake", + "c", + "cmake", + "cpp", + "css", + "diff", + "dockerfile", + "gitcommit", + "gitignore", + "help", + "html", + "htmldjango", + "javascript", + "json", + "lua", + "markdown", + "proto", + "python", + "rust", + "sh", + "toml", + "typescript", + "typescriptreact", + "vim", + "xml", + "yaml", +} + +return { + { + "nvim-treesitter/nvim-treesitter", + branch = "main", + lazy = false, + build = ":TSUpdate", + config = function() + require("nvim-treesitter").install(parsers) + + vim.api.nvim_create_autocmd("FileType", { + pattern = filetypes, + callback = function() + vim.treesitter.start() + vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" + end, + }) + end, + }, + { + "nvim-treesitter/nvim-treesitter-textobjects", + branch = "main", + dependencies = { "nvim-treesitter/nvim-treesitter" }, + init = function() + vim.g.no_plugin_maps = true + end, + config = function() + require("nvim-treesitter-textobjects").setup({ + select = { lookahead = true }, + move = { set_jumps = true }, + }) + + local select = require("nvim-treesitter-textobjects.select").select_textobject + local move = require("nvim-treesitter-textobjects.move") + + vim.keymap.set({ "x", "o" }, "ac", function() select("@comment.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "ic", function() select("@comment.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "af", function() select("@function.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "if", function() select("@function.inner", "textobjects") end) + vim.keymap.set({ "x", "o" }, "aC", function() select("@class.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "iC", function() select("@class.inner", "textobjects") end) + vim.keymap.set({ "x", "o" }, "aa", function() select("@parameter.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "ia", function() select("@parameter.inner", "textobjects") end) + vim.keymap.set({ "x", "o" }, "ao", function() select("@conditional.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "io", function() select("@conditional.inner", "textobjects") end) + vim.keymap.set({ "x", "o" }, "al", function() select("@loop.outer", "textobjects") end) + vim.keymap.set({ "x", "o" }, "il", function() select("@loop.inner", "textobjects") end) + + vim.keymap.set({ "n", "x", "o" }, "]m", function() move.goto_next_start("@function.outer", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "]]", function() move.goto_next_start("@class.outer", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "]a", function() move.goto_next_start("@parameter.inner", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "]l", function() move.goto_next_start("@loop.outer", "textobjects") end) + + vim.keymap.set({ "n", "x", "o" }, "]M", function() move.goto_next_end("@function.outer", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "][", function() move.goto_next_end("@class.outer", "textobjects") end) + + vim.keymap.set({ "n", "x", "o" }, "[m", function() move.goto_previous_start("@function.outer", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "[[", function() move.goto_previous_start("@class.outer", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "[a", function() move.goto_previous_start("@parameter.inner", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "[l", function() move.goto_previous_start("@loop.outer", "textobjects") end) + + vim.keymap.set({ "n", "x", "o" }, "[M", function() move.goto_previous_end("@function.outer", "textobjects") end) + vim.keymap.set({ "n", "x", "o" }, "[]", function() move.goto_previous_end("@class.outer", "textobjects") end) + end, + }, +} diff --git a/stowdir/.config/nvim/snippets/python.snippets b/stowdir/.config/nvim/snippets/python.snippets new file mode 100644 index 00000000..b9839885 --- /dev/null +++ b/stowdir/.config/nvim/snippets/python.snippets @@ -0,0 +1,38 @@ +snippet script "Boilerplate for a new script" + #!/usr/bin/env python3 + """${1:Script docstring.}""" + import argparse + import logging + import sys + + def parse_args(): + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--log-level", "-l", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], help="Set the logging output level. Defaults to INFO.",) + ${2:group = parser.add_argument_group() + group.add_argument("--input", "-i", type=argparse.FileType("r"), default=sys.stdin, help="${3:Script input. Defaults to stdin.}",) + group.add_argument("--output", "-o", type=argparse.FileType("w"), default=sys.stdout, help="${4:Script output. Defaults to stdout.}",)} + + return parser.parse_args() + + + def main(args): + pass + + + if __name__ == "__main__": + args = parse_args() + fmt = "%(asctime)s %(module)s %(levelname)s: %(message)s" + logging.basicConfig( + format=fmt, + datefmt="%Y-%m-%dT%H:%M:%S%z", + level=args.log_level, + stream=sys.stderr, + ) + # Color log output if possible, because I'm a sucker + try: + import coloredlogs + + coloredlogs.install(fmt=fmt, level=args.log_level, datefmt="%Y-%m-%dT%H:%M:%S%z") + except ImportError: + pass + main(args) diff --git a/stowdir/.config/nvim/snippets/sh.snippets b/stowdir/.config/nvim/snippets/sh.snippets new file mode 100644 index 00000000..771ee353 --- /dev/null +++ b/stowdir/.config/nvim/snippets/sh.snippets @@ -0,0 +1,57 @@ +snippet set "Safety settings" + set -o errexit + set -o pipefail + set -o nounset + set -o noclobber + +snippet script "Bash script template" + #!/bin/bash + set -o errexit + set -o pipefail + set -o nounset + set -o noclobber + + RED="\\033[31m" + GREEN="\\033[32m" + BLUE="\\033[34m" + RESET="\\033[0m" + + debug() { + echo -e "\${BLUE}DEBUG:\${RESET} \$*" >&2 + } + + info() { + echo -e "\${GREEN}INFO:\${RESET} \$*" >&2 + } + + error() { + echo -e "\${RED}ERROR:\${RESET} \$*" >&2 + } + + usage() { + echo "Usage: \$0 [--help]" + echo + echo " --help, -h Show this help and exit" + } + + main() { + while [[ \$# -gt 0 ]]; do + case "\$1" in + --help | -h) + usage + exit 0 + ;; + -*) + error "Unexpected option: '\$1'" + exit 1 + ;; + *) + error "Unexpected positional argument: '\$1'" + exit 1 + ;; + esac + shift + done + } + + main "\$@" diff --git a/stowdir/.config/nvim/spell/en.utf-8.add b/stowdir/.config/nvim/spell/en.utf-8.add new file mode 100644 index 00000000..f0dd2f4b --- /dev/null +++ b/stowdir/.config/nvim/spell/en.utf-8.add @@ -0,0 +1,259 @@ +2D +3D +ACK +analytics +Asemic +async +ATD +Autocompletion +autofilled +autoread +autowrite +awk +AxiDraw +backend +backport +backported +backporting +backpressure +barcode +bashrc +BitBake +bool +boolean +breakpoint +bugfix +CamelCase +candump +candumps +CCW +clangd +CLI +clothoid +clothoids +cmake +collinear +commandline +Commandline +composable +Composable +conf +config +configs +const +coredumps +cpp +cppcheck +creational +CSS +CSV +CUDA +cursorcolumn +customizations +databroker +Delaunay +deserialization +deserialize +destructor +dev +DHCP +dimensionality +dotfiles +Doxygen +Dubin's +enum +EOF +ethernet +extentslib +ffmpeg +FieldSync +filename +filenames +filesystem +filetype +filetypes +FIXME +fixups +foldexpr +fontawesome +fzf +gdb +GEOMETRYCOLLECTION +GIS +gitgutter +github +gitignore +gitlint +globals +goto +GPT +Grafana +gruvbox +Handoff +Herostratus +hexchat +homelab +hotspot +HTTPS +idiosyncracies +ignorecase +init +initializer +instantiation +interrogable +Interrogable +IPv4 +ipv6 +iteratively +jetstream +JIRA +json +keybinds +Keybinds +KVM +LaTeX +libcxxabi +libgcc +libssh2 +libunwind +lightbulb +Lindenmayer +linestring +LINESTRING +linestrings +linters +llvm +localhost +Lol +lookahead +loopback +makefile +masse +md +metadata +Minecraft +mockups +monorepo +MULTILINESTRING +MULTIPOINT +MULTIPOLYGON +namespace +NAS +natively +navbar +nginx +nohup +nvidia +OFX +OpenGL +pandoc +parameterized +paren +parens +PCA +PDU +perf +PGN +piecewise +PiHole +plaintext +Plex +POC +popup +POSIX +PowerShell +pre +preprocess +Prusinkiewicz +pyglet +QtCore +QtCreator +README +rebase +Rebase +recurse +reimport +renderer +replanned +repo +resumable +ripgrep +Roadmap +ROS +RS1 +RSS +runtime +runtimes +SBC +sed +SFP +shapefile +shapefiles +shapelib +shellcheck +shellformat +SMS +src +stateful +statusbar +stderr +stdin +stdout +struct +subclasses +sublist +submodule +submodules +subtree +sudo +SVD +SVG +syslog +Tartarus +terraform +Theming +threadsafe +tilings +Tilix +timestamp +timestamps +TOC +TODO +TODOs +toolchain +toolchains +torrenting +TTY +txt +typedef +UHaul +UI +UML +unstage +Untracked +unwinder +unwinders +usr +utils +vectorlib +vendored +vimrc +vimwiki +VPN +VR +VSN +vsplit +Wackery +Watchpoints +waypoint +waypoints +whitespace +WKB +wkt +WKT +wordcloud +writeup +writeups +Yocto +zeromq +zoomer diff --git a/stowdir/.config/nvim/stylua.toml b/stowdir/.config/nvim/stylua.toml new file mode 100644 index 00000000..3e254d04 --- /dev/null +++ b/stowdir/.config/nvim/stylua.toml @@ -0,0 +1,3 @@ +column_width = 100 +indent_type = "Spaces" +indent_width = 4 diff --git a/stowdir/.gitconfig b/stowdir/.gitconfig index c13c25f4..3f185ce1 100644 --- a/stowdir/.gitconfig +++ b/stowdir/.gitconfig @@ -2,7 +2,7 @@ name = Austin Gill email = Notgnoshi@gmail.com [core] - editor = vim + editor = nvim fileMode = false eol = lf autocrlf = input @@ -18,7 +18,8 @@ diffFilter = delta --color-only [delta] line-numbers = true - syntax-theme = base16 + syntax-theme = gruvbox-light + light = true # side-by-side diffs are nice, but utilize __delta_side_by_side_width to enable/disable them # based on the current terminal width. #side-by-side = true diff --git a/stowdir/.local/bin/tmux-window-name b/stowdir/.local/bin/tmux-window-name new file mode 100755 index 00000000..8bfe46c9 --- /dev/null +++ b/stowdir/.local/bin/tmux-window-name @@ -0,0 +1,15 @@ +#!/bin/bash +set -o errexit +set -o pipefail +set -o nounset +set -o noclobber + +path="${1:-$PWD}" + +if [[ "$path" = "$HOME" ]]; then + echo "~" +elif root=$(git -C "$path" rev-parse --show-toplevel 2>/dev/null); then + basename "$root" +else + basename "$path" +fi diff --git a/stowdir/.local/bin/vim b/stowdir/.local/bin/vim new file mode 100755 index 00000000..1a20195f --- /dev/null +++ b/stowdir/.local/bin/vim @@ -0,0 +1,9 @@ +#!/bin/bash +if command -v nvim &>/dev/null; then + exec nvim "$@" +elif [[ -x /usr/bin/vim ]]; then + exec /usr/bin/vim "$@" +else + echo "vim shim: neither nvim nor /usr/bin/vim is installed" >&2 + exit 1 +fi diff --git a/stowdir/.tmux.conf b/stowdir/.tmux.conf index 99f0e6c6..bad6c5d7 100644 --- a/stowdir/.tmux.conf +++ b/stowdir/.tmux.conf @@ -5,7 +5,6 @@ set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' set -g @plugin 'sainnhe/tmux-fzf' TMUX_FZF_LAUNCH_KEY="C-f" -set -g @plugin 'ofirgall/tmux-window-name' ################################################################################################### # Pane creation @@ -92,7 +91,8 @@ set -g mouse on set -g focus-events on set -g history-limit 1000000 -set -g @tmux_window_name_max_name_len "25" + +set -g automatic-rename-format '#{=25:#(tmux-window-name "#{pane_current_path}")}' ################################################################################################### # Initialize tmux plugin manager diff --git a/stowdir/.vim/bundle/ale b/stowdir/.vim/bundle/ale index 69c945d5..c59c0d1a 160000 --- a/stowdir/.vim/bundle/ale +++ b/stowdir/.vim/bundle/ale @@ -1 +1 @@ -Subproject commit 69c945d5daecadf8e4c4c499d0a7babda748d603 +Subproject commit c59c0d1a573a7b2fe491f78af4f2033bde454753 diff --git a/stowdir/.vim/bundle/fzf b/stowdir/.vim/bundle/fzf index 260d1609..b4a86a9c 160000 --- a/stowdir/.vim/bundle/fzf +++ b/stowdir/.vim/bundle/fzf @@ -1 +1 @@ -Subproject commit 260d160973a1df05038c93136a076ca29592e755 +Subproject commit b4a86a9c8a688159131a27b6ec9dbce72ec11573 diff --git a/stowdir/.vim/bundle/fzf.vim b/stowdir/.vim/bundle/fzf.vim index 34a564c8..b9624aa0 160000 --- a/stowdir/.vim/bundle/fzf.vim +++ b/stowdir/.vim/bundle/fzf.vim @@ -1 +1 @@ -Subproject commit 34a564c81f36047f50e593c1656f4580ff75ccca +Subproject commit b9624aa012ddcbae9e79964bfd30cc1fbe3cf263 diff --git a/stowdir/.vim/bundle/ultisnips b/stowdir/.vim/bundle/ultisnips index b22a86f9..0223456b 160000 --- a/stowdir/.vim/bundle/ultisnips +++ b/stowdir/.vim/bundle/ultisnips @@ -1 +1 @@ -Subproject commit b22a86f9dcc5257624bff3c72d8b902eac468aad +Subproject commit 0223456b89f7f797c5424ddef07cfc28b5cd86a5 diff --git a/stowdir/.vim/bundle/vim-airline b/stowdir/.vim/bundle/vim-airline index 499ae853..15866622 160000 --- a/stowdir/.vim/bundle/vim-airline +++ b/stowdir/.vim/bundle/vim-airline @@ -1 +1 @@ -Subproject commit 499ae85357db811108ba1c52aa161fb09c462572 +Subproject commit 1586662296c9dc946083e17cb6a4ef0b3e7c0d68 diff --git a/stowdir/.vim/bundle/vim-fugitive b/stowdir/.vim/bundle/vim-fugitive index 61b51c09..3b753cf8 160000 --- a/stowdir/.vim/bundle/vim-fugitive +++ b/stowdir/.vim/bundle/vim-fugitive @@ -1 +1 @@ -Subproject commit 61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4 +Subproject commit 3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0 diff --git a/stowdir/.vim/bundle/vim-gitgutter b/stowdir/.vim/bundle/vim-gitgutter index 0acb772e..21c977e8 160000 --- a/stowdir/.vim/bundle/vim-gitgutter +++ b/stowdir/.vim/bundle/vim-gitgutter @@ -1 +1 @@ -Subproject commit 0acb772e76064cc406664ab595b58b3fac76488a +Subproject commit 21c977e8597c468c7dc76001389b0b430d46a4b0 diff --git a/stowdir/.vim/bundle/vim-test b/stowdir/.vim/bundle/vim-test index 931c6cfd..bc0e9405 160000 --- a/stowdir/.vim/bundle/vim-test +++ b/stowdir/.vim/bundle/vim-test @@ -1 +1 @@ -Subproject commit 931c6cfdd3069df52c4486b25200e4b10d0595c8 +Subproject commit bc0e94059de40641d163516a83c63bc45c716acf diff --git a/stowdir/.vim/bundle/vimwiki b/stowdir/.vim/bundle/vimwiki index 72792615..a54a3002 160000 --- a/stowdir/.vim/bundle/vimwiki +++ b/stowdir/.vim/bundle/vimwiki @@ -1 +1 @@ -Subproject commit 72792615e739d0eb54a9c8f7e0a46a6e2407c9e8 +Subproject commit a54a3002e229c4b43d69ced170ff77663a5b2c40 diff --git a/stowdir/.vim/vimrc b/stowdir/.vim/vimrc index ba6892ac..08249492 100644 --- a/stowdir/.vim/vimrc +++ b/stowdir/.vim/vimrc @@ -686,7 +686,7 @@ vnoremap > >gv " These keybinds use the `clip` script for system clipboard integration. " `clip` supports X11, Wayland, and local<->remote sshclip. -inoremap =system('clip --paste') +inoremap =system('clip --paste') inoremap "cyy:call system('clip --copy', @c) vnoremap "cy:call system('clip --copy', @c) vnoremap :let @c=system('clip --paste')gv"cP