diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 62458c7..859d9bf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -77,12 +77,12 @@ jobs: - name: Validate shell configurations run: | # Test zsh configuration syntax - zsh -n zshrc || echo "Warning: zshrc has syntax issues" + zsh -n home/zshrc || echo "Warning: zshrc has syntax issues" # Test bash configuration syntax - bash -n bash_profile || echo "Warning: bash_profile has syntax issues" + bash -n home/bash_profile || echo "Warning: bash_profile has syntax issues" - name: Validate git configuration run: | # Test git configuration - git config --file gitconfig --list > /dev/null + git config --file home/gitconfig --list > /dev/null diff --git a/.gitignore b/.gitignore index 7bfc503..9f87be4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,7 @@ logs/ # Vim/Neovim .viminfo .vim/view/* -nvim/lazy-lock.json +config/nvim/lazy-lock.json # Local generated editor state .omx/ @@ -62,4 +62,4 @@ private/ local/ # Tmux Plugin Manager installs plugin checkouts here; do not track nested repos. -tmux/plugins/ +config/tmux/plugins/ diff --git a/AGENTS.md b/AGENTS.md index 2bcd4aa..b6aae9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # Repository Guidelines ## Project Structure & Module Organization -This repository manages environment configuration through symlinks. Core shell and Git files at the repo root are linked into `~/.*`, and config directories such as `nvim/` and `ghostty/` are linked into `~/.config/`. Use `scripts/install-enhanced.sh` through the Makefile for validation, backup, and verbose installs. Editor config now lives entirely in `nvim/` for a Neovim-only setup. Automation scripts are in `scripts/`, tests in `tests/`, and Git hooks under `git/templates/hooks/`. +This repository manages environment configuration through symlinks. Home-level dotfiles and shell modules live under `home/`; selected files are linked into `~/.*`. Config directories such as `config/nvim/` and `config/ghostty/` are linked into `~/.config/`. Use `scripts/install-enhanced.sh` through the Makefile for validation, backup, and verbose installs. Editor config now lives entirely in `config/nvim/` for a Neovim-only setup. Automation scripts are in `scripts/`, tests in `tests/`, extended docs in `docs/`, and Git hooks under `home/git/templates/hooks/`. ## Build, Test, and Development Commands Main workflows: @@ -18,13 +18,13 @@ Main workflows: - `brew bundle --file=Brewfile`: installs the Homebrew-managed toolchain. ## Coding Style & Naming Conventions -Match the style of the file you edit instead of normalizing the repo. Shell scripts use Bash with `set -euo pipefail`, descriptive helper functions, and four-space indentation; Makefile recipes must stay tab-indented. Lua in `nvim/lua/` uses compact two-space indentation. Prefer kebab-case for scripts such as `install-enhanced.sh`, and keep test files in the `test_*.bats` pattern. Run `make lint` before submitting shell changes. +Match the style of the file you edit instead of normalizing the repo. Shell scripts use Bash with `set -euo pipefail`, descriptive helper functions, and four-space indentation; Makefile recipes must stay tab-indented. Lua in `config/nvim/lua/` uses compact two-space indentation. Prefer kebab-case for scripts such as `install-enhanced.sh`, and keep test files in the `test_*.bats` pattern. Run `make lint` before submitting shell changes. ## Testing Guidelines -Primary coverage is in `tests/test_dotfiles.bats`, which checks script syntax, install validation, Git config parsing, and Neovim migration expectations. Add or update Bats tests whenever install behavior or validation logic changes. Before opening a PR, run `make check`; for focused work, use `bats tests/test_dotfiles.bats`, `git config --file gitconfig --list`, and `zsh -n zshrc`. +Primary coverage is in `tests/test_dotfiles.bats`, which checks script syntax, install validation, Git config parsing, and Neovim migration expectations. Add or update Bats tests whenever install behavior or validation logic changes. Before opening a PR, run `make check`; for focused work, use `bats tests/test_dotfiles.bats`, `git config --file home/gitconfig --list`, `zsh -n home/zshrc`, and `zsh -n home/zsh/*.zsh`. ## Commit & Pull Request Guidelines Recent history favors short, imperative commit subjects, with a scope prefix such as `docs:` when useful. Keep messages specific, for example: `docs: update install instructions` or `Force nvim to be the EDITOR.` PRs should explain the config change, list validation commands run, and note follow-up such as `brew bundle` or opening Neovim to install plugins. Include screenshots only for UI changes or documentation imagery. ## Security & Configuration Tips -Do not commit machine-specific secrets, tokens, or private paths unless they are already intentional repo conventions. Prefer environment variables for sensitive values and run `make security` after touching shell startup files, install scripts, or Git hooks. Installs create `~/.logs`, back up files under `~/.dotfiles-backup-*`, and link config directories such as `nvim/` and `ghostty/` into `~/.config/`. +Do not commit machine-specific secrets, tokens, or private paths unless they are already intentional repo conventions. Prefer environment variables for sensitive values and run `make security` after touching shell startup files, install scripts, or Git hooks. Installs create `~/.logs`, back up files under `~/.dotfiles-backup-*`, and link config directories such as `config/nvim/` and `config/ghostty/` into `~/.config/`. diff --git a/Brewfile b/Brewfile index fe45f5b..1191d17 100644 --- a/Brewfile +++ b/Brewfile @@ -76,8 +76,8 @@ brew "nmap" brew "no-more-secrets" brew "nodenv" brew "nvm" -brew "ollama" brew "oh-my-posh" +brew "ollama" brew "ripgrep" brew "opencode" brew "php" @@ -105,6 +105,7 @@ brew "solargraph" brew "speedtest-cli" brew "sqlc" brew "sslscan" +brew "subversion" brew "summarize" brew "swagger-codegen" brew "telnet" diff --git a/Makefile b/Makefile index b67db5f..508c187 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SHELL := /bin/bash INSTALL_SCRIPT := scripts/install-enhanced.sh TEST_SCRIPT := scripts/test-install.sh SECURITY_SCRIPT := scripts/security-check.sh -TMUX_OPEN_URL_SCRIPT := tmux/open-url.sh +TMUX_OPEN_URL_SCRIPT := config/tmux/open-url.sh SHELL_SCRIPTS := $(INSTALL_SCRIPT) $(TEST_SCRIPT) $(SECURITY_SCRIPT) $(TMUX_OPEN_URL_SCRIPT) BATS_TESTS := tests/test_dotfiles.bats diff --git a/README.md b/README.md index 238bda3..cc0e4cc 100644 --- a/README.md +++ b/README.md @@ -55,17 +55,22 @@ dotfiles/ ├── .github/workflows/ # CI/CD automation ├── scripts/ # Installation, test, and validation scripts ├── tests/ # Automated tests -├── aliases # Shell aliases -├── bash_profile # Bash configuration -├── exports # Environment variables -├── functions # Shell functions -├── git/ # Git templates and hooks -├── gitconfig # Git configuration -├── nvim/ # Neovim configuration -├── ohmyposh/ # Oh My Posh prompt themes -├── tmux/ # Tmux configuration -├── zsh/ # Modular Zsh configuration -├── zshrc # Zsh module loader +├── home/ # Files symlinked into ~/.* plus shell support +│ ├── aliases # Shell aliases +│ ├── bash_profile # Bash configuration +│ ├── exports # Environment variables +│ ├── functions # Shell functions +│ ├── git/ # Git templates and hooks +│ ├── gitconfig # Git configuration +│ ├── screenrc # GNU Screen configuration +│ ├── zsh/ # Modular Zsh configuration +│ └── zshrc # Zsh module loader +├── config/ # Directories symlinked into ~/.config/* +│ ├── ghostty/ # Ghostty terminal configuration +│ ├── nvim/ # Neovim configuration +│ ├── ohmyposh/ # Oh My Posh prompt themes +│ └── tmux/ # Tmux configuration +├── docs/ # Extended project documentation ├── Brewfile # Package management └── Makefile # Build automation ``` @@ -105,9 +110,9 @@ make check # Complete quality validation ./scripts/test-install.sh # Validate configurations -git config --file gitconfig --list -zsh -n zshrc -zsh -n zsh/*.zsh +git config --file home/gitconfig --list +zsh -n home/zshrc +zsh -n home/zsh/*.zsh ``` ## 📦 Requirements @@ -115,8 +120,8 @@ zsh -n zsh/*.zsh ### Essential - **Git**: Version control - **Zsh**: Modern shell -- **zinit**: Zsh plugin manager (bootstrapped automatically by `zsh/00-zinit.zsh`) -- **Oh My Posh**: Prompt engine using configs from `ohmyposh/` +- **zinit**: Zsh plugin manager (bootstrapped automatically by `home/zsh/00-zinit.zsh`) +- **Oh My Posh**: Prompt engine using configs from `config/ohmyposh/` - **Homebrew**: Package management (macOS) ### Optional @@ -141,18 +146,18 @@ brew bundle --file=Brewfile ## 🔄 Neovim-only editor setup This repository now uses **Neovim as the only tracked editor configuration**. -The active runtime lives under `nvim/`, with: +The active runtime lives under `config/nvim/`, with: -- `nvim/init.vim` as the thin entrypoint -- `nvim/lua/config/*` for general editor behavior -- `nvim/lua/plugins/*` for grouped lazy.nvim plugin specs -- `nvim/coc-settings.json` for CoC settings +- `config/nvim/init.vim` as the thin entrypoint +- `config/nvim/lua/config/*` for general editor behavior +- `config/nvim/lua/plugins/*` for grouped lazy.nvim plugin specs +- `config/nvim/coc-settings.json` for CoC settings Supporting Neovim docs: -- `nvim/README.md` — structure and ownership -- `nvim/PLUGIN_AUDIT.md` — current plugin inventory -- `nvim/PLUGIN_REEVALUATION.md` — keep/remove/replace decisions +- `docs/nvim/README.md` — structure and ownership +- `docs/nvim/PLUGIN_AUDIT.md` — current plugin inventory +- `docs/nvim/PLUGIN_REEVALUATION.md` — keep/remove/replace decisions ### Setup Neovim Plugins ```bash @@ -167,7 +172,7 @@ nvim -c "Lazy install" -c "qa" ## 🧩 Tmux plugin setup The installer bootstraps [TPM](https://github.com/tmux-plugins/tpm) into -`~/.config/tmux/plugins/tpm`. Other tmux plugins are declared in `tmux/tmux.conf` +`~/.config/tmux/plugins/tpm`. Other tmux plugins are declared in `config/tmux/tmux.conf` and installed by TPM. ```bash @@ -182,7 +187,7 @@ tmux source-file ~/.config/tmux/tmux.conf - Asynchronous processing - Modern architecture - Lua configuration support -- No split ownership between `nvim/` and legacy Vim files +- No split ownership between `config/nvim/` and legacy Vim files ## 🏗️ CI/CD & Automation @@ -212,7 +217,7 @@ fi ``` ### Adding New Configurations -1. Add the file to the repository +1. Add home-level dotfiles under `home/`, or XDG config directories under `config/` 2. Update `HOME_FILES` or `CONFIG_FILES` in `scripts/install-enhanced.sh` 3. Test with `make test` 4. Document any dependencies @@ -287,7 +292,7 @@ make install exec zsh ``` -The zinit bootstrap in `zsh/00-zinit.zsh` installs zinit into +The zinit bootstrap in `home/zsh/00-zinit.zsh` installs zinit into `${XDG_DATA_HOME:-$HOME/.local/share}/zinit/zinit.git` on first shell startup. ### Getting Help @@ -337,4 +342,4 @@ MIT License - see [LICENSE](LICENSE) file for details. --- -For the current improvement backlog, see [DEVOPS_RECOMMENDATIONS.md](DEVOPS_RECOMMENDATIONS.md). +For the current improvement backlog, see [docs/DEVOPS_RECOMMENDATIONS.md](docs/DEVOPS_RECOMMENDATIONS.md). diff --git a/ghostty/config b/config/ghostty/config similarity index 100% rename from ghostty/config rename to config/ghostty/config diff --git a/ghostty/themes/catppuccin-frappe b/config/ghostty/themes/catppuccin-frappe similarity index 100% rename from ghostty/themes/catppuccin-frappe rename to config/ghostty/themes/catppuccin-frappe diff --git a/ghostty/themes/catppuccin-latte b/config/ghostty/themes/catppuccin-latte similarity index 100% rename from ghostty/themes/catppuccin-latte rename to config/ghostty/themes/catppuccin-latte diff --git a/ghostty/themes/catppuccin-macchiato b/config/ghostty/themes/catppuccin-macchiato similarity index 100% rename from ghostty/themes/catppuccin-macchiato rename to config/ghostty/themes/catppuccin-macchiato diff --git a/ghostty/themes/catppuccin-mocha b/config/ghostty/themes/catppuccin-mocha similarity index 100% rename from ghostty/themes/catppuccin-mocha rename to config/ghostty/themes/catppuccin-mocha diff --git a/nvim/coc-settings.json b/config/nvim/coc-settings.json similarity index 100% rename from nvim/coc-settings.json rename to config/nvim/coc-settings.json diff --git a/nvim/init.vim b/config/nvim/init.vim similarity index 100% rename from nvim/init.vim rename to config/nvim/init.vim diff --git a/nvim/lua/config/autocmds.lua b/config/nvim/lua/config/autocmds.lua similarity index 100% rename from nvim/lua/config/autocmds.lua rename to config/nvim/lua/config/autocmds.lua diff --git a/nvim/lua/config/commands.lua b/config/nvim/lua/config/commands.lua similarity index 100% rename from nvim/lua/config/commands.lua rename to config/nvim/lua/config/commands.lua diff --git a/nvim/lua/config/keymaps.lua b/config/nvim/lua/config/keymaps.lua similarity index 100% rename from nvim/lua/config/keymaps.lua rename to config/nvim/lua/config/keymaps.lua diff --git a/nvim/lua/config/options.lua b/config/nvim/lua/config/options.lua similarity index 100% rename from nvim/lua/config/options.lua rename to config/nvim/lua/config/options.lua diff --git a/nvim/lua/config/personal.lua b/config/nvim/lua/config/personal.lua similarity index 100% rename from nvim/lua/config/personal.lua rename to config/nvim/lua/config/personal.lua diff --git a/nvim/lua/config/project-root.lua b/config/nvim/lua/config/project-root.lua similarity index 100% rename from nvim/lua/config/project-root.lua rename to config/nvim/lua/config/project-root.lua diff --git a/nvim/lua/config/showpopup.lua b/config/nvim/lua/config/showpopup.lua similarity index 100% rename from nvim/lua/config/showpopup.lua rename to config/nvim/lua/config/showpopup.lua diff --git a/nvim/lua/lazy-init.lua b/config/nvim/lua/lazy-init.lua similarity index 100% rename from nvim/lua/lazy-init.lua rename to config/nvim/lua/lazy-init.lua diff --git a/nvim/lua/plugins/ai.lua b/config/nvim/lua/plugins/ai.lua similarity index 100% rename from nvim/lua/plugins/ai.lua rename to config/nvim/lua/plugins/ai.lua diff --git a/nvim/lua/plugins/editing.lua b/config/nvim/lua/plugins/editing.lua similarity index 100% rename from nvim/lua/plugins/editing.lua rename to config/nvim/lua/plugins/editing.lua diff --git a/nvim/lua/plugins/git.lua b/config/nvim/lua/plugins/git.lua similarity index 100% rename from nvim/lua/plugins/git.lua rename to config/nvim/lua/plugins/git.lua diff --git a/nvim/lua/plugins/init.lua b/config/nvim/lua/plugins/init.lua similarity index 100% rename from nvim/lua/plugins/init.lua rename to config/nvim/lua/plugins/init.lua diff --git a/nvim/lua/plugins/lsp.lua b/config/nvim/lua/plugins/lsp.lua similarity index 100% rename from nvim/lua/plugins/lsp.lua rename to config/nvim/lua/plugins/lsp.lua diff --git a/nvim/lua/plugins/navigation.lua b/config/nvim/lua/plugins/navigation.lua similarity index 100% rename from nvim/lua/plugins/navigation.lua rename to config/nvim/lua/plugins/navigation.lua diff --git a/nvim/lua/plugins/tools.lua b/config/nvim/lua/plugins/tools.lua similarity index 100% rename from nvim/lua/plugins/tools.lua rename to config/nvim/lua/plugins/tools.lua diff --git a/nvim/lua/plugins/ui.lua b/config/nvim/lua/plugins/ui.lua similarity index 100% rename from nvim/lua/plugins/ui.lua rename to config/nvim/lua/plugins/ui.lua diff --git a/ohmyposh/default.toml b/config/ohmyposh/default.toml similarity index 100% rename from ohmyposh/default.toml rename to config/ohmyposh/default.toml diff --git a/ohmyposh/zen.toml b/config/ohmyposh/zen.toml similarity index 100% rename from ohmyposh/zen.toml rename to config/ohmyposh/zen.toml diff --git a/tmux/open-url.sh b/config/tmux/open-url.sh similarity index 100% rename from tmux/open-url.sh rename to config/tmux/open-url.sh diff --git a/tmux/tmux.conf b/config/tmux/tmux.conf similarity index 100% rename from tmux/tmux.conf rename to config/tmux/tmux.conf diff --git a/DEVOPS_RECOMMENDATIONS.md b/docs/DEVOPS_RECOMMENDATIONS.md similarity index 93% rename from DEVOPS_RECOMMENDATIONS.md rename to docs/DEVOPS_RECOMMENDATIONS.md index 45edd91..979bf47 100644 --- a/DEVOPS_RECOMMENDATIONS.md +++ b/docs/DEVOPS_RECOMMENDATIONS.md @@ -9,11 +9,11 @@ and Ubuntu. The remaining work should stay incremental and test-backed. - `make check` runs lint, security checks, installation tests, and Bats tests. - `scripts/install-enhanced.sh` validates, backs up, links home files, links config directories, and bootstraps TPM when enabled. -- `zshrc` is a thin loader for `zsh/*.zsh` modules. +- `home/zshrc` is a thin loader for `home/zsh/*.zsh` modules. - Zsh plugins are managed by zinit; the prompt is managed by Oh My Posh from - `ohmyposh/`. + `config/ohmyposh/`. - Neovim is the only tracked editor runtime and uses lazy.nvim modules. -- Tmux and Ghostty configs are tracked under `~/.config/` symlink targets. +- Tmux and Ghostty config sources live under `config/` and are linked to `~/.config/` targets. ## Recommended Next Improvements @@ -49,7 +49,7 @@ package. failures can otherwise be hard to diagnose. **Plan:** -1. Add a lightweight `zsh/README.md` documenting module order and ownership. +1. Add a lightweight `docs/zsh.md` documenting module order and ownership. 2. Add a `make doctor-shell` target or script that checks zinit, Oh My Posh, fzf, zoxide, and linked config paths. 3. Keep shell startup quiet; put diagnostics in explicit doctor commands. diff --git a/IMPLEMENTATION_SUMMARY.md b/docs/IMPLEMENTATION_SUMMARY.md similarity index 68% rename from IMPLEMENTATION_SUMMARY.md rename to docs/IMPLEMENTATION_SUMMARY.md index 6ccdfa3..5732ea6 100644 --- a/IMPLEMENTATION_SUMMARY.md +++ b/docs/IMPLEMENTATION_SUMMARY.md @@ -9,24 +9,24 @@ contracts. ## Shell -- `zshrc` is a thin entrypoint that loads `zsh/*.zsh` in lexical order. -- `zsh/00-zinit.zsh` bootstraps zinit, loads Zsh plugins/snippets, and initializes +- `home/zshrc` is a thin entrypoint that loads `home/zsh/*.zsh` in lexical order. +- `home/zsh/00-zinit.zsh` bootstraps zinit, loads Zsh plugins/snippets, and initializes Oh My Posh when available. -- `ohmyposh/` contains tracked prompt themes linked to `~/.config/ohmyposh`. -- Shared aliases, exports, and functions are sourced from `zsh/10-shared-shell.zsh`. +- `config/ohmyposh/` contains tracked prompt themes linked to `~/.config/ohmyposh`. +- Shared aliases, exports, and functions are sourced from `home/zsh/10-shared-shell.zsh`. ## Editor - Neovim is the only tracked editor configuration. -- `nvim/init.vim` delegates behavior to Lua modules under `nvim/lua/config` and - plugin specs under `nvim/lua/plugins`. +- `config/nvim/init.vim` delegates behavior to Lua modules under `config/nvim/lua/config` and + plugin specs under `config/nvim/lua/plugins`. - lazy.nvim owns plugin management. ## Terminal -- `tmux/` is linked to `~/.config/tmux`. +- `config/tmux/` is linked to `~/.config/tmux`. - The installer can bootstrap TPM unless `DOTFILES_SKIP_TPM_BOOTSTRAP` is set. -- `ghostty/` is linked to `~/.config/ghostty`. +- `config/ghostty/` is linked to `~/.config/ghostty`. ## Automation @@ -49,10 +49,10 @@ make check Useful focused checks: ```bash -zsh -n zshrc -zsh -n zsh/*.zsh -git config --file gitconfig --list -oh-my-posh init zsh --config ohmyposh/zen.toml +zsh -n home/zshrc +zsh -n home/zsh/*.zsh +git config --file home/gitconfig --list +oh-my-posh init zsh --config config/ohmyposh/zen.toml ``` ## Known Tradeoffs diff --git a/brews.md b/docs/brews.md similarity index 100% rename from brews.md rename to docs/brews.md diff --git a/docs/nvim/PLUGIN_AUDIT.md b/docs/nvim/PLUGIN_AUDIT.md new file mode 100644 index 0000000..d470304 --- /dev/null +++ b/docs/nvim/PLUGIN_AUDIT.md @@ -0,0 +1,91 @@ +# Neovim plugin audit + +## Scope + +This document describes the **current Neovim-only plugin/runtime structure**. + +Primary sources: +- `config/nvim/init.vim` +- `config/nvim/coc-settings.json` +- `config/nvim/lua/lazy-init.lua` +- `config/nvim/lua/plugins/*.lua` +- `config/nvim/lua/config/*.lua` + +## Current runtime path + +1. `config/nvim/init.vim` is a thin Neovim entrypoint. +2. `config/nvim/init.vim` boots `lazy.nvim` through `require('lazy-init')`. +3. `config/nvim/lua/lazy-init.lua` loads grouped specs from `config/nvim/lua/plugins/init.lua`. +4. General Neovim behavior is owned by Lua config modules: + - `config/nvim/lua/config/options.lua` + - `config/nvim/lua/config/keymaps.lua` + - `config/nvim/lua/config/commands.lua` + - `config/nvim/lua/config/autocmds.lua` + - `config/nvim/lua/config/personal.lua` +5. CoC JSON settings live in `config/nvim/coc-settings.json`. + +## High-level findings + +- **Neovim is self-contained under `config/nvim/`.** +- **Plugin specs are grouped by responsibility.** +- **The main preserved UX boundary is CoC, not legacy file structure.** +- **The old classic Vim compatibility tree has been removed from the active repo layout.** +- **The remaining cleanup opportunities are plugin/product decisions, not structural ownership problems.** + +## Current plugin ownership inventory + +| Plugin | Current Neovim owner | Hooks / behavior | Recommendation | Migration risk | Notes | +|---|---|---|---|---|---| +| `nvim-lua/plenary.nvim` | dependency in grouped plugin modules | dependency only | Keep | Low | Shared Lua dependency. | +| `AndrewRadev/splitjoin.vim` | `config/nvim/lua/plugins/editing.lua` | default plugin behavior | Keep | Low | No active structure problem. | +| `tpope/vim-surround` | `config/nvim/lua/plugins/editing.lua` | default mappings | Keep | Low | Stable, low-maintenance. | +| `tpope/vim-commentary` | `config/nvim/lua/plugins/editing.lua` | default mappings | Keep | Low | Stable, low-maintenance. | +| `tpope/vim-repeat` | `config/nvim/lua/plugins/editing.lua` | implicit repeat support | Keep | Low | Companion plugin. | +| `Konfekt/FastFold` | `config/nvim/lua/plugins/editing.lua` | fold behavior | Keep | Low | No current pressure to replace. | +| `lukas-reineke/indent-blankline.nvim` | `config/nvim/lua/plugins/ui.lua` | visual indent guides | Keep | Low | Lua-native indent guide plugin using the `ibl` entrypoint. | +| native root detection | `config/nvim/lua/config/project-root.lua` | project root detection via `vim.fs.root()` | Keep | Low | Plugin removed; behavior is handled with built-in Neovim APIs. | +| `stevearc/aerial.nvim` | `config/nvim/lua/plugins/navigation.lua` | `Aerial*` commands, `` | Keep | Medium | Modern outline workflow with the familiar toggle key preserved. | +| `nvim-telescope/telescope.nvim` | `config/nvim/lua/plugins/navigation.lua` | `:Telescope`, ui-select integration | Keep | Low | Modern, Lua-native. | +| `nvim-telescope/telescope-ui-select.nvim` | dependency in `navigation.lua` | UI select extension | Keep | Low | Owned with Telescope. | +| `tpope/vim-fugitive` | `config/nvim/lua/plugins/git.lua` | `:Git`, `:Gdiffsplit`, etc. | Keep | Low | Clear command-scoped tool. | +| `nvim-lualine/lualine.nvim` | `config/nvim/lua/plugins/ui.lua` | statusline/tabline | Keep | Low | Lua-native statusline/tabline using an evil_lualine-inspired layout with CoC-aware diagnostics/status. | +| `nvim-treesitter/nvim-treesitter` | `config/nvim/lua/plugins/ui.lua` | syntax highlighting | Keep | Low | Modern plugin, already colocated. | +| `neoclide/coc.nvim` | `config/nvim/lua/plugins/lsp.lua` plus `config/nvim/coc-settings.json` | completion, navigation, explorer, diagnostics, lists | Keep now | High | UX is preserved; future replacement should be parity-driven. | +| `github/copilot.vim` | `config/nvim/lua/plugins/ai.lua` | `` accept, tab-map disable | Keep | Medium | Config and mapping are active and colocated. | +| `CopilotC-Nvim/CopilotChat.nvim` | `config/nvim/lua/plugins/ai.lua` | `cc`, `cs` | Keep | Medium | Config and keymaps are colocated. | +| `greggh/claude-code.nvim` | `config/nvim/lua/plugins/ai.lua` | ``, `cC`, `cV` | Keep | Low | Modern plugin, config colocated. | +| `rizzatti/dash.vim` | `config/nvim/lua/plugins/tools.lua` | `:Dash*` commands | Keep | Low | Command-based utility. | +| `aquach/vim-http-client` | `config/nvim/lua/plugins/tools.lua` | filetype workflow | Keep | Low | No immediate change needed. | +| `vitapluvia/vim-gurl` | `config/nvim/lua/plugins/tools.lua` | `gr` | Keep | Low | Keymap is colocated with the plugin. | +| `skywind3000/asyncrun.vim` | `config/nvim/lua/plugins/tools.lua` | async command workflow | Keep | Low | No immediate change needed. | +| `ravitemer/mcphub.nvim` | `config/nvim/lua/plugins/tools.lua` | `:MCPHub` | Keep | Low | Large config now lives in the correct module. | + +## Completed migration outcomes + +### General Neovim config owned in Lua +- options and editor defaults: `config/nvim/lua/config/options.lua` +- general keymaps: `config/nvim/lua/config/keymaps.lua` +- user commands including `FormatJSON` and `WP`: `config/nvim/lua/config/commands.lua` +- reload autocmd: `config/nvim/lua/config/autocmds.lua` +- popup/personal helpers: `config/nvim/lua/config/personal.lua` + +### Plugin-owned behavior colocated +- root detection: `config/nvim/lua/config/project-root.lua` +- Aerial outline binding: `config/nvim/lua/plugins/navigation.lua` +- lualine statusline/tabline config: `config/nvim/lua/plugins/ui.lua` +- CoC globals, mappings, commands, and autocmds: `config/nvim/lua/plugins/lsp.lua` +- Copilot/CopilotChat bindings: `config/nvim/lua/plugins/ai.lua` +- Gurl keymap: `config/nvim/lua/plugins/tools.lua` + +## Remaining review targets + +These are product/maintenance decisions, not structural problems: + +1. Telescope overlap/extensions strategy +2. CoC replacement only when a parity-first migration plan exists + +## Recommended next moves + +1. Consider a later replacement plan for: + - eventually CoC, only if parity is documented first +2. Reduce headless verification noise by separating plugin bootstrap/install checks from config-structure checks. diff --git a/nvim/PLUGIN_REEVALUATION.md b/docs/nvim/PLUGIN_REEVALUATION.md similarity index 92% rename from nvim/PLUGIN_REEVALUATION.md rename to docs/nvim/PLUGIN_REEVALUATION.md index f1bfe10..540dcad 100644 --- a/nvim/PLUGIN_REEVALUATION.md +++ b/docs/nvim/PLUGIN_REEVALUATION.md @@ -10,7 +10,7 @@ Neovim-only setup. It classifies plugins into: - revisit later It is based on: -- current repo usage and keymaps under `nvim/lua/plugins/*` +- current repo usage and keymaps under `config/nvim/lua/plugins/*` - current test expectations in `tests/test_dotfiles.bats` - primary-source plugin/documentation review for replacement candidates @@ -120,7 +120,7 @@ It is based on: - Aerial describes itself as a code outline window for skimming and quick navigation, with Neovim 0.11+ support and integrations with Telescope, fzf, and Lualine. **Implemented replacement** -- `nvim/lua/plugins/navigation.lua` +- `config/nvim/lua/plugins/navigation.lua` - `AerialToggle!` on `` **Risk**: medium @@ -151,14 +151,14 @@ It is based on: ### 6. `dylanaraps/root.vim` — replaced with native Neovim **Why it was replaced** -- Root detection is now handled in `nvim/lua/config/project-root.lua`. +- Root detection is now handled in `config/nvim/lua/config/project-root.lua`. **Why replace** - This is a narrow behavior area that Neovim can now handle natively. - Native root detection would reduce plugin count. **Implemented replacement** -- `nvim/lua/config/project-root.lua` +- `config/nvim/lua/config/project-root.lua` - buffer-local root detection driven by `vim.fs.root()` **Primary-source note** @@ -169,7 +169,7 @@ It is based on: ### 7. `coc.nvim` — keep for now **Current repo evidence** -- Deeply integrated in `nvim/lua/plugins/lsp.lua` +- Deeply integrated in `config/nvim/lua/plugins/lsp.lua` - Current UX preference is explicitly CoC-style **Why keep** @@ -195,9 +195,9 @@ Primary sources reviewed: - Neovim Lua docs (`vim.fs.root()`): https://neovim.io/doc/user/lua.html Repo-local evidence: -- `nvim/lua/plugins/navigation.lua` -- `nvim/lua/plugins/ui.lua` -- `nvim/lua/plugins/lsp.lua` -- `nvim/lua/plugins/ai.lua` -- `nvim/lua/plugins/tools.lua` +- `config/nvim/lua/plugins/navigation.lua` +- `config/nvim/lua/plugins/ui.lua` +- `config/nvim/lua/plugins/lsp.lua` +- `config/nvim/lua/plugins/ai.lua` +- `config/nvim/lua/plugins/tools.lua` - `tests/test_dotfiles.bats` diff --git a/nvim/README.md b/docs/nvim/README.md similarity index 75% rename from nvim/README.md rename to docs/nvim/README.md index ca6b2b3..7ead2c2 100644 --- a/nvim/README.md +++ b/docs/nvim/README.md @@ -1,11 +1,11 @@ # Neovim configuration -This Neovim setup uses `lazy.nvim` as the plugin manager and treats `nvim/` as the source of truth for Neovim runtime behavior. +This Neovim setup uses `lazy.nvim` as the plugin manager and treats `config/nvim/` as the source of truth for Neovim runtime behavior. ## Current structure ```text -nvim/ +config/nvim/ ├── coc-settings.json ├── init.vim ├── lazy-lock.json @@ -34,15 +34,15 @@ nvim/ ## Ownership model -- `nvim/init.vim` is a thin Neovim entrypoint. -- `nvim/lua/config/*` owns general Neovim behavior: +- `config/nvim/init.vim` is a thin Neovim entrypoint. +- `config/nvim/lua/config/*` owns general Neovim behavior: - options - keymaps - commands - autocmds - personal popup helpers -- `nvim/lua/config/project-root.lua` owns built-in project root detection. -- `nvim/lua/plugins/*` owns plugin declarations and Neovim-side plugin configuration. +- `config/nvim/lua/config/project-root.lua` owns built-in project root detection. +- `config/nvim/lua/plugins/*` owns plugin declarations and Neovim-side plugin configuration. ## Plugin organization @@ -59,7 +59,7 @@ Current grouped plugin modules: ## CoC and statusline - Neovim still uses `coc.nvim` and the existing CoC-style UX. -- CoC JSON settings live in `nvim/coc-settings.json`. +- CoC JSON settings live in `config/nvim/coc-settings.json`. - `lualine.nvim` owns the statusline/tabline with an evil_lualine-inspired layout. - A Nerd Font such as Hack Nerd Font is recommended if you want all glyphs to render cleanly. @@ -83,4 +83,4 @@ make lint 1. Open `:Lazy` to inspect plugin installation state. 2. Run `:checkhealth` for Neovim diagnostics. -3. Review `nvim/PLUGIN_AUDIT.md` and `nvim/PLUGIN_REEVALUATION.md` before replacing plugins or changing CoC-era UX. +3. Review `docs/nvim/PLUGIN_AUDIT.md` and `docs/nvim/PLUGIN_REEVALUATION.md` before replacing plugins or changing CoC-era UX. diff --git a/aliases b/home/aliases similarity index 100% rename from aliases rename to home/aliases diff --git a/bash_profile b/home/bash_profile similarity index 100% rename from bash_profile rename to home/bash_profile diff --git a/exports b/home/exports similarity index 100% rename from exports rename to home/exports diff --git a/functions b/home/functions similarity index 100% rename from functions rename to home/functions diff --git a/git/templates/hooks/pre-commit b/home/git/templates/hooks/pre-commit similarity index 100% rename from git/templates/hooks/pre-commit rename to home/git/templates/hooks/pre-commit diff --git a/gitconfig b/home/gitconfig similarity index 100% rename from gitconfig rename to home/gitconfig diff --git a/screenrc b/home/screenrc similarity index 100% rename from screenrc rename to home/screenrc diff --git a/zsh/00-zinit.zsh b/home/zsh/00-zinit.zsh similarity index 100% rename from zsh/00-zinit.zsh rename to home/zsh/00-zinit.zsh diff --git a/zsh/10-shared-shell.zsh b/home/zsh/10-shared-shell.zsh similarity index 100% rename from zsh/10-shared-shell.zsh rename to home/zsh/10-shared-shell.zsh diff --git a/zsh/20-tools.zsh b/home/zsh/20-tools.zsh similarity index 100% rename from zsh/20-tools.zsh rename to home/zsh/20-tools.zsh diff --git a/zsh/30-completions.zsh b/home/zsh/30-completions.zsh similarity index 100% rename from zsh/30-completions.zsh rename to home/zsh/30-completions.zsh diff --git a/zsh/40-vendor.zsh b/home/zsh/40-vendor.zsh similarity index 100% rename from zsh/40-vendor.zsh rename to home/zsh/40-vendor.zsh diff --git a/zsh/50-keybindings.zsh b/home/zsh/50-keybindings.zsh similarity index 100% rename from zsh/50-keybindings.zsh rename to home/zsh/50-keybindings.zsh diff --git a/zsh/55-aliases.zsh b/home/zsh/55-aliases.zsh similarity index 100% rename from zsh/55-aliases.zsh rename to home/zsh/55-aliases.zsh diff --git a/zsh/60-zmv.zsh b/home/zsh/60-zmv.zsh similarity index 100% rename from zsh/60-zmv.zsh rename to home/zsh/60-zmv.zsh diff --git a/zsh/70-named-directories.zsh b/home/zsh/70-named-directories.zsh similarity index 100% rename from zsh/70-named-directories.zsh rename to home/zsh/70-named-directories.zsh diff --git a/home/zshrc b/home/zshrc new file mode 100644 index 0000000..da3e8c9 --- /dev/null +++ b/home/zshrc @@ -0,0 +1,19 @@ +# Modular zsh configuration entrypoint. +# +# The real configuration lives in home/zsh/*.zsh so each concern can be updated +# independently while this file remains safe to symlink as ~/.zshrc. + +_dotfiles_zshrc="${(%):-%N}" +_dotfiles_zshrc_dir="${_dotfiles_zshrc:A:h}" +if [[ "${_dotfiles_zshrc_dir:t}" == "home" ]]; then + DOTFILES_DIR="${DOTFILES_DIR:-${_dotfiles_zshrc_dir:h}}" +else + DOTFILES_DIR="${DOTFILES_DIR:-$_dotfiles_zshrc_dir}" +fi +unset _dotfiles_zshrc _dotfiles_zshrc_dir + +for file in "$DOTFILES_DIR"/home/zsh/*.zsh(N); do + [ -r "$file" ] && source "$file" +done + +unset file diff --git a/nvim/PLUGIN_AUDIT.md b/nvim/PLUGIN_AUDIT.md deleted file mode 100644 index 20414b1..0000000 --- a/nvim/PLUGIN_AUDIT.md +++ /dev/null @@ -1,91 +0,0 @@ -# Neovim plugin audit - -## Scope - -This document describes the **current Neovim-only plugin/runtime structure**. - -Primary sources: -- `nvim/init.vim` -- `nvim/coc-settings.json` -- `nvim/lua/lazy-init.lua` -- `nvim/lua/plugins/*.lua` -- `nvim/lua/config/*.lua` - -## Current runtime path - -1. `nvim/init.vim` is a thin Neovim entrypoint. -2. `nvim/init.vim` boots `lazy.nvim` through `require('lazy-init')`. -3. `nvim/lua/lazy-init.lua` loads grouped specs from `nvim/lua/plugins/init.lua`. -4. General Neovim behavior is owned by Lua config modules: - - `nvim/lua/config/options.lua` - - `nvim/lua/config/keymaps.lua` - - `nvim/lua/config/commands.lua` - - `nvim/lua/config/autocmds.lua` - - `nvim/lua/config/personal.lua` -5. CoC JSON settings live in `nvim/coc-settings.json`. - -## High-level findings - -- **Neovim is self-contained under `nvim/`.** -- **Plugin specs are grouped by responsibility.** -- **The main preserved UX boundary is CoC, not legacy file structure.** -- **The old classic Vim compatibility tree has been removed from the active repo layout.** -- **The remaining cleanup opportunities are plugin/product decisions, not structural ownership problems.** - -## Current plugin ownership inventory - -| Plugin | Current Neovim owner | Hooks / behavior | Recommendation | Migration risk | Notes | -|---|---|---|---|---|---| -| `nvim-lua/plenary.nvim` | dependency in grouped plugin modules | dependency only | Keep | Low | Shared Lua dependency. | -| `AndrewRadev/splitjoin.vim` | `nvim/lua/plugins/editing.lua` | default plugin behavior | Keep | Low | No active structure problem. | -| `tpope/vim-surround` | `nvim/lua/plugins/editing.lua` | default mappings | Keep | Low | Stable, low-maintenance. | -| `tpope/vim-commentary` | `nvim/lua/plugins/editing.lua` | default mappings | Keep | Low | Stable, low-maintenance. | -| `tpope/vim-repeat` | `nvim/lua/plugins/editing.lua` | implicit repeat support | Keep | Low | Companion plugin. | -| `Konfekt/FastFold` | `nvim/lua/plugins/editing.lua` | fold behavior | Keep | Low | No current pressure to replace. | -| `lukas-reineke/indent-blankline.nvim` | `nvim/lua/plugins/ui.lua` | visual indent guides | Keep | Low | Lua-native indent guide plugin using the `ibl` entrypoint. | -| native root detection | `nvim/lua/config/project-root.lua` | project root detection via `vim.fs.root()` | Keep | Low | Plugin removed; behavior is handled with built-in Neovim APIs. | -| `stevearc/aerial.nvim` | `nvim/lua/plugins/navigation.lua` | `Aerial*` commands, `` | Keep | Medium | Modern outline workflow with the familiar toggle key preserved. | -| `nvim-telescope/telescope.nvim` | `nvim/lua/plugins/navigation.lua` | `:Telescope`, ui-select integration | Keep | Low | Modern, Lua-native. | -| `nvim-telescope/telescope-ui-select.nvim` | dependency in `navigation.lua` | UI select extension | Keep | Low | Owned with Telescope. | -| `tpope/vim-fugitive` | `nvim/lua/plugins/git.lua` | `:Git`, `:Gdiffsplit`, etc. | Keep | Low | Clear command-scoped tool. | -| `nvim-lualine/lualine.nvim` | `nvim/lua/plugins/ui.lua` | statusline/tabline | Keep | Low | Lua-native statusline/tabline using an evil_lualine-inspired layout with CoC-aware diagnostics/status. | -| `nvim-treesitter/nvim-treesitter` | `nvim/lua/plugins/ui.lua` | syntax highlighting | Keep | Low | Modern plugin, already colocated. | -| `neoclide/coc.nvim` | `nvim/lua/plugins/lsp.lua` plus `nvim/coc-settings.json` | completion, navigation, explorer, diagnostics, lists | Keep now | High | UX is preserved; future replacement should be parity-driven. | -| `github/copilot.vim` | `nvim/lua/plugins/ai.lua` | `` accept, tab-map disable | Keep | Medium | Config and mapping are active and colocated. | -| `CopilotC-Nvim/CopilotChat.nvim` | `nvim/lua/plugins/ai.lua` | `cc`, `cs` | Keep | Medium | Config and keymaps are colocated. | -| `greggh/claude-code.nvim` | `nvim/lua/plugins/ai.lua` | ``, `cC`, `cV` | Keep | Low | Modern plugin, config colocated. | -| `rizzatti/dash.vim` | `nvim/lua/plugins/tools.lua` | `:Dash*` commands | Keep | Low | Command-based utility. | -| `aquach/vim-http-client` | `nvim/lua/plugins/tools.lua` | filetype workflow | Keep | Low | No immediate change needed. | -| `vitapluvia/vim-gurl` | `nvim/lua/plugins/tools.lua` | `gr` | Keep | Low | Keymap is colocated with the plugin. | -| `skywind3000/asyncrun.vim` | `nvim/lua/plugins/tools.lua` | async command workflow | Keep | Low | No immediate change needed. | -| `ravitemer/mcphub.nvim` | `nvim/lua/plugins/tools.lua` | `:MCPHub` | Keep | Low | Large config now lives in the correct module. | - -## Completed migration outcomes - -### General Neovim config owned in Lua -- options and editor defaults: `nvim/lua/config/options.lua` -- general keymaps: `nvim/lua/config/keymaps.lua` -- user commands including `FormatJSON` and `WP`: `nvim/lua/config/commands.lua` -- reload autocmd: `nvim/lua/config/autocmds.lua` -- popup/personal helpers: `nvim/lua/config/personal.lua` - -### Plugin-owned behavior colocated -- root detection: `nvim/lua/config/project-root.lua` -- Aerial outline binding: `nvim/lua/plugins/navigation.lua` -- lualine statusline/tabline config: `nvim/lua/plugins/ui.lua` -- CoC globals, mappings, commands, and autocmds: `nvim/lua/plugins/lsp.lua` -- Copilot/CopilotChat bindings: `nvim/lua/plugins/ai.lua` -- Gurl keymap: `nvim/lua/plugins/tools.lua` - -## Remaining review targets - -These are product/maintenance decisions, not structural problems: - -1. Telescope overlap/extensions strategy -2. CoC replacement only when a parity-first migration plan exists - -## Recommended next moves - -1. Consider a later replacement plan for: - - eventually CoC, only if parity is documented first -2. Reduce headless verification noise by separating plugin bootstrap/install checks from config-structure checks. diff --git a/scripts/install-enhanced.sh b/scripts/install-enhanced.sh index eece080..d088fdb 100755 --- a/scripts/install-enhanced.sh +++ b/scripts/install-enhanced.sh @@ -17,7 +17,9 @@ HISTORY_LOGS=${HOME}/.logs SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DOTFILES_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" HOME_FILES="bash_profile aliases exports functions git gitconfig zshrc screenrc" +HOME_SOURCE_DIR="home" CONFIG_FILES="nvim ghostty tmux ohmyposh" +CONFIG_SOURCE_DIR="config" BACKUP_DIR="${HOME}/.dotfiles-backup-$(date +%Y%m%d_%H%M%S)" TPM_REPO_URL="${TPM_REPO_URL:-https://github.com/tmux-plugins/tpm.git}" TPM_INSTALL_DIR="${TPM_INSTALL_DIR:-$HOME/.config/tmux/plugins/tpm}" @@ -101,14 +103,14 @@ check_requirements() { # Check if all source files exist for file in $HOME_FILES; do - if [ ! -e "$DOTFILES_DIR/$file" ]; then - missing_requirements+=("Missing source file: $DOTFILES_DIR/$file") + if [ ! -e "$DOTFILES_DIR/$HOME_SOURCE_DIR/$file" ]; then + missing_requirements+=("Missing source file: $DOTFILES_DIR/$HOME_SOURCE_DIR/$file") fi done for file in $CONFIG_FILES; do - if [ ! -e "$DOTFILES_DIR/$file" ]; then - missing_requirements+=("Missing source file: $DOTFILES_DIR/$file") + if [ ! -e "$DOTFILES_DIR/$CONFIG_SOURCE_DIR/$file" ]; then + missing_requirements+=("Missing source file: $DOTFILES_DIR/$CONFIG_SOURCE_DIR/$file") fi done @@ -250,14 +252,14 @@ install_dotfiles() { # Link home files for file in $HOME_FILES; do - if ! link "$file" "$HOME/.$file"; then + if ! link "$HOME_SOURCE_DIR/$file" "$HOME/.$file"; then ((link_errors++)) fi done # Link config files for file in $CONFIG_FILES; do - if ! link "$file" "$HOME/.config/$file"; then + if ! link "$CONFIG_SOURCE_DIR/$file" "$HOME/.config/$file"; then ((link_errors++)) fi done @@ -286,7 +288,7 @@ verify_installation() { if [ -L "$target" ]; then local link_target link_target=$(readlink "$target") - if [ "$link_target" = "$DOTFILES_DIR/$file" ]; then + if [ "$link_target" = "$DOTFILES_DIR/$HOME_SOURCE_DIR/$file" ]; then if [ "$VERBOSE" = true ]; then print_status "$GREEN" "✅ $target correctly linked" fi @@ -306,7 +308,7 @@ verify_installation() { if [ -L "$target" ]; then local link_target link_target=$(readlink "$target") - if [ "$link_target" = "$DOTFILES_DIR/$file" ]; then + if [ "$link_target" = "$DOTFILES_DIR/$CONFIG_SOURCE_DIR/$file" ]; then if [ "$VERBOSE" = true ]; then print_status "$GREEN" "✅ $target correctly linked" fi diff --git a/scripts/test-install.sh b/scripts/test-install.sh index a239d84..0756986 100755 --- a/scripts/test-install.sh +++ b/scripts/test-install.sh @@ -183,13 +183,13 @@ test_config_syntax() { # Test shell configurations if command -v zsh >/dev/null 2>&1; then - if zsh -n "$DOTFILES_DIR/zshrc" 2>/dev/null; then + if zsh -n "$DOTFILES_DIR/home/zshrc" 2>/dev/null; then print_status "$GREEN" "✅ zshrc syntax is valid" else print_status "$YELLOW" "⚠️ zshrc may have syntax issues (some plugin/runtime features might not be available in test)" fi - for file in "$DOTFILES_DIR"/zsh/*.zsh; do + for file in "$DOTFILES_DIR"/home/zsh/*.zsh; do [ -e "$file" ] || continue if zsh -n "$file" 2>/dev/null; then if [ "${VERBOSE:-false}" = true ]; then @@ -203,7 +203,7 @@ test_config_syntax() { print_status "$YELLOW" "⚠️ zsh not available for syntax testing" fi - if bash -n "$DOTFILES_DIR/bash_profile" 2>/dev/null; then + if bash -n "$DOTFILES_DIR/home/bash_profile" 2>/dev/null; then print_status "$GREEN" "✅ bash_profile syntax is valid" else print_status "$RED" "❌ bash_profile has syntax errors" @@ -211,7 +211,7 @@ test_config_syntax() { fi # Test git configuration - if git config --file "$DOTFILES_DIR/gitconfig" --list >/dev/null 2>&1; then + if git config --file "$DOTFILES_DIR/home/gitconfig" --list >/dev/null 2>&1; then print_status "$GREEN" "✅ gitconfig is valid" else print_status "$RED" "❌ gitconfig has errors" diff --git a/tests/test_dotfiles.bats b/tests/test_dotfiles.bats index db6a1c0..3c19010 100644 --- a/tests/test_dotfiles.bats +++ b/tests/test_dotfiles.bats @@ -96,26 +96,26 @@ EOF } @test "tmux config uses TPM and ignores installed plugin checkouts" { - grep -q "@plugin 'tmux-plugins/tpm'" "$DOTFILES_DIR/tmux/tmux.conf" - grep -q "run '~/.config/tmux/plugins/tpm/tpm'" "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^tmux/plugins/$' "$DOTFILES_DIR/.gitignore" + grep -q "@plugin 'tmux-plugins/tpm'" "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q "run '~/.config/tmux/plugins/tpm/tpm'" "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^config/tmux/plugins/$' "$DOTFILES_DIR/.gitignore" } @test "tmux preserves Shift+Enter for Codex multiline input" { - grep -q 'terminal-features.*,xterm-ghostty:extkeys:hyperlinks' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^set-option -g extended-keys always$' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^set-option -g extended-keys-format csi-u$' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^bind-key -n S-Enter send-keys -H 1b 5b 31 33 3b 32 75$' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^keybind = shift+enter=csi:13;2u$' "$DOTFILES_DIR/ghostty/config" + grep -q 'terminal-features.*,xterm-ghostty:extkeys:hyperlinks' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^set-option -g extended-keys always$' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^set-option -g extended-keys-format csi-u$' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^bind-key -n S-Enter send-keys -H 1b 5b 31 33 3b 32 75$' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^keybind = shift+enter=csi:13;2u$' "$DOTFILES_DIR/config/ghostty/config" } @test "tmux and ghostty preserve clickable URLs" { - grep -q 'terminal-features.*,xterm-ghostty:extkeys:hyperlinks' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^set -g word-separators " "$' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^bind-key -n MouseDown1Pane if -F "#{mouse_hyperlink}"' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q 'open-url.sh "#{q:mouse_hyperlink}"' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q 'open-url.sh "#{q:mouse_word}"' "$DOTFILES_DIR/tmux/tmux.conf" - grep -q '^link-url = true$' "$DOTFILES_DIR/ghostty/config" + grep -q 'terminal-features.*,xterm-ghostty:extkeys:hyperlinks' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^set -g word-separators " "$' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^bind-key -n MouseDown1Pane if -F "#{mouse_hyperlink}"' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q 'open-url.sh "#{q:mouse_hyperlink}"' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q 'open-url.sh "#{q:mouse_word}"' "$DOTFILES_DIR/config/tmux/tmux.conf" + grep -q '^link-url = true$' "$DOTFILES_DIR/config/ghostty/config" } @test "tmux URL opener normalizes plain links safely" { @@ -129,12 +129,12 @@ printf '%s\n' "\$1" > "$opened_url" EOF chmod +x "$fake_bin/open" - run env PATH="$fake_bin:$PATH" "$DOTFILES_DIR/tmux/open-url.sh" '"https://example.com/path?x=1".' + run env PATH="$fake_bin:$PATH" "$DOTFILES_DIR/config/tmux/open-url.sh" '"https://example.com/path?x=1".' [ "$status" -eq 0 ] [ "$(cat "$opened_url")" = "https://example.com/path?x=1" ] rm -f "$opened_url" - run env PATH="$fake_bin:$PATH" "$DOTFILES_DIR/tmux/open-url.sh" 'www.example.com/docs,' + run env PATH="$fake_bin:$PATH" "$DOTFILES_DIR/config/tmux/open-url.sh" 'www.example.com/docs,' [ "$status" -eq 0 ] [ "$(cat "$opened_url")" = "https://www.example.com/docs" ] } @@ -144,7 +144,7 @@ EOF skip "tmux not available" fi - run tmux -L "dotfiles-bats-$$" -f /dev/null start-server \; source-file -n "$DOTFILES_DIR/tmux/tmux.conf" \; kill-server + run tmux -L "dotfiles-bats-$$" -f /dev/null start-server \; source-file -n "$DOTFILES_DIR/config/tmux/tmux.conf" \; kill-server [ "$status" -eq 0 ] } @@ -153,35 +153,39 @@ EOF skip "ghostty not available" fi - run ghostty +validate-config --config-file="$DOTFILES_DIR/ghostty/config" + mkdir -p "$TEST_TMPDIR/xdg-config" + ln -s "$DOTFILES_DIR/config/ghostty" "$TEST_TMPDIR/xdg-config/ghostty" + + run env XDG_CONFIG_HOME="$TEST_TMPDIR/xdg-config" ghostty +validate-config --config-file="$DOTFILES_DIR/config/ghostty/config" [ "$status" -eq 0 ] } @test "required dotfiles exist" { - local files=("zshrc" "bash_profile" "gitconfig" "aliases" "exports" "functions") + local files=("zshrc" "bash_profile" "gitconfig" "aliases" "exports" "functions" "screenrc") for file in "${files[@]}"; do - [ -f "$DOTFILES_DIR/$file" ] + [ -f "$DOTFILES_DIR/home/$file" ] done - [ -d "$DOTFILES_DIR/zsh" ] - [ -f "$DOTFILES_DIR/zsh/00-zinit.zsh" ] - [ -f "$DOTFILES_DIR/zsh/10-shared-shell.zsh" ] - [ -f "$DOTFILES_DIR/zsh/20-tools.zsh" ] - [ -f "$DOTFILES_DIR/zsh/30-completions.zsh" ] - [ -f "$DOTFILES_DIR/zsh/40-vendor.zsh" ] - [ -f "$DOTFILES_DIR/zsh/50-keybindings.zsh" ] - [ -f "$DOTFILES_DIR/zsh/55-aliases.zsh" ] - [ -f "$DOTFILES_DIR/zsh/60-zmv.zsh" ] - [ -f "$DOTFILES_DIR/zsh/70-named-directories.zsh" ] - - [ -d "$DOTFILES_DIR/ohmyposh" ] - [ -f "$DOTFILES_DIR/ohmyposh/zen.toml" ] - [ -f "$DOTFILES_DIR/ohmyposh/default.toml" ] + [ -d "$DOTFILES_DIR/home/git" ] + [ -d "$DOTFILES_DIR/home/zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/00-zinit.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/10-shared-shell.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/20-tools.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/30-completions.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/40-vendor.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/50-keybindings.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/55-aliases.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/60-zmv.zsh" ] + [ -f "$DOTFILES_DIR/home/zsh/70-named-directories.zsh" ] + + [ -d "$DOTFILES_DIR/config/ohmyposh" ] + [ -f "$DOTFILES_DIR/config/ohmyposh/zen.toml" ] + [ -f "$DOTFILES_DIR/config/ohmyposh/default.toml" ] } @test "git configuration is valid" { - run git config --file "$DOTFILES_DIR/gitconfig" --list + run git config --file "$DOTFILES_DIR/home/gitconfig" --list [ "$status" -eq 0 ] } @@ -192,10 +196,10 @@ EOF fi # Test basic syntax (may not catch all plugin/runtime issues) - run zsh -n "$DOTFILES_DIR/zshrc" + run zsh -n "$DOTFILES_DIR/home/zshrc" [ "$status" -eq 0 ] - for file in "$DOTFILES_DIR"/zsh/*.zsh; do + for file in "$DOTFILES_DIR"/home/zsh/*.zsh; do run zsh -n "$file" [ "$status" -eq 0 ] done @@ -205,52 +209,52 @@ EOF grep -q 'CONFIG_FILES="nvim ghostty tmux ohmyposh"' "$DOTFILES_DIR/scripts/install-enhanced.sh" grep -q 'brew "oh-my-posh"' "$DOTFILES_DIR/Brewfile" grep -q 'brew "zoxide"' "$DOTFILES_DIR/Brewfile" - grep -q 'oh-my-posh init zsh --config "$HOME/.config/ohmyposh/zen.toml"' "$DOTFILES_DIR/zsh/00-zinit.zsh" + grep -q 'oh-my-posh init zsh --config "$HOME/.config/ohmyposh/zen.toml"' "$DOTFILES_DIR/home/zsh/00-zinit.zsh" } @test "bash profile syntax" { - run bash -n "$DOTFILES_DIR/bash_profile" + run bash -n "$DOTFILES_DIR/home/bash_profile" [ "$status" -eq 0 ] } @test "neovim configuration files exist" { - [ -f "$DOTFILES_DIR/nvim/init.vim" ] - [ -f "$DOTFILES_DIR/nvim/coc-settings.json" ] - [ -f "$DOTFILES_DIR/nvim/lua/lazy-init.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/options.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/keymaps.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/commands.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/autocmds.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/personal.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/project-root.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/config/showpopup.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/init.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/editing.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/navigation.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/git.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/ui.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/lsp.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/ai.lua" ] - [ -f "$DOTFILES_DIR/nvim/lua/plugins/tools.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/init.vim" ] + [ -f "$DOTFILES_DIR/config/nvim/coc-settings.json" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/lazy-init.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/options.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/keymaps.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/commands.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/autocmds.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/personal.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/project-root.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/config/showpopup.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/init.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/editing.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/navigation.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/git.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/ui.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/lsp.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/ai.lua" ] + [ -f "$DOTFILES_DIR/config/nvim/lua/plugins/tools.lua" ] [ ! -d "$DOTFILES_DIR/vim" ] } @test "neovim migration from vim-plug to lazy.nvim" { # Verify init.vim no longer sources vim-plug config - ! grep -q "source.*vimrc.plugins" "$DOTFILES_DIR/nvim/init.vim" + ! grep -q "source.*vimrc.plugins" "$DOTFILES_DIR/config/nvim/init.vim" # Verify init.vim sources lazy-init instead - grep -q "require('lazy-init')" "$DOTFILES_DIR/nvim/init.vim" - grep -q "require('config.options')" "$DOTFILES_DIR/nvim/init.vim" - grep -q "require('config.keymaps')" "$DOTFILES_DIR/nvim/init.vim" - grep -q "require('config.commands')" "$DOTFILES_DIR/nvim/init.vim" - grep -q "require('config.autocmds')" "$DOTFILES_DIR/nvim/init.vim" - grep -q "require('config.personal')" "$DOTFILES_DIR/nvim/init.vim" - grep -q "require('config.project-root')" "$DOTFILES_DIR/nvim/init.vim" - ! grep -q "source ~/.vim/" "$DOTFILES_DIR/nvim/init.vim" + grep -q "require('lazy-init')" "$DOTFILES_DIR/config/nvim/init.vim" + grep -q "require('config.options')" "$DOTFILES_DIR/config/nvim/init.vim" + grep -q "require('config.keymaps')" "$DOTFILES_DIR/config/nvim/init.vim" + grep -q "require('config.commands')" "$DOTFILES_DIR/config/nvim/init.vim" + grep -q "require('config.autocmds')" "$DOTFILES_DIR/config/nvim/init.vim" + grep -q "require('config.personal')" "$DOTFILES_DIR/config/nvim/init.vim" + grep -q "require('config.project-root')" "$DOTFILES_DIR/config/nvim/init.vim" + ! grep -q "source ~/.vim/" "$DOTFILES_DIR/config/nvim/init.vim" # Verify lazy imports grouped plugin modules - local lazy_plugins="$DOTFILES_DIR/nvim/lua/plugins" + local lazy_plugins="$DOTFILES_DIR/config/nvim/lua/plugins" grep -q 'import = "plugins.editing"' "$lazy_plugins/init.lua" grep -q 'import = "plugins.navigation"' "$lazy_plugins/init.lua" grep -q 'import = "plugins.lsp"' "$lazy_plugins/init.lua" @@ -277,11 +281,11 @@ EOF } @test "shared Neovim mappings do not reference removed or conflicting plugin keys" { - local keymaps_file="$DOTFILES_DIR/nvim/lua/config/keymaps.lua" - local navigation_plugins="$DOTFILES_DIR/nvim/lua/plugins/navigation.lua" - local lsp_plugins="$DOTFILES_DIR/nvim/lua/plugins/lsp.lua" - local ai_plugins="$DOTFILES_DIR/nvim/lua/plugins/ai.lua" - local tools_plugins="$DOTFILES_DIR/nvim/lua/plugins/tools.lua" + local keymaps_file="$DOTFILES_DIR/config/nvim/lua/config/keymaps.lua" + local navigation_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/navigation.lua" + local lsp_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/lsp.lua" + local ai_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/ai.lua" + local tools_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/tools.lua" ! grep -q "NERDTreeToggle" "$lsp_plugins" grep -q "AerialToggle" "$navigation_plugins" @@ -297,12 +301,12 @@ EOF } @test "neovim non-plugin options and keymaps are owned by Lua config modules" { - local init_file="$DOTFILES_DIR/nvim/init.vim" - local options_file="$DOTFILES_DIR/nvim/lua/config/options.lua" - local keymaps_file="$DOTFILES_DIR/nvim/lua/config/keymaps.lua" - local autocmds_file="$DOTFILES_DIR/nvim/lua/config/autocmds.lua" - local personal_file="$DOTFILES_DIR/nvim/lua/config/personal.lua" - local root_file="$DOTFILES_DIR/nvim/lua/config/project-root.lua" + local init_file="$DOTFILES_DIR/config/nvim/init.vim" + local options_file="$DOTFILES_DIR/config/nvim/lua/config/options.lua" + local keymaps_file="$DOTFILES_DIR/config/nvim/lua/config/keymaps.lua" + local autocmds_file="$DOTFILES_DIR/config/nvim/lua/config/autocmds.lua" + local personal_file="$DOTFILES_DIR/config/nvim/lua/config/personal.lua" + local root_file="$DOTFILES_DIR/config/nvim/lua/config/project-root.lua" grep -q "require('config.options')" "$init_file" grep -q "require('config.keymaps')" "$init_file" @@ -325,8 +329,8 @@ EOF } @test "copilot mapping is owned in ai plugin config and not lazy on insert" { - local ai_plugins="$DOTFILES_DIR/nvim/lua/plugins/ai.lua" - local lsp_plugins="$DOTFILES_DIR/nvim/lua/plugins/lsp.lua" + local ai_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/ai.lua" + local lsp_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/lsp.lua" grep -q 'github/copilot.vim' "$ai_plugins" grep -q 'lazy = false' "$ai_plugins" @@ -340,7 +344,7 @@ EOF } @test "lualine uses the evil_lualine theme" { - local ui_plugins="$DOTFILES_DIR/nvim/lua/plugins/ui.lua" + local ui_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/ui.lua" grep -q 'nvim-lualine/lualine.nvim' "$ui_plugins" grep -q 'bg = "NONE"' "$ui_plugins" @@ -354,7 +358,7 @@ EOF } @test "treesitter eagerly manages javascript-family parsers without auto install races" { - local ui_plugins="$DOTFILES_DIR/nvim/lua/plugins/ui.lua" + local ui_plugins="$DOTFILES_DIR/config/nvim/lua/plugins/ui.lua" grep -q 'nvim-treesitter/nvim-treesitter' "$ui_plugins" grep -q '"diff"' "$ui_plugins" @@ -365,8 +369,8 @@ EOF } @test "Neovim plugin setup for lazy-loaded plugins lives in lazy specs" { - local lazy_plugins="$DOTFILES_DIR/nvim/lua/plugins" - local coc_settings="$DOTFILES_DIR/nvim/coc-settings.json" + local lazy_plugins="$DOTFILES_DIR/config/nvim/lua/plugins" + local coc_settings="$DOTFILES_DIR/config/nvim/coc-settings.json" grep -R -q 'local telescope = require("telescope")' "$lazy_plugins" grep -R -q 'require("aerial").setup({' "$lazy_plugins" @@ -381,7 +385,7 @@ EOF } @test "neovim plugin specs are split into grouped lazy modules" { - local plugins_dir="$DOTFILES_DIR/nvim/lua/plugins" + local plugins_dir="$DOTFILES_DIR/config/nvim/lua/plugins" grep -q "return {" "$plugins_dir/init.lua" grep -q 'import = "plugins.editing"' "$plugins_dir/init.lua" @@ -399,11 +403,11 @@ EOF } @test "neovim lua files have valid basic structure" { - local lazy_init_file="$DOTFILES_DIR/nvim/lua/lazy-init.lua" + local lazy_init_file="$DOTFILES_DIR/config/nvim/lua/lazy-init.lua" grep -q 'require("lazy")' "$lazy_init_file" - for lua_file in "$DOTFILES_DIR"/nvim/lua/plugins/*.lua; do + for lua_file in "$DOTFILES_DIR"/config/nvim/lua/plugins/*.lua; do local open_braces=$(grep -o "{" "$lua_file" | wc -l) local close_braces=$(grep -o "}" "$lua_file" | wc -l) [ "$open_braces" -eq "$close_braces" ] diff --git a/zshrc b/zshrc deleted file mode 100644 index 14b08b1..0000000 --- a/zshrc +++ /dev/null @@ -1,14 +0,0 @@ -# Modular zsh configuration entrypoint. -# -# The real configuration lives in zsh/*.zsh so each concern can be updated -# independently while this file remains safe to symlink as ~/.zshrc. - -_dotfiles_zshrc="${(%):-%N}" -DOTFILES_DIR="${DOTFILES_DIR:-${_dotfiles_zshrc:A:h}}" -unset _dotfiles_zshrc - -for file in "$DOTFILES_DIR"/zsh/*.zsh(N); do - [ -r "$file" ] && source "$file" -done - -unset file