Created
October 13, 2025 13:06
-
-
Save ijse/a66c16a9e85d85f4362ee8916071048f to your computer and use it in GitHub Desktop.
修改当前终端提示PS1, 使展示当前Git分支所关联的飞书项目任务信息,每次切换分支时更新
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -e | |
| # ==================== 配置项 ==================== | |
| # 缓存过期时间(秒) | |
| CACHE_TTL=300 | |
| # 分支匹配规则(正则表达式) | |
| BRANCH_PATTERN="^(story|issue)-([0-9]+)$" | |
| # API 接口地址模板({type} 和 {id} 会被替换) | |
| API_URL_TEMPLATE="https://****/fsp/{type}/{id}/doc" | |
| # jq 提取字段路径 | |
| JQ_EXTRACT_PATH=".name" | |
| # 缓存目录名 | |
| CACHE_DIR_NAME=".task_prompt_cache" | |
| # ==================== Git Hook 脚本 ==================== | |
| HOOK_CONTENT='#!/usr/bin/env bash | |
| # 配置项(从主脚本注入) | |
| CACHE_TTL='"$CACHE_TTL"' | |
| BRANCH_PATTERN="'"$BRANCH_PATTERN"'" | |
| API_URL_TEMPLATE="'"$API_URL_TEMPLATE"'" | |
| JQ_EXTRACT_PATH="'"$JQ_EXTRACT_PATH"'" | |
| CACHE_DIR_NAME="'"$CACHE_DIR_NAME"'" | |
| # ==================== 主逻辑 ==================== | |
| CACHE_DIR=".git/$CACHE_DIR_NAME" | |
| branch=$(git symbolic-ref --short HEAD 2>/dev/null) | |
| now=$(date +%s) | |
| # 创建缓存目录 | |
| mkdir -p "$CACHE_DIR" | |
| # 对分支名进行安全编码,用于文件名 | |
| branch_encoded=$(echo "$branch" | sed "s/\//_/g") | |
| CACHE_FILE="$CACHE_DIR/$branch_encoded" | |
| # 检查该分支的缓存是否有效 | |
| if [[ -f "$CACHE_FILE" ]]; then | |
| source "$CACHE_FILE" | |
| # 验证缓存的分支名与当前分支匹配,且未过期 | |
| if [[ "$branch_cached" == "$branch" && $((now - timestamp)) -lt CACHE_TTL ]]; then | |
| exit 0 | |
| fi | |
| fi | |
| # 请求接口 | |
| if [[ $branch =~ $BRANCH_PATTERN ]]; then | |
| type=${BASH_REMATCH[1]} | |
| id=${BASH_REMATCH[2]} | |
| # 替换 URL 模板中的占位符 | |
| url="${API_URL_TEMPLATE//\{type\}/$type}" | |
| url="${url//\{id\}/$id}" | |
| # 使用 jq 提取任务名称 | |
| name=$(curl -s "$url" | jq -r "$JQ_EXTRACT_PATH // empty") | |
| else | |
| name="" | |
| fi | |
| # 更新该分支的缓存 | |
| cat > "$CACHE_FILE" <<EOF | |
| branch_cached=$branch | |
| name=$name | |
| timestamp=$now | |
| EOF | |
| ' | |
| # ==================== Shell 提示符配置 ==================== | |
| SHELL_SNIPPET=' | |
| # >>> git-task-prompt start >>> | |
| setopt prompt_subst 2>/dev/null || true | |
| # 配置项 | |
| CACHE_DIR_NAME="'"$CACHE_DIR_NAME"'" | |
| task_prompt_display() { | |
| local cache_dir=".git/$CACHE_DIR_NAME" | |
| local branch=$(git symbolic-ref --short HEAD 2>/dev/null) | |
| [[ -z "$branch" ]] && return | |
| # 对分支名进行安全编码 | |
| local branch_encoded=$(echo "$branch" | sed "s/\//_/g") | |
| local cache_file="$cache_dir/$branch_encoded" | |
| [[ -f "$cache_file" ]] || return | |
| source "$cache_file" | |
| # 验证缓存的分支名与当前分支匹配 | |
| [[ "$branch_cached" == "$branch" && -n "$name" ]] && echo "%{$fg[green]%}[$name]\n %{$reset_color%}" | |
| } | |
| # 动态多行提示符 | |
| PROMPT="$(task_prompt_display) %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)" | |
| # <<< git-task-prompt end <<< | |
| ' | |
| # ==================== 安装函数 ==================== | |
| # ==================== 安装函数 ==================== | |
| install_hooks() { | |
| local hook_dir | |
| hook_dir="$(git rev-parse --git-dir)/hooks" | |
| echo "Installing git hooks to: $hook_dir" | |
| echo "$HOOK_CONTENT" > "$hook_dir/post-checkout" | |
| echo "$HOOK_CONTENT" > "$hook_dir/post-switch" | |
| chmod +x "$hook_dir/post-checkout" "$hook_dir/post-switch" | |
| echo "✅ Git hooks installed." | |
| } | |
| inject_shell_snippet() { | |
| local installed=false | |
| for rcfile in ~/.bashrc ~/.zshrc; do | |
| [[ -f "$rcfile" ]] || continue | |
| if grep -q ">>> git-task-prompt start >>>" "$rcfile"; then | |
| echo "⏭ $rcfile already contains configuration, skipping." | |
| else | |
| echo "📝 Injecting shell config into $rcfile" | |
| echo "$SHELL_SNIPPET" >> "$rcfile" | |
| installed=true | |
| fi | |
| done | |
| [[ "$installed" == true ]] && echo "✅ Shell snippet injected." | |
| } | |
| # ==================== 卸载函数 ==================== | |
| remove_hooks() { | |
| local hook_dir | |
| hook_dir="$(git rev-parse --git-dir)/hooks" | |
| local removed=false | |
| for file in post-checkout post-switch; do | |
| if [[ -f "$hook_dir/$file" ]]; then | |
| rm -f "$hook_dir/$file" | |
| echo "🗑 Removed $hook_dir/$file" | |
| removed=true | |
| fi | |
| done | |
| # 清理缓存目录 | |
| local cache_dir="$(git rev-parse --git-dir)/$CACHE_DIR_NAME" | |
| if [[ -d "$cache_dir" ]]; then | |
| rm -rf "$cache_dir" | |
| echo "🗑 Removed cache directory: $cache_dir" | |
| removed=true | |
| fi | |
| [[ "$removed" == true ]] && echo "✅ Git hooks and cache removed." | |
| } | |
| remove_shell_snippet() { | |
| local removed=false | |
| for rcfile in ~/.bashrc ~/.zshrc; do | |
| [[ -f "$rcfile" ]] || continue | |
| if grep -q ">>> git-task-prompt start >>>" "$rcfile"; then | |
| sed -i.bak '/>>> git-task-prompt start >>>/,/<<< git-task-prompt end <<</d' "$rcfile" | |
| echo "🗑 Removed git-task-prompt snippet from $rcfile" | |
| removed=true | |
| fi | |
| done | |
| [[ "$removed" == true ]] && echo "✅ Shell snippet removed." | |
| } | |
| # ==================== 主程序 ==================== | |
| case "$1" in | |
| install) | |
| echo "🚀 Installing git-task-prompt..." | |
| install_hooks | |
| inject_shell_snippet | |
| echo "" | |
| echo "✅ git-task-prompt installed successfully!" | |
| echo "💡 Please restart your terminal or run: source ~/.zshrc" | |
| ;; | |
| uninstall) | |
| echo "🧹 Uninstalling git-task-prompt..." | |
| remove_hooks | |
| remove_shell_snippet | |
| echo "" | |
| echo "✅ git-task-prompt uninstalled." | |
| ;; | |
| *) | |
| echo "Usage: $0 {install|uninstall}" | |
| echo "" | |
| echo "Commands:" | |
| echo " install - Install git hooks and shell prompt configuration" | |
| echo " uninstall - Remove all git-task-prompt files and configurations" | |
| exit 1 | |
| ;; | |
| esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment