Replace newlines in search bar (#33504)
Release Notes: - search: Pasted newlines are now rendered as "\n" (with an underline), instead of line-wrapping. This should make it much clearer what you're searching for. <img width="675" alt="Screenshot 2025-06-27 at 00 34 52" src="https://github.com/user-attachments/assets/67275bc6-bec1-463f-b351-6b9ed0a6df81" />
This commit is contained in:
parent
d74f3f4ea6
commit
157199b65b
2 changed files with 92 additions and 10 deletions
|
@ -1143,6 +1143,7 @@ pub struct Editor {
|
||||||
drag_and_drop_selection_enabled: bool,
|
drag_and_drop_selection_enabled: bool,
|
||||||
next_color_inlay_id: usize,
|
next_color_inlay_id: usize,
|
||||||
colors: Option<LspColorData>,
|
colors: Option<LspColorData>,
|
||||||
|
folding_newlines: Task<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
|
||||||
|
@ -2159,6 +2160,7 @@ impl Editor {
|
||||||
mode,
|
mode,
|
||||||
selection_drag_state: SelectionDragState::None,
|
selection_drag_state: SelectionDragState::None,
|
||||||
drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
|
drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
|
||||||
|
folding_newlines: Task::ready(()),
|
||||||
};
|
};
|
||||||
if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
|
if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
|
||||||
editor
|
editor
|
||||||
|
@ -6717,6 +6719,77 @@ impl Editor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
|
||||||
|
struct NewlineFold;
|
||||||
|
let type_id = std::any::TypeId::of::<NewlineFold>();
|
||||||
|
if !self.mode.is_single_line() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let snapshot = self.snapshot(window, cx);
|
||||||
|
if snapshot.buffer_snapshot.max_point().row == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let task = cx.background_spawn(async move {
|
||||||
|
let new_newlines = snapshot
|
||||||
|
.buffer_chars_at(0)
|
||||||
|
.filter_map(|(c, i)| {
|
||||||
|
if c == '\n' {
|
||||||
|
Some(
|
||||||
|
snapshot.buffer_snapshot.anchor_after(i)
|
||||||
|
..snapshot.buffer_snapshot.anchor_before(i + 1),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let existing_newlines = snapshot
|
||||||
|
.folds_in_range(0..snapshot.buffer_snapshot.len())
|
||||||
|
.filter_map(|fold| {
|
||||||
|
if fold.placeholder.type_tag == Some(type_id) {
|
||||||
|
Some(fold.range.start..fold.range.end)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
(new_newlines, existing_newlines)
|
||||||
|
});
|
||||||
|
self.folding_newlines = cx.spawn(async move |this, cx| {
|
||||||
|
let (new_newlines, existing_newlines) = task.await;
|
||||||
|
if new_newlines == existing_newlines {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let placeholder = FoldPlaceholder {
|
||||||
|
render: Arc::new(move |_, _, cx| {
|
||||||
|
div()
|
||||||
|
.bg(cx.theme().status().hint_background)
|
||||||
|
.border_b_1()
|
||||||
|
.size_full()
|
||||||
|
.font(ThemeSettings::get_global(cx).buffer_font.clone())
|
||||||
|
.border_color(cx.theme().status().hint)
|
||||||
|
.child("\\n")
|
||||||
|
.into_any()
|
||||||
|
}),
|
||||||
|
constrain_width: false,
|
||||||
|
merge_adjacent: false,
|
||||||
|
type_tag: Some(type_id),
|
||||||
|
};
|
||||||
|
let creases = new_newlines
|
||||||
|
.into_iter()
|
||||||
|
.map(|range| Crease::simple(range, placeholder.clone()))
|
||||||
|
.collect();
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.display_map.update(cx, |display_map, cx| {
|
||||||
|
display_map.remove_folds_with_type(existing_newlines, type_id, cx);
|
||||||
|
display_map.fold(creases, cx);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn refresh_selected_text_highlights(
|
fn refresh_selected_text_highlights(
|
||||||
&mut self,
|
&mut self,
|
||||||
on_buffer_edit: bool,
|
on_buffer_edit: bool,
|
||||||
|
@ -17100,16 +17173,6 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffers_affected = HashSet::default();
|
|
||||||
let multi_buffer = self.buffer().read(cx);
|
|
||||||
for crease in &creases {
|
|
||||||
if let Some((_, buffer, _)) =
|
|
||||||
multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
|
|
||||||
{
|
|
||||||
buffers_affected.insert(buffer.read(cx).remote_id());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
self.display_map.update(cx, |map, cx| map.fold(creases, cx));
|
self.display_map.update(cx, |map, cx| map.fold(creases, cx));
|
||||||
|
|
||||||
if auto_scroll {
|
if auto_scroll {
|
||||||
|
@ -19435,6 +19498,7 @@ impl Editor {
|
||||||
self.refresh_active_diagnostics(cx);
|
self.refresh_active_diagnostics(cx);
|
||||||
self.refresh_code_actions(window, cx);
|
self.refresh_code_actions(window, cx);
|
||||||
self.refresh_selected_text_highlights(true, window, cx);
|
self.refresh_selected_text_highlights(true, window, cx);
|
||||||
|
self.refresh_single_line_folds(window, cx);
|
||||||
refresh_matching_bracket_highlights(self, window, cx);
|
refresh_matching_bracket_highlights(self, window, cx);
|
||||||
if self.has_active_inline_completion() {
|
if self.has_active_inline_completion() {
|
||||||
self.update_visible_inline_completion(window, cx);
|
self.update_visible_inline_completion(window, cx);
|
||||||
|
|
|
@ -22770,6 +22770,24 @@ async fn test_mtime_and_document_colors(cx: &mut TestAppContext) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_newline_replacement_in_single_line(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
let (editor, cx) = cx.add_window_view(Editor::single_line);
|
||||||
|
editor.update_in(cx, |editor, window, cx| {
|
||||||
|
editor.set_text("oops\n\nwow\n", window, cx)
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
assert_eq!(editor.display_text(cx), "oops⋯⋯wow⋯");
|
||||||
|
});
|
||||||
|
editor.update(cx, |editor, cx| editor.edit([(3..5, "")], cx));
|
||||||
|
cx.run_until_parked();
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
assert_eq!(editor.display_text(cx), "oop⋯wow⋯");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn extract_color_inlays(editor: &Editor, cx: &App) -> Vec<Rgba> {
|
fn extract_color_inlays(editor: &Editor, cx: &App) -> Vec<Rgba> {
|
||||||
editor
|
editor
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue