Compare commits

...
Sign in to create a new pull request.

138 commits

Author SHA1 Message Date
dependabot[bot]
46b28c9a08
chore(deps): bump actions/checkout from 4.3.1 to 7.0.0 (#29)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.1 to 7.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](34e114876b...9c091bb21b)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 21:22:10 +02:00
b791c20974 ci: run full installer end-to-end; add Dependabot for actions
The validate job checks configs but never executes install.sh, which
is what actually rots (apt repo URLs, GPG fingerprints, pinned
checksums). New job runs the complete install plus --unlink as a
normal user in a pristine ubuntu:24.04 container. Dependabot keeps
the pinned GitHub Actions current monthly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:18:57 +02:00
c45d1ff108 feat: enable tmux session auto-restore on server start
Resurrect + continuum were already saving every 15 minutes; this makes
sessions come back automatically after a reboot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:18:57 +02:00
c3cd129478 feat: manage bat and Claude Code configs; add --unlink mode
- New managed configs: .config/bat (ANSI theme so bat follows the
  terminal palette) and .claude/settings.json, with a .gitignore guard
  so only settings.json under .claude/ is trackable.
- dotfiles.sh: drive linking from a single link map and add
  unlink_dotfiles; install.sh grows --unlink to cleanly remove every
  symlink pointing into the repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:17:37 +02:00
6861ff1e16 feat: add local override hooks for zsh and git
~/.zshrc.local and ~/.gitconfig.local hold machine-specific settings
(secrets, work identity, installer PATH additions) so third-party
installers stop dirtying the tracked configs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:16:17 +02:00
5123fb4349 fix: config review fixes
- .gitconfig: correct misspelled user email, fix del-remote alias
  (expanded to 'git git remote prune'), filter 'today' to own commits
- .zshrc: guard lt() shift with no args, drop duplicate ~/.local/bin
  PATH entry, dedupe history (HIST_IGNORE_ALL_DUPS, HIST_IGNORE_SPACE)
- wezterm: fix hyperlink regex char class (0.9 -> 0-9)
- extras: bump nvm to v0.40.5 with verified installer checksum

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:16:01 +02:00
84b99788a7 feat: manage ssh client config
Symlink .ssh/config into ~/.ssh with proper directory permissions.
Guard .gitignore so only the client config is trackable — keys and
anything else under .ssh/ can never be committed. Also drop a
redundant tmux ignore rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:16:01 +02:00
Brian Pooe
a33c46d130 Persist zsh command history 2026-07-06 18:58:59 +02:00
Brian Pooe
97ad246684 fix: use canonical Mason plugin dependency 2026-06-11 23:17:53 +02:00
Brian Pooe
2eef4edfc5 fix: persist Homebrew path in validation workflow 2026-06-11 23:15:01 +02:00
Brian Pooe
e2170063f3 fix: install Homebrew in validation workflow 2026-06-11 21:37:32 +02:00
Brian Pooe
db49fc1a56 feat: harden dotfiles installer and add automated validation 2026-06-11 20:38:19 +02:00
Brian Pooe
394a9af367 fix: align setup with Pop!_OS toolchain 2026-06-11 18:37:16 +02:00
995af1df20
Merge pull request #28 from brianpooe/claude/cool-hopper-8vgG8
feat: control WezTerm appearance from .zshrc via generated env.lua
2026-06-11 18:10:50 +02:00
Claude
291a5faffb
feat: control WezTerm appearance from .zshrc via generated env.lua
All user-tunable knobs now live in one block at the top of .zshrc:
KANAGAWA_THEME, WEZTERM_FONT_SIZE, WEZTERM_WINDOW_OPACITY,
WEZTERM_TEXT_OPACITY.

GUI-launched WezTerm never inherits shell exports (which is why
WEZTERM_THEME silently did nothing on desktop launches). Reuse the
existing tmux current-theme.conf pattern: .zshrc writes the values to
~/.config/wezterm/env.lua (only when they change), and wezterm.lua
dofile()s it and registers it in the config reload watch list — so
editing .zshrc and opening a new shell restyles the running window.

Precedence in wezterm.lua: env.lua > process env > defaults.
env.lua is gitignored (machine-local, generated).
2026-06-11 15:41:59 +00:00
2acf2d481b
Merge pull request #27 from brianpooe/claude/cool-hopper-8vgG8
Claude/cool hopper 8vg g8
2026-06-11 17:37:41 +02:00
Claude
32b1cb085a
Reapply "fix(tmux): restore clear-screen as prefix + Ctrl+l"
This reverts commit 97ba2271e2.
2026-06-11 15:36:27 +00:00
Claude
97ba2271e2
Revert "fix(tmux): restore clear-screen as prefix + Ctrl+l"
This reverts commit 48fba064b7.
2026-06-11 15:33:36 +00:00
Claude
48fba064b7
fix(tmux): restore clear-screen as prefix + Ctrl+l
vim-tmux-navigator captures plain Ctrl+l for right-pane navigation, which
shadows the shell's clear-screen, and prefix + l is already bound to
resize-pane. Add the navigator's documented passthrough so
Ctrl+Space, Ctrl+l clears the terminal.
2026-06-11 15:31:30 +00:00
f75fb0aff3
Merge pull request #26 from brianpooe/claude/cool-hopper-8vgG8
fix(install): install JetBrainsMono Nerd Font
2026-06-11 17:28:37 +02:00
Claude
d7bb34e1ef
fix(install): install JetBrainsMono Nerd Font
The configs (wezterm.lua font, starship symbols, eza icons) assume
'JetBrainsMono Nerd Font', which was an Arch package in the old setup.
Ubuntu's fonts-jetbrains-mono is the plain family without Nerd glyphs,
so WezTerm fell back to a default font and warned on every launch.

lib/fonts.sh downloads the official nerd-fonts release tarball into
~/.local/share/fonts/JetBrainsMonoNerdFont and runs fc-cache. Skips if
fc-list already reports the family. fontconfig added to the apt base
list for fc-list/fc-cache.
2026-06-11 15:27:38 +00:00
7f5cd79b5d
Merge pull request #25 from brianpooe/claude/cool-hopper-8vgG8
fix(install): use Brave Beta's own keyring (not the stable one)
2026-06-11 17:23:11 +02:00
Claude
9f3e6ba049
fix(install): use Brave Beta's own keyring (not the stable one)
Brave's Beta channel is signed with its own key (C3DE1DD4F661CDCB).
The previous attempt to share the stable keyring failed at apt update
with NO_PUBKEY because the release bucket's keyring only contains the
stable channel's key.

The correct URL is the beta bucket itself with the channel-specific
filename: brave-browser-apt-beta.s3.brave.com/brave-browser-beta-archive-keyring.gpg
2026-06-11 15:22:14 +00:00
f0cc4fc01f
Merge pull request #24 from brianpooe/claude/cool-hopper-8vgG8
fix(install): correct Brave Beta keyring URL + make add_apt_repo robust
2026-06-11 17:20:46 +02:00
Claude
ac38ceccbc
fix(install): correct Brave Beta keyring URL + make add_apt_repo robust
Brave consolidated their per-channel keyrings; all channels now share the
keyring at https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg
The repo URL itself stays at apt-beta.s3.brave.com for the Beta channel.

add_apt_repo now downloads the key to a temp file first, validates it's
non-empty, dearmors with a binary-key fallback, then atomically installs
both the keyring and the sources.list entry. A failed fetch no longer
leaves an empty keyring or half-written list file behind.
2026-06-11 15:19:49 +00:00
4ef5dad9ae
Merge pull request #23 from brianpooe/claude/cool-hopper-8vgG8
Claude/cool hopper 8vg g8
2026-06-10 18:59:13 +02:00
Claude
096c3c8afa
feat(install): switch to Homebrew for the CLI toolchain
Ubuntu 24.04's apt versions of fzf/fd/bat/eza/zoxide/ripgrep/tmux/nvim/
lazygit/starship are frozen at April 2024 — and the previous GitHub-
release downloads went stale the moment you stopped re-running the
installer. Homebrew on Linux fixes both: always-latest releases and a
single 'brew upgrade' to update the whole CLI stack.

Two-tier install:
  apt   - zsh + base plumbing + WezTerm (vendor repo) + Brave Beta
          (vendor repo). Vendor repos auto-update via 'apt upgrade'.
  brew  - fzf fd bat eza zoxide ripgrep tmux neovim lazygit starship
          gh zsh-syntax-highlighting zsh-autosuggestions
  nvm   - official installer (pinned NVM_VERSION)
  tpm   - tmux plugin manager clone

New files:
  install/Brewfile - bundle for 'brew bundle'
  install/lib/brew.sh - Homebrew bootstrap + brew bundle
  install/lib/extras.sh - nvm + tpm
  install/install.sh - rewired entry point with --packages-only,
    --dotfiles-only, --help
  install/README.md - new docs for the two-tier strategy

.zshrc:
  - Source brew shellenv first when present, so brew bins win on PATH
  - 'update' alias now: brew upgrade && sudo apt update && sudo apt upgrade
    (previously apt-only; before that pacman-only)

Drops install/lib/packages.sh entries that the now-Brewfile-managed tools
duplicated, and removes the GitHub-release tarball install path.
2026-06-10 16:54:47 +00:00
Claude
d1a289d6ce
feat: pivot installer from Arch+Hyprland to Pop!_OS / Debian apt
User switched from Arch to Pop!_OS 24.04 (Cosmic DE). The previous install/
directory was an Arch+Hyprland desktop scaffold (pacman, yay, Hyprland,
hyprlock, waybar, rofi, swaync, swww, hypridle, swayosd, GTK theming,
wallpapers, etc.) — none of that applies on Pop!_OS where Cosmic provides
the desktop. Wiped the whole tree.

New install/ is a small apt-based tool installer for these dotfiles:

  install.sh           entry: full / --packages-only / --dotfiles-only
  lib/common.sh        helpers (apt_install, apt_update_once, signed repo
                       adder, backup_and_link)
  lib/packages.sh      apt packages + third-party apt repos
  lib/extras.sh        GitHub-release binaries + nvm + tpm
  lib/dotfiles.sh      symlinks + chsh zsh

What it installs:
- apt: zsh + plugins, tmux, fzf, fd-find, bat, eza, zoxide, ripgrep, git,
  curl, build-essential, wl-clipboard
- Signed third-party apt repos: WezTerm (apt.fury.io/wez),
  Brave Beta (brave.com), GitHub CLI (cli.github.com)
- GitHub releases (apt versions too old / absent): Neovim, Lazygit, Starship
- Per-user: nvm, tpm
- Compat shims: /usr/local/bin/fd -> fdfind, /usr/local/bin/bat -> batcat
  so the dotfiles' env vars (FZF_DEFAULT_COMMAND='fd ...') resolve

.zshrc updated for Debian:
- zsh-syntax-highlighting and zsh-autosuggestions now try the
  /usr/share/<name>/<name>.zsh Debian path first, fall back to the Arch
  /usr/share/zsh/plugins/<name>/<name>.zsh path
- fzf bindings/completion fall back: /usr/share/doc/fzf/examples/* first
  (apt), then /usr/share/fzf/* (Arch)
- 'update' alias: pacman -Syu -> sudo apt update && sudo apt upgrade -y

README updated to reflect the Pop!_OS target.
2026-06-10 16:33:47 +00:00
4c69de3ea7
Merge pull request #22 from brianpooe/claude/cool-hopper-8vgG8
Claude/cool hopper 8vg g8
2026-06-09 18:07:06 +02:00
Claude
b6d422c774
feat(install): auto-detect VirtualBox and apply guest fixes
Adds lib/vbox.sh that runs systemd-detect-virt and, on VirtualBox guests:
  - installs virtualbox-guest-utils + enables vboxservice
  - links files/hypr/vbox.conf into ~/.config/hypr/ which sets
    WLR_NO_HARDWARE_CURSORS=1, WLR_RENDERER_ALLOW_SOFTWARE=1,
    LIBGL_ALWAYS_SOFTWARE=1 and overrides the monitor rule to
    preferred mode (3440x1440@120 doesn't exist in VBox)

On bare metal an empty stub is linked instead, so the source= line in
hyprland.conf always resolves.

README adds a 'Testing in VirtualBox first' section listing the host-side
VBox settings (3D Acceleration on, 128MB video mem, VMSVGA, 8GB RAM, 40GB
disk) and the known-broken pieces (bluetooth, gpu-screen-recorder).
2026-06-09 16:03:06 +00:00
Claude
3ca8c72a27
fix(hypr): drop swayosd capslock binding (caps is swapped to esc)
input.conf already sets kb_options = caps:swapescape, so the physical
Caps key sends Escape and Caps Lock state is effectively gone. The
swayosd capslock OSD never fires under this swap; removing the dead
binding to keep keybinds.conf truthful.
2026-06-09 15:56:27 +00:00
Claude
115c606e3b
feat(install): add 12 standard Hyprland community tools
Packages added:
  pacman: swww swaync cliphist satty gpu-screen-recorder xdg-user-dirs
          udiskie gnome-keyring libsecret nwg-look qt6ct kvantum-qt{5,6}
          gnome-themes-extra adwaita-icon-theme adwaita-cursors
  AUR:    swayosd-git bibata-cursor-theme-bin

Configs added:
  hypr/hypridle.conf - 2m dim, 5m lock, 10m screen-off, 30m suspend
  hypr/env.conf - cursor + GTK theme env (Bibata, Adwaita-dark)
  swaync/config.json + style.css - Kanagawa notification center
  gtk-3.0/settings.ini + gtk-4.0/settings.ini - Adwaita-dark + Bibata

Swaps:
  mako -> swaync (notifications + center panel)
  hyprpaper -> swww (animated transitions, same bundled image)

New keybinds:
  Super+Shift+V        cliphist clipboard history via rofi
  Super+N              toggle swaync notification center
  Super+Shift+N        clear all notifications
  Super+Ctrl+R         start screen recording (focused monitor -> ~/Videos)
  Super+Ctrl+Shift+R   stop recording
  Print / Shift+Print  region/full screenshot -> satty -> ~/Pictures/screenshots
  Ctrl+Print           region screenshot -> clipboard only
  Volume/brightness keys now route through swayosd for on-screen feedback
  Caps Lock OSD via swayosd

Autostart additions: swww-daemon + initial swww img, swaync, swayosd-server,
cliphist text+image watchers, hypridle (with real config), udiskie --tray,
gnome-keyring-daemon.

Init:
  apply_desktop_settings() now sets gsettings (gtk-theme, color-scheme,
    cursor-theme, monospace font) and runs xdg-user-dirs-update
  services.sh enables swayosd-libinput-backend + user gnome-keyring-daemon
2026-06-09 15:50:58 +00:00
Claude
d9b2b709fe
feat(waybar): GNOME-style layout (workspaces | clock | stats+power)
- modules-left: workspaces only (drop window title; GNOME doesn't show it)
- modules-center: prominent clock pill with calendar tooltip styled in
  Kanagawa colors
- modules-right: stats grouped as a single chip ending in a power button,
  rounded only at the outer edges so they read as one unit
- per-module colors removed; right side uses neutral fg_dim, with accent
  reserved for the clock pill and warnings (battery low / network offline)
- workspaces: persistent 1-5, dot indicators, hover lifts to brighter bg
- clock: scroll = shift calendar month/year; right-click = mode toggle
- audio: right-click = mute; backlight: scroll = adjust
- power: clock-style accent, hover red, opens power-menu
2026-06-09 15:39:06 +00:00
Claude
0499624bc3
refactor(install): bundle wallpaper in repo, drop install-time download
The previous wallpaper.sh probed wallhaven URLs at install time and
generated hyprpaper.conf dynamically — fragile in low-connectivity
environments and adds a step that has nothing to do with config.

Simpler model:
- install/files/wallpapers/default.jpg — bundled wallpaper (binary in repo)
- install/files/hypr/hyprpaper.conf — static, points to ~/.config/hypr/wallpapers/default.jpg
- install/files/bin/fetch-wallpaper — one-shot helper to populate the bundled
  image from a URL (default: wallhaven.cc/w/2133ly). Run once, git add+commit,
  every subsequent install gets the wallpaper offline.
- lib/hyprland.sh: symlinks both files; warns if the bundled image is missing
- lib/wallpaper.sh: removed

Note: this sandbox cannot reach wallhaven (host_not_allowed), so I cannot
include the actual JPG in this commit. Run fetch-wallpaper on your Arch box
then commit install/files/wallpapers/default.jpg.
2026-06-09 15:36:16 +00:00
Claude
bffb3e11e4
fix(install): split local declaration in wallpaper.sh (SC2155) 2026-06-09 15:33:03 +00:00
Claude
0e803e7366
feat(install): set wallhaven 2133ly as default wallpaper
- lib/wallpaper.sh: downloads the default wallpaper at install time
  (tries .jpg then .png against the wallhaven CDN path) into
  ~/.config/hypr/wallpapers/default.<ext> and writes hyprpaper.conf
  pointing at it
- Override the source with WALLPAPER_URL=<direct-image-url> or just the
  URL stem with WALLPAPER_URL_BASE
- Existing hyprpaper.conf is backed up to .pre-install.<timestamp>
  unless it's already ours (marker comment)
- files/hypr/autostart.conf: exec-once = hyprpaper
- install.sh: wire setup_wallpaper into do_dotfiles_and_config

Tried to fetch from this sandbox to verify the extension but wallhaven
blocks datacenter IPs (403); the installer probes .jpg first then .png
when it actually runs on a residential network.
2026-06-09 15:32:47 +00:00
Claude
6577def1b5
feat(install): add hyprlock, mako, and a rofi power menu
- files/hypr/hyprlock.conf: blurred-screenshot lock with Kanagawa clock,
  date, user label, and rounded password input (green/red on success/fail)
- files/mako/config: Kanagawa Wave notifications, JetBrainsMono Nerd Font,
  per-urgency border colors, critical stays until dismissed
- files/bin/power-menu: rofi-driven Lock/Suspend/Logout/Reboot/Shutdown,
  bound to Super+Shift+E and the Waybar power button
- lib/hyprland.sh: link the three new pieces (hyprlock.conf, mako/config,
  ~/.local/bin/power-menu)
2026-06-09 15:24:32 +00:00
Claude
15e70e539d
feat(install): swap wofi for rofi-wayland with Kanagawa theme
- packages: wofi -> rofi-wayland
- install/files/rofi/config.rasi: modes drun/run/window/ssh, fzf sort,
  fuzzy match, icons enabled, wezterm as terminal
- install/files/rofi/kanagawa.rasi: Kanagawa Wave palette,
  JetBrainsMono Nerd Font, rounded chips, blue accent
- hypr/keybinds.conf: $menu -> rofi -show drun;
  add Super+Tab -> rofi -show window
- waybar power button now opens rofi
- README: docs updated for the swap
2026-06-09 11:12:55 +00:00
Claude
c2445ce7b3
feat(install): add Kanagawa-themed Waybar config
Drops a real waybar config + style instead of letting it fall back to the
package default. Modules: workspaces (hyprland), window title, clock, tray,
network, pulseaudio, backlight, battery, power button. Style uses the
Kanagawa Wave palette and JetBrainsMono Nerd Font to match the rest of the
stack. Symlinked from install/files/waybar/ to ~/.config/waybar/.
2026-06-09 11:10:20 +00:00
Claude
ec6be909c5
feat: replace Omarchy layer with plain Arch + Hyprland installer
Drops the omarchy/ directory and adds install/ - a direct Arch + Hyprland
installer oriented around these dotfiles, no framework on top:

- install/install.sh: entry point with --packages-only / --dotfiles-only
- install/lib/{common,packages,dotfiles,hyprland,services}.sh: modules
- install/files/hypr/: starter Hyprland config (monitors, env, input,
  keybinds, autostart, top-level) - symlinked to ~/.config/hypr/
- Pacman packages: full Hyprland desktop + dotfile dependencies
- AUR: bootstraps yay, installs brave-beta-bin
- Symlinks all dotfiles, installs tpm + nvm, switches login shell to zsh
- Enables sddm, NetworkManager, bluetooth, pipewire user stack

No btrfs / Limine / Secure Boot constraints (unlike Omarchy). 3440x1440@120
monitor + JetBrainsMono Nerd Font preserved. Hyprland border colors use the
Kanagawa Wave palette to match the rest of the stack.

wezterm.lua restored to standalone Kanagawa wave/dragon switching via
$WEZTERM_THEME, since there's no Omarchy theme source anymore.

All shell scripts shellcheck-clean; wezterm.lua passes luac.
2026-06-09 11:06:43 +00:00
9d5583bcc9
Merge pull request #21 from brianpooe/claude/cool-hopper-8vgG8
fix(omarchy): suppress chromium-related errors in theme.sh
2026-06-08 19:03:27 +02:00
Claude
1b9c2249cb
fix(omarchy): suppress chromium-related errors in theme.sh
We strip chromium from the package list, but Omarchy's install/config/theme.sh
unconditionally:
  - mkdir -p /etc/chromium/policies/managed (harmless, pointless without it)
  - tee /usr/lib/chromium/initial_preferences (fails: directory missing)

Both are sed-out during the package-patch step so the install log no longer
shows the scary 'No such file or directory' from tee. The original failure
was already non-fatal (theme.sh doesn't use set -e and the tee was the last
command) but the noise is misleading.
2026-06-08 16:51:52 +00:00
c891fe3b68
Merge pull request #20 from brianpooe/claude/cool-hopper-8vgG8
fix(omarchy): bootstrap Omarchy pacman repo so AUR/omarchy packages r…
2026-06-08 18:19:18 +02:00
Claude
94f8d85fce
fix(omarchy): bootstrap Omarchy pacman repo so AUR/omarchy packages resolve
Mirrors what upstream boot.sh does before sourcing install.sh: writes
/etc/pacman.d/mirrorlist to the Omarchy mirror and exports
OMARCHY_ONLINE_INSTALL=true + OMARCHY_MIRROR. Without this,
install/preflight/pacman.sh is a no-op, the omarchy pacman repo is never
configured, and packages from it (yay, ufw-docker, xdg-terminal-exec,
yaru-icon-theme, omarchy-walker, etc.) fail with 'target not found'.

Also adds preflight checks for root/x86_64 (matching Omarchy's guard.sh)
and documents the real hard requirements: vanilla Arch, btrfs root,
Limine bootloader, Secure Boot disabled, non-root user, no GNOME/KDE.
2026-06-08 16:16:45 +00:00
c74fb76c7b
Merge pull request #19 from brianpooe/claude/cool-hopper-8vgG8
docs(omarchy): document install steps and environment requirements
2026-06-07 19:44:45 +02:00
Claude
de658706c6
docs(omarchy): document install steps and environment requirements 2026-06-07 17:43:31 +00:00
230663865a
Merge pull request #18 from brianpooe/claude/cool-hopper-8vgG8
Claude/cool hopper 8vg g8
2026-06-07 19:42:21 +02:00
Claude
ed8934ebde
feat(omarchy): set JetBrainsMono Nerd Font as default 2026-06-07 17:41:13 +00:00
Claude
5f8dc69b6a
feat(omarchy): auto-configure 3440x1440@120 ultrawide monitor 2026-06-07 17:39:18 +00:00
781e8d6f93
Merge pull request #17 from brianpooe/claude/cool-hopper-8vgG8
Claude/cool hopper 8vg g8
2026-06-07 19:37:09 +02:00
Claude
a5900f4821
feat(omarchy): tag WezTerm window in Hyprland for terminal opacity 2026-06-07 17:35:15 +00:00
Claude
f73e3e7846
feat: add layered Omarchy installer with WezTerm + Brave Origin
Adds omarchy/ - a layered installer that patches Omarchy's package list,
runs its installer, then applies an upgrade-safe customization layer:

- Remove packages: try (tobi-try), lazydocker, cliamp, obsidian, pinta,
  signal-desktop, obs-studio, kdenlive, 1password, spotify, typora,
  libreoffice-fresh, chromium
- Clear all default web app (PWA) wrappers; drop Lazydocker TUI entry
- Install Brave Origin Beta as default browser (replaces Chromium)
- Install WezTerm as default terminal, following the active Omarchy theme
  via colors.toml with a Kanagawa Wave fallback + theme-set reload hook
- Menu overrides: trim Setup (System Sleep/DNS/Security) and Install
  (Web App/TUI/Service/Development/Editor/Terminal/Browser/AI/Gaming/Windows)
- Symlink dotfiles + install deps (zsh, plugins, tpm, nvm)

wezterm.lua now reads the Omarchy theme palette instead of a hardcoded one.
All scripts are shellcheck-clean; Lua validated with luac.
2026-06-07 17:25:44 +00:00
00252bcb78
Merge pull request #16 from brianpooe/claude/cool-hopper-8vgG8
Claude/cool hopper 8vg g8
2026-06-07 19:12:45 +02:00
Claude
3fb10bd97b
docs: add Omarchy install script prompt 2026-06-07 17:11:21 +00:00
Claude
ff4c501414
chore: switch dotfiles from Fedora to Arch
- README: Fedora -> Arch, dnf -> pacman, fd-find -> fd
- .zshrc: update alias to pacman -Syu
- .zshrc: use Arch paths for zsh plugins and fzf key bindings/completion
2026-06-07 17:07:09 +00:00
d9d06db17e
Merge pull request #15 from brianpooe/claude/cool-hopper-8vgG8
Remove offline mode and platform-specific configurations
2026-06-07 18:52:55 +02:00
Claude
84fbb30d82
chore: drop macOS/Windows support and offline nvim tooling
- Remove macOS/Windows clipboard branches, homebrew fzf path from .vimrc
- Remove is_macos/is_windows logic from wezterm.lua
- Drop scripts/nvim-offline-* and NVIM_OFFLINE plumbing from nvim config
- Clean macOS section from .gitignore; simplify .gitattributes to LF-only
- Trim README of offline-bundle section
2026-06-07 16:50:33 +00:00
21c315d5f2 remove cross platform from config 2026-06-06 11:20:21 +02:00
Brian Pooe
62404cb60f fix: markdown 2026-04-29 16:52:23 +02:00
Brian Pooe
62284ccd19 docs: nvim to ideavimrc 2026-04-29 14:59:34 +02:00
Brian Pooe
4572614e95 feat: updated ideavimrc to match nvim config 2026-04-29 14:58:40 +02:00
Brian Pooe
6102d15662 Add shared IdeaVim config and sync integration 2026-04-16 22:14:57 +02:00
Brian Pooe
b46b555e3e fix: keyboard mapping to windows 2026-03-28 14:24:36 +02:00
Brian Pooe
571f33cdab fix: monokai 2026-03-08 18:25:54 +02:00
Brian Pooe
8c7e5b3f6e fix: zed keymaps with nvim 2026-03-08 18:15:34 +02:00
Brian Pooe
4de9fc08ec feat: added zed config translation of nvim ocnfig 2026-03-08 17:32:49 +02:00
Brian Pooe
4841e2430b fix: windows script 2026-03-08 17:06:27 +02:00
Brian Pooe
4bd51bb9a0 fix: embedded shell block in powershell 2026-02-27 18:18:12 +02:00
Brian Pooe
b12ba6473f fix: visual corruption across platforms 2026-02-27 17:55:15 +02:00
Brian Pooe
172754b2b8 fix: windows keybinds 2026-02-26 21:53:50 +02:00
Brian Pooe
d1dfb3c3f8 feat(dotfiles): add Windows/WSL sync workflow and harden cross-platform theming
- add PowerShell sync script for Windows + WSL dotfiles/wezterm
deployment
- make .zshrc portable across macOS and WSL (brew detection, guarded
init, update alias)
- switch tmux to deterministic theme selection via current-theme.conf
- align wave/dragon theme files and remove fragile icon glyphs for
portability
- normalize starship wave/dragon configs for cross-platform rendering
- improve .vimrc Windows compatibility (clipboard + termguicolors guard)
- document Windows sync usage in README
2026-02-26 21:08:53 +02:00
Brian Pooe
479a296a20 fix: adjusted wezterm config for both os windows and mac 2026-02-26 19:35:26 +02:00
Brian Pooe
d29b8b682b feat: global theme setter 2026-02-18 22:10:16 +02:00
Brian Pooe
92c9823353 fix: opacity and font size for wezterm 2026-02-18 21:36:33 +02:00
Brian Pooe
5993459fef feat: unified kanagawa theme and lt for hidden folders too 2026-02-18 21:29:21 +02:00
Brian Pooe
f75f233c98 feat: added render markdown and update startship 2026-02-18 21:08:06 +02:00
Brian Pooe
8b5874e9f4 fix: mason 2026-02-15 21:54:30 +02:00
Brian Pooe
36431f73c7 fix: auto enable lsp servers explicitly managed in this config 2026-02-15 21:44:42 +02:00
Brian Pooe
304d501aba fix: rename desc for toggle neotest 2026-02-15 20:56:41 +02:00
Brian Pooe
6c1be18e7a fix: neotest keymaps for debug and toggle panel 2026-02-15 20:56:16 +02:00
Brian Pooe
82827a669a fix: window switching and neotest 2026-02-15 18:54:59 +02:00
Brian Pooe
ded6452470 feat: a simpler line navigation 2026-02-14 18:13:35 +02:00
Brian Pooe
1428860f6d feat: separate wezterm config from windows and macos specifics 2026-02-14 17:24:01 +02:00
Brian Pooe
486b2395b3 fix: blnk.comp auto start up 2026-02-14 17:23:34 +02:00
Brian Pooe
6f3dcc68a8 fix: stale paths for mason packages 2026-02-14 15:56:10 +02:00
Brian Pooe
f69382ae8e fix: lsp logs and pop errors on proxy machine 2026-02-14 15:47:51 +02:00
Brian Pooe
37b5620628 feat: run bundler in docker 2026-02-14 14:49:26 +02:00
Brian Pooe
d225b1c78e fix: builing via docker 2026-02-14 10:55:58 +02:00
Brian Pooe
19b597e2bf fix: more compatible file for both linux and macos 2026-02-12 21:55:02 +02:00
Brian Pooe
2825922354 fix: remove all macos files from the tar 2026-02-12 21:54:27 +02:00
3711a6bfda
Merge pull request #14 from brianpooe/claude/nvim-offline-setup-S6NO7
Fix mason-nvim-dap / mason-tool-installer conflicts in prepare script
2026-02-12 21:00:22 +02:00
Claude
c4e80ecc66
Fix mason-nvim-dap / mason-tool-installer conflicts in prepare script
Root cause: two separate nvim sessions meant mason-nvim-dap fired twice
(once per session), and in the second session it raced against
MasonToolsInstallSync — both tried to install codelldb simultaneously,
causing "Package is already installing" errors and codelldb failing.

Fix: run everything in a single nvim session. After Lazy sync completes,
wait 5s for vim.schedule callbacks to fire (mason-nvim-dap schedules its
installs this way), then poll the Mason registry until all async installs
finish, then run MasonToolsInstallSync which skips already-installed
packages. No more conflicts.

https://claude.ai/code/session_01J1XAGFnocxQ1cfoaRZceGA
2026-02-12 18:58:40 +00:00
13c85006aa
Merge pull request #13 from brianpooe/claude/nvim-offline-setup-S6NO7
Fix prepare script errors and pin nvim-treesitter to master
2026-02-12 20:45:08 +02:00
Claude
7008b31682
Fix prepare script errors and pin nvim-treesitter to master
Issues found when running the prepare script:

1. nvim-treesitter's main branch has a breaking rewrite that removed
   the configs module, ensure_installed, and auto_install. Pin to the
   master branch which has the stable API the config depends on.

2. Second Lazy sync caused mason-nvim-dap "Package is already
   installing" conflicts. Removed — one sync is sufficient.

3. TSInstallSync command no longer exists in new treesitter. Removed
   the step entirely — parsers are already compiled during Lazy sync
   via the :TSUpdate build step and ensure_installed.

4. Mason async installs (mason-nvim-dap) were aborted when nvim quit.
   Added a polling wait on the Mason registry so nvim stays alive
   until all async package installs complete.

5. Removed unnecessary vim.wait(5000) before MasonToolsInstallSync.

6. Collapsed from 4 steps to 3. Added treesitter parser count to the
   summary output.

https://claude.ai/code/session_01J1XAGFnocxQ1cfoaRZceGA
2026-02-12 18:41:43 +00:00
2b54666fb9
Merge pull request #12 from brianpooe/claude/nvim-offline-setup-S6NO7
Add offline mode for Neovim behind corporate proxy
2026-02-12 20:24:37 +02:00
Claude
789bac2165
Update README with offline setup instructions
https://claude.ai/code/session_01J1XAGFnocxQ1cfoaRZceGA
2026-02-12 18:22:41 +00:00
Claude
41c9b49156
Add offline mode for Neovim behind corporate proxy
When NVIM_OFFLINE=1 is set, all network-dependent operations are disabled:
- lazy.nvim update checker and git timeouts
- Mason ensure_installed for LSP servers and tools
- Treesitter auto_install for parsers
- mason-nvim-dap automatic_installation for debug adapters

Includes two scripts for the offline workflow:
- scripts/nvim-offline-prepare.sh: run on a machine with internet to
  pre-download all plugins, Mason packages, and Treesitter parsers
- scripts/nvim-offline-install.sh: deploy the bundle on the proxy machine

Also increases nvim-tree git timeout to 2s for proxy resilience.

https://claude.ai/code/session_01J1XAGFnocxQ1cfoaRZceGA
2026-02-12 17:47:22 +00:00
28a605b459
Merge pull request #11 from brianpooe/claude/fix-inline-template-highlighting-tn8Vu
Fix <leader>ot to jump to export class when already in .ts file
2026-02-11 19:23:41 +02:00
Claude
2316641b2f
Fix <leader>ot to jump to export class when already in .ts file
The 'ts' section was not included in the inline check, so it fell
through to file switching which re-opened the same file at line 1.
Now jumps to the export class line instead.

https://claude.ai/code/session_016zn34CVg7nXN6v4AvBA2K5
2026-02-11 17:21:29 +00:00
ee3ed5fec5
Merge pull request #10 from brianpooe/claude/fix-inline-template-highlighting-tn8Vu
Support inline Angular components in file switching keymaps
2026-02-11 19:19:16 +02:00
Claude
b4a74db626
Support inline Angular components in file switching keymaps
When in a .component.ts file, <leader>oh and <leader>oc now first look
for inline template:/styles: sections and jump to them. If no inline
section is found, they fall through to opening the external file.
<leader>ot jumps to the export class line when already in the .ts file.

https://claude.ai/code/session_016zn34CVg7nXN6v4AvBA2K5
2026-02-11 17:17:19 +00:00
dd5fcae429
Merge pull request #9 from brianpooe/claude/fix-inline-template-highlighting-tn8Vu
Fix Angular highlights query override using vim.treesitter.query.set()
2026-02-11 19:14:01 +02:00
Claude
f17f4cc4ad
Fix Angular highlights query override using vim.treesitter.query.set()
The after/queries/angular/highlights.scm file was being appended rather
than replacing the bundled query, so the invalid static_member_expression
node type still caused errors. Switch to vim.treesitter.query.set() which
programmatically replaces the query at runtime, bypassing runtimepath
loading order issues with nvim-treesitter.

https://claude.ai/code/session_016zn34CVg7nXN6v4AvBA2K5
2026-02-11 17:12:36 +00:00
bd7ef97f53
Merge pull request #8 from brianpooe/claude/fix-inline-template-highlighting-tn8Vu
Fix Angular treesitter query error for static_member_expression
2026-02-11 19:08:13 +02:00
Claude
2d9c3127d3
Fix Angular treesitter query error for static_member_expression
Override bundled Angular highlights.scm to remove the
static_member_expression node type reference which no longer exists
in the installed tree-sitter-angular parser, causing a query error
when opening inline templates.

https://claude.ai/code/session_016zn34CVg7nXN6v4AvBA2K5
2026-02-11 17:04:52 +00:00
cf56b5a303
Merge pull request #7 from brianpooe/claude/fix-inline-template-highlighting-tn8Vu
Claude/fix inline template highlighting tn8 vu
2026-02-11 18:54:46 +02:00
Claude
a9e443b186
Add Angular development enhancements for nvim
- Add component file switching keymaps (<leader>ot/oh/oc/os) to jump
  between .component.ts, .html, .css/.scss, and .spec.ts files
- Add htmlangular filetype detection for .component.html files with
  Angular treesitter parser activation
- Add prettier formatting for html and htmlangular filetypes
- Disable ts_ls semantic tokens to preserve treesitter injection
  highlighting in Angular inline templates

https://claude.ai/code/session_016zn34CVg7nXN6v4AvBA2K5
2026-02-11 16:52:40 +00:00
Claude
39403ba8a0
Add treesitter injection queries for Angular inline template highlighting
Adds custom treesitter injection queries so that Angular @Component inline
templates get HTML/Angular syntax highlighting and inline styles get CSS
highlighting within TypeScript files.

https://claude.ai/code/session_016zn34CVg7nXN6v4AvBA2K5
2026-02-11 16:25:07 +00:00
344e64a3ae
Merge pull request #6 from brianpooe/claude/update-nvim-save-keymap-8sHji
Claude/update nvim save keymap 8s hji
2026-02-10 21:28:50 +02:00
Claude
2061135bdd
Keep both <C-s> and <leader>sa for save all, remap close other buffers to <leader>qt
https://claude.ai/code/session_01R1YQ6iEwuV6NfSD7ChTD4S
2026-02-10 19:28:08 +00:00
Claude
353d7a14f3
Update nvim save-all keymap from <C-s> to <leader>sa
https://claude.ai/code/session_01R1YQ6iEwuV6NfSD7ChTD4S
2026-02-10 19:26:13 +00:00
f8f2d8ed64
Merge pull request #5 from brianpooe/claude/cleanup-nvim-config-d4hxk
Claude/cleanup nvim config d4hxk
2026-02-10 19:20:42 +02:00
Claude
f55b4e0646
Hide .git folder in nvim-tree file explorer
https://claude.ai/code/session_01CZ49E2kHN3z3B8BaymxJJC
2026-02-10 17:18:30 +00:00
Claude
0bfd8f0f5b
Fix outdated plugin configs: lualine, noice, telescope
- lualine: change default theme from 'nord' to 'auto' to match kanagawa
- noice: remove cmp.entry.get_documentation override (for nvim-cmp, not blink.cmp)
- telescope: move live_grep and git_files into pickers where they belong,
  move path_display into defaults so it actually takes effect
- Remove empty after/lsp directory (svelte.lua was the only file)

https://claude.ai/code/session_01CZ49E2kHN3z3B8BaymxJJC
2026-02-10 17:14:34 +00:00
Claude
070b3710b7
Remove svelte, xcode, csharp config and fix kanagawa theme in lazy.lua
- Delete svelte LSP config (lua/after/lsp/svelte.lua)
- Delete xcodebuild plugin config (lua/brian/plugins/xcodebuild.lua)
- Remove omnisharp and svelte from mason-lspconfig ensure_installed
- Remove csharpier from mason-tool-installer ensure_installed
- Remove csharp formatter from conform.nvim config
- Update lazy.lua install colorscheme from 'nord' to 'kanagawa'

https://claude.ai/code/session_01CZ49E2kHN3z3B8BaymxJJC
2026-02-10 17:08:09 +00:00
Brian Pooe
8f0aa909c2 fix: updated treesitter config 2026-02-10 18:59:40 +02:00
f63fb4dae3
Merge pull request #4 from brianpooe/claude/fix-telescope-duplicate-entries-w4yjK
fix: prevent duplicate LSP servers from attaching
2026-02-08 12:37:14 +02:00
Claude
1f6a256a2a
fix: prevent duplicate LSP servers from attaching
Two fixes:
- Add automatic_enable.exclude for rust_analyzer so mason-lspconfig
  doesn't auto-start it alongside rustaceanvim's instance
- Remove duplicate emmet_ls (emmet_language_server is the newer
  replacement and was already listed)

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 10:31:52 +00:00
3cd4f1c703
Merge pull request #3 from brianpooe/claude/fix-telescope-duplicate-entries-w4yjK
Claude/fix telescope duplicate entries w4yj k
2026-02-08 12:10:58 +02:00
Claude
c86ad0faae
refactor: remove unused tab keymaps
Bufferline is in buffer mode, so tab keymaps (tabnew, tabclose, tabn,
tabp) were dead weight. Buffer equivalents already exist (<leader>b,
<leader>x, <Tab>, <S-Tab>).

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 10:06:59 +00:00
Claude
a69ef87df8
fix: use BufferLineCloseOthers instead of tabonly for leader-tc
The tab bar shows buffers (via bufferline), not Vim tabs.
Changed <leader>tc to use BufferLineCloseOthers so it correctly
closes all other buffers in the bufferline.

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 10:05:06 +00:00
Claude
1ee40970b1
feat: add keymap to close all tabs except current
<leader>tc runs :tabonly to close all other tabs.

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 10:01:35 +00:00
Claude
23fe4e7579
feat: add command aliases for common shift-key typos
:Wqa, :WQ, :Qa, etc. now work the same as their lowercase equivalents,
avoiding frustration from holding shift too long.

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 09:58:34 +00:00
Claude
d86c3dec51
fix: remove rust_analyzer from mason-lspconfig to prevent duplicate LSP
rustaceanvim already manages its own rust-analyzer LSP instance.
Having rust_analyzer in mason-lspconfig's ensure_installed caused a
second instance to auto-attach, resulting in doubled inlay hints
(e.g. "id: id: 6", "ProductStore: ProductStore").

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 09:55:32 +00:00
Claude
5586bcb00c
fix: correct gD and leader-ca LSP keymaps
gD was incorrectly mapped to Telescope lsp_definitions (same as gd),
causing duplicate definition entries. Changed to vim.lsp.buf.declaration
which is the correct action for "go to declaration".

Also fixed leader-ca which was mapped to Telescope lsp_type_definitions
instead of vim.lsp.buf.code_action.

https://claude.ai/code/session_013d8HpzpE7xdxSGD1ErgoMG
2026-02-08 09:51:13 +00:00
Brian Pooe
2a53060358 fix: update save file to save all 2026-02-07 14:33:29 +02:00
Brian Pooe
302c7025c6 refactor: remove wezterm background image 2026-02-07 11:00:57 +02:00
Brian Pooe
aac79a742b feat: use proper undercurl and add low delay on esc 2026-02-07 11:00:05 +02:00
Brian Pooe
8a64a8690b feat: desktop switching for karabiner 2026-02-07 10:47:52 +02:00
Brian Pooe
3a1374aabe fix: map mac commands to ctrl same as windows for wezterm 2026-02-07 10:40:46 +02:00
Brian Pooe
8e103a48a5 fix: remove global roate modifiers from karabiner 2026-02-07 10:40:18 +02:00
Brian Pooe
a4820a83d0 feat: added neotest for testing code 2026-01-31 14:44:34 +02:00
Brian Pooe
979cbf1e48 feat: added debugger for python and javascript 2026-01-31 14:44:21 +02:00
Brian Pooe
5bb32b1592 feat: added debugger 2026-01-31 14:44:02 +02:00
Brian Pooe
c884ac1dd2 feat: alias for cargo run quiet mode 2026-01-31 13:20:00 +02:00
Brian Pooe
e0e1f3a9a0 fix: use telescope for lsp keymaps and update scroll keymaps 2026-01-31 13:19:41 +02:00
Brian Pooe
9937a88053 feat: ignore lazygit config 2026-01-31 13:19:09 +02:00
Brian Pooe
0479ffa8e9 feat: add scroll keymaps for lazygit 2026-01-31 13:15:43 +02:00
54 changed files with 2819 additions and 2051 deletions

7
.claude/settings.json Normal file
View file

@ -0,0 +1,7 @@
{
"effortLevel": "medium",
"tui": "fullscreen",
"skipDangerousModePermissionPrompt": true,
"theme": "dark",
"model": "claude-fable-5[1m]"
}

217
.config/.ideavimrc Normal file
View file

@ -0,0 +1,217 @@
" ============================================================
" .ideavimrc — IdeaVim configuration
" Mirrors the Neovim setup in lua/brian/
" See docs/ideavimrc.md for the full migration reference.
"
" All IDE actions use :action <ID><CR> instead of <Action>(ID).
" Both are documented by IdeaVim but <Action>() in a mapping RHS
" can silently fall through and type the text literally.
" ============================================================
" ============================================================
" sethandler — MUST be at top level before any mappings.
" IdeaVim processes these in a separate startup phase; putting
" them inside an if block causes them to be silently ignored,
" which makes C-h/C-l fire random IDE actions unpredictably.
" ============================================================
sethandler <C-h> a:vim
sethandler <C-l> a:vim
sethandler <C-j> a:vim
sethandler <C-k> a:vim
sethandler <C-s> a:vim
sethandler <C-d> a:vim
sethandler <C-u> a:vim
" ============================================================
" Leader
" ============================================================
let mapleader = " "
let maplocalleader = " "
" ============================================================
" Core options
" IdeaVim does not support indentation options (shiftwidth,
" tabstop, expandtab, smartindent) — configure those under
" Settings → Editor → Code Style in the IDE.
" ============================================================
set number
set relativenumber
set scrolloff=4
set sidescrolloff=8
set incsearch
set hlsearch
set ignorecase
set smartcase
set nowrap
set clipboard+=unnamedplus,ideaput
set timeoutlen=300
" ============================================================
" IdeaVim plugin emulation
"
" which-key : install "IdeaVim-Which-Key" from Marketplace first
" easymotion: install "IdeaVim-EasyMotion" from Marketplace first
" ============================================================
set NERDTree
set surround
set commentary
set highlightedyank
set argtextobj
set matchit
" set which-key " uncomment after installing IdeaVim-Which-Key
" set easymotion " uncomment after installing IdeaVim-EasyMotion
" ============================================================
" NvimTree-style navigation
"
" <C-h> focus the Project tool window (file tree)
" <C-l> focus the editor — no panels opened or closed
" <leader>e toggle the tree panel
" ============================================================
nnoremap <C-h> :action ActivateProjectToolWindow<CR>
nnoremap <C-l> :action FocusEditor<CR>
nnoremap <leader>e :NERDTree<CR>
" ============================================================
" Split navigation (mirrors keymaps.lua C-hjkl wincmd)
" ============================================================
nnoremap <C-k> <C-w>k
nnoremap <C-j> <C-w>j
nnoremap <leader>wh <C-w>h
nnoremap <leader>wl <C-w>l
nnoremap <leader>wj <C-w>j
nnoremap <leader>wk <C-w>k
nnoremap <leader>wp <C-w>p
nnoremap <leader>v :action SplitVertically<CR>
nnoremap <leader>h :action SplitHorizontally<CR>
nnoremap <leader>se :action ChangeSplitOrientation<CR>
nnoremap <leader>xs :action Unsplit<CR>
" ============================================================
" File / buffer / search (Telescope equivalents)
" ============================================================
nnoremap <leader>sf :action GotoFile<CR>
nnoremap <leader><leader> :action Switcher<CR>
nnoremap <leader>sb :action Switcher<CR>
nnoremap <leader>sg :action FindInPath<CR>
nnoremap <leader>so :action RecentFiles<CR>
nnoremap <leader>sds :action FileStructurePopup<CR>
nnoremap <leader>sw :action FindUsages<CR>
nnoremap <leader>sd :action ActivateProblemsViewToolWindow<CR>
nnoremap <leader>sm :action ShowBookmarks<CR>
nnoremap <leader>/ :action Find<CR>
" ============================================================
" LSP equivalents (mirrors lua/brian/lsp.lua)
" ============================================================
nnoremap gd :action GotoDeclaration<CR>
nnoremap gD :action GotoDeclaration<CR>
nnoremap gi :action GotoImplementation<CR>
nnoremap gR :action FindUsages<CR>
nnoremap gt :action GotoTypeDeclaration<CR>
nnoremap K :action QuickJavaDoc<CR>
nnoremap <leader>ca :action ShowIntentionActions<CR>
nnoremap <leader>rn :action RenameElement<CR>
nnoremap <leader>D :action ActivateProblemsViewToolWindow<CR>
nnoremap <leader>df :action ShowErrorDescription<CR>
nnoremap <leader>rs :action RestartIde<CR>
nnoremap [d :action GotoPreviousError<CR>
nnoremap ]d :action GotoNextError<CR>
" ============================================================
" Tab / buffer management
"
" <Tab> is NOT mapped to NextTab — Tab == C-i in terminal,
" which is the jumplist-forward key. Use gt / gT natively.
" ============================================================
nnoremap <leader>x :action CloseContent<CR>
nnoremap <leader>qt :action CloseAllEditorsButActive<CR>
" ============================================================
" Git (mirrors lazygit + telescope git pickers)
" ============================================================
nnoremap <leader>lg :action ActivateVersionControlToolWindow<CR>
nnoremap <leader>gc :action Vcs.ShowTabbedFileHistory<CR>
nnoremap <leader>gcf :action Annotate<CR>
nnoremap <leader>gb :action Git.Branches<CR>
nnoremap <leader>gs :action Vcs.Show.Shelf<CR>
nnoremap <leader>gf :action GotoFile<CR>
" ============================================================
" Angular component file switching
" GotoRelatedFile opens a popup: .ts / .html / .scss / .spec.ts
" Requires the Angular plugin to be installed.
" ============================================================
nnoremap <leader>ot :action GotoRelatedFile<CR>
nnoremap <leader>oh :action GotoRelatedFile<CR>
nnoremap <leader>oc :action GotoRelatedFile<CR>
nnoremap <leader>os :action GotoRelatedFile<CR>
" ============================================================
" Save / quit
" ============================================================
nnoremap <C-s> :action SaveAll<CR>
nnoremap <leader>sa :action SaveAll<CR>
nnoremap <C-q> :action CloseContent<CR>
" ============================================================
" Pure-vim mappings — identical behaviour in nvim and IdeaVim
" ============================================================
" Disable accidental space movement
nnoremap <Space> <Nop>
vnoremap <Space> <Nop>
" Clear search highlights
nnoremap <Esc> :noh<CR>
" Vertical scroll and center
nnoremap <C-d> <C-d>zz
nnoremap <C-u> <C-u>zz
" Find next/prev and center
nnoremap n nzzzv
nnoremap N Nzzzv
" Delete without yanking
nnoremap x "_x
nnoremap dd "_dd
" Keep yank register when pasting over selection
vnoremap p "_dP
" Move lines up/down
nnoremap <A-j> :m .+1<CR>==
nnoremap <A-k> :m .-2<CR>==
vnoremap <A-j> :m '>+1<CR>gv=gv
vnoremap <A-k> :m '<-2<CR>gv=gv
" Replace word under cursor (forward)
nnoremap <leader>j *``cgn
" Yank to system clipboard explicitly
nnoremap <leader>y "+y
vnoremap <leader>y "+y
nnoremap <leader>Y "+Y
" Line start/end shortcuts
nnoremap <leader>gh 0
vnoremap <leader>gh 0
nnoremap <leader>gl $
vnoremap <leader>gl $
" Toggle line wrap
nnoremap <leader>lw :set wrap!<CR>
" Increment / decrement
nnoremap <leader>+ <C-a>
nnoremap <leader>- <C-x>
" Sort selected lines (unique)
vnoremap <leader>st :sort u<CR>
" Toggle case of selection
vnoremap <leader>~ g~

View file

@ -1,196 +0,0 @@
" ========================================
" Options
" ========================================
set encoding=UTF-8
set spelllang=en_us,de_de,es_es
set nohlsearch " Disable highlight on search
set number " Enable line numbers
set mouse=a " Enable mouse mode
set breakindent " Enable break indent
set undofile " Save undo history
set ignorecase " Case-insensitive searching unless \C or capital in search
set smartcase " Enable smart case
set signcolumn=yes " Keep signcolumn on by default
set updatetime=250 " Decrease update time
set timeoutlen=300 " Time to wait for a mapped sequence to complete (in milliseconds)
set nobackup " Don't create a backup file
set nowritebackup " Don't write backup before overwriting
set completeopt=menuone,noselect " Better completion experience
set whichwrap+=<,>,[,],h,l " Allow certain keys to move to the next line
set nowrap " Display long lines as one line
set linebreak " Don't break words when wrapping
set scrolloff=8 " Keep 8 lines above/below cursor
set sidescrolloff=8 " Keep 8 columns to the left/right of cursor
set relativenumber " Use relative line numbers
set numberwidth=4 " Number column width
set shiftwidth=4 " Spaces per indentation
set tabstop=4 " Spaces per tab
set softtabstop=4 " Spaces per tab during editing ops
set expandtab " Convert tabs to spaces
set nocursorline " Don't highlight the current line
set splitbelow " Horizontal splits below current window
set splitright " Vertical splits to the right
set noswapfile " Don't use a swap file
set smartindent " Smart indentation
set showtabline=2 " Always show tab line
set backspace=indent,eol,start " Configurable backspace behavior
set pumheight=10 " Popup menu height
set conceallevel=0 " Make `` visible in markdown
set fileencoding=utf-8 " File encoding
set cmdheight=1 " Command line height
set autoindent " Auto-indent new lines
set shortmess+=c " Don't show completion menu messages
set iskeyword+=- " Treat hyphenated words as whole words
set showmatch " show the matching part of pairs [] {} and ()
set laststatus=2 " Show status bar
set statusline=%f " Path to the file
set statusline+=%= " Switch to the right side
set statusline+=%l " Current line
set statusline+=/ " Separator
set statusline+=%L " Total lines
" ========================================
" Keymaps
" ========================================
" Set leader key
let mapleader = " "
let maplocalleader = " "
" Disable the spacebar key's default behavior in Normal and Visual modes
nnoremap <Space> <Nop>
vnoremap <Space> <Nop>
" Allow moving the cursor through wrapped lines with j, k
nnoremap <expr> k v:count == 0 ? 'gk' : 'k'
nnoremap <expr> j v:count == 0 ? 'gj' : 'j'
" clear highlights
nnoremap <Esc> :noh<CR>
" save file
nnoremap <C-s> :w<CR>
" save file without auto-formatting
nnoremap <leader>sn :noautocmd w<CR>
" quit file
nnoremap <C-q> :q<CR>
" delete single character without copying into register
nnoremap x "_x
" Vertical scroll and center
nnoremap <C-d> <C-d>zz
nnoremap <C-u> <C-u>zz
" Find and center
nnoremap n nzzzv
nnoremap N Nzzzv
" Resize with arrows
nnoremap <Up> :resize -2<CR>
nnoremap <Down> :resize +2<CR>
nnoremap <Left> :vertical resize -2<CR>
nnoremap <Right> :vertical resize +2<CR>
" Navigate buffers
nnoremap <Tab> :bnext<CR>
nnoremap <S-Tab> :bprevious<CR>
nnoremap <leader>sb :buffers<CR>:buffer<Space>
" increment/decrement numbers
nnoremap <leader>+ <C-a>
nnoremap <leader>- <C-x>
" window management
nnoremap <leader>v <C-w>v
nnoremap <leader>h <C-w>s
nnoremap <leader>se <C-w>=
nnoremap <leader>xs :close<CR>
" Navigate between splits
nnoremap <C-k> :wincmd k<CR>
nnoremap <C-j> :wincmd j<CR>
nnoremap <C-h> :wincmd h<CR>
nnoremap <C-l> :wincmd l<CR>
" tabs
nnoremap <leader>to :tabnew<CR>
nnoremap <leader>tx :tabclose<CR>
nnoremap <leader>tn :tabn<CR>
nnoremap <leader>tp :tabp<CR>
nnoremap <leader>x :bdelete<CR>
nnoremap <leader>b :enew<CR>
" toggle line wrapping
nnoremap <leader>lw :set wrap!<CR>
" Press jk fast to exit insert mode
inoremap jk <ESC>
inoremap kj <ESC>
" Stay in indent mode
" vnoremap < <gv
" vnoremap > >gv
" Keep last yanked when pasting
vnoremap p "_dP
" Explicitly yank to system clipboard (highlighted and entire row)
noremap <leader>y "+y
noremap <leader>Y "+Y
" Open file explorer
noremap <silent> <leader>e :Lex<CR>
" Make W w on save
noremap :W :w
" ========================================
" Other
" ========================================
" Syntax highlighting
syntax on
" Colorscheme
" colorscheme industry
colorscheme wildcharm
set background=dark
" hi Normal ctermbg=NONE guibg=NONE
" hi NonText ctermbg=NONE guibg=NONE guifg=NONE ctermfg=NONE
" hi VertSplit guibg=NONE guifg=NONE ctermbg=NONE ctermfg=NONE
" Sync clipboard with OS
if system('uname -s') == "Darwin\n"
set clipboard=unnamed "OSX
else
set clipboard=unnamedplus "Linux
endif
" True colors
if !has('gui_running') && &term =~ '\%(screen\|tmux\)'
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
endif
set termguicolors
" Use a line cursor within insert mode and a block cursor everywhere else.
let &t_SI = "\e[6 q"
let &t_EI = "\e[2 q"
" Netrw
let g:netrw_banner = 0
let g:netrw_liststyle = 3
let g:netrw_browse_split = 4
let g:netrw_altv = 1
let g:netrw_winsize = 25
" Use 'l' instead of <CR> to open files
augroup netrw_setup | au!
au FileType netrw nmap <buffer> l <CR>
augroup END

5
.config/bat/config Normal file
View file

@ -0,0 +1,5 @@
# Follow the terminal's ANSI palette so bat matches the active Kanagawa
# variant instead of shipping its own colorscheme.
--theme="ansi"
--style="numbers,changes,header"
--italic-text=always

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
keybinding:
universal:
scrollUpMain: '<c-k>'
scrollDownMain: '<c-j>'
scrollUpMain-alt1: '<pgup>'
scrollDownMain-alt1: '<pgdown>'

View file

@ -1,4 +1,4 @@
column_width = 80
column_width = 80
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2

View file

@ -0,0 +1,30 @@
; extends
; Angular inline template - inject Angular template highlighting into @Component template property
((decorator
(call_expression
function: (identifier) @_name
arguments: (arguments
(object
(pair
key: (property_identifier) @_key
value: (template_string) @injection.content)))))
(#eq? @_name "Component")
(#eq? @_key "template")
(#set! injection.language "angular")
(#set! injection.include-children))
; Angular inline styles - inject CSS highlighting into @Component styles property
((decorator
(call_expression
function: (identifier) @_name
arguments: (arguments
(object
(pair
key: (property_identifier) @_key
value: (array
(template_string) @injection.content))))))
(#eq? @_name "Component")
(#eq? @_key "styles")
(#set! injection.language "css")
(#set! injection.include-children))

View file

@ -1,11 +0,0 @@
return {
on_attach = function(client)
vim.api.nvim_create_autocmd('BufWritePost', {
pattern = { '*.js', '*.ts' },
callback = function(ctx)
-- Here use ctx.match instead of ctx.file
client.notify('$/onDidChangeTsOrJsFile', { uri = ctx.match })
end,
})
end,
}

View file

@ -1,3 +1,195 @@
-- Command aliases for common shift-key typos
local typos = {
['W'] = 'w',
['Wq'] = 'wq',
['WQ'] = 'wq',
['Wqa'] = 'wqa',
['WQa'] = 'wqa',
['WQA'] = 'wqa',
['Wa'] = 'wa',
['WA'] = 'wa',
['Q'] = 'q',
['Qa'] = 'qa',
['QA'] = 'qa',
}
for typo, cmd in pairs(typos) do
vim.api.nvim_create_user_command(typo, cmd, { bang = true })
end
-- Activate Angular treesitter parser for component HTML templates
vim.api.nvim_create_autocmd({ 'BufReadPost', 'BufNewFile' }, {
desc = 'Set htmlangular filetype for Angular component templates',
pattern = { '*.component.html', '*.container.html' },
callback = function()
vim.bo.filetype = 'htmlangular'
vim.treesitter.start(nil, 'angular')
end,
})
-- Override Angular highlights query to fix static_member_expression error.
-- The bundled query references a node type that no longer exists in the
-- installed tree-sitter-angular parser. vim.treesitter.query.set() is used
-- instead of after/queries/ because nvim-treesitter appends rather than
-- replaces query files.
vim.treesitter.query.set(
'angular',
'highlights',
[[
; inherits: html_tags
(identifier) @variable
(pipe_operator) @operator
(string) @string
(number) @number
(pipe_call
name: (identifier) @function)
(pipe_call
arguments: (pipe_arguments
(identifier) @variable.parameter))
(structural_directive
"*" @keyword
(identifier) @keyword)
(attribute
(attribute_name) @variable.member
(#lua-match? @variable.member "#.*"))
(binding_name
(identifier) @keyword)
(event_binding
(binding_name
(identifier) @keyword))
(event_binding
"\"" @punctuation.delimiter)
(property_binding
"\"" @punctuation.delimiter)
(structural_assignment
operator: (identifier) @keyword)
(member_expression
property: (identifier) @property)
(call_expression
function: (identifier) @function)
(call_expression
function: ((identifier) @function.builtin
(#eq? @function.builtin "$any")))
(pair
key: ((identifier) @variable.builtin
(#eq? @variable.builtin "$implicit")))
[
(control_keyword)
(special_keyword)
] @keyword
((control_keyword) @keyword.repeat
(#any-of? @keyword.repeat "for" "empty"))
((control_keyword) @keyword.conditional
(#any-of? @keyword.conditional "if" "else" "switch" "case" "default"))
((control_keyword) @keyword.coroutine
(#any-of? @keyword.coroutine "defer" "placeholder" "loading"))
((control_keyword) @keyword.exception
(#eq? @keyword.exception "error"))
((identifier) @boolean
(#any-of? @boolean "true" "false"))
((identifier) @variable.builtin
(#any-of? @variable.builtin "this" "$event"))
((identifier) @constant.builtin
(#eq? @constant.builtin "null"))
[
(ternary_operator)
(conditional_operator)
] @keyword.conditional.ternary
[
"("
")"
"["
"]"
"{"
"}"
"@"
] @punctuation.bracket
(two_way_binding
[
"[("
")]"
] @punctuation.bracket)
[
"{{"
"}}"
] @punctuation.special
(template_substitution
[
"${"
"}"
] @punctuation.special)
(template_chars) @string
[
";"
"."
","
"?."
] @punctuation.delimiter
(nullish_coalescing_expression
(coalescing_operator) @operator)
(concatenation_expression
"+" @operator)
(icu_clause) @keyword.operator
(icu_category) @keyword.conditional
(binary_expression
[
"-"
"&&"
"+"
"<"
"<="
"="
"=="
"==="
"!="
"!=="
">"
">="
"*"
"/"
"||"
"%"
] @operator)
]]
)
-- Highlight when yanking (copying) text
-- Try it with `yap` in normal mode
-- See `:help vim.hl.on_yank()`

View file

@ -26,7 +26,8 @@ vim.keymap.set(
vim.keymap.set('n', '<Esc>', ':noh<CR>', opts)
-- save file
vim.keymap.set('n', '<C-s>', '<cmd> w <CR>', opts)
vim.keymap.set('n', '<C-s>', '<cmd> wa <CR>', opts)
vim.keymap.set('n', '<leader>sa', '<cmd> wa <CR>', opts)
-- save file without auto-formatting
vim.keymap.set('n', '<leader>sn', '<cmd>noautocmd w <CR>', opts)
@ -49,8 +50,8 @@ vim.keymap.set('n', 'n', 'nzzzv')
vim.keymap.set('n', 'N', 'Nzzzv')
-- Resize with arrows
vim.keymap.set('n', '<Up>', ':resize -2<CR>', opts)
vim.keymap.set('n', '<Down>', ':resize +2<CR>', opts)
vim.keymap.set('n', '<Up>', ':resize +2<CR>', opts)
vim.keymap.set('n', '<Down>', ':resize -2<CR>', opts)
vim.keymap.set('n', '<Left>', ':vertical resize -2<CR>', opts)
vim.keymap.set('n', '<Right>', ':vertical resize +2<CR>', opts)
@ -76,16 +77,20 @@ vim.keymap.set('n', '<C-k>', ':wincmd k<CR>', opts)
vim.keymap.set('n', '<C-j>', ':wincmd j<CR>', opts)
vim.keymap.set('n', '<C-h>', ':wincmd h<CR>', opts)
vim.keymap.set('n', '<C-l>', ':wincmd l<CR>', opts)
vim.keymap.set('n', '<leader>wj', '<C-w>j', opts)
vim.keymap.set('n', '<leader>wk', '<C-w>k', opts)
vim.keymap.set('n', '<leader>wp', '<C-w>p', opts)
-- Tabs
vim.keymap.set('n', '<leader>to', ':tabnew<CR>', opts) -- open new tab
vim.keymap.set('n', '<leader>tx', ':tabclose<CR>', opts) -- close current tab
vim.keymap.set('n', '<leader>tn', ':tabn<CR>', opts) -- go to next tab
vim.keymap.set('n', '<leader>tp', ':tabp<CR>', opts) -- go to previous tab
-- Buffers
vim.keymap.set('n', '<leader>qt', ':BufferLineCloseOthers<CR>', opts) -- close all buffers except current
-- Toggle line wrapping
vim.keymap.set('n', '<leader>lw', '<cmd>set wrap!<CR>', opts)
-- Line navigation (same motions as `0` and `$`)
vim.keymap.set({ 'n', 'v', 'o' }, '<leader>gh', '0', opts)
vim.keymap.set({ 'n', 'v', 'o' }, '<leader>gl', '$', opts)
-- Move text up and down
vim.keymap.set('n', '<A-j>', ':m .+1<CR>==', opts)
vim.keymap.set('n', '<A-k>', ':m .-2<CR>==', opts)
@ -105,7 +110,7 @@ vim.keymap.set('n', '<leader>Y', [["+Y]])
-- Toggle diagnostics
local diagnostics_active = true
vim.keymap.set('n', '<leader>do', function()
vim.keymap.set('n', '<leader>ud', function()
diagnostics_active = not diagnostics_active
if diagnostics_active then
@ -126,7 +131,7 @@ end, { desc = 'Go to next diagnostic message' })
vim.keymap.set(
'n',
'<leader>d',
'<leader>df',
vim.diagnostic.open_float,
{ desc = 'Open floating diagnostic message' }
)
@ -154,3 +159,80 @@ vim.keymap.set(
vim.keymap.set('v', '<leader>st', ':sort u<CR>', { noremap = true })
-- Toggle case
vim.keymap.set('v', '<leader>~', 'g~', { noremap = true })
-- Angular component file/section switching
-- For multi-file components: jump to the corresponding file
-- For inline components: jump to the template/styles/class section
local function angular_switch(section)
local file = vim.fn.expand '%:p'
local base = file:match '(.+)%.component%..+$'
if not base then
vim.notify('Not an Angular component file', vim.log.levels.WARN)
return
end
local is_ts = file:match '%.component%.ts$'
-- If we're in a .ts file, check for inline sections before switching files
if
is_ts and (section == 'template' or section == 'styles' or section == 'ts')
then
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
local pattern
if section == 'template' then
pattern = '^%s*template%s*:'
elseif section == 'styles' then
pattern = '^%s*styles%s*:'
elseif section == 'ts' then
pattern = '^export%s+class%s+'
end
for i, line in ipairs(lines) do
if line:match(pattern) then
vim.api.nvim_win_set_cursor(0, { i, 0 })
vim.cmd 'normal! zz'
return
end
end
-- No inline section found, fall through to file switching
if section == 'template' then
vim.cmd('edit ' .. base .. '.component.html')
elseif section == 'styles' then
local scss = base .. '.component.scss'
local target = vim.fn.filereadable(scss) == 1 and scss
or base .. '.component.css'
vim.cmd('edit ' .. target)
end
return
end
-- File switching for non-.ts files or spec
local target
if section == 'ts' then
target = base .. '.component.ts'
elseif section == 'template' then
target = base .. '.component.html'
elseif section == 'styles' then
local scss = base .. '.component.scss'
target = vim.fn.filereadable(scss) == 1 and scss or base .. '.component.css'
elseif section == 'spec' then
target = base .. '.component.spec.ts'
end
if target then
vim.cmd('edit ' .. target)
end
end
vim.keymap.set('n', '<leader>ot', function()
angular_switch 'ts'
end, { desc = 'Angular: go to component class' })
vim.keymap.set('n', '<leader>oh', function()
angular_switch 'template'
end, { desc = 'Angular: go to template' })
vim.keymap.set('n', '<leader>oc', function()
angular_switch 'styles'
end, { desc = 'Angular: go to styles' })
vim.keymap.set('n', '<leader>os', function()
angular_switch 'spec'
end, { desc = 'Angular: go to spec' })

View file

@ -41,3 +41,21 @@ vim.opt.shortmess:append 'c' -- don't give |ins-completion-menu| messages
vim.opt.iskeyword:append '-' -- hyphenated words recognized by searches
vim.opt.formatoptions:remove { 'c', 'r', 'o' } -- don't insert the current comment leader automatically for auto-wrapping comments using 'textwidth', hitting <Enter> in insert mode, or hitting 'o' or 'O' in normal mode.
vim.opt.runtimepath:remove '/usr/share/vim/vimfiles' -- separate vim plugins from neovim in case vim still in use
-- Temporary compatibility workaround for Neovim 0.12 directive captures.
-- Keep this scoped to 0.12 so later releases use the upstream implementation.
if vim.version().minor == 12 then
local get_node_text = vim.treesitter.get_node_text
vim.treesitter.get_node_text = function(node, source, opts)
if not node then
return ''
end
if type(node) == 'table' then
node = node[1]
if not node then
return ''
end
end
return get_node_text(node, source, opts)
end
end

View file

@ -26,7 +26,7 @@ require('lazy').setup {
spec = {
{ import = 'brian.plugins' },
},
install = { colorscheme = { 'nord' } },
install = { colorscheme = { 'kanagawa' } },
checker = { enabled = true, notify = false },
change_detection = {
notify = false,

View file

@ -1,4 +1,41 @@
local keymap = vim.keymap -- for conciseness
-- Some servers (e.g. vscode-langservers-extracted/css-lsp) send this request.
-- On newer Neovim versions this handler exists by default; keep it intact.
-- On older setups, provide a no-op fallback that still replies to the server.
if not vim.lsp.handlers['workspace/diagnostic/refresh'] then
vim.lsp.handlers['workspace/diagnostic/refresh'] = function()
return vim.NIL
end
end
local function hover_if_supported()
local bufnr = vim.api.nvim_get_current_buf()
for _, client in ipairs(vim.lsp.get_clients { bufnr = bufnr }) do
if
client.server_capabilities and client.server_capabilities.hoverProvider
then
vim.lsp.buf.hover { border = 'rounded' }
return
end
end
end
-- Avoid default `K` -> `man` behavior in buffers without LSP hover support.
keymap.set('n', 'K', hover_if_supported, { silent = true, desc = 'LSP hover' })
-- Disable semantic tokens for ts_ls so it does not override
-- treesitter injection highlighting in Angular inline templates
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('DisableTsLsSemanticTokens', {}),
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client and client.name == 'ts_ls' then
client.server_capabilities.semanticTokensProvider = nil
end
end,
})
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
callback = function(ev)
@ -14,7 +51,7 @@ vim.api.nvim_create_autocmd('LspAttach', {
keymap.set('n', 'gD', vim.lsp.buf.declaration, opts) -- go to declaration
opts.desc = 'Show LSP definition'
keymap.set('n', 'gd', vim.lsp.buf.definition, opts) -- show lsp definition
keymap.set('n', 'gd', '<cmd>Telescope lsp_definitions<CR>', opts) -- show lsp definition
opts.desc = 'Show LSP implementations'
keymap.set('n', 'gi', '<cmd>Telescope lsp_implementations<CR>', opts) -- show lsp implementations
@ -32,7 +69,7 @@ vim.api.nvim_create_autocmd('LspAttach', {
keymap.set('n', '<leader>D', '<cmd>Telescope diagnostics bufnr=0<CR>', opts) -- show diagnostics for file
opts.desc = 'Show line diagnostics'
keymap.set('n', '<leader>d', vim.diagnostic.open_float, opts) -- show diagnostics for line
keymap.set('n', '<leader>df', vim.diagnostic.open_float, opts) -- show diagnostics for line
opts.desc = 'Go to previous diagnostic'
keymap.set('n', '[d', function()
@ -44,9 +81,19 @@ vim.api.nvim_create_autocmd('LspAttach', {
vim.diagnostic.jump { count = 1, float = true }
end, opts) -- jump to next diagnostic in buffer
opts.desc = 'Show documentation for what is under cursor'
keymap.set('n', 'K', vim.lsp.buf.hover, opts) -- show documentation for what is under cursor
opts.desc = 'Scroll hover docs down'
keymap.set('n', '<C-j>', function()
if not require('noice.lsp').scroll(4) then
return '<C-j>'
end
end, { buffer = ev.buf, silent = true, expr = true })
opts.desc = 'Scroll hover docs up'
keymap.set('n', '<C-k>', function()
if not require('noice.lsp').scroll(-4) then
return '<C-k>'
end
end, { buffer = ev.buf, silent = true, expr = true })
opts.desc = 'Restart LSP'
keymap.set('n', '<leader>rs', ':LspRestart<CR>', opts) -- mapping to restart lsp if necessary
end,
@ -57,6 +104,11 @@ vim.lsp.inlay_hint.enable(true)
local severity = vim.diagnostic.severity
vim.diagnostic.config {
virtual_text = false, -- Disable inline diagnostics
float = {
border = 'rounded',
source = true, -- Show diagnostic source
},
signs = {
text = {
[severity.ERROR] = '',

View file

@ -63,7 +63,8 @@ return {
-- when the Rust fuzzy matcher is not available, by using `implementation = "prefer_rust"`
--
-- See the fuzzy documentation for more information
fuzzy = { implementation = 'prefer_rust_with_warning' },
-- Force Lua fuzzy matcher to avoid Rust/prebuilt-binary checks on locked-down machines.
fuzzy = { implementation = 'lua' },
},
opts_extend = { 'sources.default' },
}

View file

@ -0,0 +1,327 @@
return {
'mfussenegger/nvim-dap',
dependencies = {
-- UI
{
'rcarriga/nvim-dap-ui',
dependencies = { 'nvim-neotest/nvim-nio' },
keys = {
{
'<leader>du',
function()
require('dapui').toggle {}
end,
desc = 'Toggle DAP UI',
},
{
'<leader>de',
function()
require('dapui').eval()
end,
mode = { 'n', 'v' },
desc = 'Eval expression',
},
},
opts = {},
config = function(_, opts)
local dap = require 'dap'
local dapui = require 'dapui'
dapui.setup(opts)
dap.listeners.after.event_initialized['dapui_config'] = function()
dapui.open {}
end
dap.listeners.before.event_terminated['dapui_config'] = function()
dapui.close {}
end
dap.listeners.before.event_exited['dapui_config'] = function()
dapui.close {}
end
end,
},
-- Virtual text for variable values
{
'theHamsta/nvim-dap-virtual-text',
opts = {},
},
-- Mason integration for installing debug adapters
{
'jay-babu/mason-nvim-dap.nvim',
dependencies = 'mason-org/mason.nvim',
cmd = { 'DapInstall', 'DapUninstall' },
opts = {
automatic_installation = false,
handlers = {},
},
},
},
keys = {
{
'<leader>dB',
function()
require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ')
end,
desc = 'Conditional breakpoint',
},
{
'<leader>db',
function()
require('dap').toggle_breakpoint()
end,
desc = 'Toggle breakpoint',
},
{
'<leader>dc',
function()
require('dap').continue()
end,
desc = 'Continue',
},
{
'<leader>dC',
function()
require('dap').run_to_cursor()
end,
desc = 'Run to cursor',
},
{
'<leader>dg',
function()
require('dap').goto_()
end,
desc = 'Go to line (no execute)',
},
{
'<leader>di',
function()
require('dap').step_into()
end,
desc = 'Step into',
},
{
'<leader>dj',
function()
require('dap').down()
end,
desc = 'Down in stack',
},
{
'<leader>dk',
function()
require('dap').up()
end,
desc = 'Up in stack',
},
{
'<leader>dl',
function()
require('dap').run_last()
end,
desc = 'Run last',
},
{
'<leader>do',
function()
require('dap').step_out()
end,
desc = 'Step out',
},
{
'<leader>dO',
function()
require('dap').step_over()
end,
desc = 'Step over',
},
{
'<leader>dp',
function()
require('dap').pause()
end,
desc = 'Pause',
},
{
'<leader>dr',
function()
require('dap').repl.toggle()
end,
desc = 'Toggle REPL',
},
{
'<leader>ds',
function()
require('dap').session()
end,
desc = 'Session',
},
{
'<leader>dt',
function()
require('dap').terminate()
end,
desc = 'Terminate',
},
{
'<leader>dw',
function()
require('dap.ui.widgets').hover()
end,
desc = 'Widgets',
},
},
config = function()
local dap = require 'dap'
-- Signs
vim.fn.sign_define(
'DapBreakpoint',
{ text = 'B', texthl = 'DiagnosticError', linehl = '', numhl = '' }
)
vim.fn.sign_define(
'DapBreakpointCondition',
{ text = 'C', texthl = 'DiagnosticWarn', linehl = '', numhl = '' }
)
vim.fn.sign_define(
'DapLogPoint',
{ text = 'L', texthl = 'DiagnosticInfo', linehl = '', numhl = '' }
)
vim.fn.sign_define('DapStopped', {
text = '>',
texthl = 'DiagnosticOk',
linehl = 'DapStoppedLine',
numhl = '',
})
vim.fn.sign_define(
'DapBreakpointRejected',
{ text = 'R', texthl = 'DiagnosticError', linehl = '', numhl = '' }
)
-- Highlight for stopped line
vim.api.nvim_set_hl(
0,
'DapStoppedLine',
{ default = true, link = 'Visual' }
)
-- Python configuration
dap.adapters.python = function(cb, config)
if config.request == 'attach' then
local port = (config.connect or config).port
local host = (config.connect or config).host or '127.0.0.1'
cb {
type = 'server',
port = assert(
port,
'`connect.port` is required for a python `attach` configuration'
),
host = host,
options = {
source_filetype = 'python',
},
}
else
cb {
type = 'executable',
command = vim.fn.exepath 'python3',
args = { '-m', 'debugpy.adapter' },
options = {
source_filetype = 'python',
},
}
end
end
dap.configurations.python = {
{
type = 'python',
request = 'launch',
name = 'Launch file',
program = '${file}',
pythonPath = function()
local cwd = vim.fn.getcwd()
if vim.fn.executable(cwd .. '/venv/bin/python') == 1 then
return cwd .. '/venv/bin/python'
elseif vim.fn.executable(cwd .. '/.venv/bin/python') == 1 then
return cwd .. '/.venv/bin/python'
else
return vim.fn.exepath 'python3'
end
end,
},
{
type = 'python',
request = 'launch',
name = 'Launch file with arguments',
program = '${file}',
args = function()
local args_string = vim.fn.input 'Arguments: '
return vim.split(args_string, ' +')
end,
pythonPath = function()
local cwd = vim.fn.getcwd()
if vim.fn.executable(cwd .. '/venv/bin/python') == 1 then
return cwd .. '/venv/bin/python'
elseif vim.fn.executable(cwd .. '/.venv/bin/python') == 1 then
return cwd .. '/.venv/bin/python'
else
return vim.fn.exepath 'python3'
end
end,
},
}
-- JavaScript/TypeScript configuration
local js_debug_path = vim.fn.stdpath 'data'
.. '/mason/packages/js-debug-adapter'
dap.adapters['pwa-node'] = {
type = 'server',
host = 'localhost',
port = '${port}',
executable = {
command = 'node',
args = { js_debug_path .. '/js-debug/src/dapDebugServer.js', '${port}' },
},
}
dap.adapters['pwa-chrome'] = {
type = 'server',
host = 'localhost',
port = '${port}',
executable = {
command = 'node',
args = { js_debug_path .. '/js-debug/src/dapDebugServer.js', '${port}' },
},
}
local js_config = {
{
type = 'pwa-node',
request = 'launch',
name = 'Launch file',
program = '${file}',
cwd = '${workspaceFolder}',
},
{
type = 'pwa-node',
request = 'attach',
name = 'Attach to process',
processId = require('dap.utils').pick_process,
cwd = '${workspaceFolder}',
},
{
type = 'pwa-chrome',
request = 'launch',
name = 'Launch Chrome',
url = 'http://localhost:4200', -- Angular default port
webRoot = '${workspaceFolder}',
},
}
dap.configurations.javascript = js_config
dap.configurations.typescript = js_config
dap.configurations.javascriptreact = js_config
dap.configurations.typescriptreact = js_config
-- Rust/C/C++ uses codelldb (configured via rustaceanvim)
end,
}

View file

@ -25,15 +25,14 @@ return {
yaml = { 'yamlfmt', 'prettierd', 'prettier', stop_after_first = true },
markdown = { 'cbfmt', 'prettierd', 'prettier', stop_after_first = true },
graphql = { 'prettierd', 'prettier', stop_after_first = true },
html = { 'prettierd', 'prettier', stop_after_first = true },
htmlangular = { 'prettierd', 'prettier', stop_after_first = true },
lua = { 'stylua' },
go = { 'goimports', 'ast_grep' },
rust = { 'ast_grep' },
python = { 'ruff', 'black' },
csharp = { 'csharpier' },
dockerfile = { 'hadolint' },
rust = { 'rustfmt', lsp_format = 'fallback' },
python = { 'ruff_format' },
},
format_on_save = {
lsp_fallback = true,
lsp_format = 'fallback',
async = false,
timeout_ms = 1000,
},
@ -44,7 +43,7 @@ return {
vim.keymap.set({ 'n', 'v' }, '<leader>mp', function()
conform.format {
lsp_fallback = true,
lsp_format = 'fallback',
async = false,
timeout_ms = 1000,
}

View file

@ -1,51 +1,8 @@
-- Set lualine as statusline
return {
'nvim-lualine/lualine.nvim',
config = function()
-- Adapted from: https://github.com/nvim-lualine/lualine.nvim/blob/master/lua/lualine/themes/onedark.lua
local colors = {
blue = '#61afef',
green = '#98c379',
purple = '#c678dd',
cyan = '#56b6c2',
red1 = '#e06c75',
red2 = '#be5046',
yellow = '#e5c07b',
fg = '#abb2bf',
bg = '#282c34',
gray1 = '#828997',
gray2 = '#2c323c',
gray3 = '#3e4452',
}
local onedark_theme = {
normal = {
a = { fg = colors.bg, bg = colors.green, gui = 'bold' },
b = { fg = colors.fg, bg = colors.gray3 },
c = { fg = colors.fg, bg = colors.gray2 },
},
command = { a = { fg = colors.bg, bg = colors.yellow, gui = 'bold' } },
insert = { a = { fg = colors.bg, bg = colors.blue, gui = 'bold' } },
visual = { a = { fg = colors.bg, bg = colors.purple, gui = 'bold' } },
terminal = { a = { fg = colors.bg, bg = colors.cyan, gui = 'bold' } },
replace = { a = { fg = colors.bg, bg = colors.red1, gui = 'bold' } },
inactive = {
a = { fg = colors.gray1, bg = colors.bg, gui = 'bold' },
b = { fg = colors.gray1, bg = colors.bg },
c = { fg = colors.gray1, bg = colors.gray2 },
},
}
-- Import color theme based on environment variable NVIM_THEME
local env_var_nvim_theme = os.getenv 'NVIM_THEME' or 'nord'
-- Define a table of themes
local themes = {
onedark = onedark_theme,
nord = 'nord',
}
local hide_in_width = function()
event = 'VeryLazy',
opts = function()
local function hide_in_width()
return vim.fn.winwidth(0) > 100
end
@ -54,16 +11,15 @@ return {
fmt = function(str)
if hide_in_width() then
return '' .. str
else
return '' .. str:sub(1, 1) -- displays only the first character of the mode
end
return '' .. str:sub(1, 1)
end,
}
local filename = {
'filename',
file_status = true, -- displays file status (readonly status, modified status)
path = 0, -- 0 = just filename, 1 = relative path, 2 = absolute path
file_status = true,
path = 0,
}
local diagnostics = {
@ -80,21 +36,23 @@ return {
local diff = {
'diff',
colored = false,
symbols = { added = '', modified = '', removed = '' }, -- changes diff symbols
symbols = { added = '', modified = '', removed = '' },
cond = hide_in_width,
}
require('lualine').setup {
return {
options = {
icons_enabled = true,
theme = themes[env_var_nvim_theme], -- Set theme based on environment variable
-- Some useful glyphs:
-- https://www.nerdfonts.com/cheat-sheet
--        
-- Match the active colorscheme (kanagawa from theme.lua).
theme = 'auto',
section_separators = { left = '', right = '' },
component_separators = { left = '', right = '' },
disabled_filetypes = { 'alpha', 'neo-tree', 'Avante' },
disabled_filetypes = {
statusline = { 'alpha', 'NvimTree', 'lazy', 'mason' },
winbar = {},
},
always_divide_middle = true,
globalstatus = true,
},
sections = {
lualine_a = { mode },
@ -118,7 +76,7 @@ return {
lualine_z = {},
},
tabline = {},
extensions = { 'fugitive' },
extensions = {},
}
end,
}

View file

@ -1,35 +1,69 @@
local lsp_servers = {
'angularls',
'bashls',
'cssls',
'docker_compose_language_service',
'dockerls',
'emmet_language_server',
'eslint',
'graphql',
'html',
'jsonls',
'lua_ls',
'marksman',
'pyright',
'sqlls',
'tailwindcss',
'terraformls',
'ts_ls',
'vimls',
'yamlls',
}
local tools = {
'ast-grep',
'cbfmt',
'debugpy',
'editorconfig-checker',
'eslint_d',
'hadolint',
'js-debug-adapter',
'luacheck',
'prettier',
'prettierd',
'ruff',
'shellcheck',
'shfmt',
'stylua',
'vint',
'yamlfmt',
'codelldb',
}
local function dedupe(list)
local seen = {}
local out = {}
for _, item in ipairs(list) do
if not seen[item] then
seen[item] = true
table.insert(out, item)
end
end
return out
end
local tool_installer_list =
dedupe(vim.list_extend(vim.deepcopy(tools), lsp_servers))
return {
{
'mason-org/mason-lspconfig.nvim',
cond = vim.env.DOTFILES_CI ~= '1',
opts = {
-- list of servers for mason to install
ensure_installed = {
'angularls',
'bashls',
'cssls',
'denols',
'docker_compose_language_service',
'dockerls',
'emmet_language_server',
'emmet_ls',
'eslint',
'gopls',
'graphql',
'html',
'jsonls',
'lua_ls',
'marksman',
'omnisharp',
'pyright',
'rust_analyzer',
'sqlls',
'svelte',
'tailwindcss',
'terraformls',
'ts_ls',
'vimls',
'yamlls',
},
-- Only auto-enable the LSP servers we explicitly manage in this config.
-- This avoids accidental multi-server attaches (e.g. ts_ls + vtsls),
-- which can produce duplicate Telescope definition results.
automatic_enable = lsp_servers,
},
dependencies = {
{
@ -49,32 +83,21 @@ return {
},
{
'WhoIsSethDaniel/mason-tool-installer.nvim',
cond = vim.env.DOTFILES_CI ~= '1',
dependencies = {
'mason-org/mason.nvim',
},
opts = {
ensure_installed = {
'ast_grep',
'cbfmt',
'csharpier',
'editorconfig-checker',
'eslint_d',
'goimports',
'hadolint',
'luacheck',
'prettier',
'prettierd',
'ruff',
'shellcheck',
'shfmt',
'stylua',
'vint',
'yamlfmt',
'codelldb',
},
ensure_installed = tool_installer_list,
integrations = {
-- Keep mapping enabled so lspconfig names (e.g. ts_ls) resolve to Mason packages.
-- This is the sole installer to avoid racing mason-lspconfig and mason-nvim-dap.
['mason-lspconfig'] = true,
['mason-null-ls'] = false,
['mason-nvim-dap'] = false,
},
run_on_start = vim.env.DOTFILES_CI ~= '1',
start_delay = 3000,
},
},
}

View file

@ -0,0 +1,128 @@
local function run_with_output_panel(target)
local neotest = require 'neotest'
neotest.output_panel.open()
neotest.run.run(target)
end
return {
'nvim-neotest/neotest',
dependencies = {
'nvim-neotest/nvim-nio',
'nvim-lua/plenary.nvim',
'antoinemadec/FixCursorHold.nvim',
'nvim-treesitter/nvim-treesitter',
-- Adapters
'nvim-neotest/neotest-jest',
'nvim-neotest/neotest-python',
'marilari88/neotest-vitest',
-- Rust uses rustaceanvim's built-in neotest adapter
},
keys = {
{
'<leader>tt',
function()
run_with_output_panel()
end,
desc = 'Run nearest test',
},
{
'<leader>tf',
function()
run_with_output_panel(vim.fn.expand '%')
end,
desc = 'Run current file tests',
},
{
'<leader>ta',
function()
run_with_output_panel(vim.uv.cwd())
end,
desc = 'Run all tests',
},
{
'<leader>ts',
function()
require('neotest').summary.toggle()
end,
desc = 'Toggle test summary',
},
{
'<leader>to',
function()
require('neotest').output_panel.toggle()
end,
desc = 'Toggle test output panel',
},
{
'<leader>tS',
function()
require('neotest').run.stop()
end,
desc = 'Stop test run',
},
{
'<leader>tw',
function()
require('neotest').watch.toggle(vim.fn.expand '%')
end,
desc = 'Toggle test watch',
},
{
'<leader>td',
function()
run_with_output_panel { strategy = 'dap' }
end,
desc = 'Debug nearest test',
},
{
'[t',
function()
require('neotest').jump.prev { status = 'failed' }
end,
desc = 'Previous failed test',
},
{
']t',
function()
require('neotest').jump.next { status = 'failed' }
end,
desc = 'Next failed test',
},
},
config = function()
require('neotest').setup {
adapters = {
require 'neotest-jest' {
jestCommand = 'npm test --',
jestConfigFile = 'jest.config.js',
env = { CI = true },
cwd = function()
return vim.fn.getcwd()
end,
},
require 'neotest-python' {
dap = { justMyCode = false },
args = { '--log-level', 'DEBUG' },
runner = 'pytest',
},
require 'rustaceanvim.neotest',
require 'neotest-vitest',
},
status = {
virtual_text = false,
},
output = {
open_on_run = false,
},
output_panel = {
enabled = true,
open = 'botright split | resize 12',
},
quickfix = {
open = function()
vim.cmd 'copen'
end,
},
}
end,
}

View file

@ -8,7 +8,6 @@ return {
override = {
['vim.lsp.util.convert_input_to_markdown_lines'] = true,
['vim.lsp.util.stylize_markdown'] = true,
['cmp.entry.get_documentation'] = true, -- requires hrsh7th/nvim-cmp
},
},
-- you can enable a preset for easier configuration
@ -17,7 +16,7 @@ return {
command_palette = true, -- position the cmdline and popupmenu together
long_message_to_split = true, -- long messages will be sent to a split
inc_rename = false, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
lsp_doc_border = true, -- add a border to hover docs and signature help
},
},
dependencies = {

View file

@ -8,17 +8,18 @@ return {
dependencies = {
'nvim-tree/nvim-web-devicons',
},
config = function()
local nvimtree = require 'nvim-tree'
-- disable netrw at the very start of your init.lua
init = function()
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
end,
config = function()
local nvimtree = require 'nvim-tree'
-- optionally enable 24-bit colour
vim.opt.termguicolors = true
-- OR setup with some options
nvimtree.setup {
disable_netrw = true,
hijack_netrw = false,
sort = {
sorter = 'case_sensitive',
},
@ -30,10 +31,12 @@ return {
},
filters = {
dotfiles = false,
custom = { '^.git$' },
},
git = {
enable = true,
ignore = false,
timeout = 2000,
},
}
end,

View file

@ -0,0 +1,24 @@
return {
'MeanderingProgrammer/render-markdown.nvim',
ft = { 'markdown' },
dependencies = {
'nvim-treesitter/nvim-treesitter',
'nvim-tree/nvim-web-devicons',
},
keys = {
{
'<leader>mk',
'<cmd>RenderMarkdown toggle<CR>',
desc = 'Toggle markdown render/raw',
ft = 'markdown',
},
},
opts = {
-- Always keep markdown rendered in all modes.
render_modes = true,
-- Do not reveal raw syntax under cursor while moving/editing.
anti_conceal = {
enabled = false,
},
},
}

View file

@ -33,6 +33,11 @@ return {
height = { padding = 0 },
},
},
path_display = {
filename_first = {
reverse_directories = true,
},
},
mappings = {
i = {
['<C-k>'] = actions.move_selection_previous, -- move to prev result
@ -66,16 +71,14 @@ return {
oldfiles = {
initial_mode = 'normal',
},
},
live_grep = {
file_ignore_patterns = { 'node_modules', '.git', '.venv' },
additional_args = function(_)
return { '--hidden' }
end,
},
path_display = {
filename_first = {
reverse_directories = true,
live_grep = {
file_ignore_patterns = { 'node_modules', '.git', '.venv' },
additional_args = function(_)
return { '--hidden' }
end,
},
git_files = {
previewer = false,
},
},
extensions = {
@ -83,9 +86,6 @@ return {
require('telescope.themes').get_dropdown(),
},
},
git_files = {
previewer = false,
},
}
-- Enable telescope fzf native, if installed

View file

@ -1,3 +1,18 @@
local function resolve_kanagawa_variant()
local value = (vim.env.NVIM_THEME or ''):lower()
local variants = {
wave = 'wave',
dragon = 'dragon',
lotus = 'lotus',
['kanagawa-wave'] = 'wave',
['kanagawa-dragon'] = 'dragon',
['kanagawa-lotus'] = 'lotus',
}
return variants[value] or 'dragon'
end
local variant = resolve_kanagawa_variant()
return {
'rebelot/kanagawa.nvim',
priority = 1000,
@ -37,9 +52,9 @@ return {
MasonNormal = { bg = 'none', fg = theme.ui.fg_dim },
}
end,
theme = 'wave', -- Set to dragon since you're using kanagawa-dragon
theme = variant,
background = {
dark = 'wave',
dark = variant,
light = 'lotus',
},
},

View file

@ -1,108 +1,114 @@
-- Highlight, edit, and navigate code
local ci = vim.env.DOTFILES_CI == '1'
local parsers = {
'angular',
'lua',
'python',
'javascript',
'typescript',
'vimdoc',
'vim',
'regex',
'terraform',
'sql',
'dockerfile',
'toml',
'json',
'java',
'groovy',
'gitignore',
'graphql',
'yaml',
'make',
'cmake',
'markdown',
'markdown_inline',
'bash',
'tsx',
'css',
'html',
'rust',
}
return {
'nvim-treesitter/nvim-treesitter',
branch = 'master',
build = ':TSUpdate',
main = 'nvim-treesitter.configs',
dependencies = {
'nvim-treesitter/nvim-treesitter-textobjects',
},
config = function()
require('nvim-treesitter.configs').setup {
-- Add languages to be installed here that you want installed for treesitter
ensure_installed = {
'angular',
'lua',
'python',
'javascript',
'typescript',
'vimdoc',
'vim',
'regex',
'terraform',
'sql',
'dockerfile',
'toml',
'json',
'java',
'groovy',
'go',
'gitignore',
'graphql',
'yaml',
'make',
'cmake',
'markdown',
'markdown_inline',
'bash',
'tsx',
'css',
'html',
'toml',
opts = {
ensure_installed = ci and {} or parsers,
auto_install = not ci,
parser_install_dir = ci and (vim.fn.stdpath 'cache' .. '/treesitter')
or nil,
highlight = { enable = true },
indent = { enable = true },
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<c-space>',
node_incremental = '<c-space>',
scope_incremental = '<c-s>',
node_decremental = '<M-space>',
},
-- Autoinstall languages that are not installed
auto_install = true,
highlight = { enable = true },
indent = { enable = true },
incremental_selection = {
},
textobjects = {
select = {
enable = true,
lookahead = true,
keymaps = {
init_selection = '<c-space>',
node_incremental = '<c-space>',
scope_incremental = '<c-s>',
node_decremental = '<M-space>',
['aa'] = '@parameter.outer',
['ia'] = '@parameter.inner',
['af'] = '@function.outer',
['if'] = '@function.inner',
['ac'] = '@class.outer',
['ic'] = '@class.inner',
},
},
textobjects = {
select = {
enable = true,
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
keymaps = {
-- You can use the capture groups defined in textobjects.scm
['aa'] = '@parameter.outer',
['ia'] = '@parameter.inner',
['af'] = '@function.outer',
['if'] = '@function.inner',
['ac'] = '@class.outer',
['ic'] = '@class.inner',
},
move = {
enable = true,
set_jumps = true,
goto_next_start = {
[']m'] = '@function.outer',
[']]'] = '@class.outer',
},
move = {
enable = true,
set_jumps = true, -- whether to set jumps in the jumplist
goto_next_start = {
[']m'] = '@function.outer',
[']]'] = '@class.outer',
},
goto_next_end = {
[']M'] = '@function.outer',
[']['] = '@class.outer',
},
goto_previous_start = {
['[m'] = '@function.outer',
['[['] = '@class.outer',
},
goto_previous_end = {
['[M'] = '@function.outer',
['[]'] = '@class.outer',
},
goto_next_end = {
[']M'] = '@function.outer',
[']['] = '@class.outer',
},
swap = {
enable = true,
swap_next = {
['<leader>a'] = '@parameter.inner',
},
swap_previous = {
['<leader>A'] = '@parameter.inner',
},
goto_previous_start = {
['[m'] = '@function.outer',
['[['] = '@class.outer',
},
goto_previous_end = {
['[M'] = '@function.outer',
['[]'] = '@class.outer',
},
},
}
swap = {
enable = true,
swap_next = {
['<leader>a'] = '@parameter.inner',
},
swap_previous = {
['<leader>A'] = '@parameter.inner',
},
},
},
},
config = function(_, opts)
require('nvim-treesitter.configs').setup(opts)
-- Register additional file extensions
vim.filetype.add { extension = { tf = 'terraform' } }
vim.filetype.add { extension = { tfvars = 'terraform' } }
vim.filetype.add { extension = { pipeline = 'groovy' } }
vim.filetype.add { extension = { multibranch = 'groovy' } }
vim.filetype.add {
extension = {
tf = 'terraform',
tfvars = 'terraform',
pipeline = 'groovy',
multibranch = 'groovy',
},
}
end,
}

View file

@ -1,81 +0,0 @@
return {
'wojciech-kulik/xcodebuild.nvim',
dependencies = {
'nvim-telescope/telescope.nvim',
'MunifTanjim/nui.nvim',
-- "nvim-tree/nvim-tree.lua", -- (optional) to manage project files
'stevearc/oil.nvim', -- (optional) to manage project files
'nvim-treesitter', -- (optional) for Quick tests support (required Swift parser)
},
ft = { 'swift' },
config = function()
require('xcodebuild').setup {
-- put some options here or leave it empty to use default settings
}
local wk = require 'which-key'
wk.add {
{
'<leader>xC',
'<CMD>XcodebuildSetup<CR>',
desc = '[X]code [C]onfigure',
},
{
'<leader>X',
'<CMD>XcodebuildPicker<CR>',
desc = 'Show [X]codebuild Actions',
},
{
'<leader>xf',
'<CMD>XcodebuildProjectManager<CR>',
desc = 'Show Project Manager Actions',
},
-- Build
{
'<leader>xb',
'<CMD>XcodebuildBuild<CR>',
desc = '[X]code [B]uild project',
},
{
'<leader>xB',
'<CMD>XcodebuildBuildForTesting<CR>',
desc = '[X]code [B]uild project for Testing',
},
{
'<leader>xr',
'<CMD>XcodebuildBuildRun<CR>',
desc = '[X]code [R]un project',
},
-- Tests
{ '<leader>xt', '<CMD>XcodebuildTest<CR>', desc = '[X]code Run [T]ests' },
{
'<leader>xT',
'<CMD>XcodebuildTestClass<CR>',
desc = '[X]code Run Current Class [T]ests',
},
{
'<leader>x.',
'<CMD>XcodebuildTestRepeat<CR>',
desc = '[X]code Repeat Last Tests',
},
-- Selection
{
'<leader>xd',
'<CMD>XcodebuildSelectDevice<CR>',
desc = '[X]code Select [D]evice',
},
{
'<leader>xp',
'<CMD>XcodebuildSelectTestPlan<CR>',
desc = '[X]code Select Test [P]lan',
},
-- Logs
{
'<leader>xl',
'<CMD>XcodebuildToggleLogs<CR>',
desc = '[X]code Toggle [L]ogs',
},
}
end,
}

View file

@ -0,0 +1,115 @@
format = """
$directory\
$git_branch\
$git_status\
$fill\
$bun\
$lua\
$nodejs\
$python\
$rust\
$terraform\
$docker_context\
$jobs\
$cmd_duration\
$line_break\
$character"""
add_newline = true
palette = "wave"
[directory]
style = 'bold fg:dark_blue'
format = '[$path ]($style)'
truncation_length = 3
truncation_symbol = '…/'
truncate_to_repo = false
[directory.substitutions]
'Documents' = '󰈙'
'Downloads' = ' '
'Music' = ' '
'Pictures' = ' '
[git_branch]
style = 'fg:green'
symbol = ' '
format = '[on](white) [$symbol$branch ]($style)'
[git_status]
style = 'fg:red'
format = '([$all_status$ahead_behind]($style) )'
[fill]
symbol = ' '
[bun]
style = 'blue'
symbol = '🥟 '
[lua]
format = '[$symbol($version )]($style)'
symbol = ' '
[nodejs]
style = 'blue'
symbol = ' '
[python]
style = 'yellow'
symbol = ' '
[rust]
style = 'orange'
symbol = ' '
[terraform]
style = 'purple'
symbol = '󱁢 '
[package]
symbol = '󰏗 '
[docker_context]
symbol = ' '
style = 'fg:#06969A'
format = '[$symbol]($style) $path'
detect_files = ['docker-compose.yml', 'docker-compose.yaml', 'Dockerfile']
detect_extensions = ['Dockerfile']
[jobs]
symbol = ' '
style = 'red'
number_threshold = 1
format = '[$symbol]($style)'
[cmd_duration]
min_time = 500
style = 'fg:gray'
format = '[$duration]($style)'
[palettes.wave]
dark_blue = '#7e9cd8'
blue = '#7fb4ca'
teal = '#6a9589'
red = '#c34043'
orange = '#ffa066'
green = '#76946a'
yellow = '#c0a36e'
purple = '#957fb8'
gray = '#727169'
black = '#1f1f28'
white = '#dcd7ba'
[palettes.dragon]
dark_blue = '#8ba4b0'
blue = '#7e9cd8'
teal = '#8ea4a2'
red = '#c4746e'
orange = '#b6927b'
green = '#87a987'
yellow = '#c4b28a'
purple = '#a292a3'
gray = '#727169'
black = '#181616'
white = '#c5c9c5'

View file

@ -6,8 +6,9 @@ $fill\
$bun\
$lua\
$nodejs\
$golang\
$python\
$rust\
$terraform\
$docker_context\
$jobs\
$cmd_duration\
@ -15,7 +16,7 @@ $line_break\
$character"""
add_newline = true
palette = "nord"
palette = "dragon"
[directory]
style = 'bold fg:dark_blue'
@ -26,13 +27,13 @@ truncate_to_repo = false
[directory.substitutions]
'Documents' = '󰈙'
'Downloads' = ' '
'Music' = ' '
'Pictures' = ' '
'Downloads' = ' '
'Music' = ' '
'Pictures' = ' '
[git_branch]
style = 'fg:green'
symbol = ' '
symbol = ' '
format = '[on](white) [$symbol$branch ]($style)'
[git_status]
@ -43,37 +44,41 @@ format = '([$all_status$ahead_behind]($style) )'
symbol = ' '
[bun]
format = 'blue'
style = 'blue'
symbol = '🥟 '
[lua]
format = '[$symbol($version )]($style)'
symbol = ' '
symbol = ' '
[nodejs]
style = 'blue'
symbol = ' '
symbol = ' '
[golang]
style = 'blue'
symbol = ' '
[python]
style = 'yellow'
symbol = ' '
[rust]
style = 'orange'
symbol = ' '
symbol = ' '
[terraform]
style = 'purple'
symbol = '󱁢 '
[package]
symbol = '󰏗 '
[docker_context]
symbol = ' '
symbol = ' '
style = 'fg:#06969A'
format = '[$symbol]($style) $path'
detect_files = ['docker-compose.yml', 'docker-compose.yaml', 'Dockerfile']
detect_extensions = ['Dockerfile']
[jobs]
symbol = ' '
symbol = ' '
style = 'red'
number_threshold = 1
format = '[$symbol]($style)'
@ -83,28 +88,28 @@ min_time = 500
style = 'fg:gray'
format = '[$duration]($style)'
[palettes.nord]
dark_blue = '#5E81AC'
blue = '#81A1C1'
teal = '#88C0D0'
red = '#BF616A'
orange = '#D08770'
green = '#A3BE8C'
yellow = '#EBCB8B'
purple = '#B48EAD'
gray = '#434C5E'
black = '#2E3440'
white='#D8DEE9'
[palettes.wave]
dark_blue = '#7e9cd8'
blue = '#7fb4ca'
teal = '#6a9589'
red = '#c34043'
orange = '#ffa066'
green = '#76946a'
yellow = '#c0a36e'
purple = '#957fb8'
gray = '#727169'
black = '#1f1f28'
white = '#dcd7ba'
[palettes.onedark]
dark_blue='#61afef'
blue='#56b6c2'
red='#e06c75'
green='#98c379'
purple='#c678dd'
cyan='#56b6c2'
orange='#be5046'
yellow='#e5c07b'
gray='#828997'
white ='#abb2bf'
black='#2c323c'
[palettes.dragon]
dark_blue = '#8ba4b0'
blue = '#7e9cd8'
teal = '#8ea4a2'
red = '#c4746e'
orange = '#b6927b'
green = '#87a987'
yellow = '#c4b28a'
purple = '#a292a3'
gray = '#727169'
black = '#181616'
white = '#c5c9c5'

View file

@ -1,20 +1,20 @@
# bg="#3B4252"
# bg="#181616"
bg="default"
default_fg="#D8DEE9"
session_fg="#A3BE8C"
session_selection_fg="#3B4252"
session_selection_bg="#81A1C1"
active_window_fg="#88C0D0"
active_pane_border="#abb2bf"
default_fg="#c5c9c5"
session_fg="#87a987"
session_selection_fg="#181616"
session_selection_bg="#8ea4a2"
active_window_fg="#8ba4b0"
active_pane_border="#8992a7"
set -g status-left-length 200 # default: 10
set -g status-right-length 200 # default: 10
set -g status-left "#[fg=${session_fg},bold,bg=${bg}] #S #[fg=${default_fg},nobold,bg=${bg}] | "
set -g status-right " #{cpu -i 3} #{mem} "
set -g status-left "#[fg=${session_fg},bold,bg=${bg}] #S #[fg=${default_fg},nobold,bg=${bg}] | "
set -g status-right " #{cpu -i 3} #{mem} "
set -g status-justify left
set -g status-style "bg=${bg}"
set -g window-status-format "#[fg=${default_fg},bg=default] #I:#W"
set -g window-status-current-format "#[fg=${active_window_fg},bold,bg=default] #[underscore]#I:#W"
set -g window-status-current-format "#[fg=${active_window_fg},bold,bg=default] #[underscore]#I:#W"
set -g window-status-last-style "fg=${default_fg},bg=default"
set -g message-command-style "bg=default,fg=${default_fg}"
set -g message-style "bg=default,fg=${default_fg}"

View file

@ -1,20 +1,22 @@
# Enable 256-color and true-color (24-bit) support in tmux
set -g default-terminal "screen-256color" # Set terminal type for 256-color support
set -g default-terminal "tmux-256color" # Use tmux-256color for proper undercurl/italic support
set -ga terminal-overrides ",*256col*:Tc" # Override to enable true-color for compatible terminals
# General
set -g set-clipboard on # Use system clipboard
set -g detach-on-destroy off # Don't exit from tmux when closing a session
set -g escape-time 0 # Remove delay for exiting insert mode with ESC in Neovim
set -g escape-time 10 # Low delay for ESC (0 can cause escape sequence issues)
set -g history-limit 1000000 # Increase history size (from 2,000)
set -g mouse on # Enable mouse support
set -g status-interval 3 # Update the status bar every 3 seconds (default: 15 seconds)
set -g allow-passthrough on # Allow programs in the pane to bypass tmux (e.g. for image preview)
set -g allow-passthrough off # Avoid terminal state corruption from passthrough escape sequences
set -g status-position bottom
set -g focus-events on # Enable focus events for Neovim autoread/FocusGained
# Set prefix key
unbind C-b # Unbind the default prefix key
set -g prefix C-Space # Set new prefix key to Ctrl+Space
set -g prefix2 C-b # Fallback to original tmux prefix
# Refresh tmux config with r
unbind r
@ -40,9 +42,12 @@ bind -r h resize-pane -L 5
# Use m key to maximize pane
bind -r m resize-pane -Z
# vim-tmux-navigator captures plain Ctrl+l for pane navigation, which breaks
# the shell's clear-screen. Restore it as "Prefix + Ctrl+l".
bind C-l send-keys 'C-l'
# Enable vi mode to allow us to use vim keys to move around in copy mode (Prefix + [ places us in copy mode)
set-window-option -g mode-keys vi
set -g @yank_selection_mouse 'clipboard' # Fix mouse drag copy behavior
# Paste yanked text with "Prefix + P" ("Prefix + p" goes to previous window)
@ -63,12 +68,14 @@ set -g @plugin 'tmux-plugins/tmux-continuum' # Automatically saves sessions e
set -g @plugin 'hendrikmi/tmux-cpu-mem-monitor' # CPU and memory info
set -g @plugin 'tmux-plugins/tmux-yank'
# Load theme
source-file ~/.config/tmux/nord-theme.conf
# Load theme from deterministic selector file generated during shell startup.
if-shell '[ -f ~/.cache/dotfiles/tmux-theme.conf ]' \
'source-file ~/.cache/dotfiles/tmux-theme.conf' \
'source-file ~/.config/tmux/dragon-theme.conf'
# Resurrect
# Resurrect + continuum: auto-save every 15 min and restore on server start.
set -g @resurrect-capture-pane-contents 'on'
# set -g @continuum-restore 'on'
set -g @continuum-restore 'on'
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'

View file

@ -0,0 +1,23 @@
# bg="#1f1f28"
bg="default"
default_fg="#dcd7ba"
session_fg="#76946a"
session_selection_fg="#1f1f28"
session_selection_bg="#7e9cd8"
active_window_fg="#7fb4ca"
active_pane_border="#957fb8"
set -g status-left-length 200 # default: 10
set -g status-right-length 200 # default: 10
set -g status-left "#[fg=${session_fg},bold,bg=${bg}] #S #[fg=${default_fg},nobold,bg=${bg}] | "
set -g status-right " #{cpu -i 3} #{mem} "
set -g status-justify left
set -g status-style "bg=${bg}"
set -g window-status-format "#[fg=${default_fg},bg=default] #I:#W"
set -g window-status-current-format "#[fg=${active_window_fg},bold,bg=default] #[underscore]#I:#W"
set -g window-status-last-style "fg=${default_fg},bg=default"
set -g message-command-style "bg=default,fg=${default_fg}"
set -g message-style "bg=default,fg=${default_fg}"
set -g mode-style "bg=${session_selection_bg},fg=${session_selection_fg}"
set -g pane-active-border-style "fg=${active_pane_border},bg=default"
set -g pane-border-style "fg=brightblack,bg=default"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 MiB

View file

@ -4,6 +4,26 @@ if wezterm.config_builder then
config = wezterm.config_builder()
end
local function env_number(name, fallback)
local raw = os.getenv(name)
local parsed = raw and tonumber(raw) or nil
if parsed == nil then
return fallback
end
return parsed
end
-- User-tunable settings live in ~/.zshrc, which writes them to a cache file
-- (GUI-launched WezTerm never sees shell exports). WezTerm watches that
-- file and live-reloads, so editing .zshrc + opening a new shell applies.
-- Precedence: cache file > process env > defaults.
local user = {}
local env_file = wezterm.home_dir .. "/.cache/dotfiles/wezterm-env.lua"
local ok, loaded = pcall(dofile, env_file)
if ok and type(loaded) == "table" then
user = loaded
end
wezterm.add_to_config_reload_watch_list(env_file)
-- Basic settings
config.automatically_reload_config = true
config.window_close_confirmation = "NeverPrompt"
@ -13,52 +33,78 @@ config.check_for_updates = false
config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = false
config.enable_tab_bar = false
-- Font configuration
config.font_size = 15.5
config.font = wezterm.font("JetBrains Mono", { weight = "Regular" })
config.font_size = user.font_size or env_number("WEZTERM_FONT_SIZE", 16)
config.font = wezterm.font("JetBrainsMono Nerd Font", { weight = "Regular" })
config.bold_brightens_ansi_colors = true
config.force_reverse_video_cursor = true
-- Kanagawa Wave color scheme
config.colors = {
foreground = "#dcd7ba",
background = "#1f1f28",
cursor_bg = "#c8c093",
cursor_fg = "#c8c093",
cursor_border = "#c8c093",
selection_fg = "#c8c093",
selection_bg = "#2d4f67",
scrollbar_thumb = "#16161d",
split = "#54546d", -- Lighter for better split visibility
ansi = {
"#090618", -- black
"#c34043", -- red
"#76946a", -- green
"#c0a36e", -- yellow
"#7e9cd8", -- blue
"#957fb8", -- magenta
"#6a9589", -- cyan
"#c8c093", -- white
config.force_reverse_video_cursor = false
-- Kanagawa palette, variant chosen by $WEZTERM_THEME (set by .zshrc from
-- $KANAGAWA_THEME). Defaults to "wave"; falls back to "dragon" for anything else.
local themes = {
wave = {
foreground = "#dcd7ba",
background = "#1f1f28",
cursor_bg = "#c8c093",
cursor_fg = "#1f1f28",
cursor_border = "#c8c093",
selection_fg = "#c8c093",
selection_bg = "#2d4f67",
ansi = {
"#090618",
"#c34043",
"#76946a",
"#c0a36e",
"#7e9cd8",
"#957fb8",
"#6a9589",
"#c8c093",
},
brights = {
"#727169",
"#e82424",
"#98bb6c",
"#e6c384",
"#7fb4ca",
"#938aa9",
"#7aa89f",
"#dcd7ba",
},
},
brights = {
"#727169", -- bright black
"#e82424", -- bright red
"#98bb6c", -- bright green
"#e6c384", -- bright yellow
"#7fb4ca", -- bright blue
"#938aa9", -- bright magenta
"#7aa89f", -- bright cyan
"#dcd7ba", -- bright white
},
indexed = {
[16] = "#ffa066",
[17] = "#ff5d62",
dragon = {
foreground = "#c5c9c5",
background = "#181616",
cursor_bg = "#c5c9c5",
cursor_fg = "#181616",
cursor_border = "#c5c9c5",
selection_fg = "#c5c9c5",
selection_bg = "#2d4f67",
ansi = {
"#0d0c0c",
"#c4746e",
"#87a987",
"#c4b28a",
"#8ba4b0",
"#a292a3",
"#8ea4a2",
"#c5c9c5",
},
brights = {
"#727169",
"#e46876",
"#8a9a7b",
"#c0a36e",
"#7fb4ca",
"#938aa9",
"#7aa89f",
"#c5c9c5",
},
},
}
local variant = (user.theme or os.getenv("WEZTERM_THEME") or "wave"):lower()
if variant == "kanagawa-wave" then variant = "wave" end
if variant == "kanagawa-dragon" then variant = "dragon" end
config.colors = themes[variant] or themes.wave
-- Window padding
config.window_padding = {
left = 8,
@ -66,22 +112,19 @@ config.window_padding = {
top = 8,
bottom = 8,
}
-- Window transparency and blur
config.window_background_opacity = 0.85
config.macos_window_background_blur = 60
config.text_background_opacity = 0.85
-- Window transparency
config.window_background_opacity = user.window_opacity or env_number("WEZTERM_WINDOW_OPACITY", 0.80)
-- Keep text cells opaque by default; transparent text backgrounds can show
-- grid/dot artifacts on some GPU/compositor combinations.
config.text_background_opacity = user.text_opacity or env_number("WEZTERM_TEXT_OPACITY", 1.0)
-- Performance
config.scrollback_lines = 10000
config.enable_scroll_bar = false
-- Cursor
config.default_cursor_style = "BlinkingBar"
config.cursor_blink_rate = 500
config.cursor_blink_ease_in = "Constant"
config.cursor_blink_ease_out = "Constant"
-- Key bindings
config.keys = {
{ key = "Enter", mods = "CTRL", action = wezterm.action({ SendString = "\x1b[13;5u" }) },
@ -98,48 +141,18 @@ config.keys = {
{ key = "w", mods = "CTRL|SHIFT", action = wezterm.action.CloseCurrentPane({ confirm = false }) },
-- Zoom pane
{ key = "z", mods = "CTRL|SHIFT", action = wezterm.action.TogglePaneZoomState },
{
key = "f",
mods = "SHIFT|CTRL",
action = wezterm.action.ToggleFullScreen,
},
{ key = "f", mods = "SHIFT|CTRL", action = wezterm.action.ToggleFullScreen },
}
-- Hyperlink rules
config.hyperlink_rules = {
{
regex = "\\((\\w+://\\S+)\\)",
format = "$1",
highlight = 1,
},
{
regex = "\\[(\\w+://\\S+)\\]",
format = "$1",
highlight = 1,
},
{
regex = "\\{(\\w+://\\S+)\\}",
format = "$1",
highlight = 1,
},
{
regex = "<(\\w+://\\S+)>",
format = "$1",
highlight = 1,
},
{
regex = "[^(]\\b(\\w+://\\S+[)/a-zA-Z0.9-]+)",
format = "$1",
highlight = 1,
},
{
regex = "\\b\\w+@[\\w-]+(\\.[\\w-]+)+\\b",
format = "mailto:$0",
},
{ regex = "\\((\\w+://\\S+)\\)", format = "$1", highlight = 1 },
{ regex = "\\[(\\w+://\\S+)\\]", format = "$1", highlight = 1 },
{ regex = "\\{(\\w+://\\S+)\\}", format = "$1", highlight = 1 },
{ regex = "<(\\w+://\\S+)>", format = "$1", highlight = 1 },
{ regex = "[^(]\\b(\\w+://\\S+[)/a-zA-Z0-9-]+)", format = "$1", highlight = 1 },
{ regex = "\\b\\w+@[\\w-]+(\\.[\\w-]+)+\\b", format = "mailto:$0" },
}
-- Window size
config.initial_rows = 34
config.initial_cols = 135
return config

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

View file

@ -1,6 +1,6 @@
[user]
name = Brian Pooe
email = bria.method@gmail.com
email = brian.method@gmail.com
[color]
ui = auto
@ -23,17 +23,17 @@ hlog = !git log --pretty=format:\"%h - %an, %ar : %s\" --graph
all = !git log --pretty=oneline --abbrev-commit --all --no-merges
# all commits today for only me
today = !git all --since='12am'
today = !git all --since='12am' --author=brian.method@gmail.com
pom = push origin main
pos = push origin staging
pod = push origin develop
pou = push origin uat
pou = push origin uat
ruo = remote update origin
cma = commit --amend
cmna = commit -n --amend
del = branch -D
cm = commit -m
pf = push -f origin
pf = push --force-with-lease origin
po = push origin
rv = remote -v
rao = remote add origin
@ -43,13 +43,19 @@ stash-a = stash apply
undo-commit = reset --soft HEAD~1
stash-unapply = !git stash show -p | git apply -R
del-local = "!f() { git branch | grep -v 'main' | xargs git branch -d; }; f"
del-remote = git remote prune
del-remote = remote prune
latest-tag = tag -l --sort=-version:refname
back = !f() { git reset --soft HEAD~$1; }; f
[push]
default = matching
default = simple
[core]
editor=nvim
pager = less -x4
# Machine-specific overrides (e.g. a work identity via includeIf).
# Git silently skips this if the file doesn't exist. Keep last so
# local settings win.
[include]
path = ~/.gitconfig.local

6
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly

57
.github/workflows/validate.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: Validate
on:
push:
pull_request:
jobs:
dotfiles:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install validation tools
run: |
sudo apt-get update
sudo apt-get install --yes build-essential curl file git gnupg procps shellcheck shfmt zsh
source install/lib/common.sh
source install/lib/brew.sh
source install/lib/packages.sh
install_wezterm
install_homebrew
brew install neovim starship stylua
echo "$BREW_PREFIX/bin" >> "$GITHUB_PATH"
- name: Restore Neovim plugins
env:
DOTFILES_CI: "1"
XDG_CONFIG_HOME: ${{ github.workspace }}/.config
run: nvim --headless "+Lazy! restore" +qa
- name: Validate
run: bin/check-dotfiles
# End-to-end installer test: the dotfiles job validates the configs but
# never runs install.sh itself, which is what rots (apt repo URLs, GPG
# fingerprints, pinned checksums). Run the full install as a normal user
# in a pristine container.
installer:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Run full installer in a fresh container
run: |
docker run --rm -v "$PWD:/src:ro" ubuntu:24.04 bash -ec '
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends sudo curl ca-certificates git
useradd -m -s /bin/bash tester
echo "tester ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/tester
cp -r /src /home/tester/dotfiles
chown -R tester:tester /home/tester/dotfiles
su tester -c "cd ~/dotfiles && install/install.sh"
su tester -c "cd ~/dotfiles && install/install.sh --unlink"
'

78
.gitignore vendored
View file

@ -1,79 +1,41 @@
# Created by https://www.toptal.com/developers/gitignore/api/vim,macos
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,macos
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Vim ###
# Swap
# Vim
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
.nvimlog
nvim.log
.config/zed/
# Track only the managed application configurations.
.config/*
!.config/bat/
!.config/nvim/
!.config/lazygit/
!.config/starship/
!.config/wezterm/
!.config/karabiner/
!.config/karabiner/karabiner.json
.config/wezterm/env.lua
!.config/tmux/
!.config/tmux/nord-theme.conf
!.config/tmux/tmux-cheatsheet.md
!.config/tmux/tmux.conf
!.config/.vimrc
!.config/.ideavimrc
# Ignore subfolders in karabiner and tmux
.config/karabiner/**
!.config/karabiner/karabiner.json
# Ignore generated or downloaded tmux content.
.config/tmux/**
!.config/tmux/nord-theme.conf
!.config/tmux/dragon-theme.conf
!.config/tmux/wave-theme.conf
!.config/tmux/tmux-cheatsheet.md
!.config/tmux/tmux.conf
!.config/.vimrc
# End of https://www.toptal.com/developers/gitignore/api/vim,macos
# Track only the ssh client config — never keys or anything else.
.ssh/*
!.ssh/config
# Track only Claude Code settings — never history, sessions, or caches.
.claude/*
!.claude/settings.json

11
.ssh/config Normal file
View file

@ -0,0 +1,11 @@
Host caddy
HostName 10.0.15.5
User brian
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host technitium
HostName 10.0.10.5
User brian
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes

129
.zshrc
View file

@ -1,64 +1,135 @@
# Homebrew (Linux) — must come first so brew-installed tools and plugin
# paths below resolve.
if [ -x /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
fi
export PATH="$HOME/.local/bin:$PATH"
# Persistent command history. Keep HISTSIZE larger than SAVEHIST so zsh has
# room to merge history from other active shells before trimming the file.
HISTFILE="$HOME/.zsh_history"
HISTSIZE=100000
SAVEHIST=80000
setopt SHARE_HISTORY
setopt HIST_REDUCE_BLANKS
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_IGNORE_SPACE
# ===================== User-tunable environment ========================
# Single place to control the look of the whole stack.
export KANAGAWA_THEME="wave" # wave | dragon
export WEZTERM_FONT_SIZE="13"
export WEZTERM_WINDOW_OPACITY="0.9"
export WEZTERM_TEXT_OPACITY="1.0"
# ========================================================================
# Theme (kanagawa variants: dragon|wave)
case "${KANAGAWA_THEME}" in
wave|kanagawa-wave)
export TMUX_THEME="wave"
export NVIM_THEME="wave"
export STARSHIP_THEME="wave"
export WEZTERM_THEME="wave"
export STARSHIP_CONFIG="$HOME/.config/starship/starship-wave.toml"
;;
*)
export TMUX_THEME="dragon"
export NVIM_THEME="dragon"
export STARSHIP_THEME="dragon"
export WEZTERM_THEME="dragon"
export STARSHIP_CONFIG="$HOME/.config/starship/starship.toml"
;;
esac
# Generate the theme files consumed by GUI-launched WezTerm and tmux.
if command -v dotfiles-apply-theme >/dev/null 2>&1; then
dotfiles-apply-theme
fi
# Starship
export STARSHIP_CONFIG="$HOME/.config/starship/starship.toml"
eval "$(starship init zsh)"
if command -v starship >/dev/null 2>&1; then
eval "$(starship init zsh)"
fi
# zoxide - a better cd command
eval "$(zoxide init zsh)"
if command -v zoxide >/dev/null 2>&1; then
eval "$(zoxide init zsh)"
fi
# Activate syntax highlighting
source $(brew --prefix)/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
# Syntax highlighting
for _p in \
"$HOMEBREW_PREFIX/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" \
/usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
do
[ -f "$_p" ] && source "$_p" && break
done
# Disable underline
(( ${+ZSH_HIGHLIGHT_STYLES} )) || typeset -A ZSH_HIGHLIGHT_STYLES
ZSH_HIGHLIGHT_STYLES[path]=none
ZSH_HIGHLIGHT_STYLES[path_prefix]=none
# Activate autosuggestions
source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh
# Autosuggestions
# The plugin default is intentionally dim and becomes unreadable with a
# transparent terminal background.
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=#938aa9'
for _p in \
"$HOMEBREW_PREFIX/share/zsh-autosuggestions/zsh-autosuggestions.zsh" \
/usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh
do
[ -f "$_p" ] && source "$_p" && break
done
# ------------FZF--------------
# Set up fzf key bindings and fuzzy completion
export FZF_DEFAULT_COMMAND="fd --hidden --strip-cwd-prefix --exclude .git "
export FZF_DEFAULT_COMMAND="fd --hidden --strip-cwd-prefix --exclude .git"
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND="fd --type=d --hidden --strip-cwd-prefix --exclude .git"
export FZF_DEFAULT_OPTS="--height 50% --layout=default --border --color=hl:#2dd4bf"
# Setup fzf previews
export FZF_CTRL_T_OPTS="--preview 'bat --color=always -n --line-range :500 {}'"
export FZF_ALT_C_OPTS="--preview 'eza --icons=always --tree --color=always {} | head -200'"
# fzf preview for tmux
export FZF_TMUX_OPTS=" -p90%,70% "
# fzf key bindings and completion
if command -v fzf >/dev/null 2>&1; then
source <(fzf --zsh)
fi
unset _p
# -----------------------------
# Themes (onedark or nord)
export TMUX_THEME="nord"
export NVIM_THEME="nord"
export STARSHIP_THEME="nord"
export WEZTERM_THEME="nord"
unalias lt 2>/dev/null
lt() {
local level=${1:-3}
shift
eza --tree --level "$level" "$@"
(( $# )) && shift
eza --tree --all --level "$level" "$@"
}
# aliases
alias weztermconfig="nvim ~/.config/wezterm/wezterm.lua"
alias zshconfig="vim ~/.zshrc"
alias nvimconfig="vim ~/.config/nvim"
alias zshconfig="nvim ~/.zshrc"
alias nvimconfig="nvim ~/.config/nvim"
alias dev="cd $HOME/Documents"
alias ls="eza --no-filesize --long --color=always --icons=always --no-user"
alias ll="eza -lah --group-directories-first --no-filesize --long --color=always --icons=always --no-user"
alias lt="eza --tree --level"
alias vim="nvim"
alias crq="cargo run -q"
alias sudo="sudo "
alias lg="lazygit"
alias update="brew upgrade && sudo apt update && sudo apt upgrade -y"
if command -v tmux &>/dev/null && [ -z "$TMUX" ]; then
export DOTFILES_AUTO_TMUX="${DOTFILES_AUTO_TMUX:-0}"
if [ "$DOTFILES_AUTO_TMUX" = "1" ] \
&& command -v tmux &>/dev/null \
&& [ -z "$TMUX" ] \
&& [ -z "$SSH_CONNECTION" ]
then
tmux attach -t default 2>/dev/null || tmux new -s default
fi
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
# Machine-specific overrides (secrets, work proxies, installer PATH
# additions). Never tracked in the repo — keep this line last so local
# settings win.
[ -f "$HOME/.zshrc.local" ] && source "$HOME/.zshrc.local"

View file

@ -1 +1,55 @@
# dotfiles
# dotfiles
Linux dotfiles oriented around **Pop!_OS 24.04** (Cosmic DE).
## Quick Setup
```bash
git clone https://github.com/brianpooe/dotfiles.git ~/dotfiles
~/dotfiles/install/install.sh --dotfiles-only
```
The installer backs up existing targets before linking replacements.
## Install
On Pop!_OS / Ubuntu 24.04, run the bundled installer. It uses **apt** for
the system base + GUI apps (WezTerm, Brave Beta) and **Homebrew** for the
CLI toolchain (fzf, fd, bat, eza, zoxide, ripgrep, tmux, neovim, lazygit,
starship, gh, zsh plugins) so those tools stay current — one
`brew upgrade` updates everything.
```bash
~/dotfiles/install/install.sh
```
See [`install/README.md`](install/README.md) for flags and the full
package list. The `update` alias runs
`brew upgrade && sudo apt update && sudo apt upgrade -y`.
## Theme
Kanagawa theme with two variants: `dragon` (dark) and `wave` (darker blue).
Set in shell:
```bash
export KANAGAWA_THEME="wave" # or "dragon"
```
Opening a new shell runs `dotfiles-apply-theme`, which writes the generated
tmux and WezTerm settings to `~/.cache/dotfiles`.
Automatic tmux startup is opt-in:
```bash
export DOTFILES_AUTO_TMUX=1
```
## Validate
```bash
bin/check-dotfiles
```
The same checks run in GitHub Actions.

60
bin/check-dotfiles Executable file
View file

@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo_root"
export PATH="$HOME/.local/share/nvim/mason/bin:$PATH"
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
printf 'Required validation tool not found: %s\n' "$1" >&2
exit 1
}
}
for command in bash git nvim shellcheck shfmt starship stylua wezterm zsh; do
require_cmd "$command"
done
shell_files=(bin/dotfiles-apply-theme bin/check-dotfiles install/install.sh install/lib/*.sh)
git diff --check
bash -n "${shell_files[@]}"
zsh -n .zshrc
git config --file .gitconfig --list >/dev/null
shellcheck --exclude=SC1091 "${shell_files[@]}"
shfmt -d -i 2 -ci "${shell_files[@]}"
stylua --check .config/nvim
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
mkdir -p "$tmp/data/nvim"
ln -s "$HOME/.local/share/nvim/lazy" "$tmp/data/nvim/lazy"
HOME="$tmp/home" \
KANAGAWA_THEME=wave \
WEZTERM_FONT_SIZE=13 \
WEZTERM_WINDOW_OPACITY=.9 \
WEZTERM_TEXT_OPACITY=1 \
bin/dotfiles-apply-theme
STARSHIP_CONFIG="$repo_root/.config/starship/starship.toml" starship print-config >/dev/null
STARSHIP_CONFIG="$repo_root/.config/starship/starship-wave.toml" starship print-config >/dev/null
wezterm --config-file "$repo_root/.config/wezterm/wezterm.lua" show-keys --lua >/dev/null
nvim_output="$(
DOTFILES_CI=1 \
XDG_CONFIG_HOME="$repo_root/.config" \
XDG_CACHE_HOME="$tmp/cache" \
XDG_DATA_HOME="$tmp/data" \
XDG_STATE_HOME="$tmp/state" \
nvim --headless '+sleep 100m' '+lua assert(vim.v.errmsg == "", vim.v.errmsg)' '+qa' 2>&1
)"
if [[ -n $nvim_output ]]; then
printf 'Neovim startup produced unexpected output:\n%s\n' "$nvim_output" >&2
exit 1
fi
printf 'All dotfile checks passed.\n'

46
bin/dotfiles-apply-theme Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -euo pipefail
theme="${KANAGAWA_THEME:-wave}"
font_size="${WEZTERM_FONT_SIZE:-13}"
window_opacity="${WEZTERM_WINDOW_OPACITY:-0.9}"
text_opacity="${WEZTERM_TEXT_OPACITY:-1.0}"
state_dir="$HOME/.cache/dotfiles"
case "$theme" in
wave | kanagawa-wave) theme=wave ;;
dragon | kanagawa-dragon) theme=dragon ;;
*) theme=dragon ;;
esac
for value in "$font_size" "$window_opacity" "$text_opacity"; do
[[ $value =~ ^([0-9]+([.][0-9]*)?|[.][0-9]+)$ ]] || {
printf 'Invalid numeric theme value: %s\n' "$value" >&2
exit 1
}
done
mkdir -p "$state_dir"
write_if_changed() {
local destination="$1" content="$2" temporary
if [[ -f $destination ]] && [[ $(<"$destination") == "$content" ]]; then
return
fi
temporary="$(mktemp "$state_dir/.theme.XXXXXX")"
printf '%s\n' "$content" >"$temporary"
mv "$temporary" "$destination"
}
write_if_changed "$state_dir/tmux-theme.conf" \
"source-file \"$HOME/.config/tmux/$theme-theme.conf\""
write_if_changed "$state_dir/wezterm-env.lua" "return {
theme = \"$theme\",
font_size = $font_size,
window_opacity = $window_opacity,
text_opacity = $text_opacity,
}"

259
docs/ideavimrc.md Normal file
View file

@ -0,0 +1,259 @@
# Neovim → IdeaVim Migration Reference
This document maps the Neovim configuration in `.config/nvim/lua/brian/` to
the IdeaVim configuration at `.config/.ideavimrc`.
---
## Required Setup
### 1. Install IdeaVim
Available in every JetBrains IDE under **Settings → Plugins → Marketplace**.
Search for `IdeaVim`.
### 2. Symlink `.ideavimrc`
IdeaVim reads `~/.ideavimrc` by default:
```sh
ln -sf ~/dotfiles/.config/.ideavimrc ~/.ideavimrc
```
### 3. Optional Marketplace plugins
| Plugin | Purpose | Enable with |
|---|---|---|
| `IdeaVim-Which-Key` | Which-key popup for leader mappings | `set which-key` |
| `IdeaVim-EasyMotion` | `s`/`S` jump motions (like `hop.nvim`) | `set easymotion` |
Both are commented out in `.ideavimrc` by default. Uncomment after installing.
---
## Known Constraints
### Use :action syntax, not <Action>()
IdeaVim supports two syntaxes for invoking IDE actions from mappings:
```vim
nnoremap gd <Action>(GotoDeclaration) " can silently fail
nnoremap gd :action GotoDeclaration<CR> " always works
```
When `<Action>()` fails to parse (version mismatch, parse error earlier in the
file), IdeaVim executes the RHS as literal vim keystrokes. For `GotoDeclaration`
this means `(` moves sentence, `G` goes to last line, `o` opens insert mode,
then `toDeclaration)` gets typed into the buffer. Always use `:action` syntax.
### sethandler must be at the top level
`sethandler` directives tell IdeaVim to intercept a key before the IDE does.
They **must appear at the top of `.ideavimrc`**, outside any `if` block.
Placing them inside `if has('ide')` causes IdeaVim to parse them in the wrong
phase, resulting in the IDE randomly stealing the key mid-session.
```vim
" CORRECT — top level, before any mappings
sethandler <C-h> a:vim
sethandler <C-l> a:vim
```
### No if has('ide') needed in .ideavimrc
`.ideavimrc` is only ever loaded by IdeaVim, never by regular Vim/Neovim.
The `if has('ide')` guard is only needed in a shared `.vimrc`. Using it here
causes `sethandler` and other directives to break.
### Options not supported by IdeaVim
IdeaVim does not implement all Vim options. The IDE controls indentation
settings under **Settings → Editor → Code Style**. These will throw `E518`
and must not appear in `.ideavimrc`:
- `shiftwidth`
- `tabstop`
- `softtabstop`
- `expandtab`
- `smartindent`
- `autoindent`
### Do not map Tab to NextTab
In terminal, `<Tab>` and `<C-i>` are the same keycode. Mapping `<Tab>` in
normal mode breaks jumplist-forward navigation (`<C-i>`) and conflicts with
IDE completion popups. Use `gt` / `gT` instead — IdeaVim supports these
natively for next/previous tab without any mapping.
### which-key requires a separate install
`set which-key` throws `E518: Unknown option` unless the **IdeaVim-Which-Key**
plugin is installed from the Marketplace. It is commented out by default.
---
## Plugin Emulation
IdeaVim ships with emulation for several popular Vim plugins. Enable them with
`set <name>` at the top level of `.ideavimrc`.
| Neovim plugin | IdeaVim equivalent | Status |
|---|---|---|
| `nvim-surround` | `set surround` | enabled |
| `vim-commentary` | `set commentary` | enabled |
| `which-key.nvim` | `set which-key` | commented out — install IdeaVim-Which-Key first |
| `vim-matchit` | `set matchit` | enabled |
| `argtextobj.vim` | `set argtextobj` | enabled |
| highlighted yank | `set highlightedyank` | enabled |
| `nvim-tree` | `set NERDTree` | enabled (see Navigation) |
| `hop.nvim` / sneak | `set easymotion` | commented out — install IdeaVim-EasyMotion first |
---
## What the IDE Replaces Natively
These Neovim plugins have **no IdeaVim equivalent** — the IDE provides the
functionality out of the box without any configuration.
| Neovim plugin | IDE equivalent |
|---|---|
| `nvim-lspconfig` / `mason.nvim` | JetBrains built-in language support |
| `blink-cmp` | JetBrains built-in completion |
| `nvim-treesitter` | JetBrains semantic highlighting |
| `bufferline.nvim` | JetBrains editor tab bar (configure under Settings → Editor → General → Editor Tabs) |
| `lualine.nvim` | JetBrains status bar |
| `lazygit.nvim` | Git tool window (`<leader>lg`) |
| `neotest` | JetBrains test runner (green gutter icons) |
| `nvim-dap` | JetBrains built-in debugger |
| `noice.nvim` | No equivalent — IDE owns all UI chrome |
| `render-markdown` | Markdown preview plugin |
| `nvim-colorizer` | No equivalent |
| `vim-tmux-navigator` | Not applicable |
---
## Navigation: NvimTree / C-h and C-l
In Neovim, `<C-h>` and `<C-l>` navigate between window splits, and NvimTree
is just another split. JetBrains uses a separate **tool window** for the
Project tree, which is not a vim split.
| Key | Neovim behaviour | IdeaVim behaviour |
|---|---|---|
| `<C-h>` | Focus split to the left (NvimTree) | Focus the Project tool window |
| `<C-l>` | Focus split to the right (editor) | `FocusEditor` — moves focus to the editor without opening or closing any panels. Note: this must also be bound natively in **Settings → Keymap** because IdeaVim is inactive when the Project tool window has focus. |
| `<leader>e` | `NvimTreeToggle` | `:NERDTree` (toggle the tree panel) |
`sethandler <C-h> a:vim` and `sethandler <C-l> a:vim` at the top of the file
are what make this reliable. Without them the IDE intercepts these keys
randomly depending on focus state.
For **editor split** navigation (vertical/horizontal splits inside the editor),
`<C-w>h/l/j/k` works natively in IdeaVim. `<C-j>` / `<C-k>` are mapped to
`<C-w>j` / `<C-w>k`.
---
## Keymap Reference
### File & Search (Telescope → JetBrains)
| Neovim mapping | Telescope picker | IdeaVim action |
|---|---|---|
| `<leader>sf` | `find_files` | `GotoFile` |
| `<leader><leader>` | `buffers` | `Switcher` |
| `<leader>sb` | `buffers` | `Switcher` |
| `<leader>sg` | `live_grep` | `FindInPath` |
| `<leader>so` | `oldfiles` | `RecentFiles` |
| `<leader>sds` | `lsp_document_symbols` | `FileStructurePopup` |
| `<leader>sw` | `grep_string` | `FindUsages` |
| `<leader>sd` | `diagnostics` | `ActivateProblemsViewToolWindow` |
| `<leader>sm` | `marks` | `ShowBookmarks` |
| `<leader>/` | `current_buffer_fuzzy_find` | `Find` (in-file search) |
### LSP (nvim-lspconfig → IDE actions)
| Neovim mapping | Description | IdeaVim action |
|---|---|---|
| `gd` | Go to definition | `GotoDeclaration` |
| `gD` | Go to declaration | `GotoDeclaration` |
| `gi` | Go to implementation | `GotoImplementation` |
| `gR` | References | `FindUsages` |
| `gt` | Go to type definition | `GotoTypeDeclaration` |
| `K` | Hover documentation | `QuickJavaDoc` |
| `<leader>ca` | Code actions | `ShowIntentionActions` |
| `<leader>rn` | Rename symbol | `RenameElement` |
| `<leader>df` | Line diagnostics | `ShowErrorDescription` |
| `<leader>D` | File diagnostics | `ActivateProblemsViewToolWindow` |
| `[d` | Previous diagnostic | `GotoPreviousError` |
| `]d` | Next diagnostic | `GotoNextError` |
### Buffers & Tabs
| Neovim mapping | Description | IdeaVim / note |
|---|---|---|
| `<Tab>` / `<S-Tab>` | Next/prev buffer | Use `gt` / `gT` — native, no mapping needed |
| `<leader>x` | Close buffer | `CloseContent` |
| `<leader>qt` | Close other buffers | `CloseAllEditorsButActive` |
### Window / Split Management
| Neovim mapping | Description | IdeaVim action |
|---|---|---|
| `<leader>v` | Vertical split | `SplitVertically` |
| `<leader>h` | Horizontal split | `SplitHorizontally` |
| `<leader>xs` | Close split | `Unsplit` |
| `<leader>se` | Toggle split orientation | `ChangeSplitOrientation` |
| `<C-j>` / `<C-k>` | Navigate splits | `<C-w>j` / `<C-w>k` |
### Git (lazygit + telescope git pickers)
| Neovim mapping | Description | IdeaVim action |
|---|---|---|
| `<leader>lg` | Open git UI | `ActivateVersionControlToolWindow` |
| `<leader>gc` | File history (commits) | `Vcs.ShowTabbedFileHistory` |
| `<leader>gcf` | Blame / annotate | `Annotate` |
| `<leader>gb` | Branches | `Git.Branches` |
| `<leader>gs` | Stash / shelf | `Vcs.Show.Shelf` |
### Angular File Switching
In Neovim, `angular_switch()` in `keymaps.lua` switches between `.ts`,
`.html`, `.scss`, and `.spec.ts` within a component. In JetBrains the
**Angular plugin** provides `GotoRelatedFile` which opens a popup listing all
related files. All four `<leader>o*` mappings point to the same action.
Requires the **Angular and AngularJS** JetBrains plugin to be installed.
| Neovim mapping | Target |
|---|---|
| `<leader>ot` | `.component.ts` |
| `<leader>oh` | `.component.html` |
| `<leader>oc` | `.component.scss` |
| `<leader>os` | `.component.spec.ts` |
### Pure-Vim Mappings (identical behaviour)
| Mapping | Description |
|---|---|
| `<Esc>` | Clear search highlight |
| `<C-d>` / `<C-u>` | Scroll half-page and center |
| `n` / `N` | Find next/prev and center |
| `x` / `dd` | Delete without yanking to register |
| `p` (visual) | Paste without overwriting yank register |
| `<A-j>` / `<A-k>` | Move line/selection up or down |
| `<leader>j` | Replace word under cursor (`*``cgn`) |
| `<leader>y` / `<leader>Y` | Yank to system clipboard |
| `<leader>gh` / `<leader>gl` | Jump to line start / end |
| `<leader>lw` | Toggle line wrap |
| `<leader>+` / `<leader>-` | Increment / decrement number |
| `<leader>st` | Sort selected lines (unique) |
| `<leader>~` | Toggle case of selection |
| `<C-s>` | Save all |
---
## Discovering Action IDs
To find the exact action ID for any IDE action:
1. Open **Help → Find Action** (`Cmd+Shift+A`) and search **Track Action IDs**.
2. Enable it — every action you invoke will print its ID in the status bar.
3. Search available actions from inside IdeaVim:
```vim
:actionlist GotoDeclaration
```

14
install/Brewfile Normal file
View file

@ -0,0 +1,14 @@
# CLI toolchain — always latest via `brew upgrade`.
brew "fzf"
brew "fd"
brew "bat"
brew "eza"
brew "zoxide"
brew "ripgrep"
brew "tmux"
brew "neovim"
brew "lazygit"
brew "starship"
brew "gh"
brew "zsh-syntax-highlighting"
brew "zsh-autosuggestions"

89
install/README.md Normal file
View file

@ -0,0 +1,89 @@
# Pop!_OS / Ubuntu install
A small, idempotent installer that gets a fresh Pop!_OS 24.04 (or any
Ubuntu 24.04 / Debian-derivative) to the state these dotfiles assume.
## Two-tier strategy
| Source | What lives there | Why |
|--------|------------------|-----|
| **apt** | `zsh`, `git`, `curl`, `build-essential`, `python3`, `python3-pip`, `python3-venv`, `luarocks`, `wl-clipboard`, `wezterm`, `brave-browser-beta` | System base, Mason prerequisites, and GUI vendor apps. Vendor apt repos auto-update Brave/WezTerm with `apt upgrade`. |
| **Homebrew** | `fzf` `fd` `bat` `eza` `zoxide` `ripgrep` `tmux` `neovim` `lazygit` `starship` `gh` `zsh-syntax-highlighting` `zsh-autosuggestions` | CLI toolchain. Ubuntu 24.04's apt versions are frozen at April 2024; brew always has latest. One `brew upgrade` updates all of them. |
| **nvm** | Node.js runtime | Installs the latest LTS release and sets it as the default; `.zshrc` sources `~/.nvm/nvm.sh`. |
| **tpm** | tmux plugin manager | Clone of `tmux-plugins/tpm` so the bundled `tmux.conf` works on first launch. |
Downloaded installer scripts, apt signing keys, and the Nerd Font archive
are pinned and verified before use. Updating their upstream versions requires
updating the corresponding SHA-256 hashes or fingerprints in `install/lib/`.
GitHub-release-binary downloads (the previous approach for nvim/lazygit/
starship) have been retired — they ran latest at install time then went
stale. Brew solves that.
## Environment required
- Pop!_OS 24.04 (or Debian/Ubuntu derivative) — preflight aborts if
`apt-get` is missing.
- A regular user with `sudo`**not** root.
- Outbound HTTPS to `apt.fury.io`, `brave.com`, `cli.github.com`,
`github.com`, `raw.githubusercontent.com`, and Ubuntu mirrors.
## Install
```bash
git clone https://github.com/brianpooe/dotfiles.git ~/dotfiles
~/dotfiles/install/install.sh
```
Then open a new terminal (or log out + back in) so the new login shell
takes effect.
### Flags
```bash
install/install.sh # full install
install/install.sh --packages-only # apt + brew + nvm + tpm, skip symlinks
install/install.sh --dotfiles-only # symlink + chsh + tpm + nvm, skip packages
install/install.sh --help
```
## Keeping current
```bash
update # alias: brew upgrade && sudo apt update && sudo apt upgrade -y
```
The CLI tools come from brew, so they stay on bleeding-edge stable. Brave
and WezTerm come from vendor apt repos so `apt upgrade` always has the
latest of those too.
## Layout
```
install/
install.sh entry point
Brewfile CLI toolchain bundle (brew owns these)
lib/common.sh helpers: apt_install, add_apt_repo, backup_and_link
lib/packages.sh apt base + WezTerm + Brave Beta vendor repos
lib/brew.sh install Homebrew + `brew bundle`
lib/extras.sh nvm + tpm
lib/fonts.sh verified JetBrainsMono Nerd Font install
lib/dotfiles.sh symlink dotfiles + chsh zsh
```
## What the installer does, in order
1. **preflight** — verify apt + not-root + sudo + curl.
2. **apt base** — system packages plus Mason's Python venv/pip and LuaRocks prerequisites.
3. **WezTerm apt repo**`apt install wezterm`.
4. **Brave Beta apt repo**`apt install brave-browser-beta`.
5. **Homebrew install** (NONINTERACTIVE) + `brew bundle` against `Brewfile`.
6. **nvm** (pinned `$NVM_VERSION`, default `v0.40.1`) + latest LTS Node.js.
7. **tpm** clone to `~/.tmux/plugins/tpm`.
8. **Symlink** `nvim tmux starship lazygit wezterm → ~/.config/...`;
`.config/.ideavimrc → ~/.ideavimrc`; `.zshrc`, `.gitconfig → ~`;
`dotfiles-apply-theme → ~/.local/bin/`.
9. **chsh** login shell to zsh.
Pre-existing config targets get backed up to `*.pre-install.<timestamp>`,
not deleted.

94
install/install.sh Executable file
View file

@ -0,0 +1,94 @@
#!/bin/bash
# Pop!_OS / Ubuntu installer for these dotfiles.
#
# What it does (idempotent — safe to re-run):
# 1. apt: system base + Mason prerequisites (Python venv/pip, LuaRocks).
# 2. Vendor apt repos: WezTerm, Brave Beta (GUI apps stay on apt).
# 3. Homebrew + Brewfile: fzf, fd, bat, eza, zoxide, ripgrep, tmux,
# neovim, lazygit, starship, gh, zsh plugins — always latest,
# updated later with a single `brew upgrade`.
# 4. nvm + latest LTS Node.js + tmux plugin manager (tpm).
# 5. Symlinks dotfiles into ~ and ~/.config.
# 6. Switches login shell to zsh.
#
# Usage:
# install/install.sh Full install
# install/install.sh --packages-only Only packages/tools (apt + brew)
# install/install.sh --dotfiles-only Only link dotfiles + tpm/nvm + chsh
# install/install.sh --unlink Remove symlinks pointing into this repo
# install/install.sh --help
set -eEo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/common.sh"
source "$SCRIPT_DIR/lib/packages.sh"
source "$SCRIPT_DIR/lib/brew.sh"
source "$SCRIPT_DIR/lib/extras.sh"
source "$SCRIPT_DIR/lib/fonts.sh"
source "$SCRIPT_DIR/lib/dotfiles.sh"
usage() {
sed -n '2,19p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
}
MODE=all
for arg in "$@"; do
case $arg in
--packages-only) MODE=packages ;;
--dotfiles-only) MODE=dotfiles ;;
--unlink) MODE="unlink" ;;
-h | --help)
usage
exit 0
;;
*) die "Unknown argument: $arg (try --help)" ;;
esac
done
preflight() {
command -v apt-get >/dev/null 2>&1 || die "apt-get not found — this installer targets Debian/Ubuntu/Pop!_OS."
((EUID != 0)) || die "Do not run as root; run as your regular user."
require_cmd sudo
require_cmd curl
require_cmd sha256sum
}
main() {
# Unlinking only removes symlinks; skip preflight and the closing hints.
if [[ $MODE == unlink ]]; then
unlink_dotfiles
return
fi
preflight
case $MODE in
packages)
install_all_packages
install_brew_packages
install_all_extras
install_nerd_font
;;
dotfiles)
link_dotfiles
install_tpm
install_nvm
set_zsh_as_shell
;;
all)
install_all_packages
install_brew_packages
install_all_extras
install_nerd_font
link_dotfiles
set_zsh_as_shell
;;
esac
info "Done. Open a new shell (or log out + back in) to pick up the new login shell."
info "First tmux launch: prefix + I to fetch tpm plugins."
info "Keep tools current with: brew upgrade && sudo apt update && sudo apt upgrade -y"
}
main

33
install/lib/brew.sh Normal file
View file

@ -0,0 +1,33 @@
#!/bin/bash
# Homebrew on Linux: install brew itself, then everything in the Brewfile.
# Brew owns the CLI toolchain so `brew upgrade` always gets latest versions.
BREW_PREFIX="/home/linuxbrew/.linuxbrew"
HOMEBREW_INSTALL_COMMIT="93a25fd2d2fdb86422303c292b9223f84ef23eaf"
HOMEBREW_INSTALL_SHA256="17f204b128869ec71e6b650051f1e65ef5b74cf994c2ff8b919103241554dd2f"
install_homebrew() {
if [[ -x $BREW_PREFIX/bin/brew ]]; then
info "Homebrew already installed"
else
info "Installing Homebrew..."
local installer
installer="$(mktemp)"
download_verified \
"https://raw.githubusercontent.com/Homebrew/install/$HOMEBREW_INSTALL_COMMIT/install.sh" \
"$HOMEBREW_INSTALL_SHA256" \
"$installer"
if ! NONINTERACTIVE=1 bash "$installer"; then
rm -f "$installer"
die "Homebrew installer failed"
fi
rm -f "$installer"
fi
eval "$("$BREW_PREFIX/bin/brew" shellenv)"
}
install_brew_packages() {
install_homebrew
info "Installing Brewfile bundle..."
brew bundle --file="$DOTFILES_DIR/install/Brewfile"
}

119
install/lib/common.sh Normal file
View file

@ -0,0 +1,119 @@
#!/bin/bash
# Shared helpers for the Pop!_OS / Ubuntu installer.
DOTFILES_DIR="${DOTFILES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
KEYRINGS_DIR="/etc/apt/keyrings"
APT_LISTS_DIR="/etc/apt/sources.list.d"
info() { printf '\033[0;32m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33mWARNING:\033[0m %s\n' "$*" >&2; }
error() { printf '\033[0;31mERROR:\033[0m %s\n' "$*" >&2; }
die() {
error "$*"
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"
}
download_verified() {
local url="$1" sha256="$2" destination="$3"
if ! curl -fsSL --retry 3 "$url" -o "$destination"; then
rm -f "$destination"
die "Failed to download $url"
fi
if ! printf '%s %s\n' "$sha256" "$destination" | sha256sum --check --status -; then
rm -f "$destination"
die "SHA-256 verification failed for $url"
fi
}
key_fingerprints_match() {
local key="$1" expected_fingerprints="$2"
local actual_fingerprints normalized_expected
actual_fingerprints="$(
gpg --show-keys --with-colons "$key" 2>/dev/null |
awk -F: '$1 == "fpr" { print $10 }' |
sort -u |
tr '\n' ' '
)"
normalized_expected="$(
for fingerprint in $expected_fingerprints; do
printf '%s\n' "$fingerprint"
done |
sort -u |
tr '\n' ' '
)"
[[ -n $actual_fingerprints && $actual_fingerprints == "$normalized_expected" ]]
}
apt_install() {
sudo apt-get install -y --no-install-recommends "$@"
}
apt_update_once() {
if [[ -z ${_APT_UPDATED:-} ]]; then
info "Refreshing apt indexes..."
sudo apt-get update -y
_APT_UPDATED=1
fi
}
# Symlink $1 -> $2, backing up any pre-existing real target first. Idempotent.
backup_and_link() {
local src="$1" dest="$2"
if [[ ! -e $src ]]; then
warn "Source missing, skipping link: $src"
return 0
fi
mkdir -p "$(dirname "$dest")"
if [[ -L $dest ]]; then
[[ "$(readlink "$dest")" == "$src" ]] && return 0
rm -f "$dest"
elif [[ -e $dest ]]; then
mv "$dest" "$dest.pre-install.$(date +%s)"
info "Backed up existing $dest"
fi
ln -sfn "$src" "$dest"
info "Linked $dest -> $src"
}
# Add a signed apt repo. Args: name keyring_url repo_line expected_fingerprints
add_apt_repo() {
local name="$1" keyring_url="$2" repo_line="$3" expected_fingerprints="$4"
local keyring="$KEYRINGS_DIR/$name.gpg"
local list="$APT_LISTS_DIR/$name.list"
if [[ -f $list && -s $keyring ]] &&
key_fingerprints_match "$keyring" "$expected_fingerprints"; then
return 0
fi
info "Adding apt repo: $name"
local tmp_key tmp_gpg
tmp_key="$(mktemp)"
tmp_gpg="$(mktemp)"
trap 'rm -f "$tmp_key" "$tmp_gpg"' RETURN
if ! curl -fsSL "$keyring_url" -o "$tmp_key"; then
die "Failed to download key for $name from $keyring_url"
fi
[[ -s $tmp_key ]] || die "Downloaded key for $name is empty"
key_fingerprints_match "$tmp_key" "$expected_fingerprints" ||
die "Signing-key fingerprint verification failed for $name"
if ! gpg --yes --dearmor -o "$tmp_gpg" <"$tmp_key" 2>/dev/null; then
# Already binary (.gpg) keys can't be dearmored; use the raw bytes instead.
cp "$tmp_key" "$tmp_gpg"
fi
sudo install -d -m 0755 "$KEYRINGS_DIR"
sudo install -m 0644 "$tmp_gpg" "$keyring"
echo "$repo_line" | sudo tee "$list" >/dev/null
unset _APT_UPDATED # force re-update so the new repo is seen
}

59
install/lib/dotfiles.sh Normal file
View file

@ -0,0 +1,59 @@
#!/bin/bash
# Symlink the dotfiles into ~ and ~/.config; switch login shell to zsh.
# Each entry: "<repo-relative source>|<absolute destination>".
# Drives both link_dotfiles and unlink_dotfiles — add new links here.
dotfile_links() {
cat <<EOF
.config/nvim|$HOME/.config/nvim
.config/tmux|$HOME/.config/tmux
.config/starship|$HOME/.config/starship
.config/lazygit|$HOME/.config/lazygit
.config/wezterm|$HOME/.config/wezterm
.config/bat|$HOME/.config/bat
.config/.ideavimrc|$HOME/.ideavimrc
.zshrc|$HOME/.zshrc
.gitconfig|$HOME/.gitconfig
.ssh/config|$HOME/.ssh/config
.claude/settings.json|$HOME/.claude/settings.json
bin/dotfiles-apply-theme|$HOME/.local/bin/dotfiles-apply-theme
EOF
}
link_dotfiles() {
info "Linking dotfiles from $DOTFILES_DIR..."
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
local entry
while IFS= read -r entry; do
backup_and_link "$DOTFILES_DIR/${entry%%|*}" "${entry#*|}"
done < <(dotfile_links)
}
unlink_dotfiles() {
info "Removing symlinks that point into $DOTFILES_DIR..."
local entry dest
while IFS= read -r entry; do
dest="${entry#*|}"
if [[ -L $dest && $(readlink "$dest") == "$DOTFILES_DIR"/* ]]; then
rm "$dest"
info "Unlinked $dest"
fi
done < <(dotfile_links)
info "Any .pre-install.* backups were left in place; restore them manually."
}
set_zsh_as_shell() {
local zsh_bin
zsh_bin="$(command -v zsh || true)"
[[ -n $zsh_bin ]] || {
warn "zsh not installed; skipping chsh"
return
}
if [[ $SHELL == "$zsh_bin" ]]; then
info "Login shell is already zsh"
return
fi
info "Changing login shell to $zsh_bin..."
sudo chsh -s "$zsh_bin" "$USER" || warn "chsh failed; run 'chsh -s $zsh_bin' manually"
}

45
install/lib/extras.sh Normal file
View file

@ -0,0 +1,45 @@
#!/bin/bash
# Per-user helpers not managed by brew: nvm (official installer) + tpm.
NVM_VERSION="${NVM_VERSION:-v0.40.5}"
NVM_INSTALL_SHA256="${NVM_INSTALL_SHA256:-582070e4c44452c1d8d68e16fc786c2216ecba6bc6bf18dc280a03fdba6ed1a9}"
install_nvm() {
if [[ -s $HOME/.nvm/nvm.sh ]]; then
info "nvm already installed"
else
info "Installing nvm ($NVM_VERSION)..."
local installer
installer="$(mktemp)"
download_verified \
"https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" \
"$NVM_INSTALL_SHA256" \
"$installer"
PROFILE=/dev/null bash "$installer" ||
warn "nvm install failed (install manually if you need Node)"
rm -f "$installer"
fi
if [[ -s $HOME/.nvm/nvm.sh ]]; then
# Mason needs npm for its Node-backed language servers and tools.
# Keep Node owned by nvm rather than installing the distro nodejs package.
source "$HOME/.nvm/nvm.sh"
nvm install --lts
nvm alias default 'lts/*'
fi
}
install_tpm() {
if [[ -d $HOME/.tmux/plugins/tpm ]]; then
info "tpm already installed"
return
fi
info "Installing tmux plugin manager..."
git clone --depth 1 https://github.com/tmux-plugins/tpm \
"$HOME/.tmux/plugins/tpm" || warn "tpm clone failed"
}
install_all_extras() {
install_nvm
install_tpm
}

30
install/lib/fonts.sh Normal file
View file

@ -0,0 +1,30 @@
#!/bin/bash
# Nerd Fonts — the configs (wezterm, starship, eza icons) assume
# "JetBrainsMono Nerd Font". Ubuntu's fonts-jetbrains-mono is the plain
# family without the Nerd glyphs, so install from the official release
# into ~/.local/share/fonts.
NERD_FONT_NAME="JetBrainsMono"
NERD_FONT_DIR="$HOME/.local/share/fonts/${NERD_FONT_NAME}NerdFont"
NERD_FONT_VERSION="v3.4.0"
NERD_FONT_SHA256="ef552a3e638f25125c6ad4c51176a6adcdce295ab1d2ffacf0db060caf8c1582"
install_nerd_font() {
if fc-list 2>/dev/null | grep -qi "JetBrainsMono Nerd Font"; then
info "JetBrainsMono Nerd Font already installed"
return
fi
info "Installing ${NERD_FONT_NAME} Nerd Font..."
local url="https://github.com/ryanoasis/nerd-fonts/releases/download/$NERD_FONT_VERSION/${NERD_FONT_NAME}.tar.xz"
local tmp
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' RETURN
download_verified "$url" "$NERD_FONT_SHA256" "$tmp/font.tar.xz"
mkdir -p "$NERD_FONT_DIR"
tar -xJf "$tmp/font.tar.xz" -C "$NERD_FONT_DIR"
fc-cache -f "$NERD_FONT_DIR"
info "Installed to $NERD_FONT_DIR"
}

73
install/lib/packages.sh Normal file
View file

@ -0,0 +1,73 @@
#!/bin/bash
# apt: system base + GUI apps from vendor repos (WezTerm, Brave Beta).
# All CLI tools come from Homebrew (lib/brew.sh) so they stay current.
APT_PACKAGES=(
# Login shell (system-level so chsh can point at /usr/bin/zsh)
zsh
# Core plumbing + Homebrew prerequisites
git
curl
wget
ca-certificates
gnupg
build-essential
procps
file
unzip
xz-utils
# Mason prerequisites for Python and Lua packages
python3
python3-pip
python3-venv
luarocks
# Wayland clipboard (Pop!_OS Cosmic is Wayland-native)
wl-clipboard
# fc-cache / fc-list for the Nerd Font install (lib/fonts.sh)
fontconfig
)
install_apt_packages() {
apt_update_once
info "Installing apt packages (${#APT_PACKAGES[@]} packages)..."
apt_install "${APT_PACKAGES[@]}"
}
install_wezterm() {
if command -v wezterm >/dev/null 2>&1; then
info "WezTerm already installed"
return
fi
add_apt_repo wezterm-fury \
https://apt.fury.io/wez/gpg.key \
"deb [signed-by=$KEYRINGS_DIR/wezterm-fury.gpg] https://apt.fury.io/wez/ * *" \
"0CA603116C960BAFB2BF310BD7BA31CF90C4B319 82FA179A44D70EEF9CDEB52659C703F427E1A6C9"
apt_update_once
apt_install wezterm
}
install_brave_beta() {
if command -v brave-browser-beta >/dev/null 2>&1; then
info "Brave Beta already installed"
return
fi
# Brave's Beta channel is signed with its own key (C3DE1DD4F661CDCB),
# NOT the stable keyring — the keyring file in the beta bucket includes
# "beta" in the name.
add_apt_repo brave-browser-beta \
https://brave-browser-apt-beta.s3.brave.com/brave-browser-beta-archive-keyring.gpg \
"deb [signed-by=$KEYRINGS_DIR/brave-browser-beta.gpg arch=amd64] https://brave-browser-apt-beta.s3.brave.com/ stable main" \
"56F49901AB19BAF099A95A76C3DE1DD4F661CDCB 8C1F16AB24DF8F75C1CF56595929A141E0E87F1F B721E073B7EF8E56ACC6B23ECBC67D2399225CCF"
apt_update_once
apt_install brave-browser-beta
}
install_all_packages() {
install_apt_packages
install_wezterm
install_brave_beta
}