1use std::{iter::Peekable, marker::PhantomData, ops::Range, path::PathBuf};
10
11use crossterm::style::Color;
12
13use crate::{
14 buffer::Buffer,
15 context::Handle,
16 data::Pass,
17 form::{self, FormId},
18 text::{Text, txt},
19};
20
21pub trait Parameter<'a>: Sized {
39 type Returns;
41 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text>;
46}
47
48impl<'a, P: Parameter<'a>> Parameter<'a> for Option<P> {
49 type Returns = Option<P::Returns>;
50
51 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
58 match args.next_as::<P>(pa) {
59 Ok(arg) => Ok((Some(arg), None)),
60 Err(err) if args.is_forming_param => Err(err),
61 Err(_) => Ok((None, None)),
62 }
63 }
64}
65
66impl<'a, P: Parameter<'a>> Parameter<'a> for Vec<P> {
67 type Returns = Vec<P::Returns>;
68
69 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
76 let mut returns = Vec::new();
77
78 loop {
79 match args.next_as::<P>(pa) {
80 Ok(ret) => returns.push(ret),
81 Err(err) if args.is_forming_param => return Err(err),
82 Err(_) => break Ok((returns, None)),
83 }
84 }
85 }
86}
87
88impl<'a, const N: usize, P: Parameter<'a>> Parameter<'a> for [P; N] {
89 type Returns = [P::Returns; N];
90
91 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
98 use std::mem::MaybeUninit;
99 let mut returns = [const { MaybeUninit::uninit() }; N];
100
101 for r in returns.iter_mut() {
102 match args.next_as::<P>(pa) {
103 Ok(ret) => *r = MaybeUninit::new(ret),
104 Err(err) => return Err(err),
105 }
106 }
107
108 Ok((returns.map(|ret| unsafe { ret.assume_init() }), None))
109 }
110}
111
112pub struct Between<const MIN: usize, const MAX: usize, P>(PhantomData<P>);
119
120impl<'a, const MIN: usize, const MAX: usize, P: Parameter<'a>> Parameter<'a>
121 for Between<MIN, MAX, P>
122{
123 type Returns = Vec<P::Returns>;
124
125 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
132 let mut returns = Vec::new();
133
134 for _ in 0..MAX {
135 match args.next_as::<P>(pa) {
136 Ok(ret) => returns.push(ret),
137 Err(err) if args.is_forming_param => return Err(err),
138 Err(_) if returns.len() >= MIN => return Ok((returns, None)),
139 Err(err) => return Err(err),
140 }
141 }
142
143 if returns.len() >= MIN {
144 Ok((returns, None))
145 } else {
146 Err(txt!(
147 "List needed at least [a]{MIN}[] elements, got only [a]{}",
148 returns.len()
149 ))
150 }
151 }
152}
153
154impl<'a> Parameter<'a> for &'a str {
155 type Returns = &'a str;
156
157 fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
158 args.next().map(|arg| (arg, None))
159 }
160}
161
162impl Parameter<'_> for String {
163 type Returns = String;
164
165 fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
166 Ok((args.next()?.to_string(), None))
167 }
168}
169
170pub struct Remainder;
174
175impl Parameter<'_> for Remainder {
176 type Returns = String;
177
178 fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
179 let remainder: String = std::iter::from_fn(|| args.next().ok())
180 .collect::<Vec<&str>>()
181 .join(" ");
182 if remainder.is_empty() {
183 Err(txt!("There are no more arguments"))
184 } else {
185 Ok((remainder, None))
186 }
187 }
188}
189
190pub struct ColorSchemeArg;
194
195impl<'a> Parameter<'a> for ColorSchemeArg {
196 type Returns = &'a str;
197
198 fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
199 let scheme = args.next()?;
200 if crate::form::colorscheme_exists(scheme) {
201 Ok((scheme, None))
202 } else {
203 Err(txt!("The colorscheme [a]{scheme}[] was not found"))
204 }
205 }
206}
207
208impl<'a> Parameter<'a> for Buffer {
209 type Returns = Handle;
210
211 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
212 let buffer_name = args.next()?;
213 if let Some(handle) = crate::context::windows()
214 .buffers(pa)
215 .find(|handle| handle.read(pa).name() == buffer_name)
216 {
217 Ok((handle, Some(form::id_of!("param.buffer.open"))))
218 } else {
219 Err(txt!("No buffer called [a]{buffer_name}[] open"))
220 }
221 }
222}
223
224pub struct OtherBuffer;
229
230impl<'a> Parameter<'a> for OtherBuffer {
231 type Returns = Handle;
232
233 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
234 let handle = args.next_as::<Buffer>(pa)?;
235 let cur_handle = crate::context::current_buffer(pa);
236 if *cur_handle == handle {
237 Err(txt!("Argument can't be the current buffer"))
238 } else {
239 Ok((handle, Some(form::id_of!("param.buffer.open"))))
240 }
241 }
242}
243
244pub struct ValidBuffer;
248
249impl Parameter<'_> for ValidBuffer {
250 type Returns = PathBuf;
251
252 fn new(pa: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
253 let path = args.next_as::<PathBuf>(pa)?;
254
255 let canon_path = path.canonicalize();
256 let path = if let Ok(path) = &canon_path {
257 if !path.is_file() {
258 return Err(txt!("Path is not a buffer"));
259 }
260 path.clone()
261 } else if canon_path.is_err()
262 && let Ok(canon_path) = path.with_file_name(".").canonicalize()
263 {
264 canon_path.join(
265 path.file_name()
266 .ok_or_else(|| txt!("Path has no buffer name"))?,
267 )
268 } else {
269 return Err(txt!("Path was not found"));
270 };
271
272 if let Some(parent) = path.parent()
273 && let Ok(false) | Err(_) = parent.try_exists()
274 {
275 return Err(txt!("Path's parent doesn't exist"));
276 }
277
278 let form = if crate::context::windows()
279 .buffers(pa)
280 .map(|handle| handle.read(pa).path())
281 .any(|p| std::path::Path::new(&p) == path)
282 {
283 form::id_of!("param.buffer.open")
284 } else if let Ok(true) = path.try_exists() {
285 form::id_of!("param.buffer.exists")
286 } else {
287 form::id_of!("param.buffer")
288 };
289
290 Ok((path, Some(form)))
291 }
292}
293
294pub(super) enum PathOrBufferOrCfg {
296 Path(PathBuf),
297 Buffer(Handle),
298 Cfg,
299 CfgManifest,
300}
301
302impl Parameter<'_> for PathOrBufferOrCfg {
303 type Returns = Self;
304
305 fn new(pa: &Pass, args: &mut Args<'_>) -> Result<(Self::Returns, Option<FormId>), Text> {
306 if args.flags.word("cfg") {
307 Ok((Self::Cfg, None))
308 } else if args.flags.word("cfg-manifest") {
309 Ok((Self::CfgManifest, None))
310 } else if let Ok((handle, form)) = args.next_as_with_form::<Buffer>(pa) {
311 Ok((Self::Buffer(handle), form))
312 } else {
313 let (path, form) = args.next_as_with_form::<ValidBuffer>(pa)?;
314 Ok((Self::Path(path), form))
315 }
316 }
317}
318
319pub struct F32PercentOfU8;
324
325impl Parameter<'_> for F32PercentOfU8 {
326 type Returns = f32;
327
328 fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
329 let arg = args.next()?;
330 if let Some(percentage) = arg.strip_suffix("%") {
331 let percentage: u8 = percentage
332 .parse()
333 .map_err(|_| txt!("[a]{arg}[] is not a valid percentage"))?;
334 if percentage <= 100 {
335 Ok((percentage as f32 / 100.0, None))
336 } else {
337 Err(txt!("[a]{arg}[] is more than [a]100%"))
338 }
339 } else {
340 let byte: u8 = arg
341 .parse()
342 .map_err(|_| txt!("[a]{arg}[] couldn't be parsed"))?;
343 Ok((byte as f32 / 255.0, None))
344 }
345 }
346}
347
348impl<'a> Parameter<'a> for Color {
349 type Returns = Color;
350
351 fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
352 const fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
353 t = if t < 0.0 { t + 1.0 } else { t };
354 t = if t > 1.0 { t - 1.0 } else { t };
355 if t < 1.0 / 6.0 {
356 p + (q - p) * 6.0 * t
357 } else if t < 1.0 / 2.0 {
358 q
359 } else if t < 2.0 / 3.0 {
360 p + (q - p) * (2.0 / 3.0 - t) * 6.0
361 } else {
362 p
363 }
364 }
365
366 let arg = args.next()?;
367 if let Some(hex) = arg.strip_prefix("#") {
369 let total = match u32::from_str_radix(hex, 16) {
370 Ok(total) if hex.len() == 6 => total,
371 _ => return Err(txt!("Hexcode does not contain 6 hex values")),
372 };
373 let r = (total >> 16) as u8;
374 let g = (total >> 8) as u8;
375 let b = total as u8;
376 Ok((Color::Rgb { r, g, b }, None))
377 } else if arg == "rgb" {
379 let r = args.next_as::<u8>(pa)?;
380 let g = args.next_as::<u8>(pa)?;
381 let b = args.next_as::<u8>(pa)?;
382 Ok((Color::Rgb { r, g, b }, None))
383 } else if arg == "hsl" {
385 let hue = args.next_as::<F32PercentOfU8>(pa)?;
386 let sat = args.next_as::<F32PercentOfU8>(pa)?;
387 let lit = args.next_as::<F32PercentOfU8>(pa)?;
388 let [r, g, b] = if sat == 0.0 {
389 [lit.round() as u8; 3]
390 } else {
391 let q = if lit < 0.5 {
392 lit * (1.0 + sat)
393 } else {
394 lit + sat - lit * sat
395 };
396 let p = 2.0 * lit - q;
397 let r = hue_to_rgb(p, q, hue + 1.0 / 3.0);
398 let g = hue_to_rgb(p, q, hue);
399 let b = hue_to_rgb(p, q, hue - 1.0 / 3.0);
400 [r.round() as u8, g.round() as u8, b.round() as u8]
401 };
402 Ok((Color::Rgb { r, g, b }, None))
403 } else {
404 Err(txt!("Color format was not recognized"))
405 }
406 }
407}
408
409pub struct FormName;
414
415impl<'a> Parameter<'a> for FormName {
416 type Returns = &'a str;
417
418 fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
419 let arg = args.next()?;
420 if !arg.chars().all(|c| c.is_ascii_alphanumeric() || c == '.') {
421 return Err(txt!("Expected identifiers separated by '.'s, found [a]{arg}"));
422 }
423 if crate::form::exists(arg) {
424 Ok((arg, Some(form::id_of_non_static(arg))))
425 } else {
426 Err(txt!("The form [a]{arg}[] has not been set"))
427 }
428 }
429}
430
431impl<'a> Parameter<'a> for Flags<'a> {
432 type Returns = Flags<'a>;
433
434 fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
435 Ok((args.flags.clone(), None))
436 }
437}
438
439pub struct Args<'a> {
453 args: Peekable<ArgsIter<'a>>,
454 param_range: Range<usize>,
455 has_to_start_param: bool,
456 is_forming_param: bool,
457 flags: Flags<'a>,
458}
459
460impl<'a> Args<'a> {
461 #[allow(clippy::should_implement_trait)]
463 pub fn next(&mut self) -> Result<&'a str, Text> {
464 match self.args.next() {
465 Some((arg, range)) => {
466 self.param_range = range.clone();
467 if self.has_to_start_param {
468 self.has_to_start_param = false;
469 self.is_forming_param = true;
470 }
471 Ok(arg)
472 }
473 None => Err(txt!("Wrong argument count")),
474 }
475 }
476
477 pub fn next_as<P: Parameter<'a>>(&mut self, pa: &Pass) -> Result<P::Returns, Text> {
482 let initial_args = self.args.clone();
483 self.has_to_start_param = true;
484 let ret = P::new(pa, self);
485 if ret.is_ok() {
486 self.is_forming_param = false;
487 } else {
488 self.args = initial_args
489 }
490 ret.map(|(arg, _)| arg)
491 }
492
493 pub fn next_as_with_form<P: Parameter<'a>>(
498 &mut self,
499 pa: &Pass,
500 ) -> Result<(P::Returns, Option<FormId>), Text> {
501 let initial_args = self.args.clone();
502 self.has_to_start_param = true;
503 let ret = P::new(pa, self);
504 if ret.is_ok() {
505 self.is_forming_param = false;
506 } else {
507 self.args = initial_args
508 }
509 ret
510 }
511
512 pub fn next_else<T: Into<Text>>(&mut self, to_text: T) -> Result<&'a str, Text> {
514 match self.args.next() {
515 Some((arg, _)) => Ok(arg),
516 None => Err(to_text.into()),
517 }
518 }
519
520 pub fn next_start(&mut self) -> Option<usize> {
526 self.args.peek().map(|(_, r)| r.start)
527 }
528
529 pub fn param_range(&self) -> Range<usize> {
535 self.param_range.clone()
536 }
537
538 pub(super) fn clone(&self) -> Self {
540 Self {
541 args: self.args.clone(),
542 param_range: self.param_range.clone(),
543 has_to_start_param: self.has_to_start_param,
544 is_forming_param: self.is_forming_param,
545 flags: self.flags.clone(),
546 }
547 }
548}
549
550#[derive(Clone)]
555pub struct Flags<'a> {
556 blob: String,
557 word: Vec<&'a str>,
558}
559
560impl Flags<'_> {
561 pub fn blob(&self, blob: impl AsRef<str>) -> bool {
563 let mut all_chars = true;
564 for char in blob.as_ref().chars() {
565 all_chars &= self.blob.contains(char);
566 }
567 all_chars
568 }
569
570 pub fn word(&self, flag: impl AsRef<str>) -> bool {
572 self.word.contains(&flag.as_ref())
573 }
574
575 pub fn is_empty(&self) -> bool {
577 self.blob.is_empty() && self.word.is_empty()
578 }
579}
580
581pub fn get_args(command: &str) -> super::Args<'_> {
586 let mut blob = String::new();
587 let mut word = Vec::new();
588
589 let args = args_iter(command);
590 let mut args = args.peekable();
591 let mut byte = 0;
592
593 while let Some((arg, range)) = args.peek() {
594 if let Some(word_arg) = arg.strip_prefix("--") {
595 if !word_arg.is_empty() {
596 args.next();
597 if !word.contains(&word_arg) {
598 word.push(word_arg)
599 }
600 } else {
601 args.next();
602 break;
603 }
604 } else if let Some(blob_arg) = arg.strip_prefix('-') {
605 args.next();
606 for char in blob_arg.chars() {
607 if !blob.contains(char) {
608 blob.push(char)
609 }
610 }
611 } else {
612 byte = range.start;
613 break;
614 }
615 }
616
617 super::Args {
618 args,
619 param_range: byte..byte,
620 has_to_start_param: false,
621 is_forming_param: false,
622 flags: super::Flags { blob, word },
623 }
624}
625
626#[define_opaque(ArgsIter)]
628pub fn args_iter(command: &str) -> ArgsIter<'_> {
629 let mut chars = command.char_indices();
630 let mut start = None;
631 let mut end = None;
632 let mut is_quoting = false;
633 let mut last_char = 'a';
635 let mut args: ArgsIter = std::iter::from_fn(move || {
636 while let Some((b, char)) = chars.next() {
637 let lc = last_char;
638 last_char = char;
639 if start.is_some() && char.is_whitespace() && !is_quoting {
640 end = Some(b);
641 break;
642 } else if char == '"' && lc != '\\' {
643 is_quoting = !is_quoting;
644 if !is_quoting {
645 end = Some(b + 1);
646 break;
647 } else {
648 start = Some(b);
649 }
650 } else if !char.is_whitespace() && start.is_none() {
651 start = Some(b);
652 }
653 }
654
655 let e = end.take().unwrap_or(command.len());
656 start.take().map(|s| (&command[s..e], s..e))
657 });
658 args.next();
659 args
660}
661
662#[doc(hidden)]
664pub type ArgsIter<'a> = impl Iterator<Item = (&'a str, std::ops::Range<usize>)> + Clone;
665
666parse_impl!(bool);
667parse_impl!(u8);
668parse_impl!(u16);
669parse_impl!(u32);
670parse_impl!(u64);
671parse_impl!(u128);
672parse_impl!(usize);
673parse_impl!(i8);
674parse_impl!(i16);
675parse_impl!(i32);
676parse_impl!(i64);
677parse_impl!(i128);
678parse_impl!(isize);
679parse_impl!(f32);
680parse_impl!(f64);
681parse_impl!(std::path::PathBuf);
682
683macro parse_impl($t:ty) {
684 impl Parameter<'_> for $t {
685 type Returns = Self;
686
687 fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
688 let arg = args.next()?;
689 let arg = arg.parse().map_err(|_| {
690 txt!("[a]{arg}[] couldn't be parsed as [a]{}[]", stringify!($t))
691 });
692 arg.map(|arg| (arg, None))
693 }
694 }
695}