Strip off inlay hint data that should be resolved (#2843)

Kirill Bulatov created

Part of
https://linear.app/zed-industries/issue/Z-2750/investigate-performance-of-collaborating-on-large-files-with-inlay

* Declares client capabilities for hint resolution, marking both fields
available for resolution (`textEdits` and `tooltop`) as resolvable.
We do not use these fields anymore, hence can omit resolving them for
now, but LSP servers can omit them during general hint requests.

* Removes `tooltip` and replaces complex `label` with its simple string
counterpart for clients' hint responses from host: both should be
resolved through host later

Release Notes:

- Reduces collab mode clients' inlay hint footprint by enabling hint
data resolution

Change summary

crates/lsp/src/lsp.rs             |  4 +
crates/project/src/lsp_command.rs | 56 ++++++--------------------------
2 files changed, 14 insertions(+), 46 deletions(-)

Detailed changes

crates/lsp/src/lsp.rs 🔗

@@ -434,7 +434,9 @@ impl LanguageServer {
                         ..Default::default()
                     }),
                     inlay_hint: Some(InlayHintClientCapabilities {
-                        resolve_support: None,
+                        resolve_support: Some(InlayHintResolveClientCapabilities {
+                            properties: vec!["textEdits".to_string(), "tooltip".to_string()],
+                        }),
                         dynamic_registration: Some(false),
                     }),
                     ..Default::default()

crates/project/src/lsp_command.rs 🔗

@@ -1954,7 +1954,7 @@ impl LspCommand for InlayHints {
         _: &mut Project,
         _: PeerId,
         buffer_version: &clock::Global,
-        cx: &mut AppContext,
+        _: &mut AppContext,
     ) -> proto::InlayHintsResponse {
         proto::InlayHintsResponse {
             hints: response
@@ -1963,51 +1963,17 @@ impl LspCommand for InlayHints {
                     position: Some(language::proto::serialize_anchor(&response_hint.position)),
                     padding_left: response_hint.padding_left,
                     padding_right: response_hint.padding_right,
-                    label: Some(proto::InlayHintLabel {
-                        label: Some(match response_hint.label {
-                            InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
-                            InlayHintLabel::LabelParts(label_parts) => {
-                                proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
-                                    parts: label_parts.into_iter().map(|label_part| proto::InlayHintLabelPart {
-                                        value: label_part.value,
-                                        tooltip: label_part.tooltip.map(|tooltip| {
-                                            let proto_tooltip = match tooltip {
-                                                InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
-                                                InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
-                                                    kind: markup_content.kind,
-                                                    value: markup_content.value,
-                                                }),
-                                            };
-                                            proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
-                                        }),
-                                        location: label_part.location.map(|location| proto::Location {
-                                            start: Some(serialize_anchor(&location.range.start)),
-                                            end: Some(serialize_anchor(&location.range.end)),
-                                            buffer_id: location.buffer.read(cx).remote_id(),
-                                        }),
-                                    }).collect()
-                                })
-                            }
-                        }),
-                    }),
                     kind: response_hint.kind.map(|kind| kind.name().to_string()),
-                    tooltip: response_hint.tooltip.map(|response_tooltip| {
-                        let proto_tooltip = match response_tooltip {
-                            InlayHintTooltip::String(s) => {
-                                proto::inlay_hint_tooltip::Content::Value(s)
-                            }
-                            InlayHintTooltip::MarkupContent(markup_content) => {
-                                proto::inlay_hint_tooltip::Content::MarkupContent(
-                                    proto::MarkupContent {
-                                        kind: markup_content.kind,
-                                        value: markup_content.value,
-                                    },
-                                )
-                            }
-                        };
-                        proto::InlayHintTooltip {
-                            content: Some(proto_tooltip),
-                        }
+                    // Do not pass extra data such as tooltips to clients: host can put tooltip data from the cache during resolution.
+                    tooltip: None,
+                    // Similarly, do not pass label parts to clients: host can return a detailed list during resolution.
+                    label: Some(proto::InlayHintLabel {
+                        label: Some(proto::inlay_hint_label::Label::Value(
+                            match response_hint.label {
+                                InlayHintLabel::String(s) => s,
+                                InlayHintLabel::LabelParts(_) => response_hint.text(),
+                            },
+                        )),
                     }),
                 })
                 .collect(),