Skip to content

Instantly share code, notes, and snippets.

@frankdugan3
Created June 11, 2025 17:18
Show Gist options
  • Save frankdugan3/ec02a823ee07a711894bee2c87e2b10c to your computer and use it in GitHub Desktop.
Save frankdugan3/ec02a823ee07a711894bee2c87e2b10c to your computer and use it in GitHub Desktop.
#!/bin/sh
set -eu
# --- Helper: Convert snake_case to PascalCase ---
snake_to_pascal() {
echo "$1" | awk -F_ '{
for (i = 1; i <= NF; i++) {
$i = toupper(substr($i, 1, 1)) substr($i, 2)
}
print $0
}' OFS=""
}
# --- Validate and normalize root directory ---
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <project_root_directory>" >&2
exit 1
fi
# Expand path to absolute
PROJECT_ROOT=$(cd "$1" 2>/dev/null && pwd)
if [ ! -d "$PROJECT_ROOT" ]; then
echo "Error: '$1' is not a valid directory." >&2
exit 1
fi
cd "$PROJECT_ROOT"
ROOT_NAME=$(basename "$PROJECT_ROOT")
# --- Prompt for inputs with gum ---
OLD_SNAKE=$(gum input --prompt "Old project name: " --value "$ROOT_NAME")
OLD_PASCAL=$(gum input --prompt "Old module name: " --value "$(snake_to_pascal "$OLD_SNAKE")")
NEW_SNAKE=$(gum input --prompt "New project name: ")
NEW_PASCAL=$(gum input --prompt "New module name: " --value "$(snake_to_pascal "$NEW_SNAKE")")
# --- Confirm renaming ---
if ! gum confirm "Rename $OLD_SNAKE / $OLD_PASCAL to $NEW_SNAKE / $NEW_PASCAL?"; then
exit 1
fi
# --- Ask whether to include .git folder ---
RENAME_GIT="yes"
if gum confirm "Also rename inside the .git folder?" --default=true; then
RENAME_GIT="yes"
else
RENAME_GIT="no"
fi
# --- Construct ripgrep ignore flags ---
RG_IGNORE="
--glob=!_build/**
--glob=!deps/**
--glob=!.elixir_ls/**
--glob=!node_modules/**
"
if [ "$RENAME_GIT" = "no" ]; then
RG_IGNORE="$RG_IGNORE --glob=!.git/**"
fi
# --- Replace file contents ---
echo "Updating file contents..."
# shellcheck disable=SC2086
eval rg --files --hidden $RG_IGNORE | while IFS= read -r file; do
sed -i "s/$OLD_SNAKE/$NEW_SNAKE/g" "$file"
sed -i "s/$OLD_PASCAL/$NEW_PASCAL/g" "$file"
done
# --- Rename files and directories ---
echo "Renaming files and directories..."
# shellcheck disable=SC2010
find . -depth \
\( -path "./_build" -o -path "./deps" -o -path "./.elixir_ls" -o -path "./node_modules" \
$( [ "$RENAME_GIT" = "no" ] && printf '%s' '-o -path "./.git"' ) \
\) -prune -o -print | while IFS= read -r path; do
base_name=$(basename "$path")
dir_name=$(dirname "$path")
new_base_name=$(echo "$base_name" | sed "s/$OLD_SNAKE/$NEW_SNAKE/g" | sed "s/$OLD_PASCAL/$NEW_PASCAL/g")
if [ "$new_base_name" != "$base_name" ]; then
mv "$path" "$dir_name/$new_base_name"
fi
done
# --- Rename the root directory ---
cd ..
NEW_ROOT=$(echo "$ROOT_NAME" | sed "s/$OLD_SNAKE/$NEW_SNAKE/g" | sed "s/$OLD_PASCAL/$NEW_PASCAL/g")
mv "$PROJECT_ROOT" "$NEW_ROOT"
cd "$NEW_ROOT"
exec "$SHELL"
# --- Run post-commands (safe to fail) ---
direnv allow 2>/dev/null || true
mise trust 2>/dev/null || true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment