// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// Behavior for flag args.
///
/// - `SetTrue` / `SetFalse` set a boolean value.
/// - `Count` increments `Matches.flag_counts`.
/// - `Help` / `Version` display output and exit successfully when triggered.
pub(all) enum FlagAction {
SetTrue
SetFalse
Count
Help
Version
} derive(Eq, @debug.Debug)
///|
/// Behavior for option args.
///
/// - `Set` keeps the last provided value.
/// - `Append` keeps all provided values in order.
pub(all) enum OptionAction {
Set
Append
} derive(Eq, @debug.Debug)
///|
/// Unified argument model used by the parser internals.
priv struct Arg {
// All
name : String
about : String?
env : String?
requires : Array[String]
conflicts_with : Array[String]
required : Bool
global : Bool
hidden : Bool
info : ArgInfo
multiple : Bool
} derive(@debug.Debug)
///|
priv enum ArgInfo {
FlagInfo(
short~ : Char?,
long~ : String?,
action~ : FlagAction,
negatable~ : Bool
)
OptionInfo(
short~ : Char?,
long~ : String?,
action~ : OptionAction,
default_values~ : Array[String]?,
allow_hyphen_values~ : Bool
)
PositionalInfo(
num_args~ : ValueRange?,
default_values~ : Array[String]?,
allow_hyphen_values~ : Bool
)
} derive(@debug.Debug)
///|
/// Declarative flag constructor wrapper.
pub struct FlagArg {
priv arg : Arg
} derive(@debug.Debug)
///|
/// Create a flag argument.
///
/// Notes:
/// - `long` defaults to `name`.
/// - Use `long=""` to disable the long form.
/// - At least one of `short`, `long`, or `env` must be available.
/// - `global=true` makes the flag available in subcommands.
/// - `negatable=true` accepts `--no-` for long flags.
/// - If `env` is set, accepted boolean values are:
/// `1`, `0`, `true`, `false`, `yes`, `no`, `on`, `off`.
#alias(new, deprecated="Use `FlagArg()` instead")
pub fn FlagArg::FlagArg(
name : StringView,
short? : Char,
long? : StringView = name,
about? : StringView,
action? : FlagAction = SetTrue,
env? : StringView,
requires? : ArrayView[String] = [],
conflicts_with? : ArrayView[String] = [],
required? : Bool = false,
global? : Bool = false,
negatable? : Bool = false,
hidden? : Bool = false,
) -> FlagArg {
let name = name.to_owned()
let long = if long == "" { None } else { Some(long.to_owned()) }
let about = about.map(v => v.to_owned())
let env = env.map(v => v.to_owned())
{
arg: {
name,
about,
env,
global,
hidden,
requires: requires.to_owned(),
conflicts_with: conflicts_with.to_owned(),
required,
info: FlagInfo(short~, long~, action~, negatable~),
multiple: false,
},
}
}
///|
/// Declarative option constructor wrapper.
/// Named `OptionArg` to avoid shadowing the built-in `Option` type.
pub struct OptionArg {
priv arg : Arg
} derive(@debug.Debug)
///|
/// Create an option argument.
///
/// Notes:
/// - `long` defaults to `name`.
/// - Use `long=""` to disable the long form.
/// - At least one of `short`, `long`, or `env` must be available.
/// - Use `action=Append` to keep repeated occurrences.
/// - `global=true` makes the option available in subcommands.
/// - `allow_hyphen_values=true` allows values like `-1` or `--raw` to be
/// consumed as this option's value when parsing argv.
#alias(new, deprecated="Use `OptionArg()` instead")
pub fn OptionArg::OptionArg(
name : StringView,
short? : Char,
long? : StringView = name,
about? : StringView,
action? : OptionAction = Set,
env? : StringView,
default_values? : ArrayView[String],
allow_hyphen_values? : Bool = false,
requires? : ArrayView[String] = [],
conflicts_with? : ArrayView[String] = [],
required? : Bool = false,
global? : Bool = false,
hidden? : Bool = false,
) -> OptionArg {
let name = name.to_owned()
let long = if long == "" { None } else { Some(long.to_owned()) }
let about = about.map(v => v.to_owned())
let env = env.map(v => v.to_owned())
{
arg: {
name,
about,
env,
requires: requires.to_owned(),
conflicts_with: conflicts_with.to_owned(),
required,
global,
hidden,
info: OptionInfo(
short~,
long~,
action~,
default_values=default_values.map(values => values.to_owned()),
allow_hyphen_values~,
),
multiple: action is Append,
},
}
}
///|
/// Declarative positional constructor wrapper.
pub struct PositionArg {
priv arg : Arg
} derive(@debug.Debug)
///|
/// Create a positional argument.
///
/// Notes:
/// - PositionArg order follows declaration order.
/// - `num_args` controls accepted value count.
/// - If `num_args` is omitted, the default is an optional single value
/// (`0..=1`).
/// - Use `num_args=ValueRange::single()` for a required single positional.
/// - `allow_hyphen_values=true` allows leading-`-` tokens to be consumed as
/// positional values (unless they match a declared option).
/// - Tokens after `--` are always treated as positional values.
#alias(new, deprecated="Use `PositionArg()` instead")
pub fn PositionArg::PositionArg(
name : StringView,
about? : StringView,
env? : StringView,
default_values? : ArrayView[String],
num_args? : ValueRange,
allow_hyphen_values? : Bool = false,
requires? : ArrayView[String] = [],
conflicts_with? : ArrayView[String] = [],
global? : Bool = false,
hidden? : Bool = false,
) -> PositionArg {
let name = name.to_owned()
let about = about.map(v => v.to_owned())
let env = env.map(v => v.to_owned())
{
arg: {
name,
about,
env,
requires: requires.to_owned(),
conflicts_with: conflicts_with.to_owned(),
required: false,
global,
hidden,
info: PositionalInfo(
num_args~,
default_values=default_values.map(values => values.to_owned()),
allow_hyphen_values~,
),
multiple: range_allows_multiple(num_args),
},
}
}
///|
fn arg_name(arg : Arg) -> String {
arg.name
}
///|
fn range_allows_multiple(range : ValueRange?) -> Bool {
range is Some(r) &&
(match r.upper {
Some(upper) => upper > 1
None => true
})
}
///|
impl Show for FlagAction with fn to_string(self) {
match self {
SetTrue => "SetTrue"
SetFalse => "SetFalse"
Count => "Count"
Help => "Help"
Version => "Version"
}
}
///|
impl Show for OptionAction with fn to_string(self) {
match self {
Set => "Set"
Append => "Append"
}
}