1#[derive(Debug, Clone)]
9pub struct CommandContext {
10 pub name: String,
12 pub args: String,
14 pub source: String,
16 pub uuid: String,
18 pub dimension: String,
20}
21
22impl CommandContext {
23 pub fn arg_list(&self) -> Vec<&str> {
25 self.args.split_whitespace().collect()
26 }
27
28 pub fn typed_args(&self) -> Vec<&str> {
35 if self.args.is_empty() {
36 vec![]
37 } else {
38 self.args.split('\t').collect()
39 }
40 }
41
42 pub fn arg_str(&self, idx: usize) -> Option<&str> {
44 if self.args.is_empty() {
45 return None;
46 }
47 self.args.split('\t').nth(idx)
48 }
49
50 pub fn arg_int(&self, idx: usize) -> Option<i32> {
52 self.arg_str(idx)?.parse().ok()
53 }
54
55 pub fn arg_float(&self, idx: usize) -> Option<f32> {
57 self.arg_str(idx)?.parse().ok()
58 }
59
60 pub fn arg_player(&self, idx: usize) -> Option<&str> {
62 self.arg_str(idx)
63 }
64
65 pub fn arg_blockpos(&self, idx: usize) -> Option<(i32, i32, i32)> {
67 let s = self.arg_str(idx)?;
68 let mut it = s.split(',');
69 let x = it.next()?.parse().ok()?;
70 let y = it.next()?.parse().ok()?;
71 let z = it.next()?.parse().ok()?;
72 Some((x, y, z))
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 fn ctx(args: &str) -> CommandContext {
81 CommandContext { name: "hex".into(), args: args.into(), source: "Dev".into(), uuid: String::new(), dimension: String::new() }
82 }
83
84 #[test]
85 fn plain_and_typed_arguments() {
86 assert_eq!(ctx(" a b ").arg_list(), ["a", "b"]);
87 let t = ctx("5\t2.5\tSteve\t1,-2,3");
88 assert_eq!(t.typed_args().len(), 4);
89 assert_eq!(t.arg_int(0), Some(5));
90 assert_eq!(t.arg_float(1), Some(2.5));
91 assert_eq!(t.arg_player(2), Some("Steve"));
92 assert_eq!(t.arg_blockpos(3), Some((1, -2, 3)));
93 assert_eq!(t.arg_int(2), None, "not a number");
94 assert_eq!(t.arg_str(9), None);
95 assert!(ctx("").typed_args().is_empty());
96 assert_eq!(ctx("").arg_str(0), None);
97 assert_eq!(ctx("1,2").arg_blockpos(0), None);
98 }
99}