Fix f,t on soft-wrapped lines

Also remove the (dangerously confusing) display_map.find_while
This commit is contained in:
Conrad Irwin 2023-09-07 10:42:47 -06:00
parent c2c04616b4
commit 5f897f45a8
6 changed files with 76 additions and 132 deletions

View file

@ -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 {
found
}
})
.unwrap_or(from)
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
}
}
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
}
})
.unwrap_or(from)
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
}
}
fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> DisplayPoint {

View file

@ -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ˇ aˇaaˇbaaa

View file

@ -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]

View file

@ -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())
});

View file

@ -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"}}