diff options
Diffstat (limited to 'src/command.rs')
-rw-r--r-- | src/command.rs | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/src/command.rs b/src/command.rs index 30aabe2..bfd09d8 100644 --- a/src/command.rs +++ b/src/command.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use std::fmt; | 1 | use std::fmt; |
2 | use std::str::FromStr; | ||
2 | 3 | ||
3 | use cursive::event::{Event, EventResult, Key}; | 4 | use cursive::event::{Event, EventResult, Key}; |
4 | use cursive::theme::{BaseColor, Color, ColorStyle}; | 5 | use cursive::theme::{BaseColor, Color, ColorStyle}; |
@@ -105,9 +106,47 @@ fn call_on_app(s: &mut Cursive, input: &str) { | |||
105 | } | 106 | } |
106 | } | 107 | } |
107 | 108 | ||
109 | #[derive(Debug, PartialEq)] | ||
110 | pub enum GoalKind { | ||
111 | Count(u32), | ||
112 | Bit, | ||
113 | Float(u32, u8), | ||
114 | Addiction(u32), | ||
115 | } | ||
116 | |||
117 | impl FromStr for GoalKind { | ||
118 | type Err = CommandLineError; | ||
119 | |||
120 | fn from_str(s: &str) -> Result<Self> { | ||
121 | if let Some(n) = s.strip_prefix("<") { | ||
122 | return n | ||
123 | .parse::<u32>() | ||
124 | .map_err(|_| CommandLineError::InvalidGoal(s.into())) | ||
125 | .map(GoalKind::Addiction); | ||
126 | } else if s.contains(".") { | ||
127 | let value = s | ||
128 | .chars() | ||
129 | .filter(|x| x.is_digit(10)) | ||
130 | .collect::<String>() | ||
131 | .parse::<u32>() | ||
132 | .map_err(|_| CommandLineError::InvalidCommand(s.into()))?; | ||
133 | let precision = s.chars().skip_while(|&x| x != '.').count() - 1; | ||
134 | return Ok(GoalKind::Float(value, precision as u8)); | ||
135 | } | ||
136 | if let Ok(v) = s.parse::<u32>() { | ||
137 | if v == 1 { | ||
138 | return Ok(GoalKind::Bit); | ||
139 | } else { | ||
140 | return Ok(GoalKind::Count(v)); | ||
141 | } | ||
142 | } | ||
143 | return Err(CommandLineError::InvalidCommand(s.into())); | ||
144 | } | ||
145 | } | ||
146 | |||
108 | #[derive(PartialEq)] | 147 | #[derive(PartialEq)] |
109 | pub enum Command { | 148 | pub enum Command { |
110 | Add(String, Option<u32>, bool), | 149 | Add(String, Option<GoalKind>, bool), |
111 | MonthPrev, | 150 | MonthPrev, |
112 | MonthNext, | 151 | MonthNext, |
113 | Delete(String), | 152 | Delete(String), |
@@ -125,6 +164,7 @@ pub enum CommandLineError { | |||
125 | InvalidCommand(String), // command name | 164 | InvalidCommand(String), // command name |
126 | InvalidArg(u32), // position | 165 | InvalidArg(u32), // position |
127 | NotEnoughArgs(String, u32), // command name, required no. of args | 166 | NotEnoughArgs(String, u32), // command name, required no. of args |
167 | InvalidGoal(String), // goal expression | ||
128 | } | 168 | } |
129 | 169 | ||
130 | impl std::error::Error for CommandLineError {} | 170 | impl std::error::Error for CommandLineError {} |
@@ -137,6 +177,7 @@ impl fmt::Display for CommandLineError { | |||
137 | CommandLineError::NotEnoughArgs(s, n) => { | 177 | CommandLineError::NotEnoughArgs(s, n) => { |
138 | write!(f, "Command `{}` requires atleast {} argument(s)!", s, n) | 178 | write!(f, "Command `{}` requires atleast {} argument(s)!", s, n) |
139 | } | 179 | } |
180 | CommandLineError::InvalidGoal(s) => write!(f, "Invalid goal expression: `{}`", s), | ||
140 | } | 181 | } |
141 | } | 182 | } |
142 | } | 183 | } |
@@ -156,13 +197,7 @@ impl Command { | |||
156 | if args.is_empty() { | 197 | if args.is_empty() { |
157 | return Err(CommandLineError::NotEnoughArgs(first, 1)); | 198 | return Err(CommandLineError::NotEnoughArgs(first, 1)); |
158 | } | 199 | } |
159 | let goal = args | 200 | let goal = args.get(1).map(|x| GoalKind::from_str(x)).transpose()?; |
160 | .get(1) | ||
161 | .map(|x| { | ||
162 | x.parse::<u32>() | ||
163 | .map_err(|_| CommandLineError::InvalidArg(2)) | ||
164 | }) | ||
165 | .transpose()?; | ||
166 | return Ok(Command::Add( | 201 | return Ok(Command::Add( |
167 | args.get_mut(0).unwrap().to_string(), | 202 | args.get_mut(0).unwrap().to_string(), |
168 | goal, | 203 | goal, |