Skip to content

Commit

Permalink
Merge branch 'nushell:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementNerma authored May 17, 2024
2 parents 794eb53 + a580ea5 commit 7165a65
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 55 deletions.
7 changes: 7 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ descriptio = "descriptio"
ot = "ot"
# for sqlite backed history
wheres = "wheres"
# for list_menu tests
an1other = "an1other"
ver2y = "ver2y"
l3ine = "l3ine"
4should = "4should"
wr5ap = "wr5ap"
ine = "ine"
2 changes: 1 addition & 1 deletion Cargo.lock

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

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
authors = ["JT <[email protected]>", "The Nushell Project Developers"]
authors = ["The Nushell Project Developers"]
description = "A readline-like crate for CLI text input"
edition = "2021"
license = "MIT"
name = "reedline"
repository = "https://github.com/nushell/reedline"
rust-version = "1.62.1"
version = "0.31.0"
rust-version = "1.63.0"
version = "0.32.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
Expand Down
2 changes: 1 addition & 1 deletion examples/ide_completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> io::Result<()> {
// Max width of the completion box, including the border
let max_completion_width: u16 = 50;
// Max height of the completion box, including the border
let max_completion_height = u16::MAX;
let max_completion_height: u16 = u16::MAX;
// Padding inside of the completion box (on the left and right side)
let padding: u16 = 0;
// Whether to draw the default border around the completion box
Expand Down
4 changes: 3 additions & 1 deletion src/core_editor/clip_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ pub trait Clipboard: Send {

fn get(&mut self) -> (String, ClipboardMode);

#[allow(dead_code)]
fn clear(&mut self) {
self.set("", ClipboardMode::Normal);
}

#[allow(dead_code)]
fn len(&mut self) -> usize {
self.get().0.len()
}
Expand Down Expand Up @@ -41,7 +43,7 @@ impl LocalClipboard {

impl Clipboard for LocalClipboard {
fn set(&mut self, content: &str, mode: ClipboardMode) {
self.content = content.to_owned();
content.clone_into(&mut self.content);
self.mode = mode;
}

Expand Down
74 changes: 59 additions & 15 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use {
FileBackedHistory, History, HistoryCursor, HistoryItem, HistoryItemId,
HistoryNavigationQuery, HistorySessionId, SearchDirection, SearchQuery,
},
painting::{Painter, PromptLines},
painting::{Painter, PainterSuspendedState, PromptLines},
prompt::{PromptEditMode, PromptHistorySearchStatus},
result::{ReedlineError, ReedlineErrorVariants},
terminal_extensions::{bracketed_paste::BracketedPasteGuard, kitty::KittyProtocolGuard},
Expand Down Expand Up @@ -109,8 +109,9 @@ pub struct Reedline {
history_cursor_on_excluded: bool,
input_mode: InputMode,

// Yielded to the host program after a `ReedlineEvent::ExecuteHostCommand`, thus redraw in-place
executing_host_command: bool,
// State of the painter after a `ReedlineEvent::ExecuteHostCommand` was requested, used after
// execution to decide if we can re-use the previous prompt or paint a new one.
suspended_state: Option<PainterSuspendedState>,

// Validator
validator: Option<Box<dyn Validator>>,
Expand Down Expand Up @@ -210,7 +211,7 @@ impl Reedline {
history_excluded_item: None,
history_cursor_on_excluded: false,
input_mode: InputMode::Regular,
executing_host_command: false,
suspended_state: None,
painter,
transient_prompt: None,
edit_mode,
Expand Down Expand Up @@ -671,12 +672,14 @@ 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> {
if self.executing_host_command {
self.executing_host_command = false;
} else {
self.painter.initialize_prompt_position()?;
self.hide_hints = false;
self.painter
.initialize_prompt_position(self.suspended_state.as_ref())?;
if self.suspended_state.is_some() {
// Last editor was suspended to run a ExecuteHostCommand event,
// we are resuming operation now.
self.suspended_state = None;
}
self.hide_hints = false;

self.repaint(prompt)?;

Expand Down Expand Up @@ -773,8 +776,11 @@ impl Reedline {
for event in reedline_events.drain(..) {
match self.handle_event(prompt, event)? {
EventStatus::Exits(signal) => {
if !self.executing_host_command {
// Move the cursor below the input area, for external commands or new read_line call
// Check if we are merely suspended (to process an ExecuteHostCommand event)
// or if we're about to quit the editor.
if self.suspended_state.is_none() {
// We are about to quit the editor, move the cursor below the input
// area, for external commands or new read_line call
self.painter.move_cursor_to_end()?;
}
return Ok(signal);
Expand Down Expand Up @@ -851,8 +857,7 @@ impl Reedline {
Ok(EventStatus::Handled)
}
ReedlineEvent::ExecuteHostCommand(host_command) => {
// TODO: Decide if we need to do something special to have a nicer painter state on the next go
self.executing_host_command = true;
self.suspended_state = Some(self.painter.state_before_suspension());
Ok(EventStatus::Exits(Signal::Success(host_command)))
}
ReedlineEvent::Edit(commands) => {
Expand Down Expand Up @@ -1122,8 +1127,7 @@ impl Reedline {
}
}
ReedlineEvent::ExecuteHostCommand(host_command) => {
// TODO: Decide if we need to do something special to have a nicer painter state on the next go
self.executing_host_command = true;
self.suspended_state = Some(self.painter.state_before_suspension());
Ok(EventStatus::Exits(Signal::Success(host_command)))
}
ReedlineEvent::Edit(commands) => {
Expand Down Expand Up @@ -1495,6 +1499,8 @@ impl Reedline {
fn parse_bang_command(&mut self) -> Option<ReedlineEvent> {
let buffer = self.editor.get_buffer();
let parsed = parse_selection_char(buffer, '!');
let parsed_prefix = parsed.prefix.unwrap_or_default().to_string();
let parsed_marker = parsed.marker.unwrap_or_default().to_string();

if let Some(last) = parsed.remainder.chars().last() {
if last != ' ' {
Expand Down Expand Up @@ -1546,6 +1552,43 @@ impl Reedline {
history.command_line.clone(),
)
}),
ParseAction::BackwardPrefixSearch => {
let history_search_by_session = self
.history
.search(SearchQuery::last_with_prefix_and_cwd(
parsed.prefix.unwrap().to_string(),
self.get_history_session_id(),
))
.unwrap_or_else(|_| Vec::new())
.get(index.saturating_sub(1))
.map(|history| {
(
parsed.remainder.len(),
parsed_prefix.len() + parsed_marker.len(),
history.command_line.clone(),
)
});
// If we don't find any history searching by session id, then let's
// search everything, otherwise use the result from the session search
if history_search_by_session.is_none() {
self.history
.search(SearchQuery::last_with_prefix(
parsed_prefix.clone(),
self.get_history_session_id(),
))
.unwrap_or_else(|_| Vec::new())
.get(index.saturating_sub(1))
.map(|history| {
(
parsed.remainder.len(),
parsed_prefix.len() + parsed_marker.len(),
history.command_line.clone(),
)
})
} else {
history_search_by_session
}
}
ParseAction::ForwardSearch => self
.history
.search(SearchQuery {
Expand Down Expand Up @@ -1573,6 +1616,7 @@ impl Reedline {
)))
.unwrap_or_else(|_| Vec::new())
.first()
//BUGBUG: This returns the wrong results with paths with spaces in them
.and_then(|history| history.command_line.split_whitespace().next_back())
.map(|token| (parsed.remainder.len(), indicator.len(), token.to_string())),
});
Expand Down
2 changes: 1 addition & 1 deletion src/menu/description_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ impl Menu for DescriptionMenu {
.examples
.get(example_index)
.expect("the example index is always checked");
suggestion.value = example.clone();
suggestion.value.clone_from(example);
}
replace_in_buffer(Some(suggestion), editor);
}
Expand Down
1 change: 1 addition & 0 deletions src/menu/ide_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ impl Menu for IdeMenu {

fn menu_required_lines(&self, _terminal_columns: u16) -> u16 {
self.get_rows()
.min(self.default_details.max_completion_height)
}

fn menu_string(&self, available_lines: u16, use_ansi_coloring: bool) -> String {
Expand Down
24 changes: 23 additions & 1 deletion src/menu/menu_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub struct ParseResult<'buffer> {
pub marker: Option<&'buffer str>,
/// Direction of the search based on the marker
pub action: ParseAction,
/// Prefix to search for
pub prefix: Option<&'buffer str>,
}

/// Direction of the index found in the string
Expand All @@ -30,6 +32,8 @@ pub enum ParseAction {
LastToken,
/// Last executed command.
LastCommand,
/// Backward search for a prefix
BackwardPrefixSearch,
}

/// Splits a string that contains a marker character
Expand All @@ -46,7 +50,8 @@ pub enum ParseAction {
/// remainder: "this is an example",
/// index: Some(10),
/// marker: Some("!10"),
/// action: ParseAction::ForwardSearch
/// action: ParseAction::ForwardSearch,
/// prefix: None,
/// }
/// )
///
Expand All @@ -58,6 +63,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
index: None,
marker: None,
action: ParseAction::ForwardSearch,
prefix: None,
};
}

Expand All @@ -75,6 +81,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
index: Some(0),
marker: Some(&buffer[index..index + 2 * marker.len_utf8()]),
action: ParseAction::LastCommand,
prefix: None,
}
}
#[cfg(feature = "bashisms")]
Expand All @@ -84,6 +91,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
index: Some(0),
marker: Some(&buffer[index..index + 2]),
action: ParseAction::LastToken,
prefix: None,
}
}
Some(&x) if x.is_ascii_digit() || x == '-' => {
Expand All @@ -106,6 +114,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
index: Some(count),
marker: Some(&buffer[index..index + size]),
action,
prefix: None,
};
}
}
Expand All @@ -114,14 +123,26 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
index: Some(count),
marker: Some(&buffer[index..index + size]),
action,
prefix: None,
};
}
#[cfg(feature = "bashisms")]
Some(&x) if x.is_ascii_alphabetic() => {
return ParseResult {
remainder: &buffer[0..index],
index: Some(0),
marker: Some(&buffer[index..index + marker.len_utf8()]),
action: ParseAction::BackwardPrefixSearch,
prefix: Some(&buffer[index + marker.len_utf8()..buffer.len()]),
}
}
None => {
return ParseResult {
remainder: &buffer[0..index],
index: Some(0),
marker: Some(&buffer[index..buffer.len()]),
action,
prefix: Some(&buffer[index..buffer.len()]),
}
}
_ => {}
Expand All @@ -135,6 +156,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
index: None,
marker: None,
action,
prefix: None,
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/painting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod prompt_lines;
mod styled_text;
mod utils;

pub use painter::Painter;
pub use painter::{Painter, PainterSuspendedState};
pub(crate) use prompt_lines::PromptLines;
pub use styled_text::StyledText;
pub(crate) use utils::estimate_single_line_wraps;
Loading

0 comments on commit 7165a65

Please sign in to comment.