use std::str::FromStr;
use rustyline::{
Context,
completion::Completer,
error::ReadlineError,
hint::{Hinter, HistoryHinter},
line_buffer::LineBuffer,
};
use rustyline_derive::{Helper, Highlighter, Validator};
use strum::{Display, EnumString};
use tari_utilities::hex::{Hex, HexError};
use thiserror::Error;
use super::command::Command;
#[derive(Debug, Display, EnumString, Default, Clone)]
#[strum(serialize_all = "kebab-case")]
pub enum Format {
Json,
#[default]
Text,
}
#[derive(Debug, Clone)]
pub struct FromHex<T>(pub T);
impl<T: Hex> FromStr for FromHex<T> {
type Err = ParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
T::from_hex(s)
.map(Self)
.map_err(|e| ParserError::HexError(format!("{e}")))
}
}
#[derive(Debug, Error, PartialEq)]
pub enum ParserError {
#[error("Could not convert into hex: `{0}`")]
HexError(String),
}
impl From<HexError> for ParserError {
fn from(e: HexError) -> Self {
ParserError::HexError(e.to_string())
}
}
#[derive(Helper, Validator, Highlighter)]
pub struct Parser {
commands: Vec<String>,
hinter: HistoryHinter,
}
impl Completer for Parser {
type Candidate = String;
fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Result<(usize, Vec<String>), ReadlineError> {
let completions = self
.commands
.iter()
.filter(|cmd| cmd.starts_with(line))
.cloned()
.collect();
Ok((pos, completions))
}
fn update(&self, line: &mut LineBuffer, _: usize, elected: &str) {
line.update(elected, elected.len());
}
}
impl Hinter for Parser {
type Hint = String;
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
self.hinter.hint(line, pos, ctx)
}
}
impl Parser {
pub fn new() -> Self {
Parser {
commands: Command::variants(),
hinter: HistoryHinter {},
}
}
pub fn get_commands(&self) -> Vec<String> {
self.commands.clone()
}
}