mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Improve logic for obtaining surrounds range in Vim mode (#10938)
now correctly retrieves range in cases where escape characters are present. Fixed #10827 Release Notes: - vim: Fix logic for finding surrounding quotes to ignore escaped characters (#10827)
This commit is contained in:
parent
d1425603f6
commit
1a27016123
@ -23,6 +23,7 @@ collections.workspace = true
|
||||
command_palette_hooks.workspace = true
|
||||
editor.workspace = true
|
||||
gpui.workspace = true
|
||||
itertools.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = [
|
||||
|
@ -9,6 +9,9 @@ use editor::{
|
||||
movement::{self, FindRange},
|
||||
Bias, DisplayPoint,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use gpui::{actions, impl_actions, ViewContext, WindowContext};
|
||||
use language::{char_kind, BufferSnapshot, CharKind, Point, Selection};
|
||||
use serde::Deserialize;
|
||||
@ -801,15 +804,20 @@ fn surrounding_markers(
|
||||
let mut matched_closes = 0;
|
||||
let mut opening = None;
|
||||
|
||||
let mut before_ch = match movement::chars_before(map, point).next() {
|
||||
Some((ch, _)) => ch,
|
||||
_ => '\0',
|
||||
};
|
||||
if let Some((ch, range)) = movement::chars_after(map, point).next() {
|
||||
if ch == open_marker {
|
||||
if ch == open_marker && before_ch != '\\' {
|
||||
if open_marker == close_marker {
|
||||
let mut total = 0;
|
||||
for (ch, _) in movement::chars_before(map, point) {
|
||||
for ((ch, _), (before_ch, _)) in movement::chars_before(map, point).tuple_windows()
|
||||
{
|
||||
if ch == '\n' {
|
||||
break;
|
||||
}
|
||||
if ch == open_marker {
|
||||
if ch == open_marker && before_ch != '\\' {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
@ -823,11 +831,15 @@ fn surrounding_markers(
|
||||
}
|
||||
|
||||
if opening.is_none() {
|
||||
for (ch, range) in movement::chars_before(map, point) {
|
||||
for ((ch, range), (before_ch, _)) in movement::chars_before(map, point).tuple_windows() {
|
||||
if ch == '\n' && !search_across_lines {
|
||||
break;
|
||||
}
|
||||
|
||||
if before_ch == '\\' {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ch == open_marker {
|
||||
if matched_closes == 0 {
|
||||
opening = Some(range);
|
||||
@ -839,15 +851,18 @@ fn surrounding_markers(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opening.is_none() {
|
||||
for (ch, range) in movement::chars_after(map, point) {
|
||||
if ch == open_marker {
|
||||
opening = Some(range);
|
||||
break;
|
||||
} else if ch == close_marker {
|
||||
break;
|
||||
if before_ch != '\\' {
|
||||
if ch == open_marker {
|
||||
opening = Some(range);
|
||||
break;
|
||||
} else if ch == close_marker {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
before_ch = ch;
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,21 +872,28 @@ fn surrounding_markers(
|
||||
|
||||
let mut matched_opens = 0;
|
||||
let mut closing = None;
|
||||
|
||||
before_ch = match movement::chars_before(map, opening.end).next() {
|
||||
Some((ch, _)) => ch,
|
||||
_ => '\0',
|
||||
};
|
||||
for (ch, range) in movement::chars_after(map, opening.end) {
|
||||
if ch == '\n' && !search_across_lines {
|
||||
break;
|
||||
}
|
||||
|
||||
if ch == close_marker {
|
||||
if matched_opens == 0 {
|
||||
closing = Some(range);
|
||||
break;
|
||||
if before_ch != '\\' {
|
||||
if ch == close_marker {
|
||||
if matched_opens == 0 {
|
||||
closing = Some(range);
|
||||
break;
|
||||
}
|
||||
matched_opens -= 1;
|
||||
} else if ch == open_marker {
|
||||
matched_opens += 1;
|
||||
}
|
||||
matched_opens -= 1;
|
||||
} else if ch == open_marker {
|
||||
matched_opens += 1;
|
||||
}
|
||||
|
||||
before_ch = ch;
|
||||
}
|
||||
|
||||
let Some(mut closing) = closing else {
|
||||
@ -1467,6 +1489,32 @@ mod test {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_singleline_surrounding_character_objects_with_escape(
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
cx.set_shared_state(indoc! {
|
||||
"h\"e\\\"lˇlo \\\"world\"!"
|
||||
})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["v", "i", "\""]).await;
|
||||
cx.assert_shared_state(indoc! {
|
||||
"h\"«e\\\"llo \\\"worldˇ»\"!"
|
||||
})
|
||||
.await;
|
||||
|
||||
cx.set_shared_state(indoc! {
|
||||
"hello \"teˇst \\\"inside\\\" world\""
|
||||
})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["v", "i", "\""]).await;
|
||||
cx.assert_shared_state(indoc! {
|
||||
"hello \"«test \\\"inside\\\" worldˇ»\""
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_vertical_bars(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
@ -0,0 +1,10 @@
|
||||
{"Put":{"state":"h\"e\\\"lˇlo \\\"world\"!"}}
|
||||
{"Key":"v"}
|
||||
{"Key":"i"}
|
||||
{"Key":"\""}
|
||||
{"Get":{"state":"h\"«e\\\"llo \\\"worldˇ»\"!","mode":"Visual"}}
|
||||
{"Put":{"state":"hello \"teˇst \\\"inside\\\" world\""}}
|
||||
{"Key":"v"}
|
||||
{"Key":"i"}
|
||||
{"Key":"\""}
|
||||
{"Get":{"state":"hello \"«test \\\"inside\\\" worldˇ»\"","mode":"Visual"}}
|
Loading…
Reference in New Issue
Block a user