1use crate::brush::BrushMode;
4use crate::platform;
5use crate::session::{Direction, Mode, VisualState};
6
7use std::fmt;
8use std::path::PathBuf;
9use std::result;
10use std::str::FromStr;
11
12use directories as dirs;
13use rgx::core::Rgba8;
14
15pub type Result<'a, T> = result::Result<(T, Parser<'a>), Error>;
16
17#[derive(Debug, Clone)]
18pub struct Error {
19 msg: String,
20}
21
22impl Error {
23 pub fn new<S: Into<String>>(msg: S) -> Self {
24 Self { msg: msg.into() }
25 }
26
27 #[allow(dead_code)]
28 fn from<S: Into<String>, E: std::error::Error>(msg: S, err: E) -> Self {
29 Self {
30 msg: format!("{}: {}", msg.into(), err),
31 }
32 }
33}
34
35impl std::error::Error for Error {}
36
37impl From<&str> for Error {
38 fn from(input: &str) -> Self {
39 Error::new(input)
40 }
41}
42
43impl fmt::Display for Error {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 self.msg.fmt(f)
46 }
47}
48
49pub trait Parse<'a>: Sized {
50 fn parse(input: Parser<'a>) -> Result<'a, Self>;
51}
52
53impl<'a> Parse<'a> for Rgba8 {
54 fn parse(p: Parser<'a>) -> Result<'a, Self> {
55 let (s, rest) = p.count(7)?; match Rgba8::from_str(s) {
58 Ok(u) => Ok((u, rest)),
59 Err(_) => Err(Error::new(format!("malformed color value `{}`", s))),
60 }
61 }
62}
63
64impl<'a> Parse<'a> for u32 {
65 fn parse(p: Parser<'a>) -> Result<'a, Self> {
66 let (s, rest) = p.word()?;
67
68 match u32::from_str(s) {
69 Ok(u) => Ok((u, rest)),
70 Err(_) => Err(Error::new("error parsing u32")),
71 }
72 }
73}
74
75impl<'a> Parse<'a> for i32 {
76 fn parse(p: Parser<'a>) -> Result<'a, Self> {
77 let (s, rest) = p.word()?;
78
79 match i32::from_str(s) {
80 Ok(u) => Ok((u, rest)),
81 Err(_) => Err(Error::new("error parsing i32")),
82 }
83 }
84}
85
86impl<'a> Parse<'a> for f64 {
87 fn parse(p: Parser<'a>) -> Result<'a, Self> {
88 let (s, rest) = p.word()?;
89
90 match f64::from_str(s) {
91 Ok(u) => Ok((u, rest)),
92 Err(_) => Err(Error::new("error parsing f64")),
93 }
94 }
95}
96
97impl<'a> Parse<'a> for (u32, u32) {
98 fn parse(p: Parser<'a>) -> Result<'a, Self> {
99 let (w, p) = p.parse::<u32>()?;
100 let (_, p) = p.whitespace()?;
101 let (h, p) = p.parse::<u32>()?;
102
103 Ok(((w, h), p))
104 }
105}
106
107impl<'a> Parse<'a> for (i32, i32) {
108 fn parse(p: Parser<'a>) -> Result<'a, Self> {
109 let (w, p) = p.parse::<i32>()?;
110 let (_, p) = p.whitespace()?;
111 let (h, p) = p.parse::<i32>()?;
112
113 Ok(((w, h), p))
114 }
115}
116
117impl<'a> Parse<'a> for (f64, f64) {
118 fn parse(p: Parser<'a>) -> Result<'a, Self> {
119 let (x, p) = p.parse::<f64>()?;
120 let (_, p) = p.whitespace()?;
121 let (y, p) = p.parse::<f64>()?;
122
123 Ok(((x, y), p))
124 }
125}
126
127impl<'a> Parse<'a> for char {
128 fn parse(p: Parser<'a>) -> Result<'a, Self> {
129 if let Some(c) = p.input.chars().next() {
130 Ok((c, Parser::new(&p.input[1..])))
131 } else {
132 Err(Error::new("error parsing char"))
133 }
134 }
135}
136
137impl<'a> Parse<'a> for BrushMode {
138 fn parse(p: Parser<'a>) -> Result<'a, Self> {
139 let (id, p) = p.identifier()?;
140 match id {
141 "erase" => Ok((BrushMode::Erase, p)),
142 "multi" => Ok((BrushMode::Multi, p)),
143 "perfect" => Ok((BrushMode::Perfect, p)),
144 "xsym" => Ok((BrushMode::XSym, p)),
145 "ysym" => Ok((BrushMode::YSym, p)),
146 "xray" => Ok((BrushMode::XRay, p)),
147 mode => Err(Error::new(format!("unknown brush mode '{}'", mode))),
148 }
149 }
150}
151
152impl<'a> Parse<'a> for platform::Key {
153 fn parse(p: Parser<'a>) -> Result<'a, Self> {
154 let (c, p) = p.parse::<char>()?;
155 let key: platform::Key = c.into();
156
157 if key == platform::Key::Unknown {
158 return Err(Error::new(format!("unknown key {:?}", c)));
159 }
160 Ok((key, p))
161 }
162}
163
164impl<'a> Parse<'a> for platform::InputState {
165 fn parse(p: Parser<'a>) -> Result<'a, Self> {
166 let (w, p) = p.word()?;
167 match w {
168 "pressed" => Ok((platform::InputState::Pressed, p)),
169 "released" => Ok((platform::InputState::Released, p)),
170 "repeated" => Ok((platform::InputState::Repeated, p)),
171 other => Err(Error::new(format!("unkown input state {:?}", other))),
172 }
173 }
174}
175
176impl<'a> Parse<'a> for Mode {
177 fn parse(p: Parser<'a>) -> Result<'a, Self> {
178 let (id, p) = p.identifier()?;
179 match id {
180 "command" => Ok((Mode::Command, p)),
181 "normal" => Ok((Mode::Normal, p)),
182 "visual" => Ok((Mode::Visual(VisualState::default()), p)),
183 "present" => Ok((Mode::Present, p)),
184 mode => Err(Error::new(format!("unknown mode '{}'", mode))),
185 }
186 }
187}
188
189impl<'a> Parse<'a> for Direction {
190 fn parse(p: Parser<'a>) -> Result<'a, Self> {
191 let (c, p) = p.parse::<char>()?;
192 match c {
193 '+' => Ok((Direction::Forward, p)),
194 '-' => Ok((Direction::Backward, p)),
195 _ => Err(Error::new("direction must be either `+` or `-`")),
196 }
197 }
198}
199
200#[derive(Debug, Clone)]
203pub struct Parser<'a> {
204 input: &'a str,
205}
206
207impl<'a> Parser<'a> {
208 pub fn new(input: &'a str) -> Self {
209 Self { input }
210 }
211
212 pub fn empty() -> Self {
213 Self { input: "" }
214 }
215
216 pub fn finish(self) -> Result<'a, ()> {
217 let (_, p) = self.whitespace()?;
218
219 if p.is_empty() {
220 Ok(((), Parser::empty()))
221 } else {
222 Err(Error::new(format!("extraneaous input: `{}`", p.input)))
223 }
224 }
225
226 pub fn path(self) -> Result<'a, String> {
227 let (path, parser) = self.word()?;
228
229 if path == "" {
230 return Ok((String::from(""), parser));
231 }
232
233 let mut path = PathBuf::from(path);
234
235 if cfg!(unix) {
237 if let Ok(suffix) = path.strip_prefix("~") {
238 if let Some(base_dirs) = dirs::BaseDirs::new() {
239 path = base_dirs.home_dir().join(suffix);
240 }
241 }
242 }
243
244 match path.to_str() {
245 Some(p) => Ok((p.to_string(), parser)),
246 None => Err(Error::new(format!("invalid path: {:?}", path))),
247 }
248 }
249
250 pub fn peek(&self) -> Option<char> {
251 self.input.chars().nth(0)
252 }
253
254 pub fn is_empty(&self) -> bool {
255 self.input.is_empty()
256 }
257
258 pub fn sigil(self, c: char) -> Result<'a, char> {
259 if self.input.starts_with(c) {
260 Ok((c, Parser::new(&self.input[1..])))
261 } else {
262 Err(Error::new(format!("expected '{}'", c)))
263 }
264 }
265
266 pub fn string(self) -> Result<'a, &'a str> {
267 let p = self;
268
269 let (_, p) = p.sigil('"')?;
270 let (s, p) = p.until(|c| c == '"')?;
271 let (_, p) = p.sigil('"')?;
272
273 Ok((s, p))
274 }
275
276 pub fn character(self) -> Result<'a, char> {
277 let p = self;
278
279 let (_, p) = p.sigil('\'')?;
280 let (c, p) = p.parse::<char>()?;
281 let (_, p) = p.sigil('\'')?;
282
283 Ok((c, p))
284 }
285
286 pub fn alpha(self) -> Result<'a, &'a str> {
287 self.expect(|c| c.is_alphanumeric())
288 }
289
290 pub fn comment(self) -> Result<'a, &'a str> {
291 let p = self;
292
293 let (_, p) = p.whitespace()?;
294 let (_, p) = p.sigil('-')?;
295 let (_, p) = p.sigil('-')?;
296 let (_, p) = p.whitespace()?;
297 let (s, p) = p.leftover()?;
298
299 Ok((s, p))
300 }
301
302 pub fn leftover(self) -> Result<'a, &'a str> {
303 Ok((self.input, Parser::empty()))
304 }
305
306 pub fn whitespace(self) -> Result<'a, ()> {
307 self.consume(|c| c.is_whitespace())
308 }
309
310 pub fn parse<T: Parse<'a>>(self) -> Result<'a, T> {
311 T::parse(self)
312 }
313
314 pub fn word(self) -> Result<'a, &'a str> {
315 self.expect(|c| !c.is_whitespace() && c != '{' && c != '}')
316 }
317
318 pub fn count(self, n: usize) -> Result<'a, &'a str> {
319 if self.input.len() >= n {
320 Ok((&self.input[..n], Parser::new(&self.input[n..])))
321 } else {
322 Err(Error::new("reached end of input"))
323 }
324 }
325
326 pub fn identifier(self) -> Result<'a, &'a str> {
327 self.expect(|c| {
328 (c.is_ascii_lowercase()
329 || c.is_ascii_uppercase()
330 || c.is_ascii_digit()
331 || [':', '/', '_', '+', '-', '!', '?'].contains(&c))
332 })
333 }
334
335 pub fn consume<P>(self, predicate: P) -> Result<'a, ()>
336 where
337 P: Fn(char) -> bool,
338 {
339 match self.input.find(|c| !predicate(c)) {
340 Some(i) => {
341 let (_, r) = self.input.split_at(i);
342 Ok(((), Parser::new(r)))
343 }
344 None => Ok(((), Parser::empty())),
345 }
346 }
347
348 pub fn until<P>(self, predicate: P) -> Result<'a, &'a str>
349 where
350 P: Fn(char) -> bool,
351 {
352 if self.input.is_empty() {
353 return Err(Error::new("expected input"));
354 }
355 match self.input.find(predicate) {
356 Some(i) => {
357 let (l, r) = self.input.split_at(i);
358 Ok((l, Parser::new(r)))
359 }
360 None => Ok((self.input, Parser::empty())),
361 }
362 }
363
364 pub fn expect<P>(self, predicate: P) -> Result<'a, &'a str>
365 where
366 P: Fn(char) -> bool,
367 {
368 if self.is_empty() {
369 return Err(Error::new("expected input"));
370 }
371 if !self.input.is_ascii() {
372 return Err(Error::new("error parsing non-ASCII characters"));
373 }
374
375 let mut index = 0;
376 for (i, c) in self.input.chars().enumerate() {
377 if predicate(c) {
378 index = i;
379 } else {
380 break;
381 }
382 }
383 let (l, r) = self.input.split_at(index + 1);
384 Ok((l, Parser::new(r)))
385 }
386}