diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 288bc8e7afaa5c972eba2b9cb6fbf09af6043249..5ff7f09ff88ddb58734c5794b3e719d6784e3629 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -7896,6 +7896,8 @@ async fn test_mutual_editor_inlay_hint_cache_update( .unwrap(); let workspace_a = client_a.build_workspace(&project_a, cx_a); + cx_a.foreground().start_waiting(); + let editor_a = workspace_a .update(cx_a, |workspace, cx| { workspace.open_path((worktree_id, "main.rs"), None, true, cx) @@ -7904,58 +7906,8 @@ async fn test_mutual_editor_inlay_hint_cache_update( .unwrap() .downcast::() .unwrap(); - cx_a.foreground().run_until_parked(); - editor_a.update(cx_a, |editor, _| { - assert!( - extract_hint_labels(editor).is_empty(), - "No inlays should be in the new cache" - ); - let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Cache should use editor settings to get the allowed hint kinds" - ); - assert_eq!( - inlay_cache.version, 0, - "New cache should have no version updates" - ); - }); - let workspace_b = client_b.build_workspace(&project_b, cx_b); - let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), None, true, cx) - }) - .await - .unwrap() - .downcast::() - .unwrap(); - cx_b.foreground().run_until_parked(); - editor_b.update(cx_b, |editor, _| { - assert!( - extract_hint_labels(editor).is_empty(), - "No inlays should be in the new cache" - ); - let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Cache should use editor settings to get the allowed hint kinds" - ); - assert_eq!( - inlay_cache.version, 0, - "New cache should have no version updates" - ); - }); - - cx_a.foreground().start_waiting(); - let mut edits_made = 0; let fake_language_server = fake_language_servers.next().await.unwrap(); - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([13..13].clone())); - editor.handle_input(":", cx); - cx.focus(&editor_b); - edits_made += 1; - }); let next_call_id = Arc::new(AtomicU32::new(0)); fake_language_server .handle_request::(move |params, _| { @@ -7992,37 +7944,77 @@ async fn test_mutual_editor_inlay_hint_cache_update( cx_a.foreground().finish_waiting(); cx_a.foreground().run_until_parked(); - fn extract_hint_labels(editor: &Editor) -> Vec { - let mut labels = Vec::new(); - for (_, excerpt_hints) in &editor.inlay_hint_cache().hints { - let excerpt_hints = excerpt_hints.read(); - for (_, inlay) in excerpt_hints.hints.iter() { - match &inlay.label { - project::InlayHintLabel::String(s) => labels.push(s.to_string()), - _ => unreachable!(), - } - } - } - labels - } - + let mut edits_made = 0; + edits_made += 1; editor_a.update(cx_a, |editor, _| { assert_eq!( vec!["0".to_string()], extract_hint_labels(editor), - "Host should get hints from the 1st edit and 1st LSP query" + "Host should get its first hints when opens an editor" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test"); + assert_eq!( + inlay_cache.allowed_hint_kinds, allowed_hint_kinds, + "Cache should use editor settings to get the allowed hint kinds" + ); assert_eq!( inlay_cache.version, edits_made, - "Each editor should track its own inlay cache history, which should be incremented after every cache/view change" + "Host editor should track its own inlay cache history, which should be incremented after every cache/view change" ); }); + let workspace_b = client_b.build_workspace(&project_b, cx_b); + let editor_b = workspace_b + .update(cx_b, |workspace, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + + cx_b.foreground().run_until_parked(); editor_b.update(cx_b, |editor, _| { assert_eq!( vec!["0".to_string(), "1".to_string()], extract_hint_labels(editor), + "Client should get its first hints when opens an editor" + ); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!( + inlay_cache.allowed_hint_kinds, allowed_hint_kinds, + "Cache should use editor settings to get the allowed hint kinds" + ); + assert_eq!( + inlay_cache.version, edits_made, + "Client editor should track its own inlay cache history, which should be incremented after every cache/view change" + ); + }); + + editor_b.update(cx_b, |editor, cx| { + editor.change_selections(None, cx, |s| s.select_ranges([13..13].clone())); + editor.handle_input(":", cx); + cx.focus(&editor_b); + edits_made += 1; + }); + cx_a.foreground().run_until_parked(); + cx_b.foreground().run_until_parked(); + editor_a.update(cx_a, |editor, _| { + assert_eq!( + vec!["0".to_string(), "1".to_string(), "2".to_string()], + extract_hint_labels(editor), + "Host should get hints from the 1st edit and 1st LSP query" + ); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!( + inlay_cache.allowed_hint_kinds, allowed_hint_kinds, + "Inlay kinds settings never change during the test" + ); + assert_eq!(inlay_cache.version, edits_made); + }); + editor_b.update(cx_b, |editor, _| { + assert_eq!( + vec!["0".to_string(), "1".to_string(), "2".to_string(), "3".to_string()], + extract_hint_labels(editor), "Guest should get hints the 1st edit and 2nd LSP query" ); let inlay_cache = editor.inlay_hint_cache(); @@ -8043,7 +8035,7 @@ async fn test_mutual_editor_inlay_hint_cache_update( cx_b.foreground().run_until_parked(); editor_a.update(cx_a, |editor, _| { assert_eq!( - vec!["0".to_string(), "1".to_string(), "2".to_string()], + vec!["0".to_string(), "1".to_string(), "2".to_string(), "3".to_string(), "4".to_string()], extract_hint_labels(editor), "Host should get hints from 3rd edit, 5th LSP query: \ 4th query was made by guest (but not applied) due to cache invalidation logic" @@ -8061,7 +8053,9 @@ async fn test_mutual_editor_inlay_hint_cache_update( "0".to_string(), "1".to_string(), "2".to_string(), - "3".to_string() + "3".to_string(), + "4".to_string(), + "5".to_string(), ], extract_hint_labels(editor), "Guest should get hints from 3rd edit, 6th LSP query" @@ -8091,7 +8085,9 @@ async fn test_mutual_editor_inlay_hint_cache_update( "1".to_string(), "2".to_string(), "3".to_string(), - "4".to_string() + "4".to_string(), + "5".to_string(), + "6".to_string(), ], extract_hint_labels(editor), "Host should react to /refresh LSP request and get new hints from 7th LSP query" @@ -8108,7 +8104,16 @@ async fn test_mutual_editor_inlay_hint_cache_update( }); editor_b.update(cx_b, |editor, _| { assert_eq!( - vec!["0".to_string(), "1".to_string(), "2".to_string(), "3".to_string(), "4".to_string(), "5".to_string()], + vec![ + "0".to_string(), + "1".to_string(), + "2".to_string(), + "3".to_string(), + "4".to_string(), + "5".to_string(), + "6".to_string(), + "7".to_string(), + ], extract_hint_labels(editor), "Guest should get a /refresh LSP request propagated by host and get new hints from 8th LSP query" ); @@ -8120,7 +8125,7 @@ async fn test_mutual_editor_inlay_hint_cache_update( assert_eq!( inlay_cache.version, edits_made, - "Gues should accepted all edits and bump its cache version every time" + "Guest should accepted all edits and bump its cache version every time" ); }); } @@ -8148,3 +8153,17 @@ fn room_participants(room: &ModelHandle, cx: &mut TestAppContext) -> RoomP RoomParticipants { remote, pending } }) } + +fn extract_hint_labels(editor: &Editor) -> Vec { + let mut labels = Vec::new(); + for (_, excerpt_hints) in &editor.inlay_hint_cache().hints { + let excerpt_hints = excerpt_hints.read(); + for (_, inlay) in excerpt_hints.hints.iter() { + match &inlay.label { + project::InlayHintLabel::String(s) => labels.push(s.to_string()), + _ => unreachable!(), + } + } + } + labels +} diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 4644336bce2b96edb9ed5e5b35d3001e9f1be580..5d5bdd1db406bcb013baac67ac46274e9da8a465 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1393,7 +1393,6 @@ impl Editor { } this.report_editor_event("open", None, cx); - this.refresh_inlays(InlayRefreshReason::ExcerptEdited, cx); this } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 6525e7fc222843fdfa04a94317f4a2a95f6dadcf..7936ed76cb85da078e61493b812c33d83a9a72b4 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1921,7 +1921,7 @@ impl Element for EditorElement { let em_advance = style.text.em_advance(cx.font_cache()); let overscroll = vec2f(em_width, 0.); let snapshot = { - editor.set_visible_line_count(size.y() / line_height); + editor.set_visible_line_count(size.y() / line_height, cx); let editor_width = text_width - gutter_margin - overscroll.x() - em_width; let wrap_width = match editor.soft_wrap_mode(cx) { diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index b0f329c87fb2d5d803d2d0c2630bcd48499be692..d595337428dfce0a8f8fa9d5ad6c001b8072ba3f 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -19,7 +19,8 @@ use crate::{ display_map::{DisplaySnapshot, ToDisplayPoint}, hover_popover::hide_hover, persistence::DB, - Anchor, DisplayPoint, Editor, EditorMode, Event, MultiBufferSnapshot, ToPoint, + Anchor, DisplayPoint, Editor, EditorMode, Event, InlayRefreshReason, MultiBufferSnapshot, + ToPoint, }; use self::{ @@ -293,8 +294,19 @@ impl Editor { self.scroll_manager.visible_line_count } - pub(crate) fn set_visible_line_count(&mut self, lines: f32) { + pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext) { + let opened_first_time = self.scroll_manager.visible_line_count.is_none(); self.scroll_manager.visible_line_count = Some(lines); + if opened_first_time { + cx.spawn(|editor, mut cx| async move { + editor + .update(&mut cx, |editor, cx| { + editor.refresh_inlays(InlayRefreshReason::NewLinesShown, cx) + }) + .ok() + }) + .detach() + } } pub fn set_scroll_position(&mut self, scroll_position: Vector2F, cx: &mut ViewContext) { @@ -322,7 +334,7 @@ impl Editor { ); if !self.is_singleton(cx) { - self.refresh_inlays(crate::InlayRefreshReason::NewLinesShown, cx); + self.refresh_inlays(InlayRefreshReason::NewLinesShown, cx); } }