1#[doc(hidden)]
4pub use abscissa_derive::Command;
5
6use crate::{runnable::Runnable, terminal};
7use clap::{FromArgMatches, Parser};
8use std::{env, ffi::OsString, fmt::Debug};
9use termcolor::ColorChoice;
10
11pub trait Command: Debug + FromArgMatches + Runnable {
15 fn name() -> &'static str;
17
18 fn description() -> &'static str;
20
21 fn authors() -> &'static str;
23
24 fn parse_args<T, I>(into_args: I) -> Self
26 where
27 Self: Parser,
28 I: IntoIterator<Item = T>,
29 T: Into<OsString> + Clone,
30 {
31 let args: Vec<OsString> = into_args.into_iter().map(|s| s.into()).collect();
32
33 Self::try_parse_from(args.as_slice()).unwrap_or_else(|err| {
34 terminal::init(ColorChoice::Auto);
35 err.exit()
36 })
37 }
38
39 fn parse_env_args() -> Self
41 where
42 Self: Parser,
43 {
44 Self::parse_args(env::args())
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use crate::{Command, Runnable};
51 use clap::Parser;
52
53 #[derive(Command, Debug, Parser)]
54 pub struct DummyCommand {}
55
56 impl Runnable for DummyCommand {
57 fn run(&self) {
58 panic!("unimplemented");
59 }
60 }
61
62 #[test]
63 fn derived_command_test() {
64 assert_eq!(DummyCommand::name(), "abscissa_core");
65 }
66}