Skip to content

Commit

Permalink
feat: add .edit command for multi-line editing (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden authored Oct 26, 2023
1 parent b3f8f27 commit ca0f634
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 19 deletions.
19 changes: 9 additions & 10 deletions src/repl/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@ impl Repl {
let edit_mode: Box<dyn EditMode> = if config.read().vi_keybindings {
let mut normal_keybindings = default_vi_normal_keybindings();
let mut insert_keybindings = default_vi_insert_keybindings();
Self::add_menu_keybindings(&mut normal_keybindings);
Self::add_menu_keybindings(&mut insert_keybindings);
Self::add_clear_keybindings(&mut normal_keybindings);
Self::add_clear_keybindings(&mut insert_keybindings);
Self::extra_keybindings(&mut normal_keybindings);
Self::extra_keybindings(&mut insert_keybindings);
Box::new(Vi::new(insert_keybindings, normal_keybindings))
} else {
let mut keybindings = default_emacs_keybindings();
Self::add_menu_keybindings(&mut keybindings);
Self::add_clear_keybindings(&mut keybindings);
Self::extra_keybindings(&mut keybindings);
Box::new(Emacs::new(keybindings))
};
let mut editor = Reedline::create()
Expand All @@ -67,7 +64,7 @@ impl Repl {
completer
}

fn add_menu_keybindings(keybindings: &mut Keybindings) {
fn extra_keybindings(keybindings: &mut Keybindings) {
keybindings.add_binding(
KeyModifiers::NONE,
KeyCode::Tab,
Expand All @@ -76,14 +73,16 @@ impl Repl {
ReedlineEvent::MenuNext,
]),
);
}

fn add_clear_keybindings(keybindings: &mut Keybindings) {
keybindings.add_binding(
KeyModifiers::CONTROL,
KeyCode::Char('l'),
ReedlineEvent::ExecuteHostCommand(".clear screen".into()),
);
keybindings.add_binding(
KeyModifiers::CONTROL,
KeyCode::Char('s'),
ReedlineEvent::Submit,
);
}

fn create_menu() -> ReedlineMenu {
Expand Down
25 changes: 18 additions & 7 deletions src/repl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ use crate::print_now;
use crate::term;

use anyhow::{Context, Result};
use fancy_regex::Regex;
use lazy_static::lazy_static;
use reedline::Signal;
use std::rc::Rc;

pub const REPL_COMMANDS: [(&str, &str); 14] = [
pub const REPL_COMMANDS: [(&str, &str); 15] = [
(".info", "Print system-wide information"),
(".set", "Modify the configuration temporarily"),
(".model", "Choose a model"),
Expand All @@ -28,12 +30,17 @@ pub const REPL_COMMANDS: [(&str, &str); 14] = [
(".clear conversation", "End current conversation."),
(".copy", "Copy the last output to the clipboard"),
(".read", "Read the contents of a file into the prompt"),
(".edit", "Multi-line editing (CTRL+S to finish)"),
(".history", "Print the history"),
(".clear history", "Clear the history"),
(".help", "Print this help message"),
(".exit", "Exit the REPL"),
];

lazy_static! {
static ref EDIT_RE: Regex = Regex::new(r"^\s*.edit\s*").unwrap();
}

impl Repl {
pub fn run(&mut self, config: SharedConfig) -> Result<()> {
let abort = AbortSignal::new();
Expand Down Expand Up @@ -85,8 +92,7 @@ impl Repl {
}

fn handle_line(&mut self, handler: &Rc<ReplCmdHandler>, line: &str) -> Result<bool> {
let line = line.trim().replace("\\\n", "\n");
match parse_command(line.as_ref()) {
match parse_command(line) {
Some((cmd, args)) => match cmd {
".exit" => {
return Ok(true);
Expand Down Expand Up @@ -119,10 +125,6 @@ impl Repl {
Some(name) => handler.handle(ReplCmd::SetRole(name.to_string()))?,
None => print_now!("Usage: .role <name>\n\n"),
},
".read" => match args {
Some(file) => handler.handle(ReplCmd::ReadFile(file.to_string()))?,
None => print_now!("Usage: .read <file name>\n\n"),
},
".info" => {
handler.handle(ReplCmd::ViewInfo)?;
}
Expand All @@ -144,6 +146,15 @@ impl Repl {
".copy" => {
handler.handle(ReplCmd::Copy)?;
}
".read" => match args {
Some(file) => handler.handle(ReplCmd::ReadFile(file.to_string()))?,
None => print_now!("Usage: .read <file name>\n\n"),
},
".edit" => {
if let Some(text) = args {
handler.handle(ReplCmd::Submit(text.to_string()))?;
}
}
_ => dump_unknown_command(),
},
None => {
Expand Down
5 changes: 3 additions & 2 deletions src/repl/validator.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use super::EDIT_RE;

use reedline::{ValidationResult, Validator};

/// A default validator which checks for mismatched quotes and brackets
#[allow(clippy::module_name_repetitions)]
pub struct ReplValidator;

impl Validator for ReplValidator {
fn validate(&self, line: &str) -> ValidationResult {
if line.ends_with('\\') {
if let Ok(true) = EDIT_RE.is_match(line) {
ValidationResult::Incomplete
} else {
ValidationResult::Complete
Expand Down

0 comments on commit ca0f634

Please sign in to comment.