@@ -36,6 +36,7 @@ Quickstart-PC - 一键配置新电脑
3636 --verbose, -v 显示详细调试信息
3737 --log-file FILE 将日志写入文件
3838 --export-plan FILE 导出安装计划到文件
39+ --custom 自定义软件选择模式
3940 --list-profiles 列出所有可用套餐
4041 --show-profile KEY 显示指定套餐详情
4142 --skip SW 跳过指定软件(可多次使用)
@@ -62,6 +63,7 @@ Options:
6263 --verbose, -v Show detailed debug info
6364 --log-file FILE Write logs to file
6465 --export-plan FILE Export installation plan to file
66+ --custom Custom software selection mode
6567 --list-profiles List all available profiles
6668 --show-profile KEY Show profile details
6769 --skip SW Skip specified software (repeatable)
@@ -81,6 +83,7 @@ AUTO_YES=false
8183VERBOSE=false
8284LOG_FILE=" "
8385EXPORT_PLAN=" "
86+ CUSTOM_MODE=false
8487LIST_PROFILES=false
8588SHOW_PROFILE=" "
8689SKIP_SW=()
@@ -102,6 +105,7 @@ while [[ $# -gt 0 ]]; do
102105 --verbose|-v) VERBOSE=true; shift ;;
103106 --log-file) LOG_FILE=" $2 " ; shift 2 ;;
104107 --export-plan) EXPORT_PLAN=" $2 " ; shift 2 ;;
108+ --custom) CUSTOM_MODE=true; shift ;;
105109 --list-profiles) LIST_PROFILES=true; shift ;;
106110 --show-profile) SHOW_PROFILE=" $2 " ; shift 2 ;;
107111 --skip) SKIP_SW+=(" $2 " ); shift 2 ;;
@@ -915,6 +919,115 @@ install_software() {
915919 fi
916920}
917921
922+ # 自定义软件选择模式
923+ custom_select_software () {
924+ local json_file=$1
925+ local os=$2
926+ local profile_key=$3
927+
928+ # 获取套餐包含的软件
929+ local -a sw_keys=()
930+ while IFS= read -r key; do
931+ [[ -z " $key " ]] && continue
932+ sw_keys+=(" $key " )
933+ done < <( json_get_profile_includes " $json_file " " $profile_key " )
934+
935+ local num_sw=${# sw_keys[@]}
936+
937+ echo " "
938+ log_header " $LANG_SELECT_SOFTWARE "
939+ echo " "
940+ echo -e " ${CYAN} $LANG_NAVIGATE_MULTI ${NC} "
941+ echo " "
942+
943+ # 构建菜单项
944+ local -a menu_names=()
945+ local -a checked=()
946+
947+ # 全选
948+ menu_names+=(" ${ORANGE} $LANG_SELECT_ALL ${NC} " )
949+ checked+=(0)
950+
951+ for key in " ${sw_keys[@]} " ; do
952+ local name=$( json_get_software_field " $json_file " " $key " " name" )
953+ local desc=$( json_get_software_field " $json_file " " $key " " desc" )
954+
955+ if is_installed " $json_file " " $os " " $key " ; then
956+ menu_names+=(" ${GRAY} $name - $desc $LANG_INSTALLED ${NC} " )
957+ else
958+ menu_names+=(" $name - $desc " )
959+ fi
960+ checked+=(0)
961+ done
962+
963+ local num_items=${# menu_names[@]}
964+ local cursor=0
965+ local running=true
966+
967+ tput civis 2> /dev/null || true
968+ stty -echo 2> /dev/null
969+
970+ while [[ " $running " == " true" ]]; do
971+ printf " \r\033[2K"
972+ for (( i= 0 ; i< num_items; i++ )) ; do
973+ if [[ $i -eq $cursor ]]; then
974+ if [[ ${checked[$i]} -eq 1 ]]; then
975+ echo -e " ${REVERSE}${GREEN}${LANG_SELECTED}${NC}${REVERSE}${menu_names[$i]}${NC} "
976+ else
977+ echo -e " ${REVERSE}${LANG_NOT_SELECTED}${menu_names[$i]}${NC} "
978+ fi
979+ else
980+ if [[ ${checked[$i]} -eq 1 ]]; then
981+ echo -e " ${GREEN}${LANG_SELECTED}${NC}${menu_names[$i]} "
982+ else
983+ echo -e " ${LANG_NOT_SELECTED}${menu_names[$i]} "
984+ fi
985+ fi
986+ done
987+
988+ local key=" "
989+ IFS= read -rsn1 key < /dev/tty
990+
991+ # 空字符串 = 回车
992+ if [[ -z " $key " ]]; then
993+ running=false
994+ # ESC 开头 = 方向键
995+ elif [[ " $key " == $' \x1b ' ]]; then
996+ local seq=" "
997+ IFS= read -rsn2 seq < /dev/tty
998+ if [[ " $seq " == " [A" ]]; then
999+ (( cursor-- ))
1000+ [[ $cursor -lt 0 ]] && cursor=$(( num_items - 1 ))
1001+ elif [[ " $seq " == " [B" ]]; then
1002+ (( cursor++ ))
1003+ [[ $cursor -ge $num_items ]] && cursor=0
1004+ fi
1005+ # 空格 = 切换选择
1006+ elif [[ " $key " == " " ]]; then
1007+ if [[ $cursor -eq 0 ]]; then
1008+ local new_state=$(( 1 - checked[0 ]))
1009+ for (( i= 0 ; i< num_items; i++ )) ; do
1010+ checked[$i ]=$new_state
1011+ done
1012+ else
1013+ checked[$cursor ]=$(( 1 - checked[$cursor ]))
1014+ fi
1015+ fi
1016+
1017+ # 上移光标重绘
1018+ printf ' \033[%dA' " $num_items "
1019+ done
1020+
1021+ tput cnorm 2> /dev/null || true
1022+ stty echo 2> /dev/null
1023+ echo " "
1024+
1025+ SELECTED_SOFTWARE=()
1026+ for (( i= 1 ; i< num_items; i++ )) ; do
1027+ [[ ${checked[$i]} -eq 1 ]] && SELECTED_SOFTWARE+=(" ${sw_keys[$((i-1))]} " )
1028+ done
1029+ }
1030+
9181031show_banner () {
9191032 echo " "
9201033 printf " \033[0;34m╔══════════════════════════════════════╗\n"
@@ -1019,11 +1132,19 @@ main() {
10191132 fi
10201133
10211134 SELECTED_PROFILES=(" $PROFILE_KEY " )
1022- show_software_menu " $CONFIG_FILE " " $os " " ${SELECTED_PROFILES[@]} "
1135+ if [[ " $CUSTOM_MODE " == " true" ]]; then
1136+ custom_select_software " $CONFIG_FILE " " $os " " ${SELECTED_PROFILES[@]} "
1137+ else
1138+ show_software_menu " $CONFIG_FILE " " $os " " ${SELECTED_PROFILES[@]} "
1139+ fi
10231140 else
10241141 show_profile_menu " $CONFIG_FILE "
10251142 [[ ${# SELECTED_PROFILES[@]} -eq 0 ]] && log_warn " $LANG_NO_PROFILE_SELECTED " && exit 0
1026- show_software_menu " $CONFIG_FILE " " $os " " ${SELECTED_PROFILES[@]} "
1143+ if [[ " $CUSTOM_MODE " == " true" ]]; then
1144+ custom_select_software " $CONFIG_FILE " " $os " " ${SELECTED_PROFILES[@]} "
1145+ else
1146+ show_software_menu " $CONFIG_FILE " " $os " " ${SELECTED_PROFILES[@]} "
1147+ fi
10271148 fi
10281149
10291150 if [[ ${# SELECTED_SOFTWARE[@]} -eq 0 ]]; then
0 commit comments