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!(
422 "Expected identifiers separated by '.'s, found [a]{arg}"
423 ));
424 }
425 if crate::form::exists(arg) {
426 Ok((arg, Some(form::id_of_non_static(arg))))
427 } else {
428 Err(txt!("The form [a]{arg}[] has not been set"))
429 }
430 }
431}
432
433impl<'a> Parameter<'a> for Flags<'a> {
434 type Returns = Flags<'a>;
435
436 fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
437 Ok((args.flags.clone(), None))
438 }
439}
440
441pub struct Args<'a> {
455 args: Peekable<ArgsIter<'a>>,
456 param_range: Range<usize>,
457 has_to_start_param: bool,
458 is_forming_param: bool,
459 flags: Flags<'a>,
460}
461
462impl<'a> Args<'a> {
463 #[allow(clippy::should_implement_trait)]
465 pub fn next(&mut self) -> Result<&'a str, Text> {
466 match self.args.next() {
467 Some((arg, range)) => {
468 self.param_range = range.clone();
469 if self.has_to_start_param {
470 self.has_to_start_param = false;
471 self.is_forming_param = true;
472 }
473 Ok(arg)
474 }
475 None => Err(txt!("Wrong argument count")),
476 }
477 }
478
479 pub fn next_as<P: Parameter<'a>>(&mut self, pa: &Pass) -> Result<P::Returns, Text> {
484 let initial_args = self.args.clone();
485 self.has_to_start_param = true;
486 let ret = P::new(pa, self);
487 if ret.is_ok() {
488 self.is_forming_param = false;
489 } else {
490 self.args = initial_args
491 }
492 ret.map(|(arg, _)| arg)
493 }
494
495 pub fn next_as_with_form<P: Parameter<'a>>(
500 &mut self,
501 pa: &Pass,
502 ) -> Result<(P::Returns, Option<FormId>), Text> {
503 let initial_args = self.args.clone();
504 self.has_to_start_param = true;
505 let ret = P::new(pa, self);
506 if ret.is_ok() {
507 self.is_forming_param = false;
508 } else {
509 self.args = initial_args
510 }
511 ret
512 }
513
514 pub fn next_else<T: Into<Text>>(&mut self, to_text: T) -> Result<&'a str, Text> {
516 match self.args.next() {
517 Some((arg, _)) => Ok(arg),
518 None => Err(to_text.into()),
519 }
520 }
521
522 pub fn next_start(&mut self) -> Option<usize> {
528 self.args.peek().map(|(_, r)| r.start)
529 }
530
531 pub fn param_range(&self) -> Range<usize> {
537 self.param_range.clone()
538 }
539
540 pub(super) fn clone(&self) -> Self {
542 Self {
543 args: self.args.clone(),
544 param_range: self.param_range.clone(),
545 has_to_start_param: self.has_to_start_param,
546 is_forming_param: self.is_forming_param,
547 flags: self.flags.clone(),
548 }
549 }
550}
551
552#[derive(Clone)]
557pub struct Flags<'a> {
558 blob: String,
559 word: Vec<&'a str>,
560}
561
562impl Flags<'_> {
563 pub fn blob(&self, blob: impl AsRef<str>) -> bool {
565 let mut all_chars = true;
566 for char in blob.as_ref().chars() {
567 all_chars &= self.blob.contains(char);
568 }
569 all_chars
570 }
571
572 pub fn word(&self, flag: impl AsRef<str>) -> bool {
574 self.word.contains(&flag.as_ref())
575 }
576
577 pub fn is_empty(&self) -> bool {
579 self.blob.is_empty() && self.word.is_empty()
580 }
581}
582
583pub fn get_args(command: &str) -> super::Args<'_> {
588 let mut blob = String::new();
589 let mut word = Vec::new();
590
591 let args = ArgsIter::new(command);
592 let mut args = args.peekable();
593 let mut byte = 0;
594
595 while let Some((arg, range)) = args.peek() {
596 if let Some(word_arg) = arg.strip_prefix("--") {
597 if !word_arg.is_empty() {
598 args.next();
599 if !word.contains(&word_arg) {
600 word.push(word_arg)
601 }
602 } else {
603 args.next();
604 break;
605 }
606 } else if let Some(blob_arg) = arg.strip_prefix('-') {
607 args.next();
608 for char in blob_arg.chars() {
609 if !blob.contains(char) {
610 blob.push(char)
611 }
612 }
613 } else {
614 byte = range.start;
615 break;
616 }
617 }
618
619 super::Args {
620 args,
621 param_range: byte..byte,
622 has_to_start_param: false,
623 is_forming_param: false,
624 flags: super::Flags { blob, word },
625 }
626}
627
628#[derive(Clone)]
633pub struct ArgsIter<'a> {
634 command: &'a str,
635 chars: std::str::CharIndices<'a>,
636 start: Option<usize>,
637 end: Option<usize>,
638 is_quoting: bool,
639 last_char: char,
640}
641
642impl<'a> ArgsIter<'a> {
643 pub fn new(command: &'a str) -> Self {
645 let mut args_iter = Self {
646 command,
647 chars: command.char_indices(),
648 start: None,
649 end: None,
650 is_quoting: false,
651 last_char: 'a',
653 };
654
655 args_iter.next();
656 args_iter
657 }
658}
659
660impl<'a> Iterator for ArgsIter<'a> {
661 type Item = (&'a str, Range<usize>);
662
663 fn next(&mut self) -> Option<Self::Item> {
664 while let Some((b, char)) = self.chars.next() {
665 let lc = self.last_char;
666 self.last_char = char;
667 if self.start.is_some() && char.is_whitespace() && !self.is_quoting {
668 self.end = Some(b);
669 break;
670 } else if char == '"' && lc != '\\' {
671 self.is_quoting = !self.is_quoting;
672 if !self.is_quoting {
673 self.end = Some(b + 1);
674 break;
675 } else {
676 self.start = Some(b);
677 }
678 } else if !char.is_whitespace() && self.start.is_none() {
679 self.start = Some(b);
680 }
681 }
682
683 let e = self.end.take().unwrap_or(self.command.len());
684 self.start.take().map(|s| (&self.command[s..e], s..e))
685 }
686}
687
688macro_rules! parse_impl {
689 ($t:ty) => {
690 impl Parameter<'_> for $t {
691 type Returns = Self;
692
693 fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
694 let arg = args.next()?;
695 let arg = arg
696 .parse()
697 .map_err(|_| txt!("[a]{arg}[] couldn't be parsed as [a]{}[]", stringify!($t)));
698 arg.map(|arg| (arg, None))
699 }
700 }
701 };
702}
703
704parse_impl!(bool);
705parse_impl!(u8);
706parse_impl!(u16);
707parse_impl!(u32);
708parse_impl!(u64);
709parse_impl!(u128);
710parse_impl!(usize);
711parse_impl!(i8);
712parse_impl!(i16);
713parse_impl!(i32);
714parse_impl!(i64);
715parse_impl!(i128);
716parse_impl!(isize);
717parse_impl!(f32);
718parse_impl!(f64);
719parse_impl!(std::path::PathBuf);