diff --git a/.claude/skills/dotfiles/DOT-CLI.md b/.claude/skills/dotfiles/DOT-CLI.md index 018b75f..85ba597 100644 --- a/.claude/skills/dotfiles/DOT-CLI.md +++ b/.claude/skills/dotfiles/DOT-CLI.md @@ -3,14 +3,24 @@ ## Architecture `dot` is defined in one file: `~/.config/fish/functions/dot.fish`. It holds -two functions: +three functions: -- `dot` (`--wraps=git`) — dispatches `init` and any file found under +- `dot` (`--wraps=git`) — dispatches `init`, `help`, and any file found under `~/.config/dot/commands/`, otherwise forwards everything to `git --git-dir=~/.dotfiles --work-tree=$HOME $argv` (full passthrough). - `__dot_init` — the bootstrap logic, inlined in the same file rather than autoloaded separately, because it's the one subcommand that must work before the dotfiles repo has ever been cloned onto a machine. +- `__dot_help` — prints usage: the built-in commands plus whatever is + currently found under `~/.config/dot/commands/`, generated by globbing that + directory rather than a hardcoded list, so it can't drift from reality. + +`__dot_help`'s glob over `~/.config/dot/commands/*.fish` is duplicated in +`~/.config/fish/completions/dot.fish`'s `__dot_custom_subcommands` rather than +shared: fish only autoloads a function from a file named after that function, +so a helper defined inside `dot.fish` would be undefined if tab-completion +ran before `dot` had ever been sourced in the session. Keep both copies in +sync when the listing logic changes. `dot init`: @@ -33,9 +43,9 @@ of `dot` itself. 1. Create `~/.config/dot/commands/.fish` defining a `_dot_` function. 2. Confirm `dot ` dispatches to it. No other wiring is needed — - `~/.config/fish/completions/dot.fish` discovers new command files by - globbing that directory, and `--wraps=git` still covers raw git - subcommands. + `~/.config/fish/completions/dot.fish` and `__dot_help` both discover new + command files by globbing that directory, and `--wraps=git` still covers + raw git subcommands. 3. Add a case to `~/.config/dot/tests/dot.fish` covering it and run `fishtape ~/.config/dot/tests/dot.fish` until it passes. diff --git a/.config/dot/tests/dot.fish b/.config/dot/tests/dot.fish index 8efb355..364fb85 100644 --- a/.config/dot/tests/dot.fish +++ b/.config/dot/tests/dot.fish @@ -70,3 +70,22 @@ end" >$HOME/.config/dot/commands/mark.fish dot mark >/dev/null 2>&1 @test "dispatches to a command file under ~/.config/dot/commands/" (cat $marker) = marked + +# --- dot help --- +set -gx HOME (mktemp -d) +dot init --url $remote >/dev/null 2>&1 + +set -l help_output (dot help) +set -l help_status $status + +@test "dot help succeeds" $help_status -eq 0 +@test "dot help lists init" (string match -q '*init*' -- $help_output; echo $status) -eq 0 +@test "dot help mentions git passthrough" (string match -q '*git*' -- $help_output; echo $status) -eq 0 + +mkdir -p $HOME/.config/dot/commands +echo "function _dot_mark + echo marked +end" >$HOME/.config/dot/commands/mark.fish + +set -l help_with_custom (dot help) +@test "dot help lists custom commands found under ~/.config/dot/commands/" (string match -q '*mark*' -- $help_with_custom; echo $status) -eq 0 diff --git a/.config/fish/completions/dot.fish b/.config/fish/completions/dot.fish index 02ff615..ada98a8 100644 --- a/.config/fish/completions/dot.fish +++ b/.config/fish/completions/dot.fish @@ -1,5 +1,6 @@ function __dot_custom_subcommands echo init + echo help path basename $HOME/.config/dot/commands/*.fish 2>/dev/null | path change-extension '' end diff --git a/.config/fish/fish_variables b/.config/fish/fish_variables new file mode 100644 index 0000000..2a11029 --- /dev/null +++ b/.config/fish/fish_variables @@ -0,0 +1,80 @@ +# This file contains fish universal variable definitions. +# VERSION: 3.0 +SETUVAR __done_min_cmd_duration:10000 +SETUVAR __done_notification_urgency_level:low +SETUVAR _fisher_jorgebucaran_2F_fishtape_files:\x7e/\x2econfig/fish/functions/fishtape\x2efish\x1e\x7e/\x2econfig/fish/completions/fishtape\x2efish +SETUVAR _fisher_plugins:jorgebucaran/fishtape +SETUVAR _fisher_upgraded_to_4_4:\x1d +SETUVAR pure_begin_prompt_with_current_directory:true +SETUVAR pure_check_for_new_release:false +SETUVAR pure_color_at_sign:pure_color_mute +SETUVAR pure_color_aws_profile:pure_color_warning +SETUVAR pure_color_command_duration:pure_color_warning +SETUVAR pure_color_current_directory:pure_color_primary +SETUVAR pure_color_danger:red +SETUVAR pure_color_dark:black +SETUVAR pure_color_exit_status:pure_color_danger +SETUVAR pure_color_git_branch:pure_color_mute +SETUVAR pure_color_git_dirty:pure_color_mute +SETUVAR pure_color_git_stash:pure_color_info +SETUVAR pure_color_git_unpulled_commits:pure_color_info +SETUVAR pure_color_git_unpushed_commits:pure_color_info +SETUVAR pure_color_hostname:pure_color_mute +SETUVAR pure_color_info:cyan +SETUVAR pure_color_jobs:pure_color_normal +SETUVAR pure_color_k8s_context:pure_color_success +SETUVAR pure_color_k8s_namespace:pure_color_primary +SETUVAR pure_color_k8s_prefix:pure_color_info +SETUVAR pure_color_light:white +SETUVAR pure_color_mute:brblack +SETUVAR pure_color_nixdevshell_prefix:pure_color_info +SETUVAR pure_color_nixdevshell_symbol:pure_color_mute +SETUVAR pure_color_normal:normal +SETUVAR pure_color_prefix_root_prompt:pure_color_danger +SETUVAR pure_color_primary:blue +SETUVAR pure_color_prompt_on_error:pure_color_danger +SETUVAR pure_color_prompt_on_success:pure_color_success +SETUVAR pure_color_success:magenta +SETUVAR pure_color_system_time:pure_color_mute +SETUVAR pure_color_username_normal:pure_color_mute +SETUVAR pure_color_username_root:pure_color_light +SETUVAR pure_color_virtualenv:pure_color_mute +SETUVAR pure_color_warning:yellow +SETUVAR pure_convert_exit_status_to_signal:false +SETUVAR pure_enable_aws_profile:true +SETUVAR pure_enable_container_detection:true +SETUVAR pure_enable_git:true +SETUVAR pure_enable_k8s:false +SETUVAR pure_enable_nixdevshell:false +SETUVAR pure_enable_single_line_prompt:false +SETUVAR pure_enable_virtualenv:true +SETUVAR pure_reverse_prompt_symbol_in_vimode:true +SETUVAR pure_separate_prompt_on_error:false +SETUVAR pure_shorten_prompt_current_directory_length:0 +SETUVAR pure_shorten_window_title_current_directory_length:0 +SETUVAR pure_show_exit_status:false +SETUVAR pure_show_jobs:false +SETUVAR pure_show_numbered_git_indicator:false +SETUVAR pure_show_prefix_root_prompt:false +SETUVAR pure_show_subsecond_command_duration:false +SETUVAR pure_show_system_time:false +SETUVAR pure_symbol_aws_profile_prefix: +SETUVAR pure_symbol_container_prefix: +SETUVAR pure_symbol_exit_status_prefix:\x7c +SETUVAR pure_symbol_exit_status_separator:\x7c +SETUVAR pure_symbol_git_dirty:\x2a +SETUVAR pure_symbol_git_stash:\u2261 +SETUVAR pure_symbol_git_unpulled_commits:\u21e3 +SETUVAR pure_symbol_git_unpushed_commits:\u21e1 +SETUVAR pure_symbol_k8s_prefix:\u2638 +SETUVAR pure_symbol_nixdevshell_prefix:\u2744\ufe0f +SETUVAR pure_symbol_prefix_root_prompt:\x23 +SETUVAR pure_symbol_prompt:\u276f +SETUVAR pure_symbol_reverse_prompt:\u276e +SETUVAR pure_symbol_ssh_prefix: +SETUVAR pure_symbol_title_bar_separator:\x2d +SETUVAR pure_symbol_virtualenv_prefix: +SETUVAR pure_system_time_format:\x2b\x25T +SETUVAR pure_threshold_command_duration:5 +SETUVAR pure_truncate_prompt_current_directory_keeps:\x2d1 +SETUVAR pure_truncate_window_title_current_directory_keeps:\x2d1 diff --git a/.config/fish/functions/dot.fish b/.config/fish/functions/dot.fish index 85823a0..59778ca 100644 --- a/.config/fish/functions/dot.fish +++ b/.config/fish/functions/dot.fish @@ -7,6 +7,11 @@ function dot --wraps=git --description 'Manage dotfiles via a bare repo checked return $status end + if test "$argv[1]" = help + __dot_help + return $status + end + set -l commands_dir $HOME/.config/dot/commands set -l command_file $commands_dir/$argv[1].fish @@ -87,3 +92,23 @@ function __dot_init echo "dot init: bootstrapped $dotfiles_dir from $url" end + +# The custom-subcommand glob is duplicated (not shared with +# completions/dot.fish) because fish only autoloads a function from a file +# named after that function; a shared helper would go undefined if `dot help` +# ran in a completion context before `dot` itself had ever been sourced. +function __dot_help + echo "dot: manage dotfiles via a bare repo checked out over \$HOME" + echo + echo "Commands:" + echo " init bootstrap the dotfiles repo on a new machine" + echo " help show this message" + + for f in $HOME/.config/dot/commands/*.fish + test -e $f; or continue + echo " "(path basename $f | path change-extension '') + end + + echo + echo "Any other command is passed through to git (dot status, dot add, dot commit, dot push, ...)." +end diff --git a/.gitea/README.md b/.gitea/README.md index 69f6537..61dca39 100644 --- a/.gitea/README.md +++ b/.gitea/README.md @@ -1,27 +1,10 @@ # dotfiles -Managed as a bare git repo checked out over `$HOME`. Not cloned in the usual -sense — `git --git-dir=~/.dotfiles --work-tree=$HOME` treats `$HOME` itself as -the working tree. - -## Everyday use - -A fish function named `dot` wraps that invocation: - -```fish -dot status -dot add .bashrc -dot commit -m 'update bashrc' -dot push -``` - -Any git subcommand works — `dot` forwards whatever you type straight to git. +Dotfiles managed as a bare git repo checked out over `$HOME`, for machines +running CachyOS with KDE Plasma. ## Bootstrapping a new machine -Before `dot` exists there's nothing to autoload it from, so the very first -step is fetching that one file by hand: - ```sh mkdir -p ~/.config/fish/functions curl -fsSL https://git.alexion.dev/alexion/dotfiles/raw/branch/main/.config/fish/functions/dot.fish \ @@ -29,25 +12,13 @@ curl -fsSL https://git.alexion.dev/alexion/dotfiles/raw/branch/main/.config/fish fish -c 'dot init' ``` -`dot init`: +## Commands -- clones the bare repo to `~/.dotfiles` -- backs up any pre-existing files that would be overwritten by checkout into - `~/.dotfiles-backup//` -- checks out the tracked files onto `$HOME` -- sets `status.showUntrackedFiles=no` so `dot status` doesn't list all of - `$HOME` +| Command | Description | +| ----------- | ----------------------------------------------- | +| `dot help` | Lists available commands. | +| `dot init` | Bootstraps the dotfiles repo on a new machine. | +| `dot ` | Everything else is passed to `git`. | -It refuses to run if `~/.dotfiles` already exists, and it never falls back to -creating a fresh empty repo if the clone fails. - -## Adding new subcommands - -Beyond `init`, `dot` looks for `~/.config/dot/commands/.fish`. Each file -should define a `_dot_` function; `dot args...` sources the file -and calls it. These files are deliberately *not* under -`~/.config/fish/functions/`, so they never become independently invokable -commands or clutter tab-completion outside of `dot` itself. - -`~/.config/fish/completions/dot.fish` discovers them automatically by -scanning that directory, so a new command file gets tab-completion for free. +See [DOT-CLI.md](../.claude/skills/dotfiles/DOT-CLI.md) for the `dot` tool's +internal architecture, bootstrap logic, subcommand dispatch, and test suite.