From 5d2e966214e65f29fa840a2c79af6af0b8076634 Mon Sep 17 00:00:00 2001 From: taco Date: Sat, 27 Jun 2026 00:09:46 +0000 Subject: [PATCH] dotfiles v1.1.11 --- .config/fish/config.fish | 2 +- .config/fish/functions/dotfiles.fish | 122 ++++++++++++++++++++++----- .config/fish/functions/keyme.fish | 6 +- install.fish | 6 +- 4 files changed, 111 insertions(+), 25 deletions(-) diff --git a/.config/fish/config.fish b/.config/fish/config.fish index c02ca2a..a0f7548 100644 --- a/.config/fish/config.fish +++ b/.config/fish/config.fish @@ -1,4 +1,4 @@ -set -g DOTFILES_VERSION "1.1.10" +set -g DOTFILES_VERSION "1.1.11" function gitme if test (count $argv) -lt 2 diff --git a/.config/fish/functions/dotfiles.fish b/.config/fish/functions/dotfiles.fish index 38bb1af..6c3c020 100644 --- a/.config/fish/functions/dotfiles.fish +++ b/.config/fish/functions/dotfiles.fish @@ -32,7 +32,6 @@ # tmux.conf ~/.tmux.conf tmux terminal multiplexer # gitconfig ~/.gitconfig Git version control # gitignore ~/.gitignore Global Git ignore rules -# starship.toml ~/.config/starship.toml Starship prompt # bashrc ~/.bashrc Bash (when Fish is absent) # # To add support for a new file, simply drop a template in $DOTFILES_DIR @@ -92,6 +91,9 @@ function dotfiles -d "Manage dotfiles and self-update system" case publish dotfiles_publish + case add + dotfiles_add $argv[2..] + case '*' echo "dotfiles: unknown command '$cmd'" echo "Run 'dotfiles help' for usage." @@ -113,6 +115,7 @@ function dotfiles_help -d "Show the dotfiles help text" echo " status [name ...] Show checksum diff for dotfiles" echo " init [name ...] Create dotfiles from templates" echo " update [name ...] Re-apply templates (with backup)" + echo " add [name] Import a file as a new template" echo " edit Open ~/. in \$EDITOR" echo " repo [url] Show or set the remote repo URL" echo " sync Git-pull and re-apply everything" @@ -125,6 +128,8 @@ function dotfiles_help -d "Show the dotfiles help text" echo "Examples:" echo " dotfiles init Create ~/.tmux.conf, ~/.gitconfig, …" echo " dotfiles init gitconfig Create only ~/.gitconfig" + echo " dotfiles add ~/.vimrc Import ~/.vimrc as a template" + echo " dotfiles add ~/.config/kitty/kitty.conf kitty/kitty.conf" echo " dotfiles status Check every managed file for drift" echo " dotfiles sync Pull + re-apply everything" echo " dotfiles publish Bump version, commit, and push" @@ -190,9 +195,9 @@ function dotfiles_status -d "Show checksum diff for managed dotfiles" continue end - # Compare checksums - set -l tmpl_md5 (md5sum "$tmpl" | cut -d' ' -f1) - set -l dest_md5 (md5sum "$dest" | cut -d' ' -f1) + # Compare checksums (cross-platform: md5sum on Linux, md5 on macOS) + set -l tmpl_md5 (_dotfiles_md5 "$tmpl") + set -l dest_md5 (_dotfiles_md5 "$dest") if test "$tmpl_md5" = "$dest_md5" echo " ✓ $name (up to date)" @@ -336,11 +341,81 @@ function dotfiles_edit -d "Open a dotfile for editing" return 1 end - # $EDITOR is set in config.fish; fall back to nano if unset + set -q EDITOR; or set -l EDITOR nano $EDITOR "$dest" end +# ══════════════════════════════════════════════════════════════════════════════ +# dotfiles_add — import a file as a new template +# ══════════════════════════════════════════════════════════════════════════════ +# +# Usage: +# dotfiles add ~/.vimrc → imports as vimrc, deploys to ~/.vimrc +# dotfiles add ~/.config/kitty/kitty.conf kitty/kitty.conf +# → imports to kitty/kitty.conf, +# deploys to ~/.config/kitty/kitty.conf +# +# When no explicit name is given, the template name is derived by stripping +# the "$HOME/." prefix from the resolved source path. +# ══════════════════════════════════════════════════════════════════════════════ + +function dotfiles_add -d "Import a file as a new dotfile template" + set -l source $argv[1] + + if not set -q source[1] + echo "Usage: dotfiles add [name]" + echo "Example: dotfiles add ~/.vimrc" + return 1 + end + + if not test -f "$source" + echo "Error: $source is not a regular file." + return 1 + end + + # Resolve to an absolute path (cross-platform: Linux `realpath` or + # macOS `grealpath` from coreutils; fall back to basic expansion). + set -l abs_source + if command -v realpath &>/dev/null + set abs_source (realpath "$source") + else if command -v grealpath &>/dev/null + set abs_source (grealpath "$source") + else + set abs_source (string replace -r '^~' "$HOME" -- "$source") + if not string match -q '/*' "$abs_source" + set abs_source "$PWD/$abs_source" + end + end + + # Derive template name: strip "$HOME/." prefix → relative dotfile path + set -l name $argv[2] + if not set -q name[1] + set -l home_dot "$HOME/." + if string match -q "$home_dot*" "$abs_source" + set name (string sub -s (math (string length "$home_dot") + 1) "$abs_source") + else + # Fall back to basename of the source file + set name (basename "$abs_source") + end + end + + set -l tmpl (_dotfiles_template_path "$name") + + # Create parent directories under DOTFILES_DIR if needed + set -l parent (dirname "$tmpl") + if not test -d "$parent" + mkdir -p "$parent" + end + + command cp "$abs_source" "$tmpl" + echo " added template: $tmpl" + + # Deploy it immediately + dotfiles_init "$name" +end + + # ══════════════════════════════════════════════════════════════════════════════ # dotfiles_repo — show or set the remote repository URL # ══════════════════════════════════════════════════════════════════════════════ @@ -603,11 +678,13 @@ function dotfiles_publish -d "Push local changes to the remote dotfiles repo" set -l version_line 'set -g DOTFILES_VERSION "'"$new_version"'"' # Update local config.fish - sed -i 's/^set -g DOTFILES_VERSION ".*"$/'"$version_line"'/' "$local_config" + sed -i.bak 's/^set -g DOTFILES_VERSION ".*"$/'"$version_line"'/' "$local_config" + command rm -f "$local_config.bak" echo "Updated local $local_config → v$new_version" # Update cloned config.fish - sed -i 's/^set -g DOTFILES_VERSION ".*"$/'"$version_line"'/' "$repo_config" + sed -i.bak 's/^set -g DOTFILES_VERSION ".*"$/'"$version_line"'/' "$repo_config" + command rm -f "$repo_config.bak" # Set the session variable so subsequent commands in this function # and future shell sessions see the new version. @@ -730,10 +807,8 @@ function _dotfiles_list_managed -d "List available dotfile templates" end # Recursively list all regular files relative to DOTFILES_DIR. - # This supports subdirectory-based templates, e.g.: - # dotfiles/tmux.conf → tmux.conf - # dotfiles/config/starship.toml → config/starship.toml - command find "$DOTFILES_DIR" -type f -printf '%P\n' | sort + # find -printf is GNU-only, so we strip the prefix portably. + command find "$DOTFILES_DIR" -type f | sort | string replace "$DOTFILES_DIR/" "" end @@ -759,6 +834,22 @@ function _dotfiles_resolve_targets -d "Resolve user-supplied names to template n end +# ----------------------------------------------------------------------------- +# _dotfiles_md5 +# +# Cross-platform MD5 checksum: uses md5sum on Linux, md5 on macOS. +# Returns just the hash string. +# ----------------------------------------------------------------------------- + +function _dotfiles_md5 -d "Get MD5 checksum of a file (cross-platform)" + if command -v md5sum &>/dev/null + md5sum "$argv[1]" | cut -d' ' -f1 + else + md5 "$argv[1]" | sed 's/.*= //' + end +end + + # ----------------------------------------------------------------------------- # _dotfiles_template_path # @@ -795,12 +886,5 @@ end function _dotfiles_target_path -d "Get the target installation path for a dotfile" set -l name $argv[1] - - if string match -q "*/*" "$name" - # Name contains a "/" → treat as relative path under $HOME - echo "$HOME/.$name" - else - # Name without slash → place directly in $HOME, prefixed with dot - echo "$HOME/.$name" - end + echo "$HOME/.$name" end diff --git a/.config/fish/functions/keyme.fish b/.config/fish/functions/keyme.fish index 7d3a060..b6a28b9 100644 --- a/.config/fish/functions/keyme.fish +++ b/.config/fish/functions/keyme.fish @@ -31,10 +31,12 @@ function keyme -d "Generate (or regenerate) an ed25519 SSH key for Gitea and con # If an IdentityFile line already exists under this Host, replace it; # otherwise add one after the HostName line. if grep -A5 "^Host $host\$" "$config_path" | grep -q "IdentityFile" - sed -i "/^Host $host\$/,/^Host /s|IdentityFile .*|IdentityFile $key_path|" "$config_path" + sed -i.bak "/^Host $host\$/,/^Host /s|IdentityFile .*|IdentityFile $key_path|" "$config_path" + command rm -f "$config_path.bak" echo "Updated IdentityFile for Host $host in $config_path" else - sed -i "/^Host $host\$/,/^Host /s|HostName .*|&\n\tIdentityFile $key_path|" "$config_path" + sed -i.bak "/^Host $host\$/,/^Host /s|HostName .*|&\n\tIdentityFile $key_path|" "$config_path" + command rm -f "$config_path.bak" echo "Added IdentityFile for Host $host in $config_path" end else diff --git a/install.fish b/install.fish index 1fe21cd..6672efa 100644 --- a/install.fish +++ b/install.fish @@ -14,7 +14,7 @@ # remote origin to SSH so future pushes use the right URL # 3. Replaces or updates ~/.config/fish/ with the contents of the repo # 4. Sources the new config and runs `dotfiles init` to install templates -# (~/.tmux.conf, ~/.gitconfig, ~/.config/starship.toml, etc.) +# (~/.tmux.conf, ~/.gitconfig, etc.) # 5. Warns if SSH key is needed and points to the keyme helper # 6. Prints next steps # @@ -85,11 +85,11 @@ end echo "$GRN ✓$RST Git "(git --version | cut -d' ' -f3) # Optional but nice-to-have tools -for tool in tmux starship +for tool in tmux if command -v $tool &>/dev/null echo " ⬡ $tool detected (templates available)" else - echo " ⬡ $tool not found (optional — templates exist but are skipped)" + echo " ⬡ $tool not found (optional — template exists but is skipped)" end end