refactor(homebrew): 重构 Homebrew 升级管理脚本的配色和清理策略

- 实现终端主题检测功能,支持深色/浅色模式自动切换配色方案
- 添加 256 色终端支持,优化不同背景下的颜色对比度
- 引入版本变更高亮显示,突出包名、旧版本、新版本的变化
- 集成 OSC 11 协议查询终端背景色,提升跨终端兼容性
- 将清理策略从按日期清理改为统一执行 brew cleanup --prune=all
- 移除自定义缓存清理逻辑,使用 Homebrew 内置清理机制
- 增强输出着色功能,按语义对 Homebrew 输出进行彩色标记
- 更新文档说明新的清理流程和终端配色特性
This commit is contained in:
2026-07-19 01:36:04 +08:00
parent aa85eb32c7
commit ccaff22653
2 changed files with 216 additions and 11 deletions
+3 -1
View File
@@ -104,7 +104,9 @@ HB_TERMINAL_WIDTH=130 ./brew-upgrade-manager.sh
## 终端主题与配色
主脚本默认使用 `HB_COLOR_THEME=auto`。它会优先读取终端提供的背景信息,并通过标准 OSC 11 查询兼容 Apple Terminal、iTerm2、Termius、Kitty、WezTerm、Alacritty 等常见终端;在 SSH 中,终端客户端允许响应透传时也能识别本地背景。深色背景使用偏亮色阶,浅色背景使用更深的色阶,避免黄色、青色在白底上难以辨认
主脚本默认使用 `HB_COLOR_THEME=auto`,优先跟随操作系统当前的日间/夜间外观:支持 macOS、iOS/iPadOS、Windows、WSL、Android,以及使用 freedesktop Portal、GNOME、KDE、Cinnamon 或 XFCE 的 Linux 桌面
SSH 会话会直接以客户端终端背景为准,因为远端系统的日夜状态不代表 iPhone、iPad 或 Android 客户端当前主题。其他无法读取系统外观的环境(例如容器和无桌面服务器)也会继续读取 `COLORFGBG`,并通过标准 OSC 11 查询终端当前的真实背景色。Apple Terminal、iTerm2、Termius、Blink、a-Shell、iSH、Kitty、WezTerm、Alacritty 等支持相应信息的终端都能走通用回退。深色背景使用偏亮色阶,浅色背景使用更深的色阶,避免黄色、青色在白底上难以辨认。
如果终端屏蔽了背景色查询,或者需要固定配色,可以手动覆盖:
+213 -10
View File
@@ -59,9 +59,206 @@ query_terminal_background_rgb() {
return 1
}
detect_terminal_theme() {
lowercase() {
printf '%s' "$1" | tr '[:upper:]' '[:lower:]'
}
detect_apple_appearance_theme() {
local appearance="" product_name=""
[[ "$(uname -s 2>/dev/null || true)" == "Darwin" ]] || return 1
command -v defaults >/dev/null 2>&1 || return 1
product_name="$(sw_vers -productName 2>/dev/null || true)"
appearance="$(defaults read -g AppleInterfaceStyle 2>/dev/null || true)"
if [[ -z "$appearance" && \
("$product_name" == *"iPhone"* || "$product_name" == *"iOS"* || "$product_name" == *"iPad"*) ]]; then
appearance="$(defaults read /var/mobile/Library/Preferences/.GlobalPreferences AppleInterfaceStyle 2>/dev/null || true)"
fi
case "$appearance" in
Dark|dark) printf 'dark' ;;
Light|light) printf 'light' ;;
'')
# macOS 中该键不存在代表浅色;iOS/iPadOS 无权读取时交给终端检测。
if [[ "$product_name" == *"iPhone"* || "$product_name" == *"iOS"* || "$product_name" == *"iPad"* ]]; then
return 1
fi
printf 'light'
;;
*) return 1 ;;
esac
}
detect_windows_appearance_theme() {
local powershell="" appearance=""
if command -v powershell.exe >/dev/null 2>&1; then
powershell="powershell.exe"
elif command -v powershell >/dev/null 2>&1; then
powershell="powershell"
fi
[[ -n "$powershell" ]] || return 1
# shellcheck disable=SC2016 # The single-quoted variables belong to PowerShell.
appearance="$($powershell -NoLogo -NoProfile -NonInteractive -Command \
'$theme = Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" -ErrorAction SilentlyContinue; if ($null -ne $theme.SystemUsesLightTheme) { [Console]::Write($theme.SystemUsesLightTheme) } elseif ($null -ne $theme.AppsUseLightTheme) { [Console]::Write($theme.AppsUseLightTheme) }' \
2>/dev/null || true)"
appearance="${appearance//$'\r'/}"
appearance="${appearance//[[:space:]]/}"
case "$appearance" in
0) printf 'dark' ;;
1) printf 'light' ;;
*) return 1 ;;
esac
}
theme_from_rgb_255() {
local value="$1" red green blue brightness
value="${value//,/ }"
read -r red green blue <<< "$value"
if [[ "$red" =~ ^[0-9]+$ && "$green" =~ ^[0-9]+$ && "$blue" =~ ^[0-9]+$ ]] && \
((red <= 255 && green <= 255 && blue <= 255)); then
brightness=$(((red * 299 + green * 587 + blue * 114) / 1000))
if ((brightness >= 128)); then
printf 'light'
else
printf 'dark'
fi
return 0
fi
return 1
}
detect_linux_appearance_theme() {
local setting="" setting_lower="" theme_name="" theme_name_lower=""
local kde_reader="" background=""
# 无图形会话时,gsettings 可能只返回默认值而非真实主题;此时应让
# SSH/容器继续使用终端背景检测。
if [[ -z "${XDG_CURRENT_DESKTOP:-}" && -z "${DESKTOP_SESSION:-}" && \
-z "${DISPLAY:-}" && -z "${WAYLAND_DISPLAY:-}" && \
-z "${DBUS_SESSION_BUS_ADDRESS:-}" ]]; then
return 1
fi
# freedesktop Appearance PortalGNOME、KDE 和多数 Wayland 桌面的统一接口。
if command -v gdbus >/dev/null 2>&1; then
setting="$(gdbus call --session \
--dest org.freedesktop.portal.Desktop \
--object-path /org/freedesktop/portal/desktop \
--method org.freedesktop.portal.Settings.Read \
org.freedesktop.appearance color-scheme 2>/dev/null || true)"
case "$setting" in
*'uint32 1'*) printf 'dark'; return ;;
*'uint32 2'*) printf 'light'; return ;;
esac
fi
# GNOME 42+ / Cinnamon 以及兼容 gsettings 的 GTK 桌面。
if command -v gsettings >/dev/null 2>&1; then
setting="$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null || true)"
setting_lower="$(lowercase "$setting")"
case "$setting_lower" in
*prefer-dark*) printf 'dark'; return ;;
*prefer-light*) printf 'light'; return ;;
esac
theme_name="$(gsettings get org.gnome.desktop.interface gtk-theme 2>/dev/null || true)"
if [[ -z "$theme_name" ]]; then
theme_name="$(gsettings get org.cinnamon.desktop.interface gtk-theme 2>/dev/null || true)"
fi
if [[ -n "$theme_name" ]]; then
theme_name_lower="$(lowercase "$theme_name")"
if [[ "$theme_name_lower" == *dark* ]]; then
printf 'dark'
else
printf 'light'
fi
return
fi
fi
# KDE Plasma 6/5:先看配色方案名,再读取窗口背景色作判断。
if command -v kreadconfig6 >/dev/null 2>&1; then
kde_reader="kreadconfig6"
elif command -v kreadconfig5 >/dev/null 2>&1; then
kde_reader="kreadconfig5"
fi
if [[ -n "$kde_reader" ]]; then
theme_name="$($kde_reader --file kdeglobals --group General --key ColorScheme 2>/dev/null || true)"
theme_name_lower="$(lowercase "$theme_name")"
case "$theme_name_lower" in
*dark*) printf 'dark'; return ;;
*light*) printf 'light'; return ;;
esac
background="$($kde_reader --file kdeglobals --group 'Colors:Window' --key BackgroundNormal 2>/dev/null || true)"
if [[ -n "$background" ]]; then
theme_from_rgb_255 "$background" && return
fi
fi
# XFCE 的主题名通常直接包含 Dark;存在非 Dark 主题时按浅色处理。
if command -v xfconf-query >/dev/null 2>&1; then
theme_name="$(xfconf-query -c xsettings -p /Net/ThemeName 2>/dev/null || true)"
if [[ -n "$theme_name" ]]; then
theme_name_lower="$(lowercase "$theme_name")"
if [[ "$theme_name_lower" == *dark* ]]; then
printf 'dark'
else
printf 'light'
fi
return
fi
fi
return 1
}
detect_android_appearance_theme() {
local night_mode="" night_mode_lower=""
command -v cmd >/dev/null 2>&1 || return 1
night_mode="$(cmd uimode night 2>/dev/null || true)"
night_mode_lower="$(lowercase "$night_mode")"
case "$night_mode_lower" in
*'night mode: yes'*) printf 'dark' ;;
*'night mode: no'*) printf 'light' ;;
*) return 1 ;;
esac
}
detect_system_appearance_theme() {
local kernel
kernel="$(uname -s 2>/dev/null || true)"
case "$kernel" in
Darwin)
detect_apple_appearance_theme
;;
Linux)
if [[ -n "${WSL_DISTRO_NAME:-}" || "$(uname -r 2>/dev/null || true)" == *[Mm]icrosoft* ]]; then
detect_windows_appearance_theme && return
fi
if [[ -n "${ANDROID_ROOT:-}" || -n "${TERMUX_VERSION:-}" ]]; then
detect_android_appearance_theme && return
fi
detect_linux_appearance_theme
;;
MINGW*|MSYS*|CYGWIN*)
detect_windows_appearance_theme
;;
FreeBSD|OpenBSD|NetBSD|DragonFly|SunOS)
# BSD/Unix 桌面也可能提供 freedesktop、GTK、KDE 或 XFCE 接口。
detect_linux_appearance_theme
;;
*)
return 1
;;
esac
}
detect_color_theme() {
local requested="${HB_COLOR_THEME:-auto}" background_index="" rgb=""
local red green blue brightness
local red green blue brightness system_theme=""
case "$requested" in
dark|light)
@@ -72,6 +269,17 @@ detect_terminal_theme() {
*) requested=auto ;;
esac
# 本地运行优先跟随操作系统外观。SSH 中远端系统状态不代表客户端
# (例如 iOS/Android 上的 Termius),因此直接交给后面的终端背景检测。
if [[ -z "${SSH_TTY:-}" && -z "${SSH_CONNECTION:-}" && -z "${SSH_CLIENT:-}" ]]; then
system_theme="$(detect_system_appearance_theme || true)"
if [[ "$system_theme" == "dark" || "$system_theme" == "light" ]]; then
printf '%s' "$system_theme"
return
fi
fi
# 系统状态读取失败时,再查询终端自身提供的背景信息。
# COLORFGBG 的最后一项是背景色索引,常见终端会主动提供。
if [[ -n "${COLORFGBG:-}" ]]; then
background_index="${COLORFGBG##*[;:]}"
@@ -115,20 +323,15 @@ detect_terminal_theme() {
return
fi
# 终端未报告背景时,用 macOS 外观作合理回退;其他平台默认深色
if [[ "$(uname -s 2>/dev/null || true)" == "Darwin" ]] && \
[[ "$(defaults read -g AppleInterfaceStyle 2>/dev/null || true)" != "Dark" ]]; then
printf 'light'
else
printf 'dark'
fi
# 所有自动检测均不可用时默认深色,也可用 HB_COLOR_THEME 手动覆盖
printf 'dark'
}
COLOR_THEME="none"
if [[ -t 1 ]]; then
COLOR_COUNT="$(tput colors 2>/dev/null || true)"
[[ "$COLOR_COUNT" =~ ^[0-9]+$ ]] || COLOR_COUNT=8
COLOR_THEME="$(detect_terminal_theme)"
COLOR_THEME="$(detect_color_theme)"
if ((COLOR_COUNT >= 256)) && [[ "$COLOR_THEME" == "light" ]]; then
# 浅色背景使用更深的色阶,尤其避免亮黄、亮青在白底上失去对比。
RED='\033[38;5;124m'