Rework editors to register and query buffers on scroll (#40388)
Preparation to https://github.com/zed-industries/zed/pull/40183 Moves https://github.com/zed-industries/zed/pull/22958 further: now, instead of selection, scrolling the buffer into view is enough to get registered and, later, be queried for its LSP data such as inlay hints, diagnostics and document colors. This effectively undoes https://github.com/zed-industries/zed/pull/28855 as now we try to register whatever's visible more aggressively, instead of implicitly via inlay hints. Release Notes: - Reworked editors to register and query buffers on scroll
This commit is contained in:
+119
-121
@@ -1190,6 +1190,7 @@ pub struct Editor {
|
||||
inline_value_cache: InlineValueCache,
|
||||
selection_drag_state: SelectionDragState,
|
||||
colors: Option<LspColorData>,
|
||||
post_scroll_update: Task<()>,
|
||||
refresh_colors_task: Task<()>,
|
||||
folding_newlines: Task<()>,
|
||||
pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
|
||||
@@ -1786,7 +1787,7 @@ impl Editor {
|
||||
|
||||
fn new_internal(
|
||||
mode: EditorMode,
|
||||
buffer: Entity<MultiBuffer>,
|
||||
multi_buffer: Entity<MultiBuffer>,
|
||||
project: Option<Entity<Project>>,
|
||||
display_map: Option<Entity<DisplayMap>>,
|
||||
window: &mut Window,
|
||||
@@ -1844,7 +1845,7 @@ impl Editor {
|
||||
let display_map = display_map.unwrap_or_else(|| {
|
||||
cx.new(|cx| {
|
||||
DisplayMap::new(
|
||||
buffer.clone(),
|
||||
multi_buffer.clone(),
|
||||
style.font(),
|
||||
font_size,
|
||||
None,
|
||||
@@ -1857,7 +1858,7 @@ impl Editor {
|
||||
})
|
||||
});
|
||||
|
||||
let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
|
||||
let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
|
||||
|
||||
let blink_manager = cx.new(|cx| {
|
||||
let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
|
||||
@@ -1909,8 +1910,19 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
|
||||
if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
|
||||
editor.update_lsp_data(false, Some(*buffer_id), window, cx);
|
||||
let buffer_id = *buffer_id;
|
||||
if editor.buffer().read(cx).buffer(buffer_id).is_some() {
|
||||
let registered = editor.register_buffer(buffer_id, cx);
|
||||
if registered {
|
||||
editor.update_lsp_data(Some(buffer_id), window, cx);
|
||||
editor.refresh_inlay_hints(
|
||||
InlayHintRefreshReason::RefreshRequested,
|
||||
cx,
|
||||
);
|
||||
refresh_linked_ranges(editor, window, cx);
|
||||
editor.refresh_code_actions(window, cx);
|
||||
editor.refresh_document_highlights(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2029,7 +2041,7 @@ impl Editor {
|
||||
}));
|
||||
}
|
||||
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
|
||||
|
||||
let inlay_hint_settings =
|
||||
inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
|
||||
@@ -2066,8 +2078,8 @@ impl Editor {
|
||||
update_uncommitted_diff_for_buffer(
|
||||
cx.entity(),
|
||||
&project,
|
||||
buffer.read(cx).all_buffers(),
|
||||
buffer.clone(),
|
||||
multi_buffer.read(cx).all_buffers(),
|
||||
multi_buffer.clone(),
|
||||
cx,
|
||||
)
|
||||
.shared(),
|
||||
@@ -2079,7 +2091,7 @@ impl Editor {
|
||||
focus_handle,
|
||||
show_cursor_when_unfocused: false,
|
||||
last_focused_descendant: None,
|
||||
buffer: buffer.clone(),
|
||||
buffer: multi_buffer.clone(),
|
||||
display_map: display_map.clone(),
|
||||
placeholder_display_map: None,
|
||||
selections,
|
||||
@@ -2221,8 +2233,8 @@ impl Editor {
|
||||
_subscriptions: (!is_minimap)
|
||||
.then(|| {
|
||||
vec![
|
||||
cx.observe(&buffer, Self::on_buffer_changed),
|
||||
cx.subscribe_in(&buffer, window, Self::on_buffer_event),
|
||||
cx.observe(&multi_buffer, Self::on_buffer_changed),
|
||||
cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
|
||||
cx.observe_in(&display_map, window, Self::on_display_map_changed),
|
||||
cx.observe(&blink_manager, |_, _, cx| cx.notify()),
|
||||
cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
|
||||
@@ -2248,6 +2260,7 @@ impl Editor {
|
||||
colors: None,
|
||||
refresh_colors_task: Task::ready(()),
|
||||
next_color_inlay_id: 0,
|
||||
post_scroll_update: Task::ready(()),
|
||||
linked_edit_ranges: Default::default(),
|
||||
in_project_search: false,
|
||||
previous_search_ranges: None,
|
||||
@@ -2370,7 +2383,7 @@ impl Editor {
|
||||
editor.selection_history.mode = SelectionHistoryMode::Normal;
|
||||
|
||||
editor.scroll_manager.show_scrollbars(window, cx);
|
||||
jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
|
||||
jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
|
||||
|
||||
if full_mode {
|
||||
let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
|
||||
@@ -2382,24 +2395,13 @@ impl Editor {
|
||||
|
||||
editor.go_to_active_debug_line(window, cx);
|
||||
|
||||
if let Some(buffer) = buffer.read(cx).as_singleton()
|
||||
&& let Some(project) = editor.project()
|
||||
{
|
||||
let handle = project.update(cx, |project, cx| {
|
||||
project.register_buffer_with_language_servers(&buffer, cx)
|
||||
});
|
||||
editor
|
||||
.registered_buffers
|
||||
.insert(buffer.read(cx).remote_id(), handle);
|
||||
if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
|
||||
editor.register_buffer(buffer.read(cx).remote_id(), cx);
|
||||
}
|
||||
|
||||
editor.minimap =
|
||||
editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
|
||||
editor.colors = Some(LspColorData::new(cx));
|
||||
editor.update_lsp_data(false, None, window, cx);
|
||||
}
|
||||
|
||||
if editor.mode.is_full() {
|
||||
editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
|
||||
}
|
||||
|
||||
@@ -2899,20 +2901,6 @@ impl Editor {
|
||||
self.collapse_matches = collapse_matches;
|
||||
}
|
||||
|
||||
fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
|
||||
let buffers = self.buffer.read(cx).all_buffers();
|
||||
let Some(project) = self.project.as_ref() else {
|
||||
return;
|
||||
};
|
||||
project.update(cx, |project, cx| {
|
||||
for buffer in buffers {
|
||||
self.registered_buffers
|
||||
.entry(buffer.read(cx).remote_id())
|
||||
.or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
|
||||
if self.collapse_matches {
|
||||
return range.start..range.start;
|
||||
@@ -3112,19 +3100,8 @@ impl Editor {
|
||||
}
|
||||
|
||||
if local {
|
||||
if let Some(buffer_id) = new_cursor_position.buffer_id
|
||||
&& !self.registered_buffers.contains_key(&buffer_id)
|
||||
&& let Some(project) = self.project.as_ref()
|
||||
{
|
||||
project.update(cx, |project, cx| {
|
||||
let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
|
||||
return;
|
||||
};
|
||||
self.registered_buffers.insert(
|
||||
buffer_id,
|
||||
project.register_buffer_with_language_servers(&buffer, cx),
|
||||
);
|
||||
})
|
||||
if let Some(buffer_id) = new_cursor_position.buffer_id {
|
||||
self.register_buffer(buffer_id, cx);
|
||||
}
|
||||
|
||||
let mut context_menu = self.context_menu.borrow_mut();
|
||||
@@ -3174,11 +3151,12 @@ impl Editor {
|
||||
}
|
||||
self.refresh_code_actions(window, cx);
|
||||
self.refresh_document_highlights(cx);
|
||||
refresh_linked_ranges(self, window, cx);
|
||||
|
||||
self.refresh_selected_text_highlights(false, window, cx);
|
||||
refresh_matching_bracket_highlights(self, cx);
|
||||
self.update_visible_edit_prediction(window, cx);
|
||||
self.edit_prediction_requires_modifier_in_indent_conflict = true;
|
||||
linked_editing_ranges::refresh_linked_ranges(self, window, cx);
|
||||
self.inline_blame_popover.take();
|
||||
if self.git_blame_inline_enabled {
|
||||
self.start_inline_blame_timer(window, cx);
|
||||
@@ -4444,7 +4422,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
|
||||
linked_editing_ranges::refresh_linked_ranges(this, window, cx);
|
||||
refresh_linked_ranges(this, window, cx);
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
|
||||
});
|
||||
@@ -5305,12 +5283,18 @@ impl Editor {
|
||||
}
|
||||
};
|
||||
|
||||
let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
|
||||
visible_excerpts.retain(|_, (buffer, _, _)| {
|
||||
self.registered_buffers
|
||||
.contains_key(&buffer.read(cx).remote_id())
|
||||
});
|
||||
|
||||
if let Some(InlaySplice {
|
||||
to_remove,
|
||||
to_insert,
|
||||
}) = self.inlay_hint_cache.spawn_hint_refresh(
|
||||
reason_description,
|
||||
self.visible_excerpts(required_languages.as_ref(), cx),
|
||||
visible_excerpts,
|
||||
invalidate_cache,
|
||||
ignore_debounce,
|
||||
cx,
|
||||
@@ -10107,7 +10091,7 @@ impl Editor {
|
||||
})
|
||||
}
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
linked_editing_ranges::refresh_linked_ranges(this, window, cx);
|
||||
refresh_linked_ranges(this, window, cx);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16974,40 +16958,31 @@ impl Editor {
|
||||
editor
|
||||
})
|
||||
});
|
||||
editor.update(cx, |editor, cx| {
|
||||
match multibuffer_selection_mode {
|
||||
MultibufferSelectionMode::First => {
|
||||
if let Some(first_range) = ranges.first() {
|
||||
editor.change_selections(
|
||||
SelectionEffects::no_scroll(),
|
||||
window,
|
||||
cx,
|
||||
|selections| {
|
||||
selections.clear_disjoint();
|
||||
selections
|
||||
.select_anchor_ranges(std::iter::once(first_range.clone()));
|
||||
},
|
||||
);
|
||||
}
|
||||
editor.highlight_background::<Self>(
|
||||
&ranges,
|
||||
|theme| theme.colors().editor_highlighted_line_background,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
MultibufferSelectionMode::All => {
|
||||
editor.update(cx, |editor, cx| match multibuffer_selection_mode {
|
||||
MultibufferSelectionMode::First => {
|
||||
if let Some(first_range) = ranges.first() {
|
||||
editor.change_selections(
|
||||
SelectionEffects::no_scroll(),
|
||||
window,
|
||||
cx,
|
||||
|selections| {
|
||||
selections.clear_disjoint();
|
||||
selections.select_anchor_ranges(ranges);
|
||||
selections.select_anchor_ranges(std::iter::once(first_range.clone()));
|
||||
},
|
||||
);
|
||||
}
|
||||
editor.highlight_background::<Self>(
|
||||
&ranges,
|
||||
|theme| theme.colors().editor_highlighted_line_background,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
MultibufferSelectionMode::All => {
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
|
||||
selections.clear_disjoint();
|
||||
selections.select_anchor_ranges(ranges);
|
||||
});
|
||||
}
|
||||
editor.register_buffers_with_language_servers(cx);
|
||||
});
|
||||
|
||||
let item = Box::new(editor);
|
||||
@@ -17854,7 +17829,7 @@ impl Editor {
|
||||
window: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<()> {
|
||||
if !self.mode().is_full() {
|
||||
if self.ignore_lsp_data() {
|
||||
return None;
|
||||
}
|
||||
let pull_diagnostics_settings = ProjectSettings::get_global(cx)
|
||||
@@ -17866,8 +17841,14 @@ impl Editor {
|
||||
let project = self.project()?.downgrade();
|
||||
let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
|
||||
let mut buffers = self.buffer.read(cx).all_buffers();
|
||||
if let Some(buffer_id) = buffer_id {
|
||||
buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
|
||||
buffers.retain(|buffer| {
|
||||
let buffer_id_to_retain = buffer.read(cx).remote_id();
|
||||
buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
|
||||
&& self.registered_buffers.contains_key(&buffer_id_to_retain)
|
||||
});
|
||||
if buffers.is_empty() {
|
||||
self.pull_diagnostics_task = Task::ready(());
|
||||
return None;
|
||||
}
|
||||
|
||||
self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
|
||||
@@ -20864,10 +20845,7 @@ impl Editor {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
multi_buffer::Event::Edited {
|
||||
singleton_buffer_edited,
|
||||
edited_buffer,
|
||||
} => {
|
||||
multi_buffer::Event::Edited { edited_buffer } => {
|
||||
self.scrollbar_marker_state.dirty = true;
|
||||
self.active_indent_guides_state.dirty = true;
|
||||
self.refresh_active_diagnostics(cx);
|
||||
@@ -20878,31 +20856,16 @@ impl Editor {
|
||||
if self.has_active_edit_prediction() {
|
||||
self.update_visible_edit_prediction(window, cx);
|
||||
}
|
||||
if let Some(project) = self.project.as_ref()
|
||||
&& let Some(edited_buffer) = edited_buffer
|
||||
{
|
||||
project.update(cx, |project, cx| {
|
||||
self.registered_buffers
|
||||
.entry(edited_buffer.read(cx).remote_id())
|
||||
.or_insert_with(|| {
|
||||
project.register_buffer_with_language_servers(edited_buffer, cx)
|
||||
});
|
||||
});
|
||||
}
|
||||
cx.emit(EditorEvent::BufferEdited);
|
||||
cx.emit(SearchEvent::MatchesInvalidated);
|
||||
|
||||
if let Some(buffer) = edited_buffer {
|
||||
self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
|
||||
}
|
||||
|
||||
if *singleton_buffer_edited {
|
||||
if let Some(buffer) = edited_buffer
|
||||
&& buffer.read(cx).file().is_none()
|
||||
{
|
||||
if let Some(edited_buffer) = edited_buffer {
|
||||
if edited_buffer.read(cx).file().is_none() {
|
||||
cx.emit(EditorEvent::TitleChanged);
|
||||
}
|
||||
if let Some(project) = &self.project {
|
||||
|
||||
let buffer_id = edited_buffer.read(cx).remote_id();
|
||||
if let Some(project) = self.project.clone() {
|
||||
self.register_buffer(buffer_id, cx);
|
||||
self.update_lsp_data(Some(buffer_id), window, cx);
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer
|
||||
@@ -20929,6 +20892,9 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
cx.emit(EditorEvent::BufferEdited);
|
||||
cx.emit(SearchEvent::MatchesInvalidated);
|
||||
|
||||
let Some(project) = &self.project else { return };
|
||||
let (telemetry, is_via_ssh) = {
|
||||
let project = project.read(cx);
|
||||
@@ -20936,7 +20902,6 @@ impl Editor {
|
||||
let is_via_ssh = project.is_via_remote_server();
|
||||
(telemetry, is_via_ssh)
|
||||
};
|
||||
refresh_linked_ranges(self, window, cx);
|
||||
telemetry.log_edit_event("editor", is_via_ssh);
|
||||
}
|
||||
multi_buffer::Event::ExcerptsAdded {
|
||||
@@ -20958,24 +20923,22 @@ impl Editor {
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
if self.active_diagnostics != ActiveDiagnostic::All {
|
||||
self.update_lsp_data(false, Some(buffer_id), window, cx);
|
||||
}
|
||||
self.update_lsp_data(Some(buffer_id), window, cx);
|
||||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
cx.emit(EditorEvent::ExcerptsAdded {
|
||||
buffer: buffer.clone(),
|
||||
predecessor: *predecessor,
|
||||
excerpts: excerpts.clone(),
|
||||
});
|
||||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
}
|
||||
multi_buffer::Event::ExcerptsRemoved {
|
||||
ids,
|
||||
removed_buffer_ids,
|
||||
} => {
|
||||
self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
|
||||
let buffer = self.buffer.read(cx);
|
||||
self.registered_buffers
|
||||
.retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
|
||||
for buffer_id in removed_buffer_ids {
|
||||
self.registered_buffers.remove(buffer_id);
|
||||
}
|
||||
jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
|
||||
cx.emit(EditorEvent::ExcerptsRemoved {
|
||||
ids: ids.clone(),
|
||||
@@ -21007,7 +20970,7 @@ impl Editor {
|
||||
self.tasks_update_task = Some(self.refresh_runnables(window, cx));
|
||||
}
|
||||
multi_buffer::Event::LanguageChanged(buffer_id) => {
|
||||
linked_editing_ranges::refresh_linked_ranges(self, window, cx);
|
||||
self.registered_buffers.remove(&buffer_id);
|
||||
jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
|
||||
cx.emit(EditorEvent::Reparsed(*buffer_id));
|
||||
cx.notify();
|
||||
@@ -21148,7 +21111,7 @@ impl Editor {
|
||||
if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
|
||||
self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
|
||||
}
|
||||
self.refresh_colors(false, None, window, cx);
|
||||
self.refresh_colors_for_visible_range(None, window, cx);
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
@@ -22060,13 +22023,48 @@ impl Editor {
|
||||
|
||||
fn update_lsp_data(
|
||||
&mut self,
|
||||
ignore_cache: bool,
|
||||
for_buffer: Option<BufferId>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<'_, Self>,
|
||||
) {
|
||||
self.pull_diagnostics(for_buffer, window, cx);
|
||||
self.refresh_colors(ignore_cache, for_buffer, window, cx);
|
||||
self.refresh_colors_for_visible_range(for_buffer, window, cx);
|
||||
}
|
||||
|
||||
fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
|
||||
// Singletons are registered on editor creation.
|
||||
if self.ignore_lsp_data() || self.buffer().read(cx).is_singleton() {
|
||||
return;
|
||||
}
|
||||
for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
|
||||
self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
|
||||
if !self.registered_buffers.contains_key(&buffer_id)
|
||||
&& let Some(project) = self.project.as_ref()
|
||||
{
|
||||
if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
|
||||
project.update(cx, |project, cx| {
|
||||
self.registered_buffers.insert(
|
||||
buffer_id,
|
||||
project.register_buffer_with_language_servers(&buffer, cx),
|
||||
);
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
self.registered_buffers.remove(&buffer_id);
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn ignore_lsp_data(&self) -> bool {
|
||||
// `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
|
||||
// skip any LSP updates for it.
|
||||
self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2394,6 +2394,8 @@ pub mod tests {
|
||||
editor.scroll_screen(&ScrollAmount::Page(1.0), window, cx);
|
||||
})
|
||||
.unwrap();
|
||||
// Wait for the first hints request to fire off
|
||||
cx.executor().advance_clock(Duration::from_millis(100));
|
||||
cx.executor().run_until_parked();
|
||||
editor
|
||||
.update(cx, |editor, window, cx| {
|
||||
@@ -2752,6 +2754,23 @@ pub mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
editor
|
||||
.update(cx, |editor, _window, cx| {
|
||||
let expected_hints = vec![
|
||||
"main hint #0".to_string(),
|
||||
"main hint #1".to_string(),
|
||||
"main hint #2".to_string(),
|
||||
"main hint #3".to_string(),
|
||||
"main hint #4".to_string(),
|
||||
"main hint #5".to_string(),
|
||||
];
|
||||
assert_eq!(expected_hints, sorted_cached_hint_labels(editor),
|
||||
"New hints are not shown right after scrolling, we need to wait for the buffer to be registered");
|
||||
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
|
||||
})
|
||||
.unwrap();
|
||||
cx.executor().advance_clock(Duration::from_millis(100));
|
||||
cx.executor().run_until_parked();
|
||||
editor
|
||||
.update(cx, |editor, _window, cx| {
|
||||
let expected_hints = vec![
|
||||
@@ -2766,7 +2785,7 @@ pub mod tests {
|
||||
"other hint #2".to_string(),
|
||||
];
|
||||
assert_eq!(expected_hints, sorted_cached_hint_labels(editor),
|
||||
"With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
|
||||
"After scrolling to the new buffer and waiting for it to be registered, new hints should appear");
|
||||
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
|
||||
})
|
||||
.unwrap();
|
||||
@@ -2853,15 +2872,18 @@ pub mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
// Wait again to trigger the inlay hints fetch on scroll
|
||||
cx.executor().advance_clock(Duration::from_millis(100));
|
||||
cx.executor().run_until_parked();
|
||||
editor
|
||||
.update(cx, |editor, _window, cx| {
|
||||
let expected_hints = vec![
|
||||
"main hint #0".to_string(),
|
||||
"main hint #1".to_string(),
|
||||
"main hint #2".to_string(),
|
||||
"main hint #3".to_string(),
|
||||
"main hint #4".to_string(),
|
||||
"main hint #5".to_string(),
|
||||
"main hint(edited) #0".to_string(),
|
||||
"main hint(edited) #1".to_string(),
|
||||
"main hint(edited) #2".to_string(),
|
||||
"main hint(edited) #3".to_string(),
|
||||
"main hint(edited) #4".to_string(),
|
||||
"main hint(edited) #5".to_string(),
|
||||
"other hint(edited) #0".to_string(),
|
||||
"other hint(edited) #1".to_string(),
|
||||
];
|
||||
|
||||
@@ -48,7 +48,7 @@ pub(super) fn refresh_linked_ranges(
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) -> Option<()> {
|
||||
if editor.pending_rename.is_some() {
|
||||
if editor.ignore_lsp_data() || editor.pending_rename.is_some() {
|
||||
return None;
|
||||
}
|
||||
let project = editor.project()?.downgrade();
|
||||
|
||||
@@ -2,11 +2,11 @@ use std::{cmp, ops::Range};
|
||||
|
||||
use collections::HashMap;
|
||||
use futures::future::join_all;
|
||||
use gpui::{Hsla, Rgba};
|
||||
use gpui::{Hsla, Rgba, Task};
|
||||
use itertools::Itertools;
|
||||
use language::point_from_lsp;
|
||||
use multi_buffer::Anchor;
|
||||
use project::{DocumentColor, lsp_store::LspFetchStrategy};
|
||||
use project::DocumentColor;
|
||||
use settings::Settings as _;
|
||||
use text::{Bias, BufferId, OffsetRangeExt as _};
|
||||
use ui::{App, Context, Window};
|
||||
@@ -143,14 +143,13 @@ impl LspColorData {
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
pub(super) fn refresh_colors(
|
||||
pub(super) fn refresh_colors_for_visible_range(
|
||||
&mut self,
|
||||
ignore_cache: bool,
|
||||
buffer_id: Option<BufferId>,
|
||||
_: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if !self.mode().is_full() {
|
||||
if self.ignore_lsp_data() {
|
||||
return;
|
||||
}
|
||||
let Some(project) = self.project.clone() else {
|
||||
@@ -169,7 +168,9 @@ impl Editor {
|
||||
.into_values()
|
||||
.map(|(buffer, ..)| buffer)
|
||||
.filter(|editor_buffer| {
|
||||
buffer_id.is_none_or(|buffer_id| buffer_id == editor_buffer.read(cx).remote_id())
|
||||
let editor_buffer_id = editor_buffer.read(cx).remote_id();
|
||||
buffer_id.is_none_or(|buffer_id| buffer_id == editor_buffer_id)
|
||||
&& self.registered_buffers.contains_key(&editor_buffer_id)
|
||||
})
|
||||
.unique_by(|buffer| buffer.read(cx).remote_id())
|
||||
.collect::<Vec<_>>();
|
||||
@@ -179,21 +180,20 @@ impl Editor {
|
||||
.into_iter()
|
||||
.filter_map(|buffer| {
|
||||
let buffer_id = buffer.read(cx).remote_id();
|
||||
let fetch_strategy = if ignore_cache {
|
||||
LspFetchStrategy::IgnoreCache
|
||||
} else {
|
||||
LspFetchStrategy::UseCache {
|
||||
known_cache_version: self.colors.as_ref().and_then(|colors| {
|
||||
Some(colors.buffer_colors.get(&buffer_id)?.cache_version_used)
|
||||
}),
|
||||
}
|
||||
};
|
||||
let colors_task = lsp_store.document_colors(fetch_strategy, buffer, cx)?;
|
||||
let known_cache_version = self.colors.as_ref().and_then(|colors| {
|
||||
Some(colors.buffer_colors.get(&buffer_id)?.cache_version_used)
|
||||
});
|
||||
let colors_task = lsp_store.document_colors(known_cache_version, buffer, cx)?;
|
||||
Some(async move { (buffer_id, colors_task.await) })
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
if all_colors_task.is_empty() {
|
||||
self.refresh_colors_task = Task::ready(());
|
||||
return;
|
||||
}
|
||||
|
||||
self.refresh_colors_task = cx.spawn(async move |editor, cx| {
|
||||
cx.background_executor()
|
||||
.timer(FETCH_COLORS_DEBOUNCE_TIMEOUT)
|
||||
|
||||
@@ -494,15 +494,15 @@ impl Editor {
|
||||
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_in(window, async move |editor, cx| {
|
||||
self.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
|
||||
editor
|
||||
.update_in(cx, |editor, window, cx| {
|
||||
editor.register_visible_buffers(cx);
|
||||
editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
editor.refresh_colors(false, None, window, cx);
|
||||
editor.update_lsp_data(None, window, cx);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.detach()
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,8 +613,19 @@ impl Editor {
|
||||
cx,
|
||||
);
|
||||
|
||||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
self.refresh_colors(false, None, window, cx);
|
||||
self.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(50))
|
||||
.await;
|
||||
editor
|
||||
.update_in(cx, |editor, window, cx| {
|
||||
editor.register_visible_buffers(cx);
|
||||
editor.refresh_colors_for_visible_range(None, window, cx);
|
||||
editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
})
|
||||
.ok();
|
||||
});
|
||||
|
||||
editor_was_scrolled
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user