generated from PlexSheep/baserepo
idk why this isn't in master yet #94
|
@ -12,6 +12,9 @@ repository.workspace = true
|
|||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
||||
|
||||
[features]
|
||||
default = ["log"]
|
||||
log = ["dep:libpt-log", "dep:log"]
|
||||
|
@ -22,6 +25,7 @@ clap = { version = "4.5.7", features = ["derive"] }
|
|||
comfy-table = "7.1.1"
|
||||
console = "0.15.8"
|
||||
dialoguer = { version = "0.11.0", features = ["completion", "history"] }
|
||||
embed-doc-image = "0.1.4"
|
||||
exitcode = "1.1.2"
|
||||
human-panic = "2.0.0"
|
||||
indicatif = "0.17.8"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 142 KiB |
|
@ -1,13 +1,61 @@
|
|||
//! This module implements a default repl that fullfills the [Repl] trait
|
||||
//!
|
||||
//! You can implement your own [Repl] if you want.
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::Repl;
|
||||
|
||||
use embed_doc_image::embed_doc_image;
|
||||
|
||||
/// [clap] help template with only usage and commands/options
|
||||
pub const REPL_HELP_TEMPLATE: &str = r#"{usage-heading} {usage}
|
||||
|
||||
{all-args}{tab}
|
||||
"#;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use dialoguer::{BasicHistory, Completion};
|
||||
use libpt_log::trace;
|
||||
|
||||
#[allow(clippy::needless_doctest_main)] // It makes the example look better
|
||||
/// Default implementation for a REPL
|
||||
///
|
||||
/// Note that you need to define the commands by yourself with a Subcommands enum.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use libpt_cli::repl::{DefaultRepl, Repl};
|
||||
/// use libpt_cli::clap::Subcommand;
|
||||
/// use libpt_cli::strum::EnumIter;
|
||||
///
|
||||
/// #[derive(Subcommand, Debug, EnumIter, Clone)]
|
||||
/// enum ReplCommand {
|
||||
/// /// hello world
|
||||
/// Hello,
|
||||
/// /// leave the repl
|
||||
/// Exit,
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut repl = DefaultRepl::<ReplCommand>::default();
|
||||
/// loop {
|
||||
/// repl.step().unwrap();
|
||||
/// match repl.command().to_owned().unwrap() {
|
||||
/// ReplCommand::Hello => println!("Hello"),
|
||||
/// ReplCommand::Exit => break,
|
||||
/// _ => (),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// **Screenshot**
|
||||
///
|
||||
/// ![Screenshot of an example program with a REPL][repl_screenshot]
|
||||
#[embed_doc_image("repl_screenshot", "data/media/repl.png")]
|
||||
#[derive(Parser)]
|
||||
#[command(multicall = true)]
|
||||
#[command(multicall = true, help_template = REPL_HELP_TEMPLATE)]
|
||||
pub struct DefaultRepl<C>
|
||||
where
|
||||
C: Debug,
|
||||
|
@ -31,7 +79,7 @@ where
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct DefaultReplCompletion<C>
|
||||
struct DefaultReplCompletion<C>
|
||||
where
|
||||
C: Debug,
|
||||
C: Subcommand,
|
||||
|
@ -58,12 +106,6 @@ where
|
|||
fn command(&self) -> &Option<C> {
|
||||
&self.command
|
||||
}
|
||||
#[allow(refining_impl_trait)]
|
||||
fn completion() -> DefaultReplCompletion<C> {
|
||||
DefaultReplCompletion {
|
||||
commands: std::marker::PhantomData::<C>,
|
||||
}
|
||||
}
|
||||
fn step(&mut self) -> Result<(), super::error::ReplError> {
|
||||
self.buf.clear();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Errors for the Repl module
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
//! Create easy and well defined REPLs
|
||||
//!
|
||||
//! A REPL is a [Read-Eval-Print-Loop](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop).
|
||||
//! Well known examples for REPLs are shells (like bash).
|
||||
//!
|
||||
//! This module offers a convenient way to create a well-defined REPL without a lot of complicated
|
||||
//! code and with a visually pleasing aesthetic. An example REPL implementation can be found in the
|
||||
//! examples.
|
||||
//!
|
||||
//! The basic idea is that the user defines the commands with an enum and uses [claps](clap)
|
||||
//! `#[derive(Subcommand)]`. A loop is then used to read from the stdin into a buffer, that buffer
|
||||
//! is put to [clap] for parsing, similar to how [clap] would parse commandline arguments.
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub mod error;
|
||||
|
@ -6,8 +19,10 @@ mod default;
|
|||
pub use default::*;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use dialoguer::Completion;
|
||||
|
||||
/// Common Trait for repl objects
|
||||
///
|
||||
/// Unless you want to implement custom features (not just commands), just use [DefaultRepl].
|
||||
pub trait Repl<C>: Parser + Debug
|
||||
where
|
||||
C: Debug,
|
||||
|
@ -18,12 +33,12 @@ where
|
|||
fn new() -> Self;
|
||||
/// get the command that was parsed from user input
|
||||
///
|
||||
/// Will only be [None] if the repl has not had [step] executed yet.
|
||||
/// Will only be [None] if the repl has not had [step](Repl::step) executed yet.
|
||||
fn command(&self) -> &Option<C>;
|
||||
/// return all possible commands in this repl
|
||||
fn completion() -> impl Completion;
|
||||
/// advance the repl to the next iteration of the main loop
|
||||
///
|
||||
/// This should be used at the start of your loop
|
||||
/// This should be used at the start of your loop.
|
||||
///
|
||||
/// Note that the help menu is an Error: [clap::error::ErrorKind::DisplayHelp]
|
||||
fn step(&mut self) -> Result<(), ReplError>;
|
||||
}
|
||||
|
|
Reference in New Issue