generated from PlexSheep/baserepo
feat(cli): add repl example without using library items
cargo devel CI / cargo CI (push) Failing after 1m43s
Details
cargo devel CI / cargo CI (push) Failing after 1m43s
Details
This commit is contained in:
parent
a9fe9d21ec
commit
d413b74d45
|
@ -0,0 +1,133 @@
|
|||
use libpt_cli::repl::REPL_HELP_TEMPLATE;
|
||||
use libpt_cli::{clap, dialoguer, printing};
|
||||
use libpt_log::{debug, trace, Level, Logger};
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
/// This is the help menu of the repl
|
||||
///
|
||||
/// More text here
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(multicall = true)]
|
||||
pub struct Repl {
|
||||
/// the command you want to execute, along with its args
|
||||
#[command(subcommand)]
|
||||
command: ReplCommand,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum ReplCommand {
|
||||
/// wait for LEN seconds
|
||||
Wait {
|
||||
/// wait so long
|
||||
len: u64,
|
||||
},
|
||||
/// echo the given texts
|
||||
Echo {
|
||||
/// the text you want to print
|
||||
text: Vec<String>,
|
||||
/// print with a fancy border and colors
|
||||
#[arg(short, long)]
|
||||
fancy: bool,
|
||||
},
|
||||
/// hello world
|
||||
Hello,
|
||||
/// leave the repl
|
||||
Exit,
|
||||
}
|
||||
|
||||
// TODO: somehow autogenerate this!!!
|
||||
pub struct MyCompletion {
|
||||
options: Vec<String>,
|
||||
}
|
||||
impl Default for MyCompletion {
|
||||
fn default() -> Self {
|
||||
MyCompletion {
|
||||
options: vec![
|
||||
"help".to_string(),
|
||||
"?".to_string(),
|
||||
"list".to_string(),
|
||||
"publish".to_string(),
|
||||
"unpublish".to_string(),
|
||||
"delete".to_string(),
|
||||
"read".to_string(),
|
||||
"show".to_string(),
|
||||
"new".to_string(),
|
||||
"ls".to_string(),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl dialoguer::Completion for MyCompletion {
|
||||
/// Simple completion implementation based on substring
|
||||
fn get(&self, input: &str) -> Option<String> {
|
||||
let matches = self
|
||||
.options
|
||||
.iter()
|
||||
.filter(|option| option.starts_with(input))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if matches.len() == 1 {
|
||||
Some(matches[0].to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let _logger = Logger::builder()
|
||||
.show_time(false)
|
||||
.max_level(Level::DEBUG)
|
||||
.build();
|
||||
|
||||
let mut buf: String = String::new();
|
||||
let mut buf_preparsed: Vec<String>;
|
||||
let completion = MyCompletion::default();
|
||||
let mut history = dialoguer::BasicHistory::new();
|
||||
|
||||
debug!("entering the repl");
|
||||
loop {
|
||||
buf.clear();
|
||||
|
||||
buf = dialoguer::Input::with_theme(&dialoguer::theme::ColorfulTheme::default())
|
||||
.completion_with(&completion)
|
||||
.history_with(&mut history)
|
||||
.interact_text()?;
|
||||
|
||||
buf_preparsed = Vec::new();
|
||||
buf_preparsed.extend(shlex::split(&buf).unwrap_or_default());
|
||||
|
||||
trace!("read input: {buf_preparsed:?}");
|
||||
|
||||
let options = match Repl::try_parse_from(buf_preparsed) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
println!("{e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match options.command {
|
||||
ReplCommand::Exit => break,
|
||||
ReplCommand::Wait { len } => {
|
||||
debug!("len: {len}");
|
||||
let spinner = indicatif::ProgressBar::new_spinner();
|
||||
spinner.enable_steady_tick(std::time::Duration::from_millis(100));
|
||||
std::thread::sleep(std::time::Duration::from_secs(len));
|
||||
spinner.finish();
|
||||
}
|
||||
ReplCommand::Hello => println!("Hello!"),
|
||||
ReplCommand::Echo { text, fancy } => {
|
||||
if !fancy {
|
||||
println!("{}", text.concat())
|
||||
}
|
||||
else {
|
||||
printing::blockprint(text.concat(), console::Color::Cyan)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
Reference in New Issue