@@ -209,6 +209,9 @@ impl Editor {
tokens
},
Ok(BufferSemanticTokens { tokens: None }) => {
+ editor.display_map.update(cx, |display_map, _| {
+ display_map.invalidate_semantic_highlights(buffer_id);
+ });
continue;
},
Err(e) => {
@@ -458,14 +461,14 @@ mod tests {
lsp::SemanticTokensOptions {
legend: lsp::SemanticTokensLegend {
token_types: vec!["function".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
},
full: Some(lsp::SemanticTokensFullOptions::Delta { delta: None }),
- ..Default::default()
+ ..lsp::SemanticTokensOptions::default()
},
),
),
- ..Default::default()
+ ..lsp::ServerCapabilities::default()
},
cx,
)
@@ -536,14 +539,14 @@ mod tests {
lsp::SemanticTokensOptions {
legend: lsp::SemanticTokensLegend {
token_types: vec!["function".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
},
full: Some(lsp::SemanticTokensFullOptions::Delta { delta: Some(true) }),
- ..Default::default()
+ ..lsp::SemanticTokensOptions::default()
},
),
),
- ..Default::default()
+ ..lsp::ServerCapabilities::default()
},
cx,
)
@@ -612,14 +615,14 @@ mod tests {
lsp::SemanticTokensOptions {
legend: lsp::SemanticTokensLegend {
token_types: vec!["function".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
},
full: Some(lsp::SemanticTokensFullOptions::Delta { delta: Some(true) }),
- ..Default::default()
+ ..lsp::SemanticTokensOptions::default()
},
),
),
- ..Default::default()
+ ..lsp::ServerCapabilities::default()
},
cx,
)
@@ -659,7 +662,7 @@ mod tests {
async move {
Ok(Some(lsp::SemanticTokensFullDeltaResult::TokensDelta(
lsp::SemanticTokensDelta {
- edits: vec![],
+ edits: Vec::new(),
result_id: Some("b".into()),
},
)))
@@ -716,11 +719,11 @@ mod tests {
// We have 2 language servers for TOML in this test.
let toml_legend_1 = lsp::SemanticTokensLegend {
token_types: vec!["property".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
};
let toml_legend_2 = lsp::SemanticTokensLegend {
token_types: vec!["number".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
};
let app_state = cx.update(workspace::AppState::test);
@@ -954,11 +957,11 @@ mod tests {
let toml_legend = lsp::SemanticTokensLegend {
token_types: vec!["property".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
};
let rust_legend = lsp::SemanticTokensLegend {
token_types: vec!["constant".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
};
let app_state = cx.update(workspace::AppState::test);
@@ -1221,7 +1224,7 @@ mod tests {
let toml_legend = lsp::SemanticTokensLegend {
token_types: vec!["property".into()],
- token_modifiers: vec![],
+ token_modifiers: Vec::new(),
};
let app_state = cx.update(workspace::AppState::test);
@@ -1806,6 +1809,84 @@ mod tests {
);
}
+ #[gpui::test]
+ async fn test_stopping_language_server_clears_semantic_tokens(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+
+ update_test_language_settings(cx, |language_settings| {
+ language_settings.languages.0.insert(
+ "Rust".into(),
+ LanguageSettingsContent {
+ semantic_tokens: Some(SemanticTokens::Full),
+ ..LanguageSettingsContent::default()
+ },
+ );
+ });
+
+ let mut cx = EditorLspTestContext::new_rust(
+ lsp::ServerCapabilities {
+ semantic_tokens_provider: Some(
+ lsp::SemanticTokensServerCapabilities::SemanticTokensOptions(
+ lsp::SemanticTokensOptions {
+ legend: lsp::SemanticTokensLegend {
+ token_types: vec!["function".into()],
+ token_modifiers: Vec::new(),
+ },
+ full: Some(lsp::SemanticTokensFullOptions::Delta { delta: None }),
+ ..lsp::SemanticTokensOptions::default()
+ },
+ ),
+ ),
+ ..lsp::ServerCapabilities::default()
+ },
+ cx,
+ )
+ .await;
+
+ let mut full_request = cx
+ .set_request_handler::<lsp::request::SemanticTokensFullRequest, _, _>(
+ move |_, _, _| async move {
+ Ok(Some(lsp::SemanticTokensResult::Tokens(
+ lsp::SemanticTokens {
+ data: vec![
+ 0, // delta_line
+ 3, // delta_start
+ 4, // length
+ 0, // token_type
+ 0, // token_modifiers_bitset
+ ],
+ result_id: None,
+ },
+ )))
+ },
+ );
+
+ cx.set_state("ˇfn main() {}");
+ assert!(full_request.next().await.is_some());
+ cx.run_until_parked();
+
+ assert_eq!(
+ extract_semantic_highlights(&cx.editor, &cx),
+ vec![MultiBufferOffset(3)..MultiBufferOffset(7)],
+ "Semantic tokens should be present before stopping the server"
+ );
+
+ cx.update_editor(|editor, _, cx| {
+ let buffers = editor.buffer.read(cx).all_buffers().into_iter().collect();
+ editor.project.as_ref().unwrap().update(cx, |project, cx| {
+ project.stop_language_servers_for_buffers(buffers, HashSet::default(), cx);
+ })
+ });
+ cx.executor().advance_clock(Duration::from_millis(200));
+ cx.run_until_parked();
+
+ assert_eq!(
+ extract_semantic_highlights(&cx.editor, &cx),
+ Vec::new(),
+ "Semantic tokens should be cleared after stopping the server"
+ );
+ }
+
fn extract_semantic_highlight_styles(
editor: &Entity<Editor>,
cx: &TestAppContext,