This commit is contained in:
2026-02-25 16:39:22 +02:00
parent f84477f9b9
commit cf7f8609ac
8 changed files with 378 additions and 52 deletions

View File

@@ -3,13 +3,25 @@
set -euo pipefail
usage() {
echo "Usage: $(basename "$0") -c COMMENT_SYMBOL [-e EXCLUDE_PATTERN]... TARGET"
echo " -c Comment symbol (e.g., '#' or '//')"
echo "Usage: $(basename "$0") <command> [options] TARGET"
echo ""
echo "Commands:"
echo " add Add/update path comment in first 5 lines of each file"
echo " undo Remove any path comment from first 5 lines of each file"
echo ""
echo "Options:"
echo " -c Comment symbol (e.g., '#' or '//') [required for add]"
echo " -e Exclude pattern (can be specified multiple times)"
echo " TARGET File or directory to process"
exit 1
}
[[ $# -lt 1 ]] && usage
cmd="$1"
shift
[[ "$cmd" != "add" && "$cmd" != "undo" ]] && usage
comment_sym=""
excludes=()
@@ -24,66 +36,63 @@ done
shift $((OPTIND - 1))
[[ $# -ne 1 ]] && usage
[[ -z "$comment_sym" ]] && usage
if [[ "$cmd" == "add" ]]; then
[[ -z "$comment_sym" ]] && {
echo "Error: -c is required for add" >&2
usage
}
fi
target="$(realpath "$1")"
base_dir="$(pwd)"
strip_path_comment() {
local file="$1"
awk 'NR <= 5 && /path: / { next } { print }' "$file" >"$file.tmp"
mv "$file.tmp" "$file"
}
process_file() {
local file="$1"
# shellcheck disable=SC2295
local rel_path="${file#$base_dir/}"
local path_comment="$comment_sym path: $rel_path"
# Read first two lines
local line1 line2
IFS= read -r line1 <"$file" 2>/dev/null || line1=""
IFS= read -r line2 < <(tail -n +2 "$file") 2>/dev/null || line2=""
strip_path_comment "$file"
local line1
IFS= read -r line1 <"$file" 2>/dev/null || line1=""
# Handle shebang case
if [[ "$line1" =~ ^#! ]]; then
if [[ "$line2" == *"path: "* ]]; then
# Replace existing path comment on line 2
{
echo "$line1"
echo "$path_comment"
tail -n +3 "$file"
} >"$file.tmp"
else
# Insert new path comment after shebang
{
echo "$line1"
echo "$path_comment"
tail -n +2 "$file"
} >"$file.tmp"
fi
{
echo "$line1"
echo "$path_comment"
tail -n +2 "$file"
} >"$file.tmp"
else
if [[ "$line1" == *"path: "* ]]; then
# Replace existing path comment on line 1
{
echo "$path_comment"
tail -n +2 "$file"
} >"$file.tmp"
else
# Insert new path comment at top
{
echo "$path_comment"
cat "$file"
} >"$file.tmp"
fi
{
echo "$path_comment"
cat "$file"
} >"$file.tmp"
fi
mv "$file.tmp" "$file"
}
if [[ -f "$target" ]]; then
process_file "$target"
elif [[ -d "$target" ]]; then
find_cmd=(find "$target")
dispatch() {
local file="$1"
if [[ "$cmd" == "add" ]]; then
process_file "$file"
else
strip_path_comment "$file"
fi
}
# Always exclude hidden files and directories
find_cmd+=(\( -name ".*" -prune \))
if [[ -f "$target" ]]; then
dispatch "$target"
elif [[ -d "$target" ]]; then
find_cmd=(find "$target" \( -name ".*" -prune \))
if [[ ${#excludes[@]} -gt 0 ]]; then
find_cmd+=(-o \()
@@ -98,7 +107,7 @@ elif [[ -d "$target" ]]; then
find_cmd+=(-o -type f -print0)
while IFS= read -r -d '' file; do
process_file "$file"
dispatch "$file"
done < <("${find_cmd[@]}")
else
echo "Error: $target is not a file or directory" >&2

67
config/shared/bin/catfiles Executable file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="."
declare -a SKIP_DIRS=()
declare -a PATTERNS=()
usage() {
cat <<EOF
Usage: $0 [-r root_dir] [-s dir_to_skip]... -p pattern ...
Options:
-r DIR Root directory (default: .)
-s DIR Directory name to skip (can repeat)
-p PATTERN File pattern (e.g. '*.md', '*.txt') (required, can repeat)
Example:
$0 -p '*.md'
$0 -r src -s node_modules -s .git -p '*.md' -p '*.txt'
EOF
exit 1
}
while getopts ":r:s:p:" opt; do
case "$opt" in
r) ROOT="$OPTARG" ;;
s) SKIP_DIRS+=("$OPTARG") ;;
p) PATTERNS+=("$OPTARG") ;;
*) usage ;;
esac
done
shift $((OPTIND - 1))
# Require at least one pattern
(( ${#PATTERNS[@]} > 0 )) || usage
# Build prune expression
PRUNE_EXPR=()
if (( ${#SKIP_DIRS[@]} > 0 )); then
PRUNE_EXPR+=( \( )
for i in "${!SKIP_DIRS[@]}"; do
PRUNE_EXPR+=( -type d -name "${SKIP_DIRS[$i]}" -prune )
[[ $i -lt $((${#SKIP_DIRS[@]} - 1)) ]] && PRUNE_EXPR+=( -o )
done
PRUNE_EXPR+=( \) -o )
fi
# Build pattern expression
PATTERN_EXPR=( \( )
for i in "${!PATTERNS[@]}"; do
PATTERN_EXPR+=( -name "${PATTERNS[$i]}" )
[[ $i -lt $((${#PATTERNS[@]} - 1)) ]] && PATTERN_EXPR+=( -o )
done
PATTERN_EXPR+=( \) )
# Execute
find "$ROOT" \
"${PRUNE_EXPR[@]}" \
-type f \
"${PATTERN_EXPR[@]}" \
-print0 |
while IFS= read -r -d '' file; do
printf "\n===== %s =====\n" "$file"
cat "$file"
done

190
config/shared/bin/wt Executable file
View File

@@ -0,0 +1,190 @@
#!/usr/bin/env bash
set -euo pipefail
########################################
# Utilities
########################################
fail() {
echo "Error: $1" >&2
exit 1
}
ensure_repo() {
git rev-parse --is-inside-work-tree >/dev/null 2>&1 ||
fail "Not inside a git repository"
}
repo_root() {
git rev-parse --show-toplevel
}
detect_base() {
if git show-ref --verify --quiet refs/heads/main; then
echo "main"
elif git show-ref --verify --quiet refs/heads/master; then
echo "master"
else
git branch --show-current
fi
}
ensure_clean() {
git diff --quiet || fail "Working tree is dirty"
git diff --cached --quiet || fail "Index is dirty"
}
########################################
# Core Paths
########################################
ROOT=$(repo_root)
WT_DIR="$ROOT/.worktrees"
########################################
# Commands
########################################
cmd_new() {
local name="$1"
local base="${2:-$(detect_base)}"
local path="$WT_DIR/$name"
[ -d "$path" ] && fail "Worktree directory already exists"
git show-ref --verify --quiet "refs/heads/$name" &&
fail "Branch '$name' already exists"
mkdir -p "$WT_DIR"
git worktree add -b "$name" "$path" "$base"
echo "Created worktree:"
echo " branch: $name"
echo " path: $path"
}
cmd_list() {
git worktree list
}
cmd_path() {
echo "$WT_DIR/$1"
}
cmd_rm() {
local name="$1"
local path="$WT_DIR/$name"
[ -d "$path" ] || fail "Worktree not found"
git worktree remove "$path"
git branch -D "$name" >/dev/null 2>&1 || true
echo "Removed worktree '$name'"
}
cmd_finish() {
local name="$1"
shift
local keep_worktree=0
local path="$WT_DIR/$name"
local base
while [[ $# -gt 0 ]]; do
case "$1" in
--keep-worktree)
keep_worktree=1
shift
;;
*)
fail "Unknown option for finish: $1"
;;
esac
done
[ -d "$path" ] || fail "Worktree not found"
git show-ref --verify --quiet "refs/heads/$name" ||
fail "Branch '$name' not found"
base=$(detect_base)
echo "Base branch: $base"
echo "Feature branch: $name"
git checkout "$base" >/dev/null
ensure_clean
if ! git merge --squash "$name"; then
echo
echo "Resolve conflicts, then run:"
echo " git commit"
echo " wt rm $name"
exit 1
fi
git commit -m "$name"
if [ -d "$path" ] && [ "$keep_worktree" -eq 0 ]; then
if ! git worktree remove "$path"; then
git worktree remove --force "$path" || fail "Failed to remove worktree '$name'"
fi
fi
if [ "$keep_worktree" -eq 0 ]; then
git branch -D "$name"
fi
if [ "$keep_worktree" -eq 1 ]; then
echo "Merged (squash) into '$base' and kept worktree '$path'"
else
echo "Merged (squash) and removed '$name'"
fi
}
cmd_prune() {
git worktree prune
echo "Pruned stale worktree metadata"
}
########################################
# Entry
########################################
ensure_repo
case "${1:-}" in
new)
[ $# -lt 2 ] && fail "Usage: wt new <name> [base]"
cmd_new "$2" "${3:-}"
;;
list)
cmd_list
;;
path)
[ $# -lt 2 ] && fail "Usage: wt path <name>"
cmd_path "$2"
;;
finish)
[ $# -lt 2 ] && fail "Usage: wt finish <name>"
cmd_finish "$2" "${@:3}"
;;
rm)
[ $# -lt 2 ] && fail "Usage: wt rm <name>"
cmd_rm "$2"
;;
prune)
cmd_prune
;;
*)
cat <<EOF
Usage:
wt new <name> [base]
wt list
wt path <name>
wt finish <name> [--keep-worktree]
wt rm <name>
wt prune
EOF
exit 1
;;
esac

View File

@@ -21,4 +21,3 @@
last = log -1 HEAD
tags = tag -l
undo = reset --mixed HEAD~1

View File

@@ -19,3 +19,6 @@ logs/
coverage/
.devflow/
.dev-flow/
.flow/
.local/
.worktrees/

View File

@@ -7,6 +7,9 @@ bind C-Space send-prefix
# set -s default-terminal "tmux-256color"
# set -sa terminal-overrides "$term:rgb"
set -g window-size largest
set -g aggressive-resize on
set -s escape-time 10
set -s focus-events on
set -s set-clipboard on
@@ -70,7 +73,7 @@ bind v split-window -h -c "#{pane_current_path}"
# For some reason, choose-session is what I had before and it was working; however,
# it does not appear in man page and does not allow customization
# bind o choose-session
bind o choose-tree -s -O name
bind o choose-tree -Zs -O name
bind N new-window
bind n new-window -c "#{pane_current_path}"
bind c confirm-before -p "kill-pane \#P? (y/n)" kill-pane
@@ -82,5 +85,3 @@ unbind d
bind e detach
bind d command-prompt -I "flow " 'run-shell "/home/tomas/bin/dev-tmux-wrapper.sh %1 --from #{session_name}"'

View File

@@ -3,6 +3,8 @@ export LANG=en_US.UTF-8
export LC_CTYPE=en_US.UTF-8
export LC_COLLATE=C
export EDITOR=nvim
# eval "$(dircolors)"; echo "$LS_COLORS"
export LS_COLORS='rs=0:di=01;34:ln=01;33:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=00:tw=30;42:ow=34;42:st=37;44:ex=01;32'
@@ -13,6 +15,8 @@ SAVEHIST=10000
setopt auto_cd interactive_comments prompt_subst share_history
setopt append_history hist_ignore_dups hist_ignore_all_dups hist_reduce_blanks
fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' # Case-insensitive
zstyle ':completion:*' use-cache on
@@ -76,10 +80,63 @@ alias ga='git add'
alias gcm='git commit -m'
alias gp='git push'
alias gst='git status'
alias gd='git diff --patience --color-moved=dimmed-zebra --word-diff=plain --function-context --ignore-space-change -U3'
# alias gd='git diff --patience --color-moved=dimmed-zebra --word-diff=plain --function-context --ignore-space-change -U3'
alias gd='git diff --patience --color-moved=dimmed-zebra --ignore-space-change -U5'
alias glg='git log --oneline --graph --decorate --all'
alias k='kubectl'
# opencode
export PATH=/home/tomas/.opencode/bin:$PATH
export PATH="$HOME/.opencode/bin:$PATH"
git-safe-delete() {
local branch="$1"
local base="${2:-main}"
if [[ -z "$branch" ]]; then
echo "Usage: git-safe-delete <branch> [base]"
return 1
fi
if [[ "$branch" == "$(git branch --show-current)" ]]; then
echo "Cannot delete current branch."
return 1
fi
git fetch origin >/dev/null 2>&1
if git diff --quiet "$base..$branch"; then
echo "No content differences with $base."
git branch -D "$branch"
echo "Deleted $branch"
else
echo "Branch differs from $base."
echo "Diff summary:"
git diff --stat "$base..$branch"
echo
read "confirm?Force delete anyway? (y/N): "
[[ "$confirm" == "y" ]] && git branch -D "$branch"
fi
}
_git_safe_delete() {
_arguments \
'1:local branch:($(git for-each-ref --format="%(refname:short)" refs/heads))' \
'2:base branch (optional):($(git for-each-ref --format="%(refname:short)" refs/heads))'
}
compdef _git_safe_delete git-safe-delete
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
# pnpm
export PNPM_HOME="/home/tomas/.local/share/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac
# pnpm end