From c4473f41f22d1e9de1b38e2cb6700410d71e3712 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 27 Aug 2022 20:06:06 +0200 Subject: edit: implement simple command parser Just single-letter commands at this point. --- src/edit.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/src/edit.rs b/src/edit.rs index 97c1abf..a804def 100644 --- a/src/edit.rs +++ b/src/edit.rs @@ -1,7 +1,6 @@ use vtcol::{Palette, Rgb, Scheme}; -use std::fmt; -use std::rc::Rc; +use std::{fmt, path::PathBuf, rc::Rc}; use anyhow::{anyhow, Result}; @@ -324,7 +323,8 @@ slint::slint! { } #[derive(Debug)] -enum KeyInput { +enum KeyInput +{ Printable(String), Escape, Return, @@ -339,8 +339,10 @@ enum KeyInput { Junk, } -impl fmt::Display for KeyInput { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl fmt::Display for KeyInput +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { let k = match self { Self::Printable(s) => return write!(f, "‘{}’", s), Self::Escape => "ESC", @@ -360,12 +362,15 @@ impl fmt::Display for KeyInput { } /** Crude filter for rejecting strings containing control chars. */ -fn is_printable(s: &str) -> bool { +fn is_printable(s: &str) -> bool +{ s.chars().find(|c| c.is_control()).is_none() } -impl From<&KeyEvent> for KeyInput { - fn from(ev: &KeyEvent) -> Self { +impl From<&KeyEvent> for KeyInput +{ + fn from(ev: &KeyEvent) -> Self + { match ev.text.as_str() { "\u{0008}" => KeyInput::Backspace, "\t" | "\u{000b}" => KeyInput::Tab, @@ -382,17 +387,21 @@ impl From<&KeyEvent> for KeyInput { } } -pub struct Edit { - name: Option, +pub struct Edit +{ + name: Option, scheme: Scheme, } -impl Edit { - pub fn new(name: Option, scheme: Scheme) -> Self { +impl Edit +{ + pub fn new(name: Option, scheme: Scheme) -> Self + { Self { name, scheme } } - pub fn run(self) -> Result<()> { + pub fn run(self) -> Result<()> + { let Self { name, scheme } = self; let pal = Palette::try_from(&scheme)?.iter().collect::>(); @@ -475,14 +484,28 @@ impl Edit { text }, KeyInput::Return => { - todo!(); + match Command::try_from(text.as_str()) { + Err(e) => { + eprintln!("bad command [{}]: {}", text, e); + String::new() + }, + Ok(cmd) => { + if let Err(e) = cmd.exec() { + eprintln!( + "error executing command [{}]: {}", + text, e + ); + } + String::new() + }, + } /* The empty string signals to leave command mode. */ - String::new() - }, - KeyInput::Backspace => match text.char_indices().next_back() { - Some((i, _)) => text[..i].into(), - None => text.to_string(), }, + KeyInput::Backspace => + match text.char_indices().next_back() { + Some((i, _)) => text[..i].into(), + None => text.to_string(), + }, other => { eprintln!( "»»» command mode input: “{}”", @@ -507,3 +530,43 @@ impl Edit { Ok(()) } } + +#[derive(Debug)] +enum Command +{ + Noop, + Save(Option), +} + +impl TryFrom<&str> for Command +{ + type Error = anyhow::Error; + + fn try_from(text: &str) -> Result + { + let text = text.trim_start_matches(':').trim(); + if text.len() == 0 { + return Ok(Self::Noop); + } + let (cmd, args) = if let Some(cmd) = text.get(..1) { + (cmd, &text[1..]) + } else { + return Err(anyhow!("non-ascii command‽")); + }; + + match (cmd, args) { + ("w", "") => Ok(Self::Save(None)), + ("w", rest) => { + let rest = rest.trim(); + let path = PathBuf::from(rest); + Ok(Self::Save(Some(path))) + }, + _ => Err(anyhow!("only save (‘:w’) implemented for now")), + } + } +} + +impl Command +{ + fn exec(self) -> Result<()> { todo!("got command: {:?}", self) } +} -- cgit v1.2.3