shellfish/handler/
asynchronous.rs

1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use yansi::Paint;
5
6use crate::command::CommandType;
7use crate::Command;
8
9/// Async handler lets you run asynchronous commands. It also requires the
10/// shell to be run in asynchronous mode to support it.
11#[async_trait]
12pub trait AsyncHandler<T: Send> {
13    async fn handle_async(
14        &self,
15        args: Vec<String>,
16        commands: &HashMap<&str, Command<T>>,
17        state: &mut T,
18        description: &str,
19    ) -> bool;
20}
21
22/// Shellfish's default async handler. This handler is pretty simple, given
23/// the only built in commands are `help`, `quit` and `exit`.
24#[derive(Default, Copy, Clone, Eq, PartialEq)]
25pub struct DefaultAsyncHandler();
26
27#[async_trait]
28impl<T: Send> AsyncHandler<T> for DefaultAsyncHandler {
29    async fn handle_async(
30        &self,
31        line: Vec<String>,
32        commands: &HashMap<&str, Command<T>>,
33        state: &mut T,
34        description: &str,
35    ) -> bool {
36        if let Some(command) = line.first() {
37            // Add some padding.
38            println!();
39
40            match command.as_str() {
41                "quit" | "exit" => return true,
42                "help" => {
43                    println!("{}", description);
44
45                    // Print information about built-in commands
46                    println!("    help - displays help information.");
47                    println!("    quit - quits the shell.");
48                    println!("    exit - exits the shell.");
49                    for (name, command) in commands {
50                        println!("    {} - {}", name, command.help);
51                    }
52                }
53                _ => {
54                    // Attempt to find the command
55                    let command = commands.get(&line[0] as &str);
56
57                    // Checks if we got it
58                    match command {
59                        Some(command) => {
60                            if let Err(e) = match command.command {
61                                CommandType::Sync(c) => c(state, line),
62                                #[cfg(feature = "async")]
63                                CommandType::Async(a) => a(state, line).await,
64                            } {
65                                eprintln!("{}", Paint::red(&format!("Command exited unsuccessfully:\n{}\n({:?})", &e, &e)))
66                            }
67                        }
68                        None => {
69                            eprintln!(
70                                "{} {}",
71                                Paint::red("Command not found:"),
72                                line[0]
73                            )
74                        }
75                    }
76                }
77            }
78
79            // Padding
80            println!();
81        }
82        false
83    }
84}