mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
feat: add optional terminal environment setup
This commit is contained in:
+319
-5
@@ -4,7 +4,13 @@ set -u
|
||||
|
||||
PACKAGE_SOURCE=${PI_PACKAGE_SOURCE:-git:git@bitbucket.org:siakitem/my-pi.git}
|
||||
CODEGRAPH_INSTALL_URL=https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh
|
||||
KITTY_INSTALL_URL=https://sw.kovidgoyal.net/kitty/installer.sh
|
||||
OH_MY_ZSH_INSTALL_URL=https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
|
||||
POWERLEVEL10K_REPOSITORY=https://github.com/romkatv/powerlevel10k.git
|
||||
ZSH_AUTOSUGGESTIONS_REPOSITORY=https://github.com/zsh-users/zsh-autosuggestions.git
|
||||
ZSH_SYNTAX_HIGHLIGHTING_REPOSITORY=https://github.com/zsh-users/zsh-syntax-highlighting.git
|
||||
install_failed=0
|
||||
zshrc_backup_done=0
|
||||
|
||||
say() {
|
||||
printf '%s\n' "$*"
|
||||
@@ -14,9 +20,9 @@ warn() {
|
||||
printf '警告: %s\n' "$*" >&2
|
||||
}
|
||||
|
||||
ask_to_install() {
|
||||
dependency=$1
|
||||
printf '未检测到 %s。是否现在安装?[y/N] ' "$dependency"
|
||||
ask_yes_no() {
|
||||
prompt=$1
|
||||
printf '%s [y/N] ' "$prompt"
|
||||
if ! IFS= read -r answer; then
|
||||
answer=n
|
||||
fi
|
||||
@@ -26,6 +32,14 @@ ask_to_install() {
|
||||
esac
|
||||
}
|
||||
|
||||
ask_to_install() {
|
||||
ask_yes_no "未检测到 $1。是否现在安装?"
|
||||
}
|
||||
|
||||
ask_to_enable() {
|
||||
ask_yes_no "尚未启用 $1。是否现在安装所需文件并启用?"
|
||||
}
|
||||
|
||||
require_brew() {
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
return 0
|
||||
@@ -93,6 +107,246 @@ install_jdtls() {
|
||||
command -v jdtls >/dev/null 2>&1
|
||||
}
|
||||
|
||||
detect_kitty() {
|
||||
kitty_bin=
|
||||
if command -v kitty >/dev/null 2>&1; then
|
||||
kitty_bin=$(command -v kitty)
|
||||
return 0
|
||||
fi
|
||||
for candidate in /Applications/kitty.app/Contents/MacOS/kitty "$HOME/.local/kitty.app/bin/kitty"; do
|
||||
if [ -x "$candidate" ]; then
|
||||
kitty_bin=$candidate
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
install_kitty() {
|
||||
case $(uname -s) in
|
||||
Darwin)
|
||||
require_brew || return 1
|
||||
brew install --cask kitty || return 1
|
||||
;;
|
||||
*)
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
warn "安装 Kitty 需要 curl。"
|
||||
return 1
|
||||
fi
|
||||
curl -L "$KITTY_INSTALL_URL" | sh /dev/stdin || return 1
|
||||
;;
|
||||
esac
|
||||
detect_kitty
|
||||
}
|
||||
|
||||
resolve_kitty_config_dir() {
|
||||
kitty_config_dir=${KITTY_CONFIG_DIRECTORY:-${XDG_CONFIG_HOME:-$HOME/.config}/kitty}
|
||||
}
|
||||
|
||||
kitty_solarized_dark_configured() {
|
||||
resolve_kitty_config_dir
|
||||
[ -f "$kitty_config_dir/current-theme.conf" ] || return 1
|
||||
[ -f "$kitty_config_dir/kitty.conf" ] || return 1
|
||||
grep -F "Solarized Dark" "$kitty_config_dir/current-theme.conf" >/dev/null 2>&1 || return 1
|
||||
grep -E '^[[:space:]]*include[[:space:]]+([^#[:space:]]*/)?current-theme\.conf([[:space:]]*(#.*)?)?$' \
|
||||
"$kitty_config_dir/kitty.conf" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
configure_kitty_solarized_dark() {
|
||||
"$kitty_bin" +kitten themes --reload-in=none "Solarized Dark"
|
||||
}
|
||||
|
||||
resolve_zsh_paths() {
|
||||
oh_my_zsh_dir=${ZSH:-$HOME/.oh-my-zsh}
|
||||
zsh_custom_dir=${ZSH_CUSTOM:-$oh_my_zsh_dir/custom}
|
||||
zshrc_file=${ZDOTDIR:-$HOME}/.zshrc
|
||||
}
|
||||
|
||||
oh_my_zsh_installed() {
|
||||
resolve_zsh_paths
|
||||
[ -f "$oh_my_zsh_dir/oh-my-zsh.sh" ]
|
||||
}
|
||||
|
||||
install_oh_my_zsh() {
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
warn "安装 Oh My Zsh 需要 curl。"
|
||||
return 1
|
||||
fi
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
warn "安装 Oh My Zsh 需要 git。"
|
||||
return 1
|
||||
fi
|
||||
resolve_zsh_paths
|
||||
oh_my_zsh_installer=$(curl -fsSL "$OH_MY_ZSH_INSTALL_URL") || return 1
|
||||
RUNZSH=no CHSH=no KEEP_ZSHRC=yes ZSH="$oh_my_zsh_dir" \
|
||||
sh -c "$oh_my_zsh_installer" "" --unattended --keep-zshrc || return 1
|
||||
oh_my_zsh_installed
|
||||
}
|
||||
|
||||
prepare_zshrc() {
|
||||
resolve_zsh_paths
|
||||
zshrc_dir=${zshrc_file%/*}
|
||||
[ "$zshrc_dir" = "$zshrc_file" ] && zshrc_dir=.
|
||||
mkdir -p "$zshrc_dir" || return 1
|
||||
if [ ! -f "$zshrc_file" ]; then
|
||||
: > "$zshrc_file" || return 1
|
||||
fi
|
||||
if [ "$zshrc_backup_done" -eq 0 ]; then
|
||||
zshrc_backup="$zshrc_file.my-pi-backup-$(date +%Y%m%d%H%M%S)"
|
||||
cp "$zshrc_file" "$zshrc_backup" || return 1
|
||||
zshrc_backup_done=1
|
||||
say "已备份现有 Zsh 配置到 $zshrc_backup"
|
||||
fi
|
||||
}
|
||||
|
||||
zshrc_has_oh_my_zsh_loader() {
|
||||
[ -f "$zshrc_file" ] || return 1
|
||||
grep -E '^[[:space:]]*(source|\.)[[:space:]].*oh-my-zsh\.sh' "$zshrc_file" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
ensure_oh_my_zsh_loader() {
|
||||
prepare_zshrc || return 1
|
||||
if zshrc_has_oh_my_zsh_loader; then
|
||||
return 0
|
||||
fi
|
||||
{
|
||||
printf '\n# Oh My Zsh (managed by my-pi install.sh)\n'
|
||||
printf 'export ZSH="%s"\n' "$oh_my_zsh_dir"
|
||||
printf '%s\n' "source \"\$ZSH/oh-my-zsh.sh\""
|
||||
} >> "$zshrc_file"
|
||||
}
|
||||
|
||||
set_powerlevel10k_theme() {
|
||||
prepare_zshrc || return 1
|
||||
tmp_file=$(mktemp "${TMPDIR:-/tmp}/my-pi-zshrc.XXXXXX") || return 1
|
||||
if ! awk '
|
||||
BEGIN { inserted = 0 }
|
||||
/^[[:space:]]*ZSH_THEME[[:space:]]*=/ { next }
|
||||
!inserted && /^[[:space:]]*(source|\.)[[:space:]].*oh-my-zsh\.sh/ {
|
||||
print "ZSH_THEME=\"powerlevel10k/powerlevel10k\""
|
||||
inserted = 1
|
||||
}
|
||||
{ print }
|
||||
END {
|
||||
if (!inserted) print "ZSH_THEME=\"powerlevel10k/powerlevel10k\""
|
||||
}
|
||||
' "$zshrc_file" > "$tmp_file"; then
|
||||
rm -f "$tmp_file"
|
||||
return 1
|
||||
fi
|
||||
cp "$tmp_file" "$zshrc_file" || {
|
||||
rm -f "$tmp_file"
|
||||
return 1
|
||||
}
|
||||
rm -f "$tmp_file"
|
||||
}
|
||||
|
||||
p10k_config_sourced() {
|
||||
[ -f "$zshrc_file" ] || return 1
|
||||
grep -E '^[[:space:]]*\[\[[[:space:]].*\.p10k\.zsh.*source[[:space:]].*\.p10k\.zsh' \
|
||||
"$zshrc_file" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
ensure_p10k_config_source() {
|
||||
if p10k_config_sourced; then
|
||||
return 0
|
||||
fi
|
||||
printf '\n# Powerlevel10k preset (managed by my-pi install.sh)\n[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh\n' \
|
||||
>> "$zshrc_file"
|
||||
}
|
||||
|
||||
configure_powerlevel10k() {
|
||||
resolve_zsh_paths
|
||||
powerlevel10k_dir=$zsh_custom_dir/themes/powerlevel10k
|
||||
if [ ! -f "$powerlevel10k_dir/powerlevel10k.zsh-theme" ]; then
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
warn "安装 Powerlevel10k 需要 git。"
|
||||
return 1
|
||||
fi
|
||||
mkdir -p "$zsh_custom_dir/themes" || return 1
|
||||
git clone --depth=1 "$POWERLEVEL10K_REPOSITORY" "$powerlevel10k_dir" || return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$HOME/.p10k.zsh" ]; then
|
||||
sed 's/POWERLEVEL9K_MODE=nerdfont-complete/POWERLEVEL9K_MODE=ascii/' \
|
||||
"$powerlevel10k_dir/config/p10k-lean.zsh" > "$HOME/.p10k.zsh" || return 1
|
||||
say "已写入 Powerlevel10k Lean/ASCII 预设,首次启动不会进入配置向导。"
|
||||
fi
|
||||
set_powerlevel10k_theme || return 1
|
||||
ensure_oh_my_zsh_loader || return 1
|
||||
ensure_p10k_config_source
|
||||
}
|
||||
|
||||
zsh_plugin_enabled() {
|
||||
plugin=$1
|
||||
[ -f "$zshrc_file" ] || return 1
|
||||
awk -v target="$plugin" '
|
||||
{
|
||||
line = $0
|
||||
sub(/[[:space:]]*#.*/, "", line)
|
||||
if (line ~ /^[[:space:]]*plugins[[:space:]]*[+]?=/) active = 1
|
||||
if (active) {
|
||||
gsub(/[()=+]/, " ", line)
|
||||
count = split(line, fields, /[[:space:]]+/)
|
||||
for (i = 1; i <= count; i++) if (fields[i] == target) found = 1
|
||||
if ($0 ~ /\)/) active = 0
|
||||
}
|
||||
}
|
||||
END { exit(found ? 0 : 1) }
|
||||
' "$zshrc_file"
|
||||
}
|
||||
|
||||
add_zsh_plugin() {
|
||||
plugin=$1
|
||||
prepare_zshrc || return 1
|
||||
ensure_oh_my_zsh_loader || return 1
|
||||
tmp_file=$(mktemp "${TMPDIR:-/tmp}/my-pi-zshrc.XXXXXX") || return 1
|
||||
if ! awk -v plugin="$plugin" '
|
||||
BEGIN { added = 0 }
|
||||
!added && /^[[:space:]]*(source|\.)[[:space:]].*oh-my-zsh\.sh/ {
|
||||
print "plugins+=(" plugin ")"
|
||||
added = 1
|
||||
}
|
||||
{ print }
|
||||
END { if (!added) print "plugins+=(" plugin ")" }
|
||||
' "$zshrc_file" > "$tmp_file"; then
|
||||
rm -f "$tmp_file"
|
||||
return 1
|
||||
fi
|
||||
cp "$tmp_file" "$zshrc_file" || {
|
||||
rm -f "$tmp_file"
|
||||
return 1
|
||||
}
|
||||
rm -f "$tmp_file"
|
||||
}
|
||||
|
||||
install_and_enable_zsh_plugin() {
|
||||
plugin=$1
|
||||
repository=${2:-}
|
||||
if [ -n "$repository" ] && [ ! -d "$zsh_custom_dir/plugins/$plugin" ]; then
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
warn "安装 $plugin 需要 git。"
|
||||
return 1
|
||||
fi
|
||||
mkdir -p "$zsh_custom_dir/plugins" || return 1
|
||||
git clone --depth=1 "$repository" "$zsh_custom_dir/plugins/$plugin" || return 1
|
||||
fi
|
||||
add_zsh_plugin "$plugin"
|
||||
}
|
||||
|
||||
check_zsh_plugin() {
|
||||
plugin=$1
|
||||
description=$2
|
||||
repository=${3:-}
|
||||
if zsh_plugin_enabled "$plugin"; then
|
||||
say "✓ $plugin 已启用"
|
||||
elif ask_to_enable "$description"; then
|
||||
install_and_enable_zsh_plugin "$plugin" "$repository" || record_install_failure "$plugin"
|
||||
else
|
||||
say "- 已跳过 ${plugin}。"
|
||||
fi
|
||||
}
|
||||
|
||||
if ! command -v pi >/dev/null 2>&1; then
|
||||
warn "找不到 pi,无法安装组合包。请先安装 Pi 并确保 pi 位于 PATH。"
|
||||
exit 127
|
||||
@@ -104,7 +358,67 @@ if ! pi install "$PACKAGE_SOURCE"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
say "Pi 组合包安装完成,开始检查机器级 CLI 依赖。"
|
||||
say "Pi 组合包安装完成,开始检查终端环境和机器级 CLI 依赖。"
|
||||
|
||||
kitty_ok=0
|
||||
if detect_kitty; then
|
||||
kitty_ok=1
|
||||
say "✓ Kitty 已安装(${kitty_bin})"
|
||||
elif ask_to_install "Kitty 终端"; then
|
||||
if install_kitty; then
|
||||
kitty_ok=1
|
||||
say "✓ Kitty 安装完成"
|
||||
else
|
||||
record_install_failure "Kitty"
|
||||
fi
|
||||
else
|
||||
say "- 已跳过 Kitty;不会检查 Solarized Dark 主题。"
|
||||
fi
|
||||
|
||||
if [ "$kitty_ok" -eq 1 ]; then
|
||||
if kitty_solarized_dark_configured; then
|
||||
say "✓ Kitty 已配置 Solarized Dark"
|
||||
elif ask_yes_no "Kitty 尚未配置 Solarized Dark。是否现在配置?"; then
|
||||
configure_kitty_solarized_dark || record_install_failure "Kitty Solarized Dark 主题"
|
||||
else
|
||||
say "- 已跳过 Kitty Solarized Dark 主题。"
|
||||
fi
|
||||
fi
|
||||
|
||||
oh_my_zsh_ok=0
|
||||
if oh_my_zsh_installed; then
|
||||
oh_my_zsh_ok=1
|
||||
say "✓ Oh My Zsh 已安装(${oh_my_zsh_dir})"
|
||||
elif ask_to_install "Oh My Zsh"; then
|
||||
if install_oh_my_zsh; then
|
||||
oh_my_zsh_ok=1
|
||||
say "✓ Oh My Zsh 安装完成"
|
||||
else
|
||||
record_install_failure "Oh My Zsh"
|
||||
fi
|
||||
else
|
||||
say "- 已跳过 Oh My Zsh;不会检查 Powerlevel10k 和 Zsh 插件。"
|
||||
fi
|
||||
|
||||
if [ "$oh_my_zsh_ok" -eq 1 ]; then
|
||||
resolve_zsh_paths
|
||||
powerlevel10k_dir=$zsh_custom_dir/themes/powerlevel10k
|
||||
if [ -f "$powerlevel10k_dir/powerlevel10k.zsh-theme" ] && \
|
||||
grep -E "^[[:space:]]*ZSH_THEME[[:space:]]*=[[:space:]]*[\"']?powerlevel10k/powerlevel10k[\"']?" \
|
||||
"$zshrc_file" >/dev/null 2>&1 && [ -f "$HOME/.p10k.zsh" ] && p10k_config_sourced; then
|
||||
say "✓ Powerlevel10k 已安装并配置"
|
||||
elif ask_yes_no "Powerlevel10k 尚未完整配置。是否安装并应用免向导的 Lean/ASCII 预设?"; then
|
||||
configure_powerlevel10k || record_install_failure "Powerlevel10k"
|
||||
else
|
||||
say "- 已跳过 Powerlevel10k。"
|
||||
fi
|
||||
|
||||
check_zsh_plugin "git" "git 插件" ""
|
||||
check_zsh_plugin "zsh-autosuggestions" "zsh-autosuggestions(命令自动建议)" \
|
||||
"$ZSH_AUTOSUGGESTIONS_REPOSITORY"
|
||||
check_zsh_plugin "zsh-syntax-highlighting" "zsh-syntax-highlighting(语法高亮)" \
|
||||
"$ZSH_SYNTAX_HIGHLIGHTING_REPOSITORY"
|
||||
fi
|
||||
|
||||
if command -v codegraph >/dev/null 2>&1; then
|
||||
say "✓ codegraph 已安装"
|
||||
@@ -151,5 +465,5 @@ else
|
||||
say "- 已跳过 jdtls;Java LSP 功能将不可用。"
|
||||
fi
|
||||
|
||||
say "依赖检查完成。RTK 命令改写默认关闭,因此未检查可选的 rtk CLI。"
|
||||
say "终端环境与依赖检查完成。RTK 命令改写默认关闭,因此未检查可选的 rtk CLI。"
|
||||
exit "$install_failed"
|
||||
|
||||
Reference in New Issue
Block a user