diff --git a/assets/icons/plus_12.svg b/assets/icons/plus_12.svg
new file mode 100644
index 0000000000..7997c97c06
--- /dev/null
+++ b/assets/icons/plus_12.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/plus_16.svg b/assets/icons/plus_16.svg
new file mode 100644
index 0000000000..1fa008ac64
--- /dev/null
+++ b/assets/icons/plus_16.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/plus_8.svg b/assets/icons/plus_8.svg
new file mode 100644
index 0000000000..9abfd46744
--- /dev/null
+++ b/assets/icons/plus_8.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs
index 93a4c372ec..ab5b7155a5 100644
--- a/crates/editor/src/display_map.rs
+++ b/crates/editor/src/display_map.rs
@@ -1170,7 +1170,7 @@ pub mod tests {
);
language.set_theme(&theme);
- let (text, highlighted_ranges) = marked_text_ranges(r#"const[] [a]: B = "c [d]""#);
+ let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false);
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await;
@@ -1246,28 +1246,28 @@ pub mod tests {
}
use Bias::{Left, Right};
- assert("||α", false, Left, cx);
- assert("||α", true, Left, cx);
- assert("||α", false, Right, cx);
- assert("|α|", true, Right, cx);
- assert("||✋", false, Left, cx);
- assert("||✋", true, Left, cx);
- assert("||✋", false, Right, cx);
- assert("|✋|", true, Right, cx);
- assert("||🍐", false, Left, cx);
- assert("||🍐", true, Left, cx);
- assert("||🍐", false, Right, cx);
- assert("|🍐|", true, Right, cx);
- assert("||\t", false, Left, cx);
- assert("||\t", true, Left, cx);
- assert("||\t", false, Right, cx);
- assert("|\t|", true, Right, cx);
- assert(" ||\t", false, Left, cx);
- assert(" ||\t", true, Left, cx);
- assert(" ||\t", false, Right, cx);
- assert(" |\t|", true, Right, cx);
- assert(" ||\t", false, Left, cx);
- assert(" ||\t", false, Right, cx);
+ assert("ˇˇα", false, Left, cx);
+ assert("ˇˇα", true, Left, cx);
+ assert("ˇˇα", false, Right, cx);
+ assert("ˇαˇ", true, Right, cx);
+ assert("ˇˇ✋", false, Left, cx);
+ assert("ˇˇ✋", true, Left, cx);
+ assert("ˇˇ✋", false, Right, cx);
+ assert("ˇ✋ˇ", true, Right, cx);
+ assert("ˇˇ🍐", false, Left, cx);
+ assert("ˇˇ🍐", true, Left, cx);
+ assert("ˇˇ🍐", false, Right, cx);
+ assert("ˇ🍐ˇ", true, Right, cx);
+ assert("ˇˇ\t", false, Left, cx);
+ assert("ˇˇ\t", true, Left, cx);
+ assert("ˇˇ\t", false, Right, cx);
+ assert("ˇ\tˇ", true, Right, cx);
+ assert(" ˇˇ\t", false, Left, cx);
+ assert(" ˇˇ\t", true, Left, cx);
+ assert(" ˇˇ\t", false, Right, cx);
+ assert(" ˇ\tˇ", true, Right, cx);
+ assert(" ˇˇ\t", false, Left, cx);
+ assert(" ˇˇ\t", false, Right, cx);
}
#[gpui::test]
@@ -1283,10 +1283,10 @@ pub mod tests {
);
}
- assert("||", cx);
- assert("|a|", cx);
- assert("a|b|", cx);
- assert("a|α|", cx);
+ assert("ˇˇ", cx);
+ assert("ˇaˇ", cx);
+ assert("aˇbˇ", cx);
+ assert("aˇαˇ", cx);
}
#[gpui::test]
diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs
index 5211466e94..7c2d560a41 100644
--- a/crates/editor/src/editor.rs
+++ b/crates/editor/src/editor.rs
@@ -76,7 +76,7 @@ const MAX_LINE_LEN: usize = 1024;
const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
const MAX_SELECTION_HISTORY_LEN: usize = 1024;
-#[derive(Clone, Deserialize, PartialEq)]
+#[derive(Clone, Deserialize, PartialEq, Default)]
pub struct SelectNext {
#[serde(default)]
pub replace_newest: bool,
@@ -6644,9 +6644,7 @@ mod tests {
use unindent::Unindent;
use util::{
assert_set_eq,
- test::{
- marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text, TextRangeMarker,
- },
+ test::{marked_text_ranges, marked_text_ranges_by, sample_text, TextRangeMarker},
};
use workspace::{FollowableItem, ItemHandle, NavigationEntry, Pane};
@@ -7044,13 +7042,16 @@ mod tests {
#[gpui::test]
fn test_clone(cx: &mut gpui::MutableAppContext) {
- let (text, selection_ranges) = marked_text_ranges(indoc! {"
- one
- two
- three[]
- four
- five[]
- "});
+ let (text, selection_ranges) = marked_text_ranges(
+ indoc! {"
+ one
+ two
+ threeˇ
+ four
+ fiveˇ
+ "},
+ true,
+ );
cx.set_global(Settings::test(cx));
let buffer = MultiBuffer::build_simple(&text, cx);
@@ -7732,93 +7733,38 @@ mod tests {
});
view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
- assert_selection_ranges(
- "use std::<>str::{foo, bar}\n\n {[]baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", view, cx);
view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
- assert_selection_ranges(
- "use std<>::str::{foo, bar}\n\n []{baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use stdˇ::str::{foo, bar}\n\n ˇ{baz.qux()}", view, cx);
view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
- assert_selection_ranges(
- "use <>std::str::{foo, bar}\n\n[] {baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use ˇstd::str::{foo, bar}\n\nˇ {baz.qux()}", view, cx);
view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
- assert_selection_ranges(
- "<>use std::str::{foo, bar}\n[]\n {baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("ˇuse std::str::{foo, bar}\nˇ\n {baz.qux()}", view, cx);
view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
- assert_selection_ranges(
- "<>use std::str::{foo, bar[]}\n\n {baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("ˇuse std::str::{foo, barˇ}\n\n {baz.qux()}", view, cx);
view.move_to_next_word_end(&MoveToNextWordEnd, cx);
- assert_selection_ranges(
- "use<> std::str::{foo, bar}[]\n\n {baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("useˇ std::str::{foo, bar}ˇ\n\n {baz.qux()}", view, cx);
view.move_to_next_word_end(&MoveToNextWordEnd, cx);
- assert_selection_ranges(
- "use std<>::str::{foo, bar}\n[]\n {baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use stdˇ::str::{foo, bar}\nˇ\n {baz.qux()}", view, cx);
view.move_to_next_word_end(&MoveToNextWordEnd, cx);
- assert_selection_ranges(
- "use std::<>str::{foo, bar}\n\n {[]baz.qux()}",
- vec![('<', '>'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", view, cx);
view.move_right(&MoveRight, cx);
view.select_to_previous_word_start(&SelectToPreviousWordStart, cx);
- assert_selection_ranges(
- "use std::>s'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}", view, cx);
view.select_to_previous_word_start(&SelectToPreviousWordStart, cx);
- assert_selection_ranges(
- "use std>::s'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use std«ˇ::s»tr::{foo, bar}\n\n «ˇ{b»az.qux()}", view, cx);
view.select_to_next_word_end(&SelectToNextWordEnd, cx);
- assert_selection_ranges(
- "use std::>s'), ('[', ']')],
- view,
- cx,
- );
+ assert_selection_ranges("use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}", view, cx);
});
}
@@ -7878,15 +7824,10 @@ mod tests {
}
#[gpui::test]
- fn test_delete_to_beginning_of_line(cx: &mut gpui::MutableAppContext) {
- cx.set_global(Settings::test(cx));
- let (text, ranges) = marked_text_ranges("one [two three] four");
- let buffer = MultiBuffer::build_simple(&text, cx);
-
- let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
-
- editor.update(cx, |editor, cx| {
- editor.change_selections(None, cx, |s| s.select_ranges(ranges));
+ async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) {
+ let mut cx = EditorTestContext::new(cx).await;
+ cx.set_state("one «two threeˇ» four");
+ cx.update_editor(|editor, cx| {
editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
assert_eq!(editor.text(cx), " four");
});
@@ -8050,33 +7991,33 @@ mod tests {
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
cx.set_state(indoc! {"
- const a: |A = (
- (|
- [const_function}(|),
- so{m]et[h}ing_|else,|
- )|
- |);|
- "});
+ const a: ˇA = (
+ (ˇ
+ «const_functionˇ»(ˇ),
+ so«mˇ»et«hˇ»ing_ˇelse,ˇ
+ )ˇ
+ ˇ);ˇ
+ "});
cx.update_editor(|e, cx| e.newline_below(&NewlineBelow, cx));
cx.assert_editor_state(indoc! {"
const a: A = (
- |
+ ˇ
(
- |
+ ˇ
const_function(),
- |
- |
+ ˇ
+ ˇ
something_else,
- |
- |
- |
- |
+ ˇ
+ ˇ
+ ˇ
+ ˇ
)
- |
+ ˇ
);
- |
- |
- "});
+ ˇ
+ ˇ
+ "});
}
#[gpui::test]
@@ -8115,25 +8056,25 @@ mod tests {
});
});
cx.set_state(indoc! {"
- |ab|c
- |🏀|🏀|efg
- d|
+ ˇabˇc
+ ˇ🏀ˇ🏀ˇefg
+ dˇ
"});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- |ab |c
- |🏀 |🏀 |efg
- d |
+ ˇab ˇc
+ ˇ🏀 ˇ🏀 ˇefg
+ d ˇ
"});
cx.set_state(indoc! {"
a
- [🏀}🏀[🏀}🏀[🏀}
+ «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ»
"});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
a
- [🏀}🏀[🏀}🏀[🏀}
+ «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ»
"});
}
@@ -8154,26 +8095,26 @@ mod tests {
// a soft tab. cursors that are to the left of the suggested indent
// auto-indent their line.
cx.set_state(indoc! {"
- |
+ ˇ
const a: B = (
c(
d(
- |
+ ˇ
)
- |
- | )
+ ˇ
+ ˇ )
);
"});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- |
+ ˇ
const a: B = (
c(
d(
- |
+ ˇ
)
- |
- |)
+ ˇ
+ ˇ)
);
"});
@@ -8181,16 +8122,16 @@ mod tests {
cx.set_state(indoc! {"
const a: B = (
c(
- | |
- | )
+ ˇ ˇ
+ ˇ )
);
"});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
const a: B = (
c(
- |
- |)
+ ˇ
+ ˇ)
);
"});
}
@@ -8200,58 +8141,68 @@ mod tests {
let mut cx = EditorTestContext::new(cx).await;
cx.set_state(indoc! {"
- [one} [two}
+ «oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- [one} [two}
+ «oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- [one} [two}
+ «oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
// select across line ending
cx.set_state(indoc! {"
one two
- t[hree
- } four"});
+ t«hree
+ ˇ» four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
one two
- t[hree
- } four"});
+ t«hree
+ ˇ» four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
one two
- t[hree
- } four"});
+ t«hree
+ ˇ» four
+ "});
// Ensure that indenting/outdenting works when the cursor is at column 0.
cx.set_state(indoc! {"
one two
- |three
- four"});
+ ˇthree
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
one two
- |three
- four"});
+ ˇthree
+ four
+ "});
cx.set_state(indoc! {"
one two
- | three
- four"});
+ ˇ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
one two
- |three
- four"});
+ ˇthree
+ four
+ "});
}
#[gpui::test]
@@ -8265,75 +8216,90 @@ mod tests {
// select two ranges on one line
cx.set_state(indoc! {"
- [one} [two}
+ «oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- \t[one} [two}
+ \t«oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- \t\t[one} [two}
+ \t\t«oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- \t[one} [two}
+ \t«oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- [one} [two}
+ «oneˇ» «twoˇ»
three
- four"});
+ four
+ "});
// select across a line ending
cx.set_state(indoc! {"
one two
- t[hree
- }four"});
+ t«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
one two
- \tt[hree
- }four"});
+ \tt«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
one two
- \t\tt[hree
- }four"});
+ \t\tt«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
one two
- \tt[hree
- }four"});
+ \tt«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
one two
- t[hree
- }four"});
+ t«hree
+ ˇ»four
+ "});
// Ensure that indenting/outdenting works when the cursor is at column 0.
cx.set_state(indoc! {"
one two
- |three
- four"});
- cx.assert_editor_state(indoc! {"
- one two
- |three
- four"});
- cx.update_editor(|e, cx| e.tab(&Tab, cx));
- cx.assert_editor_state(indoc! {"
- one two
- \t|three
- four"});
+ ˇthree
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
one two
- |three
- four"});
+ ˇthree
+ four
+ "});
+ cx.update_editor(|e, cx| e.tab(&Tab, cx));
+ cx.assert_editor_state(indoc! {"
+ one two
+ \tˇthree
+ four
+ "});
+ cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
+ cx.assert_editor_state(indoc! {"
+ one two
+ ˇthree
+ four
+ "});
}
#[gpui::test]
@@ -8412,10 +8378,10 @@ mod tests {
select_ranges(
&mut editor,
indoc! {"
- [a] = 1
+ «aˇ» = 1
b = 2
- [const c:] usize = 3;
+ «const c:ˇ» usize = 3;
"},
cx,
);
@@ -8424,10 +8390,10 @@ mod tests {
assert_text_with_selections(
&mut editor,
indoc! {"
- [a] = 1
+ «aˇ» = 1
b = 2
- [const c:] usize = 3;
+ «const c:ˇ» usize = 3;
"},
cx,
);
@@ -8435,10 +8401,10 @@ mod tests {
assert_text_with_selections(
&mut editor,
indoc! {"
- [a] = 1
+ «aˇ» = 1
b = 2
- [const c:] usize = 3;
+ «const c:ˇ» usize = 3;
"},
cx,
);
@@ -8450,43 +8416,48 @@ mod tests {
#[gpui::test]
async fn test_backspace(cx: &mut gpui::TestAppContext) {
let mut cx = EditorTestContext::new(cx).await;
+
// Basic backspace
cx.set_state(indoc! {"
- on|e two three
- fou[r} five six
- seven {eight nine
- ]ten"});
+ onˇe two three
+ fou«rˇ» five six
+ seven «ˇeight nine
+ »ten
+ "});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
cx.assert_editor_state(indoc! {"
- o|e two three
- fou| five six
- seven |ten"});
+ oˇe two three
+ fouˇ five six
+ seven ˇten
+ "});
// Test backspace inside and around indents
cx.set_state(indoc! {"
zero
- |one
- |two
- | | | three
- | | four"});
+ ˇone
+ ˇtwo
+ ˇ ˇ ˇ three
+ ˇ ˇ four
+ "});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
cx.assert_editor_state(indoc! {"
zero
- |one
- |two
- | three| four"});
+ ˇone
+ ˇtwo
+ ˇ threeˇ four
+ "});
// Test backspace with line_mode set to true
cx.update_editor(|e, _| e.selections.line_mode = true);
cx.set_state(indoc! {"
- The |quick |brown
+ The ˇquick ˇbrown
fox jumps over
the lazy dog
- |The qu[ick b}rown"});
+ ˇThe qu«ick bˇ»rown"});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
cx.assert_editor_state(indoc! {"
- |fox jumps over
- the lazy dog|"});
+ ˇfox jumps over
+ the lazy dogˇ"});
}
#[gpui::test]
@@ -8494,25 +8465,27 @@ mod tests {
let mut cx = EditorTestContext::new(cx).await;
cx.set_state(indoc! {"
- on|e two three
- fou[r} five six
- seven {eight nine
- ]ten"});
+ onˇe two three
+ fou«rˇ» five six
+ seven «ˇeight nine
+ »ten
+ "});
cx.update_editor(|e, cx| e.delete(&Delete, cx));
cx.assert_editor_state(indoc! {"
- on| two three
- fou| five six
- seven |ten"});
+ onˇ two three
+ fouˇ five six
+ seven ˇten
+ "});
// Test backspace with line_mode set to true
cx.update_editor(|e, _| e.selections.line_mode = true);
cx.set_state(indoc! {"
- The |quick |brown
- fox {jum]ps over
+ The ˇquick ˇbrown
+ fox «ˇjum»ps over
the lazy dog
- |The qu[ick b}rown"});
+ ˇThe qu«ick bˇ»rown"});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
- cx.assert_editor_state("|the lazy dog|");
+ cx.assert_editor_state("ˇthe lazy dogˇ");
}
#[gpui::test]
@@ -8824,19 +8797,19 @@ mod tests {
async fn test_clipboard(cx: &mut gpui::TestAppContext) {
let mut cx = EditorTestContext::new(cx).await;
- cx.set_state("[one✅ }two [three }four [five }six ");
+ cx.set_state("«one✅ ˇ»two «three ˇ»four «five ˇ»six ");
cx.update_editor(|e, cx| e.cut(&Cut, cx));
- cx.assert_editor_state("|two |four |six ");
+ cx.assert_editor_state("ˇtwo ˇfour ˇsix ");
// Paste with three cursors. Each cursor pastes one slice of the clipboard text.
- cx.set_state("two |four |six |");
+ cx.set_state("two ˇfour ˇsix ˇ");
cx.update_editor(|e, cx| e.paste(&Paste, cx));
- cx.assert_editor_state("two one✅ |four three |six five |");
+ cx.assert_editor_state("two one✅ ˇfour three ˇsix five ˇ");
// Paste again but with only two cursors. Since the number of cursors doesn't
// match the number of slices in the clipboard, the entire clipboard text
// is pasted at each cursor.
- cx.set_state("|two one✅ four three six five |");
+ cx.set_state("ˇtwo one✅ four three six five ˇ");
cx.update_editor(|e, cx| {
e.handle_input("( ", cx);
e.paste(&Paste, cx);
@@ -8845,37 +8818,37 @@ mod tests {
cx.assert_editor_state(indoc! {"
( one✅
three
- five ) |two one✅ four three six five ( one✅
+ five ) ˇtwo one✅ four three six five ( one✅
three
- five ) |"});
+ five ) ˇ"});
// Cut with three selections, one of which is full-line.
cx.set_state(indoc! {"
- 1[2}3
- 4|567
- [8}9"});
+ 1«2ˇ»3
+ 4ˇ567
+ «8ˇ»9"});
cx.update_editor(|e, cx| e.cut(&Cut, cx));
cx.assert_editor_state(indoc! {"
- 1|3
- |9"});
+ 1ˇ3
+ ˇ9"});
// Paste with three selections, noticing how the copied selection that was full-line
// gets inserted before the second cursor.
cx.set_state(indoc! {"
- 1|3
- 9|
- [o}ne"});
+ 1ˇ3
+ 9ˇ
+ «oˇ»ne"});
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- 12|3
+ 12ˇ3
4567
- 9|
- 8|ne"});
+ 9ˇ
+ 8ˇne"});
// Copy with a single cursor only, which writes the whole line into the clipboard.
cx.set_state(indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"});
cx.update_editor(|e, cx| e.copy(&Copy, cx));
cx.cx.assert_clipboard_content(Some("fox jumps over\n"));
@@ -8883,17 +8856,17 @@ mod tests {
// Paste with three selections, noticing how the copied full-line selection is inserted
// before the empty selections but replaces the selection that is non-empty.
cx.set_state(indoc! {"
- T|he quick brown
- [fo}x jumps over
- t|he lazy dog"});
+ Tˇhe quick brown
+ «foˇ»x jumps over
+ tˇhe lazy dog"});
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
fox jumps over
- T|he quick brown
+ Tˇhe quick brown
fox jumps over
- |x jumps over
+ ˇx jumps over
fox jumps over
- t|he lazy dog"});
+ tˇhe lazy dog"});
}
#[gpui::test]
@@ -8909,17 +8882,17 @@ mod tests {
cx.set_state(indoc! {"
const a: B = (
c(),
- [d(
+ «d(
e,
f
- )}
+ )ˇ»
);
"});
cx.update_editor(|e, cx| e.cut(&Cut, cx));
cx.assert_editor_state(indoc! {"
const a: B = (
c(),
- |
+ ˇ
);
"});
@@ -8931,13 +8904,13 @@ mod tests {
d(
e,
f
- )|
+ )ˇ
);
"});
// Paste it at a line with a lower indent level.
cx.set_state(indoc! {"
- |
+ ˇ
const a: B = (
c(),
);
@@ -8947,7 +8920,7 @@ mod tests {
d(
e,
f
- )|
+ )ˇ
const a: B = (
c(),
);
@@ -8957,17 +8930,17 @@ mod tests {
cx.set_state(indoc! {"
const a: B = (
c(),
- [ d(
+ « d(
e,
f
)
- });
+ ˇ»);
"});
cx.update_editor(|e, cx| e.cut(&Cut, cx));
cx.assert_editor_state(indoc! {"
const a: B = (
c(),
- |);
+ ˇ);
"});
// Paste it at the same position.
@@ -8979,7 +8952,7 @@ mod tests {
e,
f
)
- |);
+ ˇ);
"});
// Paste it at a line with a higher indent level.
@@ -8988,7 +8961,7 @@ mod tests {
c(),
d(
e,
- f|
+ fˇ
)
);
"});
@@ -9002,7 +8975,7 @@ mod tests {
e,
f
)
- |
+ ˇ
)
);
"});
@@ -9326,55 +9299,27 @@ mod tests {
}
#[gpui::test]
- fn test_select_next(cx: &mut gpui::MutableAppContext) {
- cx.set_global(Settings::test(cx));
+ async fn test_select_next(cx: &mut gpui::TestAppContext) {
+ let mut cx = EditorTestContext::new(cx).await;
+ cx.set_state("abc\nˇabc abc\ndefabc\nabc");
- let (text, ranges) = marked_text_ranges("[abc]\n[abc] [abc]\ndefabc\n[abc]");
- let buffer = MultiBuffer::build_simple(&text, cx);
- let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
+ cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx));
+ cx.assert_editor_state("abc\n«abcˇ» abc\ndefabc\nabc");
- view.update(cx, |view, cx| {
- view.change_selections(None, cx, |s| {
- s.select_ranges([ranges[1].start + 1..ranges[1].start + 1])
- });
- view.select_next(
- &SelectNext {
- replace_newest: false,
- },
- cx,
- );
- assert_eq!(view.selections.ranges(cx), &ranges[1..2]);
+ cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx));
+ cx.assert_editor_state("abc\n«abcˇ» «abcˇ»\ndefabc\nabc");
- view.select_next(
- &SelectNext {
- replace_newest: false,
- },
- cx,
- );
- assert_eq!(view.selections.ranges(cx), &ranges[1..3]);
+ cx.update_editor(|view, cx| view.undo_selection(&UndoSelection, cx));
+ cx.assert_editor_state("abc\n«abcˇ» abc\ndefabc\nabc");
- view.undo_selection(&UndoSelection, cx);
- assert_eq!(view.selections.ranges(cx), &ranges[1..2]);
+ cx.update_editor(|view, cx| view.redo_selection(&RedoSelection, cx));
+ cx.assert_editor_state("abc\n«abcˇ» «abcˇ»\ndefabc\nabc");
- view.redo_selection(&RedoSelection, cx);
- assert_eq!(view.selections.ranges(cx), &ranges[1..3]);
+ cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx));
+ cx.assert_editor_state("abc\n«abcˇ» «abcˇ»\ndefabc\n«abcˇ»");
- view.select_next(
- &SelectNext {
- replace_newest: false,
- },
- cx,
- );
- assert_eq!(view.selections.ranges(cx), &ranges[1..4]);
-
- view.select_next(
- &SelectNext {
- replace_newest: false,
- },
- cx,
- );
- assert_eq!(view.selections.ranges(cx), &ranges[0..4]);
- });
+ cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx));
+ cx.assert_editor_state("«abcˇ»\n«abcˇ» «abcˇ»\ndefabc\n«abcˇ»");
}
#[gpui::test]
@@ -9952,10 +9897,15 @@ mod tests {
async fn test_snippets(cx: &mut gpui::TestAppContext) {
cx.update(|cx| cx.set_global(Settings::test(cx)));
- let (text, insertion_ranges) = marked_text_ranges(indoc! {"
- a.| b
- a.| b
- a.| b"});
+ let (text, insertion_ranges) = marked_text_ranges(
+ indoc! {"
+ a.ˇ b
+ a.ˇ b
+ a.ˇ b
+ "},
+ false,
+ );
+
let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx));
let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
@@ -9966,23 +9916,20 @@ mod tests {
.insert_snippet(&insertion_ranges, snippet, cx)
.unwrap();
- fn assert(editor: &mut Editor, cx: &mut ViewContext, marked_text_ranges: &str) {
- let range_markers = ('<', '>');
- let (expected_text, mut selection_ranges_lookup) =
- marked_text_ranges_by(marked_text_ranges, vec![range_markers.clone().into()]);
- let selection_ranges = selection_ranges_lookup
- .remove(&range_markers.into())
- .unwrap();
+ fn assert(editor: &mut Editor, cx: &mut ViewContext, marked_text: &str) {
+ let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false);
assert_eq!(editor.text(cx), expected_text);
assert_eq!(editor.selections.ranges::(cx), selection_ranges);
}
+
assert(
editor,
cx,
indoc! {"
- a.f(, two, ) b
- a.f(, two, ) b
- a.f(, two, ) b"},
+ a.f(«one», two, «three») b
+ a.f(«one», two, «three») b
+ a.f(«one», two, «three») b
+ "},
);
// Can't move earlier than the first tab stop
@@ -9991,9 +9938,10 @@ mod tests {
editor,
cx,
indoc! {"
- a.f(, two, ) b
- a.f(, two, ) b
- a.f(, two, ) b"},
+ a.f(«one», two, «three») b
+ a.f(«one», two, «three») b
+ a.f(«one», two, «three») b
+ "},
);
assert!(editor.move_to_next_snippet_tabstop(cx));
@@ -10001,9 +9949,10 @@ mod tests {
editor,
cx,
indoc! {"
- a.f(one, , three) b
- a.f(one, , three) b
- a.f(one, , three) b"},
+ a.f(one, «two», three) b
+ a.f(one, «two», three) b
+ a.f(one, «two», three) b
+ "},
);
editor.move_to_prev_snippet_tabstop(cx);
@@ -10011,9 +9960,10 @@ mod tests {
editor,
cx,
indoc! {"
- a.f(, two, ) b
- a.f(, two, ) b
- a.f(, two, ) b"},
+ a.f(«one», two, «three») b
+ a.f(«one», two, «three») b
+ a.f(«one», two, «three») b
+ "},
);
assert!(editor.move_to_next_snippet_tabstop(cx));
@@ -10021,18 +9971,20 @@ mod tests {
editor,
cx,
indoc! {"
- a.f(one, , three) b
- a.f(one, , three) b
- a.f(one, , three) b"},
+ a.f(one, «two», three) b
+ a.f(one, «two», three) b
+ a.f(one, «two», three) b
+ "},
);
assert!(editor.move_to_next_snippet_tabstop(cx));
assert(
editor,
cx,
indoc! {"
- a.f(one, two, three)<> b
- a.f(one, two, three)<> b
- a.f(one, two, three)<> b"},
+ a.f(one, two, three)ˇ b
+ a.f(one, two, three)ˇ b
+ a.f(one, two, three)ˇ b
+ "},
);
// As soon as the last tab stop is reached, snippet state is gone
@@ -10041,9 +9993,10 @@ mod tests {
editor,
cx,
indoc! {"
- a.f(one, two, three)<> b
- a.f(one, two, three)<> b
- a.f(one, two, three)<> b"},
+ a.f(one, two, three)ˇ b
+ a.f(one, two, three)ˇ b
+ a.f(one, two, three)ˇ b
+ "},
);
});
}
@@ -10293,16 +10246,18 @@ mod tests {
.await;
cx.set_state(indoc! {"
- one|
+ oneˇ
two
- three"});
+ three
+ "});
cx.simulate_keystroke(".");
handle_completion_request(
&mut cx,
indoc! {"
one.|<>
two
- three"},
+ three
+ "},
vec!["first_completion", "second_completion"],
)
.await;
@@ -10315,9 +10270,10 @@ mod tests {
.unwrap()
});
cx.assert_editor_state(indoc! {"
- one.second_completion|
+ one.second_completionˇ
two
- three"});
+ three
+ "});
handle_resolve_completion_request(
&mut cx,
@@ -10325,23 +10281,26 @@ mod tests {
indoc! {"
one.second_completion
two
- three<>"},
+ threeˇ
+ "},
"\nadditional edit",
)),
)
.await;
apply_additional_edits.await.unwrap();
cx.assert_editor_state(indoc! {"
- one.second_completion|
+ one.second_completionˇ
two
three
- additional edit"});
+ additional edit
+ "});
cx.set_state(indoc! {"
one.second_completion
- two|
- three|
- additional edit"});
+ twoˇ
+ threeˇ
+ additional edit
+ "});
cx.simulate_keystroke(" ");
assert!(cx.editor(|e, _| e.context_menu.is_none()));
cx.simulate_keystroke("s");
@@ -10349,16 +10308,19 @@ mod tests {
cx.assert_editor_state(indoc! {"
one.second_completion
- two s|
- three s|
- additional edit"});
+ two sˇ
+ three sˇ
+ additional edit
+ "});
+ //
handle_completion_request(
&mut cx,
indoc! {"
one.second_completion
two s
three
- additional edit"},
+ additional edit
+ "},
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
)
.await;
@@ -10373,7 +10335,8 @@ mod tests {
one.second_completion
two si
three
- additional edit"},
+ additional edit
+ "},
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
)
.await;
@@ -10387,9 +10350,10 @@ mod tests {
});
cx.assert_editor_state(indoc! {"
one.second_completion
- two sixth_completion|
- three sixth_completion|
- additional edit"});
+ two sixth_completionˇ
+ three sixth_completionˇ
+ additional edit
+ "});
handle_resolve_completion_request(&mut cx, None).await;
apply_additional_edits.await.unwrap();
@@ -10399,13 +10363,13 @@ mod tests {
settings.show_completions_on_input = false;
})
});
- cx.set_state("editor|");
+ cx.set_state("editorˇ");
cx.simulate_keystroke(".");
assert!(cx.editor(|e, _| e.context_menu.is_none()));
cx.simulate_keystroke("c");
cx.simulate_keystroke("l");
cx.simulate_keystroke("o");
- cx.assert_editor_state("editor.clo|");
+ cx.assert_editor_state("editor.cloˇ");
assert!(cx.editor(|e, _| e.context_menu.is_none()));
cx.update_editor(|editor, cx| {
editor.show_completions(&ShowCompletions, cx);
@@ -10418,7 +10382,7 @@ mod tests {
.confirm_completion(&ConfirmCompletion::default(), cx)
.unwrap()
});
- cx.assert_editor_state("editor.close|");
+ cx.assert_editor_state("editor.closeˇ");
handle_resolve_completion_request(&mut cx, None).await;
apply_additional_edits.await.unwrap();
@@ -10474,13 +10438,8 @@ mod tests {
edit: Option<(&'static str, &'static str)>,
) {
let edit = edit.map(|(marked_string, new_text)| {
- let replace_range_marker: TextRangeMarker = ('<', '>').into();
- let (_, mut marked_ranges) =
- marked_text_ranges_by(marked_string, vec![replace_range_marker.clone()]);
-
- let replace_range = cx
- .to_lsp_range(marked_ranges.remove(&replace_range_marker).unwrap()[0].clone());
-
+ let (_, marked_ranges) = marked_text_ranges(marked_string, false);
+ let replace_range = cx.to_lsp_range(marked_ranges[0].clone());
vec![lsp::TextEdit::new(replace_range, new_text.to_string())]
});
@@ -10631,13 +10590,21 @@ mod tests {
#[gpui::test]
fn test_editing_overlapping_excerpts(cx: &mut gpui::MutableAppContext) {
cx.set_global(Settings::test(cx));
- let (initial_text, excerpt_ranges) = marked_text_ranges(indoc! {"
+ let markers = vec![('[', ']').into(), ('(', ')').into()];
+ let (initial_text, mut excerpt_ranges) = marked_text_ranges_by(
+ indoc! {"
[aaaa
(bbbb]
- cccc)"});
- let excerpt_ranges = excerpt_ranges.into_iter().map(|context| ExcerptRange {
- context,
- primary: None,
+ cccc)",
+ },
+ markers.clone(),
+ );
+ let excerpt_ranges = markers.into_iter().map(|marker| {
+ let context = excerpt_ranges.remove(&marker).unwrap()[0].clone();
+ ExcerptRange {
+ context,
+ primary: None,
+ }
});
let buffer = cx.add_model(|cx| Buffer::new(0, initial_text, cx));
let multibuffer = cx.add_model(|cx| {
@@ -10648,34 +10615,46 @@ mod tests {
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx));
view.update(cx, |view, cx| {
- let (expected_text, selection_ranges) = marked_text_ranges(indoc! {"
- aaaa
- b|bbb
- b|bb|b
- cccc"});
+ let (expected_text, selection_ranges) = marked_text_ranges(
+ indoc! {"
+ aaaa
+ bˇbbb
+ bˇbbˇb
+ cccc"
+ },
+ true,
+ );
assert_eq!(view.text(cx), expected_text);
view.change_selections(None, cx, |s| s.select_ranges(selection_ranges));
view.handle_input("X", cx);
- let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
- aaaa
- bX|bbXb
- bX|bbX|b
- cccc"});
+ let (expected_text, expected_selections) = marked_text_ranges(
+ indoc! {"
+ aaaa
+ bXˇbbXb
+ bXˇbbXˇb
+ cccc"
+ },
+ false,
+ );
assert_eq!(view.text(cx), expected_text);
assert_eq!(view.selections.ranges(cx), expected_selections);
view.newline(&Newline, cx);
- let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
- aaaa
- bX
- |bbX
- b
- bX
- |bbX
- |b
- cccc"});
+ let (expected_text, expected_selections) = marked_text_ranges(
+ indoc! {"
+ aaaa
+ bX
+ ˇbbX
+ b
+ bX
+ ˇbbX
+ ˇb
+ cccc"
+ },
+ false,
+ );
assert_eq!(view.text(cx), expected_text);
assert_eq!(view.selections.ranges(cx), expected_selections);
});
@@ -11152,30 +11131,12 @@ mod tests {
point..point
}
- fn assert_selection_ranges(
- marked_text: &str,
- selection_marker_pairs: Vec<(char, char)>,
- view: &mut Editor,
- cx: &mut ViewContext,
- ) {
- let snapshot = view.snapshot(cx).display_snapshot;
- let mut marker_chars = Vec::new();
- for (start, end) in selection_marker_pairs.iter() {
- marker_chars.push(*start);
- marker_chars.push(*end);
- }
- let (_, markers) = marked_text_by(marked_text, marker_chars);
- let asserted_ranges: Vec> = selection_marker_pairs
- .iter()
- .map(|(start, end)| {
- let start = markers.get(start).unwrap()[0].to_display_point(&snapshot);
- let end = markers.get(end).unwrap()[0].to_display_point(&snapshot);
- start..end
- })
- .collect();
+ fn assert_selection_ranges(marked_text: &str, view: &mut Editor, cx: &mut ViewContext) {
+ let (text, ranges) = marked_text_ranges(marked_text, true);
+ assert_eq!(view.text(cx), text);
assert_eq!(
- view.selections.display_ranges(cx),
- &asserted_ranges[..],
+ view.selections.ranges(cx),
+ ranges,
"Assert selections are {}",
marked_text
);
diff --git a/crates/editor/src/highlight_matching_bracket.rs b/crates/editor/src/highlight_matching_bracket.rs
index 30bf1091f2..789393d70b 100644
--- a/crates/editor/src/highlight_matching_bracket.rs
+++ b/crates/editor/src/highlight_matching_bracket.rs
@@ -32,13 +32,10 @@ pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewCon
#[cfg(test)]
mod tests {
- use indoc::indoc;
-
- use language::{BracketPair, Language, LanguageConfig};
-
- use crate::test::EditorLspTestContext;
-
use super::*;
+ use crate::test::EditorLspTestContext;
+ use indoc::indoc;
+ use language::{BracketPair, Language, LanguageConfig};
#[gpui::test]
async fn test_matching_bracket_highlights(cx: &mut gpui::TestAppContext) {
@@ -76,67 +73,61 @@ mod tests {
.await;
// positioning cursor inside bracket highlights both
- cx.set_state_by(
- vec!['|'.into()],
- indoc! {r#"
- pub fn test("Test |argument") {
- another_test(1, 2, 3);
- }"#},
- );
+ cx.set_state(indoc! {r#"
+ pub fn test("Test ˇargument") {
+ another_test(1, 2, 3);
+ }
+ "#});
cx.assert_editor_background_highlights::(indoc! {r#"
- pub fn test[(]"Test argument"[)] {
- another_test(1, 2, 3);
- }"#});
+ pub fn test«(»"Test argument"«)» {
+ another_test(1, 2, 3);
+ }
+ "#});
- cx.set_state_by(
- vec!['|'.into()],
- indoc! {r#"
- pub fn test("Test argument") {
- another_test(1, |2, 3);
- }"#},
- );
+ cx.set_state(indoc! {r#"
+ pub fn test("Test argument") {
+ another_test(1, ˇ2, 3);
+ }
+ "#});
cx.assert_editor_background_highlights::(indoc! {r#"
pub fn test("Test argument") {
- another_test[(]1, 2, 3[)];
- }"#});
+ another_test«(»1, 2, 3«)»;
+ }
+ "#});
- cx.set_state_by(
- vec!['|'.into()],
- indoc! {r#"
- pub fn test("Test argument") {
- another|_test(1, 2, 3);
- }"#},
- );
+ cx.set_state(indoc! {r#"
+ pub fn test("Test argument") {
+ anotherˇ_test(1, 2, 3);
+ }
+ "#});
cx.assert_editor_background_highlights::(indoc! {r#"
- pub fn test("Test argument") [{]
+ pub fn test("Test argument") «{»
another_test(1, 2, 3);
- [}]"#});
+ «}»
+ "#});
// positioning outside of brackets removes highlight
- cx.set_state_by(
- vec!['|'.into()],
- indoc! {r#"
- pub f|n test("Test argument") {
- another_test(1, 2, 3);
- }"#},
- );
+ cx.set_state(indoc! {r#"
+ pub fˇn test("Test argument") {
+ another_test(1, 2, 3);
+ }
+ "#});
cx.assert_editor_background_highlights::(indoc! {r#"
pub fn test("Test argument") {
another_test(1, 2, 3);
- }"#});
+ }
+ "#});
// non empty selection dismisses highlight
- // positioning outside of brackets removes highlight
- cx.set_state_by(
- vec![('<', '>').into()],
- indoc! {r#"
- pub fn test("Teument") {
- another_test(1, 2, 3);
- }"#},
- );
+ cx.set_state(indoc! {r#"
+ pub fn test("Te«st argˇ»ument") {
+ another_test(1, 2, 3);
+ }
+ "#});
cx.assert_editor_background_highlights::(indoc! {r#"
pub fn test("Test argument") {
another_test(1, 2, 3);
- }"#});
+ }
+ "#});
}
}
diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs
index 99669cb15d..37a2a66e05 100644
--- a/crates/editor/src/hover_popover.rs
+++ b/crates/editor/src/hover_popover.rs
@@ -439,11 +439,11 @@ mod tests {
// Basic hover delays and then pops without moving the mouse
cx.set_state(indoc! {"
- fn |test()
- println!();"});
+ fn ˇtest() { println!(); }
+ "});
let hover_point = cx.display_point(indoc! {"
- fn test()
- print|ln!();"});
+ fn test() { printˇln!(); }
+ "});
cx.update_editor(|editor, cx| {
hover_at(
@@ -458,16 +458,16 @@ mod tests {
// After delay, hover should be visible.
let symbol_range = cx.lsp_range(indoc! {"
- fn test()
- [println!]();"});
+ fn test() { «println!»(); }
+ "});
let mut requests =
cx.handle_request::(move |_, _, _| async move {
Ok(Some(lsp::Hover {
contents: lsp::HoverContents::Markup(lsp::MarkupContent {
kind: lsp::MarkupKind::Markdown,
value: indoc! {"
- # Some basic docs
- Some test documentation"}
+ # Some basic docs
+ Some test documentation"}
.to_string(),
}),
range: Some(symbol_range),
@@ -496,8 +496,8 @@ mod tests {
// Mouse moved with no hover response dismisses
let hover_point = cx.display_point(indoc! {"
- fn te|st()
- println!();"});
+ fn teˇst() { println!(); }
+ "});
let mut request = cx
.lsp
.handle_request::(|_, _| async move { Ok(None) });
@@ -531,12 +531,12 @@ mod tests {
// Hover with keyboard has no delay
cx.set_state(indoc! {"
- f|n test()
- println!();"});
+ fˇn test() { println!(); }
+ "});
cx.update_editor(|editor, cx| hover(editor, &Hover, cx));
let symbol_range = cx.lsp_range(indoc! {"
- [fn] test()
- println!();"});
+ «fn» test() { println!(); }
+ "});
cx.handle_request::(move |_, _, _| async move {
Ok(Some(lsp::Hover {
contents: lsp::HoverContents::Markup(lsp::MarkupContent {
@@ -584,13 +584,13 @@ mod tests {
// Hover with just diagnostic, pops DiagnosticPopover immediately and then
// info popover once request completes
cx.set_state(indoc! {"
- fn te|st()
- println!();"});
+ fn teˇst() { println!(); }
+ "});
// Send diagnostic to client
let range = cx.text_anchor_range(indoc! {"
- fn [test]()
- println!();"});
+ fn «test»() { println!(); }
+ "});
cx.update_buffer(|buffer, cx| {
let snapshot = buffer.text_snapshot();
let set = DiagnosticSet::from_sorted_entries(
@@ -616,15 +616,15 @@ mod tests {
// Info Popover shows after request responded to
let range = cx.lsp_range(indoc! {"
- fn [test]()
- println!();"});
+ fn «test»() { println!(); }
+ "});
cx.handle_request::(move |_, _, _| async move {
Ok(Some(lsp::Hover {
contents: lsp::HoverContents::Markup(lsp::MarkupContent {
kind: lsp::MarkupKind::Markdown,
value: indoc! {"
- # Some other basic docs
- Some other test documentation"}
+ # Some other basic docs
+ Some other test documentation"}
.to_string(),
}),
range: Some(range),
diff --git a/crates/editor/src/link_go_to_definition.rs b/crates/editor/src/link_go_to_definition.rs
index b57179c07d..cc4592b6d4 100644
--- a/crates/editor/src/link_go_to_definition.rs
+++ b/crates/editor/src/link_go_to_definition.rs
@@ -405,20 +405,20 @@ mod tests {
cx.set_state(indoc! {"
struct A;
- let v|ariable = A;
+ let vˇariable = A;
"});
// Basic hold cmd+shift, expect highlight in region if response contains type definition
let hover_point = cx.display_point(indoc! {"
struct A;
- let v|ariable = A;
+ let vˇariable = A;
"});
let symbol_range = cx.lsp_range(indoc! {"
struct A;
- let [variable] = A;
+ let «variable» = A;
"});
let target_range = cx.lsp_range(indoc! {"
- struct [A];
+ struct «A»;
let variable = A;
"});
@@ -450,7 +450,7 @@ mod tests {
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::(indoc! {"
struct A;
- let [variable] = A;
+ let «variable» = A;
"});
// Unpress shift causes highlight to go away (normal goto-definition is not valid here)
@@ -473,10 +473,10 @@ mod tests {
// Cmd+shift click without existing definition requests and jumps
let hover_point = cx.display_point(indoc! {"
struct A;
- let v|ariable = A;
+ let vˇariable = A;
"});
let target_range = cx.lsp_range(indoc! {"
- struct [A];
+ struct «A»;
let variable = A;
"});
@@ -503,7 +503,7 @@ mod tests {
cx.foreground().run_until_parked();
cx.assert_editor_state(indoc! {"
- struct [A};
+ struct «Aˇ»;
let variable = A;
"});
}
@@ -520,34 +520,22 @@ mod tests {
.await;
cx.set_state(indoc! {"
- fn |test()
- do_work();
-
- fn do_work()
- test();
+ fn ˇtest() { do_work(); }
+ fn do_work() { test(); }
"});
// Basic hold cmd, expect highlight in region if response contains definition
let hover_point = cx.display_point(indoc! {"
- fn test()
- do_w|ork();
-
- fn do_work()
- test();
+ fn test() { do_wˇork(); }
+ fn do_work() { test(); }
"});
let symbol_range = cx.lsp_range(indoc! {"
- fn test()
- [do_work]();
-
- fn do_work()
- test();
+ fn test() { «do_work»(); }
+ fn do_work() { test(); }
"});
let target_range = cx.lsp_range(indoc! {"
- fn test()
- do_work();
-
- fn [do_work]()
- test();
+ fn test() { do_work(); }
+ fn «do_work»() { test(); }
"});
let mut requests = cx.handle_request::(move |url, _, _| async move {
@@ -575,11 +563,8 @@ mod tests {
requests.next().await;
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- [do_work]();
-
- fn do_work()
- test();
+ fn test() { «do_work»(); }
+ fn do_work() { test(); }
"});
// Unpress cmd causes highlight to go away
@@ -593,13 +578,11 @@ mod tests {
cx,
);
});
+
// Assert no link highlights
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- test();
+ fn test() { do_work(); }
+ fn do_work() { test(); }
"});
// Response without source range still highlights word
@@ -630,20 +613,14 @@ mod tests {
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- [do_work]();
-
- fn do_work()
- test();
+ fn test() { «do_work»(); }
+ fn do_work() { test(); }
"});
// Moving mouse to location with no response dismisses highlight
let hover_point = cx.display_point(indoc! {"
- f|n test()
- do_work();
-
- fn do_work()
- test();
+ fˇn test() { do_work(); }
+ fn do_work() { test(); }
"});
let mut requests = cx
.lsp
@@ -667,20 +644,14 @@ mod tests {
// Assert no link highlights
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- test();
+ fn test() { do_work(); }
+ fn do_work() { test(); }
"});
// Move mouse without cmd and then pressing cmd triggers highlight
let hover_point = cx.display_point(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- te|st();
+ fn test() { do_work(); }
+ fn do_work() { teˇst(); }
"});
cx.update_editor(|editor, cx| {
update_go_to_definition_link(
@@ -697,26 +668,17 @@ mod tests {
// Assert no link highlights
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- test();
+ fn test() { do_work(); }
+ fn do_work() { test(); }
"});
let symbol_range = cx.lsp_range(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- [test]();
+ fn test() { do_work(); }
+ fn do_work() { «test»(); }
"});
let target_range = cx.lsp_range(indoc! {"
- fn [test]()
- do_work();
-
- fn do_work()
- test();
+ fn «test»() { do_work(); }
+ fn do_work() { test(); }
"});
let mut requests = cx.handle_request::(move |url, _, _| async move {
@@ -743,20 +705,14 @@ mod tests {
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- [test]();
+ fn test() { do_work(); }
+ fn do_work() { «test»(); }
"});
// Moving within symbol range doesn't re-request
let hover_point = cx.display_point(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- tes|t();
+ fn test() { do_work(); }
+ fn do_work() { tesˇt(); }
"});
cx.update_editor(|editor, cx| {
update_go_to_definition_link(
@@ -771,11 +727,8 @@ mod tests {
});
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- [test]();
+ fn test() { do_work(); }
+ fn do_work() { «test»(); }
"});
// Cmd click with existing definition doesn't re-request and dismisses highlight
@@ -790,35 +743,24 @@ mod tests {
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
});
cx.assert_editor_state(indoc! {"
- fn [test}()
- do_work();
-
- fn do_work()
- test();
+ fn «testˇ»() { do_work(); }
+ fn do_work() { test(); }
"});
+
// Assert no link highlights after jump
cx.assert_editor_text_highlights::(indoc! {"
- fn test()
- do_work();
-
- fn do_work()
- test();
+ fn test() { do_work(); }
+ fn do_work() { test(); }
"});
// Cmd click without existing definition requests and jumps
let hover_point = cx.display_point(indoc! {"
- fn test()
- do_w|ork();
-
- fn do_work()
- test();
+ fn test() { do_wˇork(); }
+ fn do_work() { test(); }
"});
let target_range = cx.lsp_range(indoc! {"
- fn test()
- do_work();
-
- fn [do_work]()
- test();
+ fn test() { do_work(); }
+ fn «do_work»() { test(); }
"});
let mut requests = cx.handle_request::(move |url, _, _| async move {
@@ -836,13 +778,9 @@ mod tests {
});
requests.next().await;
cx.foreground().run_until_parked();
-
cx.assert_editor_state(indoc! {"
- fn test()
- do_work();
-
- fn [do_work}()
- test();
+ fn test() { do_work(); }
+ fn «do_workˇ»() { test(); }
"});
}
}
diff --git a/crates/editor/src/mouse_context_menu.rs b/crates/editor/src/mouse_context_menu.rs
index 513a9ed99c..3098e96e07 100644
--- a/crates/editor/src/mouse_context_menu.rs
+++ b/crates/editor/src/mouse_context_menu.rs
@@ -67,11 +67,9 @@ pub fn deploy_context_menu(
#[cfg(test)]
mod tests {
- use indoc::indoc;
-
- use crate::test::EditorLspTestContext;
-
use super::*;
+ use crate::test::EditorLspTestContext;
+ use indoc::indoc;
#[gpui::test]
async fn test_mouse_context_menu(cx: &mut gpui::TestAppContext) {
@@ -85,11 +83,15 @@ mod tests {
.await;
cx.set_state(indoc! {"
- fn te|st()
- do_work();"});
+ fn teˇst() {
+ do_work();
+ }
+ "});
let point = cx.display_point(indoc! {"
- fn test()
- do_w|ork();"});
+ fn test() {
+ do_wˇork();
+ }
+ "});
cx.update_editor(|editor, cx| {
deploy_context_menu(
editor,
@@ -102,8 +104,10 @@ mod tests {
});
cx.assert_editor_state(indoc! {"
- fn test()
- do_w|ork();"});
+ fn test() {
+ do_wˇork();
+ }
+ "});
cx.editor(|editor, app| assert!(editor.mouse_context_menu.read(app).visible()));
}
}
diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs
index 656473dbe8..0db5cc0812 100644
--- a/crates/editor/src/movement.rs
+++ b/crates/editor/src/movement.rs
@@ -287,20 +287,20 @@ mod tests {
);
}
- assert("\n| |lorem", cx);
- assert("|\n| lorem", cx);
- assert(" |lorem|", cx);
- assert("| |lorem", cx);
- assert(" |lor|em", cx);
- assert("\nlorem\n| |ipsum", cx);
- assert("\n\n|\n|", cx);
- assert(" |lorem |ipsum", cx);
- assert("lorem|-|ipsum", cx);
- assert("lorem|-#$@|ipsum", cx);
- assert("|lorem_|ipsum", cx);
- assert(" |defγ|", cx);
- assert(" |bcΔ|", cx);
- assert(" ab|——|cd", cx);
+ assert("\nˇ ˇlorem", cx);
+ assert("ˇ\nˇ lorem", cx);
+ assert(" ˇloremˇ", cx);
+ assert("ˇ ˇlorem", cx);
+ assert(" ˇlorˇem", cx);
+ assert("\nlorem\nˇ ˇipsum", cx);
+ assert("\n\nˇ\nˇ", cx);
+ assert(" ˇlorem ˇipsum", cx);
+ assert("loremˇ-ˇipsum", cx);
+ assert("loremˇ-#$@ˇipsum", cx);
+ assert("ˇlorem_ˇipsum", cx);
+ assert(" ˇdefγˇ", cx);
+ assert(" ˇbcΔˇ", cx);
+ assert(" abˇ——ˇcd", cx);
}
#[gpui::test]
@@ -315,26 +315,26 @@ mod tests {
}
// Subword boundaries are respected
- assert("lorem_|ip|sum", cx);
- assert("lorem_|ipsum|", cx);
- assert("|lorem_|ipsum", cx);
- assert("lorem_|ipsum_|dolor", cx);
- assert("lorem|Ip|sum", cx);
- assert("lorem|Ipsum|", cx);
+ assert("lorem_ˇipˇsum", cx);
+ assert("lorem_ˇipsumˇ", cx);
+ assert("ˇlorem_ˇipsum", cx);
+ assert("lorem_ˇipsum_ˇdolor", cx);
+ assert("loremˇIpˇsum", cx);
+ assert("loremˇIpsumˇ", cx);
// Word boundaries are still respected
- assert("\n| |lorem", cx);
- assert(" |lorem|", cx);
- assert(" |lor|em", cx);
- assert("\nlorem\n| |ipsum", cx);
- assert("\n\n|\n|", cx);
- assert(" |lorem |ipsum", cx);
- assert("lorem|-|ipsum", cx);
- assert("lorem|-#$@|ipsum", cx);
- assert(" |defγ|", cx);
- assert(" bc|Δ|", cx);
- assert(" |bcδ|", cx);
- assert(" ab|——|cd", cx);
+ assert("\nˇ ˇlorem", cx);
+ assert(" ˇloremˇ", cx);
+ assert(" ˇlorˇem", cx);
+ assert("\nlorem\nˇ ˇipsum", cx);
+ assert("\n\nˇ\nˇ", cx);
+ assert(" ˇlorem ˇipsum", cx);
+ assert("loremˇ-ˇipsum", cx);
+ assert("loremˇ-#$@ˇipsum", cx);
+ assert(" ˇdefγˇ", cx);
+ assert(" bcˇΔˇ", cx);
+ assert(" ˇbcδˇ", cx);
+ assert(" abˇ——ˇcd", cx);
}
#[gpui::test]
@@ -352,14 +352,14 @@ mod tests {
);
}
- assert("abc|def\ngh\nij|k", cx, |left, right| {
+ assert("abcˇdef\ngh\nijˇk", cx, |left, right| {
left == 'c' && right == 'd'
});
- assert("abcdef\n|gh\nij|k", cx, |left, right| {
+ assert("abcdef\nˇgh\nijˇk", cx, |left, right| {
left == '\n' && right == 'g'
});
let mut line_count = 0;
- assert("abcdef\n|gh\nij|k", cx, |left, _| {
+ assert("abcdef\nˇgh\nijˇk", cx, |left, _| {
if left == '\n' {
line_count += 1;
line_count == 2
@@ -380,17 +380,17 @@ mod tests {
);
}
- assert("\n| lorem|", cx);
- assert(" |lorem|", cx);
- assert(" lor|em|", cx);
- assert(" lorem| |\nipsum\n", cx);
- assert("\n|\n|\n\n", cx);
- assert("lorem| ipsum| ", cx);
- assert("lorem|-|ipsum", cx);
- assert("lorem|#$@-|ipsum", cx);
- assert("lorem|_ipsum|", cx);
- assert(" |bcΔ|", cx);
- assert(" ab|——|cd", cx);
+ assert("\nˇ loremˇ", cx);
+ assert(" ˇloremˇ", cx);
+ assert(" lorˇemˇ", cx);
+ assert(" loremˇ ˇ\nipsum\n", cx);
+ assert("\nˇ\nˇ\n\n", cx);
+ assert("loremˇ ipsumˇ ", cx);
+ assert("loremˇ-ˇipsum", cx);
+ assert("loremˇ#$@-ˇipsum", cx);
+ assert("loremˇ_ipsumˇ", cx);
+ assert(" ˇbcΔˇ", cx);
+ assert(" abˇ——ˇcd", cx);
}
#[gpui::test]
@@ -405,25 +405,25 @@ mod tests {
}
// Subword boundaries are respected
- assert("lo|rem|_ipsum", cx);
- assert("|lorem|_ipsum", cx);
- assert("lorem|_ipsum|", cx);
- assert("lorem|_ipsum|_dolor", cx);
- assert("lo|rem|Ipsum", cx);
- assert("lorem|Ipsum|Dolor", cx);
+ assert("loˇremˇ_ipsum", cx);
+ assert("ˇloremˇ_ipsum", cx);
+ assert("loremˇ_ipsumˇ", cx);
+ assert("loremˇ_ipsumˇ_dolor", cx);
+ assert("loˇremˇIpsum", cx);
+ assert("loremˇIpsumˇDolor", cx);
// Word boundaries are still respected
- assert("\n| lorem|", cx);
- assert(" |lorem|", cx);
- assert(" lor|em|", cx);
- assert(" lorem| |\nipsum\n", cx);
- assert("\n|\n|\n\n", cx);
- assert("lorem| ipsum| ", cx);
- assert("lorem|-|ipsum", cx);
- assert("lorem|#$@-|ipsum", cx);
- assert("lorem|_ipsum|", cx);
- assert(" |bc|Δ", cx);
- assert(" ab|——|cd", cx);
+ assert("\nˇ loremˇ", cx);
+ assert(" ˇloremˇ", cx);
+ assert(" lorˇemˇ", cx);
+ assert(" loremˇ ˇ\nipsum\n", cx);
+ assert("\nˇ\nˇ\n\n", cx);
+ assert("loremˇ ipsumˇ ", cx);
+ assert("loremˇ-ˇipsum", cx);
+ assert("loremˇ#$@-ˇipsum", cx);
+ assert("loremˇ_ipsumˇ", cx);
+ assert(" ˇbcˇΔ", cx);
+ assert(" abˇ——ˇcd", cx);
}
#[gpui::test]
@@ -441,14 +441,14 @@ mod tests {
);
}
- assert("abc|def\ngh\nij|k", cx, |left, right| {
+ assert("abcˇdef\ngh\nijˇk", cx, |left, right| {
left == 'j' && right == 'k'
});
- assert("ab|cdef\ngh\n|ijk", cx, |left, right| {
+ assert("abˇcdef\ngh\nˇijk", cx, |left, right| {
left == '\n' && right == 'i'
});
let mut line_count = 0;
- assert("abc|def\ngh\n|ijk", cx, |left, _| {
+ assert("abcˇdef\ngh\nˇijk", cx, |left, _| {
if left == '\n' {
line_count += 1;
line_count == 2
@@ -469,14 +469,14 @@ mod tests {
);
}
- assert("||lorem| ipsum", cx);
- assert("|lo|rem| ipsum", cx);
- assert("|lorem|| ipsum", cx);
- assert("lorem| | |ipsum", cx);
- assert("lorem\n|||\nipsum", cx);
- assert("lorem\n||ipsum|", cx);
- assert("lorem,|| |ipsum", cx);
- assert("|lorem||, ipsum", cx);
+ assert("ˇˇloremˇ ipsum", cx);
+ assert("ˇloˇremˇ ipsum", cx);
+ assert("ˇloremˇˇ ipsum", cx);
+ assert("loremˇ ˇ ˇipsum", cx);
+ assert("lorem\nˇˇˇ\nipsum", cx);
+ assert("lorem\nˇˇipsumˇ", cx);
+ assert("lorem,ˇˇ ˇipsum", cx);
+ assert("ˇloremˇˇ, ipsum", cx);
}
#[gpui::test]
diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs
index 18c13a4ba6..5f6528db1c 100644
--- a/crates/editor/src/test.rs
+++ b/crates/editor/src/test.rs
@@ -1,34 +1,28 @@
-use std::{
- any::TypeId,
- ops::{Deref, DerefMut, Range},
- sync::Arc,
-};
-
-use anyhow::Result;
-use futures::{Future, StreamExt};
-use indoc::indoc;
-
-use collections::BTreeMap;
-use gpui::{
- json, keymap::Keystroke, AppContext, ModelContext, ModelHandle, ViewContext, ViewHandle,
-};
-use language::{
- point_to_lsp, Buffer, BufferSnapshot, FakeLspAdapter, Language, LanguageConfig, Selection,
-};
-use lsp::{notification, request};
-use project::Project;
-use settings::Settings;
-use util::{
- assert_set_eq, set_eq,
- test::{marked_text, marked_text_ranges, marked_text_ranges_by, SetEqError, TextRangeMarker},
-};
-use workspace::{pane, AppState, Workspace, WorkspaceHandle};
-
use crate::{
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
multi_buffer::ToPointUtf16,
AnchorRangeExt, Autoscroll, DisplayPoint, Editor, EditorMode, MultiBuffer, ToPoint,
};
+use anyhow::Result;
+use futures::{Future, StreamExt};
+use gpui::{
+ json, keymap::Keystroke, AppContext, ModelContext, ModelHandle, ViewContext, ViewHandle,
+};
+use indoc::indoc;
+use language::{point_to_lsp, Buffer, BufferSnapshot, FakeLspAdapter, Language, LanguageConfig};
+use lsp::{notification, request};
+use project::Project;
+use settings::Settings;
+use std::{
+ any::TypeId,
+ ops::{Deref, DerefMut, Range},
+ sync::Arc,
+};
+use util::{
+ assert_set_eq, set_eq,
+ test::{generate_marked_text, marked_text_offsets, marked_text_ranges},
+};
+use workspace::{pane, AppState, Workspace, WorkspaceHandle};
#[cfg(test)]
#[ctor::ctor]
@@ -43,7 +37,7 @@ pub fn marked_display_snapshot(
text: &str,
cx: &mut gpui::MutableAppContext,
) -> (DisplaySnapshot, Vec) {
- let (unmarked_text, markers) = marked_text(text);
+ let (unmarked_text, markers) = marked_text_offsets(text);
let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
let font_id = cx
@@ -65,7 +59,7 @@ pub fn marked_display_snapshot(
}
pub fn select_ranges(editor: &mut Editor, marked_text: &str, cx: &mut ViewContext) {
- let (umarked_text, text_ranges) = marked_text_ranges(marked_text);
+ let (umarked_text, text_ranges) = marked_text_ranges(marked_text, true);
assert_eq!(editor.text(cx), umarked_text);
editor.change_selections(None, cx, |s| s.select_ranges(text_ranges));
}
@@ -75,8 +69,7 @@ pub fn assert_text_with_selections(
marked_text: &str,
cx: &mut ViewContext,
) {
- let (unmarked_text, text_ranges) = marked_text_ranges(marked_text);
-
+ let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
assert_eq!(editor.text(cx), unmarked_text);
assert_eq!(editor.selections.ranges(cx), text_ranges);
}
@@ -190,94 +183,58 @@ impl<'a> EditorTestContext<'a> {
}
}
- pub fn display_point(&mut self, cursor_location: &str) -> DisplayPoint {
- let (_, locations) = marked_text(cursor_location);
+ fn ranges(&self, marked_text: &str) -> Vec> {
+ let (unmarked_text, ranges) = marked_text_ranges(marked_text, false);
+ assert_eq!(self.buffer_text(), unmarked_text);
+ ranges
+ }
+
+ pub fn display_point(&mut self, marked_text: &str) -> DisplayPoint {
+ let ranges = self.ranges(marked_text);
let snapshot = self
.editor
.update(self.cx, |editor, cx| editor.snapshot(cx));
- locations[0].to_display_point(&snapshot.display_snapshot)
+ ranges[0].start.to_display_point(&snapshot)
}
- // Returns anchors for the current buffer using `[`..`]`
+ // Returns anchors for the current buffer using `«` and `»`
pub fn text_anchor_range(&self, marked_text: &str) -> Range {
- let range_marker: TextRangeMarker = ('[', ']').into();
- let (unmarked_text, mut ranges) =
- marked_text_ranges_by(&marked_text, vec![range_marker.clone()]);
- assert_eq!(self.buffer_text(), unmarked_text);
- let offset_range = ranges.remove(&range_marker).unwrap()[0].clone();
+ let ranges = self.ranges(marked_text);
let snapshot = self.buffer_snapshot();
-
- snapshot.anchor_before(offset_range.start)..snapshot.anchor_after(offset_range.end)
+ snapshot.anchor_before(ranges[0].start)..snapshot.anchor_after(ranges[0].end)
}
- // Sets the editor state via a marked string.
- // `|` characters represent empty selections
- // `[` to `}` represents a non empty selection with the head at `}`
- // `{` to `]` represents a non empty selection with the head at `{`
- pub fn set_state(&mut self, text: &str) {
- self.set_state_by(
- vec![
- '|'.into(),
- ('[', '}').into(),
- TextRangeMarker::ReverseRange('{', ']'),
- ],
- text,
- );
- }
-
- pub fn set_state_by(&mut self, range_markers: Vec, text: &str) {
+ /// Change the editor's text and selections using a string containing
+ /// embedded range markers that represent the ranges and directions of
+ /// each selection.
+ ///
+ /// See the `util::test::marked_text_ranges` function for more information.
+ pub fn set_state(&mut self, marked_text: &str) {
+ let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
self.editor.update(self.cx, |editor, cx| {
- let (unmarked_text, selection_ranges) = marked_text_ranges_by(&text, range_markers);
editor.set_text(unmarked_text, cx);
-
- let selection_ranges: Vec> = selection_ranges
- .values()
- .into_iter()
- .flatten()
- .cloned()
- .collect();
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.select_ranges(selection_ranges)
})
})
}
- // Asserts the editor state via a marked string.
- // `|` characters represent empty selections
- // `[` to `}` represents a non empty selection with the head at `}`
- // `{` to `]` represents a non empty selection with the head at `{`
- pub fn assert_editor_state(&mut self, text: &str) {
- let (unmarked_text, mut selection_ranges) = marked_text_ranges_by(
- &text,
- vec!['|'.into(), ('[', '}').into(), ('{', ']').into()],
- );
+ /// Make an assertion about the editor's text and the ranges and directions
+ /// of its selections using a string containing embedded range markers.
+ ///
+ /// See the `util::test::marked_text_ranges` function for more information.
+ pub fn assert_editor_state(&mut self, marked_text: &str) {
+ let (unmarked_text, expected_selections) = marked_text_ranges(marked_text, true);
let buffer_text = self.buffer_text();
assert_eq!(
buffer_text, unmarked_text,
"Unmarked text doesn't match buffer text"
);
-
- let expected_empty_selections = selection_ranges.remove(&'|'.into()).unwrap_or_default();
- let expected_reverse_selections = selection_ranges
- .remove(&('{', ']').into())
- .unwrap_or_default();
- let expected_forward_selections = selection_ranges
- .remove(&('[', '}').into())
- .unwrap_or_default();
-
- self.assert_selections(
- expected_empty_selections,
- expected_reverse_selections,
- expected_forward_selections,
- Some(text.to_string()),
- )
+ self.assert_selections(expected_selections, marked_text.to_string())
}
pub fn assert_editor_background_highlights(&mut self, marked_text: &str) {
- let (unmarked, mut ranges) = marked_text_ranges_by(marked_text, vec![('[', ']').into()]);
- assert_eq!(unmarked, self.buffer_text());
-
- let asserted_ranges = ranges.remove(&('[', ']').into()).unwrap();
+ let expected_ranges = self.ranges(marked_text);
let actual_ranges: Vec> = self.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
editor
@@ -289,176 +246,62 @@ impl<'a> EditorTestContext<'a> {
.map(|range| range.to_offset(&snapshot.buffer_snapshot))
.collect()
});
-
- assert_set_eq!(asserted_ranges, actual_ranges);
+ assert_set_eq!(actual_ranges, expected_ranges);
}
pub fn assert_editor_text_highlights(&mut self, marked_text: &str) {
- let (unmarked, mut ranges) = marked_text_ranges_by(marked_text, vec![('[', ']').into()]);
- assert_eq!(unmarked, self.buffer_text());
-
- let asserted_ranges = ranges.remove(&('[', ']').into()).unwrap();
+ let expected_ranges = self.ranges(marked_text);
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
let actual_ranges: Vec> = snapshot
- .display_snapshot
.highlight_ranges::()
.map(|ranges| ranges.as_ref().clone().1)
.unwrap_or_default()
.into_iter()
.map(|range| range.to_offset(&snapshot.buffer_snapshot))
.collect();
-
- assert_set_eq!(asserted_ranges, actual_ranges);
+ assert_set_eq!(actual_ranges, expected_ranges);
}
- pub fn assert_editor_selections(&mut self, expected_selections: Vec>) {
- let mut empty_selections = Vec::new();
- let mut reverse_selections = Vec::new();
- let mut forward_selections = Vec::new();
-
- for selection in expected_selections {
- let range = selection.range();
- if selection.is_empty() {
- empty_selections.push(range);
- } else if selection.reversed {
- reverse_selections.push(range);
- } else {
- forward_selections.push(range)
- }
- }
-
- self.assert_selections(
- empty_selections,
- reverse_selections,
- forward_selections,
- None,
- )
+ pub fn assert_editor_selections(&mut self, expected_selections: Vec>) {
+ let expected_marked_text =
+ generate_marked_text(&self.buffer_text(), &expected_selections, true);
+ self.assert_selections(expected_selections, expected_marked_text)
}
fn assert_selections(
&mut self,
- expected_empty_selections: Vec>,
- expected_reverse_selections: Vec>,
- expected_forward_selections: Vec>,
- asserted_text: Option,
+ expected_selections: Vec>,
+ expected_marked_text: String,
) {
- let (empty_selections, reverse_selections, forward_selections) =
- self.editor.read_with(self.cx, |editor, cx| {
- let mut empty_selections = Vec::new();
- let mut reverse_selections = Vec::new();
- let mut forward_selections = Vec::new();
-
- for selection in editor.selections.all::(cx) {
- let range = selection.range();
- if selection.is_empty() {
- empty_selections.push(range);
- } else if selection.reversed {
- reverse_selections.push(range);
- } else {
- forward_selections.push(range)
- }
+ let actual_selections = self
+ .editor
+ .read_with(self.cx, |editor, cx| editor.selections.all::(cx))
+ .into_iter()
+ .map(|s| {
+ if s.reversed {
+ s.end..s.start
+ } else {
+ s.start..s.end
}
+ })
+ .collect::>();
+ let actual_marked_text =
+ generate_marked_text(&self.buffer_text(), &actual_selections, true);
+ if expected_selections != actual_selections {
+ panic!(
+ indoc! {"
+ Editor has unexpected selections.
- (empty_selections, reverse_selections, forward_selections)
- });
+ Expected selections:
+ {}
- let asserted_selections = asserted_text.unwrap_or_else(|| {
- self.insert_markers(
- &expected_empty_selections,
- &expected_reverse_selections,
- &expected_forward_selections,
- )
- });
- let actual_selections =
- self.insert_markers(&empty_selections, &reverse_selections, &forward_selections);
-
- let unmarked_text = self.buffer_text();
- let all_eq: Result<(), SetEqError> =
- set_eq!(expected_empty_selections, empty_selections)
- .map_err(|err| {
- err.map(|missing| {
- let mut error_text = unmarked_text.clone();
- error_text.insert(missing.start, '|');
- error_text
- })
- })
- .and_then(|_| {
- set_eq!(expected_reverse_selections, reverse_selections).map_err(|err| {
- err.map(|missing| {
- let mut error_text = unmarked_text.clone();
- error_text.insert(missing.start, '{');
- error_text.insert(missing.end, ']');
- error_text
- })
- })
- })
- .and_then(|_| {
- set_eq!(expected_forward_selections, forward_selections).map_err(|err| {
- err.map(|missing| {
- let mut error_text = unmarked_text.clone();
- error_text.insert(missing.start, '[');
- error_text.insert(missing.end, '}');
- error_text
- })
- })
- });
-
- match all_eq {
- Err(SetEqError::LeftMissing(location_text)) => {
- panic!(
- indoc! {"
- Editor has extra selection
- Extra Selection Location:
- {}
- Asserted selections:
- {}
- Actual selections:
- {}"},
- location_text, asserted_selections, actual_selections,
- );
- }
- Err(SetEqError::RightMissing(location_text)) => {
- panic!(
- indoc! {"
- Editor is missing empty selection
- Missing Selection Location:
- {}
- Asserted selections:
- {}
- Actual selections:
- {}"},
- location_text, asserted_selections, actual_selections,
- );
- }
- _ => {}
+ Actual selections:
+ {}
+ "},
+ expected_marked_text, actual_marked_text,
+ );
}
}
-
- fn insert_markers(
- &mut self,
- empty_selections: &Vec>,
- reverse_selections: &Vec>,
- forward_selections: &Vec>,
- ) -> String {
- let mut editor_text_with_selections = self.buffer_text();
- let mut selection_marks = BTreeMap::new();
- for range in empty_selections {
- selection_marks.insert(&range.start, '|');
- }
- for range in reverse_selections {
- selection_marks.insert(&range.start, '{');
- selection_marks.insert(&range.end, ']');
- }
- for range in forward_selections {
- selection_marks.insert(&range.start, '[');
- selection_marks.insert(&range.end, '}');
- }
- for (offset, mark) in selection_marks.into_iter().rev() {
- editor_text_with_selections.insert(*offset, mark);
- }
-
- editor_text_with_selections
- }
}
impl<'a> Deref for EditorTestContext<'a> {
@@ -575,10 +418,8 @@ impl<'a> EditorLspTestContext<'a> {
// Constructs lsp range using a marked string with '[', ']' range delimiters
pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range {
- let (unmarked, mut ranges) = marked_text_ranges_by(marked_text, vec![('[', ']').into()]);
- assert_eq!(unmarked, self.buffer_text());
- let offset_range = ranges.remove(&('[', ']').into()).unwrap()[0].clone();
- self.to_lsp_range(offset_range)
+ let ranges = self.ranges(marked_text);
+ self.to_lsp_range(ranges[0].clone())
}
pub fn to_lsp_range(&mut self, range: Range) -> lsp::Range {
diff --git a/crates/util/Cargo.toml b/crates/util/Cargo.toml
index 87ec77d2df..4ec214fef1 100644
--- a/crates/util/Cargo.toml
+++ b/crates/util/Cargo.toml
@@ -15,6 +15,9 @@ futures = "0.3"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
rand = { version = "0.8", optional = true }
tempdir = { version = "0.3.7", optional = true }
-serde_json = { version = "1.0", features = [
- "preserve_order",
-], optional = true }
+serde_json = { version = "1.0", features = ["preserve_order"], optional = true }
+
+[dev-dependencies]
+rand = { version = "0.8" }
+tempdir = { version = "0.3.7" }
+serde_json = { version = "1.0", features = ["preserve_order"] }
diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs
index e5a98fd675..0616b2a75e 100644
--- a/crates/util/src/lib.rs
+++ b/crates/util/src/lib.rs
@@ -1,4 +1,4 @@
-#[cfg(feature = "test-support")]
+#[cfg(any(test, feature = "test-support"))]
pub mod test;
use futures::Future;
diff --git a/crates/util/src/test/marked_text.rs b/crates/util/src/test/marked_text.rs
index 2a5969c265..b5b68c22c9 100644
--- a/crates/util/src/test/marked_text.rs
+++ b/crates/util/src/test/marked_text.rs
@@ -1,6 +1,8 @@
-use std::{collections::HashMap, ops::Range};
+use std::{cmp::Ordering, collections::HashMap, ops::Range};
-pub fn marked_text_by(
+/// Construct a string and a list of offsets within that string using a single
+/// string containing embedded position markers.
+pub fn marked_text_offsets_by(
marked_text: &str,
markers: Vec,
) -> (String, HashMap>) {
@@ -19,9 +21,196 @@ pub fn marked_text_by(
(unmarked_text, extracted_markers)
}
-pub fn marked_text(marked_text: &str) -> (String, Vec) {
- let (unmarked_text, mut markers) = marked_text_by(marked_text, vec!['|']);
- (unmarked_text, markers.remove(&'|').unwrap_or_default())
+/// Construct a string and a list of ranges within that string using a single
+/// string containing embedded range markers, using arbitrary characters as
+/// range markers. By using multiple different range markers, you can construct
+/// ranges that overlap each other.
+///
+/// The returned ranges will be grouped by their range marking characters.
+pub fn marked_text_ranges_by(
+ marked_text: &str,
+ markers: Vec,
+) -> (String, HashMap>>) {
+ let all_markers = markers.iter().flat_map(|m| m.markers()).collect();
+
+ let (unmarked_text, mut marker_offsets) = marked_text_offsets_by(marked_text, all_markers);
+ let range_lookup = markers
+ .into_iter()
+ .map(|marker| {
+ (
+ marker.clone(),
+ match marker {
+ TextRangeMarker::Empty(empty_marker_char) => marker_offsets
+ .remove(&empty_marker_char)
+ .unwrap_or_default()
+ .into_iter()
+ .map(|empty_index| empty_index..empty_index)
+ .collect::>>(),
+ TextRangeMarker::Range(start_marker, end_marker) => {
+ let starts = marker_offsets.remove(&start_marker).unwrap_or_default();
+ let ends = marker_offsets.remove(&end_marker).unwrap_or_default();
+ assert_eq!(starts.len(), ends.len(), "marked ranges are unbalanced");
+ starts
+ .into_iter()
+ .zip(ends)
+ .map(|(start, end)| {
+ assert!(end >= start, "marked ranges must be disjoint");
+ start..end
+ })
+ .collect::>>()
+ }
+ TextRangeMarker::ReverseRange(start_marker, end_marker) => {
+ let starts = marker_offsets.remove(&start_marker).unwrap_or_default();
+ let ends = marker_offsets.remove(&end_marker).unwrap_or_default();
+ assert_eq!(starts.len(), ends.len(), "marked ranges are unbalanced");
+ starts
+ .into_iter()
+ .zip(ends)
+ .map(|(start, end)| {
+ assert!(end >= start, "marked ranges must be disjoint");
+ end..start
+ })
+ .collect::>>()
+ }
+ },
+ )
+ })
+ .collect();
+
+ (unmarked_text, range_lookup)
+}
+
+/// Construct a string and a list of ranges within that string using a single
+/// string containing embedded range markers. The characters used to mark the
+/// ranges are as follows:
+///
+/// 1. To mark a range of text, surround it with the `«` and `»` angle brackets,
+/// which can be typed on a US keyboard with the `alt-|` and `alt-shift-|` keys.
+///
+/// ```
+/// foo «selected text» bar
+/// ```
+///
+/// 2. To mark a single position in the text, use the `ˇ` caron,
+/// which can be typed on a US keyboard with the `alt-shift-t` key.
+///
+/// ```
+/// the cursors are hereˇ and hereˇ.
+/// ```
+///
+/// 3. To mark a range whose direction is meaningful (like a selection),
+/// put a caron character beside one of its bounds, on the inside:
+///
+/// ```
+/// one «ˇreversed» selection and one «forwardˇ» selection
+/// ```
+pub fn marked_text_ranges(
+ marked_text: &str,
+ ranges_are_directed: bool,
+) -> (String, Vec>) {
+ let mut unmarked_text = String::with_capacity(marked_text.len());
+ let mut ranges = Vec::new();
+ let mut prev_marked_ix = 0;
+ let mut current_range_start = None;
+ let mut current_range_cursor = None;
+
+ for (marked_ix, marker) in marked_text.match_indices(&['«', '»', 'ˇ']) {
+ unmarked_text.push_str(&marked_text[prev_marked_ix..marked_ix]);
+ let unmarked_len = unmarked_text.len();
+ let len = marker.len();
+ prev_marked_ix = marked_ix + len;
+
+ match marker {
+ "ˇ" => {
+ if current_range_start.is_some() {
+ if current_range_cursor.is_some() {
+ panic!("duplicate point marker 'ˇ' at index {marked_ix}");
+ } else {
+ current_range_cursor = Some(unmarked_len);
+ }
+ } else {
+ ranges.push(unmarked_len..unmarked_len);
+ }
+ }
+ "«" => {
+ if current_range_start.is_some() {
+ panic!("unexpected range start marker '«' at index {marked_ix}");
+ }
+ current_range_start = Some(unmarked_len);
+ }
+ "»" => {
+ let current_range_start = if let Some(start) = current_range_start.take() {
+ start
+ } else {
+ panic!("unexpected range end marker '»' at index {marked_ix}");
+ };
+
+ let mut reversed = false;
+ if let Some(current_range_cursor) = current_range_cursor.take() {
+ if current_range_cursor == current_range_start {
+ reversed = true;
+ } else if current_range_cursor != unmarked_len {
+ panic!("unexpected 'ˇ' marker in the middle of a range");
+ }
+ } else if ranges_are_directed {
+ panic!("missing 'ˇ' marker to indicate range direction");
+ }
+
+ ranges.push(if reversed {
+ unmarked_len..current_range_start
+ } else {
+ current_range_start..unmarked_len
+ });
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ unmarked_text.push_str(&marked_text[prev_marked_ix..]);
+ (unmarked_text, ranges)
+}
+
+pub fn marked_text_offsets(marked_text: &str) -> (String, Vec) {
+ let (text, ranges) = marked_text_ranges(marked_text, false);
+ (
+ text,
+ ranges
+ .into_iter()
+ .map(|range| {
+ assert_eq!(range.start, range.end);
+ range.start
+ })
+ .collect(),
+ )
+}
+
+pub fn generate_marked_text(
+ unmarked_text: &str,
+ ranges: &[Range],
+ indicate_cursors: bool,
+) -> String {
+ let mut marked_text = unmarked_text.to_string();
+ for range in ranges.iter().rev() {
+ if indicate_cursors {
+ match range.start.cmp(&range.end) {
+ Ordering::Less => {
+ marked_text.insert_str(range.end, "ˇ»");
+ marked_text.insert_str(range.start, "«");
+ }
+ Ordering::Equal => {
+ marked_text.insert_str(range.start, "ˇ");
+ }
+ Ordering::Greater => {
+ marked_text.insert_str(range.start, "»");
+ marked_text.insert_str(range.end, "«ˇ");
+ }
+ }
+ } else {
+ marked_text.insert_str(range.end, "»");
+ marked_text.insert_str(range.start, "«");
+ }
+ }
+ marked_text
}
#[derive(Clone, Eq, PartialEq, Hash)]
@@ -53,75 +242,24 @@ impl From<(char, char)> for TextRangeMarker {
}
}
-pub fn marked_text_ranges_by(
- marked_text: &str,
- markers: Vec,
-) -> (String, HashMap>>) {
- let all_markers = markers.iter().flat_map(|m| m.markers()).collect();
+#[cfg(test)]
+mod tests {
+ use super::{generate_marked_text, marked_text_ranges};
- let (unmarked_text, mut marker_offsets) = marked_text_by(marked_text, all_markers);
- let range_lookup = markers
- .into_iter()
- .map(|marker| match marker {
- TextRangeMarker::Empty(empty_marker_char) => {
- let ranges = marker_offsets
- .remove(&empty_marker_char)
- .unwrap_or_default()
- .into_iter()
- .map(|empty_index| empty_index..empty_index)
- .collect::>>();
- (marker, ranges)
- }
- TextRangeMarker::Range(start_marker, end_marker) => {
- let starts = marker_offsets.remove(&start_marker).unwrap_or_default();
- let ends = marker_offsets.remove(&end_marker).unwrap_or_default();
- assert_eq!(starts.len(), ends.len(), "marked ranges are unbalanced");
+ #[test]
+ fn test_marked_text() {
+ let (text, ranges) = marked_text_ranges("one «ˇtwo» «threeˇ» «ˇfour» fiveˇ six", true);
- let ranges = starts
- .into_iter()
- .zip(ends)
- .map(|(start, end)| {
- assert!(end >= start, "marked ranges must be disjoint");
- start..end
- })
- .collect::>>();
- (marker, ranges)
- }
- TextRangeMarker::ReverseRange(start_marker, end_marker) => {
- let starts = marker_offsets.remove(&start_marker).unwrap_or_default();
- let ends = marker_offsets.remove(&end_marker).unwrap_or_default();
- assert_eq!(starts.len(), ends.len(), "marked ranges are unbalanced");
+ assert_eq!(text, "one two three four five six");
+ assert_eq!(ranges.len(), 4);
+ assert_eq!(ranges[0], 7..4);
+ assert_eq!(ranges[1], 8..13);
+ assert_eq!(ranges[2], 18..14);
+ assert_eq!(ranges[3], 23..23);
- let ranges = starts
- .into_iter()
- .zip(ends)
- .map(|(start, end)| {
- assert!(end >= start, "marked ranges must be disjoint");
- end..start
- })
- .collect::>>();
- (marker, ranges)
- }
- })
- .collect();
-
- (unmarked_text, range_lookup)
-}
-
-// Returns ranges delimited by (), [], and <> ranges. Ranges using the same markers
-// must not be overlapping. May also include | for empty ranges
-pub fn marked_text_ranges(full_marked_text: &str) -> (String, Vec>) {
- let (unmarked, range_lookup) = marked_text_ranges_by(
- &full_marked_text,
- vec![
- '|'.into(),
- ('[', ']').into(),
- ('(', ')').into(),
- ('<', '>').into(),
- ],
- );
- let mut combined_ranges: Vec<_> = range_lookup.into_values().flatten().collect();
-
- combined_ranges.sort_by_key(|range| range.start);
- (unmarked, combined_ranges)
+ assert_eq!(
+ generate_marked_text(&text, &ranges, true),
+ "one «ˇtwo» «threeˇ» «ˇfour» fiveˇ six"
+ );
+ }
}
diff --git a/crates/vim/src/insert.rs b/crates/vim/src/insert.rs
index b8387e7165..a1d1c7b404 100644
--- a/crates/vim/src/insert.rs
+++ b/crates/vim/src/insert.rs
@@ -34,9 +34,9 @@ mod test {
cx.simulate_keystroke("i");
assert_eq!(cx.mode(), Mode::Insert);
cx.simulate_keystrokes(["T", "e", "s", "t"]);
- cx.assert_editor_state("Test|");
+ cx.assert_editor_state("Testˇ");
cx.simulate_keystroke("escape");
assert_eq!(cx.mode(), Mode::Normal);
- cx.assert_editor_state("Tes|t");
+ cx.assert_editor_state("Tesˇt");
}
}
diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs
index 39663e0db4..508477ea46 100644
--- a/crates/vim/src/normal.rs
+++ b/crates/vim/src/normal.rs
@@ -297,8 +297,7 @@ fn paste(_: &mut Workspace, _: &Paste, cx: &mut ViewContext) {
#[cfg(test)]
mod test {
use indoc::indoc;
- use language::Selection;
- use util::test::marked_text;
+ use util::test::marked_text_offsets;
use crate::{
state::{
@@ -312,15 +311,15 @@ mod test {
async fn test_h(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["h"]);
- cx.assert("The q|uick", "The |quick");
- cx.assert("|The quick", "|The quick");
+ cx.assert("The qˇuick", "The ˇquick");
+ cx.assert("ˇThe quick", "ˇThe quick");
cx.assert(
indoc! {"
The quick
- |brown"},
+ ˇbrown"},
indoc! {"
The quick
- |brown"},
+ ˇbrown"},
);
}
@@ -328,15 +327,15 @@ mod test {
async fn test_backspace(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["backspace"]);
- cx.assert("The q|uick", "The |quick");
- cx.assert("|The quick", "|The quick");
+ cx.assert("The qˇuick", "The ˇquick");
+ cx.assert("ˇThe quick", "ˇThe quick");
cx.assert(
indoc! {"
The quick
- |brown"},
+ ˇbrown"},
indoc! {"
The quick
- |brown"},
+ ˇbrown"},
);
}
@@ -346,35 +345,35 @@ mod test {
let mut cx = cx.binding(["j"]);
cx.assert(
indoc! {"
- The |quick
+ The ˇquick
brown fox"},
indoc! {"
The quick
- brow|n fox"},
+ browˇn fox"},
);
cx.assert(
indoc! {"
The quick
- brow|n fox"},
+ browˇn fox"},
indoc! {"
The quick
- brow|n fox"},
+ browˇn fox"},
);
cx.assert(
indoc! {"
- The quic|k
+ The quicˇk
brown"},
indoc! {"
The quick
- brow|n"},
+ browˇn"},
);
cx.assert(
indoc! {"
The quick
- |brown"},
+ ˇbrown"},
indoc! {"
The quick
- |brown"},
+ ˇbrown"},
);
}
@@ -384,26 +383,26 @@ mod test {
let mut cx = cx.binding(["k"]);
cx.assert(
indoc! {"
- The |quick
+ The ˇquick
brown fox"},
indoc! {"
- The |quick
+ The ˇquick
brown fox"},
);
cx.assert(
indoc! {"
The quick
- brow|n fox"},
+ browˇn fox"},
indoc! {"
- The |quick
+ The ˇquick
brown fox"},
);
cx.assert(
indoc! {"
The
- quic|k"},
+ quicˇk"},
indoc! {"
- Th|e
+ Thˇe
quick"},
);
}
@@ -412,14 +411,14 @@ mod test {
async fn test_l(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["l"]);
- cx.assert("The q|uick", "The qu|ick");
- cx.assert("The quic|k", "The quic|k");
+ cx.assert("The qˇuick", "The quˇick");
+ cx.assert("The quicˇk", "The quicˇk");
cx.assert(
indoc! {"
- The quic|k
+ The quicˇk
brown"},
indoc! {"
- The quic|k
+ The quicˇk
brown"},
);
}
@@ -428,42 +427,42 @@ mod test {
async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["$"]);
- cx.assert("T|est test", "Test tes|t");
- cx.assert("Test tes|t", "Test tes|t");
+ cx.assert("Tˇest test", "Test tesˇt");
+ cx.assert("Test tesˇt", "Test tesˇt");
cx.assert(
indoc! {"
- The |quick
+ The ˇquick
brown"},
indoc! {"
- The quic|k
+ The quicˇk
brown"},
);
cx.assert(
indoc! {"
- The quic|k
+ The quicˇk
brown"},
indoc! {"
- The quic|k
+ The quicˇk
brown"},
);
let mut cx = cx.binding(["0"]);
- cx.assert("Test |test", "|Test test");
- cx.assert("|Test test", "|Test test");
+ cx.assert("Test ˇtest", "ˇTest test");
+ cx.assert("ˇTest test", "ˇTest test");
cx.assert(
indoc! {"
- The |quick
+ The ˇquick
brown"},
indoc! {"
- |The quick
+ ˇThe quick
brown"},
);
cx.assert(
indoc! {"
- |The quick
+ ˇThe quick
brown"},
indoc! {"
- |The quick
+ ˇThe quick
brown"},
);
}
@@ -475,7 +474,7 @@ mod test {
cx.assert(
indoc! {"
- The |quick
+ The ˇquick
brown fox jumps
over the lazy dog"},
@@ -483,54 +482,54 @@ mod test {
The quick
brown fox jumps
- over| the lazy dog"},
+ overˇ the lazy dog"},
);
cx.assert(
indoc! {"
The quick
brown fox jumps
- over| the lazy dog"},
+ overˇ the lazy dog"},
indoc! {"
The quick
brown fox jumps
- over| the lazy dog"},
+ overˇ the lazy dog"},
);
cx.assert(
indoc! {"
- The qui|ck
+ The quiˇck
brown"},
indoc! {"
The quick
- brow|n"},
+ browˇn"},
);
cx.assert(
indoc! {"
- The qui|ck
+ The quiˇck
"},
indoc! {"
The quick
- |"},
+ ˇ"},
);
}
#[gpui::test]
async fn test_w(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
- let (_, cursor_offsets) = marked_text(indoc! {"
- The |quick|-|brown
- |
- |
- |fox_jumps |over
- |th||e"});
+ let (_, cursor_offsets) = marked_text_offsets(indoc! {"
+ The ˇquickˇ-ˇbrown
+ ˇ
+ ˇ
+ ˇfox_jumps ˇover
+ ˇthˇˇe"});
cx.set_state(
indoc! {"
- |The quick-brown
+ ˇThe quick-brown
fox_jumps over
@@ -540,19 +539,19 @@ mod test {
for cursor_offset in cursor_offsets {
cx.simulate_keystroke("w");
- cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
+ cx.assert_editor_selections(vec![cursor_offset..cursor_offset]);
}
// Reset and test ignoring punctuation
- let (_, cursor_offsets) = marked_text(indoc! {"
- The |quick-brown
- |
- |
- |fox_jumps |over
- |th||e"});
+ let (_, cursor_offsets) = marked_text_offsets(indoc! {"
+ The ˇquick-brown
+ ˇ
+ ˇ
+ ˇfox_jumps ˇover
+ ˇthˇˇe"});
cx.set_state(
indoc! {"
- |The quick-brown
+ ˇThe quick-brown
fox_jumps over
@@ -562,22 +561,22 @@ mod test {
for cursor_offset in cursor_offsets {
cx.simulate_keystroke("shift-w");
- cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
+ cx.assert_editor_selections(vec![cursor_offset..cursor_offset]);
}
}
#[gpui::test]
async fn test_e(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
- let (_, cursor_offsets) = marked_text(indoc! {"
- Th|e quic|k|-brow|n
+ let (_, cursor_offsets) = marked_text_offsets(indoc! {"
+ Thˇe quicˇkˇ-browˇn
- fox_jump|s ove|r
- th|e"});
+ fox_jumpˇs oveˇr
+ thˇe"});
cx.set_state(
indoc! {"
- |The quick-brown
+ ˇThe quick-brown
fox_jumps over
@@ -587,19 +586,19 @@ mod test {
for cursor_offset in cursor_offsets {
cx.simulate_keystroke("e");
- cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
+ cx.assert_editor_selections(vec![cursor_offset..cursor_offset]);
}
// Reset and test ignoring punctuation
- let (_, cursor_offsets) = marked_text(indoc! {"
- Th|e quick-brow|n
+ let (_, cursor_offsets) = marked_text_offsets(indoc! {"
+ Thˇe quick-browˇn
- fox_jump|s ove|r
- th||e"});
+ fox_jumpˇs oveˇr
+ thˇˇe"});
cx.set_state(
indoc! {"
- |The quick-brown
+ ˇThe quick-brown
fox_jumps over
@@ -608,53 +607,53 @@ mod test {
);
for cursor_offset in cursor_offsets {
cx.simulate_keystroke("shift-e");
- cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
+ cx.assert_editor_selections(vec![cursor_offset..cursor_offset]);
}
}
#[gpui::test]
async fn test_b(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
- let (_, cursor_offsets) = marked_text(indoc! {"
- ||The |quick|-|brown
- |
- |
- |fox_jumps |over
- |the"});
+ let (_, cursor_offsets) = marked_text_offsets(indoc! {"
+ ˇˇThe ˇquickˇ-ˇbrown
+ ˇ
+ ˇ
+ ˇfox_jumps ˇover
+ ˇthe"});
cx.set_state(
indoc! {"
The quick-brown
fox_jumps over
- th|e"},
+ thˇe"},
Mode::Normal,
);
for cursor_offset in cursor_offsets.into_iter().rev() {
cx.simulate_keystroke("b");
- cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
+ cx.assert_editor_selections(vec![cursor_offset..cursor_offset]);
}
// Reset and test ignoring punctuation
- let (_, cursor_offsets) = marked_text(indoc! {"
- ||The |quick-brown
- |
- |
- |fox_jumps |over
- |the"});
+ let (_, cursor_offsets) = marked_text_offsets(indoc! {"
+ ˇˇThe ˇquick-brown
+ ˇ
+ ˇ
+ ˇfox_jumps ˇover
+ ˇthe"});
cx.set_state(
indoc! {"
The quick-brown
fox_jumps over
- th|e"},
+ thˇe"},
Mode::Normal,
);
for cursor_offset in cursor_offsets.into_iter().rev() {
cx.simulate_keystroke("shift-b");
- cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
+ cx.assert_editor_selections(vec![cursor_offset..cursor_offset]);
}
}
@@ -683,21 +682,21 @@ mod test {
The quick
brown fox jumps
- over |the lazy dog"},
+ over ˇthe lazy dog"},
indoc! {"
- The q|uick
+ The qˇuick
brown fox jumps
over the lazy dog"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox jumps
over the lazy dog"},
indoc! {"
- The q|uick
+ The qˇuick
brown fox jumps
over the lazy dog"},
@@ -707,9 +706,9 @@ mod test {
The quick
brown fox jumps
- over the la|zy dog"},
+ over the laˇzy dog"},
indoc! {"
- The quic|k
+ The quicˇk
brown fox jumps
over the lazy dog"},
@@ -719,9 +718,9 @@ mod test {
brown fox jumps
- over the la|zy dog"},
+ over the laˇzy dog"},
indoc! {"
- |
+ ˇ
brown fox jumps
over the lazy dog"},
@@ -733,31 +732,31 @@ mod test {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["a"]).mode_after(Mode::Insert);
- cx.assert("The q|uick", "The qu|ick");
- cx.assert("The quic|k", "The quick|");
+ cx.assert("The qˇuick", "The quˇick");
+ cx.assert("The quicˇk", "The quickˇ");
}
#[gpui::test]
async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["shift-a"]).mode_after(Mode::Insert);
- cx.assert("The q|uick", "The quick|");
- cx.assert("The q|uick ", "The quick |");
- cx.assert("|", "|");
+ cx.assert("The qˇuick", "The quickˇ");
+ cx.assert("The qˇuick ", "The quick ˇ");
+ cx.assert("ˇ", "ˇ");
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- The quick|
+ The quickˇ
brown fox"},
);
cx.assert(
indoc! {"
- |
+ ˇ
The quick"},
indoc! {"
- |
+ ˇ
The quick"},
);
}
@@ -766,50 +765,50 @@ mod test {
async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["^"]);
- cx.assert("The q|uick", "|The quick");
- cx.assert(" The q|uick", " |The quick");
- cx.assert("|", "|");
+ cx.assert("The qˇuick", "ˇThe quick");
+ cx.assert(" The qˇuick", " ˇThe quick");
+ cx.assert("ˇ", "ˇ");
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- |The quick
+ ˇThe quick
brown fox"},
);
cx.assert(
indoc! {"
- |
+ ˇ
The quick"},
indoc! {"
- |
+ ˇ
The quick"},
);
// Indoc disallows trailing whitspace.
- cx.assert(" | \nThe quick", " | \nThe quick");
+ cx.assert(" ˇ \nThe quick", " ˇ \nThe quick");
}
#[gpui::test]
async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["shift-i"]).mode_after(Mode::Insert);
- cx.assert("The q|uick", "|The quick");
- cx.assert(" The q|uick", " |The quick");
- cx.assert("|", "|");
+ cx.assert("The qˇuick", "ˇThe quick");
+ cx.assert(" The qˇuick", " ˇThe quick");
+ cx.assert("ˇ", "ˇ");
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- |The quick
+ ˇThe quick
brown fox"},
);
cx.assert(
indoc! {"
- |
+ ˇ
The quick"},
indoc! {"
- |
+ ˇ
The quick"},
);
}
@@ -820,20 +819,20 @@ mod test {
let mut cx = cx.binding(["shift-d"]);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- The |q
+ The ˇq
brown fox"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
}
@@ -842,15 +841,15 @@ mod test {
async fn test_x(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["x"]);
- cx.assert("|Test", "|est");
- cx.assert("Te|st", "Te|t");
- cx.assert("Tes|t", "Te|s");
+ cx.assert("ˇTest", "ˇest");
+ cx.assert("Teˇst", "Teˇt");
+ cx.assert("Tesˇt", "Teˇs");
cx.assert(
indoc! {"
- Tes|t
+ Tesˇt
test"},
indoc! {"
- Te|s
+ Teˇs
test"},
);
}
@@ -859,16 +858,16 @@ mod test {
async fn test_delete_left(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["shift-x"]);
- cx.assert("Te|st", "T|st");
- cx.assert("T|est", "|est");
- cx.assert("|Test", "|Test");
+ cx.assert("Teˇst", "Tˇst");
+ cx.assert("Tˇest", "ˇest");
+ cx.assert("ˇTest", "ˇTest");
cx.assert(
indoc! {"
Test
- |test"},
+ ˇtest"},
indoc! {"
Test
- |test"},
+ ˇtest"},
);
}
@@ -878,78 +877,84 @@ mod test {
let mut cx = cx.binding(["o"]).mode_after(Mode::Insert);
cx.assert(
- "|",
+ "ˇ",
indoc! {"
- |"},
+ ˇ"},
);
cx.assert(
- "The |quick",
+ "The ˇquick",
indoc! {"
The quick
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
indoc! {"
The quick
brown fox
- |
+ ˇ
jumps over"},
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
brown fox
jumps over
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
The quick
- |
+ ˇ
brown fox
jumps over"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
cx.assert(
indoc! {"
- fn test()
- println!(|);"},
+ fn test() {
+ println!(ˇ);
+ }
+ "},
indoc! {"
- fn test()
+ fn test() {
println!();
- |"},
+ ˇ
+ }
+ "},
);
cx.assert(
indoc! {"
- fn test(|)
- println!();"},
+ fn test(ˇ) {
+ println!();
+ }"},
indoc! {"
- fn test()
- |
- println!();"},
+ fn test() {
+ ˇ
+ println!();
+ }"},
);
}
@@ -959,25 +964,25 @@ mod test {
let mut cx = cx.binding(["shift-o"]).mode_after(Mode::Insert);
cx.assert(
- "|",
+ "ˇ",
indoc! {"
- |
+ ˇ
"},
);
cx.assert(
- "The |quick",
+ "The ˇquick",
indoc! {"
- |
+ ˇ
The quick"},
);
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
indoc! {"
The quick
- |
+ ˇ
brown fox
jumps over"},
);
@@ -985,20 +990,20 @@ mod test {
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
brown fox
- |
+ ˇ
jumps over"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
- |
+ ˇ
The quick
brown fox
jumps over"},
@@ -1006,31 +1011,33 @@ mod test {
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
cx.assert(
indoc! {"
fn test()
- println!(|);"},
+ println!(ˇ);"},
indoc! {"
fn test()
- |
+ ˇ
println!();"},
);
cx.assert(
indoc! {"
- fn test(|)
- println!();"},
+ fn test(ˇ) {
+ println!();
+ }"},
indoc! {"
- |
- fn test()
- println!();"},
+ ˇ
+ fn test() {
+ println!();
+ }"},
);
}
@@ -1039,43 +1046,43 @@ mod test {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "d"]);
- cx.assert("|", "|");
- cx.assert("The |quick", "|");
+ cx.assert("ˇ", "ˇ");
+ cx.assert("The ˇquick", "ˇ");
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
indoc! {"
The quick
- jumps |over"},
+ jumps ˇover"},
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
- brown |fox"},
+ brown ˇfox"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
- brown| fox
+ brownˇ fox
jumps over"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |brown fox"},
+ ˇbrown fox"},
);
}
@@ -1084,46 +1091,46 @@ mod test {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["c", "c"]).mode_after(Mode::Insert);
- cx.assert("|", "|");
- cx.assert("The |quick", "|");
+ cx.assert("ˇ", "ˇ");
+ cx.assert("The ˇquick", "ˇ");
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
indoc! {"
The quick
- |
+ ˇ
jumps over"},
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
brown fox
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
- |
+ ˇ
brown fox
jumps over"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
}
@@ -1134,7 +1141,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
Mode::Normal,
);
@@ -1142,21 +1149,21 @@ mod test {
cx.simulate_keystrokes(["d", "d"]);
cx.assert_editor_state(indoc! {"
The quick brown
- the la|zy dog"});
+ the laˇzy dog"});
cx.simulate_keystroke("p");
cx.assert_state(
indoc! {"
The quick brown
the lazy dog
- |fox jumps over"},
+ ˇfox jumps over"},
Mode::Normal,
);
cx.set_state(
indoc! {"
The quick brown
- fox [jump}s over
+ fox «jumpˇ»s over
the lazy dog"},
Mode::Visual { line: false },
);
@@ -1164,7 +1171,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox jumps ove|r
+ fox jumps oveˇr
the lazy dog"},
Mode::Normal,
);
@@ -1172,7 +1179,7 @@ mod test {
cx.assert_state(
indoc! {"
The quick brown
- fox jumps over|jumps
+ fox jumps overˇjumps
the lazy dog"},
Mode::Normal,
);
diff --git a/crates/vim/src/normal/change.rs b/crates/vim/src/normal/change.rs
index 03f213b584..1a7b934a31 100644
--- a/crates/vim/src/normal/change.rs
+++ b/crates/vim/src/normal/change.rs
@@ -84,16 +84,16 @@ mod test {
async fn test_change_h(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["c", "h"]).mode_after(Mode::Insert);
- cx.assert("Te|st", "T|st");
- cx.assert("T|est", "|est");
- cx.assert("|Test", "|Test");
+ cx.assert("Teˇst", "Tˇst");
+ cx.assert("Tˇest", "ˇest");
+ cx.assert("ˇTest", "ˇTest");
cx.assert(
indoc! {"
Test
- |test"},
+ ˇtest"},
indoc! {"
Test
- |test"},
+ ˇtest"},
);
}
@@ -101,111 +101,111 @@ mod test {
async fn test_change_l(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["c", "l"]).mode_after(Mode::Insert);
- cx.assert("Te|st", "Te|t");
- cx.assert("Tes|t", "Tes|");
+ cx.assert("Teˇst", "Teˇt");
+ cx.assert("Tesˇt", "Tesˇ");
}
#[gpui::test]
async fn test_change_w(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["c", "w"]).mode_after(Mode::Insert);
- cx.assert("Te|st", "Te|");
- cx.assert("T|est test", "T| test");
- cx.assert("Test| test", "Test|test");
+ cx.assert("Teˇst", "Teˇ");
+ cx.assert("Tˇest test", "Tˇ test");
+ cx.assert("Testˇ test", "Testˇtest");
cx.assert(
indoc! {"
- Test te|st
+ Test teˇst
test"},
indoc! {"
- Test te|
+ Test teˇ
test"},
);
cx.assert(
indoc! {"
- Test tes|t
+ Test tesˇt
test"},
indoc! {"
- Test tes|
+ Test tesˇ
test"},
);
cx.assert(
indoc! {"
Test test
- |
+ ˇ
test"},
indoc! {"
Test test
- |
+ ˇ
test"},
);
let mut cx = cx.binding(["c", "shift-w"]);
- cx.assert("Test te|st-test test", "Test te| test");
+ cx.assert("Test teˇst-test test", "Test teˇ test");
}
#[gpui::test]
async fn test_change_e(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["c", "e"]).mode_after(Mode::Insert);
- cx.assert("Te|st Test", "Te| Test");
- cx.assert("T|est test", "T| test");
+ cx.assert("Teˇst Test", "Teˇ Test");
+ cx.assert("Tˇest test", "Tˇ test");
cx.assert(
indoc! {"
- Test te|st
+ Test teˇst
test"},
indoc! {"
- Test te|
+ Test teˇ
test"},
);
cx.assert(
indoc! {"
- Test tes|t
+ Test tesˇt
test"},
- "Test tes|",
+ "Test tesˇ",
);
cx.assert(
indoc! {"
Test test
- |
+ ˇ
test"},
indoc! {"
Test test
- |
+ ˇ
test"},
);
let mut cx = cx.binding(["c", "shift-e"]);
- cx.assert("Test te|st-test test", "Test te| test");
+ cx.assert("Test teˇst-test test", "Test teˇ test");
}
#[gpui::test]
async fn test_change_b(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["c", "b"]).mode_after(Mode::Insert);
- cx.assert("Te|st Test", "|st Test");
- cx.assert("Test |test", "|test");
- cx.assert("Test1 test2 |test3", "Test1 |test3");
+ cx.assert("Teˇst Test", "ˇst Test");
+ cx.assert("Test ˇtest", "ˇtest");
+ cx.assert("Test1 test2 ˇtest3", "Test1 ˇtest3");
cx.assert(
indoc! {"
Test test
- |test"},
+ ˇtest"},
indoc! {"
- Test |
+ Test ˇ
test"},
);
cx.assert(
indoc! {"
Test test
- |
+ ˇ
test"},
indoc! {"
- Test |
+ Test ˇ
test"},
);
let mut cx = cx.binding(["c", "shift-b"]);
- cx.assert("Test test-test |test", "Test |test");
+ cx.assert("Test test-test ˇtest", "Test ˇtest");
}
#[gpui::test]
@@ -214,20 +214,20 @@ mod test {
let mut cx = cx.binding(["c", "$"]).mode_after(Mode::Insert);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- The q|
+ The qˇ
brown fox"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
}
@@ -238,20 +238,20 @@ mod test {
let mut cx = cx.binding(["c", "0"]).mode_after(Mode::Insert);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- |uick
+ ˇuick
brown fox"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
}
@@ -263,38 +263,38 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
indoc! {"
- |
+ ˇ
jumps over"},
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
- |
+ ˇ
brown fox
jumps over"},
);
cx.assert(
indoc! {"
- |
+ ˇ
brown fox
jumps over"},
indoc! {"
- |
+ ˇ
brown fox
jumps over"},
);
@@ -307,40 +307,40 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
indoc! {"
The quick
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
brown fox
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
- |
+ ˇ
jumps over"},
);
cx.assert(
indoc! {"
The quick
brown fox
- |"},
+ ˇ"},
indoc! {"
The quick
brown fox
- |"},
+ ˇ"},
);
}
@@ -351,46 +351,46 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
indoc! {"
The quick
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
The quick
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
indoc! {"
The quick
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
- the l|azy"},
+ the lˇazy"},
indoc! {"
The quick
brown fox
jumps over
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
- |"},
+ ˇ"},
indoc! {"
The quick
brown fox
jumps over
- |"},
+ ˇ"},
);
}
@@ -401,11 +401,11 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
indoc! {"
- |
+ ˇ
jumps over
the lazy"},
);
@@ -414,29 +414,29 @@ mod test {
The quick
brown fox
jumps over
- the l|azy"},
- "|",
+ the lˇazy"},
+ "ˇ",
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over
the lazy"},
indoc! {"
- |
+ ˇ
brown fox
jumps over
the lazy"},
);
cx.assert(
indoc! {"
- |
+ ˇ
brown fox
jumps over
the lazy"},
indoc! {"
- |
+ ˇ
brown fox
jumps over
the lazy"},
diff --git a/crates/vim/src/normal/delete.rs b/crates/vim/src/normal/delete.rs
index ca2c27cf70..c639e604dc 100644
--- a/crates/vim/src/normal/delete.rs
+++ b/crates/vim/src/normal/delete.rs
@@ -46,16 +46,16 @@ mod test {
async fn test_delete_h(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "h"]);
- cx.assert("Te|st", "T|st");
- cx.assert("T|est", "|est");
- cx.assert("|Test", "|Test");
+ cx.assert("Teˇst", "Tˇst");
+ cx.assert("Tˇest", "ˇest");
+ cx.assert("ˇTest", "ˇTest");
cx.assert(
indoc! {"
Test
- |test"},
+ ˇtest"},
indoc! {"
Test
- |test"},
+ ˇtest"},
);
}
@@ -63,15 +63,15 @@ mod test {
async fn test_delete_l(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "l"]);
- cx.assert("|Test", "|est");
- cx.assert("Te|st", "Te|t");
- cx.assert("Tes|t", "Te|s");
+ cx.assert("ˇTest", "ˇest");
+ cx.assert("Teˇst", "Teˇt");
+ cx.assert("Tesˇt", "Teˇs");
cx.assert(
indoc! {"
- Tes|t
+ Tesˇt
test"},
indoc! {"
- Te|s
+ Teˇs
test"},
);
}
@@ -80,104 +80,104 @@ mod test {
async fn test_delete_w(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "w"]);
- cx.assert("Te|st", "T|e");
- cx.assert("T|est test", "T|test");
+ cx.assert("Teˇst", "Tˇe");
+ cx.assert("Tˇest test", "Tˇtest");
cx.assert(
indoc! {"
- Test te|st
+ Test teˇst
test"},
indoc! {"
- Test t|e
+ Test tˇe
test"},
);
cx.assert(
indoc! {"
- Test tes|t
+ Test tesˇt
test"},
indoc! {"
- Test te|s
+ Test teˇs
test"},
);
cx.assert(
indoc! {"
Test test
- |
+ ˇ
test"},
indoc! {"
Test test
- |
+ ˇ
test"},
);
let mut cx = cx.binding(["d", "shift-w"]);
- cx.assert("Test te|st-test test", "Test te|test");
+ cx.assert("Test teˇst-test test", "Test teˇtest");
}
#[gpui::test]
async fn test_delete_e(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "e"]);
- cx.assert("Te|st Test", "Te| Test");
- cx.assert("T|est test", "T| test");
+ cx.assert("Teˇst Test", "Teˇ Test");
+ cx.assert("Tˇest test", "Tˇ test");
cx.assert(
indoc! {"
- Test te|st
+ Test teˇst
test"},
indoc! {"
- Test t|e
+ Test tˇe
test"},
);
cx.assert(
indoc! {"
- Test tes|t
+ Test tesˇt
test"},
- "Test te|s",
+ "Test teˇs",
);
cx.assert(
indoc! {"
Test test
- |
+ ˇ
test"},
indoc! {"
Test test
- |
+ ˇ
test"},
);
let mut cx = cx.binding(["d", "shift-e"]);
- cx.assert("Test te|st-test test", "Test te| test");
+ cx.assert("Test teˇst-test test", "Test teˇ test");
}
#[gpui::test]
async fn test_delete_b(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "b"]);
- cx.assert("Te|st Test", "|st Test");
- cx.assert("Test |test", "|test");
- cx.assert("Test1 test2 |test3", "Test1 |test3");
+ cx.assert("Teˇst Test", "ˇst Test");
+ cx.assert("Test ˇtest", "ˇtest");
+ cx.assert("Test1 test2 ˇtest3", "Test1 ˇtest3");
cx.assert(
indoc! {"
Test test
- |test"},
+ ˇtest"},
// Trailing whitespace after cursor
indoc! {"
- Test|
+ Testˇ
test"},
);
cx.assert(
indoc! {"
Test test
- |
+ ˇ
test"},
// Trailing whitespace after cursor
indoc! {"
- Test|
+ Testˇ
test"},
);
let mut cx = cx.binding(["d", "shift-b"]);
- cx.assert("Test test-test |test", "Test |test");
+ cx.assert("Test test-test ˇtest", "Test ˇtest");
}
#[gpui::test]
@@ -186,20 +186,20 @@ mod test {
let mut cx = cx.binding(["d", "$"]);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- The |q
+ The ˇq
brown fox"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
}
@@ -210,20 +210,20 @@ mod test {
let mut cx = cx.binding(["d", "0"]);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox"},
indoc! {"
- |uick
+ ˇuick
brown fox"},
);
cx.assert(
indoc! {"
The quick
- |
+ ˇ
brown fox"},
indoc! {"
The quick
- |
+ ˇ
brown fox"},
);
}
@@ -235,31 +235,31 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
- "jumps |over",
+ "jumps ˇover",
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
- "The qu|ick",
+ jumps ˇover"},
+ "The quˇick",
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
indoc! {"
- brown| fox
+ brownˇ fox
jumps over"},
);
cx.assert(
indoc! {"
- |brown fox
+ ˇbrown fox
jumps over"},
- "|jumps over",
+ "ˇjumps over",
);
}
@@ -270,34 +270,34 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown |fox
+ brown ˇfox
jumps over"},
- "The qu|ick",
+ "The quˇick",
);
cx.assert(
indoc! {"
The quick
brown fox
- jumps |over"},
+ jumps ˇover"},
indoc! {"
The quick
- brown |fox"},
+ brown ˇfox"},
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over"},
- "jumps| over",
+ "jumpsˇ over",
);
cx.assert(
indoc! {"
The quick
brown fox
- |"},
+ ˇ"},
indoc! {"
The quick
- |brown fox"},
+ ˇbrown fox"},
);
}
@@ -308,40 +308,40 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
- "The q|uick",
+ "The qˇuick",
);
cx.assert(
indoc! {"
The quick
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
- "The q|uick",
+ "The qˇuick",
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
- the l|azy"},
+ the lˇazy"},
indoc! {"
The quick
brown fox
- jumps| over"},
+ jumpsˇ over"},
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
- |"},
+ ˇ"},
indoc! {"
The quick
brown fox
- |jumps over"},
+ ˇjumps over"},
);
}
@@ -352,11 +352,11 @@ mod test {
cx.assert(
indoc! {"
The quick
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
indoc! {"
- jumps| over
+ jumpsˇ over
the lazy"},
);
cx.assert(
@@ -364,28 +364,28 @@ mod test {
The quick
brown fox
jumps over
- the l|azy"},
- "|",
+ the lˇazy"},
+ "ˇ",
);
cx.assert(
indoc! {"
- The q|uick
+ The qˇuick
brown fox
jumps over
the lazy"},
indoc! {"
- brown| fox
+ brownˇ fox
jumps over
the lazy"},
);
cx.assert(
indoc! {"
- |
+ ˇ
brown fox
jumps over
the lazy"},
indoc! {"
- |brown fox
+ ˇbrown fox
jumps over
the lazy"},
);
@@ -397,7 +397,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
Mode::Normal,
);
@@ -407,7 +407,7 @@ mod test {
assert_eq!(cx.active_operator(), None);
assert_eq!(cx.mode(), Mode::Normal);
cx.assert_editor_state(indoc! {"
- The qu|ick brown
+ The quˇick brown
fox jumps over
the lazy dog"});
}
@@ -418,7 +418,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
Mode::Normal,
);
diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs
index f5764ba09b..ecad33ce3f 100644
--- a/crates/vim/src/vim.rs
+++ b/crates/vim/src/vim.rs
@@ -216,7 +216,7 @@ mod test {
async fn test_initially_disabled(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, false).await;
cx.simulate_keystrokes(["h", "j", "k", "l"]);
- cx.assert_editor_state("hjkl|");
+ cx.assert_editor_state("hjklˇ");
}
#[gpui::test]
@@ -229,24 +229,24 @@ mod test {
// Editor acts as though vim is disabled
cx.disable_vim();
cx.simulate_keystrokes(["h", "j", "k", "l"]);
- cx.assert_editor_state("hjkl|");
+ cx.assert_editor_state("hjklˇ");
// Selections aren't changed if editor is blurred but vim-mode is still disabled.
- cx.set_state("[hjkl}", Mode::Normal);
- cx.assert_editor_state("[hjkl}");
+ cx.set_state("«hjklˇ»", Mode::Normal);
+ cx.assert_editor_state("«hjklˇ»");
cx.update_editor(|_, cx| cx.blur());
- cx.assert_editor_state("[hjkl}");
+ cx.assert_editor_state("«hjklˇ»");
cx.update_editor(|_, cx| cx.focus_self());
- cx.assert_editor_state("[hjkl}");
+ cx.assert_editor_state("«hjklˇ»");
// Enabling dynamically sets vim mode again and restores normal mode
cx.enable_vim();
assert_eq!(cx.mode(), Mode::Normal);
cx.simulate_keystrokes(["h", "h", "h", "l"]);
assert_eq!(cx.buffer_text(), "hjkl".to_owned());
- cx.assert_editor_state("h|jkl");
+ cx.assert_editor_state("hˇjkl");
cx.simulate_keystrokes(["i", "T", "e", "s", "t"]);
- cx.assert_editor_state("hTest|jkl");
+ cx.assert_editor_state("hTestˇjkl");
// Disabling and enabling resets to normal mode
assert_eq!(cx.mode(), Mode::Insert);
@@ -262,7 +262,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
Mode::Normal,
);
diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs
index 76fea2e205..3f7b9c0683 100644
--- a/crates/vim/src/visual.rs
+++ b/crates/vim/src/visual.rs
@@ -284,44 +284,44 @@ mod test {
.mode_after(Mode::Visual { line: false });
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- The [quick brown
- fox jumps }over
+ The «quick brown
+ fox jumps ˇ»over
the lazy dog"},
);
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
fox jumps over
- the [lazy }dog"},
+ the «lazy ˇ»dog"},
);
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
The quick brown
- fox jumps [over
- }the lazy dog"},
+ fox jumps «over
+ ˇ»the lazy dog"},
);
let mut cx = cx
.binding(["v", "b", "k"])
.mode_after(Mode::Visual { line: false });
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- {The q]uick brown
+ «ˇThe q»uick brown
fox jumps over
the lazy dog"},
);
@@ -329,20 +329,20 @@ mod test {
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
- {fox jumps over
- the l]azy dog"},
+ «ˇfox jumps over
+ the l»azy dog"},
);
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
- The {quick brown
- fox jumps o]ver
+ The «ˇquick brown
+ fox jumps o»ver
the lazy dog"},
);
}
@@ -351,51 +351,51 @@ mod test {
async fn test_visual_delete(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["v", "w", "x"]);
- cx.assert("The quick |brown", "The quick| ");
+ cx.assert("The quick ˇbrown", "The quickˇ ");
let mut cx = cx.binding(["v", "w", "j", "x"]);
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- The |ver
+ The ˇver
the lazy dog"},
);
// Test pasting code copied on delete
cx.simulate_keystrokes(["j", "p"]);
cx.assert_editor_state(indoc! {"
The ver
- the l|quick brown
+ the lˇquick brown
fox jumps oazy dog"});
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
fox jumps over
- the |og"},
+ the ˇog"},
);
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
The quick brown
- fox jumps |he lazy dog"},
+ fox jumps ˇhe lazy dog"},
);
let mut cx = cx.binding(["v", "b", "k", "x"]);
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- |uick brown
+ ˇuick brown
fox jumps over
the lazy dog"},
);
@@ -403,18 +403,18 @@ mod test {
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
- |azy dog"},
+ ˇazy dog"},
);
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
- The |ver
+ The ˇver
the lazy dog"},
);
}
@@ -425,68 +425,68 @@ mod test {
let mut cx = cx.binding(["shift-v", "x"]);
cx.assert(
indoc! {"
- The qu|ick brown
+ The quˇick brown
fox jumps over
the lazy dog"},
indoc! {"
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
);
// Test pasting code copied on delete
cx.simulate_keystroke("p");
cx.assert_editor_state(indoc! {"
fox jumps over
- |The quick brown
+ ˇThe quick brown
the lazy dog"});
cx.assert(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
indoc! {"
The quick brown
- the la|zy dog"},
+ the laˇzy dog"},
);
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the la|zy dog"},
+ the laˇzy dog"},
indoc! {"
The quick brown
- fox ju|mps over"},
+ fox juˇmps over"},
);
let mut cx = cx.binding(["shift-v", "j", "x"]);
cx.assert(
indoc! {"
- The qu|ick brown
+ The quˇick brown
fox jumps over
the lazy dog"},
- "the la|zy dog",
+ "the laˇzy dog",
);
// Test pasting code copied on delete
cx.simulate_keystroke("p");
cx.assert_editor_state(indoc! {"
the lazy dog
- |The quick brown
+ ˇThe quick brown
fox jumps over"});
cx.assert(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
- "The qu|ick brown",
+ "The quˇick brown",
);
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the la|zy dog"},
+ the laˇzy dog"},
indoc! {"
The quick brown
- fox ju|mps over"},
+ fox juˇmps over"},
);
}
@@ -494,44 +494,44 @@ mod test {
async fn test_visual_change(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["v", "w", "c"]).mode_after(Mode::Insert);
- cx.assert("The quick |brown", "The quick |");
+ cx.assert("The quick ˇbrown", "The quick ˇ");
let mut cx = cx.binding(["v", "w", "j", "c"]).mode_after(Mode::Insert);
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- The |ver
+ The ˇver
the lazy dog"},
);
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
fox jumps over
- the |og"},
+ the ˇog"},
);
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
The quick brown
- fox jumps |he lazy dog"},
+ fox jumps ˇhe lazy dog"},
);
let mut cx = cx.binding(["v", "b", "k", "c"]).mode_after(Mode::Insert);
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- |uick brown
+ ˇuick brown
fox jumps over
the lazy dog"},
);
@@ -539,18 +539,18 @@ mod test {
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
- |azy dog"},
+ ˇazy dog"},
);
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
- The |ver
+ The ˇver
the lazy dog"},
);
}
@@ -561,11 +561,11 @@ mod test {
let mut cx = cx.binding(["shift-v", "c"]).mode_after(Mode::Insert);
cx.assert(
indoc! {"
- The qu|ick brown
+ The quˇick brown
fox jumps over
the lazy dog"},
indoc! {"
- |
+ ˇ
fox jumps over
the lazy dog"},
);
@@ -574,37 +574,37 @@ mod test {
cx.assert_editor_state(indoc! {"
fox jumps over
- |The quick brown
+ ˇThe quick brown
the lazy dog"});
cx.assert(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
indoc! {"
The quick brown
- |
+ ˇ
the lazy dog"},
);
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the la|zy dog"},
+ the laˇzy dog"},
indoc! {"
The quick brown
fox jumps over
- |"},
+ ˇ"},
);
let mut cx = cx.binding(["shift-v", "j", "c"]).mode_after(Mode::Insert);
cx.assert(
indoc! {"
- The qu|ick brown
+ The quˇick brown
fox jumps over
the lazy dog"},
indoc! {"
- |
+ ˇ
the lazy dog"},
);
// Test pasting code copied on delete
@@ -612,26 +612,26 @@ mod test {
cx.assert_editor_state(indoc! {"
the lazy dog
- |The quick brown
+ ˇThe quick brown
fox jumps over"});
cx.assert(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
indoc! {"
The quick brown
- |"},
+ ˇ"},
);
cx.assert(
indoc! {"
The quick brown
fox jumps over
- the la|zy dog"},
+ the laˇzy dog"},
indoc! {"
The quick brown
fox jumps over
- |"},
+ ˇ"},
);
}
@@ -639,16 +639,16 @@ mod test {
async fn test_visual_yank(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["v", "w", "y"]);
- cx.assert("The quick |brown", "The quick |brown");
+ cx.assert("The quick ˇbrown", "The quick ˇbrown");
cx.assert_clipboard_content(Some("brown"));
let mut cx = cx.binding(["v", "w", "j", "y"]);
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
);
@@ -659,21 +659,21 @@ mod test {
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
);
cx.assert_clipboard_content(Some("lazy d"));
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
);
cx.assert_clipboard_content(Some(indoc! {"
@@ -682,11 +682,11 @@ mod test {
let mut cx = cx.binding(["v", "b", "k", "y"]);
cx.assert(
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
indoc! {"
- |The quick brown
+ ˇThe quick brown
fox jumps over
the lazy dog"},
);
@@ -695,10 +695,10 @@ mod test {
indoc! {"
The quick brown
fox jumps over
- the |lazy dog"},
+ the ˇlazy dog"},
indoc! {"
The quick brown
- |fox jumps over
+ ˇfox jumps over
the lazy dog"},
);
cx.assert_clipboard_content(Some(indoc! {"
@@ -707,10 +707,10 @@ mod test {
cx.assert(
indoc! {"
The quick brown
- fox jumps |over
+ fox jumps ˇover
the lazy dog"},
indoc! {"
- The |quick brown
+ The ˇquick brown
fox jumps over
the lazy dog"},
);
@@ -725,7 +725,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox [jump}s over
+ fox «jumpˇ»s over
the lazy dog"},
Mode::Visual { line: false },
);
@@ -733,7 +733,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox jump|s over
+ fox jumpˇs over
the lazy dog"},
Mode::Normal,
);
@@ -741,7 +741,7 @@ mod test {
cx.assert_state(
indoc! {"
The quick brown
- fox jumps|jumps over
+ fox jumpsˇjumps over
the lazy dog"},
Mode::Normal,
);
@@ -749,7 +749,7 @@ mod test {
cx.set_state(
indoc! {"
The quick brown
- fox ju|mps over
+ fox juˇmps over
the lazy dog"},
Mode::Visual { line: true },
);
@@ -757,13 +757,13 @@ mod test {
cx.assert_state(
indoc! {"
The quick brown
- the la|zy dog"},
+ the laˇzy dog"},
Mode::Normal,
);
cx.set_state(
indoc! {"
The quick brown
- the [laz}y dog"},
+ the «lazˇ»y dog"},
Mode::Visual { line: false },
);
cx.simulate_keystroke("p");
@@ -771,7 +771,7 @@ mod test {
indoc! {"
The quick brown
the
- |fox jumps over
+ ˇfox jumps over
dog"},
Mode::Normal,
);
diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs
index caccda8ecf..a05b9ac1a8 100644
--- a/crates/workspace/src/pane.rs
+++ b/crates/workspace/src/pane.rs
@@ -1112,7 +1112,7 @@ impl View for Pane {
&cx.global::().theme.workspace.tab_bar;
let style =
theme.pane_button.style_for(mouse_state, false);
- Svg::new("icons/bolt_12.svg")
+ Svg::new("icons/plus_12.svg")
.with_color(style.color)
.constrained()
.with_width(style.icon_width)