mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Fix f,t on soft-wrapped lines
Also remove the (dangerously confusing) display_map.find_while
This commit is contained in:
parent
c2c04616b4
commit
5f897f45a8
@ -555,67 +555,6 @@ impl DisplaySnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator of the start positions of the occurrences of `target` in the `self` after `from`
|
||||
/// Stops if `condition` returns false for any of the character position pairs observed.
|
||||
pub fn find_while<'a>(
|
||||
&'a self,
|
||||
from: DisplayPoint,
|
||||
target: &str,
|
||||
condition: impl FnMut(char, DisplayPoint) -> bool + 'a,
|
||||
) -> impl Iterator<Item = DisplayPoint> + 'a {
|
||||
Self::find_internal(self.chars_at(from), target.chars().collect(), condition)
|
||||
}
|
||||
|
||||
/// Returns an iterator of the end positions of the occurrences of `target` in the `self` before `from`
|
||||
/// Stops if `condition` returns false for any of the character position pairs observed.
|
||||
pub fn reverse_find_while<'a>(
|
||||
&'a self,
|
||||
from: DisplayPoint,
|
||||
target: &str,
|
||||
condition: impl FnMut(char, DisplayPoint) -> bool + 'a,
|
||||
) -> impl Iterator<Item = DisplayPoint> + 'a {
|
||||
Self::find_internal(
|
||||
self.reverse_chars_at(from),
|
||||
target.chars().rev().collect(),
|
||||
condition,
|
||||
)
|
||||
}
|
||||
|
||||
fn find_internal<'a>(
|
||||
iterator: impl Iterator<Item = (char, DisplayPoint)> + 'a,
|
||||
target: Vec<char>,
|
||||
mut condition: impl FnMut(char, DisplayPoint) -> bool + 'a,
|
||||
) -> impl Iterator<Item = DisplayPoint> + 'a {
|
||||
// List of partial matches with the index of the last seen character in target and the starting point of the match
|
||||
let mut partial_matches: Vec<(usize, DisplayPoint)> = Vec::new();
|
||||
iterator
|
||||
.take_while(move |(ch, point)| condition(*ch, *point))
|
||||
.filter_map(move |(ch, point)| {
|
||||
if Some(&ch) == target.get(0) {
|
||||
partial_matches.push((0, point));
|
||||
}
|
||||
|
||||
let mut found = None;
|
||||
// Keep partial matches that have the correct next character
|
||||
partial_matches.retain_mut(|(match_position, match_start)| {
|
||||
if target.get(*match_position) == Some(&ch) {
|
||||
*match_position += 1;
|
||||
if *match_position == target.len() {
|
||||
found = Some(match_start.clone());
|
||||
// This match is completed. No need to keep tracking it
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
found
|
||||
})
|
||||
}
|
||||
|
||||
pub fn column_to_chars(&self, display_row: u32, target: u32) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut column = 0;
|
||||
@ -933,7 +872,7 @@ pub mod tests {
|
||||
use smol::stream::StreamExt;
|
||||
use std::{env, sync::Arc};
|
||||
use theme::SyntaxTheme;
|
||||
use util::test::{marked_text_offsets, marked_text_ranges, sample_text};
|
||||
use util::test::{marked_text_ranges, sample_text};
|
||||
use Bias::*;
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
@ -1744,32 +1683,6 @@ pub mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_internal() {
|
||||
assert("This is a ˇtest of find internal", "test");
|
||||
assert("Some text ˇaˇaˇaa with repeated characters", "aa");
|
||||
|
||||
fn assert(marked_text: &str, target: &str) {
|
||||
let (text, expected_offsets) = marked_text_offsets(marked_text);
|
||||
|
||||
let chars = text
|
||||
.chars()
|
||||
.enumerate()
|
||||
.map(|(index, ch)| (ch, DisplayPoint::new(0, index as u32)));
|
||||
let target = target.chars();
|
||||
|
||||
assert_eq!(
|
||||
expected_offsets
|
||||
.into_iter()
|
||||
.map(|offset| offset as u32)
|
||||
.collect::<Vec<_>>(),
|
||||
DisplaySnapshot::find_internal(chars, target.collect(), |_, _| true)
|
||||
.map(|point| point.column())
|
||||
.collect::<Vec<_>>()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn syntax_chunks<'a>(
|
||||
rows: Range<u32>,
|
||||
map: &ModelHandle<DisplayMap>,
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::{cmp, sync::Arc};
|
||||
use std::cmp;
|
||||
|
||||
use editor::{
|
||||
char_kind,
|
||||
display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint},
|
||||
movement::{self, FindRange},
|
||||
movement::{self, find_boundary, find_preceding_boundary, FindRange},
|
||||
Bias, CharKind, DisplayPoint, ToOffset,
|
||||
};
|
||||
use gpui::{actions, impl_actions, AppContext, WindowContext};
|
||||
@ -37,8 +37,8 @@ pub enum Motion {
|
||||
StartOfDocument,
|
||||
EndOfDocument,
|
||||
Matching,
|
||||
FindForward { before: bool, text: Arc<str> },
|
||||
FindBackward { after: bool, text: Arc<str> },
|
||||
FindForward { before: bool, char: char },
|
||||
FindBackward { after: bool, char: char },
|
||||
NextLineStart,
|
||||
}
|
||||
|
||||
@ -233,25 +233,25 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
|
||||
|
||||
fn repeat_motion(backwards: bool, cx: &mut WindowContext) {
|
||||
let find = match Vim::read(cx).workspace_state.last_find.clone() {
|
||||
Some(Motion::FindForward { before, text }) => {
|
||||
Some(Motion::FindForward { before, char }) => {
|
||||
if backwards {
|
||||
Motion::FindBackward {
|
||||
after: before,
|
||||
text,
|
||||
char,
|
||||
}
|
||||
} else {
|
||||
Motion::FindForward { before, text }
|
||||
Motion::FindForward { before, char }
|
||||
}
|
||||
}
|
||||
|
||||
Some(Motion::FindBackward { after, text }) => {
|
||||
Some(Motion::FindBackward { after, char }) => {
|
||||
if backwards {
|
||||
Motion::FindForward {
|
||||
before: after,
|
||||
text,
|
||||
char,
|
||||
}
|
||||
} else {
|
||||
Motion::FindBackward { after, text }
|
||||
Motion::FindBackward { after, char }
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
@ -403,12 +403,12 @@ impl Motion {
|
||||
SelectionGoal::None,
|
||||
),
|
||||
Matching => (matching(map, point), SelectionGoal::None),
|
||||
FindForward { before, text } => (
|
||||
find_forward(map, point, *before, text.clone(), times),
|
||||
FindForward { before, char } => (
|
||||
find_forward(map, point, *before, *char, times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
FindBackward { after, text } => (
|
||||
find_backward(map, point, *after, text.clone(), times),
|
||||
FindBackward { after, char } => (
|
||||
find_backward(map, point, *after, *char, times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
NextLineStart => (next_line_start(map, point, times), SelectionGoal::None),
|
||||
@ -793,44 +793,55 @@ fn find_forward(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
before: bool,
|
||||
target: Arc<str>,
|
||||
target: char,
|
||||
times: usize,
|
||||
) -> DisplayPoint {
|
||||
map.find_while(from, target.as_ref(), |ch, _| ch != '\n')
|
||||
.skip_while(|found_at| found_at == &from)
|
||||
.nth(times - 1)
|
||||
.map(|mut found| {
|
||||
if before {
|
||||
*found.column_mut() -= 1;
|
||||
found = map.clip_point(found, Bias::Right);
|
||||
found
|
||||
} else {
|
||||
let mut to = from;
|
||||
let mut found = false;
|
||||
|
||||
for _ in 0..times {
|
||||
found = false;
|
||||
to = find_boundary(map, to, FindRange::SingleLine, |_, right| {
|
||||
found = right == target;
|
||||
found
|
||||
});
|
||||
}
|
||||
|
||||
if found {
|
||||
if before && to.column() > 0 {
|
||||
*to.column_mut() -= 1;
|
||||
map.clip_point(to, Bias::Left)
|
||||
} else {
|
||||
to
|
||||
}
|
||||
} else {
|
||||
from
|
||||
}
|
||||
})
|
||||
.unwrap_or(from)
|
||||
}
|
||||
|
||||
fn find_backward(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
after: bool,
|
||||
target: Arc<str>,
|
||||
target: char,
|
||||
times: usize,
|
||||
) -> DisplayPoint {
|
||||
map.reverse_find_while(from, target.as_ref(), |ch, _| ch != '\n')
|
||||
.skip_while(|found_at| found_at == &from)
|
||||
.nth(times - 1)
|
||||
.map(|mut found| {
|
||||
if after {
|
||||
*found.column_mut() += 1;
|
||||
found = map.clip_point(found, Bias::Left);
|
||||
found
|
||||
} else {
|
||||
found
|
||||
let mut to = from;
|
||||
|
||||
for _ in 0..times {
|
||||
to = find_preceding_boundary(map, to, FindRange::SingleLine, |_, right| right == target);
|
||||
}
|
||||
|
||||
if map.buffer_snapshot.chars_at(to.to_point(map)).next() == Some(target) {
|
||||
if after {
|
||||
*to.column_mut() += 1;
|
||||
map.clip_point(to, Bias::Right)
|
||||
} else {
|
||||
to
|
||||
}
|
||||
} else {
|
||||
from
|
||||
}
|
||||
})
|
||||
.unwrap_or(from)
|
||||
}
|
||||
|
||||
fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> DisplayPoint {
|
||||
|
@ -780,6 +780,7 @@ mod test {
|
||||
#[gpui::test]
|
||||
async fn test_f_and_t(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
||||
for count in 1..=3 {
|
||||
let test_case = indoc! {"
|
||||
ˇaaaˇbˇ ˇbˇ ˇbˇbˇ aˇaaˇbaaa
|
||||
|
@ -449,6 +449,13 @@ async fn test_wrapped_lines(cx: &mut gpui::TestAppContext) {
|
||||
fourteen char
|
||||
"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["j", "shift-f", "e", "f", "r"])
|
||||
.await;
|
||||
cx.assert_shared_state(indoc! {"
|
||||
fourteen•
|
||||
fourteen chaˇr
|
||||
"})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -295,14 +295,20 @@ impl Vim {
|
||||
|
||||
match Vim::read(cx).active_operator() {
|
||||
Some(Operator::FindForward { before }) => {
|
||||
let find = Motion::FindForward { before, text };
|
||||
let find = Motion::FindForward {
|
||||
before,
|
||||
char: text.chars().next().unwrap(),
|
||||
};
|
||||
Vim::update(cx, |vim, _| {
|
||||
vim.workspace_state.last_find = Some(find.clone())
|
||||
});
|
||||
motion::motion(find, cx)
|
||||
}
|
||||
Some(Operator::FindBackward { after }) => {
|
||||
let find = Motion::FindBackward { after, text };
|
||||
let find = Motion::FindBackward {
|
||||
after,
|
||||
char: text.chars().next().unwrap(),
|
||||
};
|
||||
Vim::update(cx, |vim, _| {
|
||||
vim.workspace_state.last_find = Some(find.clone())
|
||||
});
|
||||
|
@ -53,3 +53,9 @@
|
||||
{"Key":"i"}
|
||||
{"Key":"w"}
|
||||
{"Get":{"state":"fourteenˇ \nfourteen char\n","mode":"Normal"}}
|
||||
{"Key":"j"}
|
||||
{"Key":"shift-f"}
|
||||
{"Key":"e"}
|
||||
{"Key":"f"}
|
||||
{"Key":"r"}
|
||||
{"Get":{"state":"fourteen \nfourteen chaˇr\n","mode":"Normal"}}
|
||||
|
Loading…
Reference in New Issue
Block a user