1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! Minecraft command parsing crate inspired by [`Brigadier`](https://github.com/Mojang/Brigadier)
//! and [`nom`](https://crates.io/crates/nom). This crate tries to combine the easy syntax from
//! `Brigadier` with the performant parsing concepts of `nom`.
//!
//! ### Creating a parser
//!
//! Using the builder pattern, different parsers can be chained together to
//! create a logical tree a command can be propagated through. This is done by
//! using the appropiate parser functions in the root of the crate. Custom
//! parsers can be implemented using [`CommandArgument`] and most other traits.
//! It is recommended to look at parser structs in [`parsers`](self::parsers)
//! for inspiration.
//!
//! ## Example
//!
//! ```no_run
//! # use brigadier_rs::{literal, integer_i32, Then, BuildExecute, ThenHelp};
//! # use std::convert::Infallible;
//! let parser = literal("foo")
//!     .then(
//!         integer_i32("bar")
//!             .build_exec(|ctx: (), bar| {
//!                 println!("Bar is {}", bar);
//!                 Ok::<(), Infallible>(())
//!             })
//!     ).build_exec(|ctx: ()| {
//!         println!("Called foo with no arguments");
//!         Ok::<(), Infallible>(())
//!     });
//! ```
//!
//! This code creates a new parser that can parse commands in the forms of `foo`
//! and `foo <bar>` and can be represented in a tree like this:
//!
//! ```ditaa
//!               +-----------+       +---------+
//!               | i32 (bar) +-----> | Execute |
//!               +-----+-----+       +---------+
//!                     ^
//!                     |
//!                 +---+------+
//! +-----------+   |    (foo) |      +---------+
//! | lit (foo) +-->| Then     +----> | Execute |
//! +-----------+   +----------+      +---------+
//! ```
//!
//! The parser first expects a literal string "foo" as denoted by the
//! `literal("foo")`. After this literal value, an optional integer can be
//! provided. Note that the second argument is optional due to the `Execute`
//! attached to the `Then` that branches to that argument.
//!
//! Unlike Mojang's brigadier, arguments are not collected in a `Context`
//! object. They are instead fed directly into the provided closures. A generic
//! context however is provided so dependents can pass data to the closures
//! after parsing (`ctx` in the example).
//!
//! ### Command help
//!
//! A `HelpArgument` is provided to easily integrate a command into a help
//! system. This is done by calling `help()` on a command parser like this:
//! ```no_run
//! # use brigadier_rs::{literal, integer_i32, Then, BuildExecute, ThenHelp, UsagePrint};
//! # use std::convert::Infallible;
//! let parser = literal("foo")
//!     .then(
//!         integer_i32("bar")
//!             .build_exec(|ctx: (), bar| {
//!                 println!("Bar is {}", bar);
//!                 Ok::<(), Infallible>(())
//!             })
//!     ).build_exec(|ctx| {
//!         println!("Called foo with no arguments");
//!         Ok::<(), Infallible>(())
//!     })
//!     .help("Short description of foo")
//!     .build_exec(|ctx: (), usages: UsagePrint<_>| {
//!         println!("'foo help' was called");
//!         Ok::<(), Infallible>(())
//!     });
//! ```
//!
//! The parser can now return `foo` and `Short description of foo` when queried
//! using [`HelpUsage`], this is useful for collecting a list of commands. This
//! also automatically chains a [`HelpArgument`](self::parsers::HelpArgument)
//! for `foo help`. The `usages` variable is an iterator over all the different
//! syntaxes this parser understands ([`UsagePrint`]). In this example, that
//! would be:
//!
//! - `foo`
//! - `foo <bar>`
//!
//! There will be as many syntaxes as action points (`build_exec`
//! or`build_propagate`) defined. Note that `foo help` is ignored.

mod argument;
mod error;
pub mod parsers;
mod usage;

pub use argument::*;
pub use error::{CmdErrorKind, CommandError};
pub use parsers::bool::boolean;
pub use parsers::help::{HelpEntry, HelpUsage, ThenHelp};
pub use parsers::literal::literal;
pub use parsers::number::{
    float_32, float_64, integer_i16, integer_i32, integer_i64, integer_i8, integer_u16, integer_u32, integer_u64, integer_u8,
};
pub use usage::*;

/// Parser trait combination of `Execute` and `HelpUsage`.
///
/// This is the result of combining one or more parsers.
pub trait CommandParser<S, U>: Execute<S, U> + HelpUsage {}

impl<S, T, U> CommandParser<S, U> for T where T: Execute<S, U> + HelpUsage {}

#[cfg(test)]
mod tests {
    use std::convert::Infallible;

    use nom::Finish;

    use crate::parsers::help::ThenHelp;
    use crate::{boolean, integer_i32, literal, BuildExecute, CommandParser, Execute, Then, UsagePrint};

    #[test]
    fn test_main() {
        let parser = literal("foo")
            .then(integer_i32("bar").max(10).build_exec(|_, i| {
                println!("Found integer {}", i);
                Ok::<(), Infallible>(())
            }))
            .build_exec(|_| {
                println!("Didn't wanna give us a value aye?");
                Ok::<(), Infallible>(())
            });

        assert!(parser.execute((), "foo 13").is_err());
        assert_eq!(("", ()), parser.execute((), "foo").unwrap());
    }

    #[test]
    fn test_usage() {
        let parser: Box<dyn CommandParser<i32, ()>> = Box::new(
            literal("foo")
                .then(integer_i32("bar").max(10).build_exec(|x, i| {
                    println!("Found integer {} for source {}", i, x);
                    Ok::<(), Infallible>(())
                }))
                .then(boolean("buzz").build_exec(|_, _| Ok::<(), Infallible>(())))
                .build_exec(|_| {
                    println!("Didn't wanna give us a value aye?");
                    Ok::<(), Infallible>(())
                })
                .help("Test description")
                .build_exec(|_, mut usages: UsagePrint<_>| {
                    assert_eq!("foo", usages.next().unwrap().unwrap());
                    assert_eq!("foo <bar>", usages.next().unwrap().unwrap());
                    assert_eq!("foo <buzz>", usages.next().unwrap().unwrap());
                    assert!(usages.next().is_none());
                    Ok::<(), Infallible>(())
                }),
        );

        let help = parser.help();
        println!("{:?}", help);

        assert_eq!(("", ()), parser.execute(10, "foo").unwrap());
        assert_eq!(
            "Unknown input: /foo true<--[HERE]",
            parser
                .execute(10, "foo true hahah")
                .finish()
                .unwrap_err()
                .convert("/foo true hahah", 10)
        );
        assert_eq!(
            "number too large to fit in target type: ...8945645620<--[HERE]",
            parser
                .execute(10, "foo 12345678945645620")
                .finish()
                .unwrap_err()
                .convert("/foo 12345678945645620", 10)
        );
        assert_eq!(("", ()), parser.execute(12, "foo true").unwrap());
        assert_eq!(("", ()), parser.execute(15, "foo help").unwrap());
    }
}