refactor(core): ♻️ 优化终端宽度检测逻辑为动态获取
通过引入 terminal_width 函数,将原本固定的终端宽度检测逻辑重构为动态获取。当未指定固定宽度时,脚本将实时读取当前终端窗口尺寸,提升了在不同交互环境下(如窗口缩放)的显示适配能力。 同时更新了配套文档,明确了命令行参数、环境变量与动态检测之间的优先级关系。
This commit is contained in:
@@ -42,7 +42,7 @@ chmod +x brew-upgrade-manager.sh
|
|||||||
./brew-upgrade-manager.sh
|
./brew-upgrade-manager.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
指定终端宽度:
|
默认会动态读取当前终端宽度;运行过程中缩放窗口时,`brew cu` 的 PTY 尺寸也会跟随更新。如果遇到非交互环境或某些表格渲染异常,可以指定固定终端宽度:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./brew-upgrade-manager.sh --width 130
|
./brew-upgrade-manager.sh --width 130
|
||||||
@@ -55,7 +55,7 @@ chmod +x brew-upgrade-manager.sh
|
|||||||
HB_TERMINAL_WIDTH=130 ./brew-upgrade-manager.sh
|
HB_TERMINAL_WIDTH=130 ./brew-upgrade-manager.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
优先级为:命令行 `--width` 高于 `HB_TERMINAL_WIDTH`,再高于自动检测值。
|
优先级为:命令行 `--width` 高于 `HB_TERMINAL_WIDTH`。两者都不设置时使用动态终端宽度。
|
||||||
|
|
||||||
## sudo 认证
|
## sudo 认证
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ brew tap buo/cask-upgrade
|
|||||||
|
|
||||||
### 表格渲染或 Ruby 报终端宽度错误
|
### 表格渲染或 Ruby 报终端宽度错误
|
||||||
|
|
||||||
使用固定宽度运行:
|
默认会跟随终端窗口变化;如果某些环境无法正确报告窗口尺寸,可以使用固定宽度运行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./brew-upgrade-manager.sh --width 130
|
./brew-upgrade-manager.sh --width 130
|
||||||
|
|||||||
@@ -53,21 +53,33 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# 确定最终的 TERMINAL_WIDTH
|
FIXED_TERMINAL_WIDTH=""
|
||||||
if [[ -n "$TERMINAL_WIDTH_OVERRIDE" ]]; then
|
if [[ -n "$TERMINAL_WIDTH_OVERRIDE" ]]; then
|
||||||
TERMINAL_WIDTH="$TERMINAL_WIDTH_OVERRIDE"
|
FIXED_TERMINAL_WIDTH="$TERMINAL_WIDTH_OVERRIDE"
|
||||||
elif [[ -n "$HB_TERMINAL_WIDTH" && "$HB_TERMINAL_WIDTH" =~ ^[0-9]+$ ]]; then
|
elif [[ -n "$HB_TERMINAL_WIDTH" && "$HB_TERMINAL_WIDTH" =~ ^[0-9]+$ ]]; then
|
||||||
TERMINAL_WIDTH="$HB_TERMINAL_WIDTH"
|
FIXED_TERMINAL_WIDTH="$HB_TERMINAL_WIDTH"
|
||||||
elif command -v stty &>/dev/null && stty size &>/dev/null; then
|
|
||||||
TERMINAL_WIDTH=$(stty size 2>/dev/null | awk '{print $2}')
|
|
||||||
if [[ -z "$TERMINAL_WIDTH" || "$TERMINAL_WIDTH" -le 0 ]]; then
|
|
||||||
TERMINAL_WIDTH=$(tput cols 2>/dev/null || echo "$DEFAULT_FALLBACK_WIDTH")
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
TERMINAL_WIDTH=$(tput cols 2>/dev/null || echo "$DEFAULT_FALLBACK_WIDTH")
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
separator() { printf '=%.0s' $(seq 1 "$TERMINAL_WIDTH"); printf "\n"; }
|
terminal_width() {
|
||||||
|
local width=""
|
||||||
|
if [[ -n "$FIXED_TERMINAL_WIDTH" ]]; then
|
||||||
|
printf "%s" "$FIXED_TERMINAL_WIDTH"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v stty &>/dev/null && stty size &>/dev/null; then
|
||||||
|
width=$(stty size 2>/dev/null | awk '{print $2}')
|
||||||
|
fi
|
||||||
|
if [[ -z "$width" || "$width" -le 0 ]]; then
|
||||||
|
width=$(tput cols 2>/dev/null || echo "$DEFAULT_FALLBACK_WIDTH")
|
||||||
|
fi
|
||||||
|
if [[ -z "$width" || "$width" -le 0 ]]; then
|
||||||
|
width="$DEFAULT_FALLBACK_WIDTH"
|
||||||
|
fi
|
||||||
|
printf "%s" "$width"
|
||||||
|
}
|
||||||
|
|
||||||
|
separator() { local width; width=$(terminal_width); printf '=%.0s' $(seq 1 "$width"); printf "\n"; }
|
||||||
print_header() { echo -e "${BLUE}$1${NC}"; }
|
print_header() { echo -e "${BLUE}$1${NC}"; }
|
||||||
|
|
||||||
# ================== 流程开始 ==================
|
# ================== 流程开始 ==================
|
||||||
@@ -113,13 +125,18 @@ echo -e "\n${CYAN}>>> [2/2] Upgrading GUI Casks (brew cu -yaq)...${NC}"
|
|||||||
# 强制注入环境变量,确保终端输出依然保留 ANSI 颜色格式
|
# 强制注入环境变量,确保终端输出依然保留 ANSI 颜色格式
|
||||||
export HOMEBREW_COLOR=1
|
export HOMEBREW_COLOR=1
|
||||||
|
|
||||||
# --- 核心修复:环境变量宽度兜底 ---
|
# --- 终端宽度处理 ---
|
||||||
# 强制将 Bash 计算好的真实终端宽度传递给底层,防止 Ruby 绘表时发生 negative argument 崩溃
|
# 交互式终端里让子进程读取 PTY 的实时尺寸;非交互环境或固定宽度模式下提供 COLUMNS 兜底。
|
||||||
export COLUMNS="$TERMINAL_WIDTH"
|
if [[ -n "$FIXED_TERMINAL_WIDTH" || ! -t 1 ]]; then
|
||||||
|
export COLUMNS
|
||||||
|
COLUMNS="$(terminal_width)"
|
||||||
|
else
|
||||||
|
unset COLUMNS
|
||||||
|
fi
|
||||||
|
|
||||||
# 使用 Python 原生 PTY 自建极简转发引擎。它只转发用户输入,不保存、不注入 sudo 密码。
|
# 使用 Python 原生 PTY 自建极简转发引擎。它只转发用户输入,不保存、不注入 sudo 密码。
|
||||||
python3 -c '
|
python3 -c '
|
||||||
import pty, os, sys, select, fcntl, termios, struct, tty
|
import pty, os, sys, select, fcntl, termios, struct, tty, signal
|
||||||
|
|
||||||
cmd = sys.argv[1:]
|
cmd = sys.argv[1:]
|
||||||
pid, fd = pty.fork()
|
pid, fd = pty.fork()
|
||||||
@@ -127,12 +144,30 @@ pid, fd = pty.fork()
|
|||||||
if pid == 0:
|
if pid == 0:
|
||||||
os.execvp(cmd[0], cmd)
|
os.execvp(cmd[0], cmd)
|
||||||
else:
|
else:
|
||||||
try:
|
def sync_winsize(*_):
|
||||||
s = struct.pack("HHHH", 0, 0, 0, 0)
|
s = struct.pack("HHHH", 0, 0, 0, 0)
|
||||||
winsize = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s)
|
try:
|
||||||
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
|
winsize = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s)
|
||||||
except Exception:
|
rows, cols, xpix, ypix = struct.unpack("HHHH", winsize)
|
||||||
pass
|
if rows > 0 and cols > 0:
|
||||||
|
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
fallback_cols = int(os.environ.get("COLUMNS", "130") or "130")
|
||||||
|
except ValueError:
|
||||||
|
fallback_cols = 130
|
||||||
|
try:
|
||||||
|
fallback_rows = int(os.environ.get("LINES", "40") or "40")
|
||||||
|
except ValueError:
|
||||||
|
fallback_rows = 40
|
||||||
|
fallback = struct.pack("HHHH", fallback_rows, fallback_cols, 0, 0)
|
||||||
|
fcntl.ioctl(fd, termios.TIOCSWINSZ, fallback)
|
||||||
|
|
||||||
|
sync_winsize()
|
||||||
|
signal.signal(signal.SIGWINCH, sync_winsize)
|
||||||
|
|
||||||
stdin_fd = sys.stdin.fileno()
|
stdin_fd = sys.stdin.fileno()
|
||||||
stdout_fd = sys.stdout.fileno()
|
stdout_fd = sys.stdout.fileno()
|
||||||
@@ -149,7 +184,10 @@ else:
|
|||||||
watch = [fd]
|
watch = [fd]
|
||||||
if forward_stdin:
|
if forward_stdin:
|
||||||
watch.append(stdin_fd)
|
watch.append(stdin_fd)
|
||||||
rfds, _, _ = select.select(watch, [], [], 0.1)
|
try:
|
||||||
|
rfds, _, _ = select.select(watch, [], [], 0.1)
|
||||||
|
except InterruptedError:
|
||||||
|
continue
|
||||||
|
|
||||||
if fd in rfds:
|
if fd in rfds:
|
||||||
data = os.read(fd, 8192)
|
data = os.read(fd, 8192)
|
||||||
|
|||||||
Reference in New Issue
Block a user