Compare commits
2 Commits
fix-git-ht
...
add_subwor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
404a268412 | ||
|
|
7aede4a348 |
@@ -389,6 +389,9 @@
|
|||||||
"bindings": {
|
"bindings": {
|
||||||
"w": "vim::Word",
|
"w": "vim::Word",
|
||||||
"shift-w": ["vim::Word", { "ignorePunctuation": true }],
|
"shift-w": ["vim::Word", { "ignorePunctuation": true }],
|
||||||
|
// Subword TextObject
|
||||||
|
// "w": "vim::Subword",
|
||||||
|
// "shift-w": ["vim::Subword", { "ignorePunctuation": true }],
|
||||||
"t": "vim::Tag",
|
"t": "vim::Tag",
|
||||||
"s": "vim::Sentence",
|
"s": "vim::Sentence",
|
||||||
"p": "vim::Paragraph",
|
"p": "vim::Paragraph",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use serde::Deserialize;
|
|||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||||
pub enum Object {
|
pub enum Object {
|
||||||
Word { ignore_punctuation: bool },
|
Word { ignore_punctuation: bool },
|
||||||
|
Subword { ignore_punctuation: bool },
|
||||||
Sentence,
|
Sentence,
|
||||||
Paragraph,
|
Paragraph,
|
||||||
Quotes,
|
Quotes,
|
||||||
@@ -47,12 +48,18 @@ struct Word {
|
|||||||
}
|
}
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
#[derive(Clone, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Subword {
|
||||||
|
#[serde(default)]
|
||||||
|
ignore_punctuation: bool,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
struct IndentObj {
|
struct IndentObj {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
include_below: bool,
|
include_below: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_actions!(vim, [Word, IndentObj]);
|
impl_actions!(vim, [Word, Subword, IndentObj]);
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
vim,
|
vim,
|
||||||
@@ -83,6 +90,13 @@ pub fn register(editor: &mut Editor, cx: &mut ViewContext<Vim>) {
|
|||||||
vim.object(Object::Word { ignore_punctuation }, cx)
|
vim.object(Object::Word { ignore_punctuation }, cx)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Vim::action(
|
||||||
|
editor,
|
||||||
|
cx,
|
||||||
|
|vim, &Subword { ignore_punctuation }: &Subword, cx| {
|
||||||
|
vim.object(Object::Subword { ignore_punctuation }, cx)
|
||||||
|
},
|
||||||
|
);
|
||||||
Vim::action(editor, cx, |vim, _: &Tag, cx| vim.object(Object::Tag, cx));
|
Vim::action(editor, cx, |vim, _: &Tag, cx| vim.object(Object::Tag, cx));
|
||||||
Vim::action(editor, cx, |vim, _: &Sentence, cx| {
|
Vim::action(editor, cx, |vim, _: &Sentence, cx| {
|
||||||
vim.object(Object::Sentence, cx)
|
vim.object(Object::Sentence, cx)
|
||||||
@@ -154,6 +168,7 @@ impl Object {
|
|||||||
pub fn is_multiline(self) -> bool {
|
pub fn is_multiline(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Object::Word { .. }
|
Object::Word { .. }
|
||||||
|
| Object::Subword { .. }
|
||||||
| Object::Quotes
|
| Object::Quotes
|
||||||
| Object::BackQuotes
|
| Object::BackQuotes
|
||||||
| Object::VerticalBars
|
| Object::VerticalBars
|
||||||
@@ -176,6 +191,7 @@ impl Object {
|
|||||||
pub fn always_expands_both_ways(self) -> bool {
|
pub fn always_expands_both_ways(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Object::Word { .. }
|
Object::Word { .. }
|
||||||
|
| Object::Subword { .. }
|
||||||
| Object::Sentence
|
| Object::Sentence
|
||||||
| Object::Paragraph
|
| Object::Paragraph
|
||||||
| Object::Argument
|
| Object::Argument
|
||||||
@@ -198,6 +214,7 @@ impl Object {
|
|||||||
pub fn target_visual_mode(self, current_mode: Mode, around: bool) -> Mode {
|
pub fn target_visual_mode(self, current_mode: Mode, around: bool) -> Mode {
|
||||||
match self {
|
match self {
|
||||||
Object::Word { .. }
|
Object::Word { .. }
|
||||||
|
| Object::Subword { .. }
|
||||||
| Object::Sentence
|
| Object::Sentence
|
||||||
| Object::Quotes
|
| Object::Quotes
|
||||||
| Object::BackQuotes
|
| Object::BackQuotes
|
||||||
@@ -243,6 +260,13 @@ impl Object {
|
|||||||
in_word(map, relative_to, ignore_punctuation)
|
in_word(map, relative_to, ignore_punctuation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Object::Subword { ignore_punctuation } => {
|
||||||
|
if around {
|
||||||
|
around_subword(map, relative_to, ignore_punctuation)
|
||||||
|
} else {
|
||||||
|
in_subword(map, relative_to, ignore_punctuation)
|
||||||
|
}
|
||||||
|
}
|
||||||
Object::Sentence => sentence(map, relative_to, around),
|
Object::Sentence => sentence(map, relative_to, around),
|
||||||
Object::Paragraph => paragraph(map, relative_to, around),
|
Object::Paragraph => paragraph(map, relative_to, around),
|
||||||
Object::Quotes => {
|
Object::Quotes => {
|
||||||
@@ -350,6 +374,63 @@ fn in_word(
|
|||||||
Some(start..end)
|
Some(start..end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn in_subword(
|
||||||
|
map: &DisplaySnapshot,
|
||||||
|
relative_to: DisplayPoint,
|
||||||
|
ignore_punctuation: bool,
|
||||||
|
) -> Option<Range<DisplayPoint>> {
|
||||||
|
let offset = relative_to.to_offset(map, Bias::Left);
|
||||||
|
// Use motion::right so that we consider the character under the cursor when looking for the start
|
||||||
|
let classifier = map
|
||||||
|
.buffer_snapshot
|
||||||
|
.char_classifier_at(relative_to.to_point(map))
|
||||||
|
.ignore_punctuation(ignore_punctuation);
|
||||||
|
let in_subword = map
|
||||||
|
.buffer_chars_at(offset)
|
||||||
|
.next()
|
||||||
|
.map(|(c, _)| {
|
||||||
|
if classifier.is_word('-') {
|
||||||
|
!classifier.is_whitespace(c) && c != '_' && c != '-'
|
||||||
|
} else {
|
||||||
|
!classifier.is_whitespace(c) && c != '_'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
let start = if in_subword {
|
||||||
|
movement::find_preceding_boundary_display_point(
|
||||||
|
map,
|
||||||
|
right(map, relative_to, 1),
|
||||||
|
movement::FindRange::SingleLine,
|
||||||
|
|left, right| {
|
||||||
|
let is_word_start = classifier.kind(left) != classifier.kind(right);
|
||||||
|
let is_subword_start = classifier.is_word('-') && left == '-' && right != '-'
|
||||||
|
|| left == '_' && right != '_'
|
||||||
|
|| left.is_lowercase() && right.is_uppercase();
|
||||||
|
is_word_start || is_subword_start
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
||||||
|
let is_word_start = classifier.kind(left) != classifier.kind(right);
|
||||||
|
let is_subword_start = classifier.is_word('-') && left == '-' && right != '-'
|
||||||
|
|| left == '_' && right != '_'
|
||||||
|
|| left.is_lowercase() && right.is_uppercase();
|
||||||
|
is_word_start || is_subword_start
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
||||||
|
let is_word_end = classifier.kind(left) != classifier.kind(right);
|
||||||
|
let is_subword_end = classifier.is_word('-') && left != '-' && right == '-'
|
||||||
|
|| left != '_' && right == '_'
|
||||||
|
|| left.is_lowercase() && right.is_uppercase();
|
||||||
|
is_word_end || is_subword_end
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(start..end)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn surrounding_html_tag(
|
pub fn surrounding_html_tag(
|
||||||
map: &DisplaySnapshot,
|
map: &DisplaySnapshot,
|
||||||
head: DisplayPoint,
|
head: DisplayPoint,
|
||||||
@@ -461,6 +542,40 @@ fn around_word(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn around_subword(
|
||||||
|
map: &DisplaySnapshot,
|
||||||
|
relative_to: DisplayPoint,
|
||||||
|
ignore_punctuation: bool,
|
||||||
|
) -> Option<Range<DisplayPoint>> {
|
||||||
|
// Use motion::right so that we consider the character under the cursor when looking for the start
|
||||||
|
let classifier = map
|
||||||
|
.buffer_snapshot
|
||||||
|
.char_classifier_at(relative_to.to_point(map))
|
||||||
|
.ignore_punctuation(ignore_punctuation);
|
||||||
|
let start = movement::find_preceding_boundary_display_point(
|
||||||
|
map,
|
||||||
|
right(map, relative_to, 1),
|
||||||
|
movement::FindRange::SingleLine,
|
||||||
|
|left, right| {
|
||||||
|
let is_word_start = classifier.kind(left) != classifier.kind(right);
|
||||||
|
let is_subword_start = classifier.is_word('-') && left != '-' && right == '-'
|
||||||
|
|| left != '_' && right == '_'
|
||||||
|
|| left.is_lowercase() && right.is_uppercase();
|
||||||
|
is_word_start || is_subword_start
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
||||||
|
let is_word_end = classifier.kind(left) != classifier.kind(right);
|
||||||
|
let is_subword_end = classifier.is_word('-') && left != '-' && right == '-'
|
||||||
|
|| left != '_' && right == '_'
|
||||||
|
|| left.is_lowercase() && right.is_uppercase();
|
||||||
|
is_word_end || is_subword_end
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(start..end)
|
||||||
|
}
|
||||||
|
|
||||||
fn around_containing_word(
|
fn around_containing_word(
|
||||||
map: &DisplaySnapshot,
|
map: &DisplaySnapshot,
|
||||||
relative_to: DisplayPoint,
|
relative_to: DisplayPoint,
|
||||||
|
|||||||
@@ -392,6 +392,20 @@ Subword motion, which allows you to navigate and select individual words in came
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Similarly subword text objects are available, and can be bound with:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"context": "vim_operator == a || vim_operator == i || vim_operator == cs",
|
||||||
|
"bindings": {
|
||||||
|
"w": "vim::Subword",
|
||||||
|
"shift-w": ["vim::Subword", { "ignorePunctuation": true }],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
Vim mode comes with shortcuts to surround the selection in normal mode (`ys`), but it doesn't have a shortcut to add surrounds in visual mode. By default, `shift-s` substitutes the selection (erases the text and enters insert mode). To use `shift-s` to add surrounds in visual mode, you can add the following object to your keymap.
|
Vim mode comes with shortcuts to surround the selection in normal mode (`ys`), but it doesn't have a shortcut to add surrounds in visual mode. By default, `shift-s` substitutes the selection (erases the text and enters insert mode). To use `shift-s` to add surrounds in visual mode, you can add the following object to your keymap.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
Reference in New Issue
Block a user