facet_args/lib.rs
1#![warn(missing_docs)]
2#![warn(clippy::std_instead_of_core)]
3#![warn(clippy::std_instead_of_alloc)]
4#![deny(unsafe_code)]
5#![doc = include_str!("../README.md")]
6
7extern crate alloc;
8
9pub mod completions;
10mod format;
11pub mod help;
12
13pub(crate) mod arg;
14pub(crate) mod error;
15pub(crate) mod span;
16
17pub use completions::{Shell, generate_completions, generate_completions_for_shape};
18pub use error::{ArgsErrorKind, ArgsErrorWithInput};
19pub use format::from_slice;
20pub use format::from_slice_with_config;
21pub use format::from_std_args;
22pub use help::{HelpConfig, generate_help, generate_help_for_shape};
23
24// Args extension attributes for use with #[facet(args::attr)] syntax.
25//
26// After importing `use facet_args as args;`, users can write:
27// #[facet(args::positional)]
28// #[facet(args::short = 'v')]
29// #[facet(args::named)]
30
31// Generate args attribute grammar using the grammar DSL.
32// This generates:
33// - `Attr` enum with all args attribute variants
34// - `__attr!` macro that dispatches to attribute handlers and returns ExtensionAttr
35// - `__parse_attr!` macro for parsing (internal use)
36facet::define_attr_grammar! {
37 ns "args";
38 crate_path ::facet_args;
39
40 /// Args attribute types for field configuration.
41 pub enum Attr {
42 /// Marks a field as a positional argument.
43 ///
44 /// Usage: `#[facet(args::positional)]`
45 Positional,
46 /// Marks a field as a named argument.
47 ///
48 /// Usage: `#[facet(args::named)]`
49 Named,
50 /// Specifies a short flag character for the field.
51 ///
52 /// Usage: `#[facet(args::short = 'v')]` or just `#[facet(args::short)]`
53 Short(Option<char>),
54 /// Marks a field as a subcommand.
55 ///
56 /// The field type must be an enum where each variant represents a subcommand.
57 /// Variant names are converted to kebab-case for matching.
58 ///
59 /// Usage: `#[facet(args::subcommand)]`
60 Subcommand,
61 /// Marks a field as a counted flag.
62 ///
63 /// Each occurrence of the flag increments the count. Works with both short
64 /// flags (`-vvv` or `-v -v -v`) and long flags (`--verbose --verbose`).
65 /// The field type must be an integer type (u8, u16, u32, u64, usize, i8, i16, i32, i64, isize).
66 /// Uses saturating arithmetic to avoid overflow.
67 ///
68 /// Usage: `#[facet(args::named, args::short = 'v', args::counted)]`
69 Counted,
70 }
71}
72
73/// Check if a field is marked with `args::counted`.
74pub fn is_counted_field(field: &facet_core::Field) -> bool {
75 field.has_attr(Some("args"), "counted")
76}
77
78/// Check if a shape is a supported type for counted fields (integer types).
79pub const fn is_supported_counted_type(shape: &'static facet_core::Shape) -> bool {
80 use facet_core::{NumericType, PrimitiveType, Type};
81 matches!(
82 shape.ty,
83 Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { .. }))
84 )
85}