Folderize prompt

- Fix docs for Prompt trait
- Separate trait and default implementation
- Hide constants that are of little use
This commit is contained in:
sholderbach 2022-03-14 15:42:20 +01:00 committed by Stefan Holderbach
parent ebafcdfe20
commit 804f31d181
5 changed files with 201 additions and 190 deletions

View File

@ -195,7 +195,7 @@ pub use history::{FileBackedHistory, History, HistoryNavigationQuery, HISTORY_SI
mod prompt;
pub use prompt::{
DefaultPrompt, Prompt, PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus,
PromptViMode, DEFAULT_PROMPT_COLOR, DEFAULT_PROMPT_INDICATOR,
PromptViMode,
};
mod edit_mode;

View File

@ -1,189 +0,0 @@
use {
chrono::Local,
crossterm::style::Color,
serde::{Deserialize, Serialize},
std::{
borrow::Cow,
env,
fmt::{Display, Formatter},
},
strum_macros::EnumIter,
};
/// The default color for the prompt
pub static DEFAULT_PROMPT_COLOR: Color = Color::Blue;
/// The default prompt indicator
pub static DEFAULT_PROMPT_INDICATOR: &str = "";
pub static DEFAULT_VI_INSERT_PROMPT_INDICATOR: &str = ": ";
pub static DEFAULT_VI_NORMAL_PROMPT_INDICATOR: &str = "";
pub static DEFAULT_MULTILINE_INDICATOR: &str = "::: ";
/// The current success/failure of the history search
pub enum PromptHistorySearchStatus {
/// Success for the search
Passing,
/// Failure to find the search
Failing,
}
/// A representation of the history search
pub struct PromptHistorySearch {
/// The status of the search
pub status: PromptHistorySearchStatus,
/// The search term used during the search
pub term: String,
}
impl PromptHistorySearch {
/// A constructor to create a history search
pub fn new(status: PromptHistorySearchStatus, search_term: String) -> Self {
PromptHistorySearch {
status,
term: search_term,
}
}
}
/// Modes that the prompt can be in
#[derive(Serialize, Deserialize, Clone, Debug, EnumIter)]
pub enum PromptEditMode {
/// The default mode
Default,
/// Emacs normal mode
Emacs,
/// A vi-specific mode
Vi(PromptViMode),
/// A custom mode
Custom(String),
}
/// The vi-specific modes that the prompt can be in
#[derive(Serialize, Deserialize, Clone, Debug, EnumIter)]
pub enum PromptViMode {
/// The default mode
Normal,
/// Insertion mode
Insert,
}
impl Default for PromptViMode {
fn default() -> Self {
PromptViMode::Normal
}
}
impl Display for PromptEditMode {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
PromptEditMode::Default => write!(f, "Default"),
PromptEditMode::Emacs => write!(f, "Emacs"),
PromptEditMode::Vi(_) => write!(f, "Vi_Normal\nVi_Insert"),
PromptEditMode::Custom(s) => write!(f, "Custom_{}", s),
}
}
}
/// API to provide a custom prompt.
///
/// Implementors have to provide [`str`]-based content which will be
/// displayed before the `LineBuffer` is drawn.
pub trait Prompt: Send {
/// Provide content off the right full prompt
fn render_prompt_left(&self) -> Cow<str>;
/// Provide content off the left full prompt
fn render_prompt_right(&self) -> Cow<str>;
/// Render the default prompt indicator
fn render_prompt_indicator(&self, prompt_mode: PromptEditMode) -> Cow<str>;
/// Render the default prompt indicator
fn render_prompt_multiline_indicator(&self) -> Cow<str>;
/// Render the default prompt indicator
fn render_prompt_history_search_indicator(
&self,
history_search: PromptHistorySearch,
) -> Cow<str>;
/// Render the vi insert mode prompt indicator
/// Get back the prompt color
fn get_prompt_color(&self) -> Color {
DEFAULT_PROMPT_COLOR
}
}
impl Prompt for DefaultPrompt {
fn render_prompt_left(&self) -> Cow<str> {
{
let left_prompt = get_working_dir().unwrap_or_else(|_| String::from("no path"));
Cow::Owned(left_prompt)
}
}
fn render_prompt_right(&self) -> Cow<str> {
{
Cow::Owned(get_now())
}
}
fn render_prompt_indicator(&self, edit_mode: PromptEditMode) -> Cow<str> {
match edit_mode {
PromptEditMode::Default | PromptEditMode::Emacs => DEFAULT_PROMPT_INDICATOR.into(),
PromptEditMode::Vi(vi_mode) => match vi_mode {
PromptViMode::Normal => DEFAULT_VI_NORMAL_PROMPT_INDICATOR.into(),
PromptViMode::Insert => DEFAULT_VI_INSERT_PROMPT_INDICATOR.into(),
},
PromptEditMode::Custom(str) => format!("({})", str).into(),
}
}
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
))
}
}
impl Default for DefaultPrompt {
fn default() -> Self {
DefaultPrompt::new()
}
}
/// Simple two-line [`Prompt`] displaying the current working directory and the time above the entry line.
#[derive(Clone)]
pub struct DefaultPrompt;
impl DefaultPrompt {
/// Constructor for the default prompt, which takes the amount of spaces required between the left and right-hand sides of the prompt
pub fn new() -> DefaultPrompt {
DefaultPrompt {}
}
}
fn get_working_dir() -> Result<String, std::io::Error> {
let path = env::current_dir()?;
Ok(path.display().to_string())
}
fn get_now() -> String {
let now = Local::now();
format!("{:>}", now.format("%m/%d/%Y %I:%M:%S %p"))
}

106
src/prompt/base.rs Normal file
View File

@ -0,0 +1,106 @@
use {
crossterm::style::Color,
serde::{Deserialize, Serialize},
std::{
borrow::Cow,
fmt::{Display, Formatter},
},
strum_macros::EnumIter,
};
/// The default color for the prompt
pub static DEFAULT_PROMPT_COLOR: Color = Color::Blue;
/// The current success/failure of the history search
pub enum PromptHistorySearchStatus {
/// Success for the search
Passing,
/// Failure to find the search
Failing,
}
/// A representation of the history search
pub struct PromptHistorySearch {
/// The status of the search
pub status: PromptHistorySearchStatus,
/// The search term used during the search
pub term: String,
}
impl PromptHistorySearch {
/// A constructor to create a history search
pub fn new(status: PromptHistorySearchStatus, search_term: String) -> Self {
PromptHistorySearch {
status,
term: search_term,
}
}
}
/// Modes that the prompt can be in
#[derive(Serialize, Deserialize, Clone, Debug, EnumIter)]
pub enum PromptEditMode {
/// The default mode
Default,
/// Emacs normal mode
Emacs,
/// A vi-specific mode
Vi(PromptViMode),
/// A custom mode
Custom(String),
}
/// The vi-specific modes that the prompt can be in
#[derive(Serialize, Deserialize, Clone, Debug, EnumIter)]
pub enum PromptViMode {
/// The default mode
Normal,
/// Insertion mode
Insert,
}
impl Default for PromptViMode {
fn default() -> Self {
PromptViMode::Normal
}
}
impl Display for PromptEditMode {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
PromptEditMode::Default => write!(f, "Default"),
PromptEditMode::Emacs => write!(f, "Emacs"),
PromptEditMode::Vi(_) => write!(f, "Vi_Normal\nVi_Insert"),
PromptEditMode::Custom(s) => write!(f, "Custom_{}", s),
}
}
}
/// API to provide a custom prompt.
///
/// Implementors have to provide [`str`]-based content which will be
/// displayed before the `LineBuffer` is drawn.
pub trait Prompt: Send {
/// Provide content off the right full prompt
fn render_prompt_left(&self) -> Cow<str>;
/// Provide content off the left full prompt
fn render_prompt_right(&self) -> Cow<str>;
/// Render the prompt indicator (Last part of the prompt that changes based on the editor mode)
fn render_prompt_indicator(&self, prompt_mode: PromptEditMode) -> Cow<str>;
/// Indicator to show before explicit new lines
fn render_prompt_multiline_indicator(&self) -> Cow<str>;
/// Render the prompt indicator for `Ctrl-R` history search
fn render_prompt_history_search_indicator(
&self,
history_search: PromptHistorySearch,
) -> Cow<str>;
/// Get back the prompt color
fn get_prompt_color(&self) -> Color {
DEFAULT_PROMPT_COLOR
}
}

86
src/prompt/default.rs Normal file
View File

@ -0,0 +1,86 @@
use crate::{Prompt, PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus, PromptViMode};
use {
chrono::Local,
std::{borrow::Cow, env},
};
/// The default prompt indicator
pub static DEFAULT_PROMPT_INDICATOR: &str = "";
pub static DEFAULT_VI_INSERT_PROMPT_INDICATOR: &str = ": ";
pub static DEFAULT_VI_NORMAL_PROMPT_INDICATOR: &str = "";
pub static DEFAULT_MULTILINE_INDICATOR: &str = "::: ";
/// Simple two-line [`Prompt`] displaying the current working directory and the time above the entry line.
#[derive(Clone)]
pub struct DefaultPrompt;
impl Prompt for DefaultPrompt {
fn render_prompt_left(&self) -> Cow<str> {
{
let left_prompt = get_working_dir().unwrap_or_else(|_| String::from("no path"));
Cow::Owned(left_prompt)
}
}
fn render_prompt_right(&self) -> Cow<str> {
{
Cow::Owned(get_now())
}
}
fn render_prompt_indicator(&self, edit_mode: PromptEditMode) -> Cow<str> {
match edit_mode {
PromptEditMode::Default | PromptEditMode::Emacs => DEFAULT_PROMPT_INDICATOR.into(),
PromptEditMode::Vi(vi_mode) => match vi_mode {
PromptViMode::Normal => DEFAULT_VI_NORMAL_PROMPT_INDICATOR.into(),
PromptViMode::Insert => DEFAULT_VI_INSERT_PROMPT_INDICATOR.into(),
},
PromptEditMode::Custom(str) => format!("({})", str).into(),
}
}
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
))
}
}
impl Default for DefaultPrompt {
fn default() -> Self {
DefaultPrompt::new()
}
}
impl DefaultPrompt {
/// Constructor for the default prompt, which takes the amount of spaces required between the left and right-hand sides of the prompt
pub fn new() -> DefaultPrompt {
DefaultPrompt {}
}
}
fn get_working_dir() -> Result<String, std::io::Error> {
let path = env::current_dir()?;
Ok(path.display().to_string())
}
fn get_now() -> String {
let now = Local::now();
format!("{:>}", now.format("%m/%d/%Y %I:%M:%S %p"))
}

8
src/prompt/mod.rs Normal file
View File

@ -0,0 +1,8 @@
mod base;
mod default;
pub use base::{
Prompt, PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus, PromptViMode,
};
pub use default::DefaultPrompt;