mirror of
https://github.com/nushell/reedline.git
synced 2024-09-11 15:55:50 +03:00
bashisms feature for reedline (#374)
* bashisms feature for reedline * cargo fmt
This commit is contained in:
parent
246706c971
commit
accce4af7f
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -27,6 +27,7 @@ jobs:
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -35,3 +35,4 @@ rstest = "0.12.0"
|
||||
|
||||
[features]
|
||||
system_clipboard = ["clipboard"]
|
||||
bashisms = []
|
||||
|
@ -7,10 +7,7 @@ use {
|
||||
highlighter::SimpleMatchHighlighter,
|
||||
hinter::{DefaultHinter, Hinter},
|
||||
history::{FileBackedHistory, History, HistoryNavigationQuery},
|
||||
menu::{
|
||||
menu_functions::{parse_selection_char, IndexDirection},
|
||||
Menu, MenuEvent, ReedlineMenu,
|
||||
},
|
||||
menu::{Menu, MenuEvent, ReedlineMenu},
|
||||
painting::{Painter, PromptLines},
|
||||
prompt::{PromptEditMode, PromptHistorySearchStatus},
|
||||
utils::text_manipulation,
|
||||
@ -25,6 +22,9 @@ use {
|
||||
std::{borrow::Borrow, io, time::Duration},
|
||||
};
|
||||
|
||||
#[cfg(feature = "bashisms")]
|
||||
use crate::menu_functions::{parse_selection_char, ParseAction};
|
||||
|
||||
// The POLL_WAIT is used to specify for how long the POLL should wait for
|
||||
// events, to accelerate the handling of paste or compound resize events. Having
|
||||
// a POLL_WAIT of zero means that every single event is treated as soon as it
|
||||
@ -733,6 +733,7 @@ impl Reedline {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bashisms")]
|
||||
if let Some(event) = self.parse_bang_command() {
|
||||
return self.handle_editor_event(prompt, event);
|
||||
}
|
||||
@ -1046,6 +1047,7 @@ impl Reedline {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bashisms")]
|
||||
/// Parses the ! command to replace entries from the history
|
||||
fn parse_bang_command(&mut self) -> Option<ReedlineEvent> {
|
||||
let buffer = self.editor.get_buffer();
|
||||
@ -1060,19 +1062,25 @@ impl Reedline {
|
||||
let history_result = parsed
|
||||
.index
|
||||
.zip(parsed.marker)
|
||||
.and_then(|(index, indicator)| {
|
||||
if matches!(parsed.direction, IndexDirection::Backward) {
|
||||
self.history
|
||||
.iter_chronologic()
|
||||
.rev()
|
||||
.nth(index.saturating_sub(1))
|
||||
.map(|history| (parsed.remainder.len(), indicator.len(), history.clone()))
|
||||
} else {
|
||||
self.history
|
||||
.iter_chronologic()
|
||||
.nth(index)
|
||||
.map(|history| (parsed.remainder.len(), indicator.len(), history.clone()))
|
||||
}
|
||||
.and_then(|(index, indicator)| match parsed.action {
|
||||
ParseAction::BackwardSearch => self
|
||||
.history
|
||||
.iter_chronologic()
|
||||
.rev()
|
||||
.nth(index.saturating_sub(1))
|
||||
.map(|history| (parsed.remainder.len(), indicator.len(), history.clone())),
|
||||
ParseAction::ForwardSearch => self
|
||||
.history
|
||||
.iter_chronologic()
|
||||
.nth(index)
|
||||
.map(|history| (parsed.remainder.len(), indicator.len(), history.clone())),
|
||||
ParseAction::LastToken => self
|
||||
.history
|
||||
.iter_chronologic()
|
||||
.rev()
|
||||
.next()
|
||||
.and_then(|history| history.split_whitespace().rev().next())
|
||||
.map(|token| (parsed.remainder.len(), indicator.len(), token.to_string())),
|
||||
});
|
||||
|
||||
if let Some((start, size, history)) = history_result {
|
||||
|
@ -16,23 +16,25 @@ pub struct ParseResult<'buffer> {
|
||||
/// Marker representation as string
|
||||
pub marker: Option<&'buffer str>,
|
||||
/// Direction of the search based on the marker
|
||||
pub direction: IndexDirection,
|
||||
pub action: ParseAction,
|
||||
}
|
||||
|
||||
/// Direction of the index found in the string
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum IndexDirection {
|
||||
/// Forward index
|
||||
Forward,
|
||||
/// Backward index
|
||||
Backward,
|
||||
pub enum ParseAction {
|
||||
/// Forward index search
|
||||
ForwardSearch,
|
||||
/// Backward index search
|
||||
BackwardSearch,
|
||||
/// Last token
|
||||
LastToken,
|
||||
}
|
||||
|
||||
/// Splits a string that contains a marker character
|
||||
///
|
||||
/// ## Example usage
|
||||
/// ```
|
||||
/// use reedline::menu_functions::{parse_selection_char, IndexDirection, ParseResult};
|
||||
/// use reedline::menu_functions::{parse_selection_char, ParseAction, ParseResult};
|
||||
///
|
||||
/// let parsed = parse_selection_char("this is an example!10", '!');
|
||||
///
|
||||
@ -42,7 +44,7 @@ pub enum IndexDirection {
|
||||
/// remainder: "this is an example",
|
||||
/// index: Some(10),
|
||||
/// marker: Some("!10"),
|
||||
/// direction: IndexDirection::Forward
|
||||
/// action: ParseAction::ForwardSearch
|
||||
/// }
|
||||
/// )
|
||||
///
|
||||
@ -53,23 +55,33 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
|
||||
remainder: buffer,
|
||||
index: None,
|
||||
marker: None,
|
||||
direction: IndexDirection::Forward,
|
||||
action: ParseAction::ForwardSearch,
|
||||
};
|
||||
}
|
||||
|
||||
let mut input = buffer.chars().peekable();
|
||||
|
||||
let mut index = 0;
|
||||
let mut direction = IndexDirection::Forward;
|
||||
let mut action = ParseAction::ForwardSearch;
|
||||
while let Some(char) = input.next() {
|
||||
if char == marker {
|
||||
match input.peek() {
|
||||
#[cfg(feature = "bashisms")]
|
||||
Some(&x) if x == marker => {
|
||||
return ParseResult {
|
||||
remainder: &buffer[0..index],
|
||||
index: Some(0),
|
||||
marker: Some(&buffer[index..index + 2]),
|
||||
direction: IndexDirection::Backward,
|
||||
action: ParseAction::BackwardSearch,
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "bashisms")]
|
||||
Some(&x) if x == '$' => {
|
||||
return ParseResult {
|
||||
remainder: &buffer[0..index],
|
||||
index: Some(0),
|
||||
marker: Some(&buffer[index..index + 2]),
|
||||
action: ParseAction::LastToken,
|
||||
}
|
||||
}
|
||||
Some(&x) if x.is_ascii_digit() || x == '-' => {
|
||||
@ -79,7 +91,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
|
||||
if c == '-' {
|
||||
let _ = input.next();
|
||||
size += 1;
|
||||
direction = IndexDirection::Backward;
|
||||
action = ParseAction::BackwardSearch;
|
||||
} else if c.is_ascii_digit() {
|
||||
let c = c.to_digit(10).expect("already checked if is a digit");
|
||||
let _ = input.next();
|
||||
@ -91,7 +103,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
|
||||
remainder: &buffer[0..index],
|
||||
index: Some(count),
|
||||
marker: Some(&buffer[index..index + size]),
|
||||
direction,
|
||||
action,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -99,7 +111,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
|
||||
remainder: &buffer[0..index],
|
||||
index: Some(count),
|
||||
marker: Some(&buffer[index..index + size]),
|
||||
direction,
|
||||
action,
|
||||
};
|
||||
}
|
||||
None => {
|
||||
@ -107,7 +119,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
|
||||
remainder: &buffer[0..index],
|
||||
index: Some(0),
|
||||
marker: Some(&buffer[index..buffer.len()]),
|
||||
direction,
|
||||
action,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -123,7 +135,7 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult {
|
||||
remainder: buffer,
|
||||
index: None,
|
||||
marker: None,
|
||||
direction,
|
||||
action,
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,6 +260,7 @@ mod tests {
|
||||
assert_eq!(res.marker, Some(":6"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "bashisms")]
|
||||
#[test]
|
||||
fn parse_double_char() {
|
||||
let input = "search!!";
|
||||
@ -256,7 +269,19 @@ mod tests {
|
||||
assert_eq!(res.remainder, "search");
|
||||
assert_eq!(res.index, Some(0));
|
||||
assert_eq!(res.marker, Some("!!"));
|
||||
assert!(matches!(res.direction, IndexDirection::Backward));
|
||||
assert!(matches!(res.action, ParseAction::BackwardSearch));
|
||||
}
|
||||
|
||||
#[cfg(feature = "bashisms")]
|
||||
#[test]
|
||||
fn parse_last_token() {
|
||||
let input = "!$";
|
||||
let res = parse_selection_char(input, '!');
|
||||
|
||||
assert_eq!(res.remainder, "");
|
||||
assert_eq!(res.index, Some(0));
|
||||
assert_eq!(res.marker, Some("!$"));
|
||||
assert!(matches!(res.action, ParseAction::LastToken));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -327,7 +352,7 @@ mod tests {
|
||||
assert_eq!(res.remainder, "");
|
||||
assert_eq!(res.index, Some(2));
|
||||
assert_eq!(res.marker, Some("!-2"));
|
||||
assert!(matches!(res.direction, IndexDirection::Backward));
|
||||
assert!(matches!(res.action, ParseAction::BackwardSearch));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user