mirror of
https://github.com/nushell/reedline.git
synced 2024-10-26 17:35:10 +03:00
Simplify application of multiplier (#484)
Take into account that only the product of the `multiplier` and `count`
are relevant to execute motions.
From 140f6d0eda/runtime/doc/motion.txt (L63-L70)
> If the motion includes a count and the operator also had a count before it,
> the two counts are multiplied. For example: "2d3w" deletes six words.
> When doubling the operator it operates on a line. When using a count, before
> or after the first character, that many lines are operated upon. Thus `3dd`
> deletes three lines. A count before and after the first character is
> multiplied, thus `2y3y` yanks six lines.
This commit is contained in:
parent
a7dababdd0
commit
26a09b7a54
@ -283,12 +283,8 @@ impl Command {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_reedline_with_motion(
|
||||
&self,
|
||||
motion: &Motion,
|
||||
count: &Option<usize>,
|
||||
) -> Option<Vec<ReedlineOption>> {
|
||||
let edits = match self {
|
||||
pub fn to_reedline_with_motion(&self, motion: &Motion) -> Option<Vec<ReedlineOption>> {
|
||||
match self {
|
||||
Self::Delete => match motion {
|
||||
Motion::End => Some(vec![ReedlineOption::Edit(EditCommand::CutToLineEnd)]),
|
||||
Motion::Line => Some(vec![ReedlineOption::Edit(EditCommand::CutCurrentLine)]),
|
||||
@ -368,16 +364,6 @@ impl Command {
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
match count {
|
||||
Some(count) => edits.map(|edits| {
|
||||
std::iter::repeat(edits)
|
||||
.take(*count)
|
||||
.flatten()
|
||||
.collect::<Vec<ReedlineOption>>()
|
||||
}),
|
||||
None => edits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,16 @@ pub enum ReedlineOption {
|
||||
Incomplete,
|
||||
}
|
||||
|
||||
impl ReedlineOption {
|
||||
pub fn into_reedline_event(self) -> Option<ReedlineEvent> {
|
||||
match self {
|
||||
ReedlineOption::Event(event) => Some(event),
|
||||
ReedlineOption::Edit(edit) => Some(ReedlineEvent::Edit(vec![edit])),
|
||||
ReedlineOption::Incomplete => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ParseResult {
|
||||
multiplier: Option<usize>,
|
||||
@ -24,6 +34,36 @@ impl ParseResult {
|
||||
self.valid
|
||||
}
|
||||
|
||||
/// Combine `multiplier` and `count` as vim only considers the product
|
||||
///
|
||||
/// Default return value: 1
|
||||
///
|
||||
/// ### Note:
|
||||
///
|
||||
/// https://github.com/vim/vim/blob/140f6d0eda7921f2f0b057ec38ed501240903fc3/runtime/doc/motion.txt#L64-L70
|
||||
fn total_multiplier(&self) -> usize {
|
||||
self.multiplier.unwrap_or(1) * self.count.unwrap_or(1)
|
||||
}
|
||||
|
||||
fn apply_multiplier(&self, raw_events: Option<Vec<ReedlineOption>>) -> ReedlineEvent {
|
||||
if let Some(raw_events) = raw_events {
|
||||
let events = std::iter::repeat(raw_events)
|
||||
.take(self.total_multiplier())
|
||||
.flatten()
|
||||
.filter_map(ReedlineOption::into_reedline_event)
|
||||
.collect::<Vec<ReedlineEvent>>();
|
||||
|
||||
if events.is_empty() || events.contains(&ReedlineEvent::None) {
|
||||
// TODO: Clarify if the `contains(ReedlineEvent::None)` path is relevant
|
||||
ReedlineEvent::None
|
||||
} else {
|
||||
ReedlineEvent::Multiple(events)
|
||||
}
|
||||
} else {
|
||||
ReedlineEvent::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter_insert_mode(&self) -> bool {
|
||||
matches!(
|
||||
(&self.command, &self.motion),
|
||||
@ -41,48 +81,10 @@ impl ParseResult {
|
||||
|
||||
pub fn to_reedline_event(&self) -> ReedlineEvent {
|
||||
match (&self.multiplier, &self.command, &self.count, &self.motion) {
|
||||
// Movements with h,j,k,l are always single char or a number followed
|
||||
// by a single command (char)
|
||||
(multiplier, Some(command), None, None) => {
|
||||
let events = command.to_reedline().into_iter().map(|event| match event {
|
||||
ReedlineOption::Edit(e) => ReedlineEvent::Edit(vec![e]),
|
||||
ReedlineOption::Event(e) => e,
|
||||
ReedlineOption::Incomplete => ReedlineEvent::None,
|
||||
});
|
||||
|
||||
let multiplier = multiplier.unwrap_or(1);
|
||||
let events = std::iter::repeat(events)
|
||||
.take(multiplier)
|
||||
.flatten()
|
||||
.collect::<Vec<ReedlineEvent>>();
|
||||
|
||||
if events.contains(&ReedlineEvent::None) {
|
||||
ReedlineEvent::None
|
||||
} else {
|
||||
ReedlineEvent::Multiple(events)
|
||||
}
|
||||
}
|
||||
(_, Some(command), None, None) => self.apply_multiplier(Some(command.to_reedline())),
|
||||
// This case handles all combinations of commands and motions that could exist
|
||||
// The option count is used to multiply the actions that should be done with the motion
|
||||
// and the multiplier repeats the whole chain x number of time
|
||||
(multiplier, Some(command), count, Some(motion)) => {
|
||||
match command.to_reedline_with_motion(motion, count) {
|
||||
Some(events) => {
|
||||
let multiplier = multiplier.unwrap_or(1);
|
||||
let events = std::iter::repeat(events)
|
||||
.take(multiplier)
|
||||
.flatten()
|
||||
.map(|option| match option {
|
||||
ReedlineOption::Edit(edit) => ReedlineEvent::Edit(vec![edit]),
|
||||
ReedlineOption::Event(event) => event,
|
||||
ReedlineOption::Incomplete => ReedlineEvent::None,
|
||||
})
|
||||
.collect::<Vec<ReedlineEvent>>();
|
||||
|
||||
ReedlineEvent::Multiple(events)
|
||||
}
|
||||
None => ReedlineEvent::None,
|
||||
}
|
||||
(_, Some(command), _, Some(motion)) => {
|
||||
self.apply_multiplier(command.to_reedline_with_motion(motion))
|
||||
}
|
||||
_ => ReedlineEvent::None,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user