Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ history.txt
target-coverage/
tarpaulin-report.html
.vscode
.idea/
43 changes: 42 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ strip-ansi-escapes = "0.1.1"
strum = "0.23"
strum_macros = "0.23"
fd-lock = "3.0.3"
time = { version = "0.3.5", features = ["parsing", "formatting","macros"] }
anyhow = "1.0.52"

[dev-dependencies]
tempfile = "3.3.0"
Expand Down
65 changes: 43 additions & 22 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ impl Reedline {
}

/// Output the complete [`History`] chronologically with numbering to the terminal
pub fn print_history(&mut self) -> Result<()> {
pub fn print_history(&mut self) -> anyhow::Result<()> {
let history: Vec<_> = self
.history
.iter_chronologic()
Expand All @@ -317,7 +317,8 @@ impl Reedline {
.collect();

for (i, entry) in history {
self.print_line(&format!("{}\t{}", i + 1, entry))?;
let format_time_type = self.history.format_time_type();
self.print_line(&entry.format(i, format_time_type)?)?;
}
Ok(())
}
Expand All @@ -327,10 +328,10 @@ impl Reedline {
/// Returns a [`crossterm::Result`] in which the `Err` type is [`crossterm::ErrorKind`]
/// to distinguish I/O errors and the `Ok` variant wraps a [`Signal`] which
/// handles user inputs.
pub fn read_line(&mut self, prompt: &dyn Prompt) -> Result<Signal> {
pub fn read_line(&mut self, prompt: &dyn Prompt, encode: bool) -> Result<Signal> {
terminal::enable_raw_mode()?;

let result = self.read_line_helper(prompt);
let result = self.read_line_helper(prompt, encode);

terminal::disable_raw_mode()?;

Expand All @@ -352,11 +353,11 @@ impl Reedline {

/// Helper implementing the logic for [`Reedline::read_line()`] to be wrapped
/// in a `raw_mode` context.
fn read_line_helper(&mut self, prompt: &dyn Prompt) -> Result<Signal> {
fn read_line_helper(&mut self, prompt: &dyn Prompt, encode: bool) -> Result<Signal> {
self.painter.initialize_prompt_position()?;
self.hide_hints = false;

self.repaint(prompt)?;
self.repaint(prompt, encode)?;

let mut crossterm_events: Vec<Event> = vec![];
let mut reedline_events: Vec<ReedlineEvent> = vec![];
Expand All @@ -375,7 +376,9 @@ impl Reedline {
Event::Resize(x, y) => {
latest_resize = Some((x, y));
}
enter @ Event::Key(KeyEvent {
enter
@
Event::Key(KeyEvent {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
}) => {
Expand Down Expand Up @@ -428,15 +431,15 @@ impl Reedline {
};

for event in reedline_events.drain(..) {
match self.handle_event(prompt, event)? {
match self.handle_event(prompt, event, encode)? {
EventStatus::Exits(signal) => {
// Move the cursor below the input area, for external commands or new read_line call
self.painter.move_cursor_to_end()?;
return Ok(signal);
}
EventStatus::Handled => {
if !paste_enter_state {
self.repaint(prompt)?;
self.repaint(prompt, encode)?;
}
}
EventStatus::Inapplicable => {
Expand All @@ -447,11 +450,16 @@ impl Reedline {
}
}

fn handle_event(&mut self, prompt: &dyn Prompt, event: ReedlineEvent) -> Result<EventStatus> {
fn handle_event(
&mut self,
prompt: &dyn Prompt,
event: ReedlineEvent,
encode: bool,
) -> Result<EventStatus> {
if self.input_mode == InputMode::HistorySearch {
self.handle_history_search_event(prompt, event)
} else {
self.handle_editor_event(prompt, event)
self.handle_editor_event(prompt, event, encode)
}
}

Expand Down Expand Up @@ -552,6 +560,7 @@ impl Reedline {
&mut self,
prompt: &dyn Prompt,
event: ReedlineEvent,
encode: bool,
) -> io::Result<EventStatus> {
match event {
ReedlineEvent::Menu(name) => {
Expand All @@ -567,7 +576,11 @@ impl Reedline {
);

if menu.get_values().len() == 1 {
return self.handle_editor_event(prompt, ReedlineEvent::Enter);
return self.handle_editor_event(
prompt,
ReedlineEvent::Enter,
encode,
);
}
}

Expand Down Expand Up @@ -706,7 +719,7 @@ impl Reedline {
if matches!(self.validator.validate(&buffer), ValidationResult::Complete) {
self.hide_hints = true;
// Additional repaint to show the content without hints etc.
self.repaint(prompt)?;
self.repaint(prompt, encode)?;
self.history.append(self.editor.get_buffer());
self.run_edit_commands(&[EditCommand::Clear]);
self.editor.reset_undo_stack();
Expand Down Expand Up @@ -737,7 +750,7 @@ impl Reedline {
self.completer.as_ref(),
);
if menu.get_values().len() == 1 {
return self.handle_editor_event(prompt, ReedlineEvent::Enter);
return self.handle_editor_event(prompt, ReedlineEvent::Enter, encode);
}
}
menu.menu_event(MenuEvent::Edit(self.quick_completions));
Expand Down Expand Up @@ -788,7 +801,7 @@ impl Reedline {
ReedlineEvent::Multiple(events) => {
let mut latest_signal = EventStatus::Inapplicable;
for event in events {
match self.handle_editor_event(prompt, event)? {
match self.handle_editor_event(prompt, event, encode)? {
EventStatus::Handled => {
latest_signal = EventStatus::Handled;
}
Expand All @@ -808,7 +821,7 @@ impl Reedline {
}
ReedlineEvent::UntilFound(events) => {
for event in events {
match self.handle_editor_event(prompt, event)? {
match self.handle_editor_event(prompt, event, encode)? {
EventStatus::Inapplicable => {
// Try again with the next event handler
}
Expand Down Expand Up @@ -996,12 +1009,12 @@ impl Reedline {
}

/// Repaint of either the buffer or the parts for reverse history search
fn repaint(&mut self, prompt: &dyn Prompt) -> io::Result<()> {
fn repaint(&mut self, prompt: &dyn Prompt, decode: bool) -> io::Result<()> {
// Repainting
if self.input_mode == InputMode::HistorySearch {
self.history_search_paint(prompt)
} else {
self.buffer_paint(prompt)
self.buffer_paint(prompt, decode)
}
}

Expand Down Expand Up @@ -1051,13 +1064,21 @@ impl Reedline {
/// Triggers a full repaint including the prompt parts
///
/// Includes the highlighting and hinting calls.
fn buffer_paint(&mut self, prompt: &dyn Prompt) -> Result<()> {
fn buffer_paint(&mut self, prompt: &dyn Prompt, encode: bool) -> Result<()> {
let cursor_position_in_buffer = self.editor.offset();
let buffer_to_paint = self.editor.get_buffer();

let encode_buffer = if encode {
let mut str_decode = String::new();
for _ in 0..buffer_to_paint.to_string().len() {
str_decode.push('*');
}
str_decode
} else {
buffer_to_paint.to_string()
};
let (before_cursor, after_cursor) = self
.highlighter
.highlight(buffer_to_paint, cursor_position_in_buffer)
.highlight(&encode_buffer, cursor_position_in_buffer)
.render_around_insertion_point(
cursor_position_in_buffer,
prompt.render_prompt_multiline_indicator().borrow(),
Expand All @@ -1066,7 +1087,7 @@ impl Reedline {

let hint: String = if self.hints_active() {
self.hinter.handle(
buffer_to_paint,
&encode_buffer,
cursor_position_in_buffer,
self.history.as_ref(),
self.use_ansi_coloring,
Expand Down
1 change: 1 addition & 0 deletions src/hinter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl Hinter for DefaultHinter {
} else {
self.current_hint = history
.iter_chronologic()
.map(|x| x.entry.to_string())
.rev()
.find(|entry| entry.starts_with(line))
.map_or_else(String::new, |entry| entry[line.len()..].to_string());
Expand Down
Loading