Detailed changes
@@ -37,7 +37,9 @@ pub use block_map::{
use block_map::{BlockRow, BlockSnapshot};
use collections::{HashMap, HashSet};
pub use crease_map::*;
-pub use fold_map::{ChunkRenderer, ChunkRendererContext, Fold, FoldId, FoldPlaceholder, FoldPoint};
+pub use fold_map::{
+ ChunkRenderer, ChunkRendererContext, ChunkRendererId, Fold, FoldId, FoldPlaceholder, FoldPoint,
+};
use fold_map::{FoldMap, FoldSnapshot};
use gpui::{App, Context, Entity, Font, HighlightStyle, LineLayout, Pixels, UnderlineStyle};
pub use inlay_map::Inlay;
@@ -538,7 +540,7 @@ impl DisplayMap {
pub fn update_fold_widths(
&mut self,
- widths: impl IntoIterator<Item = (FoldId, Pixels)>,
+ widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
cx: &mut Context<Self>,
) -> bool {
let snapshot = self.buffer.read(cx).snapshot(cx);
@@ -1,4 +1,4 @@
-use crate::display_map::inlay_map::InlayChunk;
+use crate::{InlayId, display_map::inlay_map::InlayChunk};
use super::{
Highlights,
@@ -277,13 +277,16 @@ impl FoldMapWriter<'_> {
pub(crate) fn update_fold_widths(
&mut self,
- new_widths: impl IntoIterator<Item = (FoldId, Pixels)>,
+ new_widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
) -> (FoldSnapshot, Vec<FoldEdit>) {
let mut edits = Vec::new();
let inlay_snapshot = self.0.snapshot.inlay_snapshot.clone();
let buffer = &inlay_snapshot.buffer;
for (id, new_width) in new_widths {
+ let ChunkRendererId::Fold(id) = id else {
+ continue;
+ };
if let Some(metadata) = self.0.snapshot.fold_metadata_by_id.get(&id).cloned() {
if Some(new_width) != metadata.width {
let buffer_start = metadata.range.start.to_offset(buffer);
@@ -529,7 +532,7 @@ impl FoldMap {
placeholder: Some(TransformPlaceholder {
text: ELLIPSIS,
renderer: ChunkRenderer {
- id: fold.id,
+ id: ChunkRendererId::Fold(fold.id),
render: Arc::new(move |cx| {
(fold.placeholder.render)(
fold_id,
@@ -1267,11 +1270,17 @@ pub struct Chunk<'a> {
pub renderer: Option<ChunkRenderer>,
}
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum ChunkRendererId {
+ Fold(FoldId),
+ Inlay(InlayId),
+}
+
/// A recipe for how the chunk should be presented.
#[derive(Clone)]
pub struct ChunkRenderer {
- /// The id of the fold associated with this chunk.
- pub id: FoldId,
+ /// The id of the renderer associated with this chunk.
+ pub id: ChunkRendererId,
/// Creates a custom element to represent this chunk.
pub render: Arc<dyn Send + Sync + Fn(&mut ChunkRendererContext) -> AnyElement>,
/// If true, the element is constrained to the shaped width of the text.
@@ -1,4 +1,4 @@
-use crate::{ChunkRenderer, HighlightStyles, InlayId, display_map::FoldId};
+use crate::{ChunkRenderer, HighlightStyles, InlayId};
use collections::BTreeSet;
use gpui::{Hsla, Rgba};
use language::{Chunk, Edit, Point, TextSummary};
@@ -14,7 +14,7 @@ use sum_tree::{Bias, Cursor, SumTree};
use text::{Patch, Rope};
use ui::{ActiveTheme, IntoElement as _, ParentElement as _, Styled as _, div};
-use super::{Highlights, custom_highlights::CustomHighlightsChunks};
+use super::{Highlights, custom_highlights::CustomHighlightsChunks, fold_map::ChunkRendererId};
/// Decides where the [`Inlay`]s should be displayed.
///
@@ -338,10 +338,10 @@ impl<'a> Iterator for InlayChunks<'a> {
}
InlayId::Hint(_) => self.highlight_styles.inlay_hint,
InlayId::DebuggerValue(_) => self.highlight_styles.inlay_hint,
- InlayId::Color(id) => {
+ InlayId::Color(_) => {
if let Some(color) = inlay.color {
renderer = Some(ChunkRenderer {
- id: FoldId(id),
+ id: ChunkRendererId::Inlay(inlay.id),
render: Arc::new(move |cx| {
div()
.w_4()
@@ -17333,9 +17333,9 @@ impl Editor {
self.active_indent_guides_state.dirty = true;
}
- pub fn update_fold_widths(
+ pub fn update_renderer_widths(
&mut self,
- widths: impl IntoIterator<Item = (FoldId, Pixels)>,
+ widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
cx: &mut Context<Self>,
) -> bool {
self.display_map
@@ -12,8 +12,8 @@ use crate::{
ToggleFold,
code_context_menus::{CodeActionsMenu, MENU_ASIDE_MAX_WIDTH, MENU_ASIDE_MIN_WIDTH, MENU_GAP},
display_map::{
- Block, BlockContext, BlockStyle, DisplaySnapshot, EditorMargins, FoldId, HighlightKey,
- HighlightedChunk, ToDisplayPoint,
+ Block, BlockContext, BlockStyle, ChunkRendererId, DisplaySnapshot, EditorMargins,
+ HighlightKey, HighlightedChunk, ToDisplayPoint,
},
editor_settings::{
CurrentLineHighlight, DocumentColorsRenderMode, DoubleClickInMultibuffer, Minimap,
@@ -7119,7 +7119,7 @@ pub(crate) struct LineWithInvisibles {
enum LineFragment {
Text(ShapedLine),
Element {
- id: FoldId,
+ id: ChunkRendererId,
element: Option<AnyElement>,
size: Size<Pixels>,
len: usize,
@@ -8297,7 +8297,7 @@ impl Element for EditorElement {
window,
cx,
);
- let new_fold_widths = line_layouts
+ let new_renrerer_widths = line_layouts
.iter()
.flat_map(|layout| &layout.fragments)
.filter_map(|fragment| {
@@ -8308,7 +8308,7 @@ impl Element for EditorElement {
}
});
if self.editor.update(cx, |editor, cx| {
- editor.update_fold_widths(new_fold_widths, cx)
+ editor.update_renderer_widths(new_renrerer_widths, cx)
}) {
// If the fold widths have changed, we need to prepaint
// the element again to account for any changes in
@@ -19,18 +19,21 @@ use crate::{
#[derive(Debug)]
pub(super) struct LspColorData {
- cache_version_used: usize,
+ buffer_colors: HashMap<BufferId, BufferColors>,
+ render_mode: DocumentColorsRenderMode,
+}
+
+#[derive(Debug, Default)]
+struct BufferColors {
colors: Vec<(Range<Anchor>, DocumentColor, InlayId)>,
inlay_colors: HashMap<InlayId, usize>,
- render_mode: DocumentColorsRenderMode,
+ cache_version_used: usize,
}
impl LspColorData {
pub fn new(cx: &App) -> Self {
Self {
- cache_version_used: 0,
- colors: Vec::new(),
- inlay_colors: HashMap::default(),
+ buffer_colors: HashMap::default(),
render_mode: EditorSettings::get_global(cx).lsp_document_colors,
}
}
@@ -47,8 +50,9 @@ impl LspColorData {
DocumentColorsRenderMode::Inlay => Some(InlaySplice {
to_remove: Vec::new(),
to_insert: self
- .colors
+ .buffer_colors
.iter()
+ .flat_map(|(_, buffer_colors)| buffer_colors.colors.iter())
.map(|(range, color, id)| {
Inlay::color(
id.id(),
@@ -63,33 +67,49 @@ impl LspColorData {
})
.collect(),
}),
- DocumentColorsRenderMode::None => {
- self.colors.clear();
- Some(InlaySplice {
- to_remove: self.inlay_colors.drain().map(|(id, _)| id).collect(),
- to_insert: Vec::new(),
- })
- }
+ DocumentColorsRenderMode::None => Some(InlaySplice {
+ to_remove: self
+ .buffer_colors
+ .drain()
+ .flat_map(|(_, buffer_colors)| buffer_colors.inlay_colors)
+ .map(|(id, _)| id)
+ .collect(),
+ to_insert: Vec::new(),
+ }),
DocumentColorsRenderMode::Border | DocumentColorsRenderMode::Background => {
Some(InlaySplice {
- to_remove: self.inlay_colors.drain().map(|(id, _)| id).collect(),
+ to_remove: self
+ .buffer_colors
+ .iter_mut()
+ .flat_map(|(_, buffer_colors)| buffer_colors.inlay_colors.drain())
+ .map(|(id, _)| id)
+ .collect(),
to_insert: Vec::new(),
})
}
}
}
- fn set_colors(&mut self, colors: Vec<(Range<Anchor>, DocumentColor, InlayId)>) -> bool {
- if self.colors == colors {
+ fn set_colors(
+ &mut self,
+ buffer_id: BufferId,
+ colors: Vec<(Range<Anchor>, DocumentColor, InlayId)>,
+ cache_version: Option<usize>,
+ ) -> bool {
+ let buffer_colors = self.buffer_colors.entry(buffer_id).or_default();
+ if let Some(cache_version) = cache_version {
+ buffer_colors.cache_version_used = cache_version;
+ }
+ if buffer_colors.colors == colors {
return false;
}
- self.inlay_colors = colors
+ buffer_colors.inlay_colors = colors
.iter()
.enumerate()
.map(|(i, (_, _, id))| (*id, i))
.collect();
- self.colors = colors;
+ buffer_colors.colors = colors;
true
}
@@ -103,8 +123,9 @@ impl LspColorData {
{
Vec::new()
} else {
- self.colors
+ self.buffer_colors
.iter()
+ .flat_map(|(_, buffer_colors)| &buffer_colors.colors)
.map(|(range, color, _)| {
let display_range = range.clone().to_display_points(snapshot);
let color = Hsla::from(Rgba {
@@ -162,10 +183,9 @@ impl Editor {
ColorFetchStrategy::IgnoreCache
} else {
ColorFetchStrategy::UseCache {
- known_cache_version: self
- .colors
- .as_ref()
- .map(|colors| colors.cache_version_used),
+ 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)?;
@@ -201,15 +221,13 @@ impl Editor {
return;
};
- let mut cache_version = None;
- let mut new_editor_colors = Vec::<(Range<Anchor>, DocumentColor)>::new();
+ let mut new_editor_colors = HashMap::default();
for (buffer_id, colors) in all_colors {
let Some(excerpts) = editor_excerpts.get(&buffer_id) else {
continue;
};
match colors {
Ok(colors) => {
- cache_version = colors.cache_version;
for color in colors.colors {
let color_start = point_from_lsp(color.lsp_range.start);
let color_end = point_from_lsp(color.lsp_range.end);
@@ -243,8 +261,15 @@ impl Editor {
continue;
};
+ let new_entry =
+ new_editor_colors.entry(buffer_id).or_insert_with(|| {
+ (Vec::<(Range<Anchor>, DocumentColor)>::new(), None)
+ });
+ new_entry.1 = colors.cache_version;
+ let new_buffer_colors = &mut new_entry.0;
+
let (Ok(i) | Err(i)) =
- new_editor_colors.binary_search_by(|(probe, _)| {
+ new_buffer_colors.binary_search_by(|(probe, _)| {
probe
.start
.cmp(&color_start_anchor, &multi_buffer_snapshot)
@@ -254,7 +279,7 @@ impl Editor {
.cmp(&color_end_anchor, &multi_buffer_snapshot)
})
});
- new_editor_colors
+ new_buffer_colors
.insert(i, (color_start_anchor..color_end_anchor, color));
break;
}
@@ -267,45 +292,70 @@ impl Editor {
editor
.update(cx, |editor, cx| {
let mut colors_splice = InlaySplice::default();
- let mut new_color_inlays = Vec::with_capacity(new_editor_colors.len());
let Some(colors) = &mut editor.colors else {
return;
};
- let mut existing_colors = colors.colors.iter().peekable();
- for (new_range, new_color) in new_editor_colors {
- let rgba_color = Rgba {
- r: new_color.color.red,
- g: new_color.color.green,
- b: new_color.color.blue,
- a: new_color.color.alpha,
- };
+ let mut updated = false;
+ for (buffer_id, (new_buffer_colors, new_cache_version)) in new_editor_colors {
+ let mut new_buffer_color_inlays =
+ Vec::with_capacity(new_buffer_colors.len());
+ let mut existing_buffer_colors = colors
+ .buffer_colors
+ .entry(buffer_id)
+ .or_default()
+ .colors
+ .iter()
+ .peekable();
+ for (new_range, new_color) in new_buffer_colors {
+ let rgba_color = Rgba {
+ r: new_color.color.red,
+ g: new_color.color.green,
+ b: new_color.color.blue,
+ a: new_color.color.alpha,
+ };
- loop {
- match existing_colors.peek() {
- Some((existing_range, existing_color, existing_inlay_id)) => {
- match existing_range
- .start
- .cmp(&new_range.start, &multi_buffer_snapshot)
- .then_with(|| {
- existing_range
- .end
- .cmp(&new_range.end, &multi_buffer_snapshot)
- }) {
- cmp::Ordering::Less => {
- colors_splice.to_remove.push(*existing_inlay_id);
- existing_colors.next();
- continue;
- }
- cmp::Ordering::Equal => {
- if existing_color == &new_color {
- new_color_inlays.push((
- new_range,
- new_color,
- *existing_inlay_id,
- ));
- } else {
+ loop {
+ match existing_buffer_colors.peek() {
+ Some((existing_range, existing_color, existing_inlay_id)) => {
+ match existing_range
+ .start
+ .cmp(&new_range.start, &multi_buffer_snapshot)
+ .then_with(|| {
+ existing_range
+ .end
+ .cmp(&new_range.end, &multi_buffer_snapshot)
+ }) {
+ cmp::Ordering::Less => {
colors_splice.to_remove.push(*existing_inlay_id);
+ existing_buffer_colors.next();
+ continue;
+ }
+ cmp::Ordering::Equal => {
+ if existing_color == &new_color {
+ new_buffer_color_inlays.push((
+ new_range,
+ new_color,
+ *existing_inlay_id,
+ ));
+ } else {
+ colors_splice
+ .to_remove
+ .push(*existing_inlay_id);
+ let inlay = Inlay::color(
+ post_inc(&mut editor.next_color_inlay_id),
+ new_range.start,
+ rgba_color,
+ );
+ let inlay_id = inlay.id;
+ colors_splice.to_insert.push(inlay);
+ new_buffer_color_inlays
+ .push((new_range, new_color, inlay_id));
+ }
+ existing_buffer_colors.next();
+ break;
+ }
+ cmp::Ordering::Greater => {
let inlay = Inlay::color(
post_inc(&mut editor.next_color_inlay_id),
new_range.start,
@@ -313,49 +363,40 @@ impl Editor {
);
let inlay_id = inlay.id;
colors_splice.to_insert.push(inlay);
- new_color_inlays
+ new_buffer_color_inlays
.push((new_range, new_color, inlay_id));
+ break;
}
- existing_colors.next();
- break;
- }
- cmp::Ordering::Greater => {
- let inlay = Inlay::color(
- post_inc(&mut editor.next_color_inlay_id),
- new_range.start,
- rgba_color,
- );
- let inlay_id = inlay.id;
- colors_splice.to_insert.push(inlay);
- new_color_inlays.push((new_range, new_color, inlay_id));
- break;
}
}
- }
- None => {
- let inlay = Inlay::color(
- post_inc(&mut editor.next_color_inlay_id),
- new_range.start,
- rgba_color,
- );
- let inlay_id = inlay.id;
- colors_splice.to_insert.push(inlay);
- new_color_inlays.push((new_range, new_color, inlay_id));
- break;
+ None => {
+ let inlay = Inlay::color(
+ post_inc(&mut editor.next_color_inlay_id),
+ new_range.start,
+ rgba_color,
+ );
+ let inlay_id = inlay.id;
+ colors_splice.to_insert.push(inlay);
+ new_buffer_color_inlays
+ .push((new_range, new_color, inlay_id));
+ break;
+ }
}
}
}
- }
- if existing_colors.peek().is_some() {
- colors_splice
- .to_remove
- .extend(existing_colors.map(|(_, _, id)| *id));
- }
- let mut updated = colors.set_colors(new_color_inlays);
- if let Some(cache_version) = cache_version {
- colors.cache_version_used = cache_version;
+ if existing_buffer_colors.peek().is_some() {
+ colors_splice
+ .to_remove
+ .extend(existing_buffer_colors.map(|(_, _, id)| *id));
+ }
+ updated |= colors.set_colors(
+ buffer_id,
+ new_buffer_color_inlays,
+ new_cache_version,
+ );
}
+
if colors.render_mode == DocumentColorsRenderMode::Inlay
&& (!colors_splice.to_insert.is_empty()
|| !colors_splice.to_remove.is_empty())
@@ -170,6 +170,7 @@ pub struct LocalLspStore {
_subscription: gpui::Subscription,
lsp_tree: Entity<LanguageServerTree>,
registered_buffers: HashMap<BufferId, usize>,
+ buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
}
@@ -2546,6 +2547,10 @@ impl LocalLspStore {
vec![snapshot]
});
+ self.buffers_opened_in_servers
+ .entry(buffer_id)
+ .or_default()
+ .insert(server.server_id());
cx.emit(LspStoreEvent::LanguageServerUpdate {
language_server_id: server.server_id(),
name: None,
@@ -3208,6 +3213,9 @@ impl LocalLspStore {
self.language_servers.remove(server_id_to_remove);
self.buffer_pull_diagnostics_result_ids
.remove(server_id_to_remove);
+ for buffer_servers in self.buffers_opened_in_servers.values_mut() {
+ buffer_servers.remove(server_id_to_remove);
+ }
cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
}
servers_to_remove.into_keys().collect()
@@ -3787,6 +3795,7 @@ impl LspStore {
}),
lsp_tree: LanguageServerTree::new(manifest_tree, languages.clone(), cx),
registered_buffers: HashMap::default(),
+ buffers_opened_in_servers: HashMap::default(),
buffer_pull_diagnostics_result_ids: HashMap::default(),
}),
last_formatting_failure: None,
@@ -4159,6 +4168,7 @@ impl LspStore {
lsp_store.lsp_data.remove(&buffer_id);
let local = lsp_store.as_local_mut().unwrap();
local.registered_buffers.remove(&buffer_id);
+ local.buffers_opened_in_servers.remove(&buffer_id);
if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
local.unregister_old_buffer_from_language_servers(&buffer, &file, cx);
}
@@ -6235,21 +6245,31 @@ impl LspStore {
} => {
if let Some(cached_data) = self.lsp_data.get(&buffer_id) {
if !version_queried_for.changed_since(&cached_data.colors_for_version) {
- if Some(cached_data.cache_version) == known_cache_version {
- return None;
- } else {
- return Some(
- Task::ready(Ok(DocumentColors {
- colors: cached_data
- .colors
- .values()
- .flatten()
- .cloned()
- .collect(),
- cache_version: Some(cached_data.cache_version),
- }))
- .shared(),
- );
+ let has_different_servers = self.as_local().is_some_and(|local| {
+ local
+ .buffers_opened_in_servers
+ .get(&buffer_id)
+ .cloned()
+ .unwrap_or_default()
+ != cached_data.colors.keys().copied().collect()
+ });
+ if !has_different_servers {
+ if Some(cached_data.cache_version) == known_cache_version {
+ return None;
+ } else {
+ return Some(
+ Task::ready(Ok(DocumentColors {
+ colors: cached_data
+ .colors
+ .values()
+ .flatten()
+ .cloned()
+ .collect(),
+ cache_version: Some(cached_data.cache_version),
+ }))
+ .shared(),
+ );
+ }
}
}
}
@@ -7522,6 +7542,14 @@ impl LspStore {
.unwrap_or(true)
})
.map(|(_, server)| server.server_id())
+ .filter(|server_id| {
+ self.as_local().is_none_or(|local| {
+ local
+ .buffers_opened_in_servers
+ .get(&snapshot.remote_id())
+ .is_some_and(|servers| servers.contains(server_id))
+ })
+ })
.collect::<Vec<_>>()
});
@@ -10084,6 +10112,7 @@ impl LspStore {
}
// Tell the language server about every open buffer in the worktree that matches the language.
+ let mut buffer_paths_registered = Vec::new();
self.buffer_store.clone().update(cx, |buffer_store, cx| {
for buffer_handle in buffer_store.buffers() {
let buffer = buffer_handle.read(cx);
@@ -10142,6 +10171,12 @@ impl LspStore {
version,
initial_snapshot.text(),
);
+ buffer_paths_registered.push(file.abs_path(cx));
+ local
+ .buffers_opened_in_servers
+ .entry(buffer.remote_id())
+ .or_default()
+ .insert(server_id);
}
buffer_handle.update(cx, |buffer, cx| {
buffer.set_completion_triggers(
@@ -10163,6 +10198,18 @@ impl LspStore {
}
});
+ for abs_path in buffer_paths_registered {
+ cx.emit(LspStoreEvent::LanguageServerUpdate {
+ language_server_id: server_id,
+ name: Some(adapter.name()),
+ message: proto::update_language_server::Variant::RegisteredForBuffer(
+ proto::RegisteredForBuffer {
+ buffer_abs_path: abs_path.to_string_lossy().to_string(),
+ },
+ ),
+ });
+ }
+
cx.notify();
}
@@ -10612,6 +10659,9 @@ impl LspStore {
}
if let Some(local) = self.as_local_mut() {
local.buffer_pull_diagnostics_result_ids.remove(&for_server);
+ for buffer_servers in local.buffers_opened_in_servers.values_mut() {
+ buffer_servers.remove(&for_server);
+ }
}
}