feat: enhance variant picker (#86)

* fix: variant display is more clear

* fix: unable to install all variants

* feat: select variants with ranges and exclusions
This commit is contained in:
v4n
2025-09-16 14:13:51 +03:00
committed by GitHub
parent c3d76c625c
commit 30649e0312
2 changed files with 123 additions and 21 deletions
+122 -20
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
VERSION="0.6.9"
VERSION="0.6.10"
# --- Globals ---
@@ -155,6 +155,81 @@ function remove_disabled_prefix() {
echo "$disabled_file"
}
function parse_indexes() {
_returned_indexes=()
while [[ $# -gt 0 ]]; do
case "$1" in
"--range")
[[ -z "$2" ]] && { log ERROR "Function parse indexes: range is required"; exit 1; }
range="$2"; shift 2
;;
*)
input_indexes+=("$1")
shift
;;
esac
done
# parse input_indexes 1-by-1
for index in "${input_indexes[@]}"; do
# normal index 5
if [[ "$index" =~ ^[0-9]+$ ]]; then
[[ $index -lt 1 || $index -gt $range ]] && { log ERROR "Function parse indexes: index $index out of range (1 -> $range)"; exit 1; }
_returned_indexes+=("$index")
# range index 1..5
elif [[ "$index" =~ ^[0-9]+\.\.[0-9]+$ ]]; then
# cut doesn't work with a delimiter of two characters
start=$(echo "$index" | cut -d. -f1)
end=$(echo "$index" | cut -d. -f3)
[[ $start -lt 1 || $end -lt 1 || $start -gt $range || $end -gt $range ]] && { log ERROR "Function parse indexes: range $index out of range (1 -> $range)"; exit 1; }
if [[ $start -le $end ]]; then
for ((i=start; i<=end; i++)); do
_returned_indexes+=("$i")
done
else
for ((i=start; i>=end; i--)); do
_returned_indexes+=("$i")
done
fi
# remove index -5
elif [[ "$index" =~ ^-[0-9] ]]; then
index=${index#-} # remove the - sign
# if _returned_indexes is empty, populate it with every number from 1 to range
[[ ${#_returned_indexes[@]} -eq 0 ]] && for ((i=1; i<=range; i++)); do _returned_indexes+=("$i"); done
# if exclusion range
if [[ "$index" =~ ^[0-9]+\.\.[0-9]+$ ]]; then
start=$(echo "$index" | cut -d. -f1)
end=$(echo "$index" | cut -d. -f3)
[[ $start -lt 1 || $end -lt 1 || $start -gt $range || $end -gt $range ]] && { log ERROR "Function parse indexes: exclusion range $index out of range (1 -> $range)"; exit 1; }
if [[ $start -le $end ]]; then
for ((i=start; i<=end; i++)); do
_returned_indexes=("${_returned_indexes[@]/$i}") # remove index from array
done
else
for ((i=start; i>=end; i--)); do
_returned_indexes=("${_returned_indexes[@]/$i}") # remove index from array
done
fi
else
# single exclusion
[[ $index -lt 1 || $index -gt $range ]] && { log ERROR "Function parse indexes: index $index out of range (1 -> $range)"; exit 1; }
_returned_indexes=("${_returned_indexes[@]/$index}") # remove index from array
fi
else
log ERROR "Function parse indexes: invalid index $index"
exit 1
fi
done
}
function get_mod_name_and_index() {
# if calling install multiple times in the same call of h2mm, the mod_index needs to be reset if it was -1
[[ $mod_index -eq -1 ]] && unset mod_index
@@ -822,68 +897,95 @@ function mod_install() {
# directory containing mod files
if [[ -n "$mod_dir" ]]; then
# remove trailing slash if it exists
mod_dir="${mod_dir%/}"
# verify directory exists
[[ ! -d "$mod_dir" ]] && { log ERROR "Directory $mod_dir does not exist."; exit 1; }
# read every file from the directory
readarray -d '' mod_files < <(find "$mod_dir" -type f -name "*.patch_*" -print0)
# if the name is not specified, use the name of the directory, last sed for making nexusmods names not have numbers
if [[ -z "$mod_name" ]]; then
mod_name=$(echo "$mod_dir" | sed 's:/*$::' | awk -F/ '{print $NF}' | sed -E 's/-[0-9]+-.*//')
fi
# check for mod variants and handle
# if it's a tmp directory in the format /tmp/tmp.*/, we need to go mindepth 1 to avoid listing the tmp dir itself
[[ "$mod_dir" == /tmp/tmp.* ]] && mindepth=1 || mindepth=0
# if the mod directory contains more than 1 directory, it means there are multiple variants for the mod
# prompt the user to choose which variant to install, or install multiple
readarray -d '' all_dirs < <(find "$mod_dir" -mindepth 1 -type d -print0)
readarray -d '' all_dirs < <(find "$mod_dir" -mindepth $mindepth -type d -print0)
# filter so that we only have dirs that have *.patch_* files inside them
filtered_dirs=()
for dir in "${all_dirs[@]}"; do
if find "$dir" -maxdepth 1 -type f -name "*.patch_*" -print -quit | grep -q .; then
if find "$dir" -type f -name "*.patch_*" -print -quit | grep -q .; then
filtered_dirs+=("$dir")
fi
done
if [[ ${#filtered_dirs[@]} -gt 1 ]]; then
log INFO "Multiple mod variants found for mod ${mod_name}."
if [[ ${#filtered_dirs[@]} -ne 0 ]]; then
log INFO "Multiple mod variants found for mod ${mod_name}:"
# print the variant name by display all the directories (and how they're nested)
# first, take the basename of the directory/zip we're installing from
# then, make the variant name by removing the tmp dir name from the path (if it's a zip)
# finally, take out this name, if it exists
if [[ -n "$mod_zip" ]]; then
mod_file_name="$(get_basename "$mod_zip")"
else
mod_file_name="*"
fi
for i in "${!filtered_dirs[@]}"; do
variant_name="${filtered_dirs[$i]#$mod_dir/}" # remote temp name in case its a zip
log INFO "$((i + 1)). ${variant_name#$mod_file_name/}" # remote the name of the zip/dir if it exists
variant_name="${filtered_dirs[$i]}"
# if mod_dir contains /tmp/tmp.*/* then remove the /tmp/tmp.*/ part and leave the rest, else just remove the mod_dir part
if [[ "$mod_dir" == /tmp/tmp.* ]]; then
variant_name="${variant_name#$mod_dir/*/}" # remove /tmp/tmp.* part
[[ $i == 0 && "$variant_name" == /tmp/tmp.* ]] && variant_name="$mod_name [base folder]"
else
variant_name="${variant_name#$mod_dir/}" # remove dir name before it
[[ $i == 0 && "$variant_name" == "$mod_dir" ]] && variant_name="$mod_name [base folder]"
fi
log INFO "$((i + 1)). $variant_name"
done
# prompt user to choose
log PROMPT "Enter the number of the variant(s) to install (separated by space) or press Enter to install all: "
log INFO "Use spaces to separate multiple variants (1 2 4) or use ranges (2..5) or use exclusions (-3) or any combination of them (1 3..5 7..12 -10)."
log INFO "When only exclusions are present (-3) it means all variants except the excluded ones. You can also use exclusion ranges (-3..5)."
log PROMPT "Enter the combination of variants to install (or press Enter to install all variants): "
read -a variant_indices
if [[ -n "${variant_indices[0]}" ]]; then
# clear mod_files
mod_files=()
# get the files from the chosen variant
for index in "${variant_indices[@]}"; do
[[ ! "$index" =~ ^[0-9]+$ ]] && { log ERROR "Invalid variant index."; exit 1; }
[[ $index -lt 1 || $index -gt ${#filtered_dirs[@]} ]] && { log ERROR "Variant index out of range."; exit 1; }
# use this variable for formatting the mod name
has_atleast_one_variant=false
readarray -d '' variant_files < <(find "${filtered_dirs[$((index - 1))]}" -type f -name "*.patch_*" -print0)
parse_indexes --range ${#filtered_dirs[@]} "${variant_indices[@]}"
# get the files from the chosen variant
for index in "${_returned_indexes[@]}"; do
[[ -z "$index" ]] && continue
# read the files from the directory
readarray -d '' variant_files < <(find "${filtered_dirs[$((index - 1))]}" -maxdepth 1 -type f -name "*.patch_*" -print0)
# update mod_name to contain the variant name
mod_name="${mod_name} [$(basename "${filtered_dirs[$((index - 1))]}")]"
if [[ $has_atleast_one_variant == false ]]; then
mod_name="${mod_name} [$(basename "${filtered_dirs[$((index - 1))]}")"
has_atleast_one_variant=true
else
mod_name="${mod_name} - $(basename "${filtered_dirs[$((index - 1))]}")"
fi
# add the files to the mod_files array
mod_files+=("${variant_files[@]}")
done
[[ $has_atleast_one_variant == true ]] && mod_name="${mod_name}]"
fi
fi
fi
+1 -1
View File
@@ -1 +1 @@
0.6.9
0.6.10