- commands/list/list.sh: router + command::define show [*] - commands/list/show.sh: flag::define + flag::parse, all helpers - flag::exclusive: register under top-level command name (strip ::subcmd) - flag::parse: validate exclusive groups, error on conflicting user flags - --help: intercept in command::run before routing - help::auto: don't show default subcommand in usage line
195 lines
No EOL
5.5 KiB
Bash
195 lines
No EOL
5.5 KiB
Bash
#!/usr/bin/env bash
|
|
# core/command_mixins.sh
|
|
# Mixin infrastructure — loads mixin files and provides command::mixin / flag::exclusive
|
|
|
|
# ============================================
|
|
# Active mixin tracking (per-process)
|
|
# ============================================
|
|
|
|
declare -a _ACTIVE_MIXINS=()
|
|
|
|
# ============================================
|
|
# Auto-load all mixin files
|
|
# ============================================
|
|
|
|
function command::_load_mixins() {
|
|
local mixin_file
|
|
local -a mixin_paths=(
|
|
"${_FRAMEWORK_DIR}/mixins/"*.mixin.sh
|
|
)
|
|
for mixin_file in "${mixin_paths[@]:-}"; do
|
|
[[ -f "$mixin_file" ]] && source "$mixin_file"
|
|
done
|
|
}
|
|
|
|
# ============================================
|
|
# command::mixin <name>
|
|
# Called from cmd::<name>::on_load to opt into a mixin
|
|
# ============================================
|
|
|
|
function command::mixin() {
|
|
local name="${1:-}"
|
|
[[ -z "$name" ]] && log::error "command::mixin: missing name" && return 1
|
|
|
|
local register_fn="command::mixin::${name}::register"
|
|
if declare -f "$register_fn" >/dev/null 2>&1; then
|
|
# Track for reset/process — avoid duplicates
|
|
local m already=false
|
|
for m in "${_ACTIVE_MIXINS[@]:-}"; do
|
|
[[ "$m" == "$name" ]] && already=true && break
|
|
done
|
|
$already || _ACTIVE_MIXINS+=("$name")
|
|
"$register_fn"
|
|
else
|
|
log::error "Unknown mixin: ${name} (no command::mixin::${name}::register found)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# command::_reset_mixins
|
|
# Called by command::run before each invocation
|
|
# ============================================
|
|
|
|
function command::_reset_mixin_state() {
|
|
# Reset values but keep _ACTIVE_MIXINS populated
|
|
local m
|
|
for m in "${_ACTIVE_MIXINS[@]:-}"; do
|
|
local reset_fn="command::mixin::${m}::reset"
|
|
declare -f "$reset_fn" >/dev/null 2>&1 && "$reset_fn"
|
|
done
|
|
}
|
|
|
|
function command::_reset_mixins() {
|
|
_ACTIVE_MIXINS=()
|
|
local reset_fn mixin_file
|
|
# Reset all known mixins regardless of active state
|
|
for mixin_file in \
|
|
"${WGCTL_DIR}/core/mixins/"*.mixin.sh \
|
|
"${WGCTL_DIR}/commands/mixins/"*.mixin.sh; do
|
|
[[ -f "$mixin_file" ]] || continue
|
|
local mixin_name
|
|
mixin_name=$(basename "$mixin_file" .mixin.sh)
|
|
reset_fn="command::mixin::${mixin_name}::reset"
|
|
declare -f "$reset_fn" >/dev/null 2>&1 && "$reset_fn"
|
|
done
|
|
}
|
|
|
|
# ============================================
|
|
# command::_preprocess_flags <args_nameref>
|
|
# Called by command::run — strips mixin flags from args
|
|
# ============================================
|
|
|
|
function command::_preprocess_flags() {
|
|
local -n _args_ref="$1"
|
|
local -a _filtered=()
|
|
|
|
if [[ ${#_args_ref[@]} -eq 0 ]]; then
|
|
return 0 # nothing to process
|
|
fi
|
|
|
|
for _arg in "${_args_ref[@]}"; do
|
|
local _consumed=false
|
|
for _mixin in "${_ACTIVE_MIXINS[@]:-}"; do
|
|
local _process_fn="command::mixin::${_mixin}::process"
|
|
if declare -f "$_process_fn" >/dev/null 2>&1; then
|
|
if "$_process_fn" "$_arg"; then
|
|
_consumed=true
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
$_consumed || _filtered+=("$_arg")
|
|
done
|
|
|
|
if [[ ${#_filtered[@]} -gt 0 ]]; then
|
|
_args_ref=("${_filtered[@]}")
|
|
else
|
|
_args_ref=()
|
|
fi
|
|
}
|
|
|
|
# command::_resolve_conflicts <defaults_nameref> <user_nameref> <groups_string>
|
|
# Removes conflicting defaults when user provides a member of an exclusive group
|
|
function command::_resolve_conflicts() {
|
|
local -n _def_ref="$1"
|
|
local -n _usr_ref="$2"
|
|
local groups="$3"
|
|
|
|
[[ -z "$groups" ]] && return 0
|
|
[[ ${#_def_ref[@]} -eq 0 ]] && return 0
|
|
|
|
# Work on a copy — progressively filter across all groups
|
|
local -a working=("${_def_ref[@]}")
|
|
|
|
local group
|
|
while IFS= read -r group; do
|
|
[[ -z "$group" ]] && continue
|
|
|
|
local -a members=()
|
|
IFS=',' read -ra members <<< "$group"
|
|
|
|
# Find which member (if any) the user passed from this group
|
|
local user_member=""
|
|
local member user_arg
|
|
for member in "${members[@]}"; do
|
|
for user_arg in "${_usr_ref[@]:-}"; do
|
|
if [[ "$user_arg" == "$member" ]]; then
|
|
user_member="$member"
|
|
break 2
|
|
fi
|
|
done
|
|
done
|
|
|
|
# No user member in this group — don't touch defaults
|
|
[[ -z "$user_member" ]] && continue
|
|
|
|
# User passed a member — remove all OTHER members from defaults
|
|
# (keep the same flag if it was already in defaults)
|
|
local -a new_working=()
|
|
local def_arg
|
|
for def_arg in "${working[@]:-}"; do
|
|
local is_other_member=false
|
|
for member in "${members[@]}"; do
|
|
# It's another member if it's in the group AND not the same as user's choice
|
|
if [[ "$def_arg" == "$member" && "$def_arg" != "$user_member" ]]; then
|
|
is_other_member=true
|
|
break
|
|
fi
|
|
done
|
|
$is_other_member || new_working+=("$def_arg")
|
|
done
|
|
working=("${new_working[@]:-}")
|
|
done < <(echo "$groups" | tr '|' '\n')
|
|
|
|
# Write back
|
|
if [[ ${#working[@]} -gt 0 ]]; then
|
|
_def_ref=("${working[@]}")
|
|
else
|
|
_def_ref=()
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# Flag Exclusive
|
|
# ============================================
|
|
|
|
declare -gA _FLAG_EXCLUSIVE_GROUPS=()
|
|
|
|
# flag::exclusive <flag1> <flag2> ...
|
|
# Called from on_load — registers mutually exclusive flags for current command
|
|
function flag::exclusive() {
|
|
local cmd="${_CURRENT_LOADING_CMD:-}"
|
|
[[ -z "$cmd" ]] && return 0
|
|
cmd="${cmd%%::*}"
|
|
|
|
# Join flags with comma as one group
|
|
local group
|
|
group=$(IFS=','; echo "$*")
|
|
|
|
if [[ -n "${_FLAG_EXCLUSIVE_GROUPS[$cmd]:-}" ]]; then
|
|
_FLAG_EXCLUSIVE_GROUPS["$cmd"]+="${group}|"
|
|
else
|
|
_FLAG_EXCLUSIVE_GROUPS["$cmd"]="${group}|"
|
|
fi
|
|
} |