Start a helix directory
This commit is contained in:
parent
459f7e3403
commit
b93869c564
3 changed files with 132 additions and 109 deletions
|
@ -1,3 +1,5 @@
|
|||
mod object;
|
||||
|
||||
use editor::{DisplayPoint, Editor, movement};
|
||||
use gpui::{Action, actions};
|
||||
use gpui::{Context, Window};
|
||||
|
|
129
crates/vim/src/helix/object.rs
Normal file
129
crates/vim/src/helix/object.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use editor::{
|
||||
DisplayPoint,
|
||||
display_map::DisplaySnapshot,
|
||||
movement::{self, FindRange},
|
||||
};
|
||||
use language::CharKind;
|
||||
use text::{Bias, Selection};
|
||||
|
||||
use crate::{
|
||||
motion::right,
|
||||
object::{Object, expand_to_include_whitespace},
|
||||
};
|
||||
|
||||
impl Object {
|
||||
/// Returns
|
||||
/// Follows helix convention.
|
||||
pub fn helix_range(
|
||||
self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: Selection<DisplayPoint>,
|
||||
around: bool,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let relative_to = selection.head();
|
||||
match self {
|
||||
Object::Word { ignore_punctuation } => {
|
||||
if around {
|
||||
helix_around_word(map, relative_to, ignore_punctuation)
|
||||
} else {
|
||||
helix_in_word(map, relative_to, ignore_punctuation)
|
||||
}
|
||||
}
|
||||
_ => self.range(map, selection, around, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a range that surrounds the word `relative_to` is in.
|
||||
///
|
||||
/// If `relative_to` is between words, return `None`.
|
||||
fn helix_in_word(
|
||||
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 char = map
|
||||
.buffer_chars_at(relative_to.to_offset(map, Bias::Left))
|
||||
.next()?
|
||||
.0;
|
||||
|
||||
if classifier.kind(char) == CharKind::Whitespace {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = movement::find_preceding_boundary_display_point(
|
||||
map,
|
||||
right(map, relative_to, 1),
|
||||
movement::FindRange::SingleLine,
|
||||
|left, right| classifier.kind(left) != classifier.kind(right),
|
||||
);
|
||||
|
||||
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
||||
classifier.kind(left) != classifier.kind(right)
|
||||
});
|
||||
|
||||
Some(start..end)
|
||||
}
|
||||
|
||||
/// Returns the range of the word the cursor is over and all the whitespace on one side.
|
||||
/// If there is whitespace after that is included, otherwise it's whitespace before the word if any.
|
||||
fn helix_around_word(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
ignore_punctuation: bool,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let word_range = helix_in_word(map, relative_to, ignore_punctuation)?;
|
||||
|
||||
Some(expand_to_include_whitespace(map, word_range, true))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{state::Mode, test::VimTestContext};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_select_word_object(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
let start = indoc! {"
|
||||
The quick brˇowˇnˇ
|
||||
fox «ˇjumps» ov«er
|
||||
the laˇ»zy dogˇ
|
||||
"
|
||||
};
|
||||
|
||||
cx.set_state(start, Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("m i w");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
The quick «brownˇ»
|
||||
fox «jumpsˇ» over
|
||||
the «lazyˇ» dogˇ
|
||||
"
|
||||
},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.set_state(start, Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("m a w");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
The quick« brownˇ»
|
||||
fox «jumps ˇ»over
|
||||
the «lazy ˇ»dogˇ
|
||||
"
|
||||
},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -714,27 +714,6 @@ impl Object {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the range the object spans if the cursor is over it.
|
||||
/// Follows helix convention.
|
||||
pub fn helix_range(
|
||||
self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: Selection<DisplayPoint>,
|
||||
around: bool,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let relative_to = selection.head();
|
||||
match self {
|
||||
Object::Word { ignore_punctuation } => {
|
||||
if around {
|
||||
helix_around_word(map, relative_to, ignore_punctuation)
|
||||
} else {
|
||||
helix_in_word(map, relative_to, ignore_punctuation)
|
||||
}
|
||||
}
|
||||
_ => self.range(map, selection, around, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_selection(
|
||||
self,
|
||||
map: &DisplaySnapshot,
|
||||
|
@ -780,42 +759,6 @@ fn in_word(
|
|||
Some(start..end)
|
||||
}
|
||||
|
||||
/// Returns a range that surrounds the word `relative_to` is in.
|
||||
///
|
||||
/// If `relative_to` is between words, return `None`.
|
||||
fn helix_in_word(
|
||||
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 char = map
|
||||
.buffer_chars_at(relative_to.to_offset(map, Bias::Left))
|
||||
.next()?
|
||||
.0;
|
||||
|
||||
if classifier.kind(char) == CharKind::Whitespace {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = movement::find_preceding_boundary_display_point(
|
||||
map,
|
||||
right(map, relative_to, 1),
|
||||
movement::FindRange::SingleLine,
|
||||
|left, right| classifier.kind(left) != classifier.kind(right),
|
||||
);
|
||||
|
||||
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
||||
classifier.kind(left) != classifier.kind(right)
|
||||
});
|
||||
|
||||
Some(start..end)
|
||||
}
|
||||
|
||||
fn in_subword(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
|
@ -984,18 +927,6 @@ fn around_word(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the range of the word the cursor is over and all the whitespace on one side.
|
||||
/// If there is whitespace after that is included, otherwise it's whitespace before the word if any.
|
||||
fn helix_around_word(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
ignore_punctuation: bool,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let word_range = helix_in_word(map, relative_to, ignore_punctuation)?;
|
||||
|
||||
Some(expand_to_include_whitespace(map, word_range, true))
|
||||
}
|
||||
|
||||
fn around_subword(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
|
@ -1435,7 +1366,7 @@ fn is_sentence_end(map: &DisplaySnapshot, offset: usize) -> bool {
|
|||
|
||||
/// Expands the passed range to include whitespace on one side or the other in a line. Attempts to add the
|
||||
/// whitespace to the end first and falls back to the start if there was none.
|
||||
fn expand_to_include_whitespace(
|
||||
pub fn expand_to_include_whitespace(
|
||||
map: &DisplaySnapshot,
|
||||
range: Range<DisplayPoint>,
|
||||
stop_at_newline: bool,
|
||||
|
@ -1822,45 +1753,6 @@ mod test {
|
|||
.assert_matches();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_select_word_object(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
let start = indoc! {"
|
||||
The quick brˇowˇnˇ
|
||||
fox «ˇjumps» ov«er
|
||||
the laˇ»zy dogˇ
|
||||
"
|
||||
};
|
||||
|
||||
cx.set_state(start, Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("m i w");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
The quick «brownˇ»
|
||||
fox «jumpsˇ» over
|
||||
the «lazyˇ» dogˇ
|
||||
"
|
||||
},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.set_state(start, Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("m a w");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
The quick« brownˇ»
|
||||
fox «jumps ˇ»over
|
||||
the «lazy ˇ»dogˇ
|
||||
"
|
||||
},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_visual_word_object(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue