diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..1d30bf1c
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,140 @@
+name: CI
+
+on:
+ push:
+ branches: [main, optim]
+ pull_request:
+ branches: [main]
+
+jobs:
+ install:
+ name: Install (Ubuntu)
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: false
+
+ - name: Set up machine identifier
+ run: echo "x64-linux" > "$HOME/.machine"
+
+ - name: install_dependencies.sh (Homebrew + packages)
+ run: bash install/install_dependencies.sh
+
+ - name: Persist Homebrew environment
+ run: |
+ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
+ {
+ echo "PATH=$PATH"
+ echo "HOMEBREW_PREFIX=$HOMEBREW_PREFIX"
+ echo "HOMEBREW_CELLAR=$HOMEBREW_CELLAR"
+ echo "HOMEBREW_REPOSITORY=$HOMEBREW_REPOSITORY"
+ } >> "$GITHUB_ENV"
+
+ - name: make install (symlinks)
+ run: |
+ command -v brew
+ command -v stow
+ mkdir -p "$HOME/Projects/personal"
+ ln -sfn "$PWD" "$HOME/Projects/personal/dotfiles"
+ ln -sfn "$PWD" "$HOME/.dotfiles"
+ make install
+
+ - name: Assert key symlinks exist
+ run: |
+ assert_link() {
+ if [[ ! -L "$1" ]]; then
+ echo "FAIL: expected symlink at $1"
+ ls -la "$(dirname "$1")" || true
+ exit 1
+ fi
+ echo "OK: $1 -> $(readlink "$1")"
+ }
+ assert_link "$HOME/.zshrc"
+ assert_link "$HOME/.zshenv"
+ assert_link "$HOME/.zprofile"
+ assert_link "$HOME/.gitconfig"
+ assert_link "$HOME/.bashrc"
+ assert_link "$HOME/.dotfiles"
+
+ assert_dir_or_link() {
+ if [[ ! -d "$1" && ! -L "$1" ]]; then
+ echo "FAIL: expected directory or symlink at $1"
+ ls -la "$(dirname "$1")" || true
+ exit 1
+ fi
+ if [[ -L "$1" ]]; then
+ echo "OK: $1 -> $(readlink "$1")"
+ else
+ echo "OK: $1 is a directory"
+ fi
+ }
+ assert_dir_or_link "$HOME/.config"
+
+ assert_path() {
+ if [[ ! -e "$1" ]]; then
+ echo "FAIL: expected path at $1"
+ ls -la "$(dirname "$1")" || true
+ exit 1
+ fi
+ echo "OK: $1"
+ }
+ assert_path "$HOME/.config/nvim"
+ assert_path "$HOME/.config/zsh"
+ assert_path "$HOME/.config/tmux"
+ assert_path "$HOME/.config/git"
+
+ - name: Assert zshenv sets ZDOTDIR
+ run: |
+ result=$(bash -c 'source "$HOME/.zshenv" 2>/dev/null; echo "$ZDOTDIR"')
+ [[ "$result" == "$HOME/.config/zsh" ]] \
+ && echo "OK: ZDOTDIR=$result" \
+ || { echo "FAIL: ZDOTDIR='$result'"; exit 1; }
+
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: false
+
+ - name: Install shellcheck
+ run: sudo apt-get install -y shellcheck
+
+ - name: ShellCheck
+ run: |
+ # Only lint actively maintained scripts; exclude legacy extra/, zsh configs, and submodules
+ find install/ extra/setup.sh extra/symlinks.sh install.sh \
+ -name '*.sh' \
+ | xargs shellcheck -x
+
+ - name: Bash syntax
+ run: |
+ find install/ extra/setup.sh extra/symlinks.sh install.sh \
+ -name '*.sh' \
+ | xargs -I{} bash -n {}
+
+ lua-lint:
+ name: Lua Lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: false
+
+ - name: Install luacheck
+ run: sudo apt-get install -y luarocks && sudo luarocks install luacheck
+
+ - name: Install stylua
+ run: |
+ curl -sL "https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-x86_64.zip" -o stylua.zip
+ unzip -q stylua.zip -d /usr/local/bin/
+ chmod +x /usr/local/bin/stylua
+
+ - name: luacheck
+ run: luacheck files/.config/nvim --config .luacheckrc
+
+ - name: stylua --check
+ run: stylua --check files/.config/nvim
+ continue-on-error: true
diff --git a/.gitignore b/.gitignore
index 42e0311f..60ef39d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,7 +53,6 @@ files/.hammerspoon/
files/.config/kitty/kittens/neighboring_window.py
files/.config/kitty/kittens/pass_keys.py
-files/.config/kitty/kittens/termpdf.py
files/.config/spotifyd/rustlang.spotifyd.plist
files/.config/lazygit/state.yml
diff --git a/.gitmodules b/.gitmodules
index b3878819..2b2495e9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,8 +1,3 @@
-[submodule "dotbot"]
- path = dotbot
- url = https://github.com/anishathalye/dotbot
- ignore = dirty
-
[submodule "files/.config/tmux/plugins/tpm"]
path = files/.config/tmux/plugins/tpm
url = https://github.com/tmux-plugins/tpm
diff --git a/.luacheckrc b/.luacheckrc
index c8a3f4e5..3d4078d7 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -1,3 +1,25 @@
globals = {
"vim",
+ "mrl",
+ "map",
+ "MiniTest",
+ "Stl",
+ "Stlcol",
+}
+
+-- Ignore: unused variables/arguments, line too long, shadowing, value overwritten
+ignore = {
+ "211", -- unused variable
+ "212", -- unused argument
+ "213", -- unused loop variable
+ "311", -- value assigned to variable is overwritten
+ "312", -- value of field is overwritten
+ "314", -- value assigned to field is overwritten before use
+ "411", -- redefining a local variable
+ "412", -- redefining an argument
+ "421", -- shadowing a local variable
+ "422", -- shadowing an argument
+ "431", -- shadowing an upvalue
+ "432", -- shadowing an upvalue argument
+ "631", -- line is too long
}
diff --git a/.shellcheckrc b/.shellcheckrc
new file mode 100644
index 00000000..03081277
--- /dev/null
+++ b/.shellcheckrc
@@ -0,0 +1,2 @@
+shell=bash
+severity=warning
diff --git a/Makefile b/Makefile
index be78676b..26c60f22 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
FC=${HOME}/.dotfiles
TMUX_SHARE=${HOME}/.local/share/tmux
-all: brew macos kitty nvim vim tmux fzf-marks private zsh-plugins
+all: brew install setup
test:
${HOME}/.dotfiles/tests/zsh/sanity.sh
@@ -16,16 +16,28 @@ macos:
# now we change the keymaps
bash extra/keyboard.sh
+update:
+ brew update && brew upgrade && brew update && brew upgrade && brew cleanup
+
+homebrew:
+ @command -v brew >/dev/null || /bin/bash -c "$$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
install:
- stow --ignore ".DS_Store" --target="${HOME}" --dir="${FC}" files
- rm -rf ~/Downloads; ln -sf "${HOME}/Library/Mobile Documents/com~apple~CloudDocs/Downloads" ~/Downloads
+ bash ${FC}/extra/symlinks.sh
+ @if [[ "$$(uname)" == "Darwin" ]]; then \
+ rm -rf ~/Downloads; \
+ ln -sf "${HOME}/Library/Mobile Documents/com~apple~CloudDocs/Downloads" ~/Downloads; \
+ fi
+
+setup:
+ bash ${FC}/extra/setup.sh
projects:
mkdir -p "${HOME}/Projects/icloud"
stow --ignore ".DS_Store" --target="${HOME}/Projects/icloud" --dir="${HOME}/Library/Mobile Documents/com~apple~CloudDocs/" Projects
brew:
- brew bundle --file="${FC}/homebrew/Brewfile"
+ bash ${FC}/install/install_dependencies.sh
python3 -m pip install pynvim neovim-remote mcphub[all] --upgrade
npm install -g mcp-hub@latest
@@ -98,4 +110,16 @@ zsh-plugins:
ln -sf ${HOMEBREW_PREFIX}/Cellar/alias-tips/alias-tips.plugin.zsh ${HOMEBREW_PREFIX}/share/zsh-alias-tips
-.PHONY: all install brew macos kitty nvim vim tmux fzf-marks private zsh-plugins test
+MASON := $(HOME)/.local/share/nvim/mason/bin
+
+fmt:
+ git diff --name-only --diff-filter=d | grep '\.lua$$' | xargs -r $(MASON)/stylua --
+ git diff --name-only --diff-filter=d | grep '\.sh$$' | xargs -r $(MASON)/shfmt -w
+ git diff --name-only --diff-filter=d | grep '\.py$$' | xargs -r $(MASON)/isort --
+ git diff --name-only --diff-filter=d | grep '\.py$$' | xargs -r $(MASON)/black --
+
+commit: fmt
+ git add -u
+ git commit
+
+.PHONY: all homebrew install setup brew macos kitty nvim vim tmux fzf-marks private zsh-plugins test fmt commit
diff --git a/README.md b/README.md
index 8544f3c5..577ef76d 100644
--- a/README.md
+++ b/README.md
@@ -2,93 +2,85 @@
## Introduction
-Most of my machine configuration is handled with my fictional couscous!
+Most of my machine configuration lives here.
-I use different machines for different purposes, and I have set a
-identificator for each of them. This identificator is based on the
-architecture of the machine, and the OS. The following are the
-identificators I use:
+Each machine is identified by a string stored in `~/.machine`:
-- `arm64-darwin`: for my M1 mac
-- `arm64-linux`: for my Raspberry Pi 4
-- `x64-darwin`: for my Intel mac
-- `x64-linux`: for my linux machines
-- `x64-nodos`: for IGFAE/CERN machines
-- `x64-codespaces`: used for all my codespaces
-- `x64-wsl`: used for my WSL2 setup
-- `x32-linux`: mainly used for iSH app
+| Identifier | Machine |
+| ---------------- | -------------------------- |
+| `arm64-darwin` | M-series Mac |
+| `x64-darwin` | Intel Mac |
+| `x64-linux` | Linux |
+| `x64-wsl` | WSL2 |
+| `x64-nodos` | IGFAE/CERN machines |
+| `x64-codespaces` | GitHub Codespaces |
+| `arm64-linux` | Raspberry Pi 4 |
+| `x32-linux` | iSH app |
-This information **must** be set in the `~/.machine` file. This file is
-automatically created by the `install.sh` script, but you can create it
-manually if you want. The file should contain only the identificator of the
-machine, and nothing else.
+The install script creates this file automatically, or you can write it manually.
-## Core ideas
+## Core tools
-Neovim is my main editor, and everything is circling around it. Here is a list
-of the tools I use:
+Neovim is the primary editor; everything else orbits it.
-| Dependency | Description |
-| ------------------ | ------------------------------------------- |
-| Neovim | Best editor on Earth |
-| Nerd font | Currently I use Fira Code |
-| Fuzzy Finder (fzf) | Search utility |
-| ripgrep | Search |
-| tmux | Terminal multiplexer |
-| wezterm | The terminal emulator that works everywhere |
+| Tool | Role |
+| ------------------ | ------------------------------- |
+| Neovim | Editor |
+| Nerd Font | Currently Fira Code |
+| fzf | Fuzzy finder |
+| ripgrep | Search |
+| tmux | Terminal multiplexer |
+| kitty / wezterm | Terminal emulators |
-I was mostly a Unix user till very recencly where I was forced to use Windows
-and WSL. I used to use kitty as my main terminal, but I swiched to Wezterm
-because it is the only one available on all platforms.
+## Installation
-## Makefile
-
-It still exists a Makefile to install this configuration, but I am currently
-using dotbot to manage my dotfiles.
-
-```
+```bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/marromlam/dotfiles/main/install.sh)" -f -f
```
-In WSL you need to run the following commands first:
+On WSL, run these first:
```bash
sudo sed -i -E 's/nameserver [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/nameserver 8.8.8.8/' /etc/resolv.conf
sudo apt update && sudo apt install curl -y
```
+The installer:
+1. Bootstraps Homebrew (or uses `apk` on iSH)
+2. Installs packages via `install/install_dependencies.sh`
+3. Clones this repo to `~/Projects/personal/dotfiles`
+4. Creates symlinks via GNU Stow (`make install`)
+
+After the initial install, individual steps can be re-run with `make`:
+
+```
+make brew # reinstall/update Homebrew packages
+make install # re-apply symlinks
+make setup # run post-install setup
+```
+
## macOS window manager (Amethyst + Hammerspoon)
-- Install apps from the Brewfile (`amethyst`, `hammerspoon`).
-- Dotbot links:
- - `~/.amethyst.yml` -> `files/.amethyst.yml`
- - `~/.hammerspoon` -> `files/.hammerspoon`
-- Required macOS permissions:
- - `System Settings > Privacy & Security > Accessibility`
- - Enable both `Amethyst` and `Hammerspoon`
-- Suggested if you switch from other tilers:
- - disable `yabai`/`skhd` services to avoid conflicts
- - keep only one tiler active at a time
-
-## Contributions
-
-This files should be used as a template to create your own configuration. I do
-not recommend you to make install all my dotfiles since you will not leverage
-the most part of them. Instead, try to copy what you need and create your own
-repo. But, if you find there is some plugin or configuration that I could take
-advantage of, please do not hesitate to create a pull request!
+- Installed via Brewfile (`amethyst`, `hammerspoon`)
+- Configs are symlinked: `~/.amethyst.yml` and `~/.hammerspoon/`
+- Required: `System Settings > Privacy & Security > Accessibility` — enable both apps
+- If switching from another tiler (yabai/skhd), disable the old one first
+
+## Contributing
+
+Use this as a template — don't install it wholesale. Pick what's useful and build your own config. If you spot something worth sharing back, pull requests are welcome.
diff --git a/dasfasdf b/dasfasdf
deleted file mode 100644
index e0c553e4..00000000
--- a/dasfasdf
+++ /dev/null
@@ -1,280 +0,0 @@
-
-UTF-8 encoding table and Unicode characters
-
-page with code points U+E000 to U+E0FF
-
-Share on Facebook Share on Google+ Tweet about this on Twitter Pin on Pinterest Share on Reddit Share on StumbleUpon Share on VK Digg this Buffer this page Share on LinkedIn Email this to someone
-We need your support - If you like us - feel free to share.
-
-help/imprint (Data Protection)
-
-page format standard · w/o parameter choice · print view
-language German · English
-
-code positions per page 128 · 256 · 512 · 1024
-display format for
-UTF-8 encoding hex. · decimal · hex. (0x) · octal · binary · for Perl string literals · One Latin-1 char per byte · no display
-Unicode character names not displayed · displayed · also display deprecated Unicode 1.0 names
-links for adding char to text displayed · not displayed
-numerical HTML encoding
-of the Unicode character not displayed · decimal · hexadecimal
-HTML 4.0 character entities displayed · not displayed
-Unicode
-code point character UTF-8
-(chars) name
-U+E000 î
-U+E001 î
-U+E002 î
-U+E003 î
-U+E004 î
-U+E005 î
-U+E006 î
-U+E007 î
-U+E008 î
-U+E009 î
-U+E00A î
-U+E00B î
-U+E00C î
-U+E00D î
-U+E00E î
-U+E00F î
-U+E010 î
-U+E011 î
-U+E012 î
-U+E013 î
-U+E014 î
-U+E015 î
-U+E016 î
-U+E017 î
-U+E018 î
-U+E019 î
-U+E01A î
-U+E01B î
-U+E01C î
-U+E01D î
-U+E01E î
-U+E01F î
-U+E020 î
-U+E021 î¡
-U+E022 î¢
-U+E023 î£
-U+E024 î¤
-U+E025 î¥
-U+E026 î¦
-U+E027 î§
-U+E028 î¨
-U+E029 î©
-U+E02A îª
-U+E02B î«
-U+E02C î¬
-U+E02D î
-U+E02E î®
-U+E02F î¯
-U+E030 î°
-U+E031 î±
-U+E032 î²
-U+E033 î³
-U+E034 î´
-U+E035 îµ
-U+E036 î¶
-U+E037 î·
-U+E038 î¸
-U+E039 î¹
-U+E03A îº
-U+E03B î»
-U+E03C î¼
-U+E03D î½
-U+E03E î¾
-U+E03F î¿
-U+E040 î
-U+E041 î
-U+E042 î
-U+E043 î
-U+E044 î
-U+E045 î
-U+E046 î
-U+E047 î
-U+E048 î
-U+E049 î
-U+E04A î
-U+E04B î
-U+E04C î
-U+E04D î
-U+E04E î
-U+E04F î
-U+E050 î
-U+E051 î
-U+E052 î
-U+E053 î
-U+E054 î
-U+E055 î
-U+E056 î
-U+E057 î
-U+E058 î
-U+E059 î
-U+E05A î
-U+E05B î
-U+E05C î
-U+E05D î
-U+E05E î
-U+E05F î
-U+E060 î
-U+E061 î¡
-U+E062 î¢
-U+E063 î£
-U+E064 î¤
-U+E065 î¥
-U+E066 î¦
-U+E067 î§
-U+E068 î¨
-U+E069 î©
-U+E06A îª
-U+E06B î«
-U+E06C î¬
-U+E06D î
-U+E06E î®
-U+E06F î¯
-U+E070 î°
-U+E071 î±
-U+E072 î²
-U+E073 î³
-U+E074 î´
-U+E075 îµ
-U+E076 î¶
-U+E077 î·
-U+E078 î¸
-U+E079 î¹
-U+E07A îº
-U+E07B î»
-U+E07C î¼
-U+E07D î½
-U+E07E î¾
-U+E07F î¿
-U+E080 î
-U+E081 î
-U+E082 î
-U+E083 î
-U+E084 î
-U+E085 î
-U+E086 î
-U+E087 î
-U+E088 î
-U+E089 î
-U+E08A î
-U+E08B î
-U+E08C î
-U+E08D î
-U+E08E î
-U+E08F î
-U+E090 î
-U+E091 î
-U+E092 î
-U+E093 î
-U+E094 î
-U+E095 î
-U+E096 î
-U+E097 î
-U+E098 î
-U+E099 î
-U+E09A î
-U+E09B î
-U+E09C î
-U+E09D î
-U+E09E î
-U+E09F î
-U+E0A0 î
-U+E0A1 î¡
-U+E0A2 î¢
-U+E0A3 î£
-U+E0A4 î¤
-U+E0A5 î¥
-U+E0A6 î¦
-U+E0A7 î§
-U+E0A8 î¨
-U+E0A9 î©
-U+E0AA îª
-U+E0AB î«
-U+E0AC î¬
-U+E0AD î
-U+E0AE î®
-U+E0AF î¯
-U+E0B0 î°
-U+E0B1 î±
-U+E0B2 î²
-U+E0B3 î³
-U+E0B4 î´
-U+E0B5 îµ
-U+E0B6 î¶
-U+E0B7 î·
-U+E0B8 î¸
-U+E0B9 î¹
-U+E0BA îº
-U+E0BB î»
-U+E0BC î¼
-U+E0BD î½
-U+E0BE î¾
-U+E0BF î¿
-U+E0C0 î
-U+E0C1 î
-U+E0C2 î
-U+E0C3 î
-U+E0C4 î
-U+E0C5 î
-U+E0C6 î
-U+E0C7 î
-U+E0C8 î
-U+E0C9 î
-U+E0CA î
-U+E0CB î
-U+E0CC î
-U+E0CD î
-U+E0CE î
-U+E0CF î
-U+E0D0 î
-U+E0D1 î
-U+E0D2 î
-U+E0D3 î
-U+E0D4 î
-U+E0D5 î
-U+E0D6 î
-U+E0D7 î
-U+E0D8 î
-U+E0D9 î
-U+E0DA î
-U+E0DB î
-U+E0DC î
-U+E0DD î
-U+E0DE î
-U+E0DF î
-U+E0E0 î
-U+E0E1 î¡
-U+E0E2 î¢
-U+E0E3 î£
-U+E0E4 î¤
-U+E0E5 î¥
-U+E0E6 î¦
-U+E0E7 î§
-U+E0E8 î¨
-U+E0E9 î©
-U+E0EA îª
-U+E0EB î«
-U+E0EC î¬
-U+E0ED î
-U+E0EE î®
-U+E0EF î¯
-U+E0F0 î°
-U+E0F1 î±
-U+E0F2 î²
-U+E0F3 î³
-U+E0F4 î´
-U+E0F5 îµ
-U+E0F6 î¶
-U+E0F7 î·
-U+E0F8 î¸
-U+E0F9 î¹
-U+E0FA îº
-U+E0FB î»
-U+E0FC î¼
-U+E0FD î½
-U+E0FE î¾
-U+E0FF î¿
diff --git a/dotbot b/dotbot
deleted file mode 160000
index 328bcb32..00000000
--- a/dotbot
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 328bcb32590e5057b09bd27a40bc2fb21385fbf3
diff --git a/extra/install_texlive.sh b/extra/install_texlive.sh
deleted file mode 100644
index 8e4accd5..00000000
--- a/extra/install_texlive.sh
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env bash
-# This is the fancy installer for texlive under linuxbrew, since the formule
-# is broken. Since 2021 texlive has more dependencies than the 2020, and given
-# we in almost all situations wont need the 2021 version, I will just install
-# the latest 2020 version
-#
-# WARNING: 2021 actually has some big differences wrt. 2021 for some includes
-# in tables/figures. Some 2020 code will fail on 2021. There is an
-# easy fix for this.
-
-# create a install fonder on Cellar {{{
-
-mkdir -p $HOMEBREW_PREFIX/Cellar/texlive/
-cd $HOMEBREW_PREFIX/Cellar/texlive/
-wget https://www.texlive.info/tlnet-archive/2020/07/15/tlnet/install-tl-unx.tar.gz
-tar xf install-tl-unx.tar.gz
-
-rm -rf 20200715
-mv {install-tl-,}20200715
-rm -f install-tl-unx.tar.gz*
-
-# }}}
-
-# write a profile file {{{
-
-cat > texlive.profile < $*"; }
+
+# ------------------------------------------------------------------------------
+# Homebrew packages
+# ------------------------------------------------------------------------------
+step "Installing Homebrew packages"
+bash "$DOTFILES/install/install_dependencies.sh"
+
+# ------------------------------------------------------------------------------
+# Git submodules (tpm, zsh plugins, etc.)
+# ------------------------------------------------------------------------------
+step "Updating git submodules"
+git -C "$DOTFILES" submodule update --init --recursive
+
+# ------------------------------------------------------------------------------
+# macOS system settings
+# ------------------------------------------------------------------------------
+if [[ "$(uname)" == "Darwin" ]]; then
+ step "Applying macOS settings"
+ bash "$DOTFILES/extra/macos/macos_settings.sh"
+
+ step "Applying keyboard config"
+ bash "$DOTFILES/extra/keyboard.sh"
+fi
+
+# ------------------------------------------------------------------------------
+# Python packages
+# ------------------------------------------------------------------------------
+if [[ -f "$DOTFILES/requirements.txt" ]]; then
+ step "Installing Python packages"
+ python3 -m pip install -r "$DOTFILES/requirements.txt"
+fi
+
+# ------------------------------------------------------------------------------
+# Local gitconfig (machine-specific overrides, not tracked)
+# ------------------------------------------------------------------------------
+if [[ ! -f ~/.gitconfig.local ]]; then
+ step "Creating ~/.gitconfig.local from template"
+ cp "$DOTFILES/files/config.template" ~/.gitconfig.local
+ echo " Edit ~/.gitconfig.local to set your name/email"
+fi
+
+# ------------------------------------------------------------------------------
+# tmux plugins via TPM
+# ------------------------------------------------------------------------------
+step "Installing tmux plugins"
+tmux start-server
+tmux new-session -d -s __setup__ 2>/dev/null || true
+~/.local/share/tmux/plugins/tpm/scripts/install_plugins.sh
+tmux kill-session -t __setup__ 2>/dev/null || true
+
+echo
+echo "Setup complete."
+
+# vim: ft=bash
diff --git a/extra/steps/002-tools.sh b/extra/steps/002-tools.sh
index 812331f3..ca3bf1b3 100644
--- a/extra/steps/002-tools.sh
+++ b/extra/steps/002-tools.sh
@@ -1,4 +1,4 @@
-# !/bin/bash
+#!/usr/bin/env bash
################################################################################
# Step 002: Install additional tools #
diff --git a/extra/symlinks.sh b/extra/symlinks.sh
new file mode 100755
index 00000000..9ae66657
--- /dev/null
+++ b/extra/symlinks.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+# Create symlinks from the dotfiles repo into $HOME via GNU Stow.
+# Idempotent: safe to run multiple times.
+#
+# Usage: bash extra/symlinks.sh [--force]
+# --force Remove pre-existing symlinks not owned by stow before stowing.
+# Required on first migration from another symlink manager.
+
+set -euo pipefail
+
+DOTFILES="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+
+# ------------------------------------------------------------------------------
+# Ensure stow is available (installed by Homebrew, which may not have run yet)
+# ------------------------------------------------------------------------------
+if ! command -v stow >/dev/null 2>&1; then
+ if command -v brew >/dev/null 2>&1; then
+ echo "==> Installing stow via Homebrew"
+ brew install stow
+ else
+ echo "Error: stow not found and Homebrew is not available." >&2
+ echo "Install stow manually (e.g. brew install stow) and re-run." >&2
+ exit 1
+ fi
+fi
+FORCE=0
+[[ "${1:-}" == "--force" ]] && FORCE=1
+
+# ------------------------------------------------------------------------------
+# Directories
+# ------------------------------------------------------------------------------
+mkdir -p ~/.ssh && chmod 700 ~/.ssh
+mkdir -p ~/Projects/work ~/Projects/personal
+
+# ------------------------------------------------------------------------------
+# On --force: remove any existing symlinks for files in the stow package
+# so stow can take ownership. Real files/dirs are left alone (resolve manually).
+# ------------------------------------------------------------------------------
+if [[ $FORCE -eq 1 ]]; then
+ echo "==> Removing stale symlinks for stow package"
+ while IFS= read -r -d '' f; do
+ rel="${f#"$DOTFILES/files/"}"
+ target="$HOME/$rel"
+ [[ -L "$target" ]] && { echo " unlink $target"; rm "$target"; }
+ done < <(find "$DOTFILES/files" -maxdepth 1 -mindepth 1 -print0)
+fi
+
+# ------------------------------------------------------------------------------
+# Stow the files/ package into $HOME
+# --restow: re-links everything (idempotent, also cleans up obsolete links)
+# ------------------------------------------------------------------------------
+echo "==> Stowing files/ -> $HOME"
+# --adopt moves any real files that conflict into the stow package (adopts them),
+# then --restow re-creates all links cleanly. Together they are idempotent.
+stow --dir="$DOTFILES" --target="$HOME" --adopt --restow files
+echo " done"
+
+# ------------------------------------------------------------------------------
+# Extras stow can't handle
+# ------------------------------------------------------------------------------
+
+# ~/.dotfiles self-link (used by scripts referencing $HOME/.dotfiles)
+if [[ ! -e ~/.dotfiles || $FORCE -eq 1 ]]; then
+ ln -sfn "$DOTFILES" ~/.dotfiles
+ echo " link ~/.dotfiles -> $DOTFILES"
+fi
+
+# SSH keys from private-dotfiles (separate repo, separate location)
+PRIVATE_SSH=~/Projects/personal/private-dotfiles/files/.ssh
+if [[ -d "$PRIVATE_SSH" && ( ! -e ~/.ssh || $FORCE -eq 1 ) ]]; then
+ ln -sfn "$PRIVATE_SSH" ~/.ssh
+ echo " link ~/.ssh -> $PRIVATE_SSH"
+fi
+
+# ------------------------------------------------------------------------------
+# Clean broken symlinks in $HOME (equivalent to dotbot's clean: ["~"])
+# ------------------------------------------------------------------------------
+echo "==> Cleaning broken symlinks in $HOME"
+find "$HOME" -maxdepth 1 -type l | while read -r link; do
+ [[ -e "$link" ]] || { echo " clean $link"; rm "$link"; }
+done
+
+echo
+echo "Done."
+
+# vim: ft=bash
diff --git a/files/.bashrc b/files/.bashrc
index 8f5903b6..6ff01fe4 100644
--- a/files/.bashrc
+++ b/files/.bashrc
@@ -4,15 +4,28 @@
[[ -f "$HOME/.skip" ]] && source $HOME/.skip
# Eval homebrew {{{
-# Homebrew
-if [[ "$(uname -m)" == "x86_64" ]]; then
- eval "$(/usr/local/bin/brew shellenv)"
+# Get machine operative system
+
+export MACHINEOS=$($HOME/.dotfiles/scripts/machine.sh)
+function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
+echo $MACHINEOS
+
+# Set OS-dependent stuff
+if [[ "$MACHINEOS" == "Mac" ]]; then
+ if [[ "$(uname -m)" == "x86_64" ]]; then
+ export HOMEBREW_PREFIX="/usr/local"
+ else
+ export HOMEBREW_PREFIX="/opt/homebrew"
+ fi
else
- eval "$(/opt/homebrew/bin/brew shellenv)"
+ export HOMEBREW_PREFIX="/home/linuxbrew/.linuxbrew"
fi
-# }}}
+export HOMEBREW_PREFIX="/opt/homebrew"
+eval $($HOMEBREW_PREFIX/bin/brew shellenv)
+export XDG_DATA_DIRS="$HOMEBREW_PREFIX/share:$XDG_DATA_DIRS"
+# }}}
# source basuc functions
source $HOME/.dotfiles/zsh/ufunctions.sh
@@ -83,6 +96,7 @@ fi
# vim: ft=bash fdm=marker
-# BEGIN_FZF_THEME
+
+# BEGIN_FZF_THEME: carbon-mist
source ~/.config/fzf/themes/carbon-mist.sh
-# END_FZF_THEME
+# END_FZF_THEME: carbon-mist
diff --git a/files/.config/kitty/kittens/termpdf.py b/files/.config/kitty/kittens/pdfcat.py
similarity index 86%
rename from files/.config/kitty/kittens/termpdf.py
rename to files/.config/kitty/kittens/pdfcat.py
index 25b39330..0f0ca02c 100644
--- a/files/.config/kitty/kittens/termpdf.py
+++ b/files/.config/kitty/kittens/pdfcat.py
@@ -10,7 +10,7 @@ def main(args):
@result_handler(no_ui=True)
def handle_result(args, result, target_window_id, boss):
window_title = "live_preview"
- termpdf_cmd = "termpdf.py"
+ pdfcat_cmd = "pdfcat"
page = None
if len(args) > 2:
@@ -19,7 +19,7 @@ def handle_result(args, result, target_window_id, boss):
cmd = " ".join(
[
" ", # this is intended, so it is not saved in history
- termpdf_cmd,
+ pdfcat_cmd,
# "--invert-colors",
# "--transparent",
f"--page-number {page}" if len(args) > 2 else "",
@@ -41,11 +41,10 @@ def run_cmd(window):
if cmd in fg_cmd:
# Send refresh
boss.child_monitor.needs_write(window.id, b"\x12")
- elif termpdf_cmd in fg_cmd:
- # There is a termpdf.py running, but with a different doc
+ elif pdfcat_cmd in fg_cmd:
+ # There is a pdfcat running, but with a different doc
# Send safe quit
boss.child_monitor.needs_write(window.id, "q")
- # boss.child_monitor.needs_write(window.id, "\x03")
# Open the pdf
run_cmd(window)
else:
@@ -66,8 +65,7 @@ def run_cmd(window):
active_window = tab.active_window
# Create the new window
window = tab.new_window(override_title=window_title, location="vsplit")
- # Write the termpdf.py command
- # boss.child_monitor.needs_write(window.id, "ssh gpu219\x0d")
+ # Write the pdfcat command
run_cmd(window)
# Switch the active window back to what it was
boss.set_active_window(active_window)
diff --git a/files/.config/kitty/kitty.conf b/files/.config/kitty/kitty.conf
index d630ca34..c7dfebcf 100644
--- a/files/.config/kitty/kitty.conf
+++ b/files/.config/kitty/kitty.conf
@@ -1205,7 +1205,7 @@ include ./cartograph.conf
# BEGIN_KITTY_THEME
-include themes/horizon.conf
+include themes/amberglow.conf
# END_KITTY_THEME
diff --git a/files/.config/nvim/after/ftplugin/gitcommit.lua b/files/.config/nvim/after/ftplugin/gitcommit.lua
new file mode 100644
index 00000000..eee2fe70
--- /dev/null
+++ b/files/.config/nvim/after/ftplugin/gitcommit.lua
@@ -0,0 +1,4 @@
+vim.opt_local.colorcolumn = '72'
+vim.opt_local.spell = true
+vim.opt_local.spelllang = 'en_us'
+vim.opt_local.textwidth = 72
diff --git a/files/.config/nvim/after/ftplugin/markdown.lua b/files/.config/nvim/after/ftplugin/markdown.lua
new file mode 100644
index 00000000..da31014c
--- /dev/null
+++ b/files/.config/nvim/after/ftplugin/markdown.lua
@@ -0,0 +1 @@
+vim.opt_local.wrap = false
diff --git a/files/.config/nvim/after/ftplugin/qf.lua b/files/.config/nvim/after/ftplugin/qf.lua
index 4d7624ef..e0164758 100644
--- a/files/.config/nvim/after/ftplugin/qf.lua
+++ b/files/.config/nvim/after/ftplugin/qf.lua
@@ -1,21 +1,43 @@
-- CUSTOM QUICKFIX WINDOW
+local T = require('tools')
+
vim.opt_local.wrap = false
vim.opt_local.number = false
vim.opt_local.signcolumn = 'yes'
vim.opt_local.buflisted = false
vim.opt_local.winfixheight = true
+-- @see: https://vi.stackexchange.ctrueom/a/21255
+local function qf_delete(buf)
+ buf = buf or vim.api.nvim_get_current_buf()
+ local qflist = vim.fn.getqflist()
+ local line = vim.api.nvim_win_get_cursor(0)[1]
+ local mode = vim.api.nvim_get_mode().mode
+ if mode:match('[vV]') then
+ local first_line = vim.fn.getpos("'<")[2]
+ local last_line = vim.fn.getpos("'>")[2]
+ qflist = T.fold(function(accum, item, i)
+ if i < first_line or i > last_line then accum[#accum + 1] = item end
+ return accum
+ end, qflist)
+ else
+ table.remove(qflist, line)
+ end
+ vim.fn.setqflist({}, 'r', { items = qflist })
+ vim.fn.setpos('.', { buf, line, 1, 0 })
+end
+
vim.keymap.set(
'n',
'dd',
- mrl.list.qf.delete,
+ qf_delete,
{ buffer = 0, desc = '[qf] delete current quickfix entry' }
)
vim.keymap.set(
'v',
'd',
- mrl.list.qf.delete,
+ qf_delete,
{ buffer = 0, desc = '[qf] delete selected quickfix entry' }
)
vim.keymap.set(
@@ -33,4 +55,4 @@ vim.keymap.set(
-- force quickfix to open beneath all other splits
vim.cmd.wincmd('J')
-mrl.adjust_split_height(3, 10)
+T.adjust_split_height(3, 10)
diff --git a/files/.config/nvim/after/ftplugin/tex.lua b/files/.config/nvim/after/ftplugin/tex.lua
new file mode 100644
index 00000000..da31014c
--- /dev/null
+++ b/files/.config/nvim/after/ftplugin/tex.lua
@@ -0,0 +1 @@
+vim.opt_local.wrap = false
diff --git a/files/.config/nvim/colors/carbon-mist.lua b/files/.config/nvim/colors/carbon-mist.lua
index bfc6219f..f35433f1 100644
--- a/files/.config/nvim/colors/carbon-mist.lua
+++ b/files/.config/nvim/colors/carbon-mist.lua
@@ -3,12 +3,10 @@
-- Author: Marcos Romero Lamas
-- Version: 1.0.0
-vim.cmd("hi clear")
-if vim.fn.exists("syntax_on") then
- vim.cmd("syntax reset")
-end
+vim.cmd('hi clear')
+if vim.fn.exists('syntax_on') then vim.cmd('syntax reset') end
vim.o.termguicolors = true
-vim.g.colors_name = "carbon-mist"
+vim.g.colors_name = 'carbon-mist'
-require("carbon-mist").load()
+require('carbon-mist').load()
diff --git a/files/.config/nvim/filetype.lua b/files/.config/nvim/filetype.lua
index 8f620cdf..21662145 100644
--- a/files/.config/nvim/filetype.lua
+++ b/files/.config/nvim/filetype.lua
@@ -1,5 +1,3 @@
-if not vim.filetype then return end
-
vim.filetype.add({
extension = {
lock = 'yaml',
diff --git a/files/.config/nvim/init.lua b/files/.config/nvim/init.lua
index c20e9956..630803c6 100644
--- a/files/.config/nvim/init.lua
+++ b/files/.config/nvim/init.lua
@@ -22,60 +22,24 @@ vim.g.obsidian = vim.g.icloud .. '/iCloud~md~obsidian/Documents/Marcos'
vim.g.mapleader = ' ' -- Remap leader key
vim.g.maplocalleader = '\\' -- Local leader is
---------------------------------------------------------------------------------
--- Global namespace {{{
---------------------------------------------------------------------------------
-
-local namespace = {
- ui = {
- statuscolumn = {
- enable = true, -- Re-enabled with caching optimizations
- number_width = 3,
- hide_diag_on_cursorline = true,
- },
- statusline = { enable = true },
- },
- -- some vim mappings require a mixture of commandline commands and function
- -- calls this table is place to store lua functions to be called in those
- -- mappings
- mappings = { enable = true },
-}
-
--- This table is a globally accessible store to facilitating accessing
--- helper functions and variables throughout my config
-_G.mrl = mrl or namespace
-_G.map = vim.keymap.set
-_G.P = vim.print
-
-- If opening from inside neovim terminal buffer, skip full config
if vim.env.NVIM and vim.env.TERM_PROGRAM == 'nvim' then
return require('lazy').setup({ { 'willothy/flatten.nvim', config = true } })
end
--- }}}
---------------------------------------------------------------------------------
-
--------------------------------------------------------------------------------
-- Load modules {{{
--------------------------------------------------------------------------------
-require('tools') -- has to be loaded before plugins
+require('tools') -- has to be loaded before plugins (bootstraps ui, strings, colors)
require('keymaps')
require('options')
require('highlight') -- needed by plugins for highlight tables
-require('custom.ui') -- needed by lazyloader for icons
require('lazyloader')
-- Defer non-critical modules for faster startup
-vim.defer_fn(function()
- require('custom.strings')
- require('external_grep')
-end, 0)
-
--- }}}
---------------------------------------------------------------------------------
+vim.defer_fn(function() require('external_grep') end, 0)
---------------------------------------------------------------------------------
-- }}}
--------------------------------------------------------------------------------
diff --git a/files/.config/nvim/lazy-lock.json b/files/.config/nvim/lazy-lock.json
index 7987424e..d6207a9e 100644
--- a/files/.config/nvim/lazy-lock.json
+++ b/files/.config/nvim/lazy-lock.json
@@ -1,11 +1,12 @@
{
"Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" },
"blink-cmp-avante": { "branch": "master", "commit": "4f494c6e124acbe31a8f5d58effa0c14aa38a6d5" },
- "blink.cmp": { "branch": "main", "commit": "4b18c32adef2898f95cdef6192cbd5796c1a332d" },
+ "blink.cmp": { "branch": "main", "commit": "451168851e8e2466bc97ee3e026c3dcb9141ce07" },
+ "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
"ccc.nvim": { "branch": "main", "commit": "9d1a256e006decc574789dfc7d628ca11644d4c2" },
- "codecompanion.nvim": { "branch": "main", "commit": "f22fe1b04e47110a26abe70bad537cb9baf9c665" },
- "conform.nvim": { "branch": "master", "commit": "40dcec5555f960b0a04340d76eabdf4efe78599d" },
- "copilot.lua": { "branch": "master", "commit": "10c1c888412f6dcc808c6a12525079d7bf9575f9" },
+ "codecompanion.nvim": { "branch": "main", "commit": "9827dbdde55217e7b4185e744eae15f74e9c5e8b" },
+ "conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" },
+ "copilot.lua": { "branch": "master", "commit": "0552b44fceedf0c4cba2cd4953d3976633b2509a" },
"crates.nvim": { "branch": "main", "commit": "ac9fa498a9edb96dc3056724ff69d5f40b898453" },
"csvview.nvim": { "branch": "main", "commit": "7022e18a0fbae9aecf99a3ba02b2a541edc2b8a1" },
"debugprint.nvim": { "branch": "main", "commit": "4f29196c5fe32752bb7a3e8bc83d4a4d2f3b7922" },
@@ -15,16 +16,14 @@
"file-line": { "branch": "main", "commit": "559088afaf10124ea663ee0f4f73b1de48fb1632" },
"fold-cycle.nvim": { "branch": "main", "commit": "6144567b3307bbcfed0e5b2dd23acb9576575d9e" },
"friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
- "fugitive-difftool.nvim": { "branch": "main", "commit": "5c4b2ed39f55f5f96c8b72e5fc1a828fc26ff82b" },
- "fzf-lua": { "branch": "main", "commit": "1eba927866251bae1b61dffc5b673b8dbd0f3f48" },
+ "fzf-lua": { "branch": "main", "commit": "8a79ee54d6216d10b2f153921a12b152be0c1a20" },
+ "git-conflict.nvim": { "branch": "main", "commit": "a1badcd070d176172940eb55d9d59029dad1c5a6" },
"git-worktree.nvim": { "branch": "master", "commit": "f247308e68dab9f1133759b05d944569ad054546" },
"gitgraph.nvim": { "branch": "main", "commit": "c16daa7d7dd597caf9085644c009cfa80b75db8e" },
- "github-notifications.nvim": { "branch": "master", "commit": "a1935937ec6f71ef8e72db73c66bc4e659f2aa3c" },
"gitlinker.nvim": { "branch": "master", "commit": "cc59f732f3d043b626c8702cb725c82e54d35c25" },
- "gitsigns.nvim": { "branch": "main", "commit": "9f3c6dd7868bcc116e9c1c1929ce063b978fa519" },
+ "gitsigns.nvim": { "branch": "main", "commit": "7c4faa3540d0781a28588cafbd4dd187a28ac6e3" },
"glance.nvim": { "branch": "master", "commit": "bf86d8b79dce808e65fdb6e9269d0b4ed6d2eefc" },
- "gruvbox.nvim": { "branch": "main", "commit": "a472496e1a4465a2dd574389dcf6cdb29af9bf1b" },
- "harpoon": { "branch": "harpoon2", "commit": "87b1a3506211538f460786c23f98ec63ad9af4e5" },
+ "grapple.nvim": { "branch": "main", "commit": "b41ddfc1c39f87f3d1799b99c2f0f1daa524c5f7" },
"hererocks": { "branch": "master", "commit": "3db37265c3839cbd4d27fc73f92fa7b58bc3a76f" },
"image.nvim": { "branch": "master", "commit": "da2be65c153ba15a14a342b05591652a6df70d58" },
"inc-rename.nvim": { "branch": "main", "commit": "0074b551a17338ccdcd299bd86687cc651bcb33d" },
@@ -32,10 +31,10 @@
"indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" },
"key-analyzer.nvim": { "branch": "main", "commit": "4e4bef34498e821bcbd5203f44db8b67e4f10e04" },
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
- "lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" },
+ "lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" },
"lspkind.nvim": { "branch": "master", "commit": "c7274c48137396526b59d86232eabcdc7fed8a32" },
"markdown-table-mode.nvim": { "branch": "main", "commit": "bb1ea9b76c1b29e15e14806fdfbb2319df5c06f1" },
- "mason-lspconfig.nvim": { "branch": "main", "commit": "a324581a3c83fdacdb9804b79de1cbe00ce18550" },
+ "mason-lspconfig.nvim": { "branch": "main", "commit": "a979821a975897b88493843301950c456a725982" },
"mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" },
"mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" },
"mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" },
@@ -61,27 +60,27 @@
"noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
"nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" },
"numb.nvim": { "branch": "master", "commit": "12ef3913dea8727d4632c6f2ed47957a993de627" },
- "nvim-dap": { "branch": "master", "commit": "b516f20b487b0ac6a281e376dfac1d16b5040041" },
+ "nvim-dap": { "branch": "master", "commit": "a9d8cb68ee7184111dc66156c4a2ebabfbe01bc5" },
"nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" },
"nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" },
"nvim-dev-container": { "branch": "main", "commit": "87ea57f420b3460d0c45e239057ffc38fa32f886" },
"nvim-lightbulb": { "branch": "master", "commit": "aa3a8b0f4305b25cfe368f6c9be9923a7c9d0805" },
"nvim-lint": { "branch": "master", "commit": "606b823a57b027502a9ae00978ebf4f5d5158098" },
- "nvim-lspconfig": { "branch": "master", "commit": "ead0f5f342d8d323441e7d4b88f0fc436a81ad5f" },
+ "nvim-lspconfig": { "branch": "master", "commit": "841c6d4139aedb8a3f2baf30cef5327371385b93" },
"nvim-lspimport": { "branch": "main", "commit": "9c1c61a5020faeb1863bb66eb4b2a9107e641876" },
"nvim-navic": { "branch": "master", "commit": "f5eba192f39b453675d115351808bd51276d9de5" },
"nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" },
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
- "nvim-treesitter-context": { "branch": "master", "commit": "64dd4cf3f6fd0ab17622c5ce15c91fc539c3f24a" },
- "nvim-treesitter-textobjects": { "branch": "main", "commit": "0bc4ef0a34d80fd6e67b59bd71fcbb0ef9ef4756" },
+ "nvim-treesitter-context": { "branch": "master", "commit": "9a8e39993e3b895601bf8227124a48ea8268149e" },
+ "nvim-treesitter-textobjects": { "branch": "main", "commit": "7359dfcefa38db632541e1f9b5b5f291626a1d47" },
"nvim-ts-autotag": { "branch": "main", "commit": "8e1c0a389f20bf7f5b0dd0e00306c1247bda2595" },
"nvim-ts-context-commentstring": { "branch": "main", "commit": "1b212c2eee76d787bbea6aa5e92a2b534e7b4f8f" },
"obsidian.nvim": { "branch": "main", "commit": "14e0427bef6c55da0d63f9a313fd9941be3a2479" },
+ "oil.nvim": { "branch": "master", "commit": "0fcc83805ad11cf714a949c98c605ed717e0b83e" },
"plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
- "rainbow-delimiters.nvim": { "branch": "master", "commit": "01993eb20c6cdc1d33e7e98252368840309f99b9" },
- "render-markdown.nvim": { "branch": "main", "commit": "bd482f9a4827c9422231a7db1439c5cff1e69ae0" },
- "sidekick.nvim": { "branch": "main", "commit": "c2bdf8cfcd87a6be5f8b84322c1b5052e78e302e" },
- "snacks.nvim": { "branch": "main", "commit": "fe7cfe9800a182274d0f868a74b7263b8c0c020b" },
+ "rainbow-delimiters.nvim": { "branch": "master", "commit": "607a438d8c647a355749973fd295e33505afafde" },
+ "render-markdown.nvim": { "branch": "main", "commit": "e3c18ddd27a853f85a6f513a864cf4f2982b9f26" },
+ "sidekick.nvim": { "branch": "main", "commit": "8ad0ede3ff9065878a853e4b037ba6ac88231fb0" },
"sonarqube.nvim": { "branch": "master", "commit": "811bf8f46e0aa5ed9c9b5783aaf6f87640df553a" },
"symbol-usage.nvim": { "branch": "main", "commit": "e07c07dfe7504295a369281e95a24e1afa14b243" },
"symbols-outline.nvim": { "branch": "master", "commit": "564ee65dfc9024bdde73a6621820866987cbb256" },
@@ -89,28 +88,24 @@
"tiny-inline-diagnostic.nvim": { "branch": "main", "commit": "ba133b3e932416e4b9507095731a6d7276878fe8" },
"todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" },
"toggleterm.nvim": { "branch": "main", "commit": "9a88eae817ef395952e08650b3283726786fb5fb" },
- "treesj": { "branch": "main", "commit": "186084dee5e9c8eec40f6e39481c723dd567cb05" },
+ "treesj": { "branch": "main", "commit": "26bc2a8432ba3ea79ed6aa346fba780a3d372570" },
"trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" },
- "undotree": { "branch": "master", "commit": "d8f99084d98c32f651860eb0baaf89759f91debc" },
+ "undotree": { "branch": "master", "commit": "6fa6b57cda8459e1e4b2ca34df702f55242f4e4d" },
"vim-apathy": { "branch": "master", "commit": "27128a0f55189724c841843ba41cd33cf7186032" },
"vim-dadbod": { "branch": "master", "commit": "6d1d41da4873a445c5605f2005ad2c68c99d8770" },
"vim-dadbod-completion": { "branch": "master", "commit": "a8dac0b3cf6132c80dc9b18bef36d4cf7a9e1fe6" },
"vim-dadbod-ui": { "branch": "master", "commit": "07e92e22114cc5b1ba4938d99897d85b58e20475" },
"vim-dirdiff": { "branch": "master", "commit": "84bc8999fde4b3c2d8b228b560278ab30c7ea4c9" },
- "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" },
+ "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" },
"vim-kitty": { "branch": "main", "commit": "cd72f2d9cfee8d6aba5a180a5ac3ca265b5d3a46" },
"vim-ledger": { "branch": "master", "commit": "4f2d93dd914f625e2d3db47d97bd9f428fedd68f" },
"vim-log-highlighting": { "branch": "master", "commit": "1037e26f3120e6a6a2c0c33b14a84336dee2a78f" },
"vim-markdown": { "branch": "master", "commit": "1bc9d0cd8e1cc3e901b0a49c2b50a843f1c89397" },
- "vim-maximizer": { "branch": "master", "commit": "2e54952fe91e140a2e69f35f22131219fcd9c5f1" },
"vim-repeat": { "branch": "master", "commit": "65846025c15494983dafe5e3b46c8f88ab2e9635" },
"vim-rzip": { "branch": "master", "commit": "f65400fed27b27c7cff7ef8d428c4e5ff749bf28" },
- "vim-skeleton": { "branch": "master", "commit": "aba9eb0f752986a98063908877289a50a7063d0e" },
"vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" },
"vim-snakemake": { "branch": "master", "commit": "d0015a0f86150c59fb55f65b41529e6ff4469e18" },
"vim-surround": { "branch": "master", "commit": "3d188ed2113431cf8dac77be61b842acb64433d9" },
- "vim-vinegar": { "branch": "master", "commit": "bb1bcddf43cfebe05eb565a84ab069b357d0b3d6" },
"vimtex": { "branch": "master", "commit": "82d2305ff71dfb3bd91602534cc9bb9a195bcb38" },
- "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" },
- "zen-mode.nvim": { "branch": "main", "commit": "8564ce6d29ec7554eb9df578efa882d33b3c23a7" }
+ "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
}
diff --git a/files/.config/nvim/lua/custom/globals.lua b/files/.config/nvim/lua/custom/globals.lua
deleted file mode 100644
index 46a83a21..00000000
--- a/files/.config/nvim/lua/custom/globals.lua
+++ /dev/null
@@ -1,107 +0,0 @@
-local fn, api, cmd, fmt = vim.fn, vim.api, vim.cmd, string.format
-local l = vim.log.levels
-
----------------------------------------------------------------------------------
--- Quickfix and Location List {{{
----------------------------------------------------------------------------------
-
-mrl.list = { qf = {}, loc = {} }
-
----@param list_type "loclist" | "quickfix"
----@return boolean
-local function is_list_open(list_type)
- return mrl.find(
- function(win) return not mrl.falsy(win[list_type]) end,
- fn.getwininfo()
- ) ~= nil
-end
-
-local silence = { mods = { silent = true, emsg_silent = true } }
-
----@param callback fun(...)
-local function preserve_window(callback, ...)
- local win = api.nvim_get_current_win()
- callback(...)
- if win ~= api.nvim_get_current_win() then cmd.wincmd('p') end
-end
-
-function mrl.list.qf.toggle()
- if is_list_open('quickfix') then
- cmd.cclose(silence)
- elseif #fn.getqflist() > 0 then
- preserve_window(cmd.copen, silence)
- end
-end
-
-function mrl.list.loc.toggle()
- if is_list_open('loclist') then
- cmd.lclose(silence)
- elseif #fn.getloclist(0) > 0 then
- preserve_window(cmd.lopen, silence)
- end
-end
-
--- @see: https://vi.stackexchange.com/a/21255
--- using range-aware function
-function mrl.list.qf.delete(buf)
- buf = buf or api.nvim_get_current_buf()
- local list = fn.getqflist()
- local line = api.nvim_win_get_cursor(0)[1]
- local mode = api.nvim_get_mode().mode
- if mode:match('[vV]') then
- local first_line = fn.getpos("'<")[2]
- local last_line = fn.getpos("'>")[2]
- list = mrl.fold(function(accum, item, i)
- if i < first_line or i > last_line then accum[#accum + 1] = item end
- return accum
- end, list)
- else
- table.remove(list, line)
- end
- -- replace items in the current list, do not make a new copy of it; this also preserves the list title
- fn.setqflist({}, 'r', { items = list })
- fn.setpos('.', { buf, line, 1, 0 }) -- restore current line
-end
-
--- }}}
----------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
--- FILETYPE HELPERS
---------------------------------------------------------------------------------
-
----@class FiletypeSettings
----@field g table
----@field bo vim.bo
----@field wo vim.wo
----@field opt vim.opt
----@field plugins {[string]: fun(module: table)}
-
----@param args {[1]: string, [2]: string, [3]: string, [string]: boolean | integer}[]
----@param buf integer
-local function apply_ft_mappings(args, buf)
- mrl.foreach(function(m)
- assert(
- m[1] and m[2] and m[3],
- 'map args must be a table with at least 3 items'
- )
- local opts = mrl.fold(function(acc, item, key)
- if type(key) == 'string' then acc[key] = item end
- return acc
- end, m, { buffer = buf })
- map(m[1], m[2], m[3], opts)
- end, args)
-end
-
---- A convenience wrapper that calls the ftplugin config for a plugin if it exists
---- and warns me if the plugin is not installed
----@param configs table
-function mrl.ftplugin_conf(configs)
- if type(configs) ~= 'table' then return end
- for name, callback in pairs(configs) do
- local ok, plugin = mrl.pcall(require, name)
- if ok then callback(plugin) end
- end
-end
-
--- vim: fdm=marker
diff --git a/files/.config/nvim/lua/custom/plugins/bufferline.lua b/files/.config/nvim/lua/custom/plugins/bufferline.lua
index ebe86d81..fd6c035b 100644
--- a/files/.config/nvim/lua/custom/plugins/bufferline.lua
+++ b/files/.config/nvim/lua/custom/plugins/bufferline.lua
@@ -3,188 +3,161 @@ return {
{
'akinsho/bufferline.nvim',
event = 'UIEnter',
- dependencies = {},
- cond = false,
- disable = true,
+ dependencies = { 'echasnovski/mini.icons' },
config = function()
local bufferline = require('bufferline')
- bufferline.setup({
- highlights = {
- fill = {
- fg = '#ffffff',
- bg = '#000000',
- },
- background = {
- -- fg = '#000000',
- bg = '#000000',
- },
- tab = {
- -- fg = '#000000',
- bg = '#000000',
- },
- tab_selected = {
- fg = '#000000',
- bg = '#ffaa00',
- },
- tab_separator = {
- fg = '#00ff00',
- bg = '#00aa00',
- },
- tab_separator_selected = {
- fg = '#00ff00',
- bg = '#0000ff',
- -- sp = '',
- -- underline = '',
- },
- },
- options = {
- debug = { logging = true },
- style_preset = { bufferline.style_preset.minimal },
- mode = 'buffers',
- sort_by = 'insert_after_current',
- move_wraps_at_ends = true,
- right_mouse_command = 'vert sbuffer %d',
- show_close_icon = false,
- show_buffer_close_icons = false,
- indicator = {
- -- style = 'icon',
- style = 'none',
- icon = '▎', -- this should be omitted if indicator style is not 'icon'
- },
- -- diagnostics = 'nvim_lsp',
- -- diagnostics_indicator = function(count, level)
- -- level = level:match('warn') and 'warn' or level
- -- return (icons[level] or '?') .. ' ' .. count
- -- end,
- -- diagnostics_update_in_insert = false,
- hover = { enabled = true, reveal = { 'close' } },
- offsets = {
- {
- text = 'EXPLORER',
- filetype = 'neo-tree',
- highlight = 'PanelHeading',
- -- text_align = 'left',
- separator = false,
- },
- {
- text = 'UNDOTREE',
- filetype = 'undotree',
- highlight = 'PanelHeading',
- separator = false,
- },
- {
- text = ' DATABASE VIEWER',
- filetype = 'dbui',
- highlight = 'PanelHeading',
- separator = false,
+ local UI = require('tools').ui
+
+ -- Derive colours from live highlight groups so every theme looks great.
+ local function hl_hex(name, attr, fallback)
+ local ok, h =
+ pcall(vim.api.nvim_get_hl, 0, { name = name, link = false })
+ if ok and h and h[attr] then return ('#%06x'):format(h[attr]) end
+ return fallback
+ end
+
+ local NUMS =
+ { '➊', '➋', '➌', '➍', '➎', '➏', '➐', '➑', '➒', '➓' }
+
+ local function setup()
+ local pal = UI.palette or {}
+ local bg = hl_hex('StatusLine', 'bg', 'NONE')
+ local bg_sel = hl_hex('Normal', 'bg', '#1e1e2e')
+ local fg_sel = hl_hex('Normal', 'fg', '#cdd6f4')
+ local fg_dim = pal.comment_grey or hl_hex('Comment', 'fg', '#6c7086')
+ local accent = pal.blue or hl_hex('Function', 'fg', '#82aaff')
+
+ bufferline.setup({
+ highlights = {
+ -- Tabline gutter & inactive tabs share the statusline bg
+ fill = { bg = bg },
+ background = { bg = bg, fg = fg_dim },
+ tab = { bg = bg, fg = fg_dim },
+ tab_close = { bg = bg, fg = fg_dim },
+ close_button = { bg = bg, fg = fg_dim },
+
+ -- Selected buffer pops out with normal bg
+ buffer_selected = {
+ bg = bg_sel,
+ fg = fg_sel,
+ bold = true,
+ italic = false,
},
- {
- text = ' DIFF VIEW',
- filetype = 'DiffviewFiles',
- highlight = 'PanelHeading',
- separator = false,
+ close_button_selected = { bg = bg_sel, fg = fg_dim },
+ tab_selected = { bg = bg, fg = fg_sel, bold = true },
+
+ -- Visible (non-focused split) buffer
+ buffer_visible = { bg = bg, fg = fg_dim },
+
+ -- Powerline triangle separators
+ separator = { bg = bg, fg = bg_sel },
+ separator_selected = { bg = bg_sel, fg = bg },
+ separator_visible = { bg = bg, fg = bg_sel },
+ offset_separator = { bg = bg, fg = bg_sel },
+
+ -- Indicator line under selected tab uses the accent colour
+ indicator_selected = { fg = accent, bg = bg_sel },
+
+ -- Numbers
+ numbers = { bg = bg, fg = fg_dim },
+ numbers_selected = { bg = bg_sel, fg = fg_sel },
+
+ -- Pick
+ pick = { bg = bg, fg = accent, bold = true, italic = true },
+ pick_selected = {
+ bg = bg_sel,
+ fg = accent,
+ bold = true,
+ italic = true,
},
},
- groups = {
- options = { toggle_hidden_on_enter = true },
- items = {
- bufferline.groups.builtin.pinned:with({ icon = '' }),
- bufferline.groups.builtin.ungrouped,
- {
- name = 'Dependencies',
- icon = '',
- highlight = { fg = '#ECBE7B' },
- matcher = function(buf)
- return vim.startswith(buf.path, vim.env.VIMRUNTIME)
- end,
- },
- {
- name = 'Terraform',
- matcher = function(buf) return buf.name:match('%.tf') ~= nil end,
- },
- {
- name = 'Kubernetes',
- matcher = function(buf)
- return buf.name:match('kubernetes')
- and buf.name:match('%.yaml')
- end,
- },
+
+ options = {
+ style_preset = bufferline.style_preset.minimal,
+ separator_style = { '', '' },
+ mode = 'buffers',
+ custom_areas = {
+ right = function()
+ local tabs = vim.api.nvim_list_tabpages()
+ if #tabs <= 1 then return {} end
+ local result = {}
+ local cur = vim.api.nvim_get_current_tabpage()
+ for i, tab in ipairs(tabs) do
+ local sym = NUMS[i] or tostring(i)
+ local hl = tab == cur and 'BufferLineTabSelected'
+ or 'BufferLineTab'
+ table.insert(result, { text = ' ' .. sym .. ' ', link = hl })
+ end
+ return result
+ end,
+ },
+ sort_by = 'insert_after_current',
+ move_wraps_at_ends = true,
+ right_mouse_command = 'vert sbuffer %d',
+ show_close_icon = false,
+ show_buffer_close_icons = false,
+ show_tab_indicators = false,
+ indicator = { style = 'none' },
+
+ custom_filter = function(buf_number)
+ local name = vim.api.nvim_buf_get_name(buf_number)
+ if name:match('^fugitive://') then return false end
+ if name == '' then return false end
+ return true
+ end,
+
+ hover = { enabled = true, delay = 150, reveal = { 'close' } },
+
+ offsets = {
{
- name = 'SQL',
- matcher = function(buf) return buf.name:match('%.sql$') end,
+ text = ' EXPLORER',
+ filetype = 'neo-tree',
+ highlight = 'PanelHeading',
+ separator = false,
+ text_align = 'left',
},
{
- name = 'tests',
- icon = '',
- matcher = function(buf)
- local name = buf.name
- return name:match('[_%.]spec') or name:match('[_%.]test')
- end,
+ text = ' UNDOTREE',
+ filetype = 'undotree',
+ highlight = 'PanelHeading',
+ separator = false,
+ text_align = 'left',
},
{
- name = 'docs',
- icon = '',
- matcher = function(buf)
- if
- vim.bo[buf.id].filetype == 'man' or buf.path:match('man://')
- then
- return true
- end
- for _, ext in ipairs({ 'md', 'txt', 'org', 'norg', 'wiki' }) do
- if ext == vim.fn.fnamemodify(buf.path, ':e') then
- return true
- end
- end
- end,
+ text = ' DATABASE',
+ filetype = 'dbui',
+ highlight = 'PanelHeading',
+ separator = false,
+ text_align = 'left',
},
{
- name = 'git',
- icon = ' fugitive',
- matcher = function(buf)
- if buf.path:match('fugitive://') then return true end
- end,
+ text = ' DIFF VIEW',
+ filetype = 'DiffviewFiles',
+ highlight = 'PanelHeading',
+ separator = false,
+ text_align = 'left',
},
},
},
- },
+ })
+ end
+
+ setup()
+ vim.api.nvim_create_autocmd('ColorScheme', {
+ group = vim.api.nvim_create_augroup('MrlBufferline', { clear = true }),
+ callback = setup,
})
- vim.keymap.set(
- 'n',
- '[b',
- 'BufferLineMoveNext',
- { desc = 'bufferline: move next' }
- )
- vim.keymap.set(
- 'n',
- ']b',
- 'BufferLineMovePrev',
- { desc = 'bufferline: move prev' }
- )
- vim.keymap.set(
- 'n',
- 'gbb',
- 'BufferLinePick',
- { desc = 'bufferline: pick buffer' }
- )
- vim.keymap.set(
- 'n',
- 'gbd',
- 'BufferLinePickClose',
- { desc = 'bufferline: delete buffer' }
- )
- vim.keymap.set(
- 'n',
- '',
- 'BufferLineCyclePrev',
- { desc = 'bufferline: prev' }
- )
- vim.keymap.set(
- 'n',
- '',
- 'BufferLineCycleNext',
- { desc = 'bufferline: next' }
- )
+ -- Keymaps
+ local map = function(lhs, rhs, desc)
+ vim.keymap.set('n', lhs, rhs, { desc = desc })
+ end
+ map('[b', 'BufferLineMoveNext', 'bufferline: move next')
+ map(']b', 'BufferLineMovePrev', 'bufferline: move prev')
+ map('gbb', 'BufferLinePick', 'bufferline: pick buffer')
+ map('gbd', 'BufferLinePickClose', 'bufferline: delete buffer')
+ map('', 'BufferLineCyclePrev', 'bufferline: prev')
+ map('', 'BufferLineCycleNext', 'bufferline: next')
end,
},
}
diff --git a/files/.config/nvim/lua/custom/plugins/colorscheme.lua b/files/.config/nvim/lua/custom/plugins/colorscheme.lua
index aff90ce1..e2698a0a 100644
--- a/files/.config/nvim/lua/custom/plugins/colorscheme.lua
+++ b/files/.config/nvim/lua/custom/plugins/colorscheme.lua
@@ -1,7 +1,4 @@
--- COLORSCHEME
---
-local enable_italics = true
--- check if /Users/marcos/Workspaces/personal/theme-builder exists as a folder
+-- DONE
local is_dev = vim.fn.isdirectory(
'/Users/marcos/Workspaces/personal/theme-builder'
) == 1
@@ -11,7 +8,7 @@ return {
{
'vague2k/vague.nvim',
lazy = false,
- enabled = not is_dev, -- Don't enable in dev, since it's not the main focus and adds startup time.
+ enabled = not is_dev,
cond = not is_dev,
priority = 1000,
config = function()
@@ -22,141 +19,30 @@ return {
number = 'none',
float = 'none',
error = 'none',
- comments = enable_italics and 'italic' or 'none',
+ comments = 'italic',
conditionals = 'none',
functions = 'none',
headings = 'bold',
operators = 'none',
strings = 'none',
variables = 'none',
- keywords = enable_italics and 'italic' or 'none',
+ keywords = 'italic',
},
})
vim.cmd('colorscheme vague')
end,
},
-
- {
- 'ellisonleao/gruvbox.nvim',
- -- Keep available, but don't pay startup cost unless you re-enable it.
- enabled = false,
- cond = false,
- -- enabled = false,
- priority = 900,
- config = function()
- -- Setup basic colorscheme first (fast path)
- require('gruvbox').setup({
- contrast = 'hard',
- -- palette_overrides = {
- -- dark0_hard = '#0E1018',
- -- },
- terminal_colors = true,
- undercurl = true,
- underline = true,
- bold = true,
- italic = {
- strings = enable_italics,
- emphasis = enable_italics,
- comments = enable_italics,
- operators = false,
- folds = enable_italics,
- },
- strikethrough = true,
- invert_selection = true,
- invert_signs = false,
- invert_tabline = false,
- invert_intend_guides = false,
- inverse = true,
- overrides = {
- Comment = { fg = '#81878f', italic = enable_italics, bold = true },
- Define = { link = 'GruvboxPurple' },
- Macro = { link = 'GruvboxPurple' },
- ['@constant.builtin'] = { link = 'GruvboxPurple' },
- ['@storageclass.lifetime'] = { link = 'GruvboxAqua' },
- ['@text.note'] = { link = 'TODO' },
- ['@namespace.rust'] = { link = 'Include' },
- ['@punctuation.bracket'] = { link = 'GruvboxOrange' },
- texMathDelimZoneLI = { link = 'GruvboxOrange' },
- texMathDelimZoneLD = { link = 'GruvboxOrange' },
- luaParenError = { link = 'luaParen' },
- luaError = { link = 'NONE' },
- ContextVt = { fg = '#878788' },
- CopilotSuggestion = { fg = '#878787' },
- CocCodeLens = { fg = '#878787' },
- CocWarningFloat = { fg = '#dfaf87' },
- CocInlayHint = { fg = '#ABB0B6' },
- CocPumShortcut = { fg = '#fe8019' },
- CocPumDetail = { fg = '#fe8019' },
- DiagnosticVirtualTextWarn = { fg = '#dfaf87' },
- Folded = { fg = '#fe8019', bg = '#0E1018', italic = enable_italics },
- SignColumn = { bg = '#2d2021' },
- DiffAdd = { bold = true, reverse = false, fg = '', bg = '#2a4333' },
- DiffChange = { bold = true, reverse = false, fg = '', bg = '#333841' },
- DiffDelete = {
- bold = true,
- reverse = false,
- fg = '#442d30',
- bg = '#442d30',
- },
- DiffText = { bold = true, reverse = false, fg = '', bg = '#213352' },
- StLine = { bg = '#ff0000' },
- },
- dim_inactive = false,
- transparent_mode = false,
- })
-
- -- Defer expensive highlight lookups (after colorscheme is applied)
- vim.schedule(function()
- vim.api.nvim_set_hl(0, 'StGitAdd', {
- fg = mrl.get_hi('GitSignsAdd').fg,
- bg = mrl.get_hi('Statusline').bg,
- })
- local cursor_bg = mrl.get_hi('CursorLine').bg
- local comment_fg = mrl.get_hi('Comment').fg
- vim.api.nvim_set_hl(
- 0,
- 'SymbolUsageRounding',
- { fg = cursor_bg, italic = enable_italics }
- )
- vim.api.nvim_set_hl(
- 0,
- 'SymbolUsageContent',
- { bg = cursor_bg, fg = comment_fg, italic = enable_italics }
- )
- vim.api.nvim_set_hl(0, 'SymbolUsageRef', {
- fg = mrl.get_hi('Function').fg,
- bg = cursor_bg,
- italic = enable_italics,
- })
- vim.api.nvim_set_hl(0, 'SymbolUsageDef', {
- fg = mrl.get_hi('Type').fg,
- bg = cursor_bg,
- italic = enable_italics,
- })
- vim.api.nvim_set_hl(0, 'SymbolUsageImpl', {
- fg = mrl.get_hi('@keyword').fg,
- bg = cursor_bg,
- italic = enable_italics,
- })
- end)
-
- vim.cmd('colorscheme gruvbox')
- end,
- },
-
+ -- BEGIN_NEOVIM_THEME
{
'marromlam/theme-builder.nvim',
lazy = false,
dev = true,
enabled = is_dev,
cond = is_dev,
- dir = '/Users/marcos/Workspaces/personal/theme-builder/generated/carbon-mist/nvim',
priority = 1000,
- config = function()
- vim.cmd.colorscheme('carbon-mist')
- -- vim.cmd.colorscheme('horizon')
- -- vim.cmd.colorscheme('catppuccin')
- end,
+ dir = '/Users/marcos/Workspaces/personal/theme-builder/generated/amberglow/nvim',
+ config = function() vim.cmd.colorscheme('amberglow') end,
},
+ -- END_NEOVIM_THEME
}
diff --git a/files/.config/nvim/lua/custom/plugins/completion.lua b/files/.config/nvim/lua/custom/plugins/completion.lua
index f672ca48..4b426706 100644
--- a/files/.config/nvim/lua/custom/plugins/completion.lua
+++ b/files/.config/nvim/lua/custom/plugins/completion.lua
@@ -1,4 +1,5 @@
-local highlight, ui = mrl.highlight, mrl.ui
+local highlight = require('highlight')
+local ui = require('tools').ui
return {
{
diff --git a/files/.config/nvim/lua/custom/plugins/debug.lua b/files/.config/nvim/lua/custom/plugins/debug.lua
index b67e63d5..0dfdcdcf 100644
--- a/files/.config/nvim/lua/custom/plugins/debug.lua
+++ b/files/.config/nvim/lua/custom/plugins/debug.lua
@@ -27,6 +27,11 @@ return {
function() require('dap').toggle_breakpoint() end,
desc = 'Debug: Toggle Breakpoint',
},
+ {
+ '',
+ function() require('dapui').toggle() end,
+ desc = 'Debug: See last session result.',
+ },
},
dependencies = {
'rcarriga/nvim-dap-ui', -- Creates a beautiful debugger UI
@@ -57,23 +62,6 @@ return {
},
})
- -- Basic debugging keymaps, feel free to change to your liking!
- vim.keymap.set(
- 'n',
- '',
- dap.continue,
- { desc = 'Debug: Start/Continue' }
- )
- vim.keymap.set('n', '', dap.step_into, { desc = 'Debug: Step Into' })
- vim.keymap.set('n', '', dap.step_over, { desc = 'Debug: Step Over' })
- vim.keymap.set('n', '', dap.step_out, { desc = 'Debug: Step Out' })
- vim.keymap.set(
- 'n',
- 'B',
- dap.toggle_breakpoint,
- { desc = 'Debug: Toggle Breakpoint' }
- )
-
-- Dap UI setup
-- For more information, see |:help nvim-dap-ui|
dapui.setup({
@@ -96,14 +84,6 @@ return {
},
})
- -- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception.
- vim.keymap.set(
- 'n',
- '',
- dapui.toggle,
- { desc = 'Debug: See last session result.' }
- )
-
dap.listeners.after.event_initialized['dapui_config'] = dapui.open
dap.listeners.before.event_terminated['dapui_config'] = dapui.close
dap.listeners.before.event_exited['dapui_config'] = dapui.close
diff --git a/files/.config/nvim/lua/custom/plugins/folke.lua b/files/.config/nvim/lua/custom/plugins/folke.lua
index 452ef5aa..a5647075 100644
--- a/files/.config/nvim/lua/custom/plugins/folke.lua
+++ b/files/.config/nvim/lua/custom/plugins/folke.lua
@@ -1,110 +1 @@
-return {
- {
- 'folke/snacks.nvim',
- event = { 'BufReadPre', 'BufNewFile' },
- opts = {
- -- your configuration comes here
- -- or leave it empty to use the default settings
- -- refer to the configuration section below
- bigfile = { enabled = true },
- dashboard = { enabled = false },
- explorer = { enabled = false },
- indent = { enabled = false },
- input = { enabled = false },
- picker = { enabled = false },
- notifier = { enabled = false },
- quickfile = { enabled = false },
- scope = { enabled = false },
- scroll = { enabled = false },
- statuscolumn = { enabled = false },
- words = { enabled = true },
- },
- enabled = false,
- cond = false,
- },
- {
- 'folke/zen-mode.nvim',
- enabled = false,
- cond = false,
- opts = {
- window = {
- backdrop = 0.95, -- shade the backdrop of the Zen window. Set to 1 to keep the same as Normal
- -- height and width can be:
- -- * an absolute number of cells when > 1
- -- * a percentage of the width / height of the editor when <= 1
- -- * a function that returns the width or the height
- width = 120, -- width of the Zen window
- height = 1, -- height of the Zen window
- -- by default, no options are changed for the Zen window
- -- uncomment any of the options below, or add other vim.wo options you want to apply
- options = {
- -- signcolumn = "no", -- disable signcolumn
- -- number = false, -- disable number column
- -- relativenumber = false, -- disable relative numbers
- -- cursorline = false, -- disable cursorline
- -- cursorcolumn = false, -- disable cursor column
- -- foldcolumn = "0", -- disable fold column
- -- list = false, -- disable whitespace characters
- },
- },
- plugins = {
- -- disable some global vim options (vim.o...)
- -- comment the lines to not apply the options
- options = {
- enabled = true,
- ruler = false, -- disables the ruler text in the cmd line area
- showcmd = false, -- disables the command in the last line of the screen
- -- you may turn on/off statusline in zen mode by setting 'laststatus'
- -- statusline will be shown only if 'laststatus' == 3
- laststatus = 0, -- turn off the statusline in zen mode
- },
- twilight = { enabled = true }, -- enable to start Twilight when zen mode opens
- gitsigns = { enabled = false }, -- disables git signs
- tmux = { enabled = false }, -- disables the tmux statusline
- todo = { enabled = false }, -- if set to "true", todo-comments.nvim highlights will be disabled
- -- this will change the font size on kitty when in zen mode
- -- to make this work, you need to set the following kitty options:
- -- - allow_remote_control socket-only
- -- - listen_on unix:/tmp/kitty
- kitty = {
- enabled = false,
- font = '+4', -- font size increment
- },
- -- this will change the font size on alacritty when in zen mode
- -- requires Alacritty Version 0.10.0 or higher
- -- uses `alacritty msg` subcommand to change font size
- alacritty = {
- enabled = false,
- font = '14', -- font size
- },
- -- this will change the font size on wezterm when in zen mode
- -- See alse also the Plugins/Wezterm section in this projects README
- wezterm = {
- enabled = false,
- -- can be either an absolute font size or the number of incremental steps
- font = '+4', -- (10% increase per step)
- },
- -- this will change the scale factor in Neovide when in zen mode
- -- See alse also the Plugins/Wezterm section in this projects README
- neovide = {
- enabled = false,
- -- Will multiply the current scale factor by this number
- scale = 1.2,
- -- disable the Neovide animations while in Zen mode
- disable_animations = {
- neovide_animation_length = 0,
- neovide_cursor_animate_command_line = false,
- neovide_scroll_animation_length = 0,
- neovide_position_animation_length = 0,
- neovide_cursor_animation_length = 0,
- neovide_cursor_vfx_mode = '',
- },
- },
- },
- -- callback where you can add custom code when the Zen window opens
- on_open = function(win) end,
- -- callback where you can add custom code when the Zen window closes
- on_close = function() end,
- },
- },
-}
+return {}
diff --git a/files/.config/nvim/lua/custom/plugins/fzf.lua b/files/.config/nvim/lua/custom/plugins/fzf.lua
index 9f99dbf7..6264352e 100644
--- a/files/.config/nvim/lua/custom/plugins/fzf.lua
+++ b/files/.config/nvim/lua/custom/plugins/fzf.lua
@@ -1,15 +1,10 @@
-local mrl_ref = rawget(_G, 'mrl') or {}
-local ui = mrl_ref.ui or {}
-local icons = ui.icons or {}
-local lsp_hls = (ui.lsp and ui.lsp.highlights) or {}
+local UI = require('tools').ui
+local icons = UI.icons or {}
+local lsp_hls = (UI.lsp and UI.lsp.highlights) or {}
-local function has_exec(bin)
- return vim.fn.executable(bin) == 1
-end
+local function has_exec(bin) return vim.fn.executable(bin) == 1 end
-local function trim(s)
- return (s:gsub('^%s+', ''):gsub('%s+$', ''))
-end
+local function trim(s) return (s:gsub('^%s+', ''):gsub('%s+$', '')) end
local function toggle_cli_flag(args, flag)
args.cmd = args.cmd or ''
@@ -35,7 +30,10 @@ local function open_files_in_cwd(cwd, label)
end
local where = label and (' for ' .. label) or ''
- vim.notify('Invalid directory' .. where .. ': ' .. tostring(dir), vim.log.levels.WARN)
+ vim.notify(
+ 'Invalid directory' .. where .. ': ' .. tostring(dir),
+ vim.log.levels.WARN
+ )
require('fzf-lua').files()
end
@@ -66,6 +64,7 @@ return {
},
},
-- Native integration for vim.ui.select (replaces custom wrapper).
+
ui_select = {
winopts = {
split = 'botright new',
@@ -83,11 +82,13 @@ return {
hidden = false,
no_ignore = false,
follow = false,
- rg_opts = [[--color=never --files -g "!.git"]],
- fd_opts = [[--color=never --type f --type l --exclude .git]],
+ -- --hidden lets rg/fd see dotfiles; .gitignore still filters untracked ones,
+ -- so git-tracked hidden files are listed while junk (caches, etc.) stays out.
+ rg_opts = [[--color=never --files --hidden -g "!.git"]],
+ fd_opts = [[--color=never --type f --type l --hidden --exclude .git]],
},
grep = {
- rg_opts = '--column --line-number --no-heading --color=always --smart-case --max-columns=4096 -e',
+ rg_opts = '--column --line-number --no-heading --color=always --smart-case --max-columns=4096 --hidden -e',
},
keymap = {
builtin = {
@@ -121,22 +122,46 @@ return {
},
git = {
status = {
- preview_pager = has_delta and 'delta --width=$FZF_PREVIEW_COLUMNS' or nil,
+ preview_pager = has_delta and 'delta --width=$FZF_PREVIEW_COLUMNS'
+ or nil,
},
bcommits = {
- preview_pager = has_delta and 'delta --width=$FZF_PREVIEW_COLUMNS' or nil,
+ preview_pager = has_delta and 'delta --width=$FZF_PREVIEW_COLUMNS'
+ or nil,
},
commits = {
- preview_pager = has_delta and 'delta --width=$FZF_PREVIEW_COLUMNS' or nil,
+ preview_pager = has_delta and 'delta --width=$FZF_PREVIEW_COLUMNS'
+ or nil,
},
icons = {
- ['M'] = { icon = (icons.git and icons.git.mod) or 'M', color = 'yellow' },
- ['D'] = { icon = (icons.git and icons.git.remove) or 'D', color = 'red' },
- ['A'] = { icon = (icons.git and icons.git.staged) or 'A', color = 'green' },
- ['R'] = { icon = (icons.git and icons.git.rename) or 'R', color = 'yellow' },
- ['C'] = { icon = (icons.git and icons.git.conflict) or 'C', color = 'yellow' },
- ['T'] = { icon = (icons.git and icons.git.mod) or 'T', color = 'magenta' },
- ['?'] = { icon = (icons.git and icons.git.untracked) or '?', color = 'magenta' },
+ ['M'] = {
+ icon = (icons.git and icons.git.mod) or 'M',
+ color = 'yellow',
+ },
+ ['D'] = {
+ icon = (icons.git and icons.git.remove) or 'D',
+ color = 'red',
+ },
+ ['A'] = {
+ icon = (icons.git and icons.git.staged) or 'A',
+ color = 'green',
+ },
+ ['R'] = {
+ icon = (icons.git and icons.git.rename) or 'R',
+ color = 'yellow',
+ },
+ ['C'] = {
+ icon = (icons.git and icons.git.conflict) or 'C',
+ color = 'yellow',
+ },
+ ['T'] = {
+ icon = (icons.git and icons.git.mod) or 'T',
+ color = 'magenta',
+ },
+ ['?'] = {
+ icon = (icons.git and icons.git.untracked) or '?',
+ color = 'magenta',
+ },
},
},
}
@@ -156,11 +181,10 @@ return {
-- Use defer_fn to run after fzf-lua sets its statusline
vim.defer_fn(function()
if vim.bo.filetype == 'fzf' then
- local statusline_fn = mrl_ref.ui
- and mrl_ref.ui.statusline
- and mrl_ref.ui.statusline.render
- if type(statusline_fn) == 'function' then
- vim.opt_local.statusline = '%{%v:lua.mrl.ui.statusline.render()%}'
+ if
+ type(_G.Stl) == 'table' and type(_G.Stl.render) == 'function'
+ then
+ vim.opt_local.statusline = '%{%v:lua.Stl.render()%}'
end
end
end, 0)
@@ -174,7 +198,22 @@ return {
'FzfLua',
desc = 'fzf: [f]ind [a]ll builtins',
},
- { 'ff', 'FzfLua files', desc = 'fzf: [f]ind [f]iles' },
+ {
+ 'ff',
+ function()
+ -- In a git repo: use git ls-files so tracked hidden files appear.
+ -- Outside a git repo: fall back to regular files picker.
+ local ok = vim.fn.systemlist(
+ 'git rev-parse --is-inside-work-tree 2>/dev/null'
+ )[1]
+ if ok == 'true' then
+ require('fzf-lua').git_files({ show_untracked = true })
+ else
+ require('fzf-lua').files()
+ end
+ end,
+ desc = 'fzf: [f]ind [f]iles',
+ },
{
'fb',
'FzfLua grep_curbuf',
diff --git a/files/.config/nvim/lua/custom/plugins/gaming.lua b/files/.config/nvim/lua/custom/plugins/gaming.lua
new file mode 100644
index 00000000..6c4fa7a0
--- /dev/null
+++ b/files/.config/nvim/lua/custom/plugins/gaming.lua
@@ -0,0 +1,4 @@
+return {
+
+ { 'meznaric/key-analyzer.nvim', opts = {}, cmd = 'KeyAnalyzer' },
+}
diff --git a/files/.config/nvim/lua/custom/plugins/git.lua b/files/.config/nvim/lua/custom/plugins/git.lua
index 8c52d60d..c1487251 100644
--- a/files/.config/nvim/lua/custom/plugins/git.lua
+++ b/files/.config/nvim/lua/custom/plugins/git.lua
@@ -1,29 +1,11 @@
-local icons = mrl.ui.icons.separators
+local T = require('tools')
+local icons = require('tools').ui.icons.separators
-local gitlinker = mrl.require_for_later_index('gitlinker')
+local gitlinker = T.require_for_later_index('gitlinker')
local function browser_open()
return { action_callback = require('gitlinker.actions').open_in_browser }
end
-local function check_main_or_develop_branch()
- local main_exists =
- vim.fn.system('git show-ref --verify --quiet refs/heads/main')
- if vim.v.shell_error == 0 then
- print('Main branch exists.')
- return 'main'
- end
-
- local develop_exists =
- vim.fn.system('git show-ref --verify --quiet refs/heads/develop')
- if vim.v.shell_error == 0 then
- print('Develop branch exists.')
- return 'develop'
- end
-
- print('Neither main nor develop branch exists.')
- return nil
-end
-
return {
-----------------------------------------------------------------------------
-- git signs {{{
@@ -215,15 +197,64 @@ return {
-- }}}
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
+ -- git-conflict {{{
+ -----------------------------------------------------------------------------
+ {
+ 'akinsho/git-conflict.nvim',
+ event = 'BufReadPre',
+ opts = {
+ default_mappings = true,
+ default_commands = true,
+ disable_diagnostics = true,
+ list_opener = 'copen',
+ highlights = {
+ incoming = 'DiffAdd',
+ current = 'DiffText',
+ },
+ },
+ },
+ -- }}}
+ -----------------------------------------------------------------------------
+ -----------------------------------------------------------------------------
-- fugitive {{{
-----------------------------------------------------------------------------
{
'tpope/vim-fugitive',
cmd = { 'Git' },
+ event = 'BufReadPre',
+ init = function()
+ vim.api.nvim_create_autocmd('DirChanged', {
+ group = vim.api.nvim_create_augroup('FugitiveWorktreeDetect', { clear = true }),
+ callback = function()
+ vim.fn.FugitiveDetect(vim.fn.getcwd())
+ end,
+ })
+ end,
keys = {
{
'gs',
- 'Git',
+ function()
+ -- FugitiveCommonDir returns the shared .bare dir for all worktrees of the same repo
+ local cur_common = vim.fn.FugitiveCommonDir(vim.api.nvim_get_current_buf())
+ if cur_common == '' then
+ vim.cmd('tab Git')
+ return
+ end
+ for _, tabnr in ipairs(vim.api.nvim_list_tabpages()) do
+ for _, winnr in ipairs(vim.api.nvim_tabpage_list_wins(tabnr)) do
+ local buf = vim.api.nvim_win_get_buf(winnr)
+ local name = vim.api.nvim_buf_get_name(buf)
+ if name:match('^fugitive://') then
+ local tab_common = vim.fn.FugitiveCommonDir(buf)
+ if tab_common ~= '' and tab_common == cur_common then
+ vim.api.nvim_set_current_tabpage(tabnr)
+ return
+ end
+ end
+ end
+ end
+ vim.cmd('tab Git')
+ end,
desc = '[git] Status',
mode = 'n',
},
@@ -304,7 +335,6 @@ return {
{
'sindrets/diffview.nvim',
cmd = { 'DiffviewOpen', 'DiffviewClose', 'DiffviewToggleFiles' },
- -- diff3_mixed
opts = {
enhanced_diff_hl = true,
signs = {
@@ -313,9 +343,7 @@ return {
done = '✓',
},
view = {
- merge_tool = {
- layout = 'diff3_mixed',
- },
+ merge_tool = { layout = 'diff3_mixed' },
},
},
},
@@ -370,32 +398,6 @@ return {
config = function() require('litee.gh').setup() end,
},
- {
- 'jecaro/fugitive-difftool.nvim',
- dependencies = { 'tpope/vim-fugitive' },
- keys = {
- {
- 'gPR',
- function()
- current_branch = vim.fn.system('git rev-parse --abbrev-ref HEAD')
- current_branch = current_branch:gsub('%s+', '')
- target_branch = check_main_or_develop_branch()
-
- -- print('Current branch: ' .. current_branch)
- -- print('Target branch: ' .. target_branch)
-
- print(
- 'Git! difftool --name-status '
- .. target_branch
- .. '...'
- .. current_branch
- )
- end,
- desc = 'dddd',
- },
- },
- },
-
-- }}}
{
@@ -411,6 +413,122 @@ return {
'GitWorktreeList',
'GitWorktreeSwitch',
},
+ keys = {
+ {
+ 'gwl',
+ function()
+ require('fzf-lua').fzf_exec(function(cb)
+ local lines = vim.fn.systemlist('git worktree list --porcelain')
+ local worktrees = {}
+ local cur = {}
+ for _, line in ipairs(lines) do
+ local path = line:match('^worktree (.+)')
+ local branch = line:match('^branch refs/heads/(.+)')
+ if path then cur = { path = path } end
+ if branch then cur.branch = branch end
+ if line == '' and cur.path then
+ table.insert(worktrees, cur)
+ cur = {}
+ end
+ end
+ if cur.path then table.insert(worktrees, cur) end
+ for _, wt_entry in ipairs(worktrees) do
+ cb(string.format('%s\t%s', wt_entry.branch or '(detached)', wt_entry.path))
+ end
+ cb(nil)
+ end, {
+ prompt = 'Worktrees> ',
+ actions = {
+ ['default'] = function(selected)
+ local path = selected[1]:match('\t(.+)$')
+ if path then
+ require('git-worktree').switch_worktree(path)
+ end
+ end,
+ },
+ })
+ end,
+ desc = '[git] List/switch worktree',
+ },
+ {
+ 'gwd',
+ function()
+ require('fzf-lua').fzf_exec(function(cb)
+ local lines = vim.fn.systemlist('git worktree list --porcelain')
+ local worktrees = {}
+ local cur = {}
+ for _, line in ipairs(lines) do
+ local path = line:match('^worktree (.+)')
+ local branch = line:match('^branch refs/heads/(.+)')
+ if path then cur = { path = path } end
+ if branch then cur.branch = branch end
+ if line == '' and cur.path then
+ table.insert(worktrees, cur)
+ cur = {}
+ end
+ end
+ if cur.path then table.insert(worktrees, cur) end
+ -- skip the main worktree (first entry)
+ for i, wt_entry in ipairs(worktrees) do
+ if i > 1 then
+ cb(string.format('%s\t%s', wt_entry.branch or '(detached)', wt_entry.path))
+ end
+ end
+ cb(nil)
+ end, {
+ prompt = 'Delete worktree> ',
+ fzf_opts = { ['--header'] = 'CTRL-D: force delete branch | ENTER: remove worktree only' },
+ actions = {
+ ['default'] = function(selected)
+ local path = selected[1]:match('\t(.+)$')
+ if not path then return end
+ vim.ui.input(
+ { prompt = 'Flags ([-f] [-d|-D], or enter to confirm): ' },
+ function(flags)
+ if flags == nil then return end -- cancelled
+ local cmd = 'gwrm ' .. (flags ~= '' and flags .. ' ' or '') .. vim.fn.shellescape(path)
+ local out = vim.fn.system(cmd)
+ if vim.v.shell_error ~= 0 then
+ vim.notify(out, vim.log.levels.ERROR)
+ else
+ vim.notify('Removed worktree: ' .. path)
+ end
+ end
+ )
+ end,
+ },
+ })
+ end,
+ desc = '[git] Delete worktree',
+ },
+ {
+ 'gwc',
+ function()
+ vim.ui.input({ prompt = 'New branch name: ' }, function(branch)
+ if not branch or branch == '' then return end
+ vim.ui.input(
+ { prompt = 'Path (default: ' .. branch .. '): ' },
+ function(path)
+ path = (path and path ~= '') and path or branch
+ vim.ui.input({ prompt = 'Base branch (default: HEAD): ' }, function(base)
+ base = (base and base ~= '') and base or 'HEAD'
+ require('git-worktree').create_worktree(path, branch, base)
+ end)
+ end
+ )
+ end)
+ end,
+ desc = '[git] Create worktree',
+ },
+ },
+ config = function()
+ require('git-worktree').setup()
+ require('git-worktree').on_tree_change(function(op, metadata)
+ if op == require('git-worktree').Operations.Switch then
+ vim.fn.FugitiveDetect(metadata.path)
+ end
+ end)
+ end,
},
}
diff --git a/files/.config/nvim/lua/custom/plugins/init.lua b/files/.config/nvim/lua/custom/plugins/init.lua
index 356d7824..40b13124 100644
--- a/files/.config/nvim/lua/custom/plugins/init.lua
+++ b/files/.config/nvim/lua/custom/plugins/init.lua
@@ -43,52 +43,12 @@ return {
},
},
- {
- 'noahfrederick/vim-skeleton',
- event = 'BufNewFile',
- config = function()
- vim.g.skeleton_template_dir = vim.fn.expand('~/.config/nvim')
- .. '/templates'
- vim.cmd([[
- let g:skeleton_replacements = {}
- function! g:skeleton_replacements.TITLE()
- return toupper(expand("%:t:r"))
- endfunction
- ]])
- end,
- },
-
- {
- 'rlch/github-notifications.nvim',
- dependencies = { 'nvim-lua/plenary.nvim', 'ibhagwan/fzf-lua' },
- keys = {
- {
- 'gn',
- function() require('custom.gh_notifications').open() end,
- desc = 'github notifications (fzf)',
- },
- },
- },
-
- {
- 'szw/vim-maximizer',
- keys = {
- {
- 'sm',
- 'MaximizerToggle',
- desc = '[win] Split Maximize/minimize',
- },
- },
- },
-
{
'marromlam/sailor.vim',
event = 'VimEnter',
run = './install.sh',
},
- { 'meznaric/key-analyzer.nvim', opts = {}, cmd = 'KeyAnalyzer' },
-
{
'bogado/file-line',
keys = {
@@ -101,6 +61,14 @@ return {
cmd = { 'DirDiff' },
},
- --- }}}
- ------------------------------------------------------------------------
+ {
+ 'tpope/vim-sleuth',
+ event = { 'BufReadPre', 'BufNewFile' },
+ },
+ { 'tpope/vim-surround', event = { 'BufReadPre', 'BufNewFile' } },
+
+ {
+ 'tpope/vim-repeat',
+ keys = { '.' },
+ },
}
diff --git a/files/.config/nvim/lua/custom/plugins/lazydev.lua b/files/.config/nvim/lua/custom/plugins/lazydev.lua
deleted file mode 100644
index 2108f7af..00000000
--- a/files/.config/nvim/lua/custom/plugins/lazydev.lua
+++ /dev/null
@@ -1,34 +0,0 @@
-return {
- 'folke/lazydev.nvim',
- ft = 'lua', -- only load on lua files
- opts = {
- library = {
- -- Library paths can be absolute
- -- "~/projects/my-awesome-lib",
- -- Or relative, which means they will be resolved from the plugin dir.
- -- "lazy.nvim",
- -- It can also be a table with trigger words / mods
- -- Only load luvit types when the `vim.uv` word is found
- { path = '${3rd}/luv/library', words = { 'vim%.uv' } },
- -- always load the LazyVim library
- 'LazyVim',
- -- Only load the lazyvim library when the `LazyVim` global is found
- { path = 'LazyVim', words = { 'LazyVim' } },
- -- Load the wezterm types when the `wezterm` module is required
- -- Needs `justinsgithub/wezterm-types` to be installed
- { path = 'wezterm-types', mods = { 'wezterm' } },
- -- Load the xmake types when opening file named `xmake.lua`
- -- Needs `LelouchHe/xmake-luals-addon` to be installed
- { path = 'xmake-luals-addon/library', files = { 'xmake.lua' } },
- },
- -- always enable unless `vim.g.lazydev_enabled = false`
- -- This is the default
- enabled = function(root_dir)
- return vim.g.lazydev_enabled == nil and true or vim.g.lazydev_enabled
- end,
- -- disable when a .luarc.json file is found
- enabled = function(root_dir)
- return not vim.uv.fs_stat(root_dir .. '/.luarc.json')
- end,
- },
-}
diff --git a/files/.config/nvim/lua/custom/plugins/linting.lua b/files/.config/nvim/lua/custom/plugins/linting.lua
index 50314d8f..899c1633 100644
--- a/files/.config/nvim/lua/custom/plugins/linting.lua
+++ b/files/.config/nvim/lua/custom/plugins/linting.lua
@@ -1,6 +1,6 @@
return {
'mfussenegger/nvim-lint',
- events = { 'BufWritePost', 'BufReadPost', 'InsertLeave', 'LspAttach' },
+ event = { 'BufWritePost', 'BufReadPost', 'InsertLeave', 'LspAttach' },
keys = {
{
'll',
diff --git a/files/.config/nvim/lua/custom/plugins/lsp.lua b/files/.config/nvim/lua/custom/plugins/lsp.lua
index 38b88645..570d02f5 100644
--- a/files/.config/nvim/lua/custom/plugins/lsp.lua
+++ b/files/.config/nvim/lua/custom/plugins/lsp.lua
@@ -1,5 +1,3 @@
-local icons = mrl.ui.icons.lsp
-
return { -- LSP Configuration & Plugins
{
'neovim/nvim-lspconfig',
@@ -16,23 +14,7 @@ return { -- LSP Configuration & Plugins
backdrop = 100, -- 100 = fully transparent (no dimming), 0 = fully opaque
},
},
- config = function(_, opts)
- require('mason').setup(opts)
- -- Disable columns in Mason windows after setup
- vim.api.nvim_create_autocmd('FileType', {
- pattern = 'mason',
- callback = function()
- vim.schedule(function()
- local win = vim.api.nvim_get_current_win()
- vim.wo[win].statuscolumn = ''
- vim.wo[win].signcolumn = 'no'
- vim.wo[win].foldcolumn = '0'
- vim.wo[win].number = false
- vim.wo[win].relativenumber = false
- end)
- end,
- })
- end,
+ config = function(_, opts) require('mason').setup(opts) end,
},
{ 'mason-org/mason-lspconfig.nvim', opts = {} },
{ 'WhoIsSethDaniel/mason-tool-installer.nvim', opts = {} },
@@ -40,7 +22,20 @@ return { -- LSP Configuration & Plugins
-- Useful status updates for LSP.
-- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})`
{ 'j-hui/fidget.nvim', opts = {} },
- { 'folke/lazydev.nvim' },
+ {
+ 'folke/lazydev.nvim',
+ ft = 'lua',
+ opts = {
+ library = {
+ { path = '${3rd}/luv/library', words = { 'vim%.uv' } },
+ { path = 'wezterm-types', mods = { 'wezterm' } },
+ },
+ enabled = function(root_dir)
+ return (vim.g.lazydev_enabled == nil or vim.g.lazydev_enabled)
+ and not vim.uv.fs_stat(root_dir .. '/.luarc.json')
+ end,
+ },
+ },
{
'stevanmilic/nvim-lspimport',
},
@@ -187,6 +182,7 @@ return { -- LSP Configuration & Plugins
-- code, if the language server you are using supports them
--
-- This may be unwanted, since they displace some of your code
+ local client = vim.lsp.get_client_by_id(event.data.client_id)
if
client
and client.server_capabilities.inlayHintProvider
@@ -310,10 +306,25 @@ return { -- LSP Configuration & Plugins
-- 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
+ -- Lua
+ 'stylua',
+ -- Python
+ 'black',
+ 'isort',
'flake8',
'mypy',
- 'black',
+ -- Shell
+ 'shfmt',
+ -- JS/TS
+ 'prettier',
+ 'prettierd',
+ 'eslint_d',
+ -- Misc linters
+ 'hadolint',
+ 'jsonlint',
+ 'vale',
+ 'tflint',
+ -- Other
'sonarlint-language-server',
})
require('mason-tool-installer').setup({
diff --git a/files/.config/nvim/lua/custom/plugins/mini.lua b/files/.config/nvim/lua/custom/plugins/mini.lua
index d976c5e0..ba945b59 100644
--- a/files/.config/nvim/lua/custom/plugins/mini.lua
+++ b/files/.config/nvim/lua/custom/plugins/mini.lua
@@ -197,37 +197,6 @@ return { -- Collection of various small independent plugins/modules
},
-- Visual enhancements
- {
- 'echasnovski/mini.hipatterns',
- event = { 'BufReadPre', 'BufNewFile' },
- config = function()
- local hipatterns = require('mini.hipatterns')
- hipatterns.setup({
- highlighters = {
- -- Highlight standalone 'FIXME', 'HACK', 'TODO', 'NOTE'
- fixme = {
- pattern = '%f[%w]()FIXME()%f[%W]',
- group = 'MiniHipatternsFixme',
- },
- hack = {
- pattern = '%f[%w]()HACK()%f[%W]',
- group = 'MiniHipatternsHack',
- },
- todo = {
- pattern = '%f[%w]()TODO()%f[%W]',
- group = 'MiniHipatternsTodo',
- },
- note = {
- pattern = '%f[%w]()NOTE()%f[%W]',
- group = 'MiniHipatternsNote',
- },
-
- -- Highlight hex color strings (`#rrggbb`) using that color
- hex_color = hipatterns.gen_highlighter.hex_color(),
- },
- })
- end,
- },
{
'echasnovski/mini.indentscope',
enabled = false,
diff --git a/files/.config/nvim/lua/custom/plugins/navigation.lua b/files/.config/nvim/lua/custom/plugins/navigation.lua
index 3e825c34..759f51a3 100644
--- a/files/.config/nvim/lua/custom/plugins/navigation.lua
+++ b/files/.config/nvim/lua/custom/plugins/navigation.lua
@@ -1,124 +1,65 @@
return {
{
- 'tpope/vim-vinegar',
- keys = { '-' },
+ 'stevearc/oil.nvim',
+ lazy = true,
+ opts = {
+ default_file_explorer = true,
+ delete_to_trash = true,
+ skip_confirm_for_simple_edits = true,
+ view_options = {
+ show_hidden = true,
+ },
+ keymaps = {
+ [''] = false, -- don't shadow split navigation
+ [''] = false,
+ },
+ },
+ keys = {
+ { '-', 'Oil', desc = 'oil: open parent directory' },
+ },
},
{
- 'ThePrimeagen/harpoon',
- branch = 'harpoon2',
- dependencies = { 'nvim-lua/plenary.nvim' },
- -- dependencies = { 'nvim-lua/plenary.nvim', 'nvim-telescope/telescope.nvim' },
+ 'cbochs/grapple.nvim',
+ dependencies = { 'echasnovski/mini.icons' },
+ opts = {
+ scope = 'git',
+ },
keys = {
-
+ { 'm', 'Grapple tag', desc = 'grapple: tag file' },
+ {
+ '',
+ 'Grapple toggle_tags',
+ desc = 'grapple: open tags',
+ },
{
'1',
- function() require('harpoon'):list():select(1) end,
- 'Go to buffer 1',
+ 'Grapple select index=1',
+ desc = 'grapple: select 1',
},
{
'2',
- 'BufferLineGoToBuffer 2',
- 'Go to buffer 2',
+ 'Grapple select index=2',
+ desc = 'grapple: select 2',
},
{
'3',
- 'BufferLineGoToBuffer 3',
- 'Go to buffer 3',
+ 'Grapple select index=3',
+ desc = 'grapple: select 3',
},
{
'4',
- 'BufferLineGoToBuffer 4',
- 'Go to buffer 4',
+ 'Grapple select index=4',
+ desc = 'grapple: select 4',
},
{
'5',
- 'BufferLineGoToBuffer 5',
- 'Go to buffer 5',
- },
- {
- '6',
- 'BufferLineGoToBuffer 6',
- 'Go to buffer 6',
- },
- {
- '7',
- 'BufferLineGoToBuffer 7',
- 'Go to buffer 7',
- },
- {
- '8',
- 'BufferLineGoToBuffer 8',
- 'Go to buffer 8',
- },
- {
- '9',
- 'BufferLineGoToBuffer 9',
- 'Go to buffer 9',
- },
- {
- '0',
- 'BufferLineGoToBuffer 10',
- 'Go to buffer 10',
+ 'Grapple select index=5',
+ desc = 'grapple: select 5',
},
+ { '[g', 'Grapple cycle_tags prev', desc = 'grapple: prev tag' },
+ { ']g', 'Grapple cycle_tags next', desc = 'grapple: next tag' },
},
- config = function()
- local harpoon = require('harpoon')
- harpoon:setup({})
-
- -- basic telescope configuration
- local function toggle_telescope(harpoon_files)
- local file_paths = {}
- for _, item in ipairs(harpoon_files.items) do
- table.insert(file_paths, item.value)
- end
-
- -- require('telescope.pickers')
- -- .new({}, {
- -- prompt_title = 'Harpoon',
- -- finder = require('telescope.finders').new_table({
- -- results = file_paths,
- -- }),
- -- previewer = conf.file_previewer({}),
- -- sorter = conf.generic_sorter({}),
- -- })
- -- :find()
- print(vim.inspect(file_paths))
- require('fzf-lua').buffers(file_paths, {
- winopts = {
- title = 'Harpoon',
- height = 0.33,
- row = 0.5,
- },
- previewer = false,
- actions = {
- ['default'] = function(selected)
- local session = vim.iter(file_paths):find(
- function(s) return s.name == selected[1] end
- )
- if not session then return end
- -- persisted.load({ session = session.file_path })
- end,
- ['ctrl-d'] = {
- function(selected)
- local session = vim.iter(file_paths):find(
- function(s) return s.name == selected[1] end
- )
- if not session then return end
- vim.fn.delete(vim.fn.expand(session.file_path))
- end,
- },
- },
- })
- end
-
- vim.keymap.set(
- 'n',
- '',
- function() toggle_telescope(harpoon:list()) end,
- { desc = 'Open harpoon window' }
- )
- end,
},
}
diff --git a/files/.config/nvim/lua/custom/plugins/neotree.lua b/files/.config/nvim/lua/custom/plugins/neotree.lua
index 9364d5ba..e3bea761 100644
--- a/files/.config/nvim/lua/custom/plugins/neotree.lua
+++ b/files/.config/nvim/lua/custom/plugins/neotree.lua
@@ -1,8 +1,8 @@
-- Neo-tree is a Neovim plugin to browse the file system
-- https://github.com/nvim-neo-tree/neo-tree.nvim
local fn, api = vim.fn, vim.api
-local highlight = mrl.highlight
-local icons = mrl.ui.icons
+local highlight = require('highlight')
+local icons = require('tools').ui.icons
local autocmd = api.nvim_create_autocmd
return {
@@ -52,7 +52,7 @@ return {
-- end,
config = function()
local symbols = require('lspkind').symbol_map
- local lsp_kinds = mrl.ui.lsp.highlights
+ local lsp_kinds = require('tools').ui.lsp.highlights
require('neo-tree').setup({
window = {
diff --git a/files/.config/nvim/lua/custom/plugins/noice.lua b/files/.config/nvim/lua/custom/plugins/noice.lua
index 6e05ce0d..819c4b29 100644
--- a/files/.config/nvim/lua/custom/plugins/noice.lua
+++ b/files/.config/nvim/lua/custom/plugins/noice.lua
@@ -1,5 +1,5 @@
local fn = vim.fn
-local highlight, L = mrl.highlight, vim.log.levels
+local L = vim.log.levels
return {
'folke/noice.nvim',
@@ -202,6 +202,13 @@ return {
},
opts = { skip = true },
})
+ table.insert(opts.routes, {
+ filter = {
+ event = 'msg_show',
+ find = 'client%.notify is deprecated',
+ },
+ opts = { skip = true },
+ })
-- Focus-aware notifications (send to notify_send when not focused)
local focused = true
diff --git a/files/.config/nvim/lua/custom/plugins/terminal.lua b/files/.config/nvim/lua/custom/plugins/terminal.lua
index 55330d1f..0b1d34ab 100644
--- a/files/.config/nvim/lua/custom/plugins/terminal.lua
+++ b/files/.config/nvim/lua/custom/plugins/terminal.lua
@@ -1,3 +1,6 @@
+local T = require('tools')
+local map = vim.keymap.set
+
return {
'akinsho/toggleterm.nvim',
cmd = { 'ToggleTerm', 'ToggleTermOpenAll', 'ToggleTermCloseAll' },
@@ -31,7 +34,7 @@ return {
require('toggleterm').setup(opts)
local float_handler = function(term)
- if not mrl.falsy(vim.fn.mapcheck('jk', 't')) then
+ if not T.falsy(vim.fn.mapcheck('jk', 't')) then
vim.keymap.del('t', 'jk', { buffer = term.bufnr })
vim.keymap.del('t', '', { buffer = term.bufnr })
end
@@ -86,6 +89,6 @@ return {
map('n', 'ld', function() lazydocker:toggle() end, {
desc = 'toggleterm: toggle lazydocker',
})
- mrl.command('Btop', function() btop:toggle() end)
+ T.command('Btop', function() btop:toggle() end)
end,
}
diff --git a/files/.config/nvim/lua/custom/plugins/todo.lua b/files/.config/nvim/lua/custom/plugins/todo.lua
index 01f24cb4..df1653e9 100644
--- a/files/.config/nvim/lua/custom/plugins/todo.lua
+++ b/files/.config/nvim/lua/custom/plugins/todo.lua
@@ -25,33 +25,34 @@ return {
'folke/trouble.nvim',
dependencies = { 'folke/todo-comments.nvim' },
cmd = { 'Trouble' },
+ opts = {},
keys = {
{
'xx',
- 'Trouble',
- desc = 'Open/close trouble list',
- },
- {
- 'xw',
- 'TroubleToggle workspace_diagnostics',
- desc = 'Open trouble workspace diagnostics',
+ 'Trouble diagnostics toggle',
+ desc = 'trouble: workspace diagnostics',
},
{
'xd',
- 'TroubleToggle document_diagnostics',
- desc = 'Open trouble document diagnostics',
+ 'Trouble diagnostics toggle filter.buf=0',
+ desc = 'trouble: document diagnostics',
},
{
'xq',
- 'TroubleToggle quickfix',
- desc = 'Open trouble quickfix list',
+ 'Trouble qflist toggle',
+ desc = 'trouble: quickfix list',
},
{
'xl',
- 'TroubleToggle loclist',
- desc = 'Open trouble location list',
+ 'Trouble loclist toggle',
+ desc = 'trouble: location list',
+ },
+ {
+ 'xs',
+ 'Trouble symbols toggle',
+ desc = 'trouble: document symbols',
},
- { 'xt', 'TodoTrouble', desc = 'Open todos in trouble' },
+ { 'xt', 'Trouble todo toggle', desc = 'trouble: todos' },
},
},
}
diff --git a/files/.config/nvim/lua/custom/plugins/tpope.lua b/files/.config/nvim/lua/custom/plugins/tpope.lua
deleted file mode 100644
index d688a366..00000000
--- a/files/.config/nvim/lua/custom/plugins/tpope.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-return {
- {
- 'tpope/vim-sleuth',
- event = { 'BufReadPre', 'BufNewFile' },
- },
- { 'tpope/vim-surround', event = { 'BufReadPre', 'BufNewFile' } },
-
- {
- 'tpope/vim-repeat',
- keys = { '.' },
- },
-}
diff --git a/files/.config/nvim/lua/custom/plugins/treesitter.lua b/files/.config/nvim/lua/custom/plugins/treesitter.lua
index 401c0474..6d3563b8 100644
--- a/files/.config/nvim/lua/custom/plugins/treesitter.lua
+++ b/files/.config/nvim/lua/custom/plugins/treesitter.lua
@@ -1,3 +1,4 @@
+-- DONE
return {
{
'nvim-treesitter/nvim-treesitter',
@@ -18,8 +19,7 @@ return {
},
auto_install = true,
highlight = {
- -- enable = true,
- enable = false,
+ enable = true,
disable = { 'tex', 'latex', 'applescript' },
-- Some languages depend on vim's regex highlighting system (such as Ruby) for indent rules.
-- If you are experiencing weird indenting issues, add the language to
@@ -142,7 +142,7 @@ return {
'nvim-treesitter/nvim-treesitter-context',
event = { 'BufReadPost', 'BufNewFile' },
init = function()
- local highlight = mrl.highlight
+ local highlight = require('highlight')
highlight.plugin('treesitter-context', {
{ TreesitterContextSeparator = { link = 'Dim' } },
{ TreesitterContext = { inherit = 'Normal' } },
@@ -150,9 +150,17 @@ return {
})
end,
opts = {
- multiline_threshold = 4,
+ enable = false,
+ multiline_threshold = 10,
separator = '─',
mode = 'cursor',
},
+ keys = {
+ {
+ 'sc',
+ 'TSContext toggle',
+ desc = 'Toggle [s]cope [c]ontext',
+ },
+ },
},
}
diff --git a/files/.config/nvim/lua/custom/plugins/ui.lua b/files/.config/nvim/lua/custom/plugins/ui.lua
index b59a5ce8..00a37684 100644
--- a/files/.config/nvim/lua/custom/plugins/ui.lua
+++ b/files/.config/nvim/lua/custom/plugins/ui.lua
@@ -1,4 +1,5 @@
-local icons = mrl.ui.icons
+local UI = require('tools').ui
+local icons = UI.icons
return {
{
'lukas-reineke/indent-blankline.nvim',
@@ -41,7 +42,7 @@ return {
local incline = require('incline')
local function set_hls()
- local pal = mrl.ui.palette or {}
+ local pal = UI.palette or {}
local bg = '#121212'
vim.api.nvim_set_hl(0, 'InclineNormal', {
fg = pal.whitesmoke or 'NONE',
@@ -111,7 +112,7 @@ return {
local buf = props.buf
local ft = vim.bo[buf].ft
local bt = vim.bo[buf].bt
- local decor = mrl.ui.decorations.get({
+ local decor = UI.decorations.get({
ft = ft,
bt = bt,
setting = 'winbar',
@@ -167,7 +168,7 @@ return {
local ccc = require('ccc')
local p = ccc.picker
ccc.setup({
- -- win_opts = { border = mrl.ui.border },
+ -- win_opts = { border = UI.border },
highlighter = {
auto_enable = false,
excludes = {
@@ -289,7 +290,7 @@ return {
api.nvim_create_augroup('MrlRainbowDelimiters', { clear = true })
local function set_hls()
- local pal = (mrl and mrl.ui and mrl.ui.palette) or {}
+ local pal = UI.palette or {}
local function as_hex(v, fallback)
if type(v) == 'string' or type(v) == 'number' then return v end
if type(v) == 'table' then return v.base or fallback end
diff --git a/files/.config/nvim/lua/custom/plugins/whichkey.lua b/files/.config/nvim/lua/custom/plugins/whichkey.lua
index c4a734c8..bd59258b 100644
--- a/files/.config/nvim/lua/custom/plugins/whichkey.lua
+++ b/files/.config/nvim/lua/custom/plugins/whichkey.lua
@@ -5,9 +5,40 @@ return {
config = function()
local wk = require('which-key')
wk.setup({
- win = { border = false },
+ win = {
+ border = false,
+ wo = {
+ winhl = 'Normal:StatusLine,NormalFloat:StatusLine,FloatBorder:StatusLine',
+ },
+ },
layout = { align = 'center' },
-- preset = 'modern',
})
+
+ -- Sync all WhichKey highlight bg to StatusLine
+ local function sync_hls()
+ local bg =
+ vim.api.nvim_get_hl(0, { name = 'StatusLine', link = false }).bg
+ if not bg then return end
+ bg = ('#%06x'):format(bg)
+ for _, name in ipairs({
+ 'WhichKeyNormal',
+ 'WhichKey',
+ 'WhichKeyDesc',
+ 'WhichKeyGroup',
+ 'WhichKeySeparator',
+ 'WhichKeyValue',
+ 'WhichKeyBorder',
+ 'WhichKeyTitle',
+ }) do
+ local hl = vim.api.nvim_get_hl(0, { name = name, link = false })
+ hl.bg = bg
+ hl.ctermbg = nil
+ vim.api.nvim_set_hl(0, name, hl)
+ end
+ end
+
+ sync_hls()
+ vim.api.nvim_create_autocmd('ColorScheme', { callback = sync_hls })
end,
}
diff --git a/files/.config/nvim/lua/custom/strings.lua b/files/.config/nvim/lua/custom/strings.lua
deleted file mode 100644
index 70bc2537..00000000
--- a/files/.config/nvim/lua/custom/strings.lua
+++ /dev/null
@@ -1,258 +0,0 @@
--- FORMAT STRINGS
-
-local api, L = vim.api, vim.log.levels
-local fmt, falsy = string.format, mrl.falsy
-
----@alias StringComponent {component: string, length: integer, priority: integer}
-
-local M = {}
-
-local CLICK_END = '%X'
-
---------------------------------------------------------------------------------
--- Components {{{
---------------------------------------------------------------------------------
-
----@return StringComponent
-local function separator() return { component = '%=', length = 0, priority = 0 } end
-
----@param func_name string
----@param id string
----@return string
-local function get_click_start(func_name, id)
- if not id then
- vim.schedule(function()
- local msg =
- fmt('An ID is needed to enable click handler %s to work', func_name)
- vim.notify_once(msg, L.ERROR, { title = 'Statusline' })
- end)
- return ''
- end
- return ('%%%d@%s@'):format(id, func_name)
-end
-
---- Creates a spacer statusline component i.e. for padding
---- or to represent an empty component
---- @param size integer?
---- @param opts table?
---- @return ComponentOpts?
-function M.spacer(size, opts)
- opts = opts or {}
- local filler = opts.filler or ' '
- local priority = opts.priority or 0
- if not size or size < 1 then return end
- local spacer = string.rep(filler, size)
- return { { { spacer } }, priority = priority, before = '', after = '' }
-end
-
---- truncate with an ellipsis or if surrounded by quotes, replace contents of quotes with ellipsis
---- @param str string
---- @param max_size integer
---- @return string
-local function truncate_string(str, max_size)
- if not max_size or vim.api.nvim_strwidth(str) < max_size then return str end
- local match, count = str:gsub('([\'"]).*%1', '%1…%1')
- return count > 0 and match or str:sub(1, max_size - 1) .. '…'
-end
-
----@alias Chunks {[1]: string | number, [2]: string, max_size: integer?}[]
-
----@param chunks any
----@return Chunks?
-local function normalize_chunks(chunks)
- if type(chunks) ~= 'table' then return end
- if vim.islist(chunks) then return chunks end
-
- -- Allow "sparse arrays" like {[1]=..., [2]=..., [7]=...} by compacting them.
- local keys = {}
- for k, _ in pairs(chunks) do
- if type(k) == 'number' and k >= 1 and math.floor(k) == k then
- keys[#keys + 1] = k
- end
- end
- if #keys == 0 then return end
- table.sort(keys)
-
- local dense = {}
- for _, k in ipairs(keys) do
- local v = chunks[k]
- if v ~= nil then dense[#dense + 1] = v end
- end
- return dense
-end
-
----@param chunks Chunks
----@return string
-local function chunks_to_string(chunks)
- chunks = normalize_chunks(chunks)
- if not chunks then return '' end
-
- local strings = {}
- for _, item in ipairs(chunks) do
- local text, hl = unpack(item)
- if not falsy(text) then
- if type(text) ~= 'string' then text = tostring(text) end
- if item.max_size then text = truncate_string(text, item.max_size) end
- text = text:gsub('%%', '%%%1')
- strings[#strings + 1] =
- not falsy(hl) and ('%%#%s#%s%%*'):format(hl, text) or text
- end
- end
- return table.concat(strings, '')
-end
-
---- @class ComponentOpts
---- @field [1] Chunks
---- @field priority number
---- @field click string
---- @field before string
---- @field after string
---- @field id number
---- @field max_size integer
---- @field cond boolean | number | table | string,
-
---- @param opts ComponentOpts
---- @return StringComponent?
-local function component(opts)
- assert(opts, 'component options are required')
- if opts.cond ~= nil and falsy(opts.cond) then return end
-
- local item = normalize_chunks(opts[1])
- if not item then
- error(
- fmt(
- 'component options are required but got %s instead',
- vim.inspect(opts[1])
- )
- )
- end
-
- if not opts.priority then opts.priority = 10 end
- local before, after = '', ''
-
- local item_str = chunks_to_string(item)
- if vim.api.nvim_strwidth(item_str) == 0 then return end
-
- local click_start = opts.click
- and get_click_start(opts.click, tostring(opts.id))
- or ''
- local click_end = opts.click and CLICK_END or ''
- local component_str =
- table.concat({ click_start, before, item_str, after, click_end })
- return {
- component = component_str,
- length = api.nvim_eval_statusline(component_str, { maxwidth = 0 }).width,
- priority = opts.priority,
- }
-end
-
--- }}}
--------------------------------------------------------------------------------
-
--------------------------------------------------------------------------------
--- statusline render utils {{{
--------------------------------------------------------------------------------
-
-local function sum_lengths(list)
- return mrl.fold(
- function(acc, item) return acc + (item.length or 0) end,
- list,
- 0
- )
-end
-
-local function is_lowest(item, lowest)
- -- if there hasn't been a lowest selected so far, then the item is the
- -- lowest
- if not lowest or not lowest.length then return true end
- -- if the item doesn't have a priority or a length, it is likely a special
- -- character so should never be the lowest
- if not item.priority or not item.length then return false end
- -- if the item has the same priority as the lowest, then if the item has a
- -- greater length it should become the lowest
- if item.priority == lowest.priority then
- return item.length > lowest.length
- end
- return item.priority > lowest.priority
-end
-
---- Take the lowest priority items out of the statusline if we don't have
---- space for them.
---- Note: Currently this doesn't account for if an item that has a lower
---- priority could be fit in instead
---- @param statusline table
---- @param space number
---- @param length number
-local function prioritize(statusline, space, length)
- length = length or sum_lengths(statusline)
- if length <= space then return statusline end
- local lowest, index_to_remove
- for idx, c in ipairs(statusline) do
- if is_lowest(c, lowest) then
- lowest, index_to_remove = c, idx
- end
- end
- table.remove(statusline, index_to_remove)
- return prioritize(statusline, space, length - lowest.length)
-end
-
---- @param sections ComponentOpts[][]
---- @param available_space number?
---- @return string
-function M.display(sections, available_space)
- local components = mrl.fold(function(acc, section, count)
- if #section == 0 then
- table.insert(acc, separator())
- return acc
- end
- mrl.foreach(function(args, index)
- if not args then return end
- local ok, str = mrl.pcall('Error creating component', component, args)
- if not ok then return end
- table.insert(acc, str)
- if #section == index and count ~= #sections then
- table.insert(acc, separator())
- end
- end, section)
- return acc
- end, sections)
-
- local items = available_space and prioritize(components, available_space)
- or components
- local str = vim.tbl_map(function(item) return item.component end, items)
- return table.concat(str)
-end
-
---- A helper class that allow collecting `...StringComponent`
---- into sections that can then be added to each other
---- i.e.
---- ```lua
---- section1:new(1, 2, 3) + section2:new(4, 5, 6) + section3(7, 8, 9)
---- {1, 2, 3, 4, 5, 6, 7, 8, 9} -- <--
---- ```
----@class Section
----@field __add fun(l:Section, r:Section): StringComponent[]
----@field __index Section
----@field new fun(...:StringComponent[]): Section
-local section = {}
-function section:new(...)
- local o = { ... }
- self.__index = self
- self.__add = function(l, r)
- local rt = { unpack(l) }
- for _, v in ipairs(r) do
- rt[#rt + 1] = v
- end
- return rt
- end
- return setmetatable(o, self)
-end
-
-M.section = section
-
--- }}}
---------------------------------------------------------------------------------
-
-return M
-
--- vim:fdm=marker
diff --git a/files/.config/nvim/lua/custom/ui.lua b/files/.config/nvim/lua/custom/ui.lua
deleted file mode 100644
index d636e836..00000000
--- a/files/.config/nvim/lua/custom/ui.lua
+++ /dev/null
@@ -1,478 +0,0 @@
-----------------------------------------------------------------------------------------------------
--- Styles
-----------------------------------------------------------------------------------------------------
-
--- mrl.p_table is defined in tools.lua, which is loaded before this file in
--- init.lua
---
--- Theme palette (derived from active colorscheme).
--- NOTE: we mutate this table in-place so any modules that captured a reference
--- (e.g. `local P = mrl.ui.palette`) keep seeing updates after `:colorscheme`.
-mrl.ui.palette = mrl.ui.palette or {}
-
-local function hex_from_hl(name, attr, fallback)
- local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name, link = false })
- if not ok or not hl then return fallback end
- local v = hl[attr]
- if not v then return fallback end
- return ('#%06x'):format(v)
-end
-
-local function tint(color, percent)
- local ok = type(color) == 'string' and color:match('^#%x%x%x%x%x%x$')
- if not ok then return color end
- local r = tonumber(color:sub(2, 3), 16)
- local g = tonumber(color:sub(4, 5), 16)
- local b = tonumber(color:sub(6, 7), 16)
- local function blend(component)
- component = math.floor(component * (1 + percent))
- return math.min(math.max(component, 0), 255)
- end
- return ('#%02x%02x%02x'):format(blend(r), blend(g), blend(b))
-end
-
-local function get_nightfox_palette()
- local ok, nightfox_palette = pcall(require, 'nightfox.palette')
- if not ok or not nightfox_palette or not nightfox_palette.load then
- return nil
- end
- return nightfox_palette.load(vim.g.colors_name or 'carbonfox')
-end
-
--- Nightfox palette values can be "Color" objects (tables with `.base` and a
--- callable metatable). Normalize everything we store in `mrl.ui.palette` to a
--- hex string so other modules can safely use it.
-local function as_hex(v, fallback)
- if type(v) == 'string' then return v end
- if type(v) == 'number' then return ('#%06x'):format(v) end
- if type(v) == 'table' then
- if type(v.base) == 'string' then return v.base end
- if vim.is_callable(v) then
- local ok, res = pcall(v)
- if ok then
- if type(res) == 'string' then return res end
- if type(res) == 'number' then return ('#%06x'):format(res) end
- end
- end
- end
- return fallback
-end
-
---- Refresh palette from the active colorscheme.
-function mrl.ui.refresh_palette()
- -- Prior hardcoded palette as last-resort defaults
- local defaults = {
- green = '#98c379',
- dark_green = '#10B981',
- blue = '#82AAFE',
- dark_blue = '#4e88ff',
- bright_blue = '#51afef',
- teal = '#15AABF',
- pale_pink = '#b490c0',
- magenta = '#c678dd',
- -- "red" should track the theme's git-delete color (see derived.red below)
- red = '#E06C75',
- pale_red = '#E06C75',
- light_red = '#c43e1f',
- dark_red = '#be5046',
- dark_orange = '#FF922B',
- bright_yellow = '#FAB005',
- light_yellow = '#e5c07b',
- whitesmoke = '#9E9E9E',
- light_gray = '#626262',
- comment_grey = '#5c6370',
- grey = '#3E4556',
- }
-
- local pal = get_nightfox_palette()
- local derived = {}
-
- if pal then
- -- Nightfox palette naming (works across carbonfox/nightfox variants)
- derived.green = as_hex(pal.green, defaults.green)
- derived.blue = as_hex(pal.blue, defaults.blue)
- derived.teal = as_hex(pal.cyan or pal.teal, defaults.teal)
- derived.magenta = as_hex(pal.magenta, defaults.magenta)
- derived.pale_pink = as_hex(pal.pink or pal.magenta, defaults.pale_pink)
- derived.pale_red = as_hex(pal.red, defaults.pale_red)
- -- Prefer the actual GitSignsDelete highlight if available (theme-defined)
- derived.red = hex_from_hl('GitSignsDelete', 'fg', pal.red or defaults.red)
- derived.dark_orange = as_hex(pal.orange, defaults.dark_orange)
- derived.bright_yellow = as_hex(pal.yellow, defaults.bright_yellow)
- derived.light_yellow = as_hex(pal.yellow, defaults.light_yellow)
- derived.comment_grey = as_hex(pal.comment or pal.fg3, defaults.comment_grey)
- derived.whitesmoke = as_hex(pal.fg1 or pal.fg0, defaults.whitesmoke)
- derived.light_gray = as_hex(pal.fg3, defaults.light_gray)
- derived.grey = as_hex(pal.bg3 or pal.bg2, defaults.grey)
- else
- -- Generic fallback: derive from highlight groups
- derived.pale_red = hex_from_hl('DiagnosticError', 'fg', defaults.pale_red)
- derived.red =
- hex_from_hl('GitSignsDelete', 'fg', derived.pale_red or defaults.red)
- derived.dark_orange =
- hex_from_hl('DiagnosticWarn', 'fg', defaults.dark_orange)
- derived.teal = hex_from_hl('DiagnosticInfo', 'fg', defaults.teal)
- derived.bright_blue =
- hex_from_hl('DiagnosticHint', 'fg', defaults.bright_blue)
- derived.green = hex_from_hl('GitSignsAdd', 'fg', defaults.green)
- derived.blue = hex_from_hl('Function', 'fg', defaults.blue)
- derived.magenta = hex_from_hl('Statement', 'fg', defaults.magenta)
- derived.pale_pink = hex_from_hl('Special', 'fg', defaults.pale_pink)
- derived.bright_yellow =
- hex_from_hl('WarningMsg', 'fg', defaults.bright_yellow)
- derived.light_yellow = derived.bright_yellow
- derived.comment_grey = hex_from_hl('Comment', 'fg', defaults.comment_grey)
- derived.whitesmoke = hex_from_hl('Normal', 'fg', defaults.whitesmoke)
- derived.light_gray = tint(derived.comment_grey, 0.1)
- derived.grey = tint(hex_from_hl('Normal', 'bg', defaults.grey), 0.15)
- end
-
- derived.dark_green = tint(derived.green, -0.25)
- derived.dark_blue = tint(derived.blue, -0.25)
- derived.light_red = tint(derived.pale_red, -0.15)
- derived.dark_red = tint(derived.pale_red, -0.30)
-
- -- Write into the shared table in-place
- for k in pairs(mrl.ui.palette) do
- mrl.ui.palette[k] = nil
- end
- for k, v in pairs(defaults) do
- mrl.ui.palette[k] = derived[k] or v
- end
- for k, v in pairs(derived) do
- mrl.ui.palette[k] = v
- end
-
- -- Keep LSP colors in sync with the palette (if lsp table already exists)
- if mrl.ui.lsp and mrl.ui.lsp.colors then
- mrl.ui.lsp.colors.error = mrl.ui.palette.pale_red
- mrl.ui.lsp.colors.warn = mrl.ui.palette.dark_orange
- mrl.ui.lsp.colors.hint = mrl.ui.palette.bright_blue
- mrl.ui.lsp.colors.info = mrl.ui.palette.teal
- end
-end
-
--- Simplified border configuration - use "rounded" everywhere
--- This is the standard Neovim border style name that works with most plugins
-mrl.ui.border = 'rounded'
-
-mrl.ui.icons = {
- separators = {
- left_thin_block = '▏',
- right_thin_block = '▕',
- vert_bottom_half_block = '▄',
- vert_top_half_block = '▀',
- right_block = '🮉',
- -- right_block = "▕",
- light_shade_block = '░',
- right_chubby_block = '▓',
- },
- -- Unified scrollbar glyph (used by fzf-lua and other UIs).
- -- FULL BLOCK (U+2588) to match fzf-lua preview scrollbar look.
- scrollbar = '█',
- lsp = {
- error = '', -- '✗'
- warn = '', --
- info = '', -- ℹ
- hint = '', -- ⚑
- },
- git = {
- add = '', -- ' '', -- '',
- mod = '', -- '' --'',
- remove = '', --'', -- '',
- ignore = '', --'',
- rename = '', -- '',
- untracked = '', -- '',
- ignored = '', -- '',
- unstaged = '', --'',
- staged = '', --'',
- conflict = '',
- diff = '',
- repo = '',
- logo = '',
- branch = '', -- '',
- },
- documents = {
- file = '',
- files = '',
- folder = '',
- open_folder = '',
- },
- misc = {
- --
- plus = '',
- ellipsis = '…',
- up = '⇡',
- down = '⇣',
- line = '', -- 'ℓ'
- indent = 'Ξ',
- tab = '⇥',
- bug = '', -- ''
- question = '',
- clock = '',
- cmd = '⌘',
- lock = '',
- shaded_lock = '',
- circle = '',
- project = '',
- dashboard = '',
- history = '',
- comment = '',
- robot = '',
- copilot = '',
- lightbulb = '',
- search = '',
- code = '',
- telescope = '',
- gear = '',
- chat = '',
- package = '',
- list = '',
- sign_in = '',
- check = '',
- fire = '',
- note = '',
- bookmark = '',
- pencil = '', -- '',
- tools = '',
- arrow_right = '',
- caret_right = '',
- chevron_right = '',
- double_chevron_right = '»',
- table = '',
- calendar = '',
- -- block = "▌",
- block = '▏',
- clippy = '',
- puzzle = '',
- settings = '⚙',
- key = '',
- config = '',
- box = '',
- moon = '',
- source = '',
- sleep = '',
- rocket = '',
- task = '',
- runtime = '',
- },
-}
-mrl.ui.lsp = {
- colors = {
- error = mrl.ui.palette.pale_red,
- warn = mrl.ui.palette.dark_orange,
- hint = mrl.ui.palette.bright_blue,
- info = mrl.ui.palette.teal,
- },
- --- This is a mapping of LSP Kinds to highlight groups. LSP Kinds come via the LSP spec
- --- see: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#symbolKind
- highlights = {
- File = 'Directory',
- Snippet = 'Label',
- Text = '@string',
- Method = '@method',
- Function = '@function',
- Constructor = '@constructor',
- Field = '@field',
- Variable = '@variable',
- Module = '@namespace',
- Property = '@property',
- Unit = '@constant',
- Value = '@variable',
- Enum = '@type',
- Keyword = '@keyword',
- Reference = '@parameter.reference',
- Constant = '@constant',
- Struct = '@structure',
- Event = '@variable',
- Operator = '@operator',
- Namespace = '@namespace',
- Package = '@include',
- String = '@string',
- Number = '@number',
- Boolean = '@boolean',
- Array = '@repeat',
- Object = '@type',
- Key = '@field',
- Null = '@symbol',
- EnumMember = '@field',
- Class = '@lsp.type.class',
- Interface = '@lsp.type.interface',
- TypeParameter = '@lsp.type.parameter',
- },
-}
-
--- Keep palette synced to the active colorscheme.
-vim.api.nvim_create_autocmd({ 'ColorScheme' }, {
- group = vim.api.nvim_create_augroup('MrlUIPalette', { clear = true }),
- callback = function() mrl.ui.refresh_palette() end,
-})
-vim.schedule(mrl.ui.refresh_palette)
-
-----------------------------------------------------------------------------------------------------
--- UI Settings
-----------------------------------------------------------------------------------------------------
----@class Decorations {
----@field winbar 'ignore' | boolean
----@field number boolean
----@field statusline 'minimal' | boolean
----@field statuscolumn boolean
----@field colorcolumn boolean | string
-
----@alias DecorationType 'statuscolumn'|'winbar'|'statusline'|'number'|'colorcolumn'
-
----@class Decorations
-local Preset = {}
-
----@param o Decorations
-function Preset:new(o)
- assert(o, 'a preset must be defined')
- self.__index = self
- return setmetatable(o, self)
-end
-
---- WARNING: deep extend does not copy lua meta methods
-function Preset:with(o) return vim.tbl_deep_extend('force', self, o) end
-
----@type table
-local presets = {
- statusline_only = Preset:new({
- number = false,
- winbar = false,
- colorcolumn = false,
- statusline = true,
- statuscolumn = false,
- }),
- minimal_editing = Preset:new({
- number = false,
- winbar = true,
- colorcolumn = false,
- statusline = 'minimal',
- statuscolumn = false,
- }),
- tool_panel = Preset:new({
- number = false,
- winbar = false,
- colorcolumn = false,
- statusline = 'minimal',
- statuscolumn = false,
- }),
-}
-
-local commit_buffer =
- presets.minimal_editing:with({ colorcolumn = '50,72', winbar = false })
-
-local buftypes = {
- ['quickfix'] = presets.tool_panel,
- ['nofile'] = presets.tool_panel,
- ['nowrite'] = presets.tool_panel,
- ['acwrite'] = presets.tool_panel,
- ['terminal'] = presets.tool_panel,
- ['.*fugitive.*'] = presets.tool_panel,
-}
-
---- When searching through the filetypes table if a match can't be found then search
---- again but check if there is matching lua pattern. This is useful for filetypes for
---- plugins like Neogit which have a filetype of Neogit.
-local filetypes = mrl.p_table({
- ['startuptime'] = presets.tool_panel,
- ['checkhealth'] = presets.tool_panel,
- ['log'] = presets.tool_panel,
- ['help'] = presets.tool_panel,
- ['^copilot.*'] = presets.tool_panel,
- ['dbout'] = presets.tool_panel,
- ['dbui'] = presets.tool_panel,
- ['dapui'] = presets.tool_panel,
- ['minimap'] = presets.tool_panel,
- ['Trouble'] = presets.tool_panel,
- ['tsplayground'] = presets.tool_panel,
- ['list'] = presets.tool_panel,
- ['netrw'] = presets.tool_panel,
- ['flutter.*'] = presets.tool_panel,
- ['NvimTree'] = presets.tool_panel,
- ['undotree'] = presets.tool_panel,
- ['dap-repl'] = presets.tool_panel:with({ winbar = 'ignore' }),
- ['neo-tree'] = presets.tool_panel:with({ winbar = 'ignore' }),
- ['toggleterm'] = presets.tool_panel:with({ winbar = 'ignore' }),
- ['neotest.*'] = presets.tool_panel,
- ['^Neogit.*'] = presets.tool_panel,
- ['.*fugitive.*'] = presets.tool_panel,
- ['query'] = presets.tool_panel,
- ['DiffviewFiles'] = presets.tool_panel,
- ['DiffviewFileHistory'] = presets.tool_panel,
- ['mail'] = presets.statusline_only,
- ['noice'] = presets.statusline_only,
- ['diff'] = presets.statusline_only,
- ['qf'] = presets.statusline_only,
- ['alpha'] = presets.tool_panel:with({ statusline = false }),
- ['fugitive'] = presets.statusline_only,
- ['startify'] = presets.statusline_only,
- ['man'] = presets.minimal_editing,
- ['org'] = presets.minimal_editing:with({ winbar = false }),
- ['norg'] = presets.minimal_editing:with({ winbar = false }),
- ['orgagenda'] = presets.minimal_editing:with({ winbar = false }),
- ['markdown'] = presets.minimal_editing,
- ['himalaya'] = presets.minimal_editing,
- ['gitcommit'] = commit_buffer,
- ['NeogitCommitMessage'] = commit_buffer,
-})
-
-local filenames = mrl.p_table({
- ['option-window'] = presets.tool_panel,
-})
-
-mrl.ui.decorations = {}
-
----@alias ui.OptionValue (boolean | string)
-
----Get the mrl.ui setting for a particular filetype
----@param opts {ft: string?, bt: string?, fname: string?, setting: DecorationType}
----@return {ft: ui.OptionValue?, bt: ui.OptionValue?, fname: ui.OptionValue?}
-function mrl.ui.decorations.get(opts)
- local ft, bt, fname, setting = opts.ft, opts.bt, opts.fname, opts.setting
- if (not ft and not bt and not fname) or not setting then return nil end
- return {
- ft = ft and filetypes[ft] and filetypes[ft][setting],
- bt = bt and buftypes[bt] and buftypes[bt][setting],
- fname = fname and filenames[fname] and filenames[fname][setting],
- }
-end
-
----A helper to set the value of the colorcolumn option, to my preferences, this can be used
----in an autocommand to set the `vim.opt_local.colorcolumn` or by a plugin such as `virtcolumn.nvim`
----to set it's virtual column
----@param bufnr integer
----@param fn fun(virtcolumn: string)
-function mrl.ui.decorations.set_colorcolumn(bufnr, fn)
- local buf = vim.bo[bufnr]
- local decor = mrl.ui.decorations.get({
- ft = buf.ft,
- bt = buf.bt,
- setting = 'colorcolumn',
- })
- if buf.ft == '' or buf.bt ~= '' or decor.ft == false or decor.bt == false then
- return
- end
- local ccol = decor.ft or decor.bt or ''
- local virtcolumn = not mrl.falsy(ccol) and ccol or '+1'
- if vim.is_callable(fn) then fn(virtcolumn) end
-end
-
-----------------------------------------------------------------------------------------------------
-mrl.ui.current = {
- border = 'rounded', -- Global border style - use Neovim's built-in "rounded" style
- -- Float/popup background color source of truth.
- -- Kept as a function so it always matches the active colorscheme's Normal bg.
- float_bg = function()
- -- Prefer our highlight helper (returns hex)
- if mrl and mrl.highlight and mrl.highlight.get then
- return mrl.highlight.get('Normal', 'bg')
- end
-
- -- Fallback to Neovim API (also returns hex)
- local ok, hl =
- pcall(vim.api.nvim_get_hl, 0, { name = 'Normal', link = false })
- if ok and hl and hl.bg then return ('#%06x'):format(hl.bg) end
- return 'NONE'
- end,
-}
diff --git a/files/.config/nvim/lua/dracula-pro/colors.lua b/files/.config/nvim/lua/dracula-pro/colors.lua
index f9827dbd..a1729423 100644
--- a/files/.config/nvim/lua/dracula-pro/colors.lua
+++ b/files/.config/nvim/lua/dracula-pro/colors.lua
@@ -3,96 +3,96 @@
local M = {}
M.default = {
- none = "NONE",
+ none = 'NONE',
-- Base colors
- bg = "#22212C",
- bg_dark = "#010010",
- bg_darker = "#010010",
- bg_light = "#43414E",
- bg_highlight = "#43414E",
- bg_visual = "#454158",
- bg_search = "#43414E",
- bg_sidebar = "#010010",
- bg_statusline = "#010010",
- bg_float = "#43414E",
- bg_popup = "#43414E",
+ bg = '#22212C',
+ bg_dark = '#010010',
+ bg_darker = '#010010',
+ bg_light = '#43414E',
+ bg_highlight = '#43414E',
+ bg_visual = '#454158',
+ bg_search = '#43414E',
+ bg_sidebar = '#010010',
+ bg_statusline = '#010010',
+ bg_float = '#43414E',
+ bg_popup = '#43414E',
- fg = "#F8F8F2",
- fg_dark = "#CDCDC8",
- fg_gutter = "#504C67",
- fg_sidebar = "#F8F8F2",
- fg_float = "#F8F8F2",
+ fg = '#F8F8F2',
+ fg_dark = '#CDCDC8',
+ fg_gutter = '#504C67',
+ fg_sidebar = '#F8F8F2',
+ fg_float = '#F8F8F2',
-- Accent colors
- black = "#010010",
- border = "#504C67",
- border_highlight = "#9580FF",
- comment = "#7970A9",
+ black = '#010010',
+ border = '#504C67',
+ border_highlight = '#9580FF',
+ comment = '#7970A9',
-- Syntax colors
- red = "#FF9580",
- orange = "#FFFF80",
- yellow = "#FFFF80",
- green = "#8AFF80",
- cyan = "#80FFEA",
- blue = "#9580FF",
- blue0 = "#9580FF",
- blue1 = "#9580FF",
- blue2 = "#80FFEA",
- blue5 = "#FF80BF",
- blue6 = "#99FFEE",
- blue7 = "#9580FF",
- magenta = "#FF80BF",
- magenta2 = "#FF99CC",
- purple = "#FF80BF",
- teal = "#80FFEA",
- dark3 = "#CDCDC8",
- dark5 = "#CDCDC8",
- green1 = "#8AFF80",
- green2 = "#8AFF80",
- red1 = "#FF9580",
+ red = '#FF9580',
+ orange = '#FFFF80',
+ yellow = '#FFFF80',
+ green = '#8AFF80',
+ cyan = '#80FFEA',
+ blue = '#9580FF',
+ blue0 = '#9580FF',
+ blue1 = '#9580FF',
+ blue2 = '#80FFEA',
+ blue5 = '#FF80BF',
+ blue6 = '#99FFEE',
+ blue7 = '#9580FF',
+ magenta = '#FF80BF',
+ magenta2 = '#FF99CC',
+ purple = '#FF80BF',
+ teal = '#80FFEA',
+ dark3 = '#CDCDC8',
+ dark5 = '#CDCDC8',
+ green1 = '#8AFF80',
+ green2 = '#8AFF80',
+ red1 = '#FF9580',
-- Bright variants
- bright_red = "#FFAA99",
- bright_green = "#A2FF99",
- bright_yellow = "#FFFF99",
- bright_blue = "#AA99FF",
- bright_magenta = "#FF99CC",
- bright_cyan = "#99FFEE",
+ bright_red = '#FFAA99',
+ bright_green = '#A2FF99',
+ bright_yellow = '#FFFF99',
+ bright_blue = '#AA99FF',
+ bright_magenta = '#FF99CC',
+ bright_cyan = '#99FFEE',
-- Terminal colors
- terminal_black = "#22212C",
+ terminal_black = '#22212C',
-- Semantic syntax colors (for accurate theme reproduction)
- syntax_string = "#FFFF80",
- syntax_function = "#8AFF80",
- syntax_variable = "#F8F8F2",
- syntax_keyword = "#FF80BF",
- syntax_class = "#9580FF",
- syntax_constant = "#80FFEA",
+ syntax_string = '#FFFF80',
+ syntax_function = '#8AFF80',
+ syntax_variable = '#F8F8F2',
+ syntax_keyword = '#FF80BF',
+ syntax_class = '#9580FF',
+ syntax_constant = '#80FFEA',
-- Diagnostic colors
- error = "#FF9580",
- warning = "#FFFF80",
- info = "#80FFEA",
- hint = "#504C67",
- todo = "#9580FF",
+ error = '#FF9580',
+ warning = '#FFFF80',
+ info = '#80FFEA',
+ hint = '#504C67',
+ todo = '#9580FF',
-- Git colors
git = {
- add = "#8AFF80",
- change = "#FFFF80",
- delete = "#FF9580",
- ignore = "#504C67",
+ add = '#8AFF80',
+ change = '#FFFF80',
+ delete = '#FF9580',
+ ignore = '#504C67',
},
-- Diff colors
diff = {
- add = "#5DD458",
- delete = "#D16D5B",
- change = "#D3D457",
- text = "#FFFF80",
+ add = '#5DD458',
+ delete = '#D16D5B',
+ change = '#D3D457',
+ text = '#FFFF80',
},
}
diff --git a/files/.config/nvim/lua/dracula-pro/config.lua b/files/.config/nvim/lua/dracula-pro/config.lua
index 72080476..3630fa55 100644
--- a/files/.config/nvim/lua/dracula-pro/config.lua
+++ b/files/.config/nvim/lua/dracula-pro/config.lua
@@ -17,7 +17,7 @@ M.defaults = {
M.options = {}
function M.setup(options)
- M.options = vim.tbl_deep_extend("force", {}, M.defaults, options or {})
+ M.options = vim.tbl_deep_extend('force', {}, M.defaults, options or {})
end
M.setup()
diff --git a/files/.config/nvim/lua/dracula-pro/groups/base.lua b/files/.config/nvim/lua/dracula-pro/groups/base.lua
index 29dcb9e9..abb57640 100644
--- a/files/.config/nvim/lua/dracula-pro/groups/base.lua
+++ b/files/.config/nvim/lua/dracula-pro/groups/base.lua
@@ -36,7 +36,12 @@ function M.get(c, opts)
MoreMsg = { fg = c.blue },
NonText = { fg = c.fg_dark },
Normal = { fg = c.fg, bg = opts.transparent and c.none or c.bg },
- NormalNC = { fg = c.fg, bg = opts.transparent and c.none or opts.dim_inactive and c.bg_dark or c.bg },
+ NormalNC = {
+ fg = c.fg,
+ bg = opts.transparent and c.none
+ or opts.dim_inactive and c.bg_dark
+ or c.bg,
+ },
NormalSB = { fg = c.fg_sidebar, bg = c.bg_sidebar },
NormalFloat = { fg = c.fg_float, bg = c.bg_float },
FloatBorder = { fg = c.border_highlight, bg = c.bg_float },
@@ -49,7 +54,7 @@ function M.get(c, opts)
QuickFixLine = { bg = c.bg_visual, bold = true },
Search = { bg = c.bg_search, fg = c.fg },
IncSearch = { bg = c.orange, fg = c.black },
- CurSearch = "IncSearch",
+ CurSearch = 'IncSearch',
SpecialKey = { fg = c.fg_dark },
SpellBad = { sp = c.error, undercurl = true },
SpellCap = { sp = c.warning, undercurl = true },
@@ -66,14 +71,14 @@ function M.get(c, opts)
WarningMsg = { fg = c.warning },
Whitespace = { fg = c.fg_gutter },
WildMenu = { bg = c.bg_visual },
- WinBar = "StatusLine",
- WinBarNC = "StatusLineNC",
+ WinBar = 'StatusLine',
+ WinBarNC = 'StatusLineNC',
Bold = { bold = true, fg = c.fg },
Character = { fg = c.syntax_string },
Constant = { fg = c.syntax_constant },
Debug = { fg = c.orange },
- Delimiter = "Special",
+ Delimiter = 'Special',
Error = { fg = c.error },
Function = { fg = c.syntax_function, style = opts.styles.functions },
Identifier = { fg = c.syntax_variable, style = opts.styles.variables },
diff --git a/files/.config/nvim/lua/dracula-pro/groups/plugins.lua b/files/.config/nvim/lua/dracula-pro/groups/plugins.lua
index 125545fe..72f7ccad 100644
--- a/files/.config/nvim/lua/dracula-pro/groups/plugins.lua
+++ b/files/.config/nvim/lua/dracula-pro/groups/plugins.lua
@@ -4,18 +4,18 @@ local M = {}
-- Helper function to tint colors (darken/brighten)
local function tint(color, percent)
- if not color or color == "NONE" then return "NONE" end
+ if not color or color == 'NONE' then return 'NONE' end
local r = tonumber(color:sub(2, 3), 16)
local g = tonumber(color:sub(4, 5), 16)
local b = tonumber(color:sub(6), 16)
- if not r or not g or not b then return "NONE" end
+ if not r or not g or not b then return 'NONE' end
local blend = function(component)
component = math.floor(component * (1 + percent))
return math.min(math.max(component, 0), 255)
end
- return string.format("#%02x%02x%02x", blend(r), blend(g), blend(b))
+ return string.format('#%02x%02x%02x', blend(r), blend(g), blend(b))
end
function M.get(c, opts)
@@ -35,40 +35,40 @@ function M.get(c, opts)
-- LSP Kind highlights (for completion items, breadcrumbs, etc.)
local lsp_kinds = {
- ["module"] = { fg = c.orange },
- ["snippet"] = { fg = c.purple },
- ["folder"] = { fg = c.fg },
- ["color"] = { fg = c.fg },
- ["file"] = "Directory",
- ["text"] = "@string",
- ["method"] = "@method",
- ["function"] = "@function",
- ["constructor"] = "@constructor",
- ["field"] = "@field",
- ["variable"] = "@variable",
- ["property"] = "@property",
- ["unit"] = "@constant",
- ["value"] = "@variable",
- ["enum"] = "@type",
- ["keyword"] = "@keyword",
- ["reference"] = "@parameter.reference",
- ["constant"] = "@constant",
- ["struct"] = "@structure",
- ["event"] = "@variable",
- ["operator"] = "@operator",
- ["namespace"] = "@namespace",
- ["package"] = "@include",
- ["string"] = "@string",
- ["number"] = "@number",
- ["boolean"] = "@boolean",
- ["array"] = "@repeat",
- ["object"] = "@type",
- ["key"] = "@field",
- ["null"] = "@symbol",
- ["enumMember"] = "@field",
- ["class"] = "@lsp.type.class",
- ["interface"] = "@lsp.type.interface",
- ["typeParameter"] = "@lsp.type.parameter",
+ ['module'] = { fg = c.orange },
+ ['snippet'] = { fg = c.purple },
+ ['folder'] = { fg = c.fg },
+ ['color'] = { fg = c.fg },
+ ['file'] = 'Directory',
+ ['text'] = '@string',
+ ['method'] = '@method',
+ ['function'] = '@function',
+ ['constructor'] = '@constructor',
+ ['field'] = '@field',
+ ['variable'] = '@variable',
+ ['property'] = '@property',
+ ['unit'] = '@constant',
+ ['value'] = '@variable',
+ ['enum'] = '@type',
+ ['keyword'] = '@keyword',
+ ['reference'] = '@parameter.reference',
+ ['constant'] = '@constant',
+ ['struct'] = '@structure',
+ ['event'] = '@variable',
+ ['operator'] = '@operator',
+ ['namespace'] = '@namespace',
+ ['package'] = '@include',
+ ['string'] = '@string',
+ ['number'] = '@number',
+ ['boolean'] = '@boolean',
+ ['array'] = '@repeat',
+ ['object'] = '@type',
+ ['key'] = '@field',
+ ['null'] = '@symbol',
+ ['enumMember'] = '@field',
+ ['class'] = '@lsp.type.class',
+ ['interface'] = '@lsp.type.interface',
+ ['typeParameter'] = '@lsp.type.parameter',
}
return {
@@ -87,9 +87,9 @@ function M.get(c, opts)
GitSignsChange = { fg = c.git.change },
GitSignsDelete = { fg = c.git.delete },
GitSignsUntracked = { fg = c.git.ignore },
- GitSignsAddInline = "DiffText",
- GitSignsChangeInline = "DiffChange",
- GitSignsDeleteInline = "DiffDelete",
+ GitSignsAddInline = 'DiffText',
+ GitSignsChangeInline = 'DiffChange',
+ GitSignsDeleteInline = 'DiffDelete',
-- Telescope
TelescopeSelection = { bg = custom.blue_bg },
@@ -126,11 +126,11 @@ function M.get(c, opts)
NvimTreeSymlink = { fg = c.blue },
NvimTreeRootFolder = { fg = c.fg, bold = true },
NvimTreeExecFile = { fg = c.green },
- NvimTreeLspDiagnosticsError = "DiagnosticError",
- NvimTreeLspDiagnosticsWarning = "DiagnosticWarn",
- NvimTreeLspDiagnosticsInformation = "DiagnosticInfo",
- NvimTreeLspDiagnosticsInfo = "DiagnosticInfo",
- NvimTreeLspDiagnosticsHint = "DiagnosticHint",
+ NvimTreeLspDiagnosticsError = 'DiagnosticError',
+ NvimTreeLspDiagnosticsWarning = 'DiagnosticWarn',
+ NvimTreeLspDiagnosticsInformation = 'DiagnosticInfo',
+ NvimTreeLspDiagnosticsInfo = 'DiagnosticInfo',
+ NvimTreeLspDiagnosticsHint = 'DiagnosticHint',
-- Neo-tree
NeoTreeFolderIcon = { fg = custom.gold },
@@ -185,69 +185,69 @@ function M.get(c, opts)
CmpItemAbbrMatch = { fg = c.blue, bold = true },
CmpItemAbbrMatchFuzzy = { fg = c.blue, italic = true },
CmpItemAbbrDeprecated = { fg = custom.gray, strikethrough = true },
- CmpItemKindVariable = lsp_kinds["variable"],
- CmpItemKindModule = lsp_kinds["module"],
- CmpItemKindSnippet = lsp_kinds["snippet"],
- CmpItemKindFolder = lsp_kinds["folder"],
- CmpItemKindColor = lsp_kinds["color"],
- CmpItemKindFile = lsp_kinds["file"],
- CmpItemKindText = lsp_kinds["text"],
- CmpItemKindMethod = lsp_kinds["method"],
- CmpItemKindFunction = lsp_kinds["function"],
- CmpItemKindConstructor = lsp_kinds["constructor"],
- CmpItemKindField = lsp_kinds["field"],
- CmpItemKindProperty = lsp_kinds["property"],
- CmpItemKindUnit = lsp_kinds["unit"],
- CmpItemKindValue = lsp_kinds["value"],
- CmpItemKindEnum = lsp_kinds["enum"],
- CmpItemKindKeyword = lsp_kinds["keyword"],
- CmpItemKindReference = lsp_kinds["reference"],
- CmpItemKindConstant = lsp_kinds["constant"],
- CmpItemKindStruct = lsp_kinds["struct"],
- CmpItemKindEvent = lsp_kinds["event"],
- CmpItemKindOperator = lsp_kinds["operator"],
- CmpItemKindNamespace = lsp_kinds["namespace"],
- CmpItemKindPackage = lsp_kinds["package"],
- CmpItemKindString = lsp_kinds["string"],
- CmpItemKindNumber = lsp_kinds["number"],
- CmpItemKindBoolean = lsp_kinds["boolean"],
- CmpItemKindArray = lsp_kinds["array"],
- CmpItemKindObject = lsp_kinds["object"],
- CmpItemKindKey = lsp_kinds["key"],
- CmpItemKindNull = lsp_kinds["null"],
- CmpItemKindEnumMember = lsp_kinds["enumMember"],
- CmpItemKindClass = lsp_kinds["class"],
- CmpItemKindInterface = lsp_kinds["interface"],
- CmpItemKindTypeParameter = lsp_kinds["typeParameter"],
+ CmpItemKindVariable = lsp_kinds['variable'],
+ CmpItemKindModule = lsp_kinds['module'],
+ CmpItemKindSnippet = lsp_kinds['snippet'],
+ CmpItemKindFolder = lsp_kinds['folder'],
+ CmpItemKindColor = lsp_kinds['color'],
+ CmpItemKindFile = lsp_kinds['file'],
+ CmpItemKindText = lsp_kinds['text'],
+ CmpItemKindMethod = lsp_kinds['method'],
+ CmpItemKindFunction = lsp_kinds['function'],
+ CmpItemKindConstructor = lsp_kinds['constructor'],
+ CmpItemKindField = lsp_kinds['field'],
+ CmpItemKindProperty = lsp_kinds['property'],
+ CmpItemKindUnit = lsp_kinds['unit'],
+ CmpItemKindValue = lsp_kinds['value'],
+ CmpItemKindEnum = lsp_kinds['enum'],
+ CmpItemKindKeyword = lsp_kinds['keyword'],
+ CmpItemKindReference = lsp_kinds['reference'],
+ CmpItemKindConstant = lsp_kinds['constant'],
+ CmpItemKindStruct = lsp_kinds['struct'],
+ CmpItemKindEvent = lsp_kinds['event'],
+ CmpItemKindOperator = lsp_kinds['operator'],
+ CmpItemKindNamespace = lsp_kinds['namespace'],
+ CmpItemKindPackage = lsp_kinds['package'],
+ CmpItemKindString = lsp_kinds['string'],
+ CmpItemKindNumber = lsp_kinds['number'],
+ CmpItemKindBoolean = lsp_kinds['boolean'],
+ CmpItemKindArray = lsp_kinds['array'],
+ CmpItemKindObject = lsp_kinds['object'],
+ CmpItemKindKey = lsp_kinds['key'],
+ CmpItemKindNull = lsp_kinds['null'],
+ CmpItemKindEnumMember = lsp_kinds['enumMember'],
+ CmpItemKindClass = lsp_kinds['class'],
+ CmpItemKindInterface = lsp_kinds['interface'],
+ CmpItemKindTypeParameter = lsp_kinds['typeParameter'],
-- Navic (breadcrumbs)
- NavicIconsFile = lsp_kinds["file"],
- NavicIconsModule = lsp_kinds["module"],
- NavicIconsNamespace = lsp_kinds["namespace"],
- NavicIconsPackage = lsp_kinds["package"],
- NavicIconsClass = lsp_kinds["class"],
- NavicIconsMethod = lsp_kinds["method"],
- NavicIconsProperty = lsp_kinds["property"],
- NavicIconsField = lsp_kinds["field"],
- NavicIconsConstructor = lsp_kinds["constructor"],
- NavicIconsEnum = lsp_kinds["enum"],
- NavicIconsInterface = lsp_kinds["interface"],
- NavicIconsFunction = lsp_kinds["function"],
- NavicIconsVariable = lsp_kinds["variable"],
- NavicIconsConstant = lsp_kinds["constant"],
- NavicIconsString = lsp_kinds["string"],
- NavicIconsNumber = lsp_kinds["number"],
- NavicIconsBoolean = lsp_kinds["boolean"],
- NavicIconsArray = lsp_kinds["array"],
- NavicIconsObject = lsp_kinds["object"],
- NavicIconsKey = lsp_kinds["key"],
- NavicIconsKeyword = lsp_kinds["keyword"],
- NavicIconsNull = lsp_kinds["null"],
- NavicIconsEnumMember = lsp_kinds["enumMember"],
- NavicIconsStruct = lsp_kinds["struct"],
- NavicIconsEvent = lsp_kinds["event"],
- NavicIconsOperator = lsp_kinds["operator"],
- NavicIconsTypeParameter = lsp_kinds["typeParameter"],
+ NavicIconsFile = lsp_kinds['file'],
+ NavicIconsModule = lsp_kinds['module'],
+ NavicIconsNamespace = lsp_kinds['namespace'],
+ NavicIconsPackage = lsp_kinds['package'],
+ NavicIconsClass = lsp_kinds['class'],
+ NavicIconsMethod = lsp_kinds['method'],
+ NavicIconsProperty = lsp_kinds['property'],
+ NavicIconsField = lsp_kinds['field'],
+ NavicIconsConstructor = lsp_kinds['constructor'],
+ NavicIconsEnum = lsp_kinds['enum'],
+ NavicIconsInterface = lsp_kinds['interface'],
+ NavicIconsFunction = lsp_kinds['function'],
+ NavicIconsVariable = lsp_kinds['variable'],
+ NavicIconsConstant = lsp_kinds['constant'],
+ NavicIconsString = lsp_kinds['string'],
+ NavicIconsNumber = lsp_kinds['number'],
+ NavicIconsBoolean = lsp_kinds['boolean'],
+ NavicIconsArray = lsp_kinds['array'],
+ NavicIconsObject = lsp_kinds['object'],
+ NavicIconsKey = lsp_kinds['key'],
+ NavicIconsKeyword = lsp_kinds['keyword'],
+ NavicIconsNull = lsp_kinds['null'],
+ NavicIconsEnumMember = lsp_kinds['enumMember'],
+ NavicIconsStruct = lsp_kinds['struct'],
+ NavicIconsEvent = lsp_kinds['event'],
+ NavicIconsOperator = lsp_kinds['operator'],
+ NavicIconsTypeParameter = lsp_kinds['typeParameter'],
NavicText = { fg = c.fg },
NavicSeparator = { fg = c.fg },
@@ -390,40 +390,40 @@ function M.get(c, opts)
-- Noice
NoiceCompletionItemKindDefault = { fg = c.fg_dark, bg = c.none },
- NoiceCompletionItemKindVariable = lsp_kinds["variable"],
- NoiceCompletionItemKindModule = lsp_kinds["module"],
- NoiceCompletionItemKindSnippet = lsp_kinds["snippet"],
- NoiceCompletionItemKindFolder = lsp_kinds["folder"],
- NoiceCompletionItemKindColor = lsp_kinds["color"],
- NoiceCompletionItemKindFile = lsp_kinds["file"],
- NoiceCompletionItemKindText = lsp_kinds["text"],
- NoiceCompletionItemKindMethod = lsp_kinds["method"],
- NoiceCompletionItemKindFunction = lsp_kinds["function"],
- NoiceCompletionItemKindConstructor = lsp_kinds["constructor"],
- NoiceCompletionItemKindField = lsp_kinds["field"],
- NoiceCompletionItemKindProperty = lsp_kinds["property"],
- NoiceCompletionItemKindUnit = lsp_kinds["unit"],
- NoiceCompletionItemKindValue = lsp_kinds["value"],
- NoiceCompletionItemKindEnum = lsp_kinds["enum"],
- NoiceCompletionItemKindKeyword = lsp_kinds["keyword"],
- NoiceCompletionItemKindReference = lsp_kinds["reference"],
- NoiceCompletionItemKindConstant = lsp_kinds["constant"],
- NoiceCompletionItemKindStruct = lsp_kinds["struct"],
- NoiceCompletionItemKindEvent = lsp_kinds["event"],
- NoiceCompletionItemKindOperator = lsp_kinds["operator"],
- NoiceCompletionItemKindNamespace = lsp_kinds["namespace"],
- NoiceCompletionItemKindPackage = lsp_kinds["package"],
- NoiceCompletionItemKindString = lsp_kinds["string"],
- NoiceCompletionItemKindNumber = lsp_kinds["number"],
- NoiceCompletionItemKindBoolean = lsp_kinds["boolean"],
- NoiceCompletionItemKindArray = lsp_kinds["array"],
- NoiceCompletionItemKindObject = lsp_kinds["object"],
- NoiceCompletionItemKindKey = lsp_kinds["key"],
- NoiceCompletionItemKindNull = lsp_kinds["null"],
- NoiceCompletionItemKindEnumMember = lsp_kinds["enumMember"],
- NoiceCompletionItemKindClass = lsp_kinds["class"],
- NoiceCompletionItemKindInterface = lsp_kinds["interface"],
- NoiceCompletionItemKindTypeParameter = lsp_kinds["typeParameter"],
+ NoiceCompletionItemKindVariable = lsp_kinds['variable'],
+ NoiceCompletionItemKindModule = lsp_kinds['module'],
+ NoiceCompletionItemKindSnippet = lsp_kinds['snippet'],
+ NoiceCompletionItemKindFolder = lsp_kinds['folder'],
+ NoiceCompletionItemKindColor = lsp_kinds['color'],
+ NoiceCompletionItemKindFile = lsp_kinds['file'],
+ NoiceCompletionItemKindText = lsp_kinds['text'],
+ NoiceCompletionItemKindMethod = lsp_kinds['method'],
+ NoiceCompletionItemKindFunction = lsp_kinds['function'],
+ NoiceCompletionItemKindConstructor = lsp_kinds['constructor'],
+ NoiceCompletionItemKindField = lsp_kinds['field'],
+ NoiceCompletionItemKindProperty = lsp_kinds['property'],
+ NoiceCompletionItemKindUnit = lsp_kinds['unit'],
+ NoiceCompletionItemKindValue = lsp_kinds['value'],
+ NoiceCompletionItemKindEnum = lsp_kinds['enum'],
+ NoiceCompletionItemKindKeyword = lsp_kinds['keyword'],
+ NoiceCompletionItemKindReference = lsp_kinds['reference'],
+ NoiceCompletionItemKindConstant = lsp_kinds['constant'],
+ NoiceCompletionItemKindStruct = lsp_kinds['struct'],
+ NoiceCompletionItemKindEvent = lsp_kinds['event'],
+ NoiceCompletionItemKindOperator = lsp_kinds['operator'],
+ NoiceCompletionItemKindNamespace = lsp_kinds['namespace'],
+ NoiceCompletionItemKindPackage = lsp_kinds['package'],
+ NoiceCompletionItemKindString = lsp_kinds['string'],
+ NoiceCompletionItemKindNumber = lsp_kinds['number'],
+ NoiceCompletionItemKindBoolean = lsp_kinds['boolean'],
+ NoiceCompletionItemKindArray = lsp_kinds['array'],
+ NoiceCompletionItemKindObject = lsp_kinds['object'],
+ NoiceCompletionItemKindKey = lsp_kinds['key'],
+ NoiceCompletionItemKindNull = lsp_kinds['null'],
+ NoiceCompletionItemKindEnumMember = lsp_kinds['enumMember'],
+ NoiceCompletionItemKindClass = lsp_kinds['class'],
+ NoiceCompletionItemKindInterface = lsp_kinds['interface'],
+ NoiceCompletionItemKindTypeParameter = lsp_kinds['typeParameter'],
-- Trouble
TroubleText = { fg = c.fg_dark },
@@ -479,33 +479,33 @@ function M.get(c, opts)
-- Aerial
AerialLine = { bg = c.bg_visual, bold = true },
AerialGuide = { fg = c.fg_gutter },
- AerialArrayIcon = lsp_kinds["array"],
- AerialBooleanIcon = lsp_kinds["boolean"],
- AerialClassIcon = lsp_kinds["class"],
- AerialConstantIcon = lsp_kinds["constant"],
- AerialConstructorIcon = lsp_kinds["constructor"],
- AerialEnumIcon = lsp_kinds["enum"],
- AerialEnumMemberIcon = lsp_kinds["enumMember"],
- AerialEventIcon = lsp_kinds["event"],
- AerialFieldIcon = lsp_kinds["field"],
- AerialFileIcon = lsp_kinds["file"],
- AerialFunctionIcon = lsp_kinds["function"],
- AerialInterfaceIcon = lsp_kinds["interface"],
- AerialKeyIcon = lsp_kinds["key"],
- AerialKeywordIcon = lsp_kinds["keyword"],
- AerialMethodIcon = lsp_kinds["method"],
- AerialModuleIcon = lsp_kinds["module"],
- AerialNamespaceIcon = lsp_kinds["namespace"],
- AerialNullIcon = lsp_kinds["null"],
- AerialNumberIcon = lsp_kinds["number"],
- AerialObjectIcon = lsp_kinds["object"],
- AerialOperatorIcon = lsp_kinds["operator"],
- AerialPackageIcon = lsp_kinds["package"],
- AerialPropertyIcon = lsp_kinds["property"],
- AerialStringIcon = lsp_kinds["string"],
- AerialStructIcon = lsp_kinds["struct"],
- AerialTypeParameterIcon = lsp_kinds["typeParameter"],
- AerialVariableIcon = lsp_kinds["variable"],
+ AerialArrayIcon = lsp_kinds['array'],
+ AerialBooleanIcon = lsp_kinds['boolean'],
+ AerialClassIcon = lsp_kinds['class'],
+ AerialConstantIcon = lsp_kinds['constant'],
+ AerialConstructorIcon = lsp_kinds['constructor'],
+ AerialEnumIcon = lsp_kinds['enum'],
+ AerialEnumMemberIcon = lsp_kinds['enumMember'],
+ AerialEventIcon = lsp_kinds['event'],
+ AerialFieldIcon = lsp_kinds['field'],
+ AerialFileIcon = lsp_kinds['file'],
+ AerialFunctionIcon = lsp_kinds['function'],
+ AerialInterfaceIcon = lsp_kinds['interface'],
+ AerialKeyIcon = lsp_kinds['key'],
+ AerialKeywordIcon = lsp_kinds['keyword'],
+ AerialMethodIcon = lsp_kinds['method'],
+ AerialModuleIcon = lsp_kinds['module'],
+ AerialNamespaceIcon = lsp_kinds['namespace'],
+ AerialNullIcon = lsp_kinds['null'],
+ AerialNumberIcon = lsp_kinds['number'],
+ AerialObjectIcon = lsp_kinds['object'],
+ AerialOperatorIcon = lsp_kinds['operator'],
+ AerialPackageIcon = lsp_kinds['package'],
+ AerialPropertyIcon = lsp_kinds['property'],
+ AerialStringIcon = lsp_kinds['string'],
+ AerialStructIcon = lsp_kinds['struct'],
+ AerialTypeParameterIcon = lsp_kinds['typeParameter'],
+ AerialVariableIcon = lsp_kinds['variable'],
-- Neotest
NeotestPassed = { fg = c.green },
diff --git a/files/.config/nvim/lua/dracula-pro/groups/treesitter.lua b/files/.config/nvim/lua/dracula-pro/groups/treesitter.lua
index 4ff61797..841dfc1e 100644
--- a/files/.config/nvim/lua/dracula-pro/groups/treesitter.lua
+++ b/files/.config/nvim/lua/dracula-pro/groups/treesitter.lua
@@ -4,137 +4,137 @@ local M = {}
function M.get(c, opts)
return {
- ["@annotation"] = "PreProc",
- ["@attribute"] = "PreProc",
- ["@boolean"] = "Boolean",
- ["@character"] = "Character",
- ["@character.printf"] = "SpecialChar",
- ["@character.special"] = "SpecialChar",
- ["@comment"] = "Comment",
- ["@comment.error"] = { fg = c.error },
- ["@comment.hint"] = { fg = c.hint },
- ["@comment.info"] = { fg = c.info },
- ["@comment.note"] = { fg = c.hint },
- ["@comment.todo"] = { fg = c.todo },
- ["@comment.warning"] = { fg = c.warning },
- ["@constant"] = "Constant",
- ["@constant.builtin"] = "Special",
- ["@constant.macro"] = "Define",
- ["@constructor"] = { fg = c.magenta },
- ["@constructor.tsx"] = { fg = c.blue1 },
- ["@diff.delta"] = "DiffChange",
- ["@diff.minus"] = "DiffDelete",
- ["@diff.plus"] = "DiffAdd",
- ["@function"] = "Function",
- ["@function.builtin"] = "Special",
- ["@function.call"] = "@function",
- ["@function.macro"] = "Macro",
- ["@function.method"] = "Function",
- ["@function.method.call"] = "@function.method",
- ["@keyword"] = { fg = c.purple, style = opts.styles.keywords },
- ["@keyword.conditional"] = "Conditional",
- ["@keyword.coroutine"] = "@keyword",
- ["@keyword.debug"] = "Debug",
- ["@keyword.directive"] = "PreProc",
- ["@keyword.directive.define"] = "Define",
- ["@keyword.exception"] = "Exception",
- ["@keyword.function"] = { fg = c.magenta, style = opts.styles.functions },
- ["@keyword.import"] = "Include",
- ["@keyword.operator"] = "@operator",
- ["@keyword.repeat"] = "Repeat",
- ["@keyword.return"] = "@keyword",
- ["@keyword.storage"] = "StorageClass",
- ["@label"] = { fg = c.blue },
- ["@markup"] = "@none",
- ["@markup.emphasis"] = { italic = true },
- ["@markup.environment"] = "Macro",
- ["@markup.environment.name"] = "Type",
- ["@markup.heading"] = "Title",
- ["@markup.italic"] = { italic = true },
- ["@markup.link"] = { fg = c.teal },
- ["@markup.link.label"] = "SpecialChar",
- ["@markup.link.label.symbol"] = "Identifier",
- ["@markup.link.url"] = "Underlined",
- ["@markup.list"] = { fg = c.blue5 },
- ["@markup.list.checked"] = { fg = c.green },
- ["@markup.list.markdown"] = { fg = c.orange, bold = true },
- ["@markup.list.unchecked"] = { fg = c.blue },
- ["@markup.math"] = "Special",
- ["@markup.raw"] = "String",
- ["@markup.raw.markdown_inline"] = { bg = c.terminal_black, fg = c.blue },
- ["@markup.strikethrough"] = { strikethrough = true },
- ["@markup.strong"] = { bold = true },
- ["@markup.underline"] = { underline = true },
- ["@module"] = "Include",
- ["@module.builtin"] = { fg = c.red },
- ["@namespace.builtin"] = "@variable.builtin",
- ["@none"] = {},
- ["@number"] = "Number",
- ["@number.float"] = "Float",
- ["@operator"] = { fg = c.blue5 },
- ["@property"] = { fg = c.cyan },
- ["@punctuation.bracket"] = { fg = c.fg_dark },
- ["@punctuation.delimiter"] = { fg = c.blue5 },
- ["@punctuation.special"] = { fg = c.blue5 },
- ["@string"] = "String",
- ["@string.documentation"] = { fg = c.green },
- ["@string.escape"] = { fg = c.magenta },
- ["@string.regexp"] = { fg = c.blue },
- ["@tag"] = { fg = c.red },
- ["@tag.attribute"] = { fg = c.cyan },
- ["@tag.delimiter"] = { fg = c.fg_dark },
- ["@tag.delimiter.tsx"] = { fg = c.blue },
- ["@tag.tsx"] = { fg = c.red },
- ["@type"] = "Type",
- ["@type.builtin"] = { fg = c.cyan },
- ["@type.definition"] = "Typedef",
- ["@type.qualifier"] = "@keyword",
- ["@variable"] = { fg = c.fg, style = opts.styles.variables },
- ["@variable.builtin"] = { fg = c.red },
- ["@variable.member"] = { fg = c.cyan },
- ["@variable.parameter"] = { fg = c.orange },
+ ['@annotation'] = 'PreProc',
+ ['@attribute'] = 'PreProc',
+ ['@boolean'] = 'Boolean',
+ ['@character'] = 'Character',
+ ['@character.printf'] = 'SpecialChar',
+ ['@character.special'] = 'SpecialChar',
+ ['@comment'] = 'Comment',
+ ['@comment.error'] = { fg = c.error },
+ ['@comment.hint'] = { fg = c.hint },
+ ['@comment.info'] = { fg = c.info },
+ ['@comment.note'] = { fg = c.hint },
+ ['@comment.todo'] = { fg = c.todo },
+ ['@comment.warning'] = { fg = c.warning },
+ ['@constant'] = 'Constant',
+ ['@constant.builtin'] = 'Special',
+ ['@constant.macro'] = 'Define',
+ ['@constructor'] = { fg = c.magenta },
+ ['@constructor.tsx'] = { fg = c.blue1 },
+ ['@diff.delta'] = 'DiffChange',
+ ['@diff.minus'] = 'DiffDelete',
+ ['@diff.plus'] = 'DiffAdd',
+ ['@function'] = 'Function',
+ ['@function.builtin'] = 'Special',
+ ['@function.call'] = '@function',
+ ['@function.macro'] = 'Macro',
+ ['@function.method'] = 'Function',
+ ['@function.method.call'] = '@function.method',
+ ['@keyword'] = { fg = c.purple, style = opts.styles.keywords },
+ ['@keyword.conditional'] = 'Conditional',
+ ['@keyword.coroutine'] = '@keyword',
+ ['@keyword.debug'] = 'Debug',
+ ['@keyword.directive'] = 'PreProc',
+ ['@keyword.directive.define'] = 'Define',
+ ['@keyword.exception'] = 'Exception',
+ ['@keyword.function'] = { fg = c.magenta, style = opts.styles.functions },
+ ['@keyword.import'] = 'Include',
+ ['@keyword.operator'] = '@operator',
+ ['@keyword.repeat'] = 'Repeat',
+ ['@keyword.return'] = '@keyword',
+ ['@keyword.storage'] = 'StorageClass',
+ ['@label'] = { fg = c.blue },
+ ['@markup'] = '@none',
+ ['@markup.emphasis'] = { italic = true },
+ ['@markup.environment'] = 'Macro',
+ ['@markup.environment.name'] = 'Type',
+ ['@markup.heading'] = 'Title',
+ ['@markup.italic'] = { italic = true },
+ ['@markup.link'] = { fg = c.teal },
+ ['@markup.link.label'] = 'SpecialChar',
+ ['@markup.link.label.symbol'] = 'Identifier',
+ ['@markup.link.url'] = 'Underlined',
+ ['@markup.list'] = { fg = c.blue5 },
+ ['@markup.list.checked'] = { fg = c.green },
+ ['@markup.list.markdown'] = { fg = c.orange, bold = true },
+ ['@markup.list.unchecked'] = { fg = c.blue },
+ ['@markup.math'] = 'Special',
+ ['@markup.raw'] = 'String',
+ ['@markup.raw.markdown_inline'] = { bg = c.terminal_black, fg = c.blue },
+ ['@markup.strikethrough'] = { strikethrough = true },
+ ['@markup.strong'] = { bold = true },
+ ['@markup.underline'] = { underline = true },
+ ['@module'] = 'Include',
+ ['@module.builtin'] = { fg = c.red },
+ ['@namespace.builtin'] = '@variable.builtin',
+ ['@none'] = {},
+ ['@number'] = 'Number',
+ ['@number.float'] = 'Float',
+ ['@operator'] = { fg = c.blue5 },
+ ['@property'] = { fg = c.cyan },
+ ['@punctuation.bracket'] = { fg = c.fg_dark },
+ ['@punctuation.delimiter'] = { fg = c.blue5 },
+ ['@punctuation.special'] = { fg = c.blue5 },
+ ['@string'] = 'String',
+ ['@string.documentation'] = { fg = c.green },
+ ['@string.escape'] = { fg = c.magenta },
+ ['@string.regexp'] = { fg = c.blue },
+ ['@tag'] = { fg = c.red },
+ ['@tag.attribute'] = { fg = c.cyan },
+ ['@tag.delimiter'] = { fg = c.fg_dark },
+ ['@tag.delimiter.tsx'] = { fg = c.blue },
+ ['@tag.tsx'] = { fg = c.red },
+ ['@type'] = 'Type',
+ ['@type.builtin'] = { fg = c.cyan },
+ ['@type.definition'] = 'Typedef',
+ ['@type.qualifier'] = '@keyword',
+ ['@variable'] = { fg = c.fg, style = opts.styles.variables },
+ ['@variable.builtin'] = { fg = c.red },
+ ['@variable.member'] = { fg = c.cyan },
+ ['@variable.parameter'] = { fg = c.orange },
- ["@lsp.type.boolean"] = "@boolean",
- ["@lsp.type.builtinType"] = "@type.builtin",
- ["@lsp.type.comment"] = "@comment",
- ["@lsp.type.decorator"] = "@attribute",
- ["@lsp.type.deriveHelper"] = "@attribute",
- ["@lsp.type.enum"] = "@type",
- ["@lsp.type.enumMember"] = "@constant",
- ["@lsp.type.escapeSequence"] = "@string.escape",
- ["@lsp.type.formatSpecifier"] = "@markup.list",
- ["@lsp.type.generic"] = "@variable",
- ["@lsp.type.interface"] = { fg = c.blue1 },
- ["@lsp.type.keyword"] = "@keyword",
- ["@lsp.type.lifetime"] = "@storageclass",
- ["@lsp.type.namespace"] = "@namespace",
- ["@lsp.type.number"] = "@number",
- ["@lsp.type.operator"] = "@operator",
- ["@lsp.type.parameter"] = "@variable.parameter",
- ["@lsp.type.property"] = "@property",
- ["@lsp.type.selfKeyword"] = "@variable.builtin",
- ["@lsp.type.selfTypeKeyword"] = "@variable.builtin",
- ["@lsp.type.string"] = "@string",
- ["@lsp.type.typeAlias"] = "@type.definition",
- ["@lsp.type.unresolvedReference"] = { undercurl = true, sp = c.error },
- ["@lsp.type.variable"] = {},
- ["@lsp.typemod.class.defaultLibrary"] = "@type.builtin",
- ["@lsp.typemod.enum.defaultLibrary"] = "@type.builtin",
- ["@lsp.typemod.enumMember.defaultLibrary"] = "@constant.builtin",
- ["@lsp.typemod.function.defaultLibrary"] = "@function.builtin",
- ["@lsp.typemod.keyword.async"] = "@keyword.coroutine",
- ["@lsp.typemod.keyword.injected"] = "@keyword",
- ["@lsp.typemod.macro.defaultLibrary"] = "@function.builtin",
- ["@lsp.typemod.method.defaultLibrary"] = "@function.builtin",
- ["@lsp.typemod.operator.injected"] = "@operator",
- ["@lsp.typemod.string.injected"] = "@string",
- ["@lsp.typemod.struct.defaultLibrary"] = "@type.builtin",
- ["@lsp.typemod.type.defaultLibrary"] = { fg = c.cyan },
- ["@lsp.typemod.typeAlias.defaultLibrary"] = { fg = c.cyan },
- ["@lsp.typemod.variable.callable"] = "@function",
- ["@lsp.typemod.variable.defaultLibrary"] = "@variable.builtin",
- ["@lsp.typemod.variable.injected"] = "@variable",
- ["@lsp.typemod.variable.static"] = "@constant",
+ ['@lsp.type.boolean'] = '@boolean',
+ ['@lsp.type.builtinType'] = '@type.builtin',
+ ['@lsp.type.comment'] = '@comment',
+ ['@lsp.type.decorator'] = '@attribute',
+ ['@lsp.type.deriveHelper'] = '@attribute',
+ ['@lsp.type.enum'] = '@type',
+ ['@lsp.type.enumMember'] = '@constant',
+ ['@lsp.type.escapeSequence'] = '@string.escape',
+ ['@lsp.type.formatSpecifier'] = '@markup.list',
+ ['@lsp.type.generic'] = '@variable',
+ ['@lsp.type.interface'] = { fg = c.blue1 },
+ ['@lsp.type.keyword'] = '@keyword',
+ ['@lsp.type.lifetime'] = '@storageclass',
+ ['@lsp.type.namespace'] = '@namespace',
+ ['@lsp.type.number'] = '@number',
+ ['@lsp.type.operator'] = '@operator',
+ ['@lsp.type.parameter'] = '@variable.parameter',
+ ['@lsp.type.property'] = '@property',
+ ['@lsp.type.selfKeyword'] = '@variable.builtin',
+ ['@lsp.type.selfTypeKeyword'] = '@variable.builtin',
+ ['@lsp.type.string'] = '@string',
+ ['@lsp.type.typeAlias'] = '@type.definition',
+ ['@lsp.type.unresolvedReference'] = { undercurl = true, sp = c.error },
+ ['@lsp.type.variable'] = {},
+ ['@lsp.typemod.class.defaultLibrary'] = '@type.builtin',
+ ['@lsp.typemod.enum.defaultLibrary'] = '@type.builtin',
+ ['@lsp.typemod.enumMember.defaultLibrary'] = '@constant.builtin',
+ ['@lsp.typemod.function.defaultLibrary'] = '@function.builtin',
+ ['@lsp.typemod.keyword.async'] = '@keyword.coroutine',
+ ['@lsp.typemod.keyword.injected'] = '@keyword',
+ ['@lsp.typemod.macro.defaultLibrary'] = '@function.builtin',
+ ['@lsp.typemod.method.defaultLibrary'] = '@function.builtin',
+ ['@lsp.typemod.operator.injected'] = '@operator',
+ ['@lsp.typemod.string.injected'] = '@string',
+ ['@lsp.typemod.struct.defaultLibrary'] = '@type.builtin',
+ ['@lsp.typemod.type.defaultLibrary'] = { fg = c.cyan },
+ ['@lsp.typemod.typeAlias.defaultLibrary'] = { fg = c.cyan },
+ ['@lsp.typemod.variable.callable'] = '@function',
+ ['@lsp.typemod.variable.defaultLibrary'] = '@variable.builtin',
+ ['@lsp.typemod.variable.injected'] = '@variable',
+ ['@lsp.typemod.variable.static'] = '@constant',
}
end
diff --git a/files/.config/nvim/lua/dracula-pro/init.lua b/files/.config/nvim/lua/dracula-pro/init.lua
index 34bdbfe6..9fec7d78 100644
--- a/files/.config/nvim/lua/dracula-pro/init.lua
+++ b/files/.config/nvim/lua/dracula-pro/init.lua
@@ -4,31 +4,29 @@
local M = {}
function M.load()
- local config = require("dracula-pro.config")
- local colors = require("dracula-pro.colors").setup(config.options)
+ local config = require('dracula-pro.config')
+ local colors = require('dracula-pro.colors').setup(config.options)
-- Clear existing highlights
- if vim.g.colors_name then
- vim.cmd("hi clear")
- end
+ if vim.g.colors_name then vim.cmd('hi clear') end
vim.o.termguicolors = true
- vim.g.colors_name = "dracula-pro"
+ vim.g.colors_name = 'dracula-pro'
-- Load highlight groups
local groups = {
- require("dracula-pro.groups.base").get(colors, config.options),
- require("dracula-pro.groups.treesitter").get(colors, config.options),
- require("dracula-pro.groups.plugins").get(colors, config.options),
+ require('dracula-pro.groups.base').get(colors, config.options),
+ require('dracula-pro.groups.treesitter').get(colors, config.options),
+ require('dracula-pro.groups.plugins').get(colors, config.options),
}
for _, group in ipairs(groups) do
for hl, spec in pairs(group) do
- if type(spec) == "string" then
+ if type(spec) == 'string' then
vim.api.nvim_set_hl(0, hl, { link = spec })
else
-- Resolve style table into highlight attributes
- if type(spec.style) == "table" then
+ if type(spec.style) == 'table' then
for k, v in pairs(spec.style) do
spec[k] = v
end
@@ -41,27 +39,25 @@ function M.load()
-- Terminal colors
if config.options.terminal_colors then
- vim.g.terminal_color_0 = "#22212C"
- vim.g.terminal_color_1 = "#FF9580"
- vim.g.terminal_color_2 = "#8AFF80"
- vim.g.terminal_color_3 = "#FFFF80"
- vim.g.terminal_color_4 = "#9580FF"
- vim.g.terminal_color_5 = "#FF80BF"
- vim.g.terminal_color_6 = "#80FFEA"
- vim.g.terminal_color_7 = "#F8F8F2"
- vim.g.terminal_color_8 = "#504C67"
- vim.g.terminal_color_9 = "#FFAA99"
- vim.g.terminal_color_10 = "#A2FF99"
- vim.g.terminal_color_11 = "#FFFF99"
- vim.g.terminal_color_12 = "#AA99FF"
- vim.g.terminal_color_13 = "#FF99CC"
- vim.g.terminal_color_14 = "#99FFEE"
- vim.g.terminal_color_15 = "#FFFFFF"
+ vim.g.terminal_color_0 = '#22212C'
+ vim.g.terminal_color_1 = '#FF9580'
+ vim.g.terminal_color_2 = '#8AFF80'
+ vim.g.terminal_color_3 = '#FFFF80'
+ vim.g.terminal_color_4 = '#9580FF'
+ vim.g.terminal_color_5 = '#FF80BF'
+ vim.g.terminal_color_6 = '#80FFEA'
+ vim.g.terminal_color_7 = '#F8F8F2'
+ vim.g.terminal_color_8 = '#504C67'
+ vim.g.terminal_color_9 = '#FFAA99'
+ vim.g.terminal_color_10 = '#A2FF99'
+ vim.g.terminal_color_11 = '#FFFF99'
+ vim.g.terminal_color_12 = '#AA99FF'
+ vim.g.terminal_color_13 = '#FF99CC'
+ vim.g.terminal_color_14 = '#99FFEE'
+ vim.g.terminal_color_15 = '#FFFFFF'
end
end
-function M.setup(opts)
- require("dracula-pro.config").setup(opts)
-end
+function M.setup(opts) require('dracula-pro.config').setup(opts) end
return M
diff --git a/files/.config/nvim/lua/external_grep.lua b/files/.config/nvim/lua/external_grep.lua
index b1f6b920..d65c29ba 100644
--- a/files/.config/nvim/lua/external_grep.lua
+++ b/files/.config/nvim/lua/external_grep.lua
@@ -18,7 +18,7 @@ augroup quickfix
augroup END
]])
-function mrl.external_grep(word, no_ignore)
+local function external_grep(word, no_ignore)
local word0 = (word or vim.fn.input('RG '))
if no_ignore then
vim.cmd((('silent grep ' .. word0) .. ' --no-ignore'))
@@ -31,7 +31,7 @@ end
vim.keymap.set(
'n',
'fS',
- mrl.external_grep,
+ external_grep,
{ desc = 'Ripgrep to QuickFix' }
)
diff --git a/files/.config/nvim/lua/health.lua b/files/.config/nvim/lua/health.lua
deleted file mode 100644
index d3e77c53..00000000
--- a/files/.config/nvim/lua/health.lua
+++ /dev/null
@@ -1,67 +0,0 @@
---[[
---
--- This file is not required for your own configuration,
--- but helps people determine if their system is setup correctly.
---
---]]
-
-local check_version = function()
- local verstr = string.format(
- '%s.%s.%s',
- vim.version().major,
- vim.version().minor,
- vim.version().patch
- )
- if not vim.version.cmp then
- vim.health.error(
- string.format(
- "Neovim out of date: '%s'. Upgrade to latest stable or nightly",
- verstr
- )
- )
- return
- end
-
- if vim.version.cmp(vim.version(), { 0, 9, 4 }) >= 0 then
- vim.health.ok(string.format("Neovim version is: '%s'", verstr))
- else
- vim.health.error(
- string.format(
- "Neovim out of date: '%s'. Upgrade to latest stable or nightly",
- verstr
- )
- )
- end
-end
-
-local check_external_reqs = function()
- -- Basic utils: `git`, `make`, `unzip`
- for _, exe in ipairs({ 'git', 'make', 'unzip', 'rg' }) do
- local is_executable = vim.fn.executable(exe) == 1
- if is_executable then
- vim.health.ok(string.format("Found executable: '%s'", exe))
- else
- vim.health.warn(string.format("Could not find executable: '%s'", exe))
- end
- end
-
- return true
-end
-
-return {
- check = function()
- vim.health.start('kickstart.nvim')
-
- vim.health.info([[NOTE: Not every warning is a 'must-fix' in `:checkhealth`
-
- Fix only warnings for plugins and languages you intend to use.
- Mason will give warnings for languages that are not installed.
- You do not need to install, unless you want to use those languages!]])
-
- local uv = vim.uv or vim.loop
- vim.health.info('System Information: ' .. vim.inspect(uv.os_uname()))
-
- check_version()
- check_external_reqs()
- end,
-}
diff --git a/files/.config/nvim/lua/highlight.lua b/files/.config/nvim/lua/highlight.lua
index 2cb8a87c..21bc41f3 100644
--- a/files/.config/nvim/lua/highlight.lua
+++ b/files/.config/nvim/lua/highlight.lua
@@ -1,5 +1,7 @@
-local api, notify, fmt, augroup =
- vim.api, vim.notify, string.format, mrl.augroup
+local api, fmt = vim.api, string.format
+local T = require('tools')
+local augroup = T.augroup
+local tint, blend, darken_hsl = T.tint, T.blend, T.darken_hsl
---@alias HLAttrs {from: string, attr: "fg" | "bg", alter: integer}
@@ -73,268 +75,6 @@ local function get_hl_as_hex(opts, ns)
return hl
end
---- Change the brightness of a color, negative numbers darken and positive ones brighten
----see:
---- 1. https://stackoverflow.com/q/5560248
---- 2. https://stackoverflow.com/a/37797380
----@param color string A hex color
----@param percent number a negative number darkens and a positive one brightens
----@return string
-local function tint(color, percent)
- assert(
- color and percent,
- 'cannot alter a color without specifying a color and percentage'
- )
- local r = tonumber(color:sub(2, 3), 16)
- local g = tonumber(color:sub(4, 5), 16)
- local b = tonumber(color:sub(6), 16)
- if not r or not g or not b then return 'NONE' end
- local blend = function(component)
- component = math.floor(component * (1 + percent))
- return math.min(math.max(component, 0), 255)
- end
- return fmt('#%02x%02x%02x', blend(r), blend(g), blend(b))
-end
-
---- Blend two hex colors using an alpha for the foreground.
---- `alpha = 0` returns bg, `alpha = 1` returns fg.
----@param bg string hex color (#RRGGBB)
----@param fg string hex color (#RRGGBB)
----@param alpha number 0..1
----@return string
-local function blend(bg, fg, alpha)
- assert(bg and fg and alpha ~= nil, 'blend(bg, fg, alpha) requires 3 args')
- if type(bg) ~= 'string' or type(fg) ~= 'string' then return 'NONE' end
- if bg == 'NONE' or fg == 'NONE' then return 'NONE' end
- if not bg:match('^#%x%x%x%x%x%x$') or not fg:match('^#%x%x%x%x%x%x$') then
- return 'NONE'
- end
- alpha = math.min(math.max(alpha, 0), 1)
-
- local br, bgc, bb =
- tonumber(bg:sub(2, 3), 16),
- tonumber(bg:sub(4, 5), 16),
- tonumber(bg:sub(6, 7), 16)
- local fr, fgc, fb =
- tonumber(fg:sub(2, 3), 16),
- tonumber(fg:sub(4, 5), 16),
- tonumber(fg:sub(6, 7), 16)
- if not br or not bgc or not bb or not fr or not fgc or not fb then
- return 'NONE'
- end
-
- local function mix(b, f) return math.floor((1 - alpha) * b + alpha * f + 0.5) end
- return fmt('#%02x%02x%02x', mix(br, fr), mix(bgc, fgc), mix(bb, fb))
-end
-
--- Blend two hex colors with alpha compositing
--- @param fg_hex: foreground color in hex format (e.g., "#ff0000" or "ff0000")
--- @param bg_hex: background color in hex format
--- @param alpha: alpha value for foreground (0.0 to 1.0), defaults to 0.5
--- @return: blended color in hex format
-local function blend_colors(fg_hex, bg_hex, alpha)
- alpha = alpha or 0.5
-
- if type(fg_hex) ~= 'string' or type(bg_hex) ~= 'string' then return 'NONE' end
- if fg_hex == 'NONE' or bg_hex == 'NONE' then return 'NONE' end
-
- -- Remove '#' if present
- fg_hex = fg_hex:gsub('#', '')
- bg_hex = bg_hex:gsub('#', '')
-
- if #fg_hex ~= 6 or #bg_hex ~= 6 then return 'NONE' end
-
- -- Parse hex colors to RGB
- local fg_r = tonumber(fg_hex:sub(1, 2), 16)
- local fg_g = tonumber(fg_hex:sub(3, 4), 16)
- local fg_b = tonumber(fg_hex:sub(5, 6), 16)
-
- local bg_r = tonumber(bg_hex:sub(1, 2), 16)
- local bg_g = tonumber(bg_hex:sub(3, 4), 16)
- local bg_b = tonumber(bg_hex:sub(5, 6), 16)
-
- if not fg_r or not fg_g or not fg_b or not bg_r or not bg_g or not bg_b then
- return 'NONE'
- end
-
- alpha = math.min(math.max(alpha, 0), 1)
-
- -- Alpha blend: out = fg * alpha + bg * (1 - alpha)
- local out_r = math.floor(fg_r * alpha + bg_r * (1 - alpha) + 0.5)
- local out_g = math.floor(fg_g * alpha + bg_g * (1 - alpha) + 0.5)
- local out_b = math.floor(fg_b * alpha + bg_b * (1 - alpha) + 0.5)
-
- -- Convert back to hex
- return string.format('#%02x%02x%02x', out_r, out_g, out_b)
-end
-
-local function normalize_hex(hex)
- if type(hex) ~= 'string' then return nil end
- hex = hex:gsub('#', '')
- if #hex ~= 6 then return nil end
- return hex:lower()
-end
-
--- Convert RGB (0..255) to HSL (0..1)
-local function rgb_to_hsl(r, g, b)
- r, g, b = r / 255, g / 255, b / 255
- local maxc, minc = math.max(r, g, b), math.min(r, g, b)
- local h, s, l = 0, 0, (maxc + minc) / 2
-
- if maxc ~= minc then
- local d = maxc - minc
- s = l > 0.5 and d / (2 - maxc - minc) or d / (maxc + minc)
-
- if maxc == r then
- h = (g - b) / d + (g < b and 6 or 0)
- elseif maxc == g then
- h = (b - r) / d + 2
- else
- h = (r - g) / d + 4
- end
- h = h / 6
- end
-
- return h, s, l
-end
-
--- Convert HSL (0..1) to RGB (0..255 ints)
-local function hsl_to_rgb(h, s, l)
- local function hue_to_rgb(p, q, t)
- if t < 0 then t = t + 1 end
- if t > 1 then t = t - 1 end
- if t < 1 / 6 then return p + (q - p) * 6 * t end
- if t < 1 / 2 then return q end
- if t < 2 / 3 then return p + (q - p) * (2 / 3 - t) * 6 end
- return p
- end
-
- local r, g, b
- if s == 0 then
- r, g, b = l, l, l
- else
- local q = l < 0.5 and l * (1 + s) or l + s - l * s
- local p = 2 * l - q
- r = hue_to_rgb(p, q, h + 1 / 3)
- g = hue_to_rgb(p, q, h)
- b = hue_to_rgb(p, q, h - 1 / 3)
- end
-
- return math.floor(r * 255 + 0.5),
- math.floor(g * 255 + 0.5),
- math.floor(b * 255 + 0.5)
-end
-
--- Darken a color by scaling HSL lightness while preserving hue/saturation.
--- `lightness_factor` in 0..1: lower is darker.
-local function darken_hsl(hex, lightness_factor)
- lightness_factor = lightness_factor or 0.0
- local h = normalize_hex(hex)
- if not h then return 'NONE' end
- local r = tonumber(h:sub(1, 2), 16)
- local g = tonumber(h:sub(3, 4), 16)
- local b = tonumber(h:sub(5, 6), 16)
- if not r or not g or not b then return 'NONE' end
-
- local hh, ss, ll = rgb_to_hsl(r, g, b)
-
- if lightness_factor > 0 then
- -- Lighten: move toward 1.0 (white)
- ll = ll + (1 - ll) * lightness_factor
- else
- -- Darken: move toward 0.0 (black)
- ll = ll * (1 + lightness_factor)
- end
-
- ll = math.min(math.max(ll, 0), 1)
- r, g, b = hsl_to_rgb(hh, ss, ll)
- return fmt('#%02x%02x%02x', r, g, b)
-end
-
---- Compute an alpha (0..1) such that blend(bg, fg, alpha) ~= target.
---- Returns a best-effort alpha (averaged across RGB channels) and clamps to [0,1].
----@param bg string hex color (#RRGGBB)
----@param fg string hex color (#RRGGBB)
----@param target string hex color (#RRGGBB)
----@return number
-local function blend_alpha(bg, fg, target)
- if
- type(bg) ~= 'string'
- or type(fg) ~= 'string'
- or type(target) ~= 'string'
- or bg == 'NONE'
- or fg == 'NONE'
- or target == 'NONE'
- or not bg:match('^#%x%x%x%x%x%x$')
- or not fg:match('^#%x%x%x%x%x%x$')
- or not target:match('^#%x%x%x%x%x%x$')
- then
- return 0.5
- end
-
- local br, bgc, bb =
- tonumber(bg:sub(2, 3), 16),
- tonumber(bg:sub(4, 5), 16),
- tonumber(bg:sub(6, 7), 16)
- local fr, fgc, fb =
- tonumber(fg:sub(2, 3), 16),
- tonumber(fg:sub(4, 5), 16),
- tonumber(fg:sub(6, 7), 16)
- local tr, tgc, tb =
- tonumber(target:sub(2, 3), 16),
- tonumber(target:sub(4, 5), 16),
- tonumber(target:sub(6, 7), 16)
- if
- not br
- or not bgc
- or not bb
- or not fr
- or not fgc
- or not fb
- or not tr
- or not tgc
- or not tb
- then
- return 0.5
- end
-
- local function alpha_for(b, f, t)
- local denom = (f - b)
- if denom == 0 then return nil end
- return (t - b) / denom
- end
-
- local alphas = {
- alpha_for(br, fr, tr),
- alpha_for(bgc, fgc, tgc),
- alpha_for(bb, fb, tb),
- }
-
- local sum, n = 0, 0
- for _, a in ipairs(alphas) do
- if a and a == a and a ~= math.huge and a ~= -math.huge then
- sum, n = sum + a, n + 1
- end
- end
- local a = n > 0 and (sum / n) or 0.5
- return math.min(math.max(a, 0), 1)
-end
-
-local err_warn = vim.schedule_wrap(function(group, attribute)
- notify(
- fmt(
- 'failed to get highlight %s for attribute %s\n%s',
- group,
- attribute,
- debug.traceback()
- ),
- 'ERROR',
- {
- title = fmt('Highlight - get(%s)', group),
- }
- ) -- stylua: ignore
-end)
-
---Get the value a highlight group whilst handling errors, fallbacks as well as returning a gui value
---If no attribute is specified return the entire highlight table
---in the right format
@@ -386,11 +126,9 @@ local function set(ns, name, opts)
opts, name, ns = name, ns, 0
end
- vim.validate({
- opts = { opts, 'table' },
- name = { name, 'string' },
- ns = { ns, 'number' },
- })
+ vim.validate('opts', opts, 'table')
+ vim.validate('name', name, 'string')
+ vim.validate('ns', ns, 'number')
local hl = opts.clear and {} or get_hl_as_hex({ name = opts.inherit or name })
for attribute, hl_data in pairs(opts) do
@@ -398,7 +136,7 @@ local function set(ns, name, opts)
if attrs[attribute] then hl[attribute] = new_data end
end
- mrl.pcall(fmt('setting highlight "%s"', name), api.nvim_set_hl, ns, name, hl)
+ T.pcall(fmt('setting highlight "%s"', name), api.nvim_set_hl, ns, name, hl)
end
---Apply a list of highlights
@@ -454,16 +192,12 @@ local function plugin(name, opts)
})
end
-mrl.highlight = {
+return {
get = get,
set = set,
all = all,
tint = tint,
blend = blend,
- blend_colors = blend_colors,
- blend_alpha = blend_alpha,
- rgb_to_hsl = rgb_to_hsl,
- hsl_to_rgb = hsl_to_rgb,
darken_hsl = darken_hsl,
plugin = plugin,
set_winhl = set_winhl,
diff --git a/files/.config/nvim/lua/keymaps.lua b/files/.config/nvim/lua/keymaps.lua
index 594b68a0..3faf4a67 100644
--- a/files/.config/nvim/lua/keymaps.lua
+++ b/files/.config/nvim/lua/keymaps.lua
@@ -1,37 +1,15 @@
--- TODO: move me to other place
---
---
+local T = require('tools')
local noremap_silent = { noremap = true, silent = true }
--- Commands {{{
---
----Create an nvim command
-function mrl.command(name, rhs, opts)
- opts = opts or {}
- vim.api.nvim_create_user_command(name, rhs, opts)
-end
-
----Determine if a value of any type is empty
-function mrl.falsy(item)
- if not item then return true end
- local item_type = type(item)
- if item_type == 'boolean' then return not item end
- if item_type == 'string' then return item == '' end
- if item_type == 'number' then return item <= 0 end
- if item_type == 'table' then return vim.tbl_isempty(item) end
- return item ~= nil
-end
-
--- }}}
-- Quickfix and Location List {{{
-mrl.list = { qf = {}, loc = {} }
+local list = { qf = {}, loc = {} }
---@param list_type "loclist" | "quickfix"
---@return boolean
local function is_list_open(list_type)
- return mrl.find(
- function(win) return not mrl.falsy(win[list_type]) end,
+ return T.find(
+ function(win) return not T.falsy(win[list_type]) end,
vim.fn.getwininfo()
) ~= nil
end
@@ -45,7 +23,7 @@ local function preserve_window(callback, ...)
if win ~= vim.api.nvim_get_current_win() then vim.cmd.wincmd('p') end
end
-function mrl.list.qf.toggle()
+function list.qf.toggle()
if is_list_open('quickfix') then
vim.cmd.cclose(silence)
elseif #vim.fn.getqflist() > 0 then
@@ -53,7 +31,7 @@ function mrl.list.qf.toggle()
end
end
-function mrl.list.loc.toggle()
+function list.loc.toggle()
if is_list_open('loclist') then
vim.cmd.lclose(silence)
elseif #vim.fn.getloclist(0) > 0 then
@@ -63,34 +41,30 @@ end
-- @see: https://vi.stackexchange.com/a/21255
-- using range-aware function
-function mrl.list.qf.delete(buf)
+function list.qf.delete(buf)
buf = buf or vim.api.nvim_get_current_buf()
- local list = vim.fn.getqflist()
+ local qflist = vim.fn.getqflist()
local line = vim.api.nvim_win_get_cursor(0)[1]
local mode = vim.api.nvim_get_mode().mode
if mode:match('[vV]') then
local first_line = vim.fn.getpos("'<")[2]
local last_line = vim.fn.getpos("'>")[2]
- list = mrl.fold(function(accum, item, i)
+ qflist = T.fold(function(accum, item, i)
if i < first_line or i > last_line then accum[#accum + 1] = item end
return accum
- end, list)
+ end, qflist)
else
- table.remove(list, line)
+ table.remove(qflist, line)
end
-- replace items in the current list, do not make a new copy of it; this also preserves the list title
- vim.fn.setqflist({}, 'r', { items = list })
+ vim.fn.setqflist({}, 'r', { items = qflist })
vim.fn.setpos('.', { buf, line, 1, 0 }) -- restore current line
end
-- }}}
-local fn, api, uv, cmd, command, fmt =
- vim.fn, vim.api, vim.loop, vim.cmd, mrl.command, string.format
-
-if not mrl or not mrl.mappings.enable then return end
-
local fn, api, uv, cmd, fmt = vim.fn, vim.api, vim.loop, vim.cmd, string.format
+local command = T.command
-- Credit: Justinmk
vim.keymap.set('n', 'g>', [[set nomore40messagesset more]], {
@@ -333,18 +307,8 @@ end)
vim.keymap.set('n', 'gf', 'e ')
-- quickfix list
-vim.keymap.set(
- 'n',
- '',
- mrl.list.qf.toggle,
- { desc = 'toggle quickfix list' }
-)
-vim.keymap.set(
- 'n',
- '',
- mrl.list.loc.toggle,
- { desc = 'toggle location list' }
-)
+vim.keymap.set('n', '', list.qf.toggle, { desc = 'toggle quickfix list' })
+vim.keymap.set('n', '', list.loc.toggle, { desc = 'toggle location list' })
-----------------------------------------------------------------------------//
-- Completion
@@ -453,7 +417,7 @@ vim.keymap.set(
'Reverse',
{ desc = 'reverse buffer' }
)
-vim.keymap.set('n', '', 'Todo', { desc = 'reverse buffer' })
+vim.keymap.set('n', '', 'Todo', { desc = 'toggle todo search' })
-----------------------------------------------------------------------------//
-- References
@@ -840,7 +804,7 @@ vim.keymap.set(
vim.keymap.set(
{ 'n' },
'ls',
- 'lua vim.lsp.diagnostic.get_line_diagnostics()',
+ vim.diagnostic.open_float,
{ noremap = true, silent = true }
)
diff --git a/files/.config/nvim/lua/lazyloader.lua b/files/.config/nvim/lua/lazyloader.lua
index f80ebcf3..9b3c9c1e 100644
--- a/files/.config/nvim/lua/lazyloader.lua
+++ b/files/.config/nvim/lua/lazyloader.lua
@@ -15,7 +15,7 @@ end ---@diagnostic disable-next-line: undefined-field
vim.opt.rtp:prepend(lazypath)
-- Ensure icons are available, use defaults if not
-local icons = mrl.ui and mrl.ui.icons or nil
+local icons = require('tools').ui.icons
require('lazy').setup({
{ import = 'custom.plugins' },
@@ -90,18 +90,3 @@ require('lazy').setup({
},
},
})
-
--- Disable columns in Lazy.nvim windows
-vim.api.nvim_create_autocmd('FileType', {
- pattern = 'lazy',
- callback = function()
- vim.schedule(function()
- local win = vim.api.nvim_get_current_win()
- vim.wo[win].statuscolumn = ''
- vim.wo[win].signcolumn = 'no'
- vim.wo[win].foldcolumn = '0'
- vim.wo[win].number = false
- vim.wo[win].relativenumber = false
- end)
- end,
-})
diff --git a/files/.config/nvim/lua/options.lua b/files/.config/nvim/lua/options.lua
index becb4db9..5675a808 100644
--- a/files/.config/nvim/lua/options.lua
+++ b/files/.config/nvim/lua/options.lua
@@ -29,7 +29,7 @@ vim.o.background = 'dark' -- or "light"
-- }}}
-- Timings {{{
-vim.opt.updatetime = 1000 -- Increased from 500 to reduce CursorHold frequency (improves scrolling perf)
+vim.opt.updatetime = 1000 -- Increased from 500 to reduce CursorHold frequency (improves scrolling perf)
vim.opt.timeout = true
vim.opt.timeoutlen = 500
-- }}}
@@ -121,11 +121,7 @@ vim.opt.breakindentopt = 'sbr'
vim.opt.linebreak = true -- lines wrap at words rather than random characters
-- If we render signs inside `statuscolumn`, disable the built-in signcolumn to
-- avoid duplicated icons.
-local statuscolumn_enabled = mrl
- and mrl.ui
- and mrl.ui.statuscolumn
- and mrl.ui.statuscolumn.enable
-vim.opt.signcolumn = statuscolumn_enabled and 'no' or 'yes'
+vim.opt.signcolumn = 'no' -- statuscolumn.lua manages signs
vim.opt.ruler = false
vim.opt.cmdheight = 0
vim.opt.showbreak = [[↪ ]] -- Options include -> '…', '↳ ', '→','↪ '
diff --git a/files/.config/nvim/lua/tools.lua b/files/.config/nvim/lua/tools.lua
index 3dc13d25..a57085f4 100644
--- a/files/.config/nvim/lua/tools.lua
+++ b/files/.config/nvim/lua/tools.lua
@@ -1,37 +1,26 @@
-local fn, api, v, fmt =
- vim.fn, vim.api, vim.v, string.format
+local fn, api, fmt = vim.fn, vim.api, string.format
--- colors {{{
+local M = {}
-function mrl.get_hi(name, id)
- id = id or 0
- local hi = vim.api.nvim_get_hl(0, { name = name })
- -- hi is a table with bg and fg keys. for those we want to return the hex
- -- value with ('#%06x'):format(num)
- for k, v in pairs(hi) do
- if type(v) == 'number' then hi[k] = ('#%06x'):format(v) end
- end
- return hi
-end
-
--- }}}
+--------------------------------------------------------------------------------
+-- Helpers {{{
--------------------------------------------------------------------------------
--- Commands {{{
-function mrl.command(name, rhs, opts)
- opts = opts or {}
- api.nvim_create_user_command(name, rhs, opts)
-end
+---check if a certain feature/version/commit exists in nvim
+---@param feature string
+---@return boolean
+function M.has(feature) return fn.has(feature) > 0 end
+
+local LATEST_NIGHTLY_MINOR = 10
+function M.nightly() return vim.version().minor >= LATEST_NIGHTLY_MINOR end
---- Call the given function and use `vim.notify` to notify of any errors
---- this function is a wrapper around `xpcall` which allows having a single
---- error handler for all errors
+--- Call the given function and use `vim.notify` to notify of any errors.
---@param msg string
---@param func function
---@param ... any
---@return boolean, any
---@overload fun(func: function, ...): boolean, any
-function mrl.pcall(msg, func, ...)
+function M.pcall(msg, func, ...)
local args = { ... }
if type(msg) == 'function' then
local arg = func --[[@as any]]
@@ -47,18 +36,61 @@ function mrl.pcall(msg, func, ...)
end, unpack(args))
end
-local LATEST_NIGHTLY_MINOR = 10
-function mrl.nightly() return vim.version().minor >= LATEST_NIGHTLY_MINOR end
+--- Require on index — defers the actual require until the first key access.
+function M.require_for_later_index(require_path)
+ return setmetatable({}, {
+ __index = function(_, key) return require(require_path)[key] end,
+ __newindex = function(_, key, value) require(require_path)[key] = value end,
+ })
+end
+
+--- Require on call — wraps each exported function so the module is only loaded
+--- when that function is first invoked.
+---@param require_path string
+---@return table
+function M.require_for_later_call(require_path)
+ return setmetatable({}, {
+ __index = function(_, k)
+ return function(...) return require(require_path)[k](...) end
+ end,
+ })
+end
+
+---Autosize a horizontal split to fit its content.
+---@param min_height number
+---@param max_height number
+function M.adjust_split_height(min_height, max_height)
+ api.nvim_win_set_height(
+ 0,
+ math.max(math.min(fn.line('$'), max_height), min_height)
+ )
+end
+
+function M.get_hi(name, id)
+ id = id or 0
+ local hi = vim.api.nvim_get_hl(0, { name = name })
+ for k, v in pairs(hi) do
+ if type(v) == 'number' then hi[k] = ('#%06x'):format(v) end
+ end
+ return hi
+end
+
+function M.command(name, rhs, opts)
+ opts = opts or {}
+ api.nvim_create_user_command(name, rhs, opts)
+end
-- }}}
+--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- finders and matchers {{{
+-- Tables & functional {{{
--------------------------------------------------------------------------------
----Determine if a value of any type is empty
+
+---Determine if a value of any type is empty / falsy.
---@param item any
---@return boolean?
-function mrl.falsy(item)
+function M.falsy(item)
if not item then return true end
local item_type = type(item)
if item_type == 'boolean' then return not item end
@@ -71,40 +103,59 @@ end
---@generic T:table
---@param callback fun(item: T, key: any)
---@param list table
-function mrl.foreach(callback, list)
+function M.foreach(callback, list)
for k, v in pairs(list) do
callback(v, k)
end
end
---- Check if the target matches any item in the list.
+function M.fold(callback, list, accum)
+ accum = accum or {}
+ for k, v in pairs(list) do
+ accum = callback(accum, v, k)
+ assert(accum ~= nil, 'The accumulator must be returned on each iteration')
+ end
+ return accum
+end
+
+---@generic T
+---@param callback fun(item: T, key: string | number, list: T[]): T
+---@param list T[]
+---@return T[]
+function M.map(callback, list)
+ return M.fold(function(accum, v, k)
+ accum[#accum + 1] = callback(v, k, accum)
+ return accum
+ end, list, {})
+end
+
+--- Check if the target matches any item in the list (pattern-aware).
---@param target string
---@param list string[]
---@return boolean
-function mrl.any(target, list)
+function M.any(target, list)
for _, item in ipairs(list) do
if target:match(item) then return true end
end
return false
end
----Find an item in a list
+---Find an item in a list.
---@generic T
---@param matcher fun(arg: T):boolean
---@param haystack T[]
---@return T?
-function mrl.find(matcher, haystack)
+function M.find(matcher, haystack)
for _, needle in ipairs(haystack) do
if matcher(needle) then return needle end
end
end
+---Return a table whose missing-key lookup falls back to pattern matching.
---@generic T
----Given a table return a new table which if the key is not found will search
----all the table's keys for a match using `string.match`
---@param map T
---@return T
-function mrl.p_table(map)
+function M.p_table(map)
return setmetatable(map, {
__index = function(tbl, key)
if not key then return end
@@ -115,46 +166,20 @@ function mrl.p_table(map)
})
end
----check if a certain feature/version/commit exists in nvim
----@param feature string
----@return boolean
-function mrl.has(feature) return fn.has(feature) > 0 end
-
-- }}}
--------------------------------------------------------------------------------
--- Functional utilities {{{
-function mrl.fold(callback, list, accum)
- accum = accum or {}
- for k, v in pairs(list) do
- accum = callback(accum, v, k)
- assert(accum ~= nil, 'The accumulator must be returned on each iteration')
- end
- return accum
-end
-
----@generic T
----@param callback fun(item: T, key: string | number, list: T[]): T
----@param list T[]
----@return T[]
-function mrl.map(callback, list)
- return mrl.fold(function(accum, v, k)
- accum[#accum + 1] = callback(v, k, accum)
- return accum
- end, list, {})
-end
-
--------------------------------------------------------------------------------
--- Autocommand group {{{
+-- Autocommands {{{
--------------------------------------------------------------------------------
local autocmd_keys =
{ 'event', 'buffer', 'pattern', 'desc', 'command', 'group', 'once', 'nested' }
---- Validate the keys passed to mrl.augroup are valid
+
---@param name string
---@param command Autocommand
local function validate_autocmd(name, command)
- local incorrect = mrl.fold(function(accum, _, key)
+ local incorrect = M.fold(function(accum, _, key)
if not vim.tbl_contains(autocmd_keys, key) then table.insert(accum, key) end
return accum
end, command, {})
@@ -167,12 +192,11 @@ local function validate_autocmd(name, command)
end
end
----Create an autocommand
----returns the group ID so that it can be cleared or manipulated.
----@param name string The name of the autocommand group
----@param ... Autocommand A list of autocommands to create
+---Create an autocommand group and return its ID.
+---@param name string
+---@param ... Autocommand
---@return number
-function mrl.augroup(name, ...)
+function M.augroup(name, ...)
local commands = { ... }
assert(name ~= 'User', 'The name of an augroup CANNOT be User')
assert(
@@ -183,7 +207,6 @@ function mrl.augroup(name, ...)
for _, autocmd in ipairs(commands) do
validate_autocmd(name, autocmd)
local is_callback = type(autocmd.command) == 'function'
-
api.nvim_create_autocmd(autocmd.event, {
group = name,
pattern = autocmd.pattern,
@@ -201,75 +224,840 @@ end
-- }}}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Lazy Requires {{{
--------------------------------------------------------------------------------
--- This code comes from TJ the Great:
---- source: https://github.com/tjdevries/lazy-require.nvim
-
---- Require on index.
----
---- Will only require the module after the first index of a module.
---- Only works for modules that export a table.
-function mrl.require_for_later_index(require_path)
- return setmetatable({}, {
- __index = function(_, key) return require(require_path)[key] end,
- __newindex = function(_, key, value) require(require_path)[key] = value end,
- })
-end
+--------------------------------------------------------------------------------
+-- String utilities {{{
+--------------------------------------------------------------------------------
---- Require when an exported method is called.
----
---- Creates a new function. Cannot be used to compare functions,
---- set new values, etc. Only useful for waiting to do the require until you
---- actually call the code.
----
---- ```lua
---- -- This is not loaded yet
---- local lazy_mod = lazy.require_on_exported_call('my_module')
---- local lazy_func = lazy_mod.exported_func
----
---- -- ... some time later
---- lazy_func(42) -- <- Only loads the module now
----
---- ```
----@param require_path string
----@return table
-function mrl.require_for_later_call(require_path)
- return setmetatable({}, {
- __index = function(_, k)
- return function(...) return require(require_path)[k](...) end
- end,
- })
+---Truncate a string to a maximum display-width, appending an ellipsis.
+---@param str string
+---@param max_len integer
+---@return string
+function M.truncate(str, max_len)
+ assert(str and max_len, 'string and max_len must be provided')
+ local ellipsis = M.ui.icons.misc.ellipsis
+ return api.nvim_strwidth(str) > max_len and str:sub(1, max_len) .. ellipsis
+ or str
end
-- }}}
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
--- Window utilities {{{
---- Autosize horizontal split to match its minimum content
---- https://vim.fandom.com/wiki/Automatically_fitting_a_quickfix_window_height
----@param min_height number
----@param max_height number
-function mrl.adjust_split_height(min_height, max_height)
- api.nvim_win_set_height(
- 0,
- math.max(math.min(fn.line('$'), max_height), min_height)
+--------------------------------------------------------------------------------
+-- Color utilities {{{
+--------------------------------------------------------------------------------
+
+--- Change the brightness of a color, negative numbers darken and positive ones brighten.
+---@param color string A hex color (#RRGGBB)
+---@param percent number a negative number darkens and a positive one brightens
+---@return string
+function M.tint(color, percent)
+ assert(
+ color and percent,
+ 'cannot alter a color without specifying a color and percentage'
)
+ local r = tonumber(color:sub(2, 3), 16)
+ local g = tonumber(color:sub(4, 5), 16)
+ local b = tonumber(color:sub(6), 16)
+ if not r or not g or not b then return 'NONE' end
+ local blend = function(component)
+ component = math.floor(component * (1 + percent))
+ return math.min(math.max(component, 0), 255)
+ end
+ return fmt('#%02x%02x%02x', blend(r), blend(g), blend(b))
end
+
+--- Blend two hex colors using an alpha for the foreground.
+--- `alpha = 0` returns bg, `alpha = 1` returns fg.
+---@param bg string hex color (#RRGGBB)
+---@param fg string hex color (#RRGGBB)
+---@param alpha number 0..1
+---@return string
+function M.blend(bg, fg, alpha)
+ assert(bg and fg and alpha ~= nil, 'blend(bg, fg, alpha) requires 3 args')
+ if type(bg) ~= 'string' or type(fg) ~= 'string' then return 'NONE' end
+ if bg == 'NONE' or fg == 'NONE' then return 'NONE' end
+ if not bg:match('^#%x%x%x%x%x%x$') or not fg:match('^#%x%x%x%x%x%x$') then
+ return 'NONE'
+ end
+ alpha = math.min(math.max(alpha, 0), 1)
+
+ local br, bgc, bb =
+ tonumber(bg:sub(2, 3), 16),
+ tonumber(bg:sub(4, 5), 16),
+ tonumber(bg:sub(6, 7), 16)
+ local fr, fgc, fb =
+ tonumber(fg:sub(2, 3), 16),
+ tonumber(fg:sub(4, 5), 16),
+ tonumber(fg:sub(6, 7), 16)
+ if not br or not bgc or not bb or not fr or not fgc or not fb then
+ return 'NONE'
+ end
+
+ local function mix(b, f) return math.floor((1 - alpha) * b + alpha * f + 0.5) end
+ return fmt('#%02x%02x%02x', mix(br, fr), mix(bgc, fgc), mix(bb, fb))
+end
+
+---@param hex string
+---@return string?
+local function normalize_hex(hex)
+ if type(hex) ~= 'string' then return nil end
+ hex = hex:gsub('#', '')
+ if #hex ~= 6 then return nil end
+ return hex:lower()
+end
+
+local function rgb_to_hsl(r, g, b)
+ r, g, b = r / 255, g / 255, b / 255
+ local maxc, minc = math.max(r, g, b), math.min(r, g, b)
+ local h, s, l = 0, 0, (maxc + minc) / 2
+
+ if maxc ~= minc then
+ local d = maxc - minc
+ s = l > 0.5 and d / (2 - maxc - minc) or d / (maxc + minc)
+ if maxc == r then
+ h = (g - b) / d + (g < b and 6 or 0)
+ elseif maxc == g then
+ h = (b - r) / d + 2
+ else
+ h = (r - g) / d + 4
+ end
+ h = h / 6
+ end
+
+ return h, s, l
+end
+
+local function hsl_to_rgb(h, s, l)
+ local function hue_to_rgb(p, q, t)
+ if t < 0 then t = t + 1 end
+ if t > 1 then t = t - 1 end
+ if t < 1 / 6 then return p + (q - p) * 6 * t end
+ if t < 1 / 2 then return q end
+ if t < 2 / 3 then return p + (q - p) * (2 / 3 - t) * 6 end
+ return p
+ end
+
+ local r, g, b
+ if s == 0 then
+ r, g, b = l, l, l
+ else
+ local q = l < 0.5 and l * (1 + s) or l + s - l * s
+ local p = 2 * l - q
+ r = hue_to_rgb(p, q, h + 1 / 3)
+ g = hue_to_rgb(p, q, h)
+ b = hue_to_rgb(p, q, h - 1 / 3)
+ end
+
+ return math.floor(r * 255 + 0.5),
+ math.floor(g * 255 + 0.5),
+ math.floor(b * 255 + 0.5)
+end
+
+--- Darken or lighten a hex color via HSL lightness while preserving hue/saturation.
+--- Positive `lightness_factor` lightens, negative darkens.
+---@param hex string hex color (#RRGGBB)
+---@param lightness_factor number
+---@return string
+function M.darken_hsl(hex, lightness_factor)
+ lightness_factor = lightness_factor or 0.0
+ local h = normalize_hex(hex)
+ if not h then return 'NONE' end
+ local r = tonumber(h:sub(1, 2), 16)
+ local g = tonumber(h:sub(3, 4), 16)
+ local b = tonumber(h:sub(5, 6), 16)
+ if not r or not g or not b then return 'NONE' end
+
+ local hh, ss, ll = rgb_to_hsl(r, g, b)
+
+ if lightness_factor > 0 then
+ ll = ll + (1 - ll) * lightness_factor
+ else
+ ll = ll * (1 + lightness_factor)
+ end
+
+ ll = math.min(math.max(ll, 0), 1)
+ r, g, b = hsl_to_rgb(hh, ss, ll)
+ return fmt('#%02x%02x%02x', r, g, b)
+end
+
-- }}}
--------------------------------------------------------------------------------
--- String utilities {{{
+--------------------------------------------------------------------------------
+-- UI {{{
+--------------------------------------------------------------------------------
----Truncate a string to a maximum length
----@param str string
----@param max_len integer
+---@class UI
+M.ui = {}
+
+-- Icons {{{
+
+M.ui.icons = {
+ separators = {
+ left_thin_block = '▏',
+ right_thin_block = '▕',
+ vert_bottom_half_block = '▄',
+ vert_top_half_block = '▀',
+ right_block = '🮉',
+ light_shade_block = '░',
+ right_chubby_block = '▓',
+ },
+ scrollbar = '█',
+ lsp = {
+ error = '', -- '✗'
+ warn = '', --
+ info = '', -- ℹ
+ hint = '', -- ⚑
+ },
+ git = {
+ add = '',
+ mod = '',
+ remove = '',
+ ignore = '',
+ rename = '',
+ untracked = '',
+ ignored = '',
+ unstaged = '',
+ staged = '',
+ conflict = '',
+ diff = '',
+ repo = '',
+ logo = '',
+ branch = '',
+ },
+ documents = {
+ file = '',
+ files = '',
+ folder = '',
+ open_folder = '',
+ },
+ misc = {
+ plus = '',
+ ellipsis = '…',
+ up = '⇡',
+ down = '⇣',
+ line = '',
+ indent = 'Ξ',
+ tab = '⇥',
+ bug = '',
+ question = '',
+ clock = '',
+ cmd = '⌘',
+ lock = '',
+ shaded_lock = '',
+ circle = '',
+ project = '',
+ dashboard = '',
+ history = '',
+ comment = '',
+ robot = '',
+ copilot = '',
+ lightbulb = '',
+ search = '',
+ code = '',
+ telescope = '',
+ gear = '',
+ chat = '',
+ package = '',
+ list = '',
+ sign_in = '',
+ check = '',
+ fire = '',
+ note = '',
+ bookmark = '',
+ pencil = '',
+ tools = '',
+ arrow_right = '',
+ caret_right = '',
+ chevron_right = '',
+ double_chevron_right = '»',
+ table = '',
+ calendar = '',
+ block = '▏',
+ clippy = '',
+ puzzle = '',
+ settings = '⚙',
+ key = '',
+ config = '',
+ box = '',
+ moon = '',
+ source = '',
+ sleep = '',
+ rocket = '',
+ task = '',
+ runtime = '',
+ },
+}
+
+-- }}}
+
+-- Palette {{{
+
+-- Mutated in-place so modules holding a reference keep seeing updates.
+M.ui.palette = {}
+
+local function hex_from_hl(name, attr, fallback)
+ local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name, link = false })
+ if not ok or not hl then return fallback end
+ local v = hl[attr]
+ if not v then return fallback end
+ return ('#%06x'):format(v)
+end
+
+local function palette_tint(color, percent)
+ local ok = type(color) == 'string' and color:match('^#%x%x%x%x%x%x$')
+ if not ok then return color end
+ local r = tonumber(color:sub(2, 3), 16)
+ local g = tonumber(color:sub(4, 5), 16)
+ local b = tonumber(color:sub(6, 7), 16)
+ local function blend(component)
+ component = math.floor(component * (1 + percent))
+ return math.min(math.max(component, 0), 255)
+ end
+ return ('#%02x%02x%02x'):format(blend(r), blend(g), blend(b))
+end
+
+local function get_nightfox_palette()
+ local ok, nightfox_palette = pcall(require, 'nightfox.palette')
+ if not ok or not nightfox_palette or not nightfox_palette.load then
+ return nil
+ end
+ return nightfox_palette.load(vim.g.colors_name or 'carbonfox')
+end
+
+local function as_hex(v, fallback)
+ if type(v) == 'string' then return v end
+ if type(v) == 'number' then return ('#%06x'):format(v) end
+ if type(v) == 'table' then
+ if type(v.base) == 'string' then return v.base end
+ if vim.is_callable(v) then
+ local ok, res = pcall(v)
+ if ok then
+ if type(res) == 'string' then return res end
+ if type(res) == 'number' then return ('#%06x'):format(res) end
+ end
+ end
+ end
+ return fallback
+end
+
+--- Refresh the palette from the active colorscheme.
+function M.ui.refresh_palette()
+ local palette = M.ui.palette
+ local defaults = {
+ green = '#98c379',
+ dark_green = '#10B981',
+ blue = '#82AAFE',
+ dark_blue = '#4e88ff',
+ bright_blue = '#51afef',
+ teal = '#15AABF',
+ pale_pink = '#b490c0',
+ magenta = '#c678dd',
+ red = '#E06C75',
+ pale_red = '#E06C75',
+ light_red = '#c43e1f',
+ dark_red = '#be5046',
+ dark_orange = '#FF922B',
+ bright_yellow = '#FAB005',
+ light_yellow = '#e5c07b',
+ whitesmoke = '#9E9E9E',
+ light_gray = '#626262',
+ comment_grey = '#5c6370',
+ grey = '#3E4556',
+ }
+
+ local pal = get_nightfox_palette()
+ local derived = {}
+
+ if pal then
+ derived.green = as_hex(pal.green, defaults.green)
+ derived.blue = as_hex(pal.blue, defaults.blue)
+ derived.teal = as_hex(pal.cyan or pal.teal, defaults.teal)
+ derived.magenta = as_hex(pal.magenta, defaults.magenta)
+ derived.pale_pink = as_hex(pal.pink or pal.magenta, defaults.pale_pink)
+ derived.pale_red = as_hex(pal.red, defaults.pale_red)
+ derived.red = hex_from_hl('GitSignsDelete', 'fg', pal.red or defaults.red)
+ derived.dark_orange = as_hex(pal.orange, defaults.dark_orange)
+ derived.bright_yellow = as_hex(pal.yellow, defaults.bright_yellow)
+ derived.light_yellow = as_hex(pal.yellow, defaults.light_yellow)
+ derived.comment_grey = as_hex(pal.comment or pal.fg3, defaults.comment_grey)
+ derived.whitesmoke = as_hex(pal.fg1 or pal.fg0, defaults.whitesmoke)
+ derived.light_gray = as_hex(pal.fg3, defaults.light_gray)
+ derived.grey = as_hex(pal.bg3 or pal.bg2, defaults.grey)
+ else
+ derived.pale_red = hex_from_hl('DiagnosticError', 'fg', defaults.pale_red)
+ derived.red =
+ hex_from_hl('GitSignsDelete', 'fg', derived.pale_red or defaults.red)
+ derived.dark_orange =
+ hex_from_hl('DiagnosticWarn', 'fg', defaults.dark_orange)
+ derived.teal = hex_from_hl('DiagnosticInfo', 'fg', defaults.teal)
+ derived.bright_blue =
+ hex_from_hl('DiagnosticHint', 'fg', defaults.bright_blue)
+ derived.green = hex_from_hl('GitSignsAdd', 'fg', defaults.green)
+ derived.blue = hex_from_hl('Function', 'fg', defaults.blue)
+ derived.magenta = hex_from_hl('Statement', 'fg', defaults.magenta)
+ derived.pale_pink = hex_from_hl('Special', 'fg', defaults.pale_pink)
+ derived.bright_yellow =
+ hex_from_hl('WarningMsg', 'fg', defaults.bright_yellow)
+ derived.light_yellow = derived.bright_yellow
+ derived.comment_grey = hex_from_hl('Comment', 'fg', defaults.comment_grey)
+ derived.whitesmoke = hex_from_hl('Normal', 'fg', defaults.whitesmoke)
+ derived.light_gray = palette_tint(derived.comment_grey, 0.1)
+ derived.grey =
+ palette_tint(hex_from_hl('Normal', 'bg', defaults.grey), 0.15)
+ end
+
+ derived.dark_green = palette_tint(derived.green, -0.25)
+ derived.dark_blue = palette_tint(derived.blue, -0.25)
+ derived.light_red = palette_tint(derived.pale_red, -0.15)
+ derived.dark_red = palette_tint(derived.pale_red, -0.30)
+
+ for k in pairs(palette) do
+ palette[k] = nil
+ end
+ for k, v in pairs(defaults) do
+ palette[k] = derived[k] or v
+ end
+ for k, v in pairs(derived) do
+ palette[k] = v
+ end
+
+ -- Keep LSP colors in sync
+ local lsp = M.ui.lsp
+ if lsp and lsp.colors then
+ lsp.colors.error = palette.pale_red
+ lsp.colors.warn = palette.dark_orange
+ lsp.colors.hint = palette.bright_blue
+ lsp.colors.info = palette.teal
+ end
+end
+
+vim.api.nvim_create_autocmd('ColorScheme', {
+ group = vim.api.nvim_create_augroup('UIPalette', { clear = true }),
+ callback = function() M.ui.refresh_palette() end,
+})
+vim.schedule(M.ui.refresh_palette)
+
+-- }}}
+
+-- LSP {{{
+
+M.ui.lsp = {
+ colors = {
+ error = M.ui.palette.pale_red,
+ warn = M.ui.palette.dark_orange,
+ hint = M.ui.palette.bright_blue,
+ info = M.ui.palette.teal,
+ },
+ highlights = {
+ File = 'Directory',
+ Snippet = 'Label',
+ Text = '@string',
+ Method = '@method',
+ Function = '@function',
+ Constructor = '@constructor',
+ Field = '@field',
+ Variable = '@variable',
+ Module = '@namespace',
+ Property = '@property',
+ Unit = '@constant',
+ Value = '@variable',
+ Enum = '@type',
+ Keyword = '@keyword',
+ Reference = '@parameter.reference',
+ Constant = '@constant',
+ Struct = '@structure',
+ Event = '@variable',
+ Operator = '@operator',
+ Namespace = '@namespace',
+ Package = '@include',
+ String = '@string',
+ Number = '@number',
+ Boolean = '@boolean',
+ Array = '@repeat',
+ Object = '@type',
+ Key = '@field',
+ Null = '@symbol',
+ EnumMember = '@field',
+ Class = '@lsp.type.class',
+ Interface = '@lsp.type.interface',
+ TypeParameter = '@lsp.type.parameter',
+ },
+}
+
+-- }}}
+
+-- Border & floats {{{
+
+M.ui.border = 'rounded'
+
+M.ui.current = {
+ border = 'rounded',
+ float_bg = function()
+ local ok, HL = pcall(require, 'highlight')
+ if ok and HL and HL.get then return HL.get('Normal', 'bg') end
+ local ok2, hl =
+ pcall(vim.api.nvim_get_hl, 0, { name = 'Normal', link = false })
+ if ok2 and hl and hl.bg then return ('#%06x'):format(hl.bg) end
+ return 'NONE'
+ end,
+}
+
+-- }}}
+
+-- Decorations {{{
+
+---@class Decorations
+---@field winbar 'ignore' | boolean
+---@field number boolean
+---@field statusline 'minimal' | boolean
+---@field statuscolumn boolean
+---@field colorcolumn boolean | string
+
+---@alias DecorationType 'statuscolumn'|'winbar'|'statusline'|'number'|'colorcolumn'
+
+local Preset = {}
+function Preset:new(o)
+ assert(o, 'a preset must be defined')
+ self.__index = self
+ return setmetatable(o, self)
+end
+function Preset:with(o) return vim.tbl_deep_extend('force', self, o) end
+
+local presets = {
+ statusline_only = Preset:new({
+ number = false,
+ winbar = false,
+ colorcolumn = false,
+ statusline = true,
+ statuscolumn = false,
+ }),
+ minimal_editing = Preset:new({
+ number = false,
+ winbar = true,
+ colorcolumn = false,
+ statusline = 'minimal',
+ statuscolumn = false,
+ }),
+ tool_panel = Preset:new({
+ number = false,
+ winbar = false,
+ colorcolumn = false,
+ statusline = 'minimal',
+ statuscolumn = false,
+ }),
+}
+
+local commit_buffer =
+ presets.minimal_editing:with({ colorcolumn = '50,72', winbar = false })
+
+local buftypes = {
+ ['quickfix'] = presets.tool_panel,
+ ['nofile'] = presets.tool_panel,
+ ['nowrite'] = presets.tool_panel,
+ ['acwrite'] = presets.tool_panel,
+ ['terminal'] = presets.tool_panel,
+ ['.*fugitive.*'] = presets.tool_panel,
+}
+
+local filetypes = M.p_table({
+ ['startuptime'] = presets.tool_panel,
+ ['checkhealth'] = presets.tool_panel,
+ ['log'] = presets.tool_panel,
+ ['help'] = presets.tool_panel,
+ ['^copilot.*'] = presets.tool_panel,
+ ['dbout'] = presets.tool_panel,
+ ['dbui'] = presets.tool_panel,
+ ['dapui'] = presets.tool_panel,
+ ['minimap'] = presets.tool_panel,
+ ['Trouble'] = presets.tool_panel,
+ ['tsplayground'] = presets.tool_panel,
+ ['list'] = presets.tool_panel,
+ ['netrw'] = presets.tool_panel,
+ ['flutter.*'] = presets.tool_panel,
+ ['NvimTree'] = presets.tool_panel,
+ ['undotree'] = presets.tool_panel,
+ ['dap-repl'] = presets.tool_panel:with({ winbar = 'ignore' }),
+ ['neo-tree'] = presets.tool_panel:with({ winbar = 'ignore' }),
+ ['toggleterm'] = presets.tool_panel:with({ winbar = 'ignore' }),
+ ['neotest.*'] = presets.tool_panel,
+ ['^Neogit.*'] = presets.tool_panel,
+ ['.*fugitive.*'] = presets.tool_panel,
+ ['query'] = presets.tool_panel,
+ ['DiffviewFiles'] = presets.tool_panel,
+ ['DiffviewFileHistory'] = presets.tool_panel,
+ ['mail'] = presets.statusline_only,
+ ['noice'] = presets.statusline_only,
+ ['diff'] = presets.statusline_only,
+ ['qf'] = presets.statusline_only,
+ ['alpha'] = presets.tool_panel:with({ statusline = false }),
+ ['fugitive'] = presets.statusline_only,
+ ['startify'] = presets.statusline_only,
+ ['man'] = presets.minimal_editing,
+ ['org'] = presets.minimal_editing:with({ winbar = false }),
+ ['norg'] = presets.minimal_editing:with({ winbar = false }),
+ ['orgagenda'] = presets.minimal_editing:with({ winbar = false }),
+ ['markdown'] = presets.minimal_editing,
+ ['himalaya'] = presets.minimal_editing,
+ ['gitcommit'] = commit_buffer,
+ ['NeogitCommitMessage'] = commit_buffer,
+})
+
+local filenames = M.p_table({
+ ['option-window'] = presets.tool_panel,
+})
+
+M.ui.decorations = {}
+
+---Get the decoration setting for a buffer.
+---@param opts {ft: string?, bt: string?, fname: string?, setting: DecorationType}
+---@return {ft: any, bt: any, fname: any}?
+function M.ui.decorations.get(opts)
+ local ft, bt, fname, setting = opts.ft, opts.bt, opts.fname, opts.setting
+ if (not ft and not bt and not fname) or not setting then return nil end
+ return {
+ ft = ft and filetypes[ft] and filetypes[ft][setting],
+ bt = bt and buftypes[bt] and buftypes[bt][setting],
+ fname = fname and filenames[fname] and filenames[fname][setting],
+ }
+end
+
+---Set the colorcolumn for a buffer according to filetype/buftype decoration rules.
+---@param bufnr integer
+---@param fn fun(virtcolumn: string)
+function M.ui.decorations.set_colorcolumn(bufnr, fn)
+ local buf = vim.bo[bufnr]
+ local decor = M.ui.decorations.get({
+ ft = buf.ft,
+ bt = buf.bt,
+ setting = 'colorcolumn',
+ })
+ if buf.ft == '' or buf.bt ~= '' or decor.ft == false or decor.bt == false then
+ return
+ end
+ local ccol = decor.ft or decor.bt or ''
+ local virtcolumn = not M.falsy(ccol) and ccol or '+1'
+ if vim.is_callable(fn) then fn(virtcolumn) end
+end
+
+-- }}}
+
+-- }}}
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+-- Statusline strings {{{
+--------------------------------------------------------------------------------
+
+---@alias StringComponent {component: string, length: integer, priority: integer}
+---@alias Chunks {[1]: string | number, [2]: string, max_size: integer?}[]
+
+local CLICK_END = '%X'
+
+local function sl_separator()
+ return { component = '%=', length = 0, priority = 0 }
+end
+
+local function sl_get_click_start(func_name, id)
+ if not id then
+ vim.schedule(
+ function()
+ vim.notify_once(
+ fmt('An ID is needed to enable click handler %s to work', func_name),
+ vim.log.levels.ERROR,
+ { title = 'Statusline' }
+ )
+ end
+ )
+ return ''
+ end
+ return ('%%%d@%s@'):format(id, func_name)
+end
+
+local function sl_normalize_chunks(chunks)
+ if type(chunks) ~= 'table' then return end
+ if vim.islist(chunks) then return chunks end
+ local keys = {}
+ for k in pairs(chunks) do
+ if type(k) == 'number' and k >= 1 and math.floor(k) == k then
+ keys[#keys + 1] = k
+ end
+ end
+ if #keys == 0 then return end
+ table.sort(keys)
+ local dense = {}
+ for _, k in ipairs(keys) do
+ local v = chunks[k]
+ if v ~= nil then dense[#dense + 1] = v end
+ end
+ return dense
+end
+
+local function sl_truncate_string(str, max_size)
+ if not max_size or vim.api.nvim_strwidth(str) < max_size then return str end
+ local match, count = str:gsub('([\'"]).*%1', '%1…%1')
+ return count > 0 and match or str:sub(1, max_size - 1) .. '…'
+end
+
+local function sl_chunks_to_string(chunks)
+ chunks = sl_normalize_chunks(chunks)
+ if not chunks then return '' end
+ local strings = {}
+ for _, item in ipairs(chunks) do
+ local text, hl = unpack(item)
+ if not M.falsy(text) then
+ if type(text) ~= 'string' then text = tostring(text) end
+ if item.max_size then text = sl_truncate_string(text, item.max_size) end
+ text = text:gsub('%%', '%%%1')
+ strings[#strings + 1] = not M.falsy(hl)
+ and ('%%#%s#%s%%*'):format(hl, text)
+ or text
+ end
+ end
+ return table.concat(strings, '')
+end
+
+--- @class ComponentOpts
+--- @field [1] Chunks
+--- @field priority number
+--- @field click string
+--- @field before string
+--- @field after string
+--- @field id number
+--- @field max_size integer
+--- @field cond boolean | number | table | string
+
+local function sl_component(opts)
+ assert(opts, 'component options are required')
+ if opts.cond ~= nil and M.falsy(opts.cond) then return end
+
+ local item = sl_normalize_chunks(opts[1])
+ if not item then
+ error(
+ fmt(
+ 'component options are required but got %s instead',
+ vim.inspect(opts[1])
+ )
+ )
+ end
+
+ if not opts.priority then opts.priority = 10 end
+
+ local item_str = sl_chunks_to_string(item)
+ if vim.api.nvim_strwidth(item_str) == 0 then return end
+
+ local click_start = opts.click
+ and sl_get_click_start(opts.click, tostring(opts.id))
+ or ''
+ local click_end = opts.click and CLICK_END or ''
+ local component_str =
+ table.concat({ click_start, '', item_str, '', click_end })
+ return {
+ component = component_str,
+ length = api.nvim_eval_statusline(component_str, { maxwidth = 0 }).width,
+ priority = opts.priority,
+ }
+end
+
+local function sl_sum_lengths(list)
+ return M.fold(
+ function(acc, item) return acc + (item.length or 0) end,
+ list,
+ 0
+ )
+end
+
+local function sl_is_lowest(item, lowest)
+ if not lowest or not lowest.length then return true end
+ if not item.priority or not item.length then return false end
+ if item.priority == lowest.priority then
+ return item.length > lowest.length
+ end
+ return item.priority > lowest.priority
+end
+
+local function sl_prioritize(statusline, space, length)
+ length = length or sl_sum_lengths(statusline)
+ if length <= space then return statusline end
+ local lowest, index_to_remove
+ for idx, c in ipairs(statusline) do
+ if sl_is_lowest(c, lowest) then
+ lowest, index_to_remove = c, idx
+ end
+ end
+ table.remove(statusline, index_to_remove)
+ return sl_prioritize(statusline, space, length - lowest.length)
+end
+
+M.strings = {}
+
+--- Creates a spacer statusline component.
+---@param size integer?
+---@param opts table?
+---@return ComponentOpts?
+function M.strings.spacer(size, opts)
+ opts = opts or {}
+ local filler = opts.filler or ' '
+ local priority = opts.priority or 0
+ if not size or size < 1 then return end
+ return {
+ { { string.rep(filler, size) } },
+ priority = priority,
+ before = '',
+ after = '',
+ }
+end
+
+--- Render a list of sections into a statusline string, dropping lowest-priority
+--- components when space is constrained.
+---@param sections ComponentOpts[][]
+---@param available_space number?
---@return string
-function mrl.truncate(str, max_len)
- assert(str and max_len, 'string and max_len must be provided')
- return api.nvim_strwidth(str) > max_len
- and str:sub(1, max_len) .. mrl.ui.icons.misc.ellipsis
- or str
+function M.strings.display(sections, available_space)
+ local components = M.fold(function(acc, section, count)
+ if #section == 0 then
+ table.insert(acc, sl_separator())
+ return acc
+ end
+ M.foreach(function(args, index)
+ if not args then return end
+ local ok, str = M.pcall('Error creating component', sl_component, args)
+ if not ok then return end
+ table.insert(acc, str)
+ if #section == index and count ~= #sections then
+ table.insert(acc, sl_separator())
+ end
+ end, section)
+ return acc
+ end, sections)
+
+ local items = available_space and sl_prioritize(components, available_space)
+ or components
+ local str = vim.tbl_map(function(item) return item.component end, items)
+ return table.concat(str)
+end
+
+--- Section helper: collects StringComponents and supports `+` concatenation.
+---@class Section
+---@field new fun(...:StringComponent[]): Section
+local section = {}
+function section:new(...)
+ local o = { ... }
+ self.__index = self
+ self.__add = function(l, r)
+ local rt = { unpack(l) }
+ for _, v in ipairs(r) do
+ rt[#rt + 1] = v
+ end
+ return rt
+ end
+ return setmetatable(o, self)
end
+M.strings.section = section
+
-- }}}
+--------------------------------------------------------------------------------
+
+return M
+
+-- vim:fdm=marker
diff --git a/files/.config/nvim/plugin/autocommands.lua b/files/.config/nvim/plugin/autocommands.lua
index 6f8fc83d..e5af403b 100644
--- a/files/.config/nvim/plugin/autocommands.lua
+++ b/files/.config/nvim/plugin/autocommands.lua
@@ -1,78 +1,6 @@
-if not mrl then return end
-
--- Helper to safely call augroup, deferring if not available yet
-local function augroup(name, ...)
- local args = { ... }
- if mrl and mrl.augroup then
- return mrl.augroup(name, unpack(args))
- else
- -- Defer until augroup is available
- vim.schedule(function()
- if mrl and mrl.augroup then mrl.augroup(name, unpack(args)) end
- end)
- end
-end
+local augroup = require('tools').augroup
-local fn, api, v, env, cmd, fmt =
- vim.fn, vim.api, vim.v, vim.env, vim.cmd, string.format
-
--- -----------------------------------------------------------------------------
--- Performance-sensitive: avoid heavy Vimscript in init.lua
--- -----------------------------------------------------------------------------
-
--- Highlight lines starting with '##' (headings) using a lightweight sign group.
--- This replaces the old Vimscript that unplaced/placed signs across 1000 ids.
--- do
--- local group = api.nvim_create_augroup('HeadingLineSign', { clear = true })
--- local sign_name = 'highlightline'
--- local sign_group = 'headingline'
--- local debounce_ms = 120
--- local pending = {} ---@type table
---
--- -- Define sign once (safe to call multiple times).
--- pcall(fn.sign_define, sign_name, { linehl = 'Match' })
---
--- local function update(bufnr)
--- if not api.nvim_buf_is_valid(bufnr) then return end
--- if vim.bo[bufnr].buftype ~= '' then return end
---
--- local ft = vim.bo[bufnr].filetype
--- if ft ~= 'markdown' and ft ~= 'org' and ft ~= 'norg' then return end
---
--- pcall(fn.sign_unplace, sign_group, { buffer = bufnr })
---
--- local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
--- for i, line in ipairs(lines) do
--- if line:match('^%s*##') then
--- -- id=0 lets Vim allocate IDs; placing is scoped to sign_group+buffer.
--- pcall(fn.sign_place, 0, sign_group, sign_name, bufnr, {
--- lnum = i,
--- priority = 10,
--- })
--- end
--- end
--- end
---
--- local function schedule(bufnr)
--- if pending[bufnr] then
--- pending[bufnr]:stop()
--- pending[bufnr]:close()
--- pending[bufnr] = nil
--- end
--- pending[bufnr] = vim.defer_fn(function()
--- pending[bufnr] = nil
--- update(bufnr)
--- end, debounce_ms)
--- end
---
--- api.nvim_create_autocmd(
--- { 'BufWinEnter', 'TextChanged', 'TextChangedI', 'TextChangedP' },
--- {
--- group = group,
--- callback = function(args) schedule(args.buf) end,
--- }
--- )
--- end
+local fn, api, v, cmd = vim.fn, vim.api, vim.v, vim.cmd
-- Better terminal UX inside fzf-lua: allow Esc to abort.
api.nvim_create_autocmd('FileType', {
@@ -94,7 +22,6 @@ do
local function disable(buf)
if not api.nvim_buf_is_valid(buf) then return end
- -- Common plugin conventions:
vim.b[buf].miniindentscope_disable = true
vim.b[buf].ibl_disable = true
vim.b[buf].indent_blankline_enabled = false
@@ -105,7 +32,6 @@ do
callback = function(args) disable(args.buf) end,
})
- -- Some terminal plugins use a FileType instead of buftype checks.
api.nvim_create_autocmd('FileType', {
group = group,
pattern = { 'toggleterm', 'terminal' },
@@ -128,25 +54,23 @@ do
local win = api.nvim_get_current_win()
if not api.nvim_win_is_valid(win) then return end
- api.nvim_win_call(win, function()
- vim.opt_local.winhighlight:append({
- -- Force terminal windows to inherit the main editor background.
- Normal = 'Normal',
- NormalNC = 'NormalNC',
- -- For floating terminal windows, ensure the float "Normal" maps to Normal too.
- NormalFloat = 'Normal',
- })
- end)
+ api.nvim_win_call(
+ win,
+ function()
+ vim.opt_local.winhighlight:append({
+ Normal = 'Normal',
+ NormalNC = 'NormalNC',
+ NormalFloat = 'Normal',
+ })
+ end
+ )
end
- -- Apply early, but also re-apply on WinEnter since some plugins set winhighlight
- -- after opening (Sidekick/toggleterm/etc).
api.nvim_create_autocmd(
{ 'TermOpen', 'BufWinEnter', 'BufEnter', 'WinEnter' },
{
group = group,
callback = function(args)
- -- Defer one tick so we win over later winhighlight setters.
vim.schedule(function() apply_terminal_winhighlight(args.buf) end)
end,
}
@@ -162,8 +86,6 @@ do
end
-- Highlight when yanking (copying) text
--- Try it with `yap` in normal mode
--- See `:help vim.highlight.on_yank()`
vim.api.nvim_create_autocmd('TextYankPost', {
desc = 'Highlight when yanking (copying) text',
group = vim.api.nvim_create_augroup(
@@ -175,7 +97,7 @@ vim.api.nvim_create_autocmd('TextYankPost', {
local function stop_hl()
if v.hlsearch == 0 or api.nvim_get_mode().mode ~= 'n' then return end
- vim.api.nvim_feedkeys(vim.keycode('(StopHL)'), 'm', false)
+ vim.cmd('nohlsearch')
end
local function hl_search()
@@ -184,7 +106,6 @@ local function hl_search()
local ok, match = pcall(fn.matchstrpos, curr_line, fn.getreg('/'), 0)
if not ok then return end
local _, p_start, p_end = unpack(match)
- -- if the cursor is in a search result, leave highlighting on
if col < p_start or col > p_end then stop_hl() end
end
@@ -202,66 +123,20 @@ augroup('VimrcIncSearchHighlight', {
end,
}, {
event = 'RecordingEnter',
- command = function() vim.o.hlsearch = false end,
-}, {
- event = 'RecordingLeave',
- command = function() vim.o.hlsearch = true end,
-})
-
--- Search highlighting {{{
-
-----------------------------------------------------------------------------------------------------
--- HLSEARCH
-----------------------------------------------------------------------------------------------------
--- In order to get hlsearch working the way I like i.e. on when using /,?,N,n,*,#, etc. and off when
--- When I'm not using them, I need to set the following:
--- The mappings below are essentially faked user input this is because in order to automatically turn off
--- the search highlight just changing the value of 'hlsearch' inside a function does not work
--- read `:h nohlsearch`. So to have this workaround I check that the current mouse position is not a search
--- result, if it is we leave highlighting on, otherwise I turn it off on cursor moved by faking my input
--- using the expr mappings below.
---
--- This is based on the implementation discussed here:
--- https://github.com/neovim/neovim/issues/5581
-
-vim.keymap.set(
- { 'n', 'v', 'o', 'i', 'c' },
- '(StopHL)',
- 'execute("nohlsearch")[-1]',
- { expr = true }
-)
-
-local function stop_hl()
- if v.hlsearch == 0 or api.nvim_get_mode().mode ~= 'n' then return end
- api.nvim_feedkeys(vim.keycode('(StopHL)'), 'm', false)
-end
-
--- REMOVED DUPLICATE: This function and autocmd group was already defined above (lines 180-209)
--- Duplicate removed to fix scrolling lag caused by double CursorMoved events
-
--- }}}
-
--- Recording macro {{{
-
-vim.api.nvim_create_autocmd('RecordingEnter', {
- pattern = '*',
- callback = function()
+ command = function()
+ vim.o.hlsearch = false
vim.g.macro_recording = 'macro @' .. vim.fn.reg_recording()
vim.cmd('redrawstatus')
end,
-})
-
--- Autocmd to track the end of macro recording
-vim.api.nvim_create_autocmd('RecordingLeave', {
- pattern = '*',
- callback = function()
+}, {
+ event = 'RecordingLeave',
+ command = function()
+ vim.o.hlsearch = true
vim.g.macro_recording = ''
vim.cmd('redrawstatus')
end,
})
--- }}}
-
augroup('UpdateVim', {
event = { 'FocusLost' },
pattern = { '*' },
@@ -269,7 +144,7 @@ augroup('UpdateVim', {
}, {
event = { 'VimResized' },
pattern = { '*' },
- command = 'wincmd =', -- Make windows equal size when vim resizes
+ command = 'wincmd =',
})
-- -----------------------------------------------------------------------------
@@ -320,19 +195,16 @@ do
if fn.winnr('$') ~= 1 then
api.nvim_win_close(0, true)
else
- -- If it's the last window, delete the buffer instead.
pcall(cmd.bdelete, { 0, bang = true })
end
end
- -- Auto open quickfix after grep-like commands.
api.nvim_create_autocmd('QuickFixCmdPost', {
group = group,
pattern = '*grep*',
command = 'cwindow',
})
- -- Close certain filetypes by pressing q.
api.nvim_create_autocmd('FileType', {
group = group,
callback = function(args)
@@ -355,7 +227,6 @@ do
end,
})
- -- Close quickfix buffer if it's the only remaining window.
api.nvim_create_autocmd('BufEnter', {
group = group,
callback = function()
@@ -365,7 +236,6 @@ do
end,
})
- -- Close location list when quitting a window.
api.nvim_create_autocmd('QuitPre', {
group = group,
nested = true,
@@ -400,7 +270,6 @@ do
local path = api.nvim_buf_get_name(bufnr)
if path == '' then return false end
- -- Always allow formatting in your own code/config.
local allow_prefixes = {
vim.g.personal_directory,
vim.g.work_directory,
@@ -410,20 +279,16 @@ do
}
for _, p in ipairs(allow_prefixes) do
if p and startswith(path, p) then
- -- Don't blanket-allow HOME; only use it to prevent disabling on empty vars.
- -- If you want stricter behavior, remove HOME from this list.
if p ~= vim.env.HOME then return false end
end
end
- -- Disable formatting in runtime/plugin directories.
if vim.env.VIMRUNTIME and startswith(path, vim.env.VIMRUNTIME) then
return true
end
for _, dir in ipairs(vim.split(vim.o.runtimepath, ',', { plain = true })) do
if dir ~= '' and startswith(path, dir) then
- -- Never disable in your actual config path.
if vim.g.vim_dir and startswith(path, vim.g.vim_dir) then
return false
end
@@ -493,7 +358,7 @@ do
})
end
--- Auto create dir when saving a file, in case some intermediate directory does not exist
+-- Auto create dir when saving a file
vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
group = vim.api.nvim_create_augroup('AutoCreateDir', { clear = true }),
callback = function(event)
@@ -511,136 +376,7 @@ vim.api.nvim_create_autocmd({ 'FocusGained', 'TermClose', 'TermLeave' }, {
end,
})
--- LSP inline diagnostics {{{
---
--- local function best_diagnostic(diagnostics)
--- if vim.tbl_isempty(diagnostics) then
--- return
--- end
---
--- local best = nil
--- local line_diagnostics = {}
--- local line_nr = vim.api.nvim_win_get_cursor(0)[1] - 1
---
--- for k, v in pairs(diagnostics) do
--- if v.lnum == line_nr then
--- line_diagnostics[k] = v
--- end
--- end
---
--- for _, diagnostic in ipairs(line_diagnostics) do
--- if best == nil then
--- best = diagnostic
--- elseif diagnostic.severity < best.severity then
--- best = diagnostic
--- end
--- end
---
--- return best
--- end
---
--- local function current_line_diagnostics()
--- local bufnr = 0
--- local line_nr = vim.api.nvim_win_get_cursor(0)[1] - 1
--- local opts = { ["lnum"] = line_nr }
---
--- return vim.diagnostic.get(bufnr, opts)
--- end
---
--- local signs = {
--- Error = " ",
--- Warn = " ",
--- Hint = " ",
--- Info = " ",
--- }
---
--- local virt_handler = vim.diagnostic.handlers.virtual_text
--- local ns = vim.api.nvim_create_namespace "current_line_virt"
--- local severity = vim.diagnostic.severity
--- local virt_options = {
--- prefix = "",
--- format = function(diagnostic)
--- local message = vim.split(diagnostic.message, "\n")[1]
---
--- if diagnostic.severity == severity.ERROR then
--- return signs.Error .. message
--- elseif diagnostic.severity == severity.INFO then
--- return signs.Info .. message
--- elseif diagnostic.severity == severity.WARN then
--- return signs.Warn .. message
--- elseif diagnostic.severity == severity.HINT then
--- return signs.Hint .. message
--- else
--- return message
--- end
--- end,
--- }
---
--- vim.diagnostic.handlers.current_line_virt = {
--- show = function(_, bufnr, diagnostics, _)
--- local diagnostic = best_diagnostic(diagnostics)
--- if not diagnostic then
--- return
--- end
---
--- local filtered_diagnostics = { diagnostic }
---
--- pcall(
--- virt_handler.show,
--- ns,
--- bufnr,
--- filtered_diagnostics,
--- { virtual_text = virt_options }
--- )
--- end,
--- hide = function(_, bufnr)
--- bufnr = bufnr or vim.api.nvim_get_current_buf()
--- virt_handler.hide(ns, bufnr)
--- end,
--- }
---
--- vim.diagnostic.config {
--- float = { source = "always" },
--- signs = false,
--- virtual_text = false,
--- severity_sort = true,
--- current_line_virt = true,
--- }
---
--- vim.api.nvim_create_augroup("lsp_diagnostic_current_line", {
--- clear = true,
--- })
---
---
--- vim.api.nvim_clear_autocmds {
--- buffer = bufnr,
--- group = "lsp_diagnostic_current_line",
--- }
---
--- vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
--- group = "lsp_diagnostic_current_line",
--- buffer = bufnr,
--- callback = function()
--- vim.diagnostic.handlers.current_line_virt.show(
--- nil,
--- 0,
--- current_line_diagnostics(),
--- nil
--- )
--- end,
--- })
---
--- vim.api.nvim_create_autocmd("CursorMoved", {
--- group = "lsp_diagnostic_current_line",
--- buffer = bufnr,
--- callback = function()
--- vim.diagnostic.handlers.current_line_virt.hide(nil, nil)
--- end,
--- })
-
--- }}}
-
--- Cursorline only in active window (Folke's pattern)
+-- Cursorline only in active window
vim.api.nvim_create_autocmd({ 'InsertLeave', 'WinEnter' }, {
callback = function()
if vim.w.auto_cursorline then
@@ -658,34 +394,51 @@ vim.api.nvim_create_autocmd({ 'InsertEnter', 'WinLeave' }, {
end,
})
--- Disable statuscolumn and other columns in floating windows
+-- Disable statuscolumn/signcolumn/foldcolumn in floating windows and tool panels.
do
- local group = vim.api.nvim_create_augroup('DisableColumnsInFloats', { clear = true })
-
- local function disable_columns_in_float()
- local win = vim.api.nvim_get_current_win()
- local win_config = vim.api.nvim_win_get_config(win)
- if win_config.relative ~= '' then
- -- This is a floating window - disable all column decorations
- vim.wo[win].statuscolumn = ''
- vim.wo[win].signcolumn = 'no'
- vim.wo[win].foldcolumn = '0'
- vim.wo[win].number = false
- vim.wo[win].relativenumber = false
- end
+ local group =
+ vim.api.nvim_create_augroup('DisableColumnsInFloats', { clear = true })
+
+ local no_number_filetypes = {
+ 'lazy',
+ 'mason',
+ 'noice',
+ 'notify',
+ 'trouble',
+ 'aerial',
+ 'dap-repl',
+ 'dapui_console',
+ 'dapui_watches',
+ 'dapui_stacks',
+ 'dapui_breakpoints',
+ 'dapui_scopes',
+ }
+
+ local function disable_decoration_columns(win)
+ vim.wo[win].statuscolumn = ''
+ vim.wo[win].signcolumn = 'no'
+ vim.wo[win].foldcolumn = '0'
end
- -- Apply on multiple events to catch Mason, Lazy, and other plugin floats
- vim.api.nvim_create_autocmd({ 'WinEnter', 'BufWinEnter', 'FileType' }, {
+ vim.api.nvim_create_autocmd('WinEnter', {
group = group,
- callback = disable_columns_in_float,
+ callback = function()
+ local win = vim.api.nvim_get_current_win()
+ if vim.api.nvim_win_get_config(win).relative ~= '' then
+ disable_decoration_columns(win)
+ end
+ end,
})
- -- Also apply with a slight delay to override plugin settings
- vim.api.nvim_create_autocmd('WinEnter', {
+ vim.api.nvim_create_autocmd('FileType', {
group = group,
+ pattern = no_number_filetypes,
callback = function()
- vim.schedule(disable_columns_in_float)
+ vim.opt_local.statuscolumn = ''
+ vim.opt_local.signcolumn = 'no'
+ vim.opt_local.foldcolumn = '0'
+ vim.opt_local.number = false
+ vim.opt_local.relativenumber = false
end,
})
end
@@ -693,24 +446,58 @@ end
-- Window dimming: Dim inactive windows for better focus
do
local group = vim.api.nvim_create_augroup('WindowDimming', { clear = true })
-
+
vim.api.nvim_create_autocmd('WinLeave', {
group = group,
callback = function()
- -- Only dim non-floating windows
local win_config = vim.api.nvim_win_get_config(0)
if win_config.relative == '' then
- vim.cmd [[setlocal winhl=CursorLine:CursorLineNC]]
+ vim.cmd([[setlocal winhl=CursorLine:CursorLineNC]])
end
end,
})
-
+
vim.api.nvim_create_autocmd('WinEnter', {
group = group,
- callback = function()
- vim.cmd [[setlocal winhl=]]
- end,
+ callback = function() vim.cmd([[setlocal winhl=]]) end,
})
end
--- }}
+-- -----------------------------------------------------------------------------
+-- Sidebar panels: strip line numbers and remap highlights to panel groups
+-- -----------------------------------------------------------------------------
+
+do
+ local sidebar_fts = {
+ 'undotree',
+ 'diff',
+ 'Outline',
+ 'dbui',
+ 'neotest-summary',
+ 'fugitive',
+ 'AvanteSidebar',
+ 'AvanteInput',
+ 'Avante',
+ 'AvanteSelectedFiles',
+ }
+
+ local function on_sidebar_enter()
+ vim.opt_local.number = false
+ vim.opt_local.relativenumber = false
+ vim.opt_local.winhighlight:append({
+ Normal = 'PanelDarkBackground',
+ EndOfBuffer = 'PanelDarkBackground',
+ SignColumn = 'PanelDarkBackground',
+ WinSeparator = 'PanelWinSeparator',
+ })
+ end
+
+ vim.api.nvim_create_autocmd('FileType', {
+ group = vim.api.nvim_create_augroup(
+ 'SidebarPanelHighlights',
+ { clear = true }
+ ),
+ pattern = sidebar_fts,
+ callback = on_sidebar_enter,
+ })
+end
diff --git a/files/.config/nvim/plugin/colors.lua b/files/.config/nvim/plugin/colors.lua
index 3df878ea..352af4a6 100644
--- a/files/.config/nvim/plugin/colors.lua
+++ b/files/.config/nvim/plugin/colors.lua
@@ -1,43 +1,5 @@
-if not mrl then return end
-
--- Helper to safely call augroup, deferring if not available yet
-local function augroup(name, ...)
- local args = { ... }
- if mrl and mrl.augroup then
- return mrl.augroup(name, unpack(args))
- else
- vim.schedule(function()
- if mrl and mrl.augroup then mrl.augroup(name, unpack(args)) end
- end)
- end
-end
-
-local highlight = mrl.highlight
-
-local function blend_colors(fg_hex, bg_hex, alpha)
- alpha = alpha or 0.5
-
- -- Remove '#' if present
- fg_hex = fg_hex:gsub('#', '')
- bg_hex = bg_hex:gsub('#', '')
-
- -- Parse hex colors to RGB
- local fg_r = tonumber(fg_hex:sub(1, 2), 16)
- local fg_g = tonumber(fg_hex:sub(3, 4), 16)
- local fg_b = tonumber(fg_hex:sub(5, 6), 16)
-
- local bg_r = tonumber(bg_hex:sub(1, 2), 16)
- local bg_g = tonumber(bg_hex:sub(3, 4), 16)
- local bg_b = tonumber(bg_hex:sub(5, 6), 16)
-
- -- Alpha blend: out = fg * alpha + bg * (1 - alpha)
- local out_r = math.floor(fg_r * alpha + bg_r * (1 - alpha) + 0.5)
- local out_g = math.floor(fg_g * alpha + bg_g * (1 - alpha) + 0.5)
- local out_b = math.floor(fg_b * alpha + bg_b * (1 - alpha) + 0.5)
-
- -- Convert back to hex
- return string.format('#%02x%02x%02x', out_r, out_g, out_b)
-end
+local highlight = require('highlight')
+local augroup = require('tools').augroup
local function general_overrides(dim_factor)
local is_dark = vim.g.high_contrast_theme
@@ -45,10 +7,11 @@ local function general_overrides(dim_factor)
local normal_fg = highlight.get('Normal', 'fg', '#ffffff')
local bg_color = highlight.tint(normal_bg, -dim_factor)
local bg_color2 = highlight.tint(normal_bg, 0.5 * dim_factor)
- local stl_bg = highlight.darken_hsl(normal_bg, -0.20)
+ -- local stl_bg = highlight.darken_hsl(normal_bg, -0.20)
+ local stl_bg = highlight.get('Statusline', 'bg')
local float_bg = highlight.darken_hsl(normal_bg, 0)
local popup_bg = highlight.darken_hsl(normal_bg, -0.20)
- local pal = (mrl.ui and mrl.ui.palette) or {}
+ local pal = require('tools').ui.palette or {}
-- Deleted-line diff background should track the theme's GitSignsDelete color.
-- Fall back to palette red/pale_red if GitSignsDelete isn't available yet.
local diff_delete_fg = highlight.get(
@@ -76,27 +39,6 @@ local function general_overrides(dim_factor)
local popup_thumb =
highlight.blend(popup_bg, highlight.get('Comment', 'fg', normal_fg), 0.30)
- -- Statuscolumn git bar colors (subtle bg tint from GitSigns fg colors)
- local git_bar_alpha = 0.28
- local git_add_bar_bg = highlight.blend(normal_bg, diff_add_fg, git_bar_alpha)
- local git_change_bar_bg =
- highlight.blend(normal_bg, diff_change_fg, git_bar_alpha)
- local git_delete_bar_bg =
- highlight.blend(normal_bg, diff_delete_fg, git_bar_alpha)
- local git_untracked_bar_bg =
- highlight.blend(normal_bg, highlight.get('Comment', 'fg', normal_fg), 0.20)
-
- -- VSCode-ish: keep original text colors, just tint backgrounds.
- -- Use HSL darkening to keep hue/saturation consistent across themes.
- local diff_bg_factor = 0.3
- local diff_add_bg = highlight.darken_hsl(diff_add_fg, -1 + 0.15)
- local diff_delete_bg = highlight.darken_hsl(diff_delete_fg, -1 + 0.15)
- local diff_change_bg = highlight.darken_hsl(diff_change_fg, -1 + 0.20)
- local diff_text_bg = highlight.darken_hsl(diff_change_fg, -1 + 0.30)
- -- Diff filler lines use the `fillchars.diff` glyph (you set it to '╱').
- -- This glyph is highlighted with `DiffDelete` and can look too bright, so
- -- keep it as a subtle dark grey, just above the background.
- local diff_delete_filler_fg = highlight.darken_hsl(normal_fg, -0.8)
-- do
-- local configured = mrl.ui.current and mrl.ui.current.float_bg
-- if vim.is_callable(configured) then
@@ -112,10 +54,10 @@ local function general_overrides(dim_factor)
-- end
highlight.all({
-- Status line
- { PanelSt = { link = 'StatusLine' } },
- { TabLineSel = { fg = { from = 'Normal' }, bg = '#ff0000' } },
+ { PanelSt = { link = 'Normal' } },
+ { TabLineSel = { fg = { from = 'Normal' }, bg = stl_bg } },
-- { StatuslineNC = { fg = { from = 'Normal', attr = 'fg' }, fg = bg_color } },
- { StatusLine = { fg = { from = 'Normal', attr = 'fg' }, bg = stl_bg } },
+ -- { StatusLine = { fg = { from = 'Normal', attr = 'fg' }, bg = stl_bg } },
-- { StatusLineNC = { bg = { from = 'Normal', attr = 'fg' }, fg = bg_color } },
{
StDevEnv = {
@@ -439,6 +381,18 @@ local function general_overrides(dim_factor)
-- bg = diff_text_bg,
-- },
-- },
+ -- Diffview file panel background (winhighlight uses DiffviewNormal for Normal).
+ { DiffviewNormal = { bg = { from = 'Normal', attr = 'bg' }, fg = { from = 'Normal', attr = 'fg' } } },
+ { DiffviewEndOfBuffer = { bg = { from = 'Normal', attr = 'bg' } } },
+ -- Diffview file panel: status letter fg only, no bg bleed from DiffAdd/DiffDelete/etc.
+ { DiffviewStatusAdded = { fg = { from = 'GitSignsAdd', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewStatusUntracked = { fg = { from = 'GitSignsAdd', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewStatusModified = { fg = { from = 'GitSignsChange', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewStatusRenamed = { fg = { from = 'GitSignsChange', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewStatusDeleted = { fg = { from = 'GitSignsDelete', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewStatusUnmerged = { fg = { from = 'DiagnosticWarn', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewFilePanelInsertions = { fg = { from = 'GitSignsAdd', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
+ { DiffviewFilePanelDeletions = { fg = { from = 'GitSignsDelete', attr = 'fg' }, bg = { from = 'Normal', attr = 'bg' } } },
-- these highlights are syntax groups that are set in diff.vim
{ diffAdded = { inherit = 'DiffAdd' } },
{ diffChanged = { inherit = 'DiffChange' } },
@@ -562,111 +516,10 @@ local function general_overrides(dim_factor)
-- {DiagnosticSignInfoLine = { bg = mrl.get_hi('SignColumn').bg }},
-- { DiagnosticSignInfo = { bg = mrl.get_hi('Normal').bg, fg = mrl.get_hi('MoreMsg').fg } },
-- }}}
- -- FzfLua {{{
- -- FzfLuaNormal Normal hls.normal Main win fg/bg
- {
- FzfLuaNormal = {
- link = 'NormalFloat',
- },
- },
- {
- FzfLuaTitle = {
- link = 'NormalFloat',
- },
- },
- {
- FzfLuaTitle = {
- link = 'NormalFloat',
- },
- },
- {
- -- Make fzf-lua borders follow FloatBorder exactly.
- FzfLuaBorder = { clear = true, link = 'FloatBorder' },
- },
- {
- FzfLuaPreviewNormal = {
- link = 'NormalFloat',
- },
- },
- {
- FzfLuaPreviewBorder = {
- clear = true,
- link = 'FloatBorder',
- },
- },
- {
- FzfLuaPreviewTitle = {
- link = 'NormalFloat',
- },
- },
- {
- FzfLuaHelpNormal = {
- link = 'NormalFloat',
- },
- },
- {
- FzfLuaHelpBorder = {
- clear = true,
- link = 'FloatBorder',
- },
- },
- -- FzfLuaBorder Normal hls.border Main win border
- -- FzfLuaTitle FzfLuaNormal hls.title Main win title
- -- FzfLuaBackdrop *bg=Black hls.backdrop Backdrop color
- -- FzfLuaPreviewNormal FzfLuaNormal hls.preview_normal Builtin preview fg/bg
- -- FzfLuaPreviewBorder FzfLuaBorder hls.preview_border Builtin preview border
- -- FzfLuaPreviewTitle FzfLuaTitle hls.preview_title Builtin preview title
- -- { FzfLuaCursor = { bg = "#ff00ff", fg = "#00ff00"} },
- -- { FzfLuaCursor = { bg = "#ff00ff" , fg = { from = 'Normal', attr = 'fg' } } },
- -- { FzfLuaCursorLine = { bg = "#ffff00", fg = "#00ff00"} },
- -- FzfLuaCursor Cursor hls.cursor Builtin preview Cursor
- -- FzfLuaCursorLine CursorLine hls.cursorline Builtin preview Cursorline
- -- FzfLuaCursorLineNr CursorLineNr hls.cursorlinenr Builtin preview CursorLineNr
- -- FzfLuaSearch IncSearch hls.search Builtin preview search matches
- -- FzfLuaScrollBorderEmpty FzfLuaBorder hls.scrollborder_e Builtin preview border scroll empty
- -- FzfLuaScrollBorderFull FzfLuaBorder hls.scrollborder_f Builtin preview border scroll full
- -- FzfLuaScrollFloatEmpty PmenuSbar hls.scrollfloat_e Builtin preview float scroll empty
- -- FzfLuaScrollFloatFull PmenuThumb hls.scrollfloat_f Builtin preview float scroll full
- -- FzfLuaHelpNormal FzfLuaNormal hls.help_normal Help win fg/bg
- -- FzfLuaHelpBorder FzfLuaBorder hls.help_border Help win border
- -- FzfLuaHeaderBind *BlanchedAlmond hls.header_bind Header keybind
- -- FzfLuaHeaderText *Brown1 hls.header_text Header text
- -- FzfLuaPathColNr *CadetBlue1 hls.path_colnr Path col nr (lines,qf,lsp,diag)
- -- FzfLuaPathLineNr *LightGreen hls.path_linenr Path line nr (lines,qf,lsp,diag)
- -- FzfLuaBufName *LightMagenta hls.buf_name Buffer name (lines)
- -- FzfLuaBufNr *BlanchedAlmond hls.buf_nr Buffer number (all buffers)
- -- FzfLuaBufFlagCur *Brown1 hls.buf_flag_cur Buffer line (buffers)
- -- FzfLuaBufFlagAlt *CadetBlue1 hls.buf_flag_alt Buffer line (buffers)
- -- FzfLuaTabTitle *LightSkyBlue1 hls.tab_title Tab title (tabs)
- -- FzfLuaTabMarker *BlanchedAlmond hls.tab_marker Tab marker (tabs)
- -- FzfLuaDirIcon Directory hls.dir_icon Paths directory icon
- -- FzfLuaDirPart Comment hls.dir_part Path formatters directory hl group
- -- FzfLuaFilePart @none hls.file_part Path formatters file hl group
- -- FzfLuaLiveSym *Brown1 hls.live_sym LSP live symbols query match
- -- fzf-lua's internal "fzf" UI groups (make sure no debug colors leak).
- { FzfLuaFzfNormal = { clear = true, link = 'FzfLuaNormal' } },
- -- { FzfLuaFzfCursorLine = { bg = "#ffff00", fg = "#00ff00"} },
- -- { FzfLuaFzfPrompt = { bg = "#ff0000", fg = "#00ff00"} },
- { ['@fzf.normal'] = { clear = true, link = 'FzfLuaNormal' } },
- -- FzfLuaFzfNormal FzfLuaNormal fzf.normal fzf's fg|bg
- -- FzfLuaFzfCursorLine FzfLuaCursorLine fzf.cursorline fzf's fg+|bg+
- -- FzfLuaFzfMatch Special fzf.match fzf's hl+
- -- FzfLuaFzfBorder FzfLuaBorder fzf.border fzf's border
- -- FzfLuaFzfScrollbar FzfLuaFzfBorder fzf.scrollbar fzf's scrollbar
- -- FzfLuaFzfSeparator FzfLuaFzfBorder fzf.separator fzf's separator
- -- FzfLuaFzfGutter FzfLuaNormal fzf.gutter fzf's gutter (hl bg is used)
- -- FzfLuaFzfHeader FzfLuaTitle fzf.header fzf's header
- -- FzfLuaFzfInfo NonText fzf.info fzf's info
- -- FzfLuaFzfPointer Special fzf.pointer fzf's pointer
- -- FzfLuaFzfMarker FzfLuaFzfPointer fzf.marker fzf's marker
- -- FzfLuaFzfSpinner FzfLuaFzfPointer fzf.spinner fzf's spinner
- -- FzfLuaFzfPrompt Special fzf.prompt fzf's prompt
- -- FzfLuaFzfQuery FzfLuaNormal fzf.query fzf's header
- -- }}}
})
end
-local function set_sidebar_highlight(dim_factor)
+local function set_sidebar_highlight()
highlight.all({
{
-- Panels should match the main window background.
@@ -685,61 +538,6 @@ local function set_sidebar_highlight(dim_factor)
},
{ PanelStNC = { link = 'PanelWinSeparator' } },
{ PanelSt = { bg = { from = 'Normal', attr = 'bg' } } },
-
- -- Avanté Panel colors
- {
- AvanteSidebarNormal = { link = 'PanelDarkBackground' },
- },
- {
- AvanteTitle = {
- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- -- fg = '#00ff00',
- },
- },
- {
- AvanteReversedTitle = {
- fg = { from = 'PanelDarkBackground', attr = 'bg' },
- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- },
- },
- {
- AvanteSubtitle = {
- -- fg = '#ff0000',
- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- },
- },
- {
- AvanteThirdTitle = {
- -- fg = '#ff0000',
- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- },
- },
- {
- AvanteReversedSubtitle = { link = 'AvanteReversedTitle' },
- },
- {
- AvanteReversedThirdTitle = { link = 'AvanteReversedTitle' },
- },
- {
- AvanteSidebarWinHorizontalSeparator = {
- -- bg = '#ff0000',
- -- fg = '#ff0000',
- fg = { from = 'PanelDarkBackground', attr = 'bg' },
- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- },
- },
- {
- AvanteSidebarWinSeparator = {
- -- bg = '#ff0000',
- -- fg = '#ff0000',
- -- fg = { from = 'PanelDarkBackground', attr = 'bg' },
- -- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- bg = { from = 'PanelDarkBackground', attr = 'bg' },
- -- fg = { from = 'PanelDarkBackground', attr = 'bg' },
- -- inherit = 'PanelBackground',
- fg = { from = 'WinSeparator' },
- },
- },
})
end
@@ -756,24 +554,20 @@ local sidebar_fts = {
'AvanteSelectedFiles',
}
+
local function on_sidebar_enter()
-- Panels should feel like sidebars: no line numbers.
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.opt_local.winhighlight:append({
Normal = 'PanelDarkBackground',
- -- AvanteSidebarNormal = { link = 'PanelDarkBackground' },
EndOfBuffer = 'PanelDarkBackground',
- -- StatusLine = 'PanelSt',
- -- StatusLineNC = 'PanelStNC',
SignColumn = 'PanelDarkBackground',
- -- VertSplit = 'PanelVertSplit',
- -- VertSplit = 'PanelWinSeparator',
WinSeparator = 'PanelWinSeparator',
})
end
-local function colorscheme_overrides(dim_factor)
+local function colorscheme_overrides()
local overrides = {
['github_dark_default'] = {
{ TabLineSel = { link = 'Todo' } },
@@ -784,20 +578,15 @@ local function colorscheme_overrides(dim_factor)
end
local function user_highlights()
- local dim_factor = 0.5
- if vim.g.colors_name == 'gruvbox' then
- dim_factor = 0.25
- elseif vim.g.colors_name == 'horizon' then
- dim_factor = 0.75
- elseif vim.g.colors_name == 'github_dark_default' then
- dim_factor = -1
- end
-
+ local dim_factor = 0.25
general_overrides(dim_factor)
- set_sidebar_highlight(dim_factor)
- colorscheme_overrides(dim_factor)
+ set_sidebar_highlight()
+ colorscheme_overrides()
end
+-------------------------------------------------------------------------------
+-- Auto-commands to apply highlights at the right time. {{{
+-------------------------------------------------------------------------------
augroup('UserHighlights', {
event = 'ColorScheme',
command = function() user_highlights() end,
@@ -813,4 +602,7 @@ augroup('UserHighlights', {
command = function() on_sidebar_enter() end,
})
--- vim: foldmethod=marker
+-- }}}
+-------------------------------------------------------------------------------
+
+-- vim: fdm=marker
diff --git a/files/.config/nvim/plugin/lastplace.lua b/files/.config/nvim/plugin/lastplace.lua
index 9197e284..9305b295 100644
--- a/files/.config/nvim/plugin/lastplace.lua
+++ b/files/.config/nvim/plugin/lastplace.lua
@@ -5,22 +5,10 @@
-- References:
-- github.com/ethanholz/nvim-lastplace/blob/main/lua/nvim-lastplace/init.lua
-if not mrl then return end
-
-- }}}
--------------------------------------------------------------------------------
--- Helper to safely call augroup, deferring if not available yet
-local function augroup(name, ...)
- local args = { ... }
- if mrl and mrl.augroup then
- return mrl.augroup(name, unpack(args))
- else
- vim.schedule(function()
- if mrl and mrl.augroup then mrl.augroup(name, unpack(args)) end
- end)
- end
-end
+local augroup = require('tools').augroup
local fn = vim.fn
local ignore_buftype = { 'quickfix', 'nofile', 'help', 'terminal' }
diff --git a/files/.config/nvim/plugin/lsp.lua b/files/.config/nvim/plugin/lsp.lua
index dc93184a..e4092f62 100644
--- a/files/.config/nvim/plugin/lsp.lua
+++ b/files/.config/nvim/plugin/lsp.lua
@@ -1,19 +1,6 @@
-if not mrl then return end
-
--- Wait for icons to be available
-if not mrl.ui or not mrl.ui.icons or not mrl.ui.icons.lsp then
- vim.schedule(function()
- if mrl and mrl.ui and mrl.ui.icons and mrl.ui.icons.lsp then
- -- Re-source this file
- dofile(vim.fn.expand(':p'))
- end
- end)
- return
-end
-
-- Optimized: Cache severity constants and icons lookup
local S = vim.diagnostic.severity
-local icons = mrl.ui.icons.lsp
+local icons = require('tools').ui.icons.lsp
-- Diagnostics configuration (optimized for startup time)
vim.diagnostic.config({
diff --git a/files/.config/nvim/plugin/root.lua b/files/.config/nvim/plugin/root.lua
index 042c2e78..7f5db439 100644
--- a/files/.config/nvim/plugin/root.lua
+++ b/files/.config/nvim/plugin/root.lua
@@ -1,18 +1,5 @@
-if not mrl then return end
-
--- Helper to safely call augroup, deferring if not available yet
-local function augroup(name, ...)
- local args = { ... }
- if mrl and mrl.augroup then
- return mrl.augroup(name, unpack(args))
- else
- vim.schedule(function()
- if mrl and mrl.augroup then mrl.augroup(name, unpack(args)) end
- end)
- end
-end
-
-local fn, fs, api = vim.fn, vim.fs, vim.api
+local augroup = require('tools').augroup
+local fn, fs = vim.fn, vim.fs
-------------------------------------------------------------------------------
-- Project root finder
@@ -50,7 +37,7 @@ local function get_lsp_root(buf)
end
local function set_root_directory(args)
- local path = api.nvim_buf_get_name(args.buf)
+ local path = vim.api.nvim_buf_get_name(args.buf)
if path == '' then return end
path = fs.dirname(path)
diff --git a/files/.config/nvim/plugin/statuscolumn.lua b/files/.config/nvim/plugin/statuscolumn.lua
index 93c5b93e..19d002a2 100644
--- a/files/.config/nvim/plugin/statuscolumn.lua
+++ b/files/.config/nvim/plugin/statuscolumn.lua
@@ -1,27 +1,20 @@
-if
- not mrl
- or not mrl.ui
- or not mrl.ui.statuscolumn
- or not mrl.ui.statuscolumn.enable
-then
- return
-end
-
--- Custom statuscolumn inspired by akinsho:
--- - separates git signs from other signs
--- - shows fold marker
--- - can be disabled per buffer via your "decorations" presets
+local UI = require('tools').ui
-mrl.ui.statuscolumn = mrl.ui.statuscolumn or {}
+_G.Stlcol = {}
local api, fn = vim.api, vim.fn
local v = vim.v
local space = ' '
-local icons = (mrl.ui and mrl.ui.icons and mrl.ui.icons.separators) or {}
-local diag_icons = (mrl.ui and mrl.ui.icons and mrl.ui.icons.lsp) or {}
+local icons = UI.icons.separators or {}
+local diag_icons = UI.icons.lsp or {}
local diag_warn_icon = diag_icons.warn or 'W'
local diag_err_icon = diag_icons.error or 'E'
+local cfg = {
+ number_width = 3,
+ hide_diag_on_cursorline = true,
+}
+
local function hl(hl_group, text)
if not hl_group or hl_group == '' then return text end
return ('%%#%s#%s%%*'):format(hl_group, text)
@@ -72,7 +65,7 @@ local function fold_mark(lnum)
end
local function format_number(win, lnum, relnum, virtnum, line_count)
- local min_width = mrl.ui.statuscolumn.number_width or vim.o.numberwidth or 0
+ local min_width = cfg.number_width or vim.o.numberwidth or 0
local col_width = math.max(api.nvim_strwidth(tostring(line_count)), min_width)
if virtnum and virtnum ~= 0 then
-- virtual line: show a subtle placeholder
@@ -178,8 +171,8 @@ end
local function should_disable(buf, ft)
if vim.bo[buf].buftype ~= '' then return true end
- if not mrl.ui.decorations or not mrl.ui.decorations.get then return false end
- local decor = mrl.ui.decorations.get({
+ if not UI.decorations or not UI.decorations.get then return false end
+ local decor = UI.decorations.get({
ft = ft,
bt = vim.bo[buf].buftype,
setting = 'statuscolumn',
@@ -188,7 +181,7 @@ local function should_disable(buf, ft)
and (decor.ft == false or decor.bt == false or decor.fname == false)
end
-function mrl.ui.statuscolumn.render()
+function Stlcol.render()
local win = tonumber(vim.g.statusline_winid) or api.nvim_get_current_win()
local buf = api.nvim_win_get_buf(win)
local ft = vim.bo[buf].filetype
@@ -198,7 +191,7 @@ function mrl.ui.statuscolumn.render()
local line_count = api.nvim_buf_line_count(buf)
local cursor_line = api.nvim_win_get_cursor(win)[1]
- local hide_diag_on_cursorline = mrl.ui.statuscolumn.hide_diag_on_cursorline
+ local hide_diag_on_cursorline = cfg.hide_diag_on_cursorline
local diag = (hide_diag_on_cursorline and lnum == cursor_line) and ' '
or best_diag(buf, lnum - 1)
local git = best_sign(buf, lnum - 1, true)
@@ -216,11 +209,11 @@ function mrl.ui.statuscolumn.render()
})
end
-vim.o.statuscolumn = '%{%v:lua.mrl.ui.statuscolumn.render()%}'
+vim.o.statuscolumn = '%{%v:lua.Stlcol.render()%}'
-- Disable statuscolumn for buffers where your decorations preset says so.
api.nvim_create_autocmd({ 'BufEnter', 'FileType' }, {
- group = api.nvim_create_augroup('MrlStatusColumn', { clear = true }),
+ group = api.nvim_create_augroup('StatusColumn', { clear = true }),
callback = function(args)
local buf = args.buf
local ft = vim.bo[buf].filetype
@@ -259,7 +252,7 @@ api.nvim_create_autocmd({ 'BufEnter', 'FileType' }, {
-- Clear extmark cache when signs/diagnostics update to ensure fresh data
api.nvim_create_autocmd({ 'DiagnosticChanged', 'User' }, {
- group = api.nvim_create_augroup('MrlStatusColumnCache', { clear = true }),
+ group = api.nvim_create_augroup('StatusColumnCache', { clear = true }),
pattern = { '*', 'GitSignsUpdate' },
callback = function()
-- Clear the cache on diagnostic/sign changes
diff --git a/files/.config/nvim/plugin/statusline.lua b/files/.config/nvim/plugin/statusline.lua
index ba65d196..4b208935 100644
--- a/files/.config/nvim/plugin/statusline.lua
+++ b/files/.config/nvim/plugin/statusline.lua
@@ -1,35 +1,19 @@
-if
- not mrl
- or not mrl.ui
- or not mrl.ui.statusline
- or not mrl.ui.statusline.enable
-then
- return
-end
-
--- Wait for icons to be available
-if not mrl.ui.icons then
- vim.schedule(function()
- if mrl and mrl.ui and mrl.ui.icons then
- dofile(vim.fn.expand(':p'))
- end
- end)
- return
-end
+local T = require('tools')
+local UI = require('tools').ui
+local HL = require('highlight')
-mrl.ui.statusline = {}
+_G.Stl = {}
-- LSP clients are collapsed by default: show only 🧩 .
local state = { lsp_clients_visible = false }
-local str = require('custom.strings')
+local str = require('tools').strings
local section, spacer, display = str.section, str.spacer, str.display
-local icons, lsp, highlight, decorations =
- mrl.ui.icons, mrl.ui.lsp, mrl.highlight, mrl.ui.decorations
+local icons, lsp, highlight, decorations = UI.icons, UI.lsp, HL, UI.decorations
local api, fn, fs, fmt, strwidth =
vim.api, vim.fn, vim.fs, string.format, vim.api.nvim_strwidth
-local P, falsy = mrl.ui.palette, mrl.falsy
+local P, falsy = UI.palette, T.falsy
local sep = package.config:sub(1, 1)
local space = ' '
@@ -54,7 +38,7 @@ local identifiers = {
terminal = '',
quickfix = '',
},
- filetypes = mrl.p_table({
+ filetypes = T.p_table({
['fzf'] = '', -- '',
['fzf-lua'] = '',
['log'] = '',
@@ -79,7 +63,7 @@ local identifiers = {
['toggleterm'] = '',
['Avante.*'] = icons.misc.chat,
}),
- names = mrl.p_table({
+ names = T.p_table({
['fzf'] = 'FZF',
['fzf-lua'] = 'FZF',
['orgagenda'] = 'Org',
@@ -262,7 +246,9 @@ end
local function special_buffers(ctx)
if ctx.preview then return 'preview' end
if ctx.buftype == 'quickfix' then return 'Quickfix List' end
- if ctx.bufname and ctx.bufname:match('^fzf%-lua') then return 'FZF' end
+ if ctx.filetype == 'fzf' or (ctx.bufname and ctx.bufname:match('^fzf')) then
+ return 'FZF'
+ end
if ctx.filetype == 'AvanteInput' then return 'Avante' end
if ctx.filetype == 'AvanteSelectedFiles' then return 'Avante' end
if ctx.filetype == 'Avante' then return 'Avante' end
@@ -294,19 +280,10 @@ local function dir_env(directory)
if not directory then return '', '' end
local paths = {
[vim.g.dotfiles] = '$DOTFILES',
- [vim.g.projects_directory .. '/personal/dotfiles'] = '$DOTFILES',
[vim.g.work_directory] = '$WORK',
- ['~/Workspaces/work/'] = '$WORK',
- ['/home/marcos/Workspaces/work/'] = '$WORK',
[vim.env.VIMRUNTIME] = '$VIMRUNTIME',
[vim.g.projects_directory] = '$WORKSPACES',
- ['/home/marcos/Projects/'] = '$WORKSPACES',
- ['/home/marcos/Workspaces/personal/dotfiles/'] = '$DOTFILES',
- ['/Users/marcos/Workspaces/personal/dotfiles/'] = '$DOTFILES',
- ['/home/marcos/Projects/personal/dotfiles/'] = '$DOTFILES',
- ['~/Projects/personal/dotfiles/'] = '$DOTFILES',
- ['/Users/marcos/Library/Mobile Documents/iCloud~md~obsidian'] = '$OBSIDIAN',
- ['~/Library/Mobile Documents/iCloud~md~obsidian'] = '$OBSIDIAN',
+ [vim.g.obsidian] = '$OBSIDIAN',
[vim.env.HOME] = '~',
}
local result, env, prev_match = directory, '', ''
@@ -441,7 +418,7 @@ end
local function diagnostic_info(context)
local diagnostics = vim.diagnostic.get(context.bufnum)
local severities = vim.diagnostic.severity
- local lsp_icons = mrl.ui.icons.lsp
+ local lsp_icons = UI.icons.lsp
if vim.tbl_isempty(diagnostics) then
return {
error = { count = 0, icon = lsp_icons.error },
@@ -497,7 +474,7 @@ end
local LSP_COMPONENT_ID = 2000
-function mrl.ui.statusline.lsp_client_click()
+function Stl.lsp_client_click()
state.lsp_clients_visible = not state.lsp_clients_visible
vim.cmd('redrawstatus')
end
@@ -618,7 +595,7 @@ end
-- RENDER
--------------------------------------------------------------------------------
-function mrl.ui.statusline.render()
+function Stl.render()
local curwin = api.nvim_get_current_win()
local curbuf = api.nvim_win_get_buf(curwin)
@@ -652,7 +629,6 @@ function mrl.ui.statusline.render()
local l1 = section:new({
{
- -- { ' ' .. vim.g.dev_environ .. '▐', 'StDevEnv' },
{ '' .. vim.g.dev_environ .. '', 'StDevEnv' },
},
priority = 1,
@@ -719,7 +695,7 @@ function mrl.ui.statusline.render()
},
priority = 2,
id = LSP_COMPONENT_ID,
- click = 'v:lua.mrl.ui.statusline.lsp_client_click',
+ click = 'v:lua.Stl.lsp_client_click',
},
}
if state.lsp_clients_visible and lsp_client_count > 0 then
@@ -928,9 +904,6 @@ function mrl.ui.statusline.render()
priority = 6,
}
-- }}}
- -- Space after {{{
- -- { { { space, 'StSeparator' } }, priority = 1 }
- -- }}}
)
-- removes 5 columns to add some padding
return display({ l1 + l2, m1, r1 + r2 }, available_space - 5)
@@ -940,21 +913,9 @@ end
vim.g.qf_disable_statusline = 1
-- set the statusline
-vim.o.statusline = '%{%v:lua.mrl.ui.statusline.render()%}'
-
--- Helper to safely call augroup
-local function augroup(name, ...)
- local args = { ... }
- if mrl and mrl.augroup then
- return mrl.augroup(name, unpack(args))
- else
- vim.schedule(function()
- if mrl and mrl.augroup then mrl.augroup(name, unpack(args)) end
- end)
- end
-end
+vim.o.statusline = '%{%v:lua.Stl.render()%}'
-augroup('CustomStatusline', {
+T.augroup('CustomStatusline', {
event = 'FocusGained',
command = function() vim.g.vim_in_focus = true end,
}, {
diff --git a/files/.config/nvim/queries/html/rainbow.scm b/files/.config/nvim/queries/html/rainbow.scm
deleted file mode 100644
index d704915e..00000000
--- a/files/.config/nvim/queries/html/rainbow.scm
+++ /dev/null
@@ -1,23 +0,0 @@
-;; A pair of opening and closing tag with any content in-between. Excludes
-;; self-closing tags or opening tags without closing tag.
-
-(element
- (start_tag
- (tag_name) @opening)
- (end_tag
- (tag_name) @closing)) @container
-
-(style_element
- (start_tag
- (tag_name) @opening)
- (end_tag
- (tag_name) @closing)) @container
-
-(script_element
- (start_tag
- (tag_name) @opening)
- (end_tag
- (tag_name) @closing)) @container
-
-(self_closing_tag
- (tag_name) @intermediate) @container
diff --git a/files/.config/nvim/skeleton/skel.sh b/files/.config/nvim/skeleton/skel.sh
index af6ac3a3..485e6f15 100644
--- a/files/.config/nvim/skeleton/skel.sh
+++ b/files/.config/nvim/skeleton/skel.sh
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
-@CURSOR@
set -eou pipefail
+@CURSOR@
+
# vim:foldmethod=marker
diff --git a/files/.config/nvim/skeleton/skel.slides.tex b/files/.config/nvim/skeleton/skel.slides.tex
deleted file mode 100644
index 2b90a60d..00000000
--- a/files/.config/nvim/skeleton/skel.slides.tex
+++ /dev/null
@@ -1 +0,0 @@
-dfsdf
diff --git a/files/.config/nvim/skeleton/skel_slides.tex b/files/.config/nvim/skeleton/skel_slides.tex
deleted file mode 100644
index 5c1b1494..00000000
--- a/files/.config/nvim/skeleton/skel_slides.tex
+++ /dev/null
@@ -1 +0,0 @@
-hola
diff --git a/files/.config/nvim/tests/integration/test_keymaps.lua b/files/.config/nvim/tests/integration/test_keymaps.lua
new file mode 100644
index 00000000..3728123c
--- /dev/null
+++ b/files/.config/nvim/tests/integration/test_keymaps.lua
@@ -0,0 +1,55 @@
+-- Integration test: verify that key bindings from keymaps.lua are registered.
+-- Boots a child Neovim with the real config root on rtp, loads options.lua
+-- (which patches vim.keymap.set) then keymaps.lua, and checks that specific
+-- maps exist.
+
+local T = MiniTest.new_set()
+local eq = MiniTest.expect.equality
+
+local config_root =
+ vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':h:h:h')
+
+T['keymaps'] = MiniTest.new_set({
+ hooks = {
+ pre_once = function()
+ T.child = MiniTest.new_child_neovim()
+ T.child.start({ '-u', 'NONE' })
+ T.child.lua(('vim.opt.rtp:prepend(%q)'):format(config_root))
+ -- options.lua patches vim.keymap.set; keymaps.lua uses it
+ T.child.lua("require('options')")
+ T.child.lua("require('keymaps')")
+ end,
+ post_once = function() T.child.stop() end,
+ },
+})
+
+--- Check that a keymap is registered for the given mode and lhs.
+local function has_map(mode, lhs)
+ return T.child.lua_get(
+ (
+ '(function() '
+ .. 'local maps = vim.fn.maparg(%q, %q, false, true); '
+ .. 'return maps ~= nil and maps.lhs ~= nil '
+ .. 'end)()'
+ ):format(lhs, mode)
+ )
+end
+
+T['keymaps'][' saves in normal mode'] = function()
+ eq(has_map('n', ''), true)
+end
+T['keymaps'][']q moves to next quickfix item'] = function()
+ eq(has_map('n', ']q'), true)
+end
+T['keymaps']['[q moves to prev quickfix item'] = function()
+ eq(has_map('n', '[q'), true)
+end
+T['keymaps'][']l moves to next loclist item'] = function()
+ eq(has_map('n', ']l'), true)
+end
+T['keymaps']['[l moves to prev loclist item'] = function()
+ eq(has_map('n', '[l'), true)
+end
+T['keymaps']['g> shows messages'] = function() eq(has_map('n', 'g>'), true) end
+
+return T
diff --git a/files/.config/nvim/tests/integration/test_lsp.lua b/files/.config/nvim/tests/integration/test_lsp.lua
new file mode 100644
index 00000000..d377276c
--- /dev/null
+++ b/files/.config/nvim/tests/integration/test_lsp.lua
@@ -0,0 +1,135 @@
+-- Integration tests for LSP / Mason setup.
+--
+-- Tier 1 — Mason registry.
+-- Loads mason.nvim directly in this test process (using the real lazy data
+-- dir so the registry index is available) and asserts that each expected
+-- package name is known to mason-registry.
+--
+-- Tier 2 — On-disk binaries.
+-- Checks ~/.local/share/nvim/mason/ to confirm every tool was actually
+-- installed. Skipped gracefully when the directory doesn't exist.
+
+local T = MiniTest.new_set()
+local eq = MiniTest.expect.equality
+
+-- ─── Tool / server lists (keep in sync with lua/custom/plugins/lsp.lua) ──────
+
+local LSP_SERVERS = {
+ 'basedpyright',
+ 'ruff',
+ 'lua_ls',
+}
+
+local EXTRA_TOOLS = {
+ 'stylua',
+ 'black',
+ 'isort',
+ 'flake8',
+ 'mypy',
+ 'shfmt',
+ 'prettier',
+ 'prettierd',
+ 'eslint_d',
+ 'hadolint',
+ 'jsonlint',
+ 'vale',
+ 'tflint',
+ 'sonarlint-language-server',
+}
+
+-- mason-lspconfig package names (differ from server names for some servers)
+local SERVER_TO_PACKAGE = {
+ lua_ls = 'lua-language-server',
+ basedpyright = 'basedpyright',
+ ruff = 'ruff',
+}
+
+-- ─── Tier 1: mason-registry knows every package ───────────────────────────────
+-- We load mason.nvim into this process using the real lazy install path.
+-- We must temporarily override XDG_DATA_HOME so mason reads its cached registry
+-- from the real data dir, not the isolated tmp dir set by minimal_init.lua.
+
+local real_data = vim.fn.expand('~/.local/share/nvim')
+local mason_plugin_path = real_data .. '/lazy/mason.nvim'
+local mason_exists = vim.loop.fs_stat(mason_plugin_path) ~= nil
+
+-- Load mason once, restoring the real data dir for its setup
+local mason_registry
+if mason_exists then
+ -- Temporarily point XDG_DATA_HOME at the real nvim data parent so mason
+ -- can find its cached registry index (under ~/.local/share/nvim/mason/)
+ local old_xdg = vim.env.XDG_DATA_HOME
+ vim.env.XDG_DATA_HOME = vim.fn.expand('~/.local/share')
+
+ vim.opt.rtp:prepend(mason_plugin_path)
+ local ok, reg = pcall(function()
+ require('mason').setup()
+ return require('mason-registry')
+ end)
+
+ vim.env.XDG_DATA_HOME = old_xdg
+
+ if ok then mason_registry = reg end
+end
+
+T['mason registry'] = MiniTest.new_set()
+
+local function registry_has(pkg_name)
+ if not mason_registry then
+ MiniTest.skip('mason.nvim not available — skipping registry checks')
+ end
+ local ok = pcall(function() return mason_registry.get_package(pkg_name) end)
+ return ok
+end
+
+for _, tool in ipairs(EXTRA_TOOLS) do
+ local name = tool
+ T['mason registry']['tool: ' .. name] = function()
+ eq(registry_has(name), true)
+ end
+end
+
+for _, server in ipairs(LSP_SERVERS) do
+ local pkg = SERVER_TO_PACKAGE[server] or server
+ local sname = server
+ T['mason registry']['lsp: ' .. sname] = function() eq(registry_has(pkg), true) end
+end
+
+-- ─── Tier 2: on-disk presence ─────────────────────────────────────────────────
+
+local mason_root = real_data .. '/mason'
+local mason_bin = mason_root .. '/bin'
+local mason_pkgs = mason_root .. '/packages'
+local mason_bin_exists = vim.loop.fs_stat(mason_bin) ~= nil
+
+T['mason installed tools'] = MiniTest.new_set()
+
+local function bin_exists(name)
+ return vim.loop.fs_stat(mason_bin .. '/' .. name) ~= nil
+end
+local function pkg_exists(name)
+ return vim.loop.fs_stat(mason_pkgs .. '/' .. name) ~= nil
+end
+
+for _, tool in ipairs(EXTRA_TOOLS) do
+ local name = tool
+ T['mason installed tools']['bin: ' .. name] = function()
+ if not mason_bin_exists then
+ MiniTest.skip('Mason not installed on this machine')
+ end
+ eq(bin_exists(name), true)
+ end
+end
+
+for _, server in ipairs(LSP_SERVERS) do
+ local pkg = SERVER_TO_PACKAGE[server] or server
+ local sname = server
+ T['mason installed tools']['lsp: ' .. sname] = function()
+ if not mason_bin_exists then
+ MiniTest.skip('Mason not installed on this machine')
+ end
+ eq(pkg_exists(pkg), true)
+ end
+end
+
+return T
diff --git a/files/.config/nvim/tests/integration/test_options.lua b/files/.config/nvim/tests/integration/test_options.lua
new file mode 100644
index 00000000..6af50859
--- /dev/null
+++ b/files/.config/nvim/tests/integration/test_options.lua
@@ -0,0 +1,45 @@
+-- Integration test: verify vim options are set by options.lua.
+-- Boots a child Neovim, loads options.lua from the config root, then asserts
+-- key option values.
+
+local T = MiniTest.new_set()
+local eq = MiniTest.expect.equality
+
+-- Resolve the config root relative to this file's location:
+-- this file lives at /tests/integration/test_options.lua
+local config_root = vim.fn.fnamemodify(
+ debug.getinfo(1, 'S').source:sub(2), -- strip leading '@'
+ ':h:h:h'
+)
+
+T['options'] = MiniTest.new_set({
+ hooks = {
+ pre_once = function()
+ T.child = MiniTest.new_child_neovim()
+ T.child.start({ '-u', 'NONE' })
+ -- Put the config lua/ directory on rtp so require() works
+ T.child.lua(('vim.opt.rtp:prepend(%q)'):format(config_root))
+ T.child.lua("require('options')")
+ end,
+ post_once = function() T.child.stop() end,
+ },
+})
+
+local function get_opt(name) return T.child.lua_get(('vim.o[%q]'):format(name)) end
+
+T['options']['number is set'] = function() eq(get_opt('number'), true) end
+T['options']['relativenumber is set'] = function()
+ eq(get_opt('relativenumber'), true)
+end
+T['options']['splitbelow is set'] = function() eq(get_opt('splitbelow'), true) end
+T['options']['splitright is set'] = function() eq(get_opt('splitright'), true) end
+T['options']['undofile is set'] = function() eq(get_opt('undofile'), true) end
+T['options']['termguicolors is set'] = function()
+ eq(get_opt('termguicolors'), true)
+end
+T['options']['ignorecase is set'] = function() eq(get_opt('ignorecase'), true) end
+T['options']['smartcase is set'] = function() eq(get_opt('smartcase'), true) end
+T['options']['expandtab is set'] = function() eq(get_opt('expandtab'), true) end
+T['options']['showtabline is 0'] = function() eq(get_opt('showtabline'), 0) end
+
+return T
diff --git a/files/.config/nvim/tests/integration/test_plugins_load.lua b/files/.config/nvim/tests/integration/test_plugins_load.lua
new file mode 100644
index 00000000..d49271ee
--- /dev/null
+++ b/files/.config/nvim/tests/integration/test_plugins_load.lua
@@ -0,0 +1,33 @@
+-- Smoke tests: verify core Lua modules can be require()'d without errors.
+-- Catches import-time syntax errors or broken module structure independently
+-- of whether plugins are installed.
+
+local T = MiniTest.new_set()
+
+local config_root =
+ vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':h:h:h')
+
+vim.opt.rtp:prepend(config_root)
+
+local function loads(mod_name)
+ T[mod_name .. ' loads without error'] = function()
+ local ok, result = pcall(require, mod_name)
+ MiniTest.expect.equality(ok, true)
+ MiniTest.expect.no_equality(result, nil)
+ end
+end
+
+loads('tools') -- core utilities + ui + strings + colors
+loads('highlight') -- highlight helpers (depends on tools)
+
+-- options.lua has side effects but returns nothing; just check it doesn't error
+T['options.lua executes without error'] = function()
+ local ok, err = pcall(require, 'options')
+ if not ok then
+ if type(err) == 'string' and err:match('already') then return end
+ error(err)
+ end
+ MiniTest.expect.equality(ok, true)
+end
+
+return T
diff --git a/files/.config/nvim/tests/minimal_init.lua b/files/.config/nvim/tests/minimal_init.lua
new file mode 100644
index 00000000..88bbda8d
--- /dev/null
+++ b/files/.config/nvim/tests/minimal_init.lua
@@ -0,0 +1,34 @@
+-- Minimal init for running tests with mini.test.
+-- Does NOT load the full lazy.nvim stack — only bootstraps mini.test itself.
+
+local tmp = vim.fn.fnamemodify('/tmp/nvim-test', ':p')
+vim.env.XDG_CONFIG_HOME = tmp .. '/config'
+vim.env.XDG_DATA_HOME = tmp .. '/data'
+vim.env.XDG_STATE_HOME = tmp .. '/state'
+vim.env.XDG_CACHE_HOME = tmp .. '/cache'
+
+-- Bootstrap mini.test into a dedicated data dir
+local mini_test_path = tmp .. '/data/mini-test/mini.test'
+if not vim.loop.fs_stat(mini_test_path) then
+ vim.fn.system({
+ 'git',
+ 'clone',
+ '--filter=blob:none',
+ 'https://github.com/echasnovski/mini.test',
+ mini_test_path,
+ })
+end
+
+-- Add mini.test to runtimepath
+vim.opt.rtp:prepend(mini_test_path)
+
+-- Add the nvim config root so tests can `require('tools')`, `require('highlight')`, etc.
+local config_root =
+ vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':h:h')
+vim.opt.rtp:prepend(config_root)
+
+-- Stub out vim.notify to avoid noise during unit tests
+vim.notify = function() end
+
+-- Set up MiniTest global so test files can reference MiniTest.* at file scope
+require('mini.test').setup()
diff --git a/files/.config/nvim/tests/run_tests.sh b/files/.config/nvim/tests/run_tests.sh
new file mode 100755
index 00000000..44afcc07
--- /dev/null
+++ b/files/.config/nvim/tests/run_tests.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+# Run the full Neovim test suite using mini.test.
+# Usage: bash tests/run_tests.sh [directory]
+#
+# When run from the repo root:
+# bash files/.config/nvim/tests/run_tests.sh
+# Or from the nvim config root:
+# bash tests/run_tests.sh
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+NVIM_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
+TEST_DIR="${1:-$SCRIPT_DIR}"
+
+cd "$NVIM_ROOT"
+
+echo "Running tests in: $TEST_DIR"
+echo "Neovim config root: $NVIM_ROOT"
+
+nvim --headless --noplugin -u "$SCRIPT_DIR/minimal_init.lua" \
+ -c "lua require('mini.test').run({ execute = { reporter = require('mini.test').gen_reporter.stdout({ group_depth = 2 }) } })" \
+ -c "qa!"
diff --git a/files/.config/nvim/tests/unit/test_highlight.lua b/files/.config/nvim/tests/unit/test_highlight.lua
new file mode 100644
index 00000000..721f1e18
--- /dev/null
+++ b/files/.config/nvim/tests/unit/test_highlight.lua
@@ -0,0 +1,109 @@
+-- Unit tests for lua/highlight.lua exported pure functions:
+-- tint, blend, darken_hsl
+--
+-- These functions are pure (no Neovim UI API required at call time) so they
+-- can run in a plain headless Neovim without a display.
+
+local T = MiniTest.new_set()
+local eq = MiniTest.expect.equality
+
+-- tint, blend, darken_hsl live in tools.lua (pure, no Neovim UI API at call time).
+local hl = require('tools')
+
+-- tint {{{
+T['tint'] = MiniTest.new_set()
+
+T['tint']['brightens a color with positive percent'] = function()
+ -- #808080 brightened by 0% should stay #808080
+ local result = hl.tint('#808080', 0)
+ eq(result, '#808080')
+end
+T['tint']['darkens a color with negative percent'] = function()
+ -- #ffffff darkened by -50% => #7f7f7f (floor(255 * 0.5) = 127 = 0x7f)
+ local result = hl.tint('#ffffff', -0.5)
+ eq(result, '#7f7f7f')
+end
+T['tint']['clamps to black'] = function()
+ local result = hl.tint('#101010', -2.0)
+ eq(result, '#000000')
+end
+T['tint']['clamps to white'] = function()
+ local result = hl.tint('#f0f0f0', 100)
+ eq(result, '#ffffff')
+end
+T['tint']['returns NONE for invalid color'] = function()
+ local result = hl.tint('notacolor', 0.1)
+ eq(result, 'NONE')
+end
+
+-- }}}
+
+-- blend {{{
+T['blend'] = MiniTest.new_set()
+
+T['blend']['alpha=0 returns bg'] = function()
+ eq(hl.blend('#000000', '#ffffff', 0), '#000000')
+end
+T['blend']['alpha=1 returns fg'] = function()
+ eq(hl.blend('#000000', '#ffffff', 1), '#ffffff')
+end
+T['blend']['50% blend of black and white is grey'] = function()
+ -- floor((1-0.5)*0 + 0.5*255 + 0.5) = floor(127.5 + 0.5) = 128 = 0x80
+ eq(hl.blend('#000000', '#ffffff', 0.5), '#808080')
+end
+T['blend']['returns NONE when bg is NONE'] = function()
+ eq(hl.blend('NONE', '#ffffff', 0.5), 'NONE')
+end
+T['blend']['returns NONE when fg is NONE'] = function()
+ eq(hl.blend('#000000', 'NONE', 0.5), 'NONE')
+end
+T['blend']['returns NONE for invalid hex'] = function()
+ eq(hl.blend('invalid', '#ffffff', 0.5), 'NONE')
+end
+T['blend']['clamps alpha below 0'] = function()
+ eq(hl.blend('#000000', '#ffffff', -1), '#000000')
+end
+T['blend']['clamps alpha above 1'] = function()
+ eq(hl.blend('#000000', '#ffffff', 2), '#ffffff')
+end
+
+-- }}}
+
+-- darken_hsl {{{
+T['darken_hsl'] = MiniTest.new_set()
+
+T['darken_hsl']['factor=0 returns original color'] = function()
+ -- darken with factor 0 => ll * (1+0) = ll unchanged
+ local result = hl.darken_hsl('#ff0000', 0)
+ eq(result, '#ff0000')
+end
+T['darken_hsl']['darkens a color'] = function()
+ -- Any negative factor should produce a darker (lower lightness) result.
+ -- We just check it differs from the original and is a valid hex.
+ local result = hl.darken_hsl('#ffffff', -0.5)
+ MiniTest.expect.no_equality(result, '#ffffff')
+ MiniTest.expect.no_equality(result, 'NONE')
+ eq(result:sub(1, 1), '#')
+ eq(#result, 7)
+end
+T['darken_hsl']['lightens a color'] = function()
+ local result = hl.darken_hsl('#333333', 0.5)
+ MiniTest.expect.no_equality(result, '#333333')
+ MiniTest.expect.no_equality(result, 'NONE')
+ eq(result:sub(1, 1), '#')
+ eq(#result, 7)
+end
+T['darken_hsl']['returns NONE for invalid hex'] = function()
+ eq(hl.darken_hsl('notacolor', -0.2), 'NONE')
+end
+T['darken_hsl']['pure black stays black when darkened'] = function()
+ eq(hl.darken_hsl('#000000', -0.5), '#000000')
+end
+T['darken_hsl']['pure white stays white when lightened'] = function()
+ -- lightness is already 1.0; moving toward 1.0 keeps it there
+ eq(hl.darken_hsl('#ffffff', 0.5), '#ffffff')
+end
+
+-- }}}
+
+return T
diff --git a/files/.config/nvim/tests/unit/test_strings.lua b/files/.config/nvim/tests/unit/test_strings.lua
new file mode 100644
index 00000000..c4bd2697
--- /dev/null
+++ b/files/.config/nvim/tests/unit/test_strings.lua
@@ -0,0 +1,53 @@
+-- Unit tests for statusline string utilities (tools.strings).
+-- spacer, section
+
+local T = MiniTest.new_set()
+local eq = MiniTest.expect.equality
+
+local S = require('tools').strings
+
+-- spacer {{{
+T['spacer'] = MiniTest.new_set()
+
+T['spacer']['returns nil for size < 1'] = function()
+ eq(S.spacer(0), nil)
+ eq(S.spacer(-1), nil)
+end
+T['spacer']['returns nil when size is absent'] = function() eq(S.spacer(), nil) end
+T['spacer']['returns a component with correct padding'] = function()
+ local result = S.spacer(3)
+ MiniTest.expect.no_equality(result, nil)
+ local chunks = result[1]
+ MiniTest.expect.no_equality(chunks, nil)
+ eq(chunks[1][1], ' ')
+end
+T['spacer']['respects custom filler'] = function()
+ local result = S.spacer(2, { filler = '-' })
+ local chunks = result[1]
+ eq(chunks[1][1], '--')
+end
+
+-- }}}
+
+-- section {{{
+T['section'] = MiniTest.new_set()
+
+T['section']['new creates a table with provided args'] = function()
+ local s = S.section:new('a', 'b', 'c')
+ eq(s[1], 'a')
+ eq(s[2], 'b')
+ eq(s[3], 'c')
+end
+T['section']['addition concatenates two sections'] = function()
+ local s1 = S.section:new('a', 'b')
+ local s2 = S.section:new('c', 'd')
+ local combined = s1 + s2
+ eq(combined[1], 'a')
+ eq(combined[2], 'b')
+ eq(combined[3], 'c')
+ eq(combined[4], 'd')
+end
+
+-- }}}
+
+return T
diff --git a/files/.config/nvim/tests/unit/test_tools.lua b/files/.config/nvim/tests/unit/test_tools.lua
new file mode 100644
index 00000000..9664f0d3
--- /dev/null
+++ b/files/.config/nvim/tests/unit/test_tools.lua
@@ -0,0 +1,113 @@
+-- Unit tests for lua/tools.lua pure functions.
+-- Requires: mini.test (bootstrapped by minimal_init.lua)
+
+local T = MiniTest.new_set()
+local eq = MiniTest.expect.equality
+
+-- `tools` is on the rtp via minimal_init.lua
+local tools = require('tools')
+
+-- falsy {{{
+T['falsy'] = MiniTest.new_set()
+
+T['falsy']['nil returns true'] = function() eq(tools.falsy(nil), true) end
+T['falsy']['false returns true'] = function() eq(tools.falsy(false), true) end
+T['falsy']['true returns false'] = function() eq(tools.falsy(true), false) end
+T['falsy']['empty string returns true'] = function() eq(tools.falsy(''), true) end
+T['falsy']['non-empty string returns false'] = function()
+ eq(tools.falsy('hello'), false)
+end
+T['falsy']['zero returns true'] = function() eq(tools.falsy(0), true) end
+T['falsy']['negative number returns true'] = function()
+ eq(tools.falsy(-1), true)
+end
+T['falsy']['positive number returns false'] = function()
+ eq(tools.falsy(1), false)
+end
+T['falsy']['empty table returns true'] = function() eq(tools.falsy({}), true) end
+T['falsy']['non-empty table returns false'] = function()
+ eq(tools.falsy({ 1 }), false)
+end
+
+-- }}}
+
+-- any {{{
+T['any'] = MiniTest.new_set()
+
+T['any']['matches item in list'] = function()
+ eq(tools.any('foo', { 'foo', 'bar' }), true)
+end
+T['any']['returns false when no match'] = function()
+ eq(tools.any('baz', { 'foo', 'bar' }), false)
+end
+T['any']['supports pattern matching'] = function()
+ eq(tools.any('hello.lua', { '%.lua$' }), true)
+end
+T['any']['empty list returns false'] = function()
+ eq(tools.any('foo', {}), false)
+end
+
+-- }}}
+
+-- find {{{
+T['find'] = MiniTest.new_set()
+
+T['find']['returns matching item'] = function()
+ local result = tools.find(function(x) return x > 2 end, { 1, 2, 3, 4 })
+ eq(result, 3)
+end
+T['find']['returns nil when no match'] = function()
+ local result = tools.find(function(x) return x > 10 end, { 1, 2, 3 })
+ eq(result, nil)
+end
+T['find']['returns first match'] = function()
+ local result = tools.find(function(x) return x % 2 == 0 end, { 1, 2, 4, 6 })
+ eq(result, 2)
+end
+
+-- }}}
+
+-- fold {{{
+T['fold'] = MiniTest.new_set()
+
+T['fold']['sums a list'] = function()
+ local sum = tools.fold(function(acc, v) return acc + v end, { 1, 2, 3, 4 }, 0)
+ eq(sum, 10)
+end
+T['fold']['concatenates strings'] = function()
+ local result = tools.fold(
+ function(acc, v) return acc .. v end,
+ { 'a', 'b', 'c' },
+ ''
+ )
+ eq(result, 'abc')
+end
+T['fold']['uses empty table as default accumulator'] = function()
+ local result = tools.fold(function(acc, v)
+ acc[#acc + 1] = v * 2
+ return acc
+ end, { 1, 2, 3 })
+ eq(result, { 2, 4, 6 })
+end
+
+-- }}}
+
+-- map {{{
+T['map'] = MiniTest.new_set()
+
+T['map']['doubles each element'] = function()
+ local result = tools.map(function(v) return v * 2 end, { 1, 2, 3 })
+ eq(result, { 2, 4, 6 })
+end
+T['map']['maps strings to uppercase'] = function()
+ local result = tools.map(function(v) return v:upper() end, { 'a', 'b', 'c' })
+ eq(result, { 'A', 'B', 'C' })
+end
+T['map']['returns empty table for empty input'] = function()
+ local result = tools.map(function(v) return v end, {})
+ eq(result, {})
+end
+
+-- }}}
+
+return T
diff --git a/files/.config/tmux/.tmux-cht-command b/files/.config/tmux/.tmux-cht-command
deleted file mode 100644
index 1296585c..00000000
--- a/files/.config/tmux/.tmux-cht-command
+++ /dev/null
@@ -1,39 +0,0 @@
-find
-man
-tldr
-sed
-awk
-tr
-cp
-ls
-grep
-xargs
-rg
-ps
-mv
-kill
-lsof
-less
-head
-tail
-tar
-cp
-rm
-rename
-jq
-cat
-ssh
-cargo
-git
-git-worktree
-git-status
-git-commit
-git-rebase
-docker
-docker-compose
-stow
-chmod
-chown
-make
-kinit
-krb5
diff --git a/files/.config/tmux/.tmux-cht-languages b/files/.config/tmux/.tmux-cht-languages
deleted file mode 100644
index f4ff6807..00000000
--- a/files/.config/tmux/.tmux-cht-languages
+++ /dev/null
@@ -1,18 +0,0 @@
-golang
-nodejs
-javascript
-tmux
-typescript
-zsh
-cpp
-c
-lua
-rust
-python
-bash
-php
-haskell
-ArnoldC
-css
-html
-fortran
diff --git a/files/.config/tmux/TODO.md b/files/.config/tmux/TODO.md
new file mode 100644
index 00000000..7f85ca15
--- /dev/null
+++ b/files/.config/tmux/TODO.md
@@ -0,0 +1,4 @@
+- [ ] Consolidate helpers
+- [ ] Icons should stay in statusbar
+- [ ] Add pomodoro popup and calendar integration
+- [ ] Themse should live in ~/.local/share
diff --git a/files/.config/tmux/statusbar.conf b/files/.config/tmux/statusbar.conf
index 14bfad29..31e956a6 100644
--- a/files/.config/tmux/statusbar.conf
+++ b/files/.config/tmux/statusbar.conf
@@ -13,6 +13,9 @@ set-option -g status-interval 10
set -g status-left-length 30
set -g status-right-length 30
+SESSION_ICON=""
+BELL_ICON="⚘"
+
# }}}
diff --git a/files/.config/tmux/tmux.conf b/files/.config/tmux/tmux.conf
index 08544c7e..4a744c34 100644
--- a/files/.config/tmux/tmux.conf
+++ b/files/.config/tmux/tmux.conf
@@ -247,7 +247,9 @@ set -g @resurrect-capture-pane-contents 'on'
set -g @resurrect-processes 'ssh nvim'
# Theme: source a theme file (defines colors/variables), then the statusbar layout
-source $HOME/.config/tmux/themes/carbon-mist.tmux
+# BEGIN_TMUX_THEME
+source-file ~/.config/tmux/themes/amberglow.tmux
+# END_TMUX_THEME
source $HOME/.config/tmux/statusbar.conf
# Initialize plugin manager
@@ -256,21 +258,3 @@ run -b '$HOME/.local/share/tmux/plugins/tpm/tpm'
# }}}
# vim: fdm=marker ft=tmux
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/files/.config/wezterm/wezterm.lua b/files/.config/wezterm/wezterm.lua
index 04238d08..59c187f3 100644
--- a/files/.config/wezterm/wezterm.lua
+++ b/files/.config/wezterm/wezterm.lua
@@ -580,51 +580,10 @@ return {
},
-- default_gui_startup_args = { 'connect', 'wsl' },
-- }}}
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
--- BEGIN_WEZTERM_THEME: carbon-mist
-config.color_scheme = 'carbon-mist'
--- END_WEZTERM_THEME: carbon-mist
+ -- BEGIN_WEZTERM_THEME
+ color_scheme = 'amberglow',
+ -- END_WEZTERM_THEME
+}
-- vim: fdm=marker ts=2 sw=2 sts=2 et
diff --git a/files/.config/zsh/README.md b/files/.config/zsh/README.md
index f1991bf0..ba91dff1 100644
--- a/files/.config/zsh/README.md
+++ b/files/.config/zsh/README.md
@@ -31,7 +31,7 @@ Plugins are installed to:
The installer is:
-- `~/Projects/personal/dotfiles/homebrew/install_zsh.sh`
+- `~/Projects/personal/dotfiles/install/install_zsh.sh`
It deletes existing plugin directories and clones fresh copies for idempotent installs.
diff --git a/files/.config/zsh/aliases.d/git.sh b/files/.config/zsh/aliases.d/git.sh
index e93d28b1..5236fffa 100644
--- a/files/.config/zsh/aliases.d/git.sh
+++ b/files/.config/zsh/aliases.d/git.sh
@@ -7,18 +7,15 @@
alias g="git"
alias gss="git status -s"
alias gst="git status"
-alias gc="git commit"
-alias gd="git diff"
+alias gc='git commit -v'
+alias gd='git diff'
alias gco="git checkout"
alias ga='git add'
alias gaa='git add --all'
-alias gcb='git checkout -b'
alias gb='git branch'
alias gbD='git branch -D'
alias gbl='git blame -b -w'
alias gbr='git branch --remote'
-alias gc='git commit -v'
-alias gd='git diff'
alias gf='git fetch'
alias gfa='git fetch --all --prune'
alias gfo='git fetch origin'
@@ -32,123 +29,112 @@ alias gcl='git clone --recurse-submodules'
alias gl='git pull'
alias glum='git pull upstream $(git_main_branch)'
alias grhh='git reset --hard'
-alias groh='git reset origin/$(git_current_branch) --hard'
alias grbi='git rebase -i'
alias grbm='git rebase $(git_main_branch)'
+alias gcb='git checkout -b'
alias gcm='git checkout $(git_main_branch)'
alias gcd="git checkout development"
-alias gcb="git checkout -b"
alias gstp="git stash pop"
alias gsts="git stash show -p"
function grename() {
- if [[ -z "$1" || -z "$2" ]]; then
- echo "Usage: $0 old_branch new_branch"
- return 1
- fi
-
- # Rename branch locally
- git branch -m "$1" "$2"
- # Rename branch in origin remote
- if git push origin :"$1"; then
- git push --set-upstream origin "$2"
- fi
+ if [[ -z "$1" || -z "$2" ]]; then
+ echo "Usage: $0 old_branch new_branch"
+ return 1
+ fi
+
+ # Rename branch locally
+ git branch -m "$1" "$2"
+ # Rename branch in origin remote
+ if git push origin :"$1"; then
+ git push --set-upstream origin "$2"
+ fi
}
function gdnolock() {
- git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock"
+ git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock"
}
# compdef _git gdnolock=git-diff
# Check if main exists and use instead of master
function git_main_branch() {
- local branch
- for branch in main trunk; do
- if command git show-ref -q --verify refs/heads/$branch; then
- echo $branch
- return
- fi
- done
- echo master
+ local branch
+ for branch in main trunk; do
+ if command git show-ref -q --verify refs/heads/$branch; then
+ echo $branch
+ return
+ fi
+ done
+ echo master
}
# }}}
# Github CLI {{{
function cs-list() {
- gh codespace list | awk 'NR > 0 {print $1"@"$5}'
+ gh codespace list | awk 'NR > 0 {print $1"@"$5}'
}
function cs-ssh() {
- # if we get one argument, we assume it's a codespace name
- # else we use fzf to select one
-
- if [ $# -eq 1 ]; then
- gh codespace ssh -c $1
- else
- CODESPACE=$(gh codespace list | awk 'NR > 0 {print $1"@"$5}' | fzf | awk -F@ '{print $1}')
- echo $CODESPACE
- gh codespace ssh -c $CODESPACE
- fi
+ # if we get one argument, we assume it's a codespace name
+ # else we use fzf to select one
+
+ if [ $# -eq 1 ]; then
+ gh codespace ssh -c $1
+ else
+ CODESPACE=$(gh codespace list | awk 'NR > 0 {print $1"@"$5}' | fzf | awk -F@ '{print $1}')
+ echo $CODESPACE
+ gh codespace ssh -c $CODESPACE
+ fi
}
-
-
-
-
-
# }}}
# Mounting {{{
select_partition() {
- local partition
-
- # Use lsblk to list all partitions (excluding loops) not mounted and pipe to fzf for selection
- PARTITION=$(lsblk -o NAME,SIZE,TYPE,MOUNTPOINT -n | awk '$3 == "part" {gsub(/[├└]─/, "", $1); print $1}' | fzf --height 50% --reverse --prompt="Select a partition to mount: " --header="NAME SIZE TYPE")
-
- # Check if a partition was selected
- if [ -n "$PARTITION" ]; then
- echo "Selected partition: $PARTITION"
- # Perform further actions with the selected partition, e.g., mount it
- # Add your custom logic here
- sudo mount /dev/$PARTITION /mnt/
- else
- echo "No partition selected."
- fi
+ local partition
+
+ # Use lsblk to list all partitions (excluding loops) not mounted and pipe to fzf for selection
+ PARTITION=$(lsblk -o NAME,SIZE,TYPE,MOUNTPOINT -n | awk '$3 == "part" {gsub(/[├└]─/, "", $1); print $1}' | fzf --height 50% --reverse --prompt="Select a partition to mount: " --header="NAME SIZE TYPE")
+
+ # Check if a partition was selected
+ if [ -n "$PARTITION" ]; then
+ echo "Selected partition: $PARTITION"
+ # Perform further actions with the selected partition, e.g., mount it
+ # Add your custom logic here
+ sudo mount /dev/$PARTITION /mnt/
+ else
+ echo "No partition selected."
+ fi
}
# }}}
-
# Docker {{{
-dcu(){
+dcu() {
# docker-service
docker compose up -d
}
-dcd(){
+dcd() {
docker compose down
}
# }}}
-
repo() {
# This will list up to 2 depth of given directory. Add/remove '*/' to your preferences.
# The path should be absolute path.
# Note that too many depth will slow-down the script, less depth will show fewer results.
- local srchDir=/Users/marcos/Projects/*/*/
+ local srchDir=$HOME/Workspaces/*/*/
# if any arguments arn't given, just list up everything else use search query
- [ "$1" = false ] && cd "$(ls -d $srchDir | fzf)" || local qTerm="${@}"; cd "$(ls -d $srchDir | fzf -q "$qTerm")"
+ [ "$1" = false ] && cd "$(ls -d $srchDir | fzf)" || local qTerm="${@}"
+ cd "$(ls -d $srchDir | fzf -q "$qTerm")"
}
-
-
ocurrences() {
rg -o "$@" | wc -l
}
-
-
# vim: fdm=marker et ts=4 sw=4 tw=80
diff --git a/files/.config/zsh/aliases.d/misc.sh b/files/.config/zsh/aliases.d/misc.sh
index c48a3cf8..c974219a 100644
--- a/files/.config/zsh/aliases.d/misc.sh
+++ b/files/.config/zsh/aliases.d/misc.sh
@@ -20,7 +20,6 @@ alias x="exit" # Exit Terminal
alias del="rm -rf"
alias dots="cd $DOTFILES"
alias coding="cd $PROJECTS_DIR"
-alias lp="lsp"
# ssh aliases {{{
diff --git a/files/.config/zsh/aliases.d/nav.sh b/files/.config/zsh/aliases.d/nav.sh
index de904f64..1ad67d06 100644
--- a/files/.config/zsh/aliases.d/nav.sh
+++ b/files/.config/zsh/aliases.d/nav.sh
@@ -43,7 +43,6 @@ alias dnd='do-not-disturb toggle'
alias md="mkdir -p"
-alias cat='bat --paging=never --style=plain'
batdiff() {
git diff --name-only --relative --diff-filter=d | xargs bat --diff
diff --git a/files/.config/zsh/common.sh b/files/.config/zsh/common.sh
index 0c6e669b..f5c702e2 100644
--- a/files/.config/zsh/common.sh
+++ b/files/.config/zsh/common.sh
@@ -31,7 +31,6 @@ USER_PATHS=(
"$HOME/.cargo/bin"
)
-
# Filter paths that exist
SYS_PATHS=($(for p in "${SYS_PATHS[@]}"; do path_exists "$p" && echo "$p"; done))
USER_PATHS=($(for p in "${USER_PATHS[@]}"; do path_exists "$p" && echo "$p"; done))
diff --git a/files/.config/zsh/rc.d/05-env.zsh b/files/.config/zsh/rc.d/05-env.zsh
deleted file mode 100644
index 2ac6b8d6..00000000
--- a/files/.config/zsh/rc.d/05-env.zsh
+++ /dev/null
@@ -1,16 +0,0 @@
-# Conda and virtualenv settings
-
-# disables prompt mangling in virtual_env/bin/activate
-
-# get current environment name
-
-# Lazy-load conda on first use
-load_conda() {
- source $HOME/.config/zsh/conda.sh
- unset -f conda
- unset -f load_conda
-}
-conda() {
- load_conda
- conda "$@"
-}
diff --git a/files/.config/zsh/rc.d/10-plugins.zsh b/files/.config/zsh/rc.d/10-plugins.zsh
index 455bb11f..6c3b8247 100644
--- a/files/.config/zsh/rc.d/10-plugins.zsh
+++ b/files/.config/zsh/rc.d/10-plugins.zsh
@@ -31,11 +31,12 @@ if command -v pixi >/dev/null; then
unset _pixi_st
fi
_load_pixi_completions() {
- source "$_pixi_cache"
- unset _pixi_cache
+ local _cache="$HOME/.cache/zsh/pixi-completion.zsh"
+ [[ -f "$_cache" ]] && source "$_cache"
add-zsh-hook -d precmd _load_pixi_completions
}
add-zsh-hook precmd _load_pixi_completions
+ unset _pixi_cache
fi
# zsh suggestions
diff --git a/files/.config/zsh/rc.d/40-fzf.zsh b/files/.config/zsh/rc.d/40-fzf.zsh
index 86d6c7a7..8f7b172c 100644
--- a/files/.config/zsh/rc.d/40-fzf.zsh
+++ b/files/.config/zsh/rc.d/40-fzf.zsh
@@ -5,10 +5,6 @@ export FZF_DEFAULT_OPTS='
'
export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS'
- --color=fg:-1,fg+:3,bg:-1,bg+:0
- --color=hl:5,hl+:5,info:4,marker:6
- --color=prompt:4,spinner:6,pointer:3,header:1
- --color=gutter:-1,border:-1,label:0,query:#d9d9d9
--preview-window="border-sharp"
--prompt=" "
--marker="◆"
@@ -18,4 +14,7 @@ export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS'
--layout="reverse-list"
--info="inline"'
+# Colors sourced separately by the active theme
+[ -f ~/.config/fzf/themes/amberglow.sh ] && source ~/.config/fzf/themes/amberglow.sh
+
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
diff --git a/files/.config/zsh/rc.d/70-path-extra.zsh b/files/.config/zsh/rc.d/70-path-extra.zsh
deleted file mode 100644
index 2d21e629..00000000
--- a/files/.config/zsh/rc.d/70-path-extra.zsh
+++ /dev/null
@@ -1,2 +0,0 @@
-# Extra PATHs (optional)
-# export PATH="$HOME/.local/opt/sometool/bin:$PATH"
diff --git a/files/.config/zsh/rc.d/80-keychain.zsh b/files/.config/zsh/rc.d/80-keychain.zsh
deleted file mode 100644
index b1abe91a..00000000
--- a/files/.config/zsh/rc.d/80-keychain.zsh
+++ /dev/null
@@ -1,4 +0,0 @@
-# Keychain/agent bootstrap (optional)
-# if command -v keychain >/dev/null; then
-# eval "$(keychain --eval --quiet id_rsa)"
-# fi
diff --git a/files/.config/zsh/rc.d/85-env-local.zsh b/files/.config/zsh/rc.d/85-env-local.zsh
deleted file mode 100644
index 9f0c251a..00000000
--- a/files/.config/zsh/rc.d/85-env-local.zsh
+++ /dev/null
@@ -1,2 +0,0 @@
-# Machine-specific environment (non-secret)
-# export FOO=bar
diff --git a/files/.config/zsh/utils.sh b/files/.config/zsh/utils.sh
index 8ffc917a..5899aa7d 100644
--- a/files/.config/zsh/utils.sh
+++ b/files/.config/zsh/utils.sh
@@ -116,7 +116,6 @@ alias kill_jupyter="kill $(netstat -tulpn 2>&1 | pgrep jupyter)"
/opt/homebrew/bin/claude --print "$query"
}
-# vim: fdm=marker ft=zsh
# Get current environment name
get_env() {
@@ -128,3 +127,5 @@ get_env() {
echo "syst"
fi
}
+
+# vim: fdm=marker ft=bash
diff --git a/files/.config/zsh/windows.sh b/files/.config/zsh/windows.sh
index a5712ce1..026ae655 100644
--- a/files/.config/zsh/windows.sh
+++ b/files/.config/zsh/windows.sh
@@ -68,5 +68,4 @@ sync-windows-config() {
}
-
# vim: fdm=marker ft=bash
diff --git a/files/.config/zsh/zshenv b/files/.config/zsh/zshenv
index 06f050b7..aebd4b34 100644
--- a/files/.config/zsh/zshenv
+++ b/files/.config/zsh/zshenv
@@ -13,7 +13,6 @@ export VIRTUAL_ENV_DISABLE_PROMPT=1
export LG_CONFIG_FILE=$HOME/.config/lazygit/config.yml
export MACHINE=$(cat ~/.machine)
export BROWSER="$HOMEBREW_PREFIX/bin/browsh"
-export LESSOPEN="|/opt/homebrew/bin/lesspipe.sh %s"
export DISPLAY=:0
# Manual pages
@@ -22,6 +21,10 @@ if which nvim >/dev/null; then
export MANPAGER='nvim +Man!'
fi
export BAT_PAGER="less -RF"
+if command -v bat >/dev/null; then
+ export LESSOPEN="|bat --color=always --style=plain --paging=never %s"
+ export LESS="-R"
+fi
# Locale
export LC_ALL=en_US.UTF-8
@@ -61,6 +64,20 @@ export FZF_TMUX=0 # Don't open FZF in a separate split in tmux
export PYTHONSTARTUP=$HOME/.config/python/pythonrc.py
+# ==============================================================================
+# Conda lazy-loader
+# ==============================================================================
+
+load_conda() {
+ source $HOME/.config/zsh/conda.sh
+ unset -f conda
+ unset -f load_conda
+}
+conda() {
+ load_conda
+ conda "$@"
+}
+
# ==============================================================================
# Source Additional Configurations
# ==============================================================================
diff --git a/files/.stow-local-ignore b/files/.stow-local-ignore
new file mode 100644
index 00000000..9163dd94
--- /dev/null
+++ b/files/.stow-local-ignore
@@ -0,0 +1,5 @@
+# Files to ignore when stowing
+\.DS_Store
+\.git
+config\.template
+others\.md
diff --git a/files/.zshenv b/files/.zshenv
new file mode 100644
index 00000000..826714b1
--- /dev/null
+++ b/files/.zshenv
@@ -0,0 +1 @@
+export ZDOTDIR="$HOME/.config/zsh"
diff --git a/homebrew/Brewfile b/homebrew/Brewfile
deleted file mode 100644
index 413ce7e4..00000000
--- a/homebrew/Brewfile
+++ /dev/null
@@ -1,200 +0,0 @@
-cask_args appdir: '/Applications', force: true
-
-# Add standard taps
-# tap "homebrew/cask"
-# tap "homebrew/cask-fonts"
-# tap "homebrew/cask-versions"
-# tap "homebrew/bundle"
-# tap "homebrew/services"
-tap "browsh-org/homebrew-browsh"
-tap "koekeishiya/formulae"
-tap "iina/homebrew-mpv-iina"
-tap "iina/mpv-iina"
-tap 'jayadamsmorgan/yatoro'
-
-# Custom taps tap "koekeishiya/formulae"
-tap "Rigellute/tap"
-tap "Schniz/tap"
-tap "rlue/utils"
-tap "epk/epk"
-tap "marromlam/custom"
-
-# Homebrew essentials --------------------------------------------------------
-#
-# cli tools
-brew "bat" # alternative to cat
-brew "calcurse" # TODO: What is this one
-brew "git"
-brew "git-delta"
-brew "browsh" # terminal browser
-brew "fpp" # facebook path picker
-brew "fzf" # fuzzy finder
-brew "ripgrep" # like grep, but faster
-brew "ydiff"
-brew "gnu-sed"
-brew "neovim"
-brew "lazygit" # awesome git util
-brew "jq" # json-query
-brew "yq" # yaml-query
-brew "btop" # like top, but better
-brew "tmux" # terminal multiplexer
-brew "tree" # show a tree
-brew "wget" # like curl
-brew "stow" # linking files and folders
-brew "eza" # like ls but better
-brew "otree" # explore json, yaml and toml
-brew "asdf"
-brew "cmake"
-brew "fswatch"
-brew "p7zip"
-brew "pixi"
-brew "pkgconf"
-brew "sevenzip"
-brew "tailscale"
-brew "timg"
-brew "ykman"
-brew "yt-dlp"
-
-# brew "mosh" # similar to ssh
-
-# Window manager
-# brew "skhd" # control
-
-#brew "starship"
-#brew "composer"
-#brew "coreutils"
-#brew "dbus"
-#brew "editorconfig"
-#brew "fnm"
-#brew "fontconfig"
-#brew "fontforge"
-#brew "gawk"
-#brew "gitlab-gem"
-#brew "ifstat"
-#brew "mkcert"
-brew "gd" # TODO: what is this
-
-# Language compilers and runners ----------------------------------------------
-#
-brew "node"
-brew "yarn"
-# brew "openjdk" # Required for Neovim SonarLint plugin
- # Run: ./homebrew/install-java-sonarqube.sh
-brew "marromlam/custom/xmlformat"
-# brew "prettier"
-# npm install fixjson
-
-brew "gcc"
-# brew 'clang-format' # C-like
-
-# brew "python"
-# brew "pyright" # python
-# brew "flake8"
-# brew "black"
-#
-# brew "bash"
-# brew "shfmt" # bash
-# brew "bash-language-server"
-
-brew "texlive" # latex
-# cask "mactex-no-gui" # mactex without crap
-# brew "texlab"
-# brew "bibtex-tidy"
-# brew "latexindent"
-brew "pandoc"
-
-brew "lua" # lua
-# brew "stylua"
-# brew "lua-language-server"
-
-
-#brew "mycli"
-brew "ncurses"
-#brew "php"
-brew "pkg-config"
-#brew "portaudio"
-#brew "rbenv"
-brew "readline"
-#brew "readydocker"
-brew "rlue/utils/timer"
-# brew "spotify-tui"
-# brew "spotifyd"
-#brew "tmuxinator"
-#brew "tmuxinator-fzf-start"
-# brew "sshfs" # mount ssh volumes
-brew "mupdf-tools" # tools for pdf -- TODO: maybe not needed
-brew "ffmpeg" # video converter
-
-#brew "ruby"
-
-
-# Containerization ------------------------------------------------------------
-brew "docker"
-brew "colima"
-brew "lazydocker"
-
-
-
-# GUI Applications ------------------------------------------------------------
-#
-cask "iina" # video player
-cask "transmission" # torrent client
-
-cask "kitty" # best terminal on Earth
-# cask "wezterm"
-
-# cask "inkscape" # draw
-
-# cask "brave-browser" # chromium based browser
-cask "orion" # browser
-
-cask "obsidian" # knowledge
-cask "rectangle" # window manager
-cask "amethyst" # tiling window manager
-cask "hammerspoon" # automation + custom window actions
-cask "grandperspective" # tools to show up large files
-cask "keycastr" # cast keys on screen
-cask "ghostty"
-cask "appcleaner"
-cask "chatgpt"
-cask "claude-code"
-cask "codex"
-cask "copilot-cli"
-cask "whatsapp"
-# cask "cursor" # intentionally not tracked; WSL tracks `cursor-cli` for cursor-agent
-
-
-# Others ----------------------------------------------------------------------
-#
-# cask "debit-and-credit" # finance
-# cask 'apple-configurator' # apple
-# cask "monday.dotcom"
-# caskk "firefox"
-# cask "synergy"
-# cask "barrier"
-# cask "ip-scanner"
-# cask "tomito"
-# cask "caffeine"
-# cask "raspberry-pi-imager"
-# cask "balenaetcher" # iso and image writer
-# cask "zerotier-one"
-# cask "whatsapp"
-# cask "add-guard"
-# cask "autofirma"
-
-# cask "microsoft-teams"
-# cask "microsoft-office"
-cask 'domzilla-caffeine'
-
-
-
-# Fonts -----------------------------------------------------------------------
-cask "font-hasklug-nerd-font" # I use this font as the nerd one
-cask "font-jetbrains-mono"
-cask "font-victor-mono" # main font
-cask "font-iosevka"
-cask "font-sf-mono-nerd-font"
-cask "font-fira-code-nerd-font"
-cask "font-hack-nerd-font"
-cask "font-symbols-only-nerd-font"
-cask "font-sf-pro"
diff --git a/homebrew/BrewfileLinux b/homebrew/BrewfileLinux
deleted file mode 100644
index 41c8788d..00000000
--- a/homebrew/BrewfileLinux
+++ /dev/null
@@ -1,78 +0,0 @@
-# Add standard taps
-tap "homebrew/cask"
-tap "homebrew/cask-fonts"
-tap "homebrew/cask-versions"
-tap "homebrew/bundle"
-tap "homebrew/services"
-tap "browsh-org/homebrew-browsh"
-
-# Custom taps
-tap "koekeishiya/formulae"
-tap "Rigellute/tap"
-tap "Schniz/tap"
-tap "rlue/utils"
-tap "epk/epk"
-tap "marromlam/custom"
-
-# Homebrew essentials
-brew "bat" # alternative to cat
-brew "calcurse"
-brew "browsh"
-#brew "composer"
-#brew "coreutils"
-#brew "dbus"
-#brew "editorconfig"
-#brew "fnm"
-#brew "fontconfig"
-#brew "fontforge"
-brew "fpp" # facebook path picker
-brew "fzf" # fuzzy finder
-#brew "gawk"
-brew "git"
-#brew "gitlab-gem"
-brew 'imagemagick'
-brew "gnu-sed"
-#brew "ifstat"
-#brew "jq"
-#brew "lazydocker"
-brew "lazygit" # awesome git util
-#brew "mkcert"
-brew "git-delta"
-#brew "mosh"
-#brew "mycli"
-brew "ncurses"
-brew "neovim"
-brew "node"
-#brew "php"
-brew "pandoc"
-brew "pkg-config"
-#brew "portaudio"
-brew "python"
-#brew "rbenv"
-brew "readline"
-#brew "readydocker"
-brew "ripgrep" # like grep, but faster
-brew "rlue/utils/timer"
-#brew "ruby"
-brew "spotify-tui"
-#brew "starship"
-brew "stow"
-brew "tmux" # terminal multiplexer
-#brew "tmuxinator"
-#brew "tmuxinator-fzf-start"
-brew "tree"
-brew "wget" # like curl
-brew "yarn"
-brew "marromlam/custom/xmlformat"
-# brew "sshfs" # mount ssh volumes
-brew "mupdf-tools"
-brew "ffmpeg" # video converter
-
-brew "shfmt"
-brew "eza"
-brew "gcc"
-# npm install fixjson
-# brew install clang-format
-
-# WSL-only cask for the `cursor-agent` binary
-cask "cursor-cli"
diff --git a/homebrew/LinuxBrewfile b/homebrew/LinuxBrewfile
deleted file mode 100644
index 7c919a69..00000000
--- a/homebrew/LinuxBrewfile
+++ /dev/null
@@ -1,34 +0,0 @@
-# Custom taps
-tap "koekeishiya/formulae"
-tap "Rigellute/tap"
-tap "Schniz/tap"
-tap "rlue/utils"
-tap "epk/epk"
-tap "marromlam/custom"
-
-
-# Homebrew essentials
-brew "gcc"
-brew "ruby"
-brew "glibc"
-brew "bat" # alternative to cat
-brew "calcurse"
-brew "fpp" # facebook path picker
-brew "fzf" # fuzzy finder
-brew "git" # updated git
-brew "lazydocker"
-brew "lazygit" # awesome git util
-brew "git-delta" # pretty git diffs
-brew "ncurses" # needed for a bunch of stuff
-brew "neovim" # best editor on Earth
-brew "node"
-brew "marromlam/custom/xmlformat"
-brew "pandoc"
-brew "pkg-config"
-brew "python"
-brew "ripgrep" # like grep, but faster
-brew "rlue/utils/timer"
-brew "stow" # to create symbolic links
-brew "tmux" # terminal multiplexer
-brew "tree" # shows directory tree
-brew "wget" # like curl
diff --git a/homebrew/homebrew.sh b/homebrew/homebrew.sh
deleted file mode 100644
index 61e5f091..00000000
--- a/homebrew/homebrew.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-echo "================================================================================"
-echo "Installing homebrew"
-echo "--------------------------------------------------------------------------------";
-
-set -e
-
-if [[ "$(uname -m)" == "x86_64" ]]; then
- # intel / rossetta
- export HOMEBREW_PREFIX="/usr/local"
-else
- # running on Apple Silicon
- export HOMEBREW_PREFIX="/opt/homebrew"
-fi
-
-unset HOMEBREW_CELLAR
-export HOMEBREW_CELLAR="$HOMEBREW_PREFIX/Cellar"
-
-if test "$1" = "-f"; then
- if [[ -d "$HOMEBREW_PREFIX" ]]; then
- # Remove contents without deleting the prefix directory itself.
- sudo bash -c 'shopt -s dotglob nullglob; rm -rf "$1"/*' _ "$HOMEBREW_PREFIX"
- fi
- echo "Forcing homebrew install"
-else
- echo "Not forcing homebrew install..."
-fi
-
-if [[ ! -d "$HOMEBREW_PREFIX" ]]; then
- [[ ! -x git ]] && xcode-select --install || echo "cmd-line tools installed"
- /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-else
- echo "Homebrew already installed. Skipping."
-fi
-
-eval $($HOMEBREW_PREFIX/bin/brew shellenv)
-export XDG_DATA_DIRS="$HOMEBREW_PREFIX/share:$XDG_DATA_DIRS"
-brew install stow
-
-exit 0
-
-echo "--------------------------------------------------------------------------------";
-echo "Done "
-echo "================================================================================"
diff --git a/homebrew/ish-install.sh b/homebrew/ish-install.sh
deleted file mode 100644
index 9d312181..00000000
--- a/homebrew/ish-install.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-bash
-docker
-ssh
-bash
-curl
-tar
-go # <-- not working
-shadow
-nvim
-github-cli # <-- not working
-jq
-aws
-session-manager-plugin
diff --git a/homebrew/kitty.sh b/homebrew/kitty.sh
deleted file mode 100644
index 44c5ad21..00000000
--- a/homebrew/kitty.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ -d "$HOMEBREW_PREFIX/Cellar/kitty" ]]; then
- echo "kitty is already installed"
-else
- VERSION=0.43.1
- mkdir $HOMEBREW_PREFIX/Cellar/kitty
- pushd $HOMEBREW_PREFIX/Cellar/kitty
- wget https://github.com/kovidgoyal/kitty/releases/download/v$VERSION/kitty-$VERSION-x86_64.txz -O kitty.txz
- tar xf kitty.txz -C $HOMEBREW_PREFIX/Cellar/kitty
- ln -sf $HOMEBREW_PREFIX/Cellar/kitty/bin/kitty $HOMEBREW_PREFIX/bin
- rm kitty.txz
- popd
-fi
-
-# vim: fdm=marker
diff --git a/homebrew/linuxbrew.sh b/homebrew/linuxbrew.sh
deleted file mode 100644
index 3ea02e50..00000000
--- a/homebrew/linuxbrew.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ -d "$HOMEBREW_PREFIX/bin" ]]; then
- eval $($HOMEBREW_PREFIX/bin/brew shellenv)
-else
- sudo git clone --depth 1 https://github.com/Homebrew/brew $HOMEBREW_PREFIX/Homebrew
- mkdir $HOMEBREW_PREFIX/bin
- ln -s $HOMEBREW_PREFIX/Homebrew/bin/brew $HOMEBREW_PREFIX/bin
- eval $($HOMEBREW_PREFIX/bin/brew shellenv)
-fi
-
-brew install stow
-
-# vim: fdm=marker
diff --git a/homebrew/pdfcat.sh b/homebrew/pdfcat.sh
deleted file mode 100644
index 0d52ab86..00000000
--- a/homebrew/pdfcat.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ -d "$HOMEBREW_PREFIX/Cellar/termpdf.py" ]]; then
- echo "termpdf is already installed"
-else
- git clone git@github.com:marromlam/pdfcat.git $HOMEBREW_PREFIX/Cellar/pdfcat
- pushd $HOMEBREW_PREFIX/Cellar/pdfcat
- $HOMEBREW_PREFIX/bin/python3 -m pip install -r requirements.txt
- $HOMEBREW_PREFIX/bin/python3 -m pip install -e ../pdfcat
- ln -sf $HOMEBREW_PREFIX/Cellar/pdfcat/termpdf.py $HOMEBREW_PREFIX/bin
- ln -sf $HOMEBREW_PREFIX/Cellar/pdfcat/termpdf.py $HOMEBREW_PREFIX/bin/pdfcat
- popd
-fi
-
-# vim: fdm=marker
diff --git a/homebrew/rust.sh b/homebrew/rust.sh
deleted file mode 100644
index ad0938fc..00000000
--- a/homebrew/rust.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env bash
-
-# install rust
-# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
-# sources of the standard library.
-# rustup component add rust-src
-
-# rust analyzer
-# rustup +nightly component add rust-analyzer-preview
-
-# rustup compoent clippy
-
-# brew install rust # only one version of rust
-# brew install rustup # several versions fo rust
-rustup-init
-
-rustup component add rustfmt
-rustup component add clippy
-rustup component add rust-src
-# rustup component add rust-analysis-preview
-# rustup component add rust-analysis-preview-ui
-# rustup component add rust-analysis-preview-clippy
-
-# vim:foldmethod=marker
diff --git a/install b/install
deleted file mode 100644
index 5a7e72c4..00000000
--- a/install
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-CONFIG="install.conf.yaml"
-DOTBOT_DIR="dotbot"
-
-DOTBOT_BIN="bin/dotbot"
-BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-
-cd "${BASEDIR}"
-git -C "${DOTBOT_DIR}" submodule sync --quiet --recursive
-git submodule update --init --recursive "${DOTBOT_DIR}"
-
-"${BASEDIR}/${DOTBOT_DIR}/${DOTBOT_BIN}" -d "${BASEDIR}" -c "${CONFIG}" "${@}"
diff --git a/install.conf.yaml b/install.conf.yaml
deleted file mode 100644
index 58b87169..00000000
--- a/install.conf.yaml
+++ /dev/null
@@ -1,73 +0,0 @@
-- defaults:
- link:
- create: true
- relink: true
-
-- create:
- ~/.ssh:
- mode: 0600
- ~/.config:
- ~/Projects:
- ~/Projects/work:
- ~/Projects/personal:
-
-- clean: ["~"]
-
-- link:
- ~/.ssh:
- force: true
- mode: 0600
- path: ~/Projects/personal/private-dotfiles/files/.ssh
- ~/.gitconfig:
- force: true
- path: files/.gitconfig
- ~/.gitmessage:
- force: true
- path: files/.gitmessage
- ~/.bash_profile:
- force: true
- path: files/.bash_profile
- ~/.bashrc:
- force: true
- path: files/.bashrc
- ~/.zshrc:
- force: true
- path: files/.zshrc
- ~/.sh_profile:
- force: true
- path: files/.sh_profile
- ~/.rgignore:
- force: true
- path: files/.rgignore
- ~/.config:
- force: true
- path: files/.config
- ~/.hammerspoon:
- force: true
- path: files/.hammerspoon
- ~/.amethyst.yml:
- force: true
- path: files/.amethyst.yml
- ~/.dotfiles:
- force: true
- path: ~/Projects/personal/dotfiles
-
-- shell:
- - [
- zsh -c 'source ~/.zshrc; brew bundle --file=$HOME/.Brewfile',
- Install homebrew dependencies,
- ]
- - [git submodule update --init --recursive, Installing submodules]
- - [bash extra/macos_settings.sh, Installing macOS config]
- - [bash extra/keyboard.sh, Installing keyboard config]
- - [
- zsh -c 'source ~/.zshrc; python3 -m pip install -r $HOME/.dotfiles/requirements.txt',
- Installing python packages,
- ]
- - [
- zsh -c 'source ~/.zshrc; tmux start-server && tmux new-session -d && ~/.config/tmux/plugins/tpm/scripts/install_plugins.sh && tmux kill-server',
- Installing python packages,
- ]
- # - [source ~/.zshrc, Install fzf marks]
- # - [ bash extra/nvim.sh, Installing neovim config]
- # - [cp -n ./git/config.template ~/.gitconfig.local]
diff --git a/install.sh b/install.sh
index 2024e8e3..5f4b3dc8 100644
--- a/install.sh
+++ b/install.sh
@@ -1,79 +1,105 @@
-# Might as well ask for password up-front, right?
-set -e
-echo "Starting install script, please grant me sudo access..."
-sudo -v
+#!/usr/bin/env bash
+# Bootstrap installer — run with:
+# bash -c "$(curl -fsSL https://raw.githubusercontent.com/marromlam/dotfiles/main/install.sh)"
-# Keep-alive: update existing sudo time stamp if set, otherwise do nothing.
-while true; do
- sudo -n true
- sleep 60
- kill -0 "$$" || exit
-done 2>/dev/null &
+set -euo pipefail
-# machine type
-# first check if there is a .machine file in the home directory
-# if not, then check the hostname
-if [ -f ~/.machine ]; then
- MACHINEOS=$(cat ~/.machine)
-else
- unameOut="$(uname -s)"
- case "${unameOut}" in
- Linux*) MACHINEOS=Linux ;;
- Darwin*) MACHINEOS=Mac ;;
- CYGWIN*) MACHINEOS=Cygwin ;;
- MINGW*) MACHINEOS=MinGw ;;
- *) MACHINEOS="UNKNOWN:${unameOut}" ;;
- esac
- echo $MACHINEOS >~/.machine
-fi
-echo "Machine: $MACHINEOS"
+DOTFILES="${DOTFILES:-$HOME/Projects/personal/dotfiles}"
+REPO_URL="https://github.com/marromlam/dotfiles.git"
+
+step() { echo; echo "==> $*"; }
-# clone temp dir
-REPO_URL=https://raw.githubusercontent.com/marromlam/dotfiles
-REPO_BRANCH=main
-mkdir -p ${HOME}/tmp
-curl -o ${HOME}/tmp/homebrew_install.sh $REPO_URL/$REPO_BRANCH/homebrew/install.sh
-curl -o ${HOME}/tmp/keys.sh $REPO_URL/$REPO_BRANCH/extra/keys.sh
-curl -o ${HOME}/tmp/dotfiles.sh $REPO_URL/$REPO_BRANCH/extra/dotfiles.sh
-curl -o ${HOME}/tmp/reload_shell $REPO_URL/$REPO_BRANCH/scripts/reload_shell
-curl -o ${HOME}/tmp/preflight_wsl.sh $REPO_URL/$REPO_BRANCH/extra/windows/preflight_wsl.sh
+# ------------------------------------------------------------------------------
+# Detect machine type and write ~/.machine
+# ------------------------------------------------------------------------------
+detect_machine() {
+ if [[ -f "$HOME/.machine" ]]; then
+ echo "$HOME/.machine already set: $(cat "$HOME/.machine")"
+ return
+ fi
-# if [[ "$MACHINEOS" == "Mac" ]]; then
-# echo "Installing homebrew on macOS (forced=$0)"
-# bash ${HOME}/tmp/homebrew.sh $0
-# else
-# echo "Installing homebrew on Linux (forced=$0)"
-# export HOMEBREW_PREFIX="$HOME/.linuxbrew"
-# bash ${HOME}/tmp/linuxbrew.sh $0
-# fi
+ local os arch
+ os="$(uname -s)"
+ arch="$(uname -m)"
+
+ local machine
+ case "$os" in
+ Darwin)
+ if [[ "$arch" == "arm64" ]]; then machine="arm64-darwin"
+ else machine="x64-darwin"
+ fi ;;
+ Linux)
+ if grep -qi microsoft /proc/version 2>/dev/null; then machine="x64-wsl"
+ elif [[ "$arch" == "x86_64" ]]; then machine="x64-linux"
+ elif [[ "$arch" == "aarch64" ]]; then machine="arm64-linux"
+ elif [[ "$arch" == "i686" ]]; then machine="x32-linux"
+ else machine="x64-linux"
+ fi ;;
+ *) machine="x64-linux" ;;
+ esac
-export MACHINE=$(cat $HOME/.machine)
-echo "Machine: $MACHINE"
+ echo "$machine" > "$HOME/.machine"
+ echo "Detected machine: $machine"
+}
-# if MACHINE is 'x64-wsl' then install wsl
-if [[ "$MACHINE" == "x64-wsl" ]]; then
- bash $HOME/tmp/preflight_wsl.sh
- bash $HOME/.dotfiles/setup/wsl_network_setup.sh
- export HOMEBREW_PREFIX="/home/linuxbrew/.linuxbrew"
- sudo mkdir -p /home/linuxbrew/.linuxbrew
- sudo chown -R $(whoami) /home/linuxbrew/.linuxbrew
- echo "Installing homebrew on Linux (forced=$0)"
- bash ${HOME}/tmp/homebrew_install.sh "$1"
-fi
+# ------------------------------------------------------------------------------
+# Install minimal apt packages needed to bootstrap (git, curl)
+# Only runs on Linux where apt is available
+# ------------------------------------------------------------------------------
+apt_bootstrap() {
+ if ! command -v apt-get >/dev/null 2>&1; then
+ return
+ fi
+ if ! command -v curl >/dev/null 2>&1; then
+ step "Installing curl via apt"
+ sudo apt-get update -qq
+ sudo apt-get install -y curl
+ fi
+}
-mkdir -p ~/Projects/{work,personal}
+# ------------------------------------------------------------------------------
+# Download and run install_dependencies.sh from the repo
+# This installs Homebrew + all packages (including git and stow)
+# before we can clone the full repo.
+# ------------------------------------------------------------------------------
+install_dependencies() {
+ local raw_url="https://raw.githubusercontent.com/marromlam/dotfiles/main/install/install_dependencies.sh"
+ local tmp_script
+ tmp_script="$(mktemp /tmp/install_dependencies.XXXXXX.sh)"
+ step "Downloading install_dependencies.sh"
+ curl -fsSL "$raw_url" -o "$tmp_script"
+ chmod +x "$tmp_script"
+ step "Running install_dependencies.sh"
+ bash "$tmp_script"
+ rm -f "$tmp_script"
+}
-# install private dotfiles
-printf " \n\n"
-bash ${HOME}/tmp/keys.sh $1
+# ------------------------------------------------------------------------------
+# Clone or update the dotfiles repo
+# git is now available via Homebrew
+# ------------------------------------------------------------------------------
+clone_dotfiles() {
+ if [[ -d "$DOTFILES/.git" ]]; then
+ step "Updating dotfiles repo"
+ git -C "$DOTFILES" pull --ff-only
+ else
+ step "Cloning dotfiles to $DOTFILES"
+ mkdir -p "$(dirname "$DOTFILES")"
+ git clone "$REPO_URL" "$DOTFILES"
+ fi
-# create projects folder
+ step "Updating submodules"
+ git -C "$DOTFILES" submodule update --init --recursive
+}
-# clone dotfiles
-printf " \n\n"
-bash ${HOME}/tmp/dotfiles.sh -dotfiles
-sudo chsh -s $(which zsh)
+# ------------------------------------------------------------------------------
+# Main
+# ------------------------------------------------------------------------------
+detect_machine
+apt_bootstrap
+install_dependencies
+clone_dotfiles
-# clone dotfiles
-printf " \n\n"
-~/Projects/personal/dotfiles/install
+step "Running make install setup"
+cd "$DOTFILES"
+make install setup
diff --git a/homebrew/README-java.md b/install/README-java.md
similarity index 93%
rename from homebrew/README-java.md
rename to install/README-java.md
index 5deea4b1..78f7d949 100644
--- a/homebrew/README-java.md
+++ b/install/README-java.md
@@ -6,7 +6,7 @@ This directory contains a setup script for installing Java (OpenJDK) which is re
```bash
# From the dotfiles directory
-./homebrew/install-java-sonarqube.sh
+./install/install-java-sonarqube.sh
```
## What It Does
@@ -49,7 +49,7 @@ Check status in Neovim:
## Troubleshooting
**"Unable to locate a Java Runtime"**
-- Run the installation script: `./homebrew/install-java-sonarqube.sh`
+- Run the installation script: `./install/install-java-sonarqube.sh`
- Restart your terminal
- Verify: `java -version`
diff --git a/homebrew/install-java-sonarqube.sh b/install/install-java-sonarqube.sh
similarity index 100%
rename from homebrew/install-java-sonarqube.sh
rename to install/install-java-sonarqube.sh
diff --git a/homebrew/install.sh b/install/install_dependencies.sh
similarity index 77%
rename from homebrew/install.sh
rename to install/install_dependencies.sh
index 9d9297a2..c49b5c39 100644
--- a/homebrew/install.sh
+++ b/install/install_dependencies.sh
@@ -5,7 +5,7 @@ set -euo pipefail
FORCE_INSTALL=0
MACHINE_OVERRIDE=""
-if [[ "${1:-}" == "-f" ]]; then
+if [[ "${1:-}" == "--force" ]]; then
FORCE_INSTALL=1
shift
fi
@@ -55,11 +55,9 @@ ensure_prefix_dir() {
}
install_homebrew_macos() {
- if [[ "$FORCE_INSTALL" -eq 1 ]]; then
- if [[ -d "$HOMEBREW_PREFIX" ]]; then
- # Remove contents without deleting the prefix directory itself.
- sudo bash -c 'shopt -s dotglob nullglob; rm -rf "$1"/*' _ "$HOMEBREW_PREFIX"
- fi
+ if [[ "$FORCE_INSTALL" -eq 1 ]] && [[ -d "$HOMEBREW_PREFIX" ]]; then
+ echo "Removing existing Homebrew at $HOMEBREW_PREFIX..."
+ sudo rm -rf "$HOMEBREW_PREFIX"
fi
if [[ ! -d "$HOMEBREW_PREFIX" ]]; then
@@ -71,11 +69,9 @@ install_homebrew_macos() {
}
install_homebrew_linux() {
- if [[ "$FORCE_INSTALL" -eq 1 ]]; then
- if [[ -d "$HOMEBREW_PREFIX" ]]; then
- # Remove contents without deleting the prefix directory itself.
- sudo bash -c 'shopt -s dotglob nullglob; rm -rf "$1"/*' _ "$HOMEBREW_PREFIX"
- fi
+ if [[ "$FORCE_INSTALL" -eq 1 ]] && [[ -d "$HOMEBREW_PREFIX" ]]; then
+ echo "Removing existing Homebrew at $HOMEBREW_PREFIX..."
+ sudo rm -rf "$HOMEBREW_PREFIX"
fi
if [[ -d "$HOMEBREW_PREFIX/bin" ]]; then
@@ -111,7 +107,7 @@ brew_tap_once() {
if brew tap | grep -qx "$tap"; then
return
fi
- brew tap "$tap"
+ GIT_TERMINAL_PROMPT=0 brew tap "$tap" || echo "Warning: failed to tap $tap; skipping."
}
brew_install_once() {
@@ -145,10 +141,15 @@ brew_install_cask_once() {
}
install_kitty_linux() {
- if [[ "$OS_NAME" == "Darwin" ]]; then
+ # Skip on macOS (installed via cask) and WSL (use Windows-side kitty)
+ if [[ "$OS_NAME" == "Darwin" ]] || [[ "$MACHINE" == "x64-wsl" ]]; then
return
fi
+ if [[ "$FORCE_INSTALL" -eq 1 ]]; then
+ rm -rf "$HOMEBREW_PREFIX/Cellar/kitty" "$HOMEBREW_PREFIX/bin/kitty"
+ fi
+
if [[ -d "$HOMEBREW_PREFIX/Cellar/kitty" ]]; then
echo "kitty is already installed"
return
@@ -165,17 +166,21 @@ install_kitty_linux() {
}
install_pdfcat() {
- if [[ -d "$HOMEBREW_PREFIX/Cellar/pdfcat" ]]; then
+ local dest="$HOMEBREW_PREFIX/Cellar/pdfcat"
+
+ if [[ "$FORCE_INSTALL" -eq 1 ]]; then
+ rm -rf "$dest" "$HOMEBREW_PREFIX/bin/pdfcat"
+ fi
+
+ if [[ -d "$dest" ]]; then
echo "pdfcat is already installed"
return
fi
- git clone git@github.com:marromlam/pdfcat.git "$HOMEBREW_PREFIX/Cellar/pdfcat"
- pushd "$HOMEBREW_PREFIX/Cellar/pdfcat" >/dev/null
- "$HOMEBREW_PREFIX/bin/python3" -m pip install -r requirements.txt
- "$HOMEBREW_PREFIX/bin/python3" -m pip install -e ../pdfcat
- ln -sf "$HOMEBREW_PREFIX/Cellar/pdfcat/termpdf.py" "$HOMEBREW_PREFIX/bin/termpdf.py"
- ln -sf "$HOMEBREW_PREFIX/Cellar/pdfcat/termpdf.py" "$HOMEBREW_PREFIX/bin/pdfcat"
+ git clone https://github.com/marromlam/pdfcat.git "$dest"
+ pushd "$dest" >/dev/null
+ "$HOMEBREW_PREFIX/bin/python3" -m pip install -e .
+ ln -sf "$dest/pdfcat" "$HOMEBREW_PREFIX/bin/pdfcat"
popd >/dev/null
}
@@ -199,8 +204,9 @@ install_rust() {
}
install_ish_packages() {
- echo "iSH detected. Install these packages manually in iSH:"
- echo "bash docker ssh curl tar shadow nvim jq aws session-manager-plugin"
+ echo "iSH detected. Installing packages via apk..."
+ apk update
+ apk add bash curl tar shadow git neovim tmux fzf ripgrep jq
}
if [[ "$MACHINE" == "x32-linux" ]]; then
@@ -210,6 +216,10 @@ fi
bootstrap_homebrew
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# shellcheck source=install/install_sonarqube.sh
+source "$SCRIPT_DIR/install_sonarqube.sh"
+
TAPS_COMMON=(
"browsh-org/homebrew-browsh"
"koekeishiya/formulae"
@@ -217,6 +227,7 @@ TAPS_COMMON=(
"Schniz/tap"
"rlue/utils"
"epk/epk"
+ "marromlam/custom"
)
TAPS_MAC=(
@@ -258,6 +269,7 @@ BREW_MAC=(
"lua"
"ncurses"
"pkg-config"
+ "pkgconf"
"readline"
"rlue/utils/timer"
"mupdf-tools"
@@ -265,6 +277,16 @@ BREW_MAC=(
"docker"
"colima"
"lazydocker"
+ "cmake"
+ "fswatch"
+ "p7zip"
+ "sevenzip"
+ "mosh"
+ "tailscale"
+ "timg"
+ "ykman"
+ "yt-dlp"
+ "marromlam/custom/xmlformat"
)
BREW_LINUX=(
@@ -302,9 +324,15 @@ BREW_LINUX=(
"lsd"
"exa"
"gcc"
+ "mosh"
"sshfs"
"zsh-syntax-highlighting"
"zsh-autosuggestions"
+ "bat"
+ "calcurse"
+ "eza"
+ "jq"
+ "marromlam/custom/xmlformat"
)
CASK_MAC_ONLY=(
@@ -314,8 +342,17 @@ CASK_MAC_ONLY=(
"orion"
"obsidian"
"rectangle"
+ "amethyst"
+ "hammerspoon"
"grandperspective"
"keycastr"
+ "ghostty"
+ "appcleaner"
+ "chatgpt"
+ "claude-code"
+ "codex"
+ "copilot-cli"
+ "whatsapp"
"domzilla-caffeine"
"font-hasklug-nerd-font"
"font-jetbrains-mono"
@@ -366,10 +403,12 @@ fi
install_pdfcat
install_rust
+install_sonarqube
brew_install_once "pixi"
-if [[ -x "${HOME}/Projects/personal/dotfiles/homebrew/install_zsh.sh" ]]; then
- bash "${HOME}/Projects/personal/dotfiles/homebrew/install_zsh.sh"
+DOTFILES_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+if [[ -x "$DOTFILES_ROOT/install/install_zsh.sh" ]]; then
+ bash "$DOTFILES_ROOT/install/install_zsh.sh"
elif [[ -x "${HOME}/tmp/install_zsh.sh" ]]; then
bash "${HOME}/tmp/install_zsh.sh"
fi
diff --git a/install/install_sonarqube.sh b/install/install_sonarqube.sh
new file mode 100644
index 00000000..0504675f
--- /dev/null
+++ b/install/install_sonarqube.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+install_sonarqube() {
+ # Install OpenJDK (required for sonarlint-language-server)
+ brew_install_once "openjdk"
+
+ # Create macOS system symlink for system-wide Java access
+ if [[ "$OS_NAME" == "Darwin" ]]; then
+ local openjdk_path
+ openjdk_path="$(brew --prefix)/opt/openjdk/libexec/openjdk.jdk"
+ local java_link="/Library/Java/JavaVirtualMachines/openjdk.jdk"
+ if [[ ! -L "$java_link" ]] && [[ ! -d "$java_link" ]]; then
+ sudo ln -sfn "$openjdk_path" "$java_link"
+ fi
+ fi
+
+ # Install sonarlint-language-server via Mason (nvim headless)
+ local mason_bin="$HOME/.local/share/nvim/mason/bin/sonarlint-language-server"
+ if [[ ! -f "$mason_bin" ]]; then
+ if command -v nvim >/dev/null 2>&1; then
+ nvim --headless -c "MasonInstall sonarlint-language-server" -c "qa"
+ else
+ echo "nvim not found; skipping sonarlint-language-server Mason install."
+ fi
+ fi
+}
+
+# If sourced (from install_dependencies.sh), functions are available but not run.
+# If executed directly, run install_sonarqube.
+if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
+ # Need brew_install_once and OS_NAME when run standalone
+ if ! command -v brew >/dev/null 2>&1; then
+ echo "brew not found. Run install_dependencies.sh first."
+ exit 1
+ fi
+ OS_NAME="$(uname -s)"
+ brew_install_once() {
+ local pkg="$1"
+ if brew list --formula "$pkg" >/dev/null 2>&1; then return; fi
+ brew install "$pkg" || brew reinstall "$pkg" || echo "Failed to install $pkg; continuing."
+ }
+ install_sonarqube
+fi
diff --git a/homebrew/install_zsh.sh b/install/install_zsh.sh
similarity index 100%
rename from homebrew/install_zsh.sh
rename to install/install_zsh.sh
diff --git a/scripts/couscous.sh b/scripts/couscous.sh
deleted file mode 100755
index 78dd8fff..00000000
--- a/scripts/couscous.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-THEME=$1
-KITTYTHEMES=$HOME/.config/kitty/kitty-themes
-
-# clone all kitty themes if needed
-if [ ! -d $KITTYTHEMES ]; then
- git clone --depth 1 http://github.com/dexpota/kitty-themes.git $KITTYTHEMES
-fi
-
-# show all themes
-ls $KITTYTHEMES/themes
-
-# Change kitty theme
-kitty @ set-colors -a "$KITTYTHEMES/themes/$THEME.conf"
-rm -rf $HOME/.config/kitty/theme.conf
-ln -s $KITTYTHEMES/themes/$THEME.conf $HOME/.config/kitty/theme.conf
diff --git a/scripts/fzrepl b/scripts/fzrepl
deleted file mode 100755
index 435e5d1a..00000000
--- a/scripts/fzrepl
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env bash
-
-usage() {
- less -FEXR <<'HELP'
-fzrepl
- interactively edit stdin using stream filters like awk, sed, jq
-
- -c, --cmd command used to filter input
- -q, --query default command string to use
-
-command history can be saved to a file by setting the environment variable
-FZREPL_FILE
-
-examples:
- echo 'foo bar' | fzrepl -c 'awk {q}' -q '{print}'
- echo 'hello world' | fzrepl -q p 'sed -n {q}'
- FZREPL_FILE=jqhistory fzrepl jq package.json
-HELP
-}
-
-# TODO: better "wrapping", this is painful:
-# fzrepl 'node -e {q}' -q "done = data => data;\nlet A='';process.stdin.on('data',x=>A=A.concat(x.toString())).on('end',()=>{let d = done(A);process.stdout.write(`${String.prototype.trim.call(typeof d==='string'?d:JSON.stringify(d,null,2))}\n`)})"
-
-declare tmpfile=/tmp/fzreplinput
-declare cmd
-declare default_query
-declare output
-
-declare -A colors
-colors[red]=$(tput setaf 1)
-colors[green]=$(tput setaf 2)
-colors[reset]=$(tput sgr0)
-
-cleanup() {
- [[ -e "$tmpfile" ]] && rm "$tmpfile"
-}
-trap cleanup SIGHUP SIGINT SIGTERM
-
-color() {
- local color
- color="$1"; shift
- printf '%s' "${colors[$color]}" "$*" "${colors[reset]}"
-}
-
-err() {
- color red "$@" >&2
- return 1
-}
-
-die() {
- (( $# > 0 )) && err "$@"
- exit 1
-}
-
-for arg; do
- case $arg in
- -q|--query)
- [[ -z $2 || $2 = -* ]] && die "missing argument to $1"
- default_query="$2"
- shift 2 ;;
- -c|--cmd)
- [[ -z $2 || $2 = -* ]] && die "missing argument to $1"
- cmd="$2"
- shift 2 ;;
- -h|--help) usage; exit ;;
- *) break 2;
- esac
-done
-
-if [[ -z $cmd && -n $1 && ! -f $1 ]]; then
- cmd="$1"
- shift
-fi
-
-if [[ -z $cmd ]]; then
- usage
- exit 1
-fi
-
-if [[ $cmd != *'{q}'* ]]; then
- cmd+=' {q}'
-fi
-
-if [[ -n $1 && -f $1 ]]; then
- file=$1
- shift
-fi
-
-if [[ -z $file ]]; then
- file=/dev/stdin
-fi
-
-mapfile -t REPLY < <(
- tee "$tmpfile" < "$file" | fzf \
- --sync \
- --ansi \
- --height=100% \
- --disabled \
- --print-query \
- --query="$default_query" \
- ${FZREPL_FILE:+--history=$FZREPL_FILE} \
- --preview="$cmd < '$tmpfile'"
-)
-
-q="${REPLY[0]}"
-q=${q@Q}
-echo "${cmd//'{q}'/$q}"
-
-
-# vim: ft=bash
diff --git a/scripts/gwrm b/scripts/gwrm
new file mode 100755
index 00000000..6370e3ce
--- /dev/null
+++ b/scripts/gwrm
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+# gwrm — remove a git worktree and optionally delete its branch
+# Usage: gwrm [-f] [-d|-D]
+# -f force remove even if worktree has uncommitted changes
+# -d delete local branch after removing worktree (safe, merged only)
+# -D force-delete local branch after removing worktree
+
+set -euo pipefail
+
+force=''
+delete_branch=''
+
+while getopts 'fdD' opt; do
+ case $opt in
+ f) force='--force' ;;
+ d) delete_branch='-d' ;;
+ D) delete_branch='-D' ;;
+ *) echo "Usage: gwrm [-f] [-d|-D] " >&2; exit 1 ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+if [ $# -ne 1 ]; then
+ echo "Usage: gwrm [-f] [-d|-D] " >&2
+ exit 1
+fi
+
+target=$1
+
+# Resolve worktree path and branch from `git worktree list --porcelain`
+wt_path=''
+wt_branch=''
+cur_path=''
+cur_branch=''
+
+while IFS= read -r line; do
+ case $line in
+ 'worktree '*) cur_path="${line#worktree }" ;;
+ 'branch refs/heads/'*) cur_branch="${line#branch refs/heads/}" ;;
+ '')
+ # end of a worktree block — check if it matches the target
+ if [ "$cur_path" = "$target" ] || [ "$cur_branch" = "$target" ]; then
+ wt_path="$cur_path"
+ wt_branch="$cur_branch"
+ fi
+ cur_path=''; cur_branch=''
+ ;;
+ esac
+done < <(git worktree list --porcelain; echo '')
+
+if [ -z "$wt_path" ]; then
+ echo "gwrm: no worktree found matching '$target'" >&2
+ exit 1
+fi
+
+# Safety: refuse to remove the current worktree
+if [ "$wt_path" = "$(git worktree list --porcelain | awk 'NR==2{print $2}')" ] || \
+ [ "$(realpath "$wt_path")" = "$(realpath "$(pwd)")" ]; then
+ echo "gwrm: cannot remove the current worktree" >&2
+ exit 1
+fi
+
+echo "Removing worktree: $wt_path"
+git worktree remove $force "$wt_path"
+git worktree prune
+
+if [ -n "$delete_branch" ] && [ -n "$wt_branch" ]; then
+ echo "Deleting branch: $wt_branch"
+ git branch "$delete_branch" "$wt_branch"
+fi
+
+# vim: ft=bash
diff --git a/scripts/install-java-sonarlint.sh b/scripts/install-java-sonarlint.sh
deleted file mode 100755
index d82fa8e1..00000000
--- a/scripts/install-java-sonarlint.sh
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/env bash
-#
-# Safe Java + SonarLint Installer for macOS
-# Installs everything via Homebrew to keep it clean and manageable
-#
-# Usage: ./install-java-sonarlint.sh
-
-set -euo pipefail
-
-# Colors for output
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
-NC='\033[0m' # No Color
-
-# Helper functions
-log_info() {
- echo -e "${BLUE}[INFO]${NC} $*"
-}
-
-log_success() {
- echo -e "${GREEN}[SUCCESS]${NC} $*"
-}
-
-log_warning() {
- echo -e "${YELLOW}[WARNING]${NC} $*"
-}
-
-log_error() {
- echo -e "${RED}[ERROR]${NC} $*"
-}
-
-# Check if running on macOS
-if [[ "$(uname -s)" != "Darwin" ]]; then
- log_error "This script is designed for macOS only"
- exit 1
-fi
-
-# Determine Homebrew prefix (supports both Intel and Apple Silicon)
-if [[ -d "/opt/homebrew" ]]; then
- BREW_PREFIX="/opt/homebrew"
-elif [[ -d "/usr/local" ]]; then
- BREW_PREFIX="/usr/local"
-else
- log_error "Homebrew installation not found"
- exit 1
-fi
-
-log_info "Using Homebrew prefix: $BREW_PREFIX"
-
-# Check if Homebrew is installed
-if ! command -v brew &> /dev/null; then
- log_error "Homebrew is not installed. Please install it first:"
- echo " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
- exit 1
-fi
-
-log_success "Homebrew is installed"
-
-# Update Homebrew
-log_info "Updating Homebrew..."
-brew update || log_warning "Failed to update Homebrew (continuing anyway)"
-
-# Check if Java is already installed
-if command -v java &> /dev/null && java -version &> /dev/null; then
- JAVA_VERSION=$(java -version 2>&1 | head -n 1)
- log_success "Java is already installed: $JAVA_VERSION"
-
- # Ask if user wants to reinstall
- read -p "Do you want to reinstall/update Java? [y/N] " -n 1 -r
- echo
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
- log_info "Skipping Java installation"
- SKIP_JAVA=true
- fi
-fi
-
-# Install OpenJDK via Homebrew
-if [[ "${SKIP_JAVA:-false}" != "true" ]]; then
- log_info "Installing OpenJDK 21 (LTS) via Homebrew..."
-
- # Install openjdk@21
- if brew list openjdk@21 &> /dev/null; then
- log_info "OpenJDK 21 is already installed, upgrading if needed..."
- brew upgrade openjdk@21 || log_warning "OpenJDK 21 is already up to date"
- else
- brew install openjdk@21
- fi
-
- log_success "OpenJDK 21 installed successfully"
-
- # Determine the correct openjdk path
- OPENJDK_PATH="$BREW_PREFIX/opt/openjdk@21"
-
- if [[ ! -d "$OPENJDK_PATH" ]]; then
- log_error "OpenJDK installation directory not found: $OPENJDK_PATH"
- exit 1
- fi
-
- log_info "OpenJDK installed at: $OPENJDK_PATH"
-fi
-
-# Determine shell config file
-if [[ -n "${ZSH_VERSION:-}" ]] || [[ "$SHELL" == *"zsh"* ]]; then
- SHELL_CONFIG="$HOME/.zshrc"
-elif [[ -n "${BASH_VERSION:-}" ]] || [[ "$SHELL" == *"bash"* ]]; then
- SHELL_CONFIG="$HOME/.bashrc"
-else
- SHELL_CONFIG="$HOME/.profile"
-fi
-
-log_info "Detected shell config: $SHELL_CONFIG"
-
-# Update shell configuration with JAVA_HOME and PATH
-if [[ "${SKIP_JAVA:-false}" != "true" ]]; then
- log_info "Configuring environment variables in $SHELL_CONFIG..."
-
- # Create backup
- cp "$SHELL_CONFIG" "$SHELL_CONFIG.backup-$(date +%Y%m%d-%H%M%S)"
- log_info "Created backup: $SHELL_CONFIG.backup-$(date +%Y%m%d-%H%M%S)"
-
- # Remove old Java entries if they exist
- sed -i.tmp '/# Java (OpenJDK) - Homebrew/d' "$SHELL_CONFIG" 2>/dev/null || true
- sed -i.tmp '/export JAVA_HOME.*openjdk/d' "$SHELL_CONFIG" 2>/dev/null || true
- sed -i.tmp '/export PATH.*openjdk.*bin/d' "$SHELL_CONFIG" 2>/dev/null || true
- rm -f "$SHELL_CONFIG.tmp"
-
- # Add new Java configuration
- cat >> "$SHELL_CONFIG" << EOF
-
-# Java (OpenJDK) - Homebrew
-export JAVA_HOME="$BREW_PREFIX/opt/openjdk@21"
-export PATH="\$JAVA_HOME/bin:\$PATH"
-EOF
-
- log_success "Environment variables configured in $SHELL_CONFIG"
-
- # Export for current session
- export JAVA_HOME="$BREW_PREFIX/opt/openjdk@21"
- export PATH="$JAVA_HOME/bin:$PATH"
-fi
-
-# Verify Java installation
-if command -v java &> /dev/null; then
- JAVA_VERSION=$(java -version 2>&1 | head -n 1)
- log_success "Java verification: $JAVA_VERSION"
-
- # Show Java path
- JAVA_PATH=$(which java)
- log_info "Java executable: $JAVA_PATH"
-
- # Show JAVA_HOME
- log_info "JAVA_HOME: ${JAVA_HOME:-not set}"
-else
- log_error "Java installation verification failed"
- log_info "Please restart your terminal and run: java -version"
-fi
-
-# Install Mason if not already installed (for Neovim)
-log_info "Checking for Neovim installation..."
-if command -v nvim &> /dev/null; then
- log_success "Neovim is installed"
-
- # Check if Mason is available
- log_info "Verifying Mason installation in Neovim..."
- if nvim --headless -c "lua if pcall(require, 'mason') then print('MASON_OK') else print('MASON_NOT_FOUND') end" -c "qa" 2>&1 | grep -q "MASON_OK"; then
- log_success "Mason is installed in Neovim"
-
- # Install sonarlint-language-server via Mason
- log_info "Installing sonarlint-language-server via Mason..."
- nvim --headless -c "lua require('mason.api.command').MasonInstall({'sonarlint-language-server'})" -c "sleep 30000m" -c "qa" 2>&1 &
- MASON_PID=$!
-
- log_info "Mason is installing sonarlint-language-server (PID: $MASON_PID)"
- log_info "This may take a few minutes..."
-
- # Wait for Mason installation
- wait $MASON_PID || log_warning "Mason installation may have issues, check :Mason in Neovim"
-
- log_success "SonarLint installation initiated via Mason"
- else
- log_warning "Mason not found in Neovim"
- log_info "SonarLint will be installed automatically when you open Neovim"
- fi
-else
- log_warning "Neovim is not installed"
- log_info "Install Neovim first, then SonarLint will be installed automatically"
-fi
-
-# Summary
-echo ""
-echo "═══════════════════════════════════════════════════════════════"
-log_success "Installation Complete!"
-echo "═══════════════════════════════════════════════════════════════"
-echo ""
-log_info "Summary:"
-echo " ✓ Java (OpenJDK 21) installed via Homebrew"
-echo " ✓ JAVA_HOME configured: $BREW_PREFIX/opt/openjdk@21"
-echo " ✓ Java added to PATH in $SHELL_CONFIG"
-echo " ✓ SonarLint installation initiated"
-echo ""
-log_warning "IMPORTANT: Restart your terminal or run:"
-echo " source $SHELL_CONFIG"
-echo ""
-log_info "To verify the installation, run:"
-echo " java -version"
-echo " echo \$JAVA_HOME"
-echo ""
-log_info "In Neovim, check Mason status with:"
-echo " :Mason"
-echo " :LspInfo"
-echo ""
-log_info "Installation locations (all in Homebrew):"
-echo " Java: $BREW_PREFIX/opt/openjdk@21"
-echo " Mason tools: ~/.local/share/nvim/mason/"
-echo ""
-log_success "All done! 🎉"
diff --git a/scripts/jukitty b/scripts/jukitty
deleted file mode 100755
index e46abf18..00000000
--- a/scripts/jukitty
+++ /dev/null
@@ -1,64 +0,0 @@
-_jukitty(){
- #nvim $1
-
- # 1 - First export the display
- export DISPLAY=:0.0
-
- # 2 - Check whether lemonade is running
- ps cax | grep lemonade> /dev/null
- if [ $? -eq 0 ]; then
- echo "= lemonade is running. ="
- else
- echo "= lemonade was not running... lemonade was launched. ="
- nohup lemonade server -allow 127.0.0.1 &
- fi
-
- # 3 - Generate random string as window titles
- EDITOR_ID=`xxd -l4 -ps /dev/urandom`
- KERNEL_ID=`xxd -l4 -ps /dev/urandom`
-
- # 4 - Launch a new tab / os-window and split it
- KE_ID=`kitty @ launch --type=tab --title $EDITOR_ID --keep-focus`
- KK_ID=`kitty @ launch -m title:$EDITOR_ID --title $KERNEL_ID --keep-focus`
-
- # 5 -put juKitty as window name
- kitty @ set-tab-title --match title:$EDITOR_ID "juKitty"
-
- echo "keditor" $KE_ID
- echo "kkernel" $KK_ID
-
- # export KITTY_WINDOW_ID to be the one in the KKERNEL_ID window
- kitty @ send-text --match title:$EDITOR_ID "export KITTY_WINDOW_ID=${KK_ID}\n"
- # open nvim in first window
- kitty @ send-text --match title:$EDITOR_ID "nvim $1\n"
- kitty @ send-text --match title:$KERNEL_ID "alias ssh=ssh -R 2489:127.0.0.1:2489\n"
-
- #nvim $1
-
- kitty @ focus-tab --match title:$KERNEL_ID
- #LOGO=${cat << EndOfMessage
- # _ _ __ _ _ _
- # (_) _ _ | |/ / (_) | |_ | |_ _ _
- # | | | | | | | ' / | | | __| | __| | | | |
- # | | | |_| | | . \ | | | |_ | |_ | |_| |
- # _/ | \__,_| |_|\_\ |_| \__| \__| \__, |
- # |__/ |___/
- #EndOfMessage
- #}
-
- merde="
- _ _ __ _ _ _
- (_) _ _ | |/ / (_) | |_ | |_ _ _
- | | | | | | | ' / | | | __| | __| | | | |
- | | | |_| | | . \ | | | |_ | |_ | |_| |
- _/ | \__,_| |_|\_\ |_| \__| \__| \__, |
- |__/ |___/
- "
- #echo $merde | kitty @ send-text --match title:$KERNEL_ID --stdin
-
- kitty @ send-text --match title:$KERNEL_ID "clc; echo juKitty kernel running at ${KERNEL_ID} with window ID = ${KK_ID}\n"
- #ls | kitty @ send-text --match title:$KERNEL_ID --stdin
- #kitty @ send-text --match title:$KERNEL_ID cat ls
-}
-
-_jukitty "$@"
diff --git a/scripts/killer b/scripts/killer
deleted file mode 100755
index 6e0a9d3f..00000000
--- a/scripts/killer
+++ /dev/null
@@ -1 +0,0 @@
-ps -ax | fzf -m --layout=reverse | xargs | python -c "import sys; print('\n'.join([el.split(' ')[-1] for el in sys.stdin.read().replace('tty','?? ').split(' ??')][:-1]))" | xargs
diff --git a/scripts/rgfzf b/scripts/rgfzf
index f1b61970..8ca8b38c 100755
--- a/scripts/rgfzf
+++ b/scripts/rgfzf
@@ -20,7 +20,7 @@ IFS=: read -ra selected < <(
)
if [[ ${selected[0]} == *.pdf ]]; then
- [ -n "${selected[0]}" ] && termpdf.py "${selected[0]}" "+${selected[1]}"
+ [ -n "${selected[0]}" ] && pdfcat "${selected[0]}" "+${selected[1]}"
else
[ -n "${selected[0]}" ] && $EDITOR "${selected[0]}" "+${selected[1]}"
fi
diff --git a/scripts/tex-preview b/scripts/tex-preview
deleted file mode 100755
index 12c66edc..00000000
--- a/scripts/tex-preview
+++ /dev/null
@@ -1,34 +0,0 @@
-TEXCODE=$1
-
-# %& -job-name=newfilenameialwayswanted
-
-
-mkdir -p /tmp/tex-preview
-rm -rf /tmp/tex-preview/output.tex && touch /tmp/tex-preview/output.tex
-
-echo "\documentclass[10pt]{standalone}" > /tmp/tex-preview/output.tex
-echo "\usepackage{xcolor}" >> /tmp/tex-preview/output.tex
-# echo "\usepackage[showframe]{geometry}" >> /tmp/tex-preview/output.tex
-echo "\begin{document}" >> /tmp/tex-preview/output.tex
-echo "\color{white}" >> /tmp/tex-preview/output.tex
-echo "%%%%%" >> /tmp/tex-preview/output.tex
-# echo "\centering \verb|$1|" >> /tmp/tex-preview/output.tex
-echo " " >> /tmp/tex-preview/output.tex
-/usr/bin/cat $1 >> /tmp/tex-preview/output.tex
-echo " " >> /tmp/tex-preview/output.tex
-echo "%%%%%" >> /tmp/tex-preview/output.tex
-echo "\end{document}" >> /tmp/tex-preview/output.tex
-
-
-pushd /tmp/tex-preview > /dev/null
-# pdflatex output.tex > pdflatex.log 2>&1
-/home3/marcos.romero/.linuxbrew/bin/pdflatex -halt-on-error -interaction=nonstopmode output.tex > pdflatex.log 2>&1
-
-if which kitty >/dev/null; then
- kitty +kitten icat /tmp/tex-preview/output.pdf
-else
- echo "Compiled pdf at: /tmp/tex-preview/output.pdf"
-fi
-popd > popd
-
-# vim: ft=sh
diff --git a/scripts/vimura b/scripts/vimura
deleted file mode 100755
index 139ca556..00000000
--- a/scripts/vimura
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-if [ $1 == "neovim" ]; then
- synctex_command="nvr --remote +%{line} %{input}"
-else
- synctex_command="vim --servername vimd --remote +%{line} %{input}"
-fi
-zathura -x "$synctex_command" ${@:2}
diff --git a/todo.md b/todo.md
deleted file mode 100644
index ac39620d..00000000
--- a/todo.md
+++ /dev/null
@@ -1,6 +0,0 @@
-- [ ] Check what is the contour cli utility
-- [ ] https://github.com/rebelot/heirline.nvim
-
-
-
-