lsp: Use itemDefaults if sent along with completion items (#11902)

Thorsten Ball created

This fixes #10532 by properly making use of `itemDefaults.data` when
that is sent along next to completion `items`.

With this line here we tell the language server that we support `data`
in `itemDefaults`, but we actually never checked for it and never used
it:


https://github.com/zed-industries/zed/blob/a0d7ec9f8e70799163313767b5a8bc34d9e4aa1b/crates/lsp/src/lsp.rs#L653

In the case of `tailwindcss-language-server` that means that most of the
items it returns (more than 10k items!) were missing the `data`
attribute, since the language server thought it can send it along in the
`itemDefaults` (because we advertised our capability to use it.)

When we then did a `completionItem/resolve`, we would not send a `data`
attribute along, which lead to an error on the
`tailwindcss-language-server` side and thus no documentation.

This PR also adds support for the other `itemDefaults` that could be
sent along and that we say we support:


https://github.com/zed-industries/zed/blob/a0d7ec9f8e70799163313767b5a8bc34d9e4aa1b/crates/lsp/src/lsp.rs#L650-L653

`editRange` we handle separately, so this PR only adds the other 3.

Release Notes:

- Fixed documentation not showing up for completion items coming from
`tailwindcss-language-server`.
([#10532](https://github.com/zed-industries/zed/issues/10532)).

Demo:


https://github.com/zed-industries/zed/assets/1185253/bc5ea0b3-7d83-499f-a908-b0d2a1db8a41

Change summary

crates/project/src/lsp_command.rs | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

Detailed changes

crates/project/src/lsp_command.rs 🔗

@@ -1495,6 +1495,33 @@ impl LspCommand for GetCompletions {
             })?
             .ok_or_else(|| anyhow!("no such language server"))?;
 
+        let item_defaults = response_list
+            .as_ref()
+            .and_then(|list| list.item_defaults.as_ref());
+
+        if let Some(item_defaults) = item_defaults {
+            let default_data = item_defaults.data.as_ref();
+            let default_commit_characters = item_defaults.commit_characters.as_ref();
+            let default_insert_text_mode = item_defaults.insert_text_mode.as_ref();
+
+            if default_data.is_some()
+                || default_commit_characters.is_some()
+                || default_insert_text_mode.is_some()
+            {
+                for item in completions.iter_mut() {
+                    if let Some(data) = default_data {
+                        item.data = Some(data.clone())
+                    }
+                    if let Some(characters) = default_commit_characters {
+                        item.commit_characters = Some(characters.clone())
+                    }
+                    if let Some(text_mode) = default_insert_text_mode {
+                        item.insert_text_mode = Some(*text_mode)
+                    }
+                }
+            }
+        }
+
         let mut completion_edits = Vec::new();
         buffer.update(&mut cx, |buffer, _cx| {
             let snapshot = buffer.snapshot();