vim: Add $ and = as subword motion boundaries (#48276)

These changes update subword motions in order to also take `$` and `=`
into consideration as stopping punctuation, improving the subword
motions for certain languages where `$` and `=` are commonly used, like
PHP, for variables and assignments.

Closes #48267 

Release Notes:

- Improved Vim's subword motions to stop at `$` and `=` characters
This commit is contained in:
Dino authored and GitHub committed 2026-02-04 23:38:00 +00:00
1 parent 33ae3bbd53
commit f2a3a9b365
1 file changed
+42 -8
+42 -8
View File
@@ -1807,8 +1807,8 @@ pub(crate) fn next_subword_end(
|left, right| {
let left_kind = classifier.kind(left);
let right_kind = classifier.kind(right);
let is_stopping_punct = |c: char| ".\"'{}[]()<>".contains(c);
let found_subword_end = is_subword_end(left, right, "_-");
let is_stopping_punct = |c: char| ".$=\"'{}[]()<>".contains(c);
let found_subword_end = is_subword_end(left, right, "$_-");
let is_word_end = (left_kind != right_kind)
&& (!left.is_ascii_punctuation() || is_stopping_punct(left));
@@ -1922,8 +1922,8 @@ fn next_subword_start(
let left_kind = classifier.kind(left);
let right_kind = classifier.kind(right);
let at_newline = right == '\n';
let is_stopping_punct = |c: char| "\"'{}[]()<>".contains(c);
let found_subword_start = is_subword_start(left, right, "._-");
let is_stopping_punct = |c: char| "$=\"'{}[]()<>".contains(c);
let found_subword_start = is_subword_start(left, right, ".$_-");
let is_word_start = (left_kind != right_kind)
&& (!right.is_ascii_punctuation() || is_stopping_punct(right));
let found = (!right.is_whitespace() && (is_word_start || found_subword_start))
@@ -1964,10 +1964,10 @@ fn previous_subword_start(
let right_kind = classifier.kind(right);
let at_newline = right == '\n';
let is_stopping_punct = |c: char| ".\"'{}[]()<>".contains(c);
let is_stopping_punct = |c: char| ".$=\"'{}[]()<>".contains(c);
let is_word_start = (left_kind != right_kind)
&& (is_stopping_punct(right) || !right.is_ascii_punctuation());
let found_subword_start = is_subword_start(left, right, "._-");
let found_subword_start = is_subword_start(left, right, ".$_-");
let found = (!right.is_whitespace() && (is_word_start || found_subword_start))
|| at_newline && crossed_newline
@@ -2012,8 +2012,8 @@ fn previous_subword_end(
let left_kind = classifier.kind(left);
let right_kind = classifier.kind(right);
let is_stopping_punct = |c: char| ".;\"'{}[]()<>".contains(c);
let found_subword_end = is_subword_end(left, right, "_-");
let is_stopping_punct = |c: char| ".$;=\"'{}[]()<>".contains(c);
let found_subword_end = is_subword_end(left, right, "$_-");
if found_subword_end {
return true;
@@ -4855,6 +4855,22 @@ mod test {
cx.set_state("ˇfoo;bar", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("foo;ˇbar", Mode::Normal);
cx.set_state("ˇ<?php\n\n$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?ˇphp\n\n$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?php\nˇ\n$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?php\n\nˇ$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?php\n\n$ˇsomeVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?php\n\n$someˇVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?php\n\n$someVariable ˇ= 2;", Mode::Normal);
cx.simulate_keystrokes("w");
cx.assert_state("<?php\n\n$someVariable = ˇ2;", Mode::Normal);
}
#[gpui::test]
@@ -4969,6 +4985,24 @@ mod test {
cx.assert_state("foo;ˇbar", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("ˇfoo;bar", Mode::Normal);
cx.set_state("<?php\n\n$someVariable = 2ˇ;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?php\n\n$someVariable = ˇ2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?php\n\n$someVariable ˇ= 2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?php\n\n$someˇVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?php\n\n$ˇsomeVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?php\n\nˇ$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?php\nˇ\n$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("<?ˇphp\n\n$someVariable = 2;", Mode::Normal);
cx.simulate_keystrokes("b");
cx.assert_state("ˇ<?php\n\n$someVariable = 2;", Mode::Normal);
}
#[gpui::test]