mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 02:17:35 +03:00
Fix VIM cw on last character of a word doesn't work as expected: (#10963)
At the moment, using the default expand_selection seems to do the job well, without the need for some additional logic, which may also make the code a little clearer, Fix #10945 Release Notes: - N/A
This commit is contained in:
parent
d9d509a2bb
commit
5c2f27a501
@ -31,48 +31,42 @@ pub fn change_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &m
|
|||||||
editor.set_clip_at_line_ends(false, cx);
|
editor.set_clip_at_line_ends(false, cx);
|
||||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
s.move_with(|map, selection| {
|
s.move_with(|map, selection| {
|
||||||
motion_succeeded |= if let Motion::NextWordStart { ignore_punctuation } = motion
|
motion_succeeded |= match motion {
|
||||||
{
|
Motion::NextWordStart { ignore_punctuation }
|
||||||
expand_changed_word_selection(
|
| Motion::NextSubwordStart { ignore_punctuation } => {
|
||||||
map,
|
expand_changed_word_selection(
|
||||||
selection,
|
map,
|
||||||
times,
|
selection,
|
||||||
ignore_punctuation,
|
times,
|
||||||
&text_layout_details,
|
ignore_punctuation,
|
||||||
false,
|
&text_layout_details,
|
||||||
)
|
motion == Motion::NextSubwordStart { ignore_punctuation },
|
||||||
} else if let Motion::NextSubwordStart { ignore_punctuation } = motion {
|
)
|
||||||
expand_changed_word_selection(
|
|
||||||
map,
|
|
||||||
selection,
|
|
||||||
times,
|
|
||||||
ignore_punctuation,
|
|
||||||
&text_layout_details,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let result = motion.expand_selection(
|
|
||||||
map,
|
|
||||||
selection,
|
|
||||||
times,
|
|
||||||
false,
|
|
||||||
&text_layout_details,
|
|
||||||
);
|
|
||||||
if let Motion::CurrentLine = motion {
|
|
||||||
let mut start_offset = selection.start.to_offset(map, Bias::Left);
|
|
||||||
let scope = map
|
|
||||||
.buffer_snapshot
|
|
||||||
.language_scope_at(selection.start.to_point(&map));
|
|
||||||
for (ch, offset) in map.buffer_chars_at(start_offset) {
|
|
||||||
if ch == '\n' || char_kind(&scope, ch) != CharKind::Whitespace {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
start_offset = offset + ch.len_utf8();
|
|
||||||
}
|
|
||||||
selection.start = start_offset.to_display_point(map);
|
|
||||||
}
|
}
|
||||||
result
|
_ => {
|
||||||
};
|
let result = motion.expand_selection(
|
||||||
|
map,
|
||||||
|
selection,
|
||||||
|
times,
|
||||||
|
false,
|
||||||
|
&text_layout_details,
|
||||||
|
);
|
||||||
|
if let Motion::CurrentLine = motion {
|
||||||
|
let mut start_offset = selection.start.to_offset(map, Bias::Left);
|
||||||
|
let scope = map
|
||||||
|
.buffer_snapshot
|
||||||
|
.language_scope_at(selection.start.to_point(&map));
|
||||||
|
for (ch, offset) in map.buffer_chars_at(start_offset) {
|
||||||
|
if ch == '\n' || char_kind(&scope, ch) != CharKind::Whitespace {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start_offset = offset + ch.len_utf8();
|
||||||
|
}
|
||||||
|
selection.start = start_offset.to_display_point(map);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
copy_selections_content(vim, editor, motion.linewise(), cx);
|
copy_selections_content(vim, editor, motion.linewise(), cx);
|
||||||
@ -116,8 +110,8 @@ pub fn change_object(vim: &mut Vim, object: Object, around: bool, cx: &mut Windo
|
|||||||
// Special case: "cw" and "cW" are treated like "ce" and "cE" if the cursor is
|
// Special case: "cw" and "cW" are treated like "ce" and "cE" if the cursor is
|
||||||
// on a non-blank. This is because "cw" is interpreted as change-word, and a
|
// on a non-blank. This is because "cw" is interpreted as change-word, and a
|
||||||
// word does not include the following white space. {Vi: "cw" when on a blank
|
// word does not include the following white space. {Vi: "cw" when on a blank
|
||||||
// followed by other blanks changes only the first blank; this is probably a
|
// followed by other blanks changes only the first blank; this is probably a
|
||||||
// bug, because "dw" deletes all the blanks}
|
// bug, because "dw" deletes all the blanks}
|
||||||
fn expand_changed_word_selection(
|
fn expand_changed_word_selection(
|
||||||
map: &DisplaySnapshot,
|
map: &DisplaySnapshot,
|
||||||
selection: &mut Selection<DisplayPoint>,
|
selection: &mut Selection<DisplayPoint>,
|
||||||
@ -126,7 +120,7 @@ fn expand_changed_word_selection(
|
|||||||
text_layout_details: &TextLayoutDetails,
|
text_layout_details: &TextLayoutDetails,
|
||||||
use_subword: bool,
|
use_subword: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if times.is_none() || times.unwrap() == 1 {
|
let is_in_word = || {
|
||||||
let scope = map
|
let scope = map
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.language_scope_at(selection.start.to_point(map));
|
.language_scope_at(selection.start.to_point(map));
|
||||||
@ -135,25 +129,28 @@ fn expand_changed_word_selection(
|
|||||||
.next()
|
.next()
|
||||||
.map(|(c, _)| char_kind(&scope, c) != CharKind::Whitespace)
|
.map(|(c, _)| char_kind(&scope, c) != CharKind::Whitespace)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
return in_word;
|
||||||
if in_word {
|
};
|
||||||
if use_subword {
|
if (times.is_none() || times.unwrap() == 1) && is_in_word() {
|
||||||
selection.end =
|
let next_char = map
|
||||||
motion::next_subword_end(map, selection.end, ignore_punctuation, 1, false);
|
.buffer_chars_at(
|
||||||
} else {
|
motion::next_char(map, selection.end, false).to_offset(map, Bias::Left),
|
||||||
selection.end =
|
)
|
||||||
motion::next_word_end(map, selection.end, ignore_punctuation, 1, false);
|
.next();
|
||||||
|
match next_char {
|
||||||
|
Some((' ', _)) => selection.end = motion::next_char(map, selection.end, false),
|
||||||
|
_ => {
|
||||||
|
if use_subword {
|
||||||
|
selection.end =
|
||||||
|
motion::next_subword_end(map, selection.end, ignore_punctuation, 1, false);
|
||||||
|
} else {
|
||||||
|
selection.end =
|
||||||
|
motion::next_word_end(map, selection.end, ignore_punctuation, 1, false);
|
||||||
|
}
|
||||||
|
selection.end = motion::next_char(map, selection.end, false);
|
||||||
}
|
}
|
||||||
selection.end = motion::next_char(map, selection.end, false);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let motion = if use_subword {
|
|
||||||
Motion::NextSubwordStart { ignore_punctuation }
|
|
||||||
} else {
|
|
||||||
Motion::NextWordStart { ignore_punctuation }
|
|
||||||
};
|
|
||||||
motion.expand_selection(map, selection, None, false, &text_layout_details)
|
|
||||||
}
|
}
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
let motion = if use_subword {
|
let motion = if use_subword {
|
||||||
Motion::NextSubwordStart { ignore_punctuation }
|
Motion::NextSubwordStart { ignore_punctuation }
|
||||||
@ -209,6 +206,7 @@ mod test {
|
|||||||
cx.assert("Teˇst").await;
|
cx.assert("Teˇst").await;
|
||||||
cx.assert("Tˇest test").await;
|
cx.assert("Tˇest test").await;
|
||||||
cx.assert("Testˇ test").await;
|
cx.assert("Testˇ test").await;
|
||||||
|
cx.assert("Tesˇt test").await;
|
||||||
cx.assert(indoc! {"
|
cx.assert(indoc! {"
|
||||||
Test teˇst
|
Test teˇst
|
||||||
test"})
|
test"})
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
{"Key":"c"}
|
{"Key":"c"}
|
||||||
{"Key":"w"}
|
{"Key":"w"}
|
||||||
{"Get":{"state":"Testˇtest","mode":"Insert"}}
|
{"Get":{"state":"Testˇtest","mode":"Insert"}}
|
||||||
|
{"Put":{"state":"Tesˇt test"}}
|
||||||
|
{"Key":"c"}
|
||||||
|
{"Key":"w"}
|
||||||
|
{"Get":{"state":"Tesˇ test","mode":"Insert"}}
|
||||||
{"Put":{"state":"Test teˇst\ntest"}}
|
{"Put":{"state":"Test teˇst\ntest"}}
|
||||||
{"Key":"c"}
|
{"Key":"c"}
|
||||||
{"Key":"w"}
|
{"Key":"w"}
|
||||||
|
Loading…
Reference in New Issue
Block a user