idk why this isn't in master yet #94

Merged
cscherrNT merged 79 commits from devel into master 2024-07-22 13:30:20 +02:00
6 changed files with 35 additions and 43 deletions
Showing only changes of commit 476efb85c8 - Show all commits

View File

@ -48,7 +48,7 @@ fn main() -> anyhow::Result<()> {
Err(e) => {
// if the user requested the help, print in blue, otherwise in red as it's just an
// error
if let libpt_cli::repl::error::ReplError::Parsing(e) = &e {
if let libpt_cli::repl::error::Error::Parsing(e) = &e {
if e.kind() == clap::error::ErrorKind::DisplayHelp {
println!("{}", style(e).cyan());
continue;
@ -76,7 +76,7 @@ fn main() -> anyhow::Result<()> {
if !fancy {
println!("{}", text.join(" "))
} else {
printing::blockprint(text.join(" "), console::Color::Cyan)
printing::blockprint(&text.join(" "), console::Color::Cyan)
}
}
}

View File

@ -80,7 +80,6 @@ Author: {author-with-newline}
/// # use libpt_cli::args::VerbosityLevel;
/// use libpt_log::Level;
/// # use clap::Parser;
/// use log;
///
/// # #[derive(Parser, Debug)]
/// # pub struct Opts {
@ -94,8 +93,6 @@ Author: {author-with-newline}
/// // Level might be None if the user wants no output at all.
/// // for the 'tracing' level:
/// let level: Level = opts.verbose.level();
/// // for the 'log' level:
/// let llevel: log::Level = opts.verbose.level_for_log_crate();
/// }
/// ```
#[derive(Parser, Clone, PartialEq, Eq, Hash)]

View File

@ -45,10 +45,11 @@ use console::{style, Color};
/// use libpt_cli::console::Color;
/// use libpt_cli::printing::blockprint;
/// # fn main() {
/// blockprint("Hello world!".to_string(), Color::Blue);
/// blockprint("Hello world!", Color::Blue);
/// # }
/// ```
#[inline]
#[allow(clippy::needless_pass_by_value)] // we just take an impl, using a &impl is much less ergonomic
pub fn blockprint(content: impl ToString, color: Color) {
println!("{}", blockfmt(content, color));
}
@ -66,11 +67,12 @@ pub fn blockprint(content: impl ToString, color: Color) {
/// use libpt_cli::console::Color;
/// use libpt_cli::printing::blockfmt;
/// # fn main() {
/// let formatted_content = blockfmt("Hello world!".to_string(), Color::Blue);
/// let formatted_content = blockfmt("Hello world!", Color::Blue);
/// println!("{}", formatted_content);
/// # }
/// ```
#[inline]
#[allow(clippy::needless_pass_by_value)] // we just take an impl, using a &impl is much less ergonomic
pub fn blockfmt(content: impl ToString, color: Color) -> String {
blockfmt_advanced(
content,
@ -98,7 +100,7 @@ pub fn blockfmt(content: impl ToString, color: Color) -> String {
/// println!(
/// "{}",
/// blockfmt_advanced(
/// "Hello world!".to_string(),
/// "Hello world!",
/// Some(Color::Blue),
/// presets::UTF8_FULL,
/// ContentArrangement::DynamicFullWidth,
@ -120,6 +122,8 @@ pub fn blockfmt(content: impl ToString, color: Color) -> String {
/// - `preset`: The preset style for the border
/// - `arrangement`: The arrangement of the the border (e.g., stretch to sides, wrap around )
/// - `alignment`: The alignment of the content within the cells (e.g., left, center, right)
#[allow(clippy::missing_panics_doc)] // we add a row then unwrap it, no panic should be possible
#[allow(clippy::needless_pass_by_value)] // we just take an impl, using a &impl is much less ergonomic
pub fn blockfmt_advanced(
content: impl ToString,
color: Option<Color>,

View File

@ -56,11 +56,10 @@ use libpt_log::trace;
#[embed_doc_image("repl_screenshot", "data/media/repl.png")]
#[derive(Parser)]
#[command(multicall = true, help_template = REPL_HELP_TEMPLATE)]
#[allow(clippy::module_name_repetitions)] // we can't just name it `Default`, that's part of std
pub struct DefaultRepl<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
/// the command you want to execute, along with its arguments
#[command(subcommand)]
@ -81,18 +80,14 @@ where
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord)]
struct DefaultReplCompletion<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
commands: std::marker::PhantomData<C>,
}
impl<C> Repl<C> for DefaultRepl<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
fn new() -> Self {
Self {
@ -106,7 +101,7 @@ where
fn command(&self) -> &Option<C> {
&self.command
}
fn step(&mut self) -> Result<(), super::error::ReplError> {
fn step(&mut self) -> Result<(), super::error::Error> {
self.buf.clear();
// NOTE: display::Input requires some kind of lifetime that would be a bother to store in
@ -139,9 +134,7 @@ where
impl<C> Default for DefaultRepl<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
fn default() -> Self {
Self::new()
@ -150,9 +143,7 @@ where
impl<C> Debug for DefaultRepl<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DefaultRepl")
@ -167,16 +158,15 @@ where
impl<C> DefaultReplCompletion<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
pub fn new() -> Self {
/// Make a new [`DefaultReplCompletion`] for the type `C`
pub const fn new() -> Self {
Self {
commands: std::marker::PhantomData::<C>,
}
}
fn commands(&self) -> Vec<String> {
fn commands() -> Vec<String> {
let mut buf = Vec::new();
// every crate has the help command, but it is not part of the enum
buf.push("help".to_string());
@ -199,9 +189,7 @@ where
impl<C> Default for DefaultReplCompletion<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
fn default() -> Self {
Self::new()
@ -210,14 +198,11 @@ where
impl<C> Completion for DefaultReplCompletion<C>
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
/// Simple completion implementation based on substring
fn get(&self, input: &str) -> Option<String> {
let matches = self
.commands()
let matches = Self::commands()
.into_iter()
.filter(|option| option.starts_with(input))
.collect::<Vec<_>>();

View File

@ -3,9 +3,11 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ReplError {
pub enum Error {
#[error(transparent)]
Parsing(#[from] clap::Error),
#[error(transparent)]
Input(#[from] dialoguer::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}

View File

@ -14,7 +14,7 @@
use std::fmt::Debug;
pub mod error;
use error::ReplError;
use error::Error;
mod default;
pub use default::*;
@ -25,9 +25,7 @@ use clap::{Parser, Subcommand};
/// Unless you want to implement custom features (not just commands), just use [`DefaultRepl`].
pub trait Repl<C>: Parser + Debug
where
C: Debug,
C: Subcommand,
C: strum::IntoEnumIterator,
C: Debug + Subcommand + strum::IntoEnumIterator,
{
/// create a new repl
fn new() -> Self;
@ -40,5 +38,11 @@ where
/// 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>;
///
/// # Errors
///
/// * [`Error::Input`] [dialoguer] User Input had some kind of I/O Error
/// * [`Error::Parsing`] [clap] could not parse the user input, or user requested help
/// * [`Error::Other`] Any other error with [anyhow], [`DefaultRepl`] does not use this but custom implementations might
fn step(&mut self) -> Result<(), Error>;
}