diff options
| author | sigoden <sigoden@gmail.com> | 2023-03-09 08:26:35 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-09 08:26:35 +0800 |
| commit | a7f2da156c0692121e35dbe20bdacc76baadd5c4 (patch) | |
| tree | 0b25540ce1676b262525122232fc1d438f6df7c4 | |
| parent | e78b5f7c58fa3b6dff71042da2bbf6003c78184d (diff) | |
| download | aichat-a7f2da156c0692121e35dbe20bdacc76baadd5c4.tar.gz | |
feat: add role info to readline indicator (#47)
```
coder〉
```
| -rw-r--r-- | src/repl/init.rs | 65 | ||||
| -rw-r--r-- | src/repl/mod.rs | 8 |
2 files changed, 57 insertions, 16 deletions
diff --git a/src/repl/init.rs b/src/repl/init.rs index 14dbd9c..998b9d0 100644 --- a/src/repl/init.rs +++ b/src/repl/init.rs @@ -1,16 +1,23 @@ -use super::Repl; use super::REPL_COMMANDS; use crate::config::{Config, SharedConfig}; use anyhow::{Context, Result}; use reedline::{ - default_emacs_keybindings, ColumnarMenu, DefaultCompleter, DefaultPrompt, DefaultPromptSegment, - Emacs, FileBackedHistory, KeyCode, KeyModifiers, Keybindings, Reedline, ReedlineEvent, - ReedlineMenu, ValidationResult, Validator, + default_emacs_keybindings, ColumnarMenu, DefaultCompleter, Emacs, FileBackedHistory, KeyCode, + KeyModifiers, Keybindings, Prompt, PromptHistorySearch, PromptHistorySearchStatus, Reedline, + ReedlineEvent, ReedlineMenu, ValidationResult, Validator, }; +use std::borrow::Cow; const MENU_NAME: &str = "completion_menu"; +const DEFAULT_PROMPT_INDICATOR: &str = "〉"; +const DEFAULT_MULTILINE_INDICATOR: &str = "::: "; + +pub struct Repl { + pub editor: Reedline, + pub prompt: ReplPrompt, +} impl Repl { pub fn init(config: SharedConfig) -> Result<Self> { @@ -19,7 +26,7 @@ impl Repl { .filter(|(_, _, v)| *v) .map(|(v, _, _)| *v) .collect(); - let completer = Self::create_completer(config); + let completer = Self::create_completer(config.clone()); let keybindings = Self::create_keybindings(); let history = Self::create_history()?; let menu = Self::create_menu(); @@ -33,14 +40,10 @@ impl Repl { .with_partial_completions(true) .with_validator(Box::new(ReplValidator { multiline_commands })) .with_ansi_colors(true); - let prompt = Self::create_prompt(); + let prompt = ReplPrompt(config); Ok(Self { editor, prompt }) } - fn create_prompt() -> DefaultPrompt { - DefaultPrompt::new(DefaultPromptSegment::Empty, DefaultPromptSegment::Empty) - } - fn create_completer(config: SharedConfig) -> DefaultCompleter { let mut completion: Vec<String> = REPL_COMMANDS .into_iter() @@ -118,3 +121,45 @@ fn incomplete_brackets(line: &str, multiline_commands: &[&str]) -> bool { !balance.is_empty() } + +#[derive(Clone)] +pub struct ReplPrompt(SharedConfig); + +impl Prompt for ReplPrompt { + fn render_prompt_left(&self) -> Cow<str> { + let config = self.0.lock(); + if let Some(role) = config.role.as_ref() { + role.name.to_string().into() + } else { + Cow::Borrowed("") + } + } + + fn render_prompt_right(&self) -> Cow<str> { + Cow::Borrowed("") + } + + fn render_prompt_indicator(&self, _prompt_mode: reedline::PromptEditMode) -> Cow<str> { + Cow::Borrowed(DEFAULT_PROMPT_INDICATOR) + } + + fn render_prompt_multiline_indicator(&self) -> Cow<str> { + Cow::Borrowed(DEFAULT_MULTILINE_INDICATOR) + } + + fn render_prompt_history_search_indicator( + &self, + history_search: PromptHistorySearch, + ) -> Cow<str> { + let prefix = match history_search.status { + PromptHistorySearchStatus::Passing => "", + PromptHistorySearchStatus::Failing => "failing ", + }; + // NOTE: magic strings, given there is logic on how these compose I am not sure if it + // is worth extracting in to static constant + Cow::Owned(format!( + "({}reverse-search: {}) ", + prefix, history_search.term + )) + } +} diff --git a/src/repl/mod.rs b/src/repl/mod.rs index b5fee57..e9a0b51 100644 --- a/src/repl/mod.rs +++ b/src/repl/mod.rs @@ -4,6 +4,7 @@ mod init; pub use self::abort::*; pub use self::handler::*; +pub use self::init::Repl; use crate::client::ChatGptClient; use crate::config::SharedConfig; @@ -11,7 +12,7 @@ use crate::print_now; use crate::term; use anyhow::{Context, Result}; -use reedline::{DefaultPrompt, Reedline, Signal}; +use reedline::Signal; use std::sync::Arc; pub const REPL_COMMANDS: [(&str, &str, bool); 10] = [ @@ -27,11 +28,6 @@ pub const REPL_COMMANDS: [(&str, &str, bool); 10] = [ (".exit", "Exit the REPL", false), ]; -pub struct Repl { - editor: Reedline, - prompt: DefaultPrompt, -} - impl Repl { pub fn run(&mut self, client: ChatGptClient, config: SharedConfig) -> Result<()> { let abort = AbortSignal::new(); |
