Cargo.lock 🔗
@@ -1732,6 +1732,7 @@ dependencies = [
"regex",
"smol",
"theme",
+ "unindent",
"workspace",
]
Max Brunsfeld created
Cargo.lock | 1
crates/editor/src/editor.rs | 28 +++++--
crates/editor/src/element.rs | 4
crates/find/Cargo.toml | 6 +
crates/find/src/find.rs | 150 ++++++++++++++++++++++++++++++++++++++
5 files changed, 179 insertions(+), 10 deletions(-)
@@ -1732,6 +1732,7 @@ dependencies = [
"regex",
"smol",
"theme",
+ "unindent",
"workspace",
]
@@ -3750,11 +3750,23 @@ impl Editor {
cx.notify();
}
+ #[cfg(feature = "test-support")]
+ pub fn highlighted_ranges(
+ &mut self,
+ cx: &mut ViewContext<Self>,
+ ) -> Vec<(Range<DisplayPoint>, Color)> {
+ let snapshot = self.snapshot(cx);
+ let buffer = &snapshot.buffer_snapshot;
+ let start = buffer.anchor_before(0);
+ let end = buffer.anchor_after(buffer.len());
+ self.highlighted_ranges_in_range(start..end, &snapshot)
+ }
+
pub fn highlighted_ranges_in_range(
&self,
search_range: Range<Anchor>,
display_snapshot: &DisplaySnapshot,
- ) -> Vec<(Color, Range<DisplayPoint>)> {
+ ) -> Vec<(Range<DisplayPoint>, Color)> {
let mut results = Vec::new();
let buffer = &display_snapshot.buffer_snapshot;
for (color, ranges) in self.highlighted_ranges.values() {
@@ -3780,7 +3792,7 @@ impl Editor {
.end
.to_point(buffer)
.to_display_point(display_snapshot);
- results.push((*color, start..end))
+ results.push((start..end, *color))
}
}
results
@@ -6679,20 +6691,20 @@ mod tests {
),
&[
(
- Color::red(),
DisplayPoint::new(4, 2)..DisplayPoint::new(4, 4),
+ Color::red(),
),
(
- Color::red(),
DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5),
+ Color::red(),
),
(
+ DisplayPoint::new(3, 2)..DisplayPoint::new(3, 5),
Color::green(),
- DisplayPoint::new(3, 2)..DisplayPoint::new(3, 5)
),
(
+ DisplayPoint::new(5, 3)..DisplayPoint::new(5, 6),
Color::green(),
- DisplayPoint::new(5, 3)..DisplayPoint::new(5, 6)
),
]
);
@@ -6702,9 +6714,9 @@ mod tests {
&snapshot,
),
&[(
- Color::red(),
DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5),
- ),]
+ Color::red(),
+ )]
);
});
}
@@ -316,7 +316,7 @@ impl EditorElement {
cx.scene.push_layer(Some(bounds));
- for (color, range) in &layout.highlighted_ranges {
+ for (range, color) in &layout.highlighted_ranges {
self.paint_highlighted_range(
range.clone(),
start_row,
@@ -997,7 +997,7 @@ pub struct LayoutState {
line_height: f32,
em_width: f32,
em_advance: f32,
- highlighted_ranges: Vec<(Color, Range<DisplayPoint>)>,
+ highlighted_ranges: Vec<(Range<DisplayPoint>, Color)>,
selections: HashMap<ReplicaId, Vec<text::Selection<DisplayPoint>>>,
text_offset: Vector2F,
}
@@ -17,3 +17,9 @@ anyhow = "1.0"
postage = { version = "0.4.1", features = ["futures-traits"] }
regex = "1.5"
smol = { version = "1.2" }
+
+[dev-dependencies]
+editor = { path = "../editor", features = ["test-support"] }
+gpui = { path = "../gpui", features = ["test-support"] }
+workspace = { path = "../workspace", features = ["test-support"] }
+unindent = "0.1"
@@ -148,6 +148,16 @@ impl FindBar {
}
}
+ #[cfg(test)]
+ fn set_query(&mut self, query: &str, cx: &mut ViewContext<Self>) {
+ self.query_editor.update(cx, |query_editor, cx| {
+ query_editor.buffer().update(cx, |query_buffer, cx| {
+ let len = query_buffer.read(cx).len();
+ query_buffer.edit([0..len], query, cx);
+ });
+ });
+ }
+
fn render_mode_button(
&self,
icon: &str,
@@ -397,3 +407,143 @@ async fn regex_search(
Ok(ranges)
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use editor::{DisplayPoint, Editor, EditorSettings, MultiBuffer};
+ use gpui::{color::Color, TestAppContext};
+ use std::sync::Arc;
+ use unindent::Unindent as _;
+
+ #[gpui::test]
+ async fn test_find_simple(mut cx: TestAppContext) {
+ let fonts = cx.font_cache();
+ let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default());
+ theme.find.match_background = Color::red();
+ let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap();
+
+ let buffer = cx.update(|cx| {
+ MultiBuffer::build_simple(
+ &r#"
+ A regular expression (shortened as regex or regexp;[1] also referred to as
+ rational expression[2][3]) is a sequence of characters that specifies a search
+ pattern in text. Usually such patterns are used by string-searching algorithms
+ for "find" or "find and replace" operations on strings, or for input validation.
+ "#
+ .unindent(),
+ cx,
+ )
+ });
+ let editor = cx.add_view(Default::default(), |cx| {
+ Editor::new(buffer.clone(), Arc::new(EditorSettings::test), cx)
+ });
+
+ let find_bar = cx.add_view(Default::default(), |cx| {
+ let mut find_bar = FindBar::new(watch::channel_with(settings).1, cx);
+ find_bar.active_item_changed(Some(Box::new(editor.clone())), cx);
+ find_bar
+ });
+
+ // default: case-insensitive substring search.
+ find_bar.update(&mut cx, |find_bar, cx| {
+ find_bar.set_query("us", cx);
+ });
+ editor.next_notification(&cx).await;
+ editor.update(&mut cx, |editor, cx| {
+ assert_eq!(
+ editor.highlighted_ranges(cx),
+ &[
+ (
+ DisplayPoint::new(2, 17)..DisplayPoint::new(2, 19),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),
+ Color::red(),
+ ),
+ ]
+ );
+ });
+
+ // switch to case sensitive search
+ find_bar.update(&mut cx, |find_bar, cx| {
+ find_bar.toggle_mode(&ToggleMode(SearchMode::CaseSensitive), cx);
+ });
+ editor.next_notification(&cx).await;
+ editor.update(&mut cx, |editor, cx| {
+ assert_eq!(
+ editor.highlighted_ranges(cx),
+ &[(
+ DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),
+ Color::red(),
+ ),]
+ );
+ });
+
+ find_bar.update(&mut cx, |find_bar, cx| {
+ find_bar.set_query("or", cx);
+ });
+ editor.next_notification(&cx).await;
+ editor.update(&mut cx, |editor, cx| {
+ assert_eq!(
+ editor.highlighted_ranges(cx),
+ &[
+ (
+ DisplayPoint::new(0, 24)..DisplayPoint::new(0, 26),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(2, 71)..DisplayPoint::new(2, 73),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(3, 1)..DisplayPoint::new(3, 3),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(3, 60)..DisplayPoint::new(3, 62),
+ Color::red(),
+ ),
+ ]
+ );
+ });
+
+ // switch to whole word search
+ find_bar.update(&mut cx, |find_bar, cx| {
+ find_bar.toggle_mode(&ToggleMode(SearchMode::WholeWord), cx);
+ });
+ editor.next_notification(&cx).await;
+ editor.update(&mut cx, |editor, cx| {
+ assert_eq!(
+ editor.highlighted_ranges(cx),
+ &[
+ (
+ DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13),
+ Color::red(),
+ ),
+ (
+ DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58),
+ Color::red(),
+ ),
+ ]
+ );
+ });
+ }
+}