diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index aad9e96d3a18dfa64a8db4247c6f146e579b8b8c..376aa60ba42f275acbdb8fe5e1f59fdf1d7be711 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1143,6 +1143,7 @@ pub struct Editor { drag_and_drop_selection_enabled: bool, next_color_inlay_id: usize, colors: Option, + folding_newlines: Task<()>, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] @@ -2159,6 +2160,7 @@ impl Editor { mode, selection_drag_state: SelectionDragState::None, 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() { editor @@ -6717,6 +6719,77 @@ impl Editor { }) } + fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context) { + struct NewlineFold; + let type_id = std::any::TypeId::of::(); + 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::>(); + 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::>(); + + (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( &mut self, on_buffer_edit: bool, @@ -17100,16 +17173,6 @@ impl Editor { 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)); if auto_scroll { @@ -19435,6 +19498,7 @@ impl Editor { self.refresh_active_diagnostics(cx); self.refresh_code_actions(window, cx); self.refresh_selected_text_highlights(true, window, cx); + self.refresh_single_line_folds(window, cx); refresh_matching_bracket_highlights(self, window, cx); if self.has_active_inline_completion() { self.update_visible_inline_completion(window, cx); diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 1716acc9850a0c67ef21259c33199e78fd85ab0e..1df4c54b1cbcc8cf9ca1c00aa2d762c6b1dda05f 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -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] fn extract_color_inlays(editor: &Editor, cx: &App) -> Vec { editor