1use crate::{
2 buffer_store::{BufferStore, BufferStoreEvent},
3 environment::ProjectEnvironment,
4 lsp_command::{self, *},
5 lsp_ext_command,
6 project_settings::ProjectSettings,
7 relativize_path, resolve_path,
8 worktree_store::WorktreeStore,
9 yarn::YarnPathStore,
10 CodeAction, Completion, CoreCompletion, Hover, InlayHint, Item as _, ProjectPath,
11 ProjectTransaction, ResolveState, Symbol,
12};
13use anyhow::{anyhow, Context as _, Result};
14use async_trait::async_trait;
15use client::{proto, TypedEnvelope};
16use collections::{btree_map, BTreeMap, HashMap, HashSet};
17use futures::{
18 future::{join_all, Shared},
19 select,
20 stream::FuturesUnordered,
21 Future, FutureExt, StreamExt,
22};
23use globset::{Glob, GlobSet, GlobSetBuilder};
24use gpui::{
25 AppContext, AsyncAppContext, Entity, EventEmitter, Model, ModelContext, PromptLevel, Task,
26 WeakModel,
27};
28use http_client::HttpClient;
29use itertools::Itertools;
30use language::{
31 language_settings::{language_settings, AllLanguageSettings, LanguageSettings},
32 markdown, point_to_lsp, prepare_completion_documentation,
33 proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
34 range_from_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
35 DiagnosticEntry, DiagnosticSet, Documentation, File as _, Language, LanguageRegistry,
36 LanguageServerName, LocalFile, LspAdapterDelegate, Patch, PendingLanguageServer, PointUtf16,
37 TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
38};
39use lsp::{
40 CompletionContext, DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
41 Edit, FileSystemWatcher, InsertTextFormat, LanguageServer, LanguageServerBinary,
42 LanguageServerId, LspRequestFuture, MessageActionItem, MessageType, OneOf, ServerHealthStatus,
43 ServerStatus, SymbolKind, TextEdit, WorkDoneProgressCancelParams,
44};
45use parking_lot::{Mutex, RwLock};
46use postage::watch;
47use rand::prelude::*;
48
49use rpc::proto::AnyProtoClient;
50use serde::Serialize;
51use settings::{Settings, SettingsLocation, SettingsStore};
52use sha2::{Digest, Sha256};
53use similar::{ChangeTag, TextDiff};
54use smol::channel::Sender;
55use snippet::Snippet;
56use std::{
57 cmp::Ordering,
58 convert::TryInto,
59 ffi::OsStr,
60 iter, mem,
61 ops::Range,
62 path::{self, Path, PathBuf},
63 process::Stdio,
64 str,
65 sync::{atomic::Ordering::SeqCst, Arc},
66 time::{Duration, Instant},
67};
68use text::{Anchor, BufferId, LineEnding};
69use util::{
70 debug_panic, defer, maybe, merge_json_value_into, post_inc, ResultExt, TryFutureExt as _,
71};
72
73pub use fs::*;
74pub use language::Location;
75#[cfg(any(test, feature = "test-support"))]
76pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
77pub use worktree::{
78 Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, RepositoryEntry,
79 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
80 FS_WATCH_LATENCY,
81};
82
83const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4;
84const SERVER_REINSTALL_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
85const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
86pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
87
88pub struct LspStore {
89 downstream_client: Option<AnyProtoClient>,
90 upstream_client: Option<AnyProtoClient>,
91 project_id: u64,
92 http_client: Arc<dyn HttpClient>,
93 fs: Arc<dyn Fs>,
94 nonce: u128,
95 buffer_store: Model<BufferStore>,
96 worktree_store: Model<WorktreeStore>,
97 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
98 environment: Option<Model<ProjectEnvironment>>,
99 supplementary_language_servers:
100 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
101 languages: Arc<LanguageRegistry>,
102 language_servers: HashMap<LanguageServerId, LanguageServerState>,
103 language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
104 language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
105 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
106 language_server_watched_paths: HashMap<LanguageServerId, HashMap<WorktreeId, GlobSet>>,
107 language_server_watcher_registrations:
108 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
109 active_entry: Option<ProjectEntryId>,
110 _maintain_workspace_config: Task<Result<()>>,
111 _maintain_buffer_languages: Task<()>,
112 next_diagnostic_group_id: usize,
113 diagnostic_summaries:
114 HashMap<WorktreeId, HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>>,
115 diagnostics: HashMap<
116 WorktreeId,
117 HashMap<
118 Arc<Path>,
119 Vec<(
120 LanguageServerId,
121 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
122 )>,
123 >,
124 >,
125 yarn: Model<YarnPathStore>,
126 _subscription: gpui::Subscription,
127}
128
129pub enum LspStoreEvent {
130 LanguageServerAdded(LanguageServerId),
131 LanguageServerRemoved(LanguageServerId),
132 LanguageServerUpdate {
133 language_server_id: LanguageServerId,
134 message: proto::update_language_server::Variant,
135 },
136 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
137 LanguageServerPrompt(LanguageServerPromptRequest),
138 LanguageDetected {
139 buffer: Model<Buffer>,
140 new_language: Option<Arc<Language>>,
141 },
142 Notification(String),
143 RefreshInlayHints,
144 DiagnosticsUpdated {
145 language_server_id: LanguageServerId,
146 path: ProjectPath,
147 },
148 DiskBasedDiagnosticsStarted {
149 language_server_id: LanguageServerId,
150 },
151 DiskBasedDiagnosticsFinished {
152 language_server_id: LanguageServerId,
153 },
154 SnippetEdit {
155 buffer_id: BufferId,
156 edits: Vec<(lsp::Range, Snippet)>,
157 most_recent_edit: clock::Lamport,
158 },
159 StartFormattingLocalBuffer(BufferId),
160 FinishFormattingLocalBuffer(BufferId),
161}
162
163#[derive(Clone, Debug, Serialize)]
164pub struct LanguageServerStatus {
165 pub name: String,
166 pub pending_work: BTreeMap<String, LanguageServerProgress>,
167 pub has_pending_diagnostic_updates: bool,
168 progress_tokens: HashSet<String>,
169}
170
171#[derive(Clone, Debug)]
172struct CoreSymbol {
173 pub language_server_name: LanguageServerName,
174 pub source_worktree_id: WorktreeId,
175 pub path: ProjectPath,
176 pub name: String,
177 pub kind: lsp::SymbolKind,
178 pub range: Range<Unclipped<PointUtf16>>,
179 pub signature: [u8; 32],
180}
181
182impl LspStore {
183 pub fn init(client: &AnyProtoClient) {
184 client.add_model_request_handler(Self::handle_multi_lsp_query);
185 client.add_model_request_handler(Self::handle_restart_language_servers);
186 client.add_model_message_handler(Self::handle_start_language_server);
187 client.add_model_message_handler(Self::handle_update_language_server);
188 client.add_model_message_handler(Self::handle_update_diagnostic_summary);
189 client.add_model_request_handler(Self::handle_resolve_completion_documentation);
190 client.add_model_request_handler(Self::handle_apply_code_action);
191 client.add_model_request_handler(Self::handle_inlay_hints);
192 client.add_model_request_handler(Self::handle_get_project_symbols);
193 client.add_model_request_handler(Self::handle_resolve_inlay_hint);
194 client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
195 client.add_model_request_handler(Self::handle_refresh_inlay_hints);
196 client.add_model_request_handler(Self::handle_on_type_formatting);
197 client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion);
198 client.add_model_request_handler(Self::handle_lsp_command::<GetCodeActions>);
199 client.add_model_request_handler(Self::handle_lsp_command::<GetCompletions>);
200 client.add_model_request_handler(Self::handle_lsp_command::<GetHover>);
201 client.add_model_request_handler(Self::handle_lsp_command::<GetDefinition>);
202 client.add_model_request_handler(Self::handle_lsp_command::<GetDeclaration>);
203 client.add_model_request_handler(Self::handle_lsp_command::<GetTypeDefinition>);
204 client.add_model_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
205 client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
206 client.add_model_request_handler(Self::handle_lsp_command::<PrepareRename>);
207 client.add_model_request_handler(Self::handle_lsp_command::<PerformRename>);
208 client.add_model_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
209 client.add_model_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
210 }
211
212 #[allow(clippy::too_many_arguments)]
213 pub(crate) fn new(
214 buffer_store: Model<BufferStore>,
215 worktree_store: Model<WorktreeStore>,
216 environment: Option<Model<ProjectEnvironment>>,
217 languages: Arc<LanguageRegistry>,
218 http_client: Arc<dyn HttpClient>,
219 fs: Arc<dyn Fs>,
220 downstream_client: Option<AnyProtoClient>,
221 upstream_client: Option<AnyProtoClient>,
222 remote_id: Option<u64>,
223 cx: &mut ModelContext<Self>,
224 ) -> Self {
225 let yarn = YarnPathStore::new(fs.clone(), cx);
226 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
227 .detach();
228
229 Self {
230 downstream_client,
231 upstream_client,
232 http_client,
233 fs,
234 project_id: remote_id.unwrap_or(0),
235 buffer_store,
236 worktree_store,
237 languages: languages.clone(),
238 environment,
239 nonce: StdRng::from_entropy().gen(),
240 buffer_snapshots: Default::default(),
241 supplementary_language_servers: Default::default(),
242 language_servers: Default::default(),
243 language_server_ids: Default::default(),
244 language_server_statuses: Default::default(),
245 last_workspace_edits_by_language_server: Default::default(),
246 language_server_watched_paths: Default::default(),
247 language_server_watcher_registrations: Default::default(),
248 next_diagnostic_group_id: Default::default(),
249 diagnostic_summaries: Default::default(),
250 diagnostics: Default::default(),
251 active_entry: None,
252 yarn,
253 _maintain_workspace_config: Self::maintain_workspace_config(cx),
254 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
255 _subscription: cx.on_app_quit(Self::shutdown_language_servers),
256 }
257 }
258
259 fn on_buffer_store_event(
260 &mut self,
261 _: Model<BufferStore>,
262 event: &BufferStoreEvent,
263 cx: &mut ModelContext<Self>,
264 ) {
265 match event {
266 BufferStoreEvent::BufferAdded(buffer) => {
267 self.register_buffer(buffer, cx).log_err();
268 }
269 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
270 if let Some(old_file) = File::from_dyn(old_file.as_ref()) {
271 self.unregister_buffer_from_language_servers(&buffer, old_file, cx);
272 }
273
274 self.detect_language_for_buffer(&buffer, cx);
275 self.register_buffer_with_language_servers(&buffer, cx);
276 }
277 BufferStoreEvent::BufferDropped(_) => {}
278 }
279 }
280
281 fn on_buffer_event(
282 &mut self,
283 buffer: Model<Buffer>,
284 event: &language::Event,
285 cx: &mut ModelContext<Self>,
286 ) {
287 match event {
288 language::Event::Edited { .. } => {
289 self.on_buffer_edited(buffer, cx);
290 }
291
292 language::Event::Saved => {
293 self.on_buffer_saved(buffer, cx);
294 }
295
296 _ => {}
297 }
298 }
299
300 fn register_buffer(
301 &mut self,
302 buffer: &Model<Buffer>,
303 cx: &mut ModelContext<Self>,
304 ) -> Result<()> {
305 buffer.update(cx, |buffer, _| {
306 buffer.set_language_registry(self.languages.clone())
307 });
308
309 cx.subscribe(buffer, |this, buffer, event, cx| {
310 this.on_buffer_event(buffer, event, cx);
311 })
312 .detach();
313
314 self.detect_language_for_buffer(buffer, cx);
315 self.register_buffer_with_language_servers(buffer, cx);
316 cx.observe_release(buffer, |this, buffer, cx| {
317 if let Some(file) = File::from_dyn(buffer.file()) {
318 if file.is_local() {
319 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
320 for server in this.language_servers_for_buffer(buffer, cx) {
321 server
322 .1
323 .notify::<lsp::notification::DidCloseTextDocument>(
324 lsp::DidCloseTextDocumentParams {
325 text_document: lsp::TextDocumentIdentifier::new(uri.clone()),
326 },
327 )
328 .log_err();
329 }
330 }
331 }
332 })
333 .detach();
334
335 Ok(())
336 }
337
338 fn maintain_buffer_languages(
339 languages: Arc<LanguageRegistry>,
340 cx: &mut ModelContext<Self>,
341 ) -> Task<()> {
342 let mut subscription = languages.subscribe();
343 let mut prev_reload_count = languages.reload_count();
344 cx.spawn(move |this, mut cx| async move {
345 while let Some(()) = subscription.next().await {
346 if let Some(this) = this.upgrade() {
347 // If the language registry has been reloaded, then remove and
348 // re-assign the languages on all open buffers.
349 let reload_count = languages.reload_count();
350 if reload_count > prev_reload_count {
351 prev_reload_count = reload_count;
352 this.update(&mut cx, |this, cx| {
353 this.buffer_store.clone().update(cx, |buffer_store, cx| {
354 for buffer in buffer_store.buffers() {
355 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
356 {
357 this.unregister_buffer_from_language_servers(
358 &buffer, &f, cx,
359 );
360 buffer
361 .update(cx, |buffer, cx| buffer.set_language(None, cx));
362 }
363 }
364 });
365 })
366 .ok();
367 }
368
369 this.update(&mut cx, |this, cx| {
370 let mut plain_text_buffers = Vec::new();
371 let mut buffers_with_unknown_injections = Vec::new();
372 for handle in this.buffer_store.read(cx).buffers() {
373 let buffer = handle.read(cx);
374 if buffer.language().is_none()
375 || buffer.language() == Some(&*language::PLAIN_TEXT)
376 {
377 plain_text_buffers.push(handle);
378 } else if buffer.contains_unknown_injections() {
379 buffers_with_unknown_injections.push(handle);
380 }
381 }
382
383 for buffer in plain_text_buffers {
384 this.detect_language_for_buffer(&buffer, cx);
385 this.register_buffer_with_language_servers(&buffer, cx);
386 }
387
388 for buffer in buffers_with_unknown_injections {
389 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
390 }
391 })
392 .ok();
393 }
394 }
395 })
396 }
397
398 fn detect_language_for_buffer(
399 &mut self,
400 buffer_handle: &Model<Buffer>,
401 cx: &mut ModelContext<Self>,
402 ) {
403 // If the buffer has a language, set it and start the language server if we haven't already.
404 let buffer = buffer_handle.read(cx);
405 let Some(file) = buffer.file() else {
406 return;
407 };
408 let content = buffer.as_rope();
409 let Some(new_language_result) = self
410 .languages
411 .language_for_file(file, Some(content), cx)
412 .now_or_never()
413 else {
414 return;
415 };
416
417 match new_language_result {
418 Err(e) => {
419 if e.is::<language::LanguageNotFound>() {
420 cx.emit(LspStoreEvent::LanguageDetected {
421 buffer: buffer_handle.clone(),
422 new_language: None,
423 });
424 }
425 }
426 Ok(new_language) => {
427 self.set_language_for_buffer(buffer_handle, new_language, cx);
428 }
429 };
430 }
431
432 pub fn set_language_for_buffer(
433 &mut self,
434 buffer: &Model<Buffer>,
435 new_language: Arc<Language>,
436 cx: &mut ModelContext<Self>,
437 ) {
438 buffer.update(cx, |buffer, cx| {
439 if buffer.language().map_or(true, |old_language| {
440 !Arc::ptr_eq(old_language, &new_language)
441 }) {
442 buffer.set_language(Some(new_language.clone()), cx);
443 }
444 });
445
446 let buffer_file = buffer.read(cx).file().cloned();
447 let buffer_file = File::from_dyn(buffer_file.as_ref());
448
449 if let Some(file) = buffer_file {
450 let worktree = file.worktree.clone();
451 if worktree.read(cx).is_local() {
452 self.start_language_servers(&worktree, new_language.clone(), cx)
453 }
454 }
455
456 cx.emit(LspStoreEvent::LanguageDetected {
457 buffer: buffer.clone(),
458 new_language: Some(new_language),
459 })
460 }
461
462 pub fn buffer_store(&self) -> Model<BufferStore> {
463 self.buffer_store.clone()
464 }
465
466 #[cfg(any(test, feature = "test-support"))]
467 pub(crate) fn set_environment(&mut self, environment: Model<ProjectEnvironment>) {
468 self.environment = Some(environment);
469 }
470
471 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
472 self.active_entry = active_entry;
473 }
474
475 fn shutdown_language_servers(
476 &mut self,
477 _cx: &mut ModelContext<Self>,
478 ) -> impl Future<Output = ()> {
479 let shutdown_futures = self
480 .language_servers
481 .drain()
482 .map(|(_, server_state)| async {
483 use LanguageServerState::*;
484 match server_state {
485 Running { server, .. } => server.shutdown()?.await,
486 Starting(task) => task.await?.shutdown()?.await,
487 }
488 })
489 .collect::<Vec<_>>();
490
491 async move {
492 futures::future::join_all(shutdown_futures).await;
493 }
494 }
495
496 pub(crate) fn send_diagnostic_summaries(
497 &self,
498 worktree: &mut Worktree,
499 ) -> Result<(), anyhow::Error> {
500 if let Some(client) = self.downstream_client.clone() {
501 if let Some(summaries) = self.diagnostic_summaries.get(&worktree.id()) {
502 for (path, summaries) in summaries {
503 for (&server_id, summary) in summaries {
504 client.send(proto::UpdateDiagnosticSummary {
505 project_id: self.project_id,
506 worktree_id: worktree.id().to_proto(),
507 summary: Some(summary.to_proto(server_id, path)),
508 })?;
509 }
510 }
511 }
512 }
513 Ok(())
514 }
515
516 pub fn request_lsp<R: LspCommand>(
517 &self,
518 buffer_handle: Model<Buffer>,
519 server: LanguageServerToQuery,
520 request: R,
521 cx: &mut ModelContext<Self>,
522 ) -> Task<Result<R::Response>>
523 where
524 <R::LspRequest as lsp::request::Request>::Result: Send,
525 <R::LspRequest as lsp::request::Request>::Params: Send,
526 {
527 let buffer = buffer_handle.read(cx);
528 if self.upstream_client.is_some() {
529 return self.send_lsp_proto_request(buffer_handle, self.project_id, request, cx);
530 }
531 let language_server = match server {
532 LanguageServerToQuery::Primary => {
533 match self.primary_language_server_for_buffer(buffer, cx) {
534 Some((_, server)) => Some(Arc::clone(server)),
535 None => return Task::ready(Ok(Default::default())),
536 }
537 }
538 LanguageServerToQuery::Other(id) => self
539 .language_server_for_buffer(buffer, id, cx)
540 .map(|(_, server)| Arc::clone(server)),
541 };
542 let file = File::from_dyn(buffer.file()).and_then(File::as_local);
543 if let (Some(file), Some(language_server)) = (file, language_server) {
544 let lsp_params = request.to_lsp(&file.abs_path(cx), buffer, &language_server, cx);
545 let status = request.status();
546 return cx.spawn(move |this, cx| async move {
547 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
548 return Ok(Default::default());
549 }
550
551 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
552
553 let id = lsp_request.id();
554 let _cleanup = if status.is_some() {
555 cx.update(|cx| {
556 this.update(cx, |this, cx| {
557 this.on_lsp_work_start(
558 language_server.server_id(),
559 id.to_string(),
560 LanguageServerProgress {
561 is_disk_based_diagnostics_progress: false,
562 is_cancellable: false,
563 title: None,
564 message: status.clone(),
565 percentage: None,
566 last_update_at: cx.background_executor().now(),
567 },
568 cx,
569 );
570 })
571 })
572 .log_err();
573
574 Some(defer(|| {
575 cx.update(|cx| {
576 this.update(cx, |this, cx| {
577 this.on_lsp_work_end(
578 language_server.server_id(),
579 id.to_string(),
580 cx,
581 );
582 })
583 })
584 .log_err();
585 }))
586 } else {
587 None
588 };
589
590 let result = lsp_request.await;
591
592 let response = result.map_err(|err| {
593 log::warn!(
594 "Generic lsp request to {} failed: {}",
595 language_server.name(),
596 err
597 );
598 err
599 })?;
600
601 request
602 .response_from_lsp(
603 response,
604 this.upgrade().ok_or_else(|| anyhow!("no app context"))?,
605 buffer_handle,
606 language_server.server_id(),
607 cx.clone(),
608 )
609 .await
610 });
611 }
612
613 Task::ready(Ok(Default::default()))
614 }
615
616 fn send_lsp_proto_request<R: LspCommand>(
617 &self,
618 buffer: Model<Buffer>,
619 project_id: u64,
620 request: R,
621 cx: &mut ModelContext<'_, Self>,
622 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
623 let Some(upstream_client) = self.upstream_client.clone() else {
624 return Task::ready(Err(anyhow!("disconnected before completing request")));
625 };
626 let message = request.to_proto(project_id, buffer.read(cx));
627 cx.spawn(move |this, cx| async move {
628 let response = upstream_client.request(message).await?;
629 let this = this.upgrade().context("project dropped")?;
630 request
631 .response_from_proto(response, this, buffer, cx)
632 .await
633 })
634 }
635
636 pub async fn execute_code_actions_on_servers(
637 this: &WeakModel<LspStore>,
638 adapters_and_servers: &Vec<(Arc<CachedLspAdapter>, Arc<LanguageServer>)>,
639 code_actions: Vec<lsp::CodeActionKind>,
640 buffer: &Model<Buffer>,
641 push_to_history: bool,
642 project_transaction: &mut ProjectTransaction,
643 cx: &mut AsyncAppContext,
644 ) -> Result<(), anyhow::Error> {
645 for (lsp_adapter, language_server) in adapters_and_servers.iter() {
646 let code_actions = code_actions.clone();
647
648 let actions = this
649 .update(cx, move |this, cx| {
650 let request = GetCodeActions {
651 range: text::Anchor::MIN..text::Anchor::MAX,
652 kinds: Some(code_actions),
653 };
654 let server = LanguageServerToQuery::Other(language_server.server_id());
655 this.request_lsp(buffer.clone(), server, request, cx)
656 })?
657 .await?;
658
659 for mut action in actions {
660 Self::try_resolve_code_action(&language_server, &mut action)
661 .await
662 .context("resolving a formatting code action")?;
663
664 if let Some(edit) = action.lsp_action.edit {
665 if edit.changes.is_none() && edit.document_changes.is_none() {
666 continue;
667 }
668
669 let new = Self::deserialize_workspace_edit(
670 this.upgrade().ok_or_else(|| anyhow!("project dropped"))?,
671 edit,
672 push_to_history,
673 lsp_adapter.clone(),
674 language_server.clone(),
675 cx,
676 )
677 .await?;
678 project_transaction.0.extend(new.0);
679 }
680
681 if let Some(command) = action.lsp_action.command {
682 this.update(cx, |this, _| {
683 this.last_workspace_edits_by_language_server
684 .remove(&language_server.server_id());
685 })?;
686
687 language_server
688 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
689 command: command.command,
690 arguments: command.arguments.unwrap_or_default(),
691 ..Default::default()
692 })
693 .await?;
694
695 this.update(cx, |this, _| {
696 project_transaction.0.extend(
697 this.last_workspace_edits_by_language_server
698 .remove(&language_server.server_id())
699 .unwrap_or_default()
700 .0,
701 )
702 })?;
703 }
704 }
705 }
706
707 Ok(())
708 }
709
710 async fn try_resolve_code_action(
711 lang_server: &LanguageServer,
712 action: &mut CodeAction,
713 ) -> anyhow::Result<()> {
714 if GetCodeActions::can_resolve_actions(&lang_server.capabilities()) {
715 if action.lsp_action.data.is_some()
716 && (action.lsp_action.command.is_none() || action.lsp_action.edit.is_none())
717 {
718 action.lsp_action = lang_server
719 .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action.clone())
720 .await?;
721 }
722 }
723
724 anyhow::Ok(())
725 }
726
727 pub fn apply_code_action(
728 &self,
729 buffer_handle: Model<Buffer>,
730 mut action: CodeAction,
731 push_to_history: bool,
732 cx: &mut ModelContext<Self>,
733 ) -> Task<Result<ProjectTransaction>> {
734 if let Some(upstream_client) = self.upstream_client.clone() {
735 let request = proto::ApplyCodeAction {
736 project_id: self.project_id,
737 buffer_id: buffer_handle.read(cx).remote_id().into(),
738 action: Some(Self::serialize_code_action(&action)),
739 };
740 cx.spawn(move |this, cx| async move {
741 let response = upstream_client
742 .request(request)
743 .await?
744 .transaction
745 .ok_or_else(|| anyhow!("missing transaction"))?;
746 BufferStore::deserialize_project_transaction(
747 this.read_with(&cx, |this, _| this.buffer_store.downgrade())?,
748 response,
749 push_to_history,
750 cx,
751 )
752 .await
753 })
754 } else {
755 let buffer = buffer_handle.read(cx);
756 let (lsp_adapter, lang_server) = if let Some((adapter, server)) =
757 self.language_server_for_buffer(buffer, action.server_id, cx)
758 {
759 (adapter.clone(), server.clone())
760 } else {
761 return Task::ready(Ok(Default::default()));
762 };
763 cx.spawn(move |this, mut cx| async move {
764 Self::try_resolve_code_action(&lang_server, &mut action)
765 .await
766 .context("resolving a code action")?;
767 if let Some(edit) = action.lsp_action.edit {
768 if edit.changes.is_some() || edit.document_changes.is_some() {
769 return Self::deserialize_workspace_edit(
770 this.upgrade().ok_or_else(|| anyhow!("no app present"))?,
771 edit,
772 push_to_history,
773 lsp_adapter.clone(),
774 lang_server.clone(),
775 &mut cx,
776 )
777 .await;
778 }
779 }
780
781 if let Some(command) = action.lsp_action.command {
782 this.update(&mut cx, |this, _| {
783 this.last_workspace_edits_by_language_server
784 .remove(&lang_server.server_id());
785 })?;
786
787 let result = lang_server
788 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
789 command: command.command,
790 arguments: command.arguments.unwrap_or_default(),
791 ..Default::default()
792 })
793 .await;
794
795 if let Err(err) = result {
796 // TODO: LSP ERROR
797 return Err(err);
798 }
799
800 return this.update(&mut cx, |this, _| {
801 this.last_workspace_edits_by_language_server
802 .remove(&lang_server.server_id())
803 .unwrap_or_default()
804 });
805 }
806
807 Ok(ProjectTransaction::default())
808 })
809 }
810 }
811
812 pub fn resolve_inlay_hint(
813 &self,
814 hint: InlayHint,
815 buffer_handle: Model<Buffer>,
816 server_id: LanguageServerId,
817 cx: &mut ModelContext<Self>,
818 ) -> Task<anyhow::Result<InlayHint>> {
819 if let Some(upstream_client) = self.upstream_client.clone() {
820 let request = proto::ResolveInlayHint {
821 project_id: self.project_id,
822 buffer_id: buffer_handle.read(cx).remote_id().into(),
823 language_server_id: server_id.0 as u64,
824 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
825 };
826 cx.spawn(move |_, _| async move {
827 let response = upstream_client
828 .request(request)
829 .await
830 .context("inlay hints proto request")?;
831 match response.hint {
832 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
833 .context("inlay hints proto resolve response conversion"),
834 None => Ok(hint),
835 }
836 })
837 } else {
838 let buffer = buffer_handle.read(cx);
839 let (_, lang_server) = if let Some((adapter, server)) =
840 self.language_server_for_buffer(buffer, server_id, cx)
841 {
842 (adapter.clone(), server.clone())
843 } else {
844 return Task::ready(Ok(hint));
845 };
846 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
847 return Task::ready(Ok(hint));
848 }
849
850 let buffer_snapshot = buffer.snapshot();
851 cx.spawn(move |_, mut cx| async move {
852 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
853 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
854 );
855 let resolved_hint = resolve_task
856 .await
857 .context("inlay hint resolve LSP request")?;
858 let resolved_hint = InlayHints::lsp_to_project_hint(
859 resolved_hint,
860 &buffer_handle,
861 server_id,
862 ResolveState::Resolved,
863 false,
864 &mut cx,
865 )
866 .await?;
867 Ok(resolved_hint)
868 })
869 }
870 }
871
872 pub(crate) fn linked_edit(
873 &self,
874 buffer: &Model<Buffer>,
875 position: Anchor,
876 cx: &mut ModelContext<Self>,
877 ) -> Task<Result<Vec<Range<Anchor>>>> {
878 let snapshot = buffer.read(cx).snapshot();
879 let scope = snapshot.language_scope_at(position);
880 let Some(server_id) = self
881 .language_servers_for_buffer(buffer.read(cx), cx)
882 .filter(|(_, server)| {
883 server
884 .capabilities()
885 .linked_editing_range_provider
886 .is_some()
887 })
888 .filter(|(adapter, _)| {
889 scope
890 .as_ref()
891 .map(|scope| scope.language_allowed(&adapter.name))
892 .unwrap_or(true)
893 })
894 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
895 .next()
896 .or_else(|| {
897 self.upstream_client
898 .is_some()
899 .then_some(LanguageServerToQuery::Primary)
900 })
901 .filter(|_| {
902 maybe!({
903 let language_name = buffer.read(cx).language_at(position)?.name();
904 Some(
905 AllLanguageSettings::get_global(cx)
906 .language(Some(&language_name))
907 .linked_edits,
908 )
909 }) == Some(true)
910 })
911 else {
912 return Task::ready(Ok(vec![]));
913 };
914
915 self.request_lsp(
916 buffer.clone(),
917 server_id,
918 LinkedEditingRange { position },
919 cx,
920 )
921 }
922
923 fn apply_on_type_formatting(
924 &self,
925 buffer: Model<Buffer>,
926 position: Anchor,
927 trigger: String,
928 cx: &mut ModelContext<Self>,
929 ) -> Task<Result<Option<Transaction>>> {
930 if let Some(client) = self.upstream_client.clone() {
931 let request = proto::OnTypeFormatting {
932 project_id: self.project_id,
933 buffer_id: buffer.read(cx).remote_id().into(),
934 position: Some(serialize_anchor(&position)),
935 trigger,
936 version: serialize_version(&buffer.read(cx).version()),
937 };
938 cx.spawn(move |_, _| async move {
939 client
940 .request(request)
941 .await?
942 .transaction
943 .map(language::proto::deserialize_transaction)
944 .transpose()
945 })
946 } else {
947 cx.spawn(move |this, mut cx| async move {
948 // Do not allow multiple concurrent formatting requests for the
949 // same buffer.
950 this.update(&mut cx, |_, cx| {
951 cx.emit(LspStoreEvent::StartFormattingLocalBuffer(
952 buffer.read(cx).remote_id(),
953 ));
954 })?;
955
956 let _cleanup = defer({
957 let this = this.clone();
958 let mut cx = cx.clone();
959 let closure_buffer = buffer.clone();
960 move || {
961 this.update(&mut cx, |_, cx| {
962 cx.emit(LspStoreEvent::FinishFormattingLocalBuffer(
963 closure_buffer.read(cx).remote_id(),
964 ))
965 })
966 .ok();
967 }
968 });
969
970 buffer
971 .update(&mut cx, |buffer, _| {
972 buffer.wait_for_edits(Some(position.timestamp))
973 })?
974 .await?;
975 this.update(&mut cx, |this, cx| {
976 let position = position.to_point_utf16(buffer.read(cx));
977 this.on_type_format(buffer, position, trigger, false, cx)
978 })?
979 .await
980 })
981 }
982 }
983
984 pub fn on_type_format<T: ToPointUtf16>(
985 &mut self,
986 buffer: Model<Buffer>,
987 position: T,
988 trigger: String,
989 push_to_history: bool,
990 cx: &mut ModelContext<Self>,
991 ) -> Task<Result<Option<Transaction>>> {
992 let position = position.to_point_utf16(buffer.read(cx));
993 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
994 }
995
996 fn on_type_format_impl(
997 &mut self,
998 buffer: Model<Buffer>,
999 position: PointUtf16,
1000 trigger: String,
1001 push_to_history: bool,
1002 cx: &mut ModelContext<Self>,
1003 ) -> Task<Result<Option<Transaction>>> {
1004 let options = buffer.update(cx, |buffer, cx| {
1005 lsp_command::lsp_formatting_options(language_settings(
1006 buffer.language_at(position).as_ref(),
1007 buffer.file(),
1008 cx,
1009 ))
1010 });
1011 self.request_lsp(
1012 buffer.clone(),
1013 LanguageServerToQuery::Primary,
1014 OnTypeFormatting {
1015 position,
1016 trigger,
1017 options,
1018 push_to_history,
1019 },
1020 cx,
1021 )
1022 }
1023
1024 pub async fn format_via_lsp(
1025 this: &WeakModel<Self>,
1026 buffer: &Model<Buffer>,
1027 abs_path: &Path,
1028 language_server: &Arc<LanguageServer>,
1029 settings: &LanguageSettings,
1030 cx: &mut AsyncAppContext,
1031 ) -> Result<Vec<(Range<Anchor>, String)>> {
1032 let uri = lsp::Url::from_file_path(abs_path)
1033 .map_err(|_| anyhow!("failed to convert abs path to uri"))?;
1034 let text_document = lsp::TextDocumentIdentifier::new(uri);
1035 let capabilities = &language_server.capabilities();
1036
1037 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1038 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1039
1040 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1041 language_server
1042 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1043 text_document,
1044 options: lsp_command::lsp_formatting_options(settings),
1045 work_done_progress_params: Default::default(),
1046 })
1047 .await?
1048 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1049 let buffer_start = lsp::Position::new(0, 0);
1050 let buffer_end = buffer.update(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1051
1052 language_server
1053 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1054 text_document,
1055 range: lsp::Range::new(buffer_start, buffer_end),
1056 options: lsp_command::lsp_formatting_options(settings),
1057 work_done_progress_params: Default::default(),
1058 })
1059 .await?
1060 } else {
1061 None
1062 };
1063
1064 if let Some(lsp_edits) = lsp_edits {
1065 this.update(cx, |this, cx| {
1066 this.edits_from_lsp(buffer, lsp_edits, language_server.server_id(), None, cx)
1067 })?
1068 .await
1069 } else {
1070 Ok(Vec::new())
1071 }
1072 }
1073
1074 pub fn code_actions(
1075 &mut self,
1076 buffer_handle: &Model<Buffer>,
1077 range: Range<Anchor>,
1078 cx: &mut ModelContext<Self>,
1079 ) -> Task<Vec<CodeAction>> {
1080 if let Some(upstream_client) = self.upstream_client.as_ref() {
1081 let request_task = upstream_client.request(proto::MultiLspQuery {
1082 buffer_id: buffer_handle.read(cx).remote_id().into(),
1083 version: serialize_version(&buffer_handle.read(cx).version()),
1084 project_id: self.project_id,
1085 strategy: Some(proto::multi_lsp_query::Strategy::All(
1086 proto::AllLanguageServers {},
1087 )),
1088 request: Some(proto::multi_lsp_query::Request::GetCodeActions(
1089 GetCodeActions {
1090 range: range.clone(),
1091 kinds: None,
1092 }
1093 .to_proto(self.project_id, buffer_handle.read(cx)),
1094 )),
1095 });
1096 let buffer = buffer_handle.clone();
1097 cx.spawn(|weak_project, cx| async move {
1098 let Some(project) = weak_project.upgrade() else {
1099 return Vec::new();
1100 };
1101 join_all(
1102 request_task
1103 .await
1104 .log_err()
1105 .map(|response| response.responses)
1106 .unwrap_or_default()
1107 .into_iter()
1108 .filter_map(|lsp_response| match lsp_response.response? {
1109 proto::lsp_response::Response::GetCodeActionsResponse(response) => {
1110 Some(response)
1111 }
1112 unexpected => {
1113 debug_panic!("Unexpected response: {unexpected:?}");
1114 None
1115 }
1116 })
1117 .map(|code_actions_response| {
1118 let response = GetCodeActions {
1119 range: range.clone(),
1120 kinds: None,
1121 }
1122 .response_from_proto(
1123 code_actions_response,
1124 project.clone(),
1125 buffer.clone(),
1126 cx.clone(),
1127 );
1128 async move { response.await.log_err().unwrap_or_default() }
1129 }),
1130 )
1131 .await
1132 .into_iter()
1133 .flatten()
1134 .collect()
1135 })
1136 } else {
1137 let all_actions_task = self.request_multiple_lsp_locally(
1138 &buffer_handle,
1139 Some(range.start),
1140 GetCodeActions {
1141 range: range.clone(),
1142 kinds: None,
1143 },
1144 cx,
1145 );
1146 cx.spawn(|_, _| async move { all_actions_task.await.into_iter().flatten().collect() })
1147 }
1148 }
1149
1150 #[inline(never)]
1151 pub fn completions(
1152 &self,
1153 buffer: &Model<Buffer>,
1154 position: PointUtf16,
1155 context: CompletionContext,
1156 cx: &mut ModelContext<Self>,
1157 ) -> Task<Result<Vec<Completion>>> {
1158 let language_registry = self.languages.clone();
1159
1160 if let Some(_) = self.upstream_client.clone() {
1161 let task = self.send_lsp_proto_request(
1162 buffer.clone(),
1163 self.project_id,
1164 GetCompletions { position, context },
1165 cx,
1166 );
1167 let language = buffer.read(cx).language().cloned();
1168
1169 // In the future, we should provide project guests with the names of LSP adapters,
1170 // so that they can use the correct LSP adapter when computing labels. For now,
1171 // guests just use the first LSP adapter associated with the buffer's language.
1172 let lsp_adapter = language
1173 .as_ref()
1174 .and_then(|language| language_registry.lsp_adapters(language).first().cloned());
1175
1176 cx.foreground_executor().spawn(async move {
1177 let completions = task.await?;
1178 let mut result = Vec::new();
1179 populate_labels_for_completions(
1180 completions,
1181 &language_registry,
1182 language,
1183 lsp_adapter,
1184 &mut result,
1185 )
1186 .await;
1187 Ok(result)
1188 })
1189 } else {
1190 let snapshot = buffer.read(cx).snapshot();
1191 let offset = position.to_offset(&snapshot);
1192 let scope = snapshot.language_scope_at(offset);
1193 let language = snapshot.language().cloned();
1194
1195 let server_ids: Vec<_> = self
1196 .language_servers_for_buffer(buffer.read(cx), cx)
1197 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
1198 .filter(|(adapter, _)| {
1199 scope
1200 .as_ref()
1201 .map(|scope| scope.language_allowed(&adapter.name))
1202 .unwrap_or(true)
1203 })
1204 .map(|(_, server)| server.server_id())
1205 .collect();
1206
1207 let buffer = buffer.clone();
1208 cx.spawn(move |this, mut cx| async move {
1209 let mut tasks = Vec::with_capacity(server_ids.len());
1210 this.update(&mut cx, |this, cx| {
1211 for server_id in server_ids {
1212 let lsp_adapter = this.language_server_adapter_for_id(server_id);
1213 tasks.push((
1214 lsp_adapter,
1215 this.request_lsp(
1216 buffer.clone(),
1217 LanguageServerToQuery::Other(server_id),
1218 GetCompletions {
1219 position,
1220 context: context.clone(),
1221 },
1222 cx,
1223 ),
1224 ));
1225 }
1226 })?;
1227
1228 let mut completions = Vec::new();
1229 for (lsp_adapter, task) in tasks {
1230 if let Ok(new_completions) = task.await {
1231 populate_labels_for_completions(
1232 new_completions,
1233 &language_registry,
1234 language.clone(),
1235 lsp_adapter,
1236 &mut completions,
1237 )
1238 .await;
1239 }
1240 }
1241
1242 Ok(completions)
1243 })
1244 }
1245 }
1246
1247 pub fn resolve_completions(
1248 &self,
1249 buffer: Model<Buffer>,
1250 completion_indices: Vec<usize>,
1251 completions: Arc<RwLock<Box<[Completion]>>>,
1252 cx: &mut ModelContext<Self>,
1253 ) -> Task<Result<bool>> {
1254 let client = self.upstream_client.clone();
1255 let language_registry = self.languages.clone();
1256 let project_id = self.project_id;
1257
1258 let buffer_id = buffer.read(cx).remote_id();
1259 let buffer_snapshot = buffer.read(cx).snapshot();
1260
1261 cx.spawn(move |this, mut cx| async move {
1262 let mut did_resolve = false;
1263 if let Some(client) = client {
1264 for completion_index in completion_indices {
1265 let (server_id, completion) = {
1266 let completions_guard = completions.read();
1267 let completion = &completions_guard[completion_index];
1268 if completion.documentation.is_some() {
1269 continue;
1270 }
1271
1272 did_resolve = true;
1273 let server_id = completion.server_id;
1274 let completion = completion.lsp_completion.clone();
1275
1276 (server_id, completion)
1277 };
1278
1279 Self::resolve_completion_remote(
1280 project_id,
1281 server_id,
1282 buffer_id,
1283 completions.clone(),
1284 completion_index,
1285 completion,
1286 client.clone(),
1287 language_registry.clone(),
1288 )
1289 .await;
1290 }
1291 } else {
1292 for completion_index in completion_indices {
1293 let (server_id, completion) = {
1294 let completions_guard = completions.read();
1295 let completion = &completions_guard[completion_index];
1296 if completion.documentation.is_some() {
1297 continue;
1298 }
1299
1300 let server_id = completion.server_id;
1301 let completion = completion.lsp_completion.clone();
1302
1303 (server_id, completion)
1304 };
1305
1306 let server = this
1307 .read_with(&mut cx, |this, _| this.language_server_for_id(server_id))
1308 .ok()
1309 .flatten();
1310 let Some(server) = server else {
1311 continue;
1312 };
1313
1314 did_resolve = true;
1315 Self::resolve_completion_local(
1316 server,
1317 &buffer_snapshot,
1318 completions.clone(),
1319 completion_index,
1320 completion,
1321 language_registry.clone(),
1322 )
1323 .await;
1324 }
1325 }
1326
1327 Ok(did_resolve)
1328 })
1329 }
1330
1331 async fn resolve_completion_local(
1332 server: Arc<lsp::LanguageServer>,
1333 snapshot: &BufferSnapshot,
1334 completions: Arc<RwLock<Box<[Completion]>>>,
1335 completion_index: usize,
1336 completion: lsp::CompletionItem,
1337 language_registry: Arc<LanguageRegistry>,
1338 ) {
1339 let can_resolve = server
1340 .capabilities()
1341 .completion_provider
1342 .as_ref()
1343 .and_then(|options| options.resolve_provider)
1344 .unwrap_or(false);
1345 if !can_resolve {
1346 return;
1347 }
1348
1349 let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
1350 let Some(completion_item) = request.await.log_err() else {
1351 return;
1352 };
1353
1354 if let Some(lsp_documentation) = completion_item.documentation.as_ref() {
1355 let documentation = language::prepare_completion_documentation(
1356 lsp_documentation,
1357 &language_registry,
1358 None, // TODO: Try to reasonably work out which language the completion is for
1359 )
1360 .await;
1361
1362 let mut completions = completions.write();
1363 let completion = &mut completions[completion_index];
1364 completion.documentation = Some(documentation);
1365 } else {
1366 let mut completions = completions.write();
1367 let completion = &mut completions[completion_index];
1368 completion.documentation = Some(Documentation::Undocumented);
1369 }
1370
1371 if let Some(text_edit) = completion_item.text_edit.as_ref() {
1372 // Technically we don't have to parse the whole `text_edit`, since the only
1373 // language server we currently use that does update `text_edit` in `completionItem/resolve`
1374 // is `typescript-language-server` and they only update `text_edit.new_text`.
1375 // But we should not rely on that.
1376 let edit = parse_completion_text_edit(text_edit, snapshot);
1377
1378 if let Some((old_range, mut new_text)) = edit {
1379 LineEnding::normalize(&mut new_text);
1380
1381 let mut completions = completions.write();
1382 let completion = &mut completions[completion_index];
1383
1384 completion.new_text = new_text;
1385 completion.old_range = old_range;
1386 }
1387 }
1388 if completion_item.insert_text_format == Some(InsertTextFormat::SNIPPET) {
1389 // vtsls might change the type of completion after resolution.
1390 let mut completions = completions.write();
1391 let completion = &mut completions[completion_index];
1392 if completion_item.insert_text_format != completion.lsp_completion.insert_text_format {
1393 completion.lsp_completion.insert_text_format = completion_item.insert_text_format;
1394 }
1395 }
1396 }
1397
1398 #[allow(clippy::too_many_arguments)]
1399 async fn resolve_completion_remote(
1400 project_id: u64,
1401 server_id: LanguageServerId,
1402 buffer_id: BufferId,
1403 completions: Arc<RwLock<Box<[Completion]>>>,
1404 completion_index: usize,
1405 completion: lsp::CompletionItem,
1406 client: AnyProtoClient,
1407 language_registry: Arc<LanguageRegistry>,
1408 ) {
1409 let request = proto::ResolveCompletionDocumentation {
1410 project_id,
1411 language_server_id: server_id.0 as u64,
1412 lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
1413 buffer_id: buffer_id.into(),
1414 };
1415
1416 let Some(response) = client
1417 .request(request)
1418 .await
1419 .context("completion documentation resolve proto request")
1420 .log_err()
1421 else {
1422 return;
1423 };
1424
1425 let documentation = if response.documentation.is_empty() {
1426 Documentation::Undocumented
1427 } else if response.documentation_is_markdown {
1428 Documentation::MultiLineMarkdown(
1429 markdown::parse_markdown(&response.documentation, &language_registry, None).await,
1430 )
1431 } else if response.documentation.lines().count() <= 1 {
1432 Documentation::SingleLine(response.documentation)
1433 } else {
1434 Documentation::MultiLinePlainText(response.documentation)
1435 };
1436
1437 let mut completions = completions.write();
1438 let completion = &mut completions[completion_index];
1439 completion.documentation = Some(documentation);
1440
1441 let old_range = response
1442 .old_start
1443 .and_then(deserialize_anchor)
1444 .zip(response.old_end.and_then(deserialize_anchor));
1445 if let Some((old_start, old_end)) = old_range {
1446 if !response.new_text.is_empty() {
1447 completion.new_text = response.new_text;
1448 completion.old_range = old_start..old_end;
1449 }
1450 }
1451 }
1452
1453 pub fn apply_additional_edits_for_completion(
1454 &self,
1455 buffer_handle: Model<Buffer>,
1456 completion: Completion,
1457 push_to_history: bool,
1458 cx: &mut ModelContext<Self>,
1459 ) -> Task<Result<Option<Transaction>>> {
1460 let buffer = buffer_handle.read(cx);
1461 let buffer_id = buffer.remote_id();
1462
1463 if let Some(client) = self.upstream_client.clone() {
1464 let project_id = self.project_id;
1465 cx.spawn(move |_, mut cx| async move {
1466 let response = client
1467 .request(proto::ApplyCompletionAdditionalEdits {
1468 project_id,
1469 buffer_id: buffer_id.into(),
1470 completion: Some(Self::serialize_completion(&CoreCompletion {
1471 old_range: completion.old_range,
1472 new_text: completion.new_text,
1473 server_id: completion.server_id,
1474 lsp_completion: completion.lsp_completion,
1475 })),
1476 })
1477 .await?;
1478
1479 if let Some(transaction) = response.transaction {
1480 let transaction = language::proto::deserialize_transaction(transaction)?;
1481 buffer_handle
1482 .update(&mut cx, |buffer, _| {
1483 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
1484 })?
1485 .await?;
1486 if push_to_history {
1487 buffer_handle.update(&mut cx, |buffer, _| {
1488 buffer.push_transaction(transaction.clone(), Instant::now());
1489 })?;
1490 }
1491 Ok(Some(transaction))
1492 } else {
1493 Ok(None)
1494 }
1495 })
1496 } else {
1497 let server_id = completion.server_id;
1498 let lang_server = match self.language_server_for_buffer(buffer, server_id, cx) {
1499 Some((_, server)) => server.clone(),
1500 _ => return Task::ready(Ok(Default::default())),
1501 };
1502
1503 cx.spawn(move |this, mut cx| async move {
1504 let can_resolve = lang_server
1505 .capabilities()
1506 .completion_provider
1507 .as_ref()
1508 .and_then(|options| options.resolve_provider)
1509 .unwrap_or(false);
1510 let additional_text_edits = if can_resolve {
1511 lang_server
1512 .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
1513 .await?
1514 .additional_text_edits
1515 } else {
1516 completion.lsp_completion.additional_text_edits
1517 };
1518 if let Some(edits) = additional_text_edits {
1519 let edits = this
1520 .update(&mut cx, |this, cx| {
1521 this.edits_from_lsp(
1522 &buffer_handle,
1523 edits,
1524 lang_server.server_id(),
1525 None,
1526 cx,
1527 )
1528 })?
1529 .await?;
1530
1531 buffer_handle.update(&mut cx, |buffer, cx| {
1532 buffer.finalize_last_transaction();
1533 buffer.start_transaction();
1534
1535 for (range, text) in edits {
1536 let primary = &completion.old_range;
1537 let start_within = primary.start.cmp(&range.start, buffer).is_le()
1538 && primary.end.cmp(&range.start, buffer).is_ge();
1539 let end_within = range.start.cmp(&primary.end, buffer).is_le()
1540 && range.end.cmp(&primary.end, buffer).is_ge();
1541
1542 //Skip additional edits which overlap with the primary completion edit
1543 //https://github.com/zed-industries/zed/pull/1871
1544 if !start_within && !end_within {
1545 buffer.edit([(range, text)], None, cx);
1546 }
1547 }
1548
1549 let transaction = if buffer.end_transaction(cx).is_some() {
1550 let transaction = buffer.finalize_last_transaction().unwrap().clone();
1551 if !push_to_history {
1552 buffer.forget_transaction(transaction.id);
1553 }
1554 Some(transaction)
1555 } else {
1556 None
1557 };
1558 Ok(transaction)
1559 })?
1560 } else {
1561 Ok(None)
1562 }
1563 })
1564 }
1565 }
1566
1567 pub fn inlay_hints(
1568 &mut self,
1569 buffer_handle: Model<Buffer>,
1570 range: Range<Anchor>,
1571 cx: &mut ModelContext<Self>,
1572 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
1573 let buffer = buffer_handle.read(cx);
1574 let range_start = range.start;
1575 let range_end = range.end;
1576 let buffer_id = buffer.remote_id().into();
1577 let lsp_request = InlayHints { range };
1578
1579 if let Some(client) = self.upstream_client.clone() {
1580 let request = proto::InlayHints {
1581 project_id: self.project_id,
1582 buffer_id,
1583 start: Some(serialize_anchor(&range_start)),
1584 end: Some(serialize_anchor(&range_end)),
1585 version: serialize_version(&buffer_handle.read(cx).version()),
1586 };
1587 cx.spawn(move |project, cx| async move {
1588 let response = client
1589 .request(request)
1590 .await
1591 .context("inlay hints proto request")?;
1592 LspCommand::response_from_proto(
1593 lsp_request,
1594 response,
1595 project.upgrade().ok_or_else(|| anyhow!("No project"))?,
1596 buffer_handle.clone(),
1597 cx.clone(),
1598 )
1599 .await
1600 .context("inlay hints proto response conversion")
1601 })
1602 } else {
1603 let lsp_request_task = self.request_lsp(
1604 buffer_handle.clone(),
1605 LanguageServerToQuery::Primary,
1606 lsp_request,
1607 cx,
1608 );
1609 cx.spawn(move |_, mut cx| async move {
1610 buffer_handle
1611 .update(&mut cx, |buffer, _| {
1612 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
1613 })?
1614 .await
1615 .context("waiting for inlay hint request range edits")?;
1616 lsp_request_task.await.context("inlay hints LSP request")
1617 })
1618 }
1619 }
1620
1621 pub fn signature_help<T: ToPointUtf16>(
1622 &self,
1623 buffer: &Model<Buffer>,
1624 position: T,
1625 cx: &mut ModelContext<Self>,
1626 ) -> Task<Vec<SignatureHelp>> {
1627 let position = position.to_point_utf16(buffer.read(cx));
1628
1629 if let Some(client) = self.upstream_client.clone() {
1630 let request_task = client.request(proto::MultiLspQuery {
1631 buffer_id: buffer.read(cx).remote_id().into(),
1632 version: serialize_version(&buffer.read(cx).version()),
1633 project_id: self.project_id,
1634 strategy: Some(proto::multi_lsp_query::Strategy::All(
1635 proto::AllLanguageServers {},
1636 )),
1637 request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
1638 GetSignatureHelp { position }.to_proto(self.project_id, buffer.read(cx)),
1639 )),
1640 });
1641 let buffer = buffer.clone();
1642 cx.spawn(|weak_project, cx| async move {
1643 let Some(project) = weak_project.upgrade() else {
1644 return Vec::new();
1645 };
1646 join_all(
1647 request_task
1648 .await
1649 .log_err()
1650 .map(|response| response.responses)
1651 .unwrap_or_default()
1652 .into_iter()
1653 .filter_map(|lsp_response| match lsp_response.response? {
1654 proto::lsp_response::Response::GetSignatureHelpResponse(response) => {
1655 Some(response)
1656 }
1657 unexpected => {
1658 debug_panic!("Unexpected response: {unexpected:?}");
1659 None
1660 }
1661 })
1662 .map(|signature_response| {
1663 let response = GetSignatureHelp { position }.response_from_proto(
1664 signature_response,
1665 project.clone(),
1666 buffer.clone(),
1667 cx.clone(),
1668 );
1669 async move { response.await.log_err().flatten() }
1670 }),
1671 )
1672 .await
1673 .into_iter()
1674 .flatten()
1675 .collect()
1676 })
1677 } else {
1678 let all_actions_task = self.request_multiple_lsp_locally(
1679 buffer,
1680 Some(position),
1681 GetSignatureHelp { position },
1682 cx,
1683 );
1684 cx.spawn(|_, _| async move {
1685 all_actions_task
1686 .await
1687 .into_iter()
1688 .flatten()
1689 .filter(|help| !help.markdown.is_empty())
1690 .collect::<Vec<_>>()
1691 })
1692 }
1693 }
1694
1695 pub fn hover(
1696 &self,
1697 buffer: &Model<Buffer>,
1698 position: PointUtf16,
1699 cx: &mut ModelContext<Self>,
1700 ) -> Task<Vec<Hover>> {
1701 if let Some(client) = self.upstream_client.clone() {
1702 let request_task = client.request(proto::MultiLspQuery {
1703 buffer_id: buffer.read(cx).remote_id().into(),
1704 version: serialize_version(&buffer.read(cx).version()),
1705 project_id: self.project_id,
1706 strategy: Some(proto::multi_lsp_query::Strategy::All(
1707 proto::AllLanguageServers {},
1708 )),
1709 request: Some(proto::multi_lsp_query::Request::GetHover(
1710 GetHover { position }.to_proto(self.project_id, buffer.read(cx)),
1711 )),
1712 });
1713 let buffer = buffer.clone();
1714 cx.spawn(|weak_project, cx| async move {
1715 let Some(project) = weak_project.upgrade() else {
1716 return Vec::new();
1717 };
1718 join_all(
1719 request_task
1720 .await
1721 .log_err()
1722 .map(|response| response.responses)
1723 .unwrap_or_default()
1724 .into_iter()
1725 .filter_map(|lsp_response| match lsp_response.response? {
1726 proto::lsp_response::Response::GetHoverResponse(response) => {
1727 Some(response)
1728 }
1729 unexpected => {
1730 debug_panic!("Unexpected response: {unexpected:?}");
1731 None
1732 }
1733 })
1734 .map(|hover_response| {
1735 let response = GetHover { position }.response_from_proto(
1736 hover_response,
1737 project.clone(),
1738 buffer.clone(),
1739 cx.clone(),
1740 );
1741 async move {
1742 response
1743 .await
1744 .log_err()
1745 .flatten()
1746 .and_then(remove_empty_hover_blocks)
1747 }
1748 }),
1749 )
1750 .await
1751 .into_iter()
1752 .flatten()
1753 .collect()
1754 })
1755 } else {
1756 let all_actions_task = self.request_multiple_lsp_locally(
1757 &buffer,
1758 Some(position),
1759 GetHover { position },
1760 cx,
1761 );
1762 cx.spawn(|_, _| async move {
1763 all_actions_task
1764 .await
1765 .into_iter()
1766 .filter_map(|hover| remove_empty_hover_blocks(hover?))
1767 .collect::<Vec<Hover>>()
1768 })
1769 }
1770 }
1771
1772 pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
1773 let language_registry = self.languages.clone();
1774
1775 if let Some(upstream_client) = self.upstream_client.as_ref() {
1776 let request = upstream_client.request(proto::GetProjectSymbols {
1777 project_id: self.project_id,
1778 query: query.to_string(),
1779 });
1780 cx.foreground_executor().spawn(async move {
1781 let response = request.await?;
1782 let mut symbols = Vec::new();
1783 let core_symbols = response
1784 .symbols
1785 .into_iter()
1786 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
1787 .collect::<Vec<_>>();
1788 populate_labels_for_symbols(
1789 core_symbols,
1790 &language_registry,
1791 None,
1792 None,
1793 &mut symbols,
1794 )
1795 .await;
1796 Ok(symbols)
1797 })
1798 } else {
1799 struct WorkspaceSymbolsResult {
1800 lsp_adapter: Arc<CachedLspAdapter>,
1801 language: Arc<Language>,
1802 worktree: WeakModel<Worktree>,
1803 worktree_abs_path: Arc<Path>,
1804 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
1805 }
1806
1807 let mut requests = Vec::new();
1808 for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
1809 let Some(worktree_handle) = self
1810 .worktree_store
1811 .read(cx)
1812 .worktree_for_id(*worktree_id, cx)
1813 else {
1814 continue;
1815 };
1816 let worktree = worktree_handle.read(cx);
1817 if !worktree.is_visible() {
1818 continue;
1819 }
1820 let worktree_abs_path = worktree.abs_path().clone();
1821
1822 let (lsp_adapter, language, server) = match self.language_servers.get(server_id) {
1823 Some(LanguageServerState::Running {
1824 adapter,
1825 language,
1826 server,
1827 ..
1828 }) => (adapter.clone(), language.clone(), server),
1829
1830 _ => continue,
1831 };
1832
1833 requests.push(
1834 server
1835 .request::<lsp::request::WorkspaceSymbolRequest>(
1836 lsp::WorkspaceSymbolParams {
1837 query: query.to_string(),
1838 ..Default::default()
1839 },
1840 )
1841 .log_err()
1842 .map(move |response| {
1843 let lsp_symbols = response.flatten().map(|symbol_response| match symbol_response {
1844 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
1845 flat_responses.into_iter().map(|lsp_symbol| {
1846 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
1847 }).collect::<Vec<_>>()
1848 }
1849 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
1850 nested_responses.into_iter().filter_map(|lsp_symbol| {
1851 let location = match lsp_symbol.location {
1852 OneOf::Left(location) => location,
1853 OneOf::Right(_) => {
1854 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
1855 return None
1856 }
1857 };
1858 Some((lsp_symbol.name, lsp_symbol.kind, location))
1859 }).collect::<Vec<_>>()
1860 }
1861 }).unwrap_or_default();
1862
1863 WorkspaceSymbolsResult {
1864 lsp_adapter,
1865 language,
1866 worktree: worktree_handle.downgrade(),
1867 worktree_abs_path,
1868 lsp_symbols,
1869 }
1870 }),
1871 );
1872 }
1873
1874 cx.spawn(move |this, mut cx| async move {
1875 let responses = futures::future::join_all(requests).await;
1876 let this = match this.upgrade() {
1877 Some(this) => this,
1878 None => return Ok(Vec::new()),
1879 };
1880
1881 let mut symbols = Vec::new();
1882 for result in responses {
1883 let core_symbols = this.update(&mut cx, |this, cx| {
1884 result
1885 .lsp_symbols
1886 .into_iter()
1887 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
1888 let abs_path = symbol_location.uri.to_file_path().ok()?;
1889 let source_worktree = result.worktree.upgrade()?;
1890 let source_worktree_id = source_worktree.read(cx).id();
1891
1892 let path;
1893 let worktree;
1894 if let Some((tree, rel_path)) =
1895 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
1896 {
1897 worktree = tree;
1898 path = rel_path;
1899 } else {
1900 worktree = source_worktree.clone();
1901 path = relativize_path(&result.worktree_abs_path, &abs_path);
1902 }
1903
1904 let worktree_id = worktree.read(cx).id();
1905 let project_path = ProjectPath {
1906 worktree_id,
1907 path: path.into(),
1908 };
1909 let signature = this.symbol_signature(&project_path);
1910 Some(CoreSymbol {
1911 language_server_name: result.lsp_adapter.name.clone(),
1912 source_worktree_id,
1913 path: project_path,
1914 kind: symbol_kind,
1915 name: symbol_name,
1916 range: range_from_lsp(symbol_location.range),
1917 signature,
1918 })
1919 })
1920 .collect()
1921 })?;
1922
1923 populate_labels_for_symbols(
1924 core_symbols,
1925 &language_registry,
1926 Some(result.language),
1927 Some(result.lsp_adapter),
1928 &mut symbols,
1929 )
1930 .await;
1931 }
1932
1933 Ok(symbols)
1934 })
1935 }
1936 }
1937
1938 pub fn diagnostic_summaries<'a>(
1939 &'a self,
1940 include_ignored: bool,
1941 cx: &'a AppContext,
1942 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
1943 self.worktree_store
1944 .read(cx)
1945 .visible_worktrees(cx)
1946 .filter_map(|worktree| {
1947 let worktree = worktree.read(cx);
1948 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
1949 })
1950 .flat_map(move |(worktree, summaries)| {
1951 let worktree_id = worktree.id();
1952 summaries
1953 .iter()
1954 .filter(move |(path, _)| {
1955 include_ignored
1956 || worktree
1957 .entry_for_path(path.as_ref())
1958 .map_or(false, |entry| !entry.is_ignored)
1959 })
1960 .flat_map(move |(path, summaries)| {
1961 summaries.iter().map(move |(server_id, summary)| {
1962 (
1963 ProjectPath {
1964 worktree_id,
1965 path: path.clone(),
1966 },
1967 *server_id,
1968 *summary,
1969 )
1970 })
1971 })
1972 })
1973 }
1974
1975 pub fn started_language_servers(&self) -> Vec<(WorktreeId, LanguageServerName)> {
1976 self.language_server_ids.keys().cloned().collect()
1977 }
1978
1979 pub fn on_buffer_edited(
1980 &mut self,
1981 buffer: Model<Buffer>,
1982 cx: &mut ModelContext<Self>,
1983 ) -> Option<()> {
1984 let buffer = buffer.read(cx);
1985 let file = File::from_dyn(buffer.file())?;
1986 let abs_path = file.as_local()?.abs_path(cx);
1987 let uri = lsp::Url::from_file_path(abs_path).unwrap();
1988 let next_snapshot = buffer.text_snapshot();
1989
1990 let language_servers: Vec<_> = self
1991 .language_servers_for_buffer(buffer, cx)
1992 .map(|i| i.1.clone())
1993 .collect();
1994
1995 for language_server in language_servers {
1996 let language_server = language_server.clone();
1997
1998 let buffer_snapshots = self
1999 .buffer_snapshots
2000 .get_mut(&buffer.remote_id())
2001 .and_then(|m| m.get_mut(&language_server.server_id()))?;
2002 let previous_snapshot = buffer_snapshots.last()?;
2003
2004 let build_incremental_change = || {
2005 buffer
2006 .edits_since::<(PointUtf16, usize)>(previous_snapshot.snapshot.version())
2007 .map(|edit| {
2008 let edit_start = edit.new.start.0;
2009 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
2010 let new_text = next_snapshot
2011 .text_for_range(edit.new.start.1..edit.new.end.1)
2012 .collect();
2013 lsp::TextDocumentContentChangeEvent {
2014 range: Some(lsp::Range::new(
2015 point_to_lsp(edit_start),
2016 point_to_lsp(edit_end),
2017 )),
2018 range_length: None,
2019 text: new_text,
2020 }
2021 })
2022 .collect()
2023 };
2024
2025 let document_sync_kind = language_server
2026 .capabilities()
2027 .text_document_sync
2028 .as_ref()
2029 .and_then(|sync| match sync {
2030 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
2031 lsp::TextDocumentSyncCapability::Options(options) => options.change,
2032 });
2033
2034 let content_changes: Vec<_> = match document_sync_kind {
2035 Some(lsp::TextDocumentSyncKind::FULL) => {
2036 vec![lsp::TextDocumentContentChangeEvent {
2037 range: None,
2038 range_length: None,
2039 text: next_snapshot.text(),
2040 }]
2041 }
2042 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
2043 _ => {
2044 #[cfg(any(test, feature = "test-support"))]
2045 {
2046 build_incremental_change()
2047 }
2048
2049 #[cfg(not(any(test, feature = "test-support")))]
2050 {
2051 continue;
2052 }
2053 }
2054 };
2055
2056 let next_version = previous_snapshot.version + 1;
2057 buffer_snapshots.push(LspBufferSnapshot {
2058 version: next_version,
2059 snapshot: next_snapshot.clone(),
2060 });
2061
2062 language_server
2063 .notify::<lsp::notification::DidChangeTextDocument>(
2064 lsp::DidChangeTextDocumentParams {
2065 text_document: lsp::VersionedTextDocumentIdentifier::new(
2066 uri.clone(),
2067 next_version,
2068 ),
2069 content_changes,
2070 },
2071 )
2072 .log_err();
2073 }
2074
2075 None
2076 }
2077
2078 pub fn on_buffer_saved(
2079 &mut self,
2080 buffer: Model<Buffer>,
2081 cx: &mut ModelContext<Self>,
2082 ) -> Option<()> {
2083 let file = File::from_dyn(buffer.read(cx).file())?;
2084 let worktree_id = file.worktree_id(cx);
2085 let abs_path = file.as_local()?.abs_path(cx);
2086 let text_document = lsp::TextDocumentIdentifier {
2087 uri: lsp::Url::from_file_path(abs_path).log_err()?,
2088 };
2089
2090 for (_, _, server) in self.language_servers_for_worktree(worktree_id) {
2091 if let Some(include_text) = include_text(server.as_ref()) {
2092 let text = if include_text {
2093 Some(buffer.read(cx).text())
2094 } else {
2095 None
2096 };
2097 server
2098 .notify::<lsp::notification::DidSaveTextDocument>(
2099 lsp::DidSaveTextDocumentParams {
2100 text_document: text_document.clone(),
2101 text,
2102 },
2103 )
2104 .log_err();
2105 }
2106 }
2107
2108 for language_server_id in self.language_server_ids_for_buffer(buffer.read(cx), cx) {
2109 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
2110 }
2111
2112 None
2113 }
2114
2115 fn maintain_workspace_config(cx: &mut ModelContext<Self>) -> Task<Result<()>> {
2116 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
2117 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
2118
2119 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
2120 *settings_changed_tx.borrow_mut() = ();
2121 });
2122
2123 cx.spawn(move |this, mut cx| async move {
2124 while let Some(()) = settings_changed_rx.next().await {
2125 let servers = this.update(&mut cx, |this, cx| {
2126 this.language_server_ids
2127 .iter()
2128 .filter_map(|((worktree_id, _), server_id)| {
2129 let worktree = this
2130 .worktree_store
2131 .read(cx)
2132 .worktree_for_id(*worktree_id, cx)?;
2133 let state = this.language_servers.get(server_id)?;
2134 let delegate = ProjectLspAdapterDelegate::new(this, &worktree, cx);
2135 match state {
2136 LanguageServerState::Starting(_) => None,
2137 LanguageServerState::Running {
2138 adapter, server, ..
2139 } => Some((
2140 adapter.adapter.clone(),
2141 server.clone(),
2142 delegate as Arc<dyn LspAdapterDelegate>,
2143 )),
2144 }
2145 })
2146 .collect::<Vec<_>>()
2147 })?;
2148
2149 for (adapter, server, delegate) in servers {
2150 let settings = adapter.workspace_configuration(&delegate, &mut cx).await?;
2151
2152 server
2153 .notify::<lsp::notification::DidChangeConfiguration>(
2154 lsp::DidChangeConfigurationParams { settings },
2155 )
2156 .ok();
2157 }
2158 }
2159
2160 drop(settings_observation);
2161 anyhow::Ok(())
2162 })
2163 }
2164
2165 pub fn primary_language_server_for_buffer<'a>(
2166 &'a self,
2167 buffer: &'a Buffer,
2168 cx: &'a AppContext,
2169 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
2170 // The list of language servers is ordered based on the `language_servers` setting
2171 // for each language, thus we can consider the first one in the list to be the
2172 // primary one.
2173 self.language_servers_for_buffer(buffer, cx).next()
2174 }
2175
2176 pub fn language_server_for_buffer<'a>(
2177 &'a self,
2178 buffer: &'a Buffer,
2179 server_id: LanguageServerId,
2180 cx: &'a AppContext,
2181 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
2182 self.language_servers_for_buffer(buffer, cx)
2183 .find(|(_, s)| s.server_id() == server_id)
2184 }
2185
2186 fn language_servers_for_worktree(
2187 &self,
2188 worktree_id: WorktreeId,
2189 ) -> impl Iterator<Item = (&Arc<CachedLspAdapter>, &Arc<Language>, &Arc<LanguageServer>)> {
2190 self.language_server_ids
2191 .iter()
2192 .filter_map(move |((language_server_worktree_id, _), id)| {
2193 if *language_server_worktree_id == worktree_id {
2194 if let Some(LanguageServerState::Running {
2195 adapter,
2196 language,
2197 server,
2198 ..
2199 }) = self.language_servers.get(id)
2200 {
2201 return Some((adapter, language, server));
2202 }
2203 }
2204 None
2205 })
2206 }
2207
2208 pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
2209 self.diagnostics.remove(&id_to_remove);
2210 self.diagnostic_summaries.remove(&id_to_remove);
2211
2212 let mut servers_to_remove = HashMap::default();
2213 let mut servers_to_preserve = HashSet::default();
2214 for ((worktree_id, server_name), &server_id) in &self.language_server_ids {
2215 if worktree_id == &id_to_remove {
2216 servers_to_remove.insert(server_id, server_name.clone());
2217 } else {
2218 servers_to_preserve.insert(server_id);
2219 }
2220 }
2221 servers_to_remove.retain(|server_id, _| !servers_to_preserve.contains(server_id));
2222 for (server_id_to_remove, server_name) in servers_to_remove {
2223 self.language_server_ids
2224 .remove(&(id_to_remove, server_name));
2225 self.language_server_statuses.remove(&server_id_to_remove);
2226 self.language_server_watched_paths
2227 .remove(&server_id_to_remove);
2228 self.last_workspace_edits_by_language_server
2229 .remove(&server_id_to_remove);
2230 self.language_servers.remove(&server_id_to_remove);
2231 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id_to_remove));
2232 }
2233 }
2234
2235 pub fn shared(
2236 &mut self,
2237 project_id: u64,
2238 downstream_client: AnyProtoClient,
2239 _: &mut ModelContext<Self>,
2240 ) {
2241 self.project_id = project_id;
2242 self.downstream_client = Some(downstream_client.clone());
2243
2244 for (server_id, status) in &self.language_server_statuses {
2245 downstream_client
2246 .send(proto::StartLanguageServer {
2247 project_id,
2248 server: Some(proto::LanguageServer {
2249 id: server_id.0 as u64,
2250 name: status.name.clone(),
2251 }),
2252 })
2253 .log_err();
2254 }
2255 }
2256
2257 pub fn disconnected_from_host(&mut self) {
2258 self.downstream_client.take();
2259 }
2260
2261 pub(crate) fn set_language_server_statuses_from_proto(
2262 &mut self,
2263 language_servers: Vec<proto::LanguageServer>,
2264 ) {
2265 self.language_server_statuses = language_servers
2266 .into_iter()
2267 .map(|server| {
2268 (
2269 LanguageServerId(server.id as usize),
2270 LanguageServerStatus {
2271 name: server.name,
2272 pending_work: Default::default(),
2273 has_pending_diagnostic_updates: false,
2274 progress_tokens: Default::default(),
2275 },
2276 )
2277 })
2278 .collect();
2279 }
2280
2281 pub(crate) fn register_language_server(
2282 &mut self,
2283 worktree_id: WorktreeId,
2284 language_server_name: LanguageServerName,
2285 language_server_id: LanguageServerId,
2286 ) {
2287 self.language_server_ids
2288 .insert((worktree_id, language_server_name), language_server_id);
2289 }
2290
2291 pub(crate) fn register_buffer_with_language_servers(
2292 &mut self,
2293 buffer_handle: &Model<Buffer>,
2294 cx: &mut ModelContext<Self>,
2295 ) {
2296 let buffer = buffer_handle.read(cx);
2297 let buffer_id = buffer.remote_id();
2298
2299 if let Some(file) = File::from_dyn(buffer.file()) {
2300 if !file.is_local() {
2301 return;
2302 }
2303
2304 let abs_path = file.abs_path(cx);
2305 let Some(uri) = lsp::Url::from_file_path(&abs_path).log_err() else {
2306 return;
2307 };
2308 let initial_snapshot = buffer.text_snapshot();
2309 let language = buffer.language().cloned();
2310 let worktree_id = file.worktree_id(cx);
2311
2312 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2313 for (server_id, diagnostics) in
2314 diagnostics.get(file.path()).cloned().unwrap_or_default()
2315 {
2316 self.update_buffer_diagnostics(buffer_handle, server_id, None, diagnostics, cx)
2317 .log_err();
2318 }
2319 }
2320
2321 if let Some(language) = language {
2322 for adapter in self.languages.lsp_adapters(&language) {
2323 let server = self
2324 .language_server_ids
2325 .get(&(worktree_id, adapter.name.clone()))
2326 .and_then(|id| self.language_servers.get(id))
2327 .and_then(|server_state| {
2328 if let LanguageServerState::Running { server, .. } = server_state {
2329 Some(server.clone())
2330 } else {
2331 None
2332 }
2333 });
2334 let server = match server {
2335 Some(server) => server,
2336 None => continue,
2337 };
2338
2339 server
2340 .notify::<lsp::notification::DidOpenTextDocument>(
2341 lsp::DidOpenTextDocumentParams {
2342 text_document: lsp::TextDocumentItem::new(
2343 uri.clone(),
2344 adapter.language_id(&language),
2345 0,
2346 initial_snapshot.text(),
2347 ),
2348 },
2349 )
2350 .log_err();
2351
2352 buffer_handle.update(cx, |buffer, cx| {
2353 buffer.set_completion_triggers(
2354 server
2355 .capabilities()
2356 .completion_provider
2357 .as_ref()
2358 .and_then(|provider| provider.trigger_characters.clone())
2359 .unwrap_or_default(),
2360 cx,
2361 );
2362 });
2363
2364 let snapshot = LspBufferSnapshot {
2365 version: 0,
2366 snapshot: initial_snapshot.clone(),
2367 };
2368 self.buffer_snapshots
2369 .entry(buffer_id)
2370 .or_default()
2371 .insert(server.server_id(), vec![snapshot]);
2372 }
2373 }
2374 }
2375 }
2376
2377 pub(crate) fn unregister_buffer_from_language_servers(
2378 &mut self,
2379 buffer: &Model<Buffer>,
2380 old_file: &File,
2381 cx: &mut AppContext,
2382 ) {
2383 let old_path = match old_file.as_local() {
2384 Some(local) => local.abs_path(cx),
2385 None => return,
2386 };
2387
2388 buffer.update(cx, |buffer, cx| {
2389 let worktree_id = old_file.worktree_id(cx);
2390
2391 let ids = &self.language_server_ids;
2392
2393 if let Some(language) = buffer.language().cloned() {
2394 for adapter in self.languages.lsp_adapters(&language) {
2395 if let Some(server_id) = ids.get(&(worktree_id, adapter.name.clone())) {
2396 buffer.update_diagnostics(*server_id, Default::default(), cx);
2397 }
2398 }
2399 }
2400
2401 self.buffer_snapshots.remove(&buffer.remote_id());
2402 let file_url = lsp::Url::from_file_path(old_path).unwrap();
2403 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2404 language_server
2405 .notify::<lsp::notification::DidCloseTextDocument>(
2406 lsp::DidCloseTextDocumentParams {
2407 text_document: lsp::TextDocumentIdentifier::new(file_url.clone()),
2408 },
2409 )
2410 .log_err();
2411 }
2412 });
2413 }
2414
2415 pub fn update_diagnostic_entries(
2416 &mut self,
2417 server_id: LanguageServerId,
2418 abs_path: PathBuf,
2419 version: Option<i32>,
2420 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2421 cx: &mut ModelContext<Self>,
2422 ) -> Result<(), anyhow::Error> {
2423 let (worktree, relative_path) =
2424 self.worktree_store
2425 .read(cx)
2426 .find_worktree(&abs_path, cx)
2427 .ok_or_else(|| anyhow!("no worktree found for diagnostics path {abs_path:?}"))?;
2428
2429 let project_path = ProjectPath {
2430 worktree_id: worktree.read(cx).id(),
2431 path: relative_path.into(),
2432 };
2433
2434 if let Some(buffer) = self.buffer_store.read(cx).get_by_path(&project_path, cx) {
2435 self.update_buffer_diagnostics(&buffer, server_id, version, diagnostics.clone(), cx)?;
2436 }
2437
2438 let updated = worktree.update(cx, |worktree, cx| {
2439 self.update_worktree_diagnostics(
2440 worktree.id(),
2441 server_id,
2442 project_path.path.clone(),
2443 diagnostics,
2444 cx,
2445 )
2446 })?;
2447 if updated {
2448 cx.emit(LspStoreEvent::DiagnosticsUpdated {
2449 language_server_id: server_id,
2450 path: project_path,
2451 })
2452 }
2453 Ok(())
2454 }
2455
2456 pub fn update_worktree_diagnostics(
2457 &mut self,
2458 worktree_id: WorktreeId,
2459 server_id: LanguageServerId,
2460 worktree_path: Arc<Path>,
2461 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2462 _: &mut ModelContext<Worktree>,
2463 ) -> Result<bool> {
2464 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
2465 let diagnostics_for_tree = self.diagnostics.entry(worktree_id).or_default();
2466 let summaries_by_server_id = summaries_for_tree.entry(worktree_path.clone()).or_default();
2467
2468 let old_summary = summaries_by_server_id
2469 .remove(&server_id)
2470 .unwrap_or_default();
2471
2472 let new_summary = DiagnosticSummary::new(&diagnostics);
2473 if new_summary.is_empty() {
2474 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&worktree_path) {
2475 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
2476 diagnostics_by_server_id.remove(ix);
2477 }
2478 if diagnostics_by_server_id.is_empty() {
2479 diagnostics_for_tree.remove(&worktree_path);
2480 }
2481 }
2482 } else {
2483 summaries_by_server_id.insert(server_id, new_summary);
2484 let diagnostics_by_server_id = diagnostics_for_tree
2485 .entry(worktree_path.clone())
2486 .or_default();
2487 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
2488 Ok(ix) => {
2489 diagnostics_by_server_id[ix] = (server_id, diagnostics);
2490 }
2491 Err(ix) => {
2492 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
2493 }
2494 }
2495 }
2496
2497 if !old_summary.is_empty() || !new_summary.is_empty() {
2498 if let Some(downstream_client) = &self.downstream_client {
2499 downstream_client
2500 .send(proto::UpdateDiagnosticSummary {
2501 project_id: self.project_id,
2502 worktree_id: worktree_id.to_proto(),
2503 summary: Some(proto::DiagnosticSummary {
2504 path: worktree_path.to_string_lossy().to_string(),
2505 language_server_id: server_id.0 as u64,
2506 error_count: new_summary.error_count as u32,
2507 warning_count: new_summary.warning_count as u32,
2508 }),
2509 })
2510 .log_err();
2511 }
2512 }
2513
2514 Ok(!old_summary.is_empty() || !new_summary.is_empty())
2515 }
2516
2517 pub fn open_buffer_for_symbol(
2518 &mut self,
2519 symbol: &Symbol,
2520 cx: &mut ModelContext<Self>,
2521 ) -> Task<Result<Model<Buffer>>> {
2522 if let Some(client) = self.upstream_client.clone() {
2523 let request = client.request(proto::OpenBufferForSymbol {
2524 project_id: self.project_id,
2525 symbol: Some(Self::serialize_symbol(symbol)),
2526 });
2527 cx.spawn(move |this, mut cx| async move {
2528 let response = request.await?;
2529 let buffer_id = BufferId::new(response.buffer_id)?;
2530 this.update(&mut cx, |this, cx| {
2531 this.wait_for_remote_buffer(buffer_id, cx)
2532 })?
2533 .await
2534 })
2535 } else {
2536 let Some(&language_server_id) = self.language_server_ids.get(&(
2537 symbol.source_worktree_id,
2538 symbol.language_server_name.clone(),
2539 )) else {
2540 return Task::ready(Err(anyhow!(
2541 "language server for worktree and language not found"
2542 )));
2543 };
2544
2545 let worktree_abs_path = if let Some(worktree_abs_path) = self
2546 .worktree_store
2547 .read(cx)
2548 .worktree_for_id(symbol.path.worktree_id, cx)
2549 .map(|worktree| worktree.read(cx).abs_path())
2550 {
2551 worktree_abs_path
2552 } else {
2553 return Task::ready(Err(anyhow!("worktree not found for symbol")));
2554 };
2555
2556 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
2557 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
2558 uri
2559 } else {
2560 return Task::ready(Err(anyhow!("invalid symbol path")));
2561 };
2562
2563 self.open_local_buffer_via_lsp(
2564 symbol_uri,
2565 language_server_id,
2566 symbol.language_server_name.clone(),
2567 cx,
2568 )
2569 }
2570 }
2571
2572 pub fn open_local_buffer_via_lsp(
2573 &mut self,
2574 mut abs_path: lsp::Url,
2575 language_server_id: LanguageServerId,
2576 language_server_name: LanguageServerName,
2577 cx: &mut ModelContext<Self>,
2578 ) -> Task<Result<Model<Buffer>>> {
2579 cx.spawn(move |this, mut cx| async move {
2580 // Escape percent-encoded string.
2581 let current_scheme = abs_path.scheme().to_owned();
2582 let _ = abs_path.set_scheme("file");
2583
2584 let abs_path = abs_path
2585 .to_file_path()
2586 .map_err(|_| anyhow!("can't convert URI to path"))?;
2587 let p = abs_path.clone();
2588 let yarn_worktree = this
2589 .update(&mut cx, move |this, cx| {
2590 this.yarn.update(cx, |_, cx| {
2591 cx.spawn(|this, mut cx| async move {
2592 let t = this
2593 .update(&mut cx, |this, cx| {
2594 this.process_path(&p, ¤t_scheme, cx)
2595 })
2596 .ok()?;
2597 t.await
2598 })
2599 })
2600 })?
2601 .await;
2602 let (worktree_root_target, known_relative_path) =
2603 if let Some((zip_root, relative_path)) = yarn_worktree {
2604 (zip_root, Some(relative_path))
2605 } else {
2606 (Arc::<Path>::from(abs_path.as_path()), None)
2607 };
2608 let (worktree, relative_path) = if let Some(result) =
2609 this.update(&mut cx, |this, cx| {
2610 this.worktree_store.update(cx, |worktree_store, cx| {
2611 worktree_store.find_worktree(&worktree_root_target, cx)
2612 })
2613 })? {
2614 let relative_path =
2615 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
2616 (result.0, relative_path)
2617 } else {
2618 let worktree = this
2619 .update(&mut cx, |this, cx| {
2620 this.worktree_store.update(cx, |worktree_store, cx| {
2621 worktree_store.create_worktree(&worktree_root_target, false, cx)
2622 })
2623 })?
2624 .await?;
2625 this.update(&mut cx, |this, cx| {
2626 this.register_language_server(
2627 worktree.read(cx).id(),
2628 language_server_name,
2629 language_server_id,
2630 )
2631 })
2632 .ok();
2633 let worktree_root = worktree.update(&mut cx, |this, _| this.abs_path())?;
2634 let relative_path = if let Some(known_path) = known_relative_path {
2635 known_path
2636 } else {
2637 abs_path.strip_prefix(worktree_root)?.into()
2638 };
2639 (worktree, relative_path)
2640 };
2641 let project_path = ProjectPath {
2642 worktree_id: worktree.update(&mut cx, |worktree, _| worktree.id())?,
2643 path: relative_path,
2644 };
2645 this.update(&mut cx, |this, cx| {
2646 this.buffer_store().update(cx, |buffer_store, cx| {
2647 buffer_store.open_buffer(project_path, cx)
2648 })
2649 })?
2650 .await
2651 })
2652 }
2653
2654 pub(crate) fn update_buffer_diagnostics(
2655 &mut self,
2656 buffer: &Model<Buffer>,
2657 server_id: LanguageServerId,
2658 version: Option<i32>,
2659 mut diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2660 cx: &mut ModelContext<Self>,
2661 ) -> Result<()> {
2662 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2663 Ordering::Equal
2664 .then_with(|| b.is_primary.cmp(&a.is_primary))
2665 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2666 .then_with(|| a.severity.cmp(&b.severity))
2667 .then_with(|| a.message.cmp(&b.message))
2668 }
2669
2670 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2671
2672 diagnostics.sort_unstable_by(|a, b| {
2673 Ordering::Equal
2674 .then_with(|| a.range.start.cmp(&b.range.start))
2675 .then_with(|| b.range.end.cmp(&a.range.end))
2676 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2677 });
2678
2679 let mut sanitized_diagnostics = Vec::new();
2680 let edits_since_save = Patch::new(
2681 snapshot
2682 .edits_since::<Unclipped<PointUtf16>>(buffer.read(cx).saved_version())
2683 .collect(),
2684 );
2685 for entry in diagnostics {
2686 let start;
2687 let end;
2688 if entry.diagnostic.is_disk_based {
2689 // Some diagnostics are based on files on disk instead of buffers'
2690 // current contents. Adjust these diagnostics' ranges to reflect
2691 // any unsaved edits.
2692 start = edits_since_save.old_to_new(entry.range.start);
2693 end = edits_since_save.old_to_new(entry.range.end);
2694 } else {
2695 start = entry.range.start;
2696 end = entry.range.end;
2697 }
2698
2699 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2700 ..snapshot.clip_point_utf16(end, Bias::Right);
2701
2702 // Expand empty ranges by one codepoint
2703 if range.start == range.end {
2704 // This will be go to the next boundary when being clipped
2705 range.end.column += 1;
2706 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2707 if range.start == range.end && range.end.column > 0 {
2708 range.start.column -= 1;
2709 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2710 }
2711 }
2712
2713 sanitized_diagnostics.push(DiagnosticEntry {
2714 range,
2715 diagnostic: entry.diagnostic,
2716 });
2717 }
2718 drop(edits_since_save);
2719
2720 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2721 buffer.update(cx, |buffer, cx| {
2722 buffer.update_diagnostics(server_id, set, cx)
2723 });
2724 Ok(())
2725 }
2726
2727 fn request_multiple_lsp_locally<P, R>(
2728 &self,
2729 buffer: &Model<Buffer>,
2730 position: Option<P>,
2731 request: R,
2732 cx: &mut ModelContext<'_, Self>,
2733 ) -> Task<Vec<R::Response>>
2734 where
2735 P: ToOffset,
2736 R: LspCommand + Clone,
2737 <R::LspRequest as lsp::request::Request>::Result: Send,
2738 <R::LspRequest as lsp::request::Request>::Params: Send,
2739 {
2740 debug_assert!(self.upstream_client.is_none());
2741
2742 let snapshot = buffer.read(cx).snapshot();
2743 let scope = position.and_then(|position| snapshot.language_scope_at(position));
2744 let server_ids = self
2745 .language_servers_for_buffer(buffer.read(cx), cx)
2746 .filter(|(adapter, _)| {
2747 scope
2748 .as_ref()
2749 .map(|scope| scope.language_allowed(&adapter.name))
2750 .unwrap_or(true)
2751 })
2752 .map(|(_, server)| server.server_id())
2753 .collect::<Vec<_>>();
2754 let mut response_results = server_ids
2755 .into_iter()
2756 .map(|server_id| {
2757 self.request_lsp(
2758 buffer.clone(),
2759 LanguageServerToQuery::Other(server_id),
2760 request.clone(),
2761 cx,
2762 )
2763 })
2764 .collect::<FuturesUnordered<_>>();
2765
2766 return cx.spawn(|_, _| async move {
2767 let mut responses = Vec::with_capacity(response_results.len());
2768 while let Some(response_result) = response_results.next().await {
2769 if let Some(response) = response_result.log_err() {
2770 responses.push(response);
2771 }
2772 }
2773 responses
2774 });
2775 }
2776
2777 async fn handle_lsp_command<T: LspCommand>(
2778 this: Model<Self>,
2779 envelope: TypedEnvelope<T::ProtoRequest>,
2780 mut cx: AsyncAppContext,
2781 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
2782 where
2783 <T::LspRequest as lsp::request::Request>::Params: Send,
2784 <T::LspRequest as lsp::request::Request>::Result: Send,
2785 {
2786 let sender_id = envelope.original_sender_id()?;
2787 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
2788 let buffer_handle = this.update(&mut cx, |this, cx| {
2789 this.buffer_store.read(cx).get_existing(buffer_id)
2790 })??;
2791 let request = T::from_proto(
2792 envelope.payload,
2793 this.clone(),
2794 buffer_handle.clone(),
2795 cx.clone(),
2796 )
2797 .await?;
2798 let response = this
2799 .update(&mut cx, |this, cx| {
2800 this.request_lsp(
2801 buffer_handle.clone(),
2802 LanguageServerToQuery::Primary,
2803 request,
2804 cx,
2805 )
2806 })?
2807 .await?;
2808 this.update(&mut cx, |this, cx| {
2809 Ok(T::response_to_proto(
2810 response,
2811 this,
2812 sender_id,
2813 &buffer_handle.read(cx).version(),
2814 cx,
2815 ))
2816 })?
2817 }
2818
2819 async fn handle_multi_lsp_query(
2820 this: Model<Self>,
2821 envelope: TypedEnvelope<proto::MultiLspQuery>,
2822 mut cx: AsyncAppContext,
2823 ) -> Result<proto::MultiLspQueryResponse> {
2824 let sender_id = envelope.original_sender_id()?;
2825 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
2826 let version = deserialize_version(&envelope.payload.version);
2827 let buffer = this.update(&mut cx, |this, cx| {
2828 this.buffer_store.read(cx).get_existing(buffer_id)
2829 })??;
2830 buffer
2831 .update(&mut cx, |buffer, _| {
2832 buffer.wait_for_version(version.clone())
2833 })?
2834 .await?;
2835 let buffer_version = buffer.update(&mut cx, |buffer, _| buffer.version())?;
2836 match envelope
2837 .payload
2838 .strategy
2839 .context("invalid request without the strategy")?
2840 {
2841 proto::multi_lsp_query::Strategy::All(_) => {
2842 // currently, there's only one multiple language servers query strategy,
2843 // so just ensure it's specified correctly
2844 }
2845 }
2846 match envelope.payload.request {
2847 Some(proto::multi_lsp_query::Request::GetHover(get_hover)) => {
2848 let get_hover =
2849 GetHover::from_proto(get_hover, this.clone(), buffer.clone(), cx.clone())
2850 .await?;
2851 let all_hovers = this
2852 .update(&mut cx, |this, cx| {
2853 this.request_multiple_lsp_locally(
2854 &buffer,
2855 Some(get_hover.position),
2856 get_hover,
2857 cx,
2858 )
2859 })?
2860 .await
2861 .into_iter()
2862 .filter_map(|hover| remove_empty_hover_blocks(hover?));
2863 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
2864 responses: all_hovers
2865 .map(|hover| proto::LspResponse {
2866 response: Some(proto::lsp_response::Response::GetHoverResponse(
2867 GetHover::response_to_proto(
2868 Some(hover),
2869 project,
2870 sender_id,
2871 &buffer_version,
2872 cx,
2873 ),
2874 )),
2875 })
2876 .collect(),
2877 })
2878 }
2879 Some(proto::multi_lsp_query::Request::GetCodeActions(get_code_actions)) => {
2880 let get_code_actions = GetCodeActions::from_proto(
2881 get_code_actions,
2882 this.clone(),
2883 buffer.clone(),
2884 cx.clone(),
2885 )
2886 .await?;
2887
2888 let all_actions = this
2889 .update(&mut cx, |project, cx| {
2890 project.request_multiple_lsp_locally(
2891 &buffer,
2892 Some(get_code_actions.range.start),
2893 get_code_actions,
2894 cx,
2895 )
2896 })?
2897 .await
2898 .into_iter();
2899
2900 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
2901 responses: all_actions
2902 .map(|code_actions| proto::LspResponse {
2903 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
2904 GetCodeActions::response_to_proto(
2905 code_actions,
2906 project,
2907 sender_id,
2908 &buffer_version,
2909 cx,
2910 ),
2911 )),
2912 })
2913 .collect(),
2914 })
2915 }
2916 Some(proto::multi_lsp_query::Request::GetSignatureHelp(get_signature_help)) => {
2917 let get_signature_help = GetSignatureHelp::from_proto(
2918 get_signature_help,
2919 this.clone(),
2920 buffer.clone(),
2921 cx.clone(),
2922 )
2923 .await?;
2924
2925 let all_signatures = this
2926 .update(&mut cx, |project, cx| {
2927 project.request_multiple_lsp_locally(
2928 &buffer,
2929 Some(get_signature_help.position),
2930 get_signature_help,
2931 cx,
2932 )
2933 })?
2934 .await
2935 .into_iter();
2936
2937 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
2938 responses: all_signatures
2939 .map(|signature_help| proto::LspResponse {
2940 response: Some(
2941 proto::lsp_response::Response::GetSignatureHelpResponse(
2942 GetSignatureHelp::response_to_proto(
2943 signature_help,
2944 project,
2945 sender_id,
2946 &buffer_version,
2947 cx,
2948 ),
2949 ),
2950 ),
2951 })
2952 .collect(),
2953 })
2954 }
2955 None => anyhow::bail!("empty multi lsp query request"),
2956 }
2957 }
2958
2959 async fn handle_apply_code_action(
2960 this: Model<Self>,
2961 envelope: TypedEnvelope<proto::ApplyCodeAction>,
2962 mut cx: AsyncAppContext,
2963 ) -> Result<proto::ApplyCodeActionResponse> {
2964 let sender_id = envelope.original_sender_id()?;
2965 let action = Self::deserialize_code_action(
2966 envelope
2967 .payload
2968 .action
2969 .ok_or_else(|| anyhow!("invalid action"))?,
2970 )?;
2971 let apply_code_action = this.update(&mut cx, |this, cx| {
2972 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
2973 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
2974 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
2975 })??;
2976
2977 let project_transaction = apply_code_action.await?;
2978 let project_transaction = this.update(&mut cx, |this, cx| {
2979 this.buffer_store.update(cx, |buffer_store, cx| {
2980 buffer_store.serialize_project_transaction_for_peer(
2981 project_transaction,
2982 sender_id,
2983 cx,
2984 )
2985 })
2986 })?;
2987 Ok(proto::ApplyCodeActionResponse {
2988 transaction: Some(project_transaction),
2989 })
2990 }
2991
2992 async fn handle_update_diagnostic_summary(
2993 this: Model<Self>,
2994 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
2995 mut cx: AsyncAppContext,
2996 ) -> Result<()> {
2997 this.update(&mut cx, |this, cx| {
2998 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
2999 if let Some(message) = envelope.payload.summary {
3000 let project_path = ProjectPath {
3001 worktree_id,
3002 path: Path::new(&message.path).into(),
3003 };
3004 let path = project_path.path.clone();
3005 let server_id = LanguageServerId(message.language_server_id as usize);
3006 let summary = DiagnosticSummary {
3007 error_count: message.error_count as usize,
3008 warning_count: message.warning_count as usize,
3009 };
3010
3011 if summary.is_empty() {
3012 if let Some(worktree_summaries) =
3013 this.diagnostic_summaries.get_mut(&worktree_id)
3014 {
3015 if let Some(summaries) = worktree_summaries.get_mut(&path) {
3016 summaries.remove(&server_id);
3017 if summaries.is_empty() {
3018 worktree_summaries.remove(&path);
3019 }
3020 }
3021 }
3022 } else {
3023 this.diagnostic_summaries
3024 .entry(worktree_id)
3025 .or_default()
3026 .entry(path)
3027 .or_default()
3028 .insert(server_id, summary);
3029 }
3030 cx.emit(LspStoreEvent::DiagnosticsUpdated {
3031 language_server_id: LanguageServerId(message.language_server_id as usize),
3032 path: project_path,
3033 });
3034 }
3035 Ok(())
3036 })?
3037 }
3038
3039 async fn handle_start_language_server(
3040 this: Model<Self>,
3041 envelope: TypedEnvelope<proto::StartLanguageServer>,
3042 mut cx: AsyncAppContext,
3043 ) -> Result<()> {
3044 let server = envelope
3045 .payload
3046 .server
3047 .ok_or_else(|| anyhow!("invalid server"))?;
3048 this.update(&mut cx, |this, cx| {
3049 this.language_server_statuses.insert(
3050 LanguageServerId(server.id as usize),
3051 LanguageServerStatus {
3052 name: server.name,
3053 pending_work: Default::default(),
3054 has_pending_diagnostic_updates: false,
3055 progress_tokens: Default::default(),
3056 },
3057 );
3058 cx.notify();
3059 })?;
3060 Ok(())
3061 }
3062
3063 async fn handle_update_language_server(
3064 this: Model<Self>,
3065 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
3066 mut cx: AsyncAppContext,
3067 ) -> Result<()> {
3068 this.update(&mut cx, |this, cx| {
3069 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
3070
3071 match envelope
3072 .payload
3073 .variant
3074 .ok_or_else(|| anyhow!("invalid variant"))?
3075 {
3076 proto::update_language_server::Variant::WorkStart(payload) => {
3077 this.on_lsp_work_start(
3078 language_server_id,
3079 payload.token,
3080 LanguageServerProgress {
3081 title: payload.title,
3082 is_disk_based_diagnostics_progress: false,
3083 is_cancellable: false,
3084 message: payload.message,
3085 percentage: payload.percentage.map(|p| p as usize),
3086 last_update_at: cx.background_executor().now(),
3087 },
3088 cx,
3089 );
3090 }
3091
3092 proto::update_language_server::Variant::WorkProgress(payload) => {
3093 this.on_lsp_work_progress(
3094 language_server_id,
3095 payload.token,
3096 LanguageServerProgress {
3097 title: None,
3098 is_disk_based_diagnostics_progress: false,
3099 is_cancellable: false,
3100 message: payload.message,
3101 percentage: payload.percentage.map(|p| p as usize),
3102 last_update_at: cx.background_executor().now(),
3103 },
3104 cx,
3105 );
3106 }
3107
3108 proto::update_language_server::Variant::WorkEnd(payload) => {
3109 this.on_lsp_work_end(language_server_id, payload.token, cx);
3110 }
3111
3112 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
3113 this.disk_based_diagnostics_started(language_server_id, cx);
3114 }
3115
3116 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
3117 this.disk_based_diagnostics_finished(language_server_id, cx)
3118 }
3119 }
3120
3121 Ok(())
3122 })?
3123 }
3124
3125 pub fn disk_based_diagnostics_started(
3126 &mut self,
3127 language_server_id: LanguageServerId,
3128 cx: &mut ModelContext<Self>,
3129 ) {
3130 if let Some(language_server_status) =
3131 self.language_server_statuses.get_mut(&language_server_id)
3132 {
3133 language_server_status.has_pending_diagnostic_updates = true;
3134 }
3135
3136 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
3137 }
3138
3139 pub fn disk_based_diagnostics_finished(
3140 &mut self,
3141 language_server_id: LanguageServerId,
3142 cx: &mut ModelContext<Self>,
3143 ) {
3144 if let Some(language_server_status) =
3145 self.language_server_statuses.get_mut(&language_server_id)
3146 {
3147 language_server_status.has_pending_diagnostic_updates = false;
3148 }
3149
3150 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
3151 }
3152
3153 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
3154 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
3155 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
3156 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
3157 // the language server might take some time to publish diagnostics.
3158 fn simulate_disk_based_diagnostics_events_if_needed(
3159 &mut self,
3160 language_server_id: LanguageServerId,
3161 cx: &mut ModelContext<Self>,
3162 ) {
3163 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
3164
3165 let Some(LanguageServerState::Running {
3166 simulate_disk_based_diagnostics_completion,
3167 adapter,
3168 ..
3169 }) = self.language_servers.get_mut(&language_server_id)
3170 else {
3171 return;
3172 };
3173
3174 if adapter.disk_based_diagnostics_progress_token.is_some() {
3175 return;
3176 }
3177
3178 let prev_task = simulate_disk_based_diagnostics_completion.replace(cx.spawn(
3179 move |this, mut cx| async move {
3180 cx.background_executor()
3181 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
3182 .await;
3183
3184 this.update(&mut cx, |this, cx| {
3185 this.disk_based_diagnostics_finished(language_server_id, cx);
3186
3187 if let Some(LanguageServerState::Running {
3188 simulate_disk_based_diagnostics_completion,
3189 ..
3190 }) = this.language_servers.get_mut(&language_server_id)
3191 {
3192 *simulate_disk_based_diagnostics_completion = None;
3193 }
3194 })
3195 .ok();
3196 },
3197 ));
3198
3199 if prev_task.is_none() {
3200 self.disk_based_diagnostics_started(language_server_id, cx);
3201 }
3202 }
3203
3204 pub fn language_server_statuses(
3205 &self,
3206 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
3207 self.language_server_statuses
3208 .iter()
3209 .map(|(key, value)| (*key, value))
3210 }
3211
3212 fn rebuild_watched_paths(
3213 &mut self,
3214 language_server_id: LanguageServerId,
3215 cx: &mut ModelContext<Self>,
3216 ) {
3217 let Some(watchers) = self
3218 .language_server_watcher_registrations
3219 .get(&language_server_id)
3220 else {
3221 return;
3222 };
3223
3224 let watched_paths = self
3225 .language_server_watched_paths
3226 .entry(language_server_id)
3227 .or_default();
3228
3229 let mut builders = HashMap::default();
3230 for watcher in watchers.values().flatten() {
3231 for worktree in self.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
3232 let glob_is_inside_worktree = worktree.update(cx, |tree, _| {
3233 if let Some(abs_path) = tree.abs_path().to_str() {
3234 let relative_glob_pattern = match &watcher.glob_pattern {
3235 lsp::GlobPattern::String(s) => Some(
3236 s.strip_prefix(abs_path)
3237 .unwrap_or(s)
3238 .strip_prefix(std::path::MAIN_SEPARATOR)
3239 .unwrap_or(s),
3240 ),
3241 lsp::GlobPattern::Relative(rp) => {
3242 let base_uri = match &rp.base_uri {
3243 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3244 lsp::OneOf::Right(base_uri) => base_uri,
3245 };
3246 base_uri.to_file_path().ok().and_then(|file_path| {
3247 (file_path.to_str() == Some(abs_path))
3248 .then_some(rp.pattern.as_str())
3249 })
3250 }
3251 };
3252 if let Some(relative_glob_pattern) = relative_glob_pattern {
3253 let literal_prefix = glob_literal_prefix(relative_glob_pattern);
3254 tree.as_local_mut()
3255 .unwrap()
3256 .add_path_prefix_to_scan(Path::new(literal_prefix).into());
3257 if let Some(glob) = Glob::new(relative_glob_pattern).log_err() {
3258 builders
3259 .entry(tree.id())
3260 .or_insert_with(|| GlobSetBuilder::new())
3261 .add(glob);
3262 }
3263 return true;
3264 }
3265 }
3266 false
3267 });
3268 if glob_is_inside_worktree {
3269 break;
3270 }
3271 }
3272 }
3273
3274 watched_paths.clear();
3275 for (worktree_id, builder) in builders {
3276 if let Ok(globset) = builder.build() {
3277 watched_paths.insert(worktree_id, globset);
3278 }
3279 }
3280
3281 cx.notify();
3282 }
3283
3284 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3285 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3286 Some(server.clone())
3287 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3288 Some(Arc::clone(server))
3289 } else {
3290 None
3291 }
3292 }
3293
3294 async fn on_lsp_workspace_edit(
3295 this: WeakModel<Self>,
3296 params: lsp::ApplyWorkspaceEditParams,
3297 server_id: LanguageServerId,
3298 adapter: Arc<CachedLspAdapter>,
3299 mut cx: AsyncAppContext,
3300 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3301 let this = this
3302 .upgrade()
3303 .ok_or_else(|| anyhow!("project project closed"))?;
3304 let language_server = this
3305 .update(&mut cx, |this, _| this.language_server_for_id(server_id))?
3306 .ok_or_else(|| anyhow!("language server not found"))?;
3307 let transaction = Self::deserialize_workspace_edit(
3308 this.clone(),
3309 params.edit,
3310 true,
3311 adapter.clone(),
3312 language_server.clone(),
3313 &mut cx,
3314 )
3315 .await
3316 .log_err();
3317 this.update(&mut cx, |this, _| {
3318 if let Some(transaction) = transaction {
3319 this.last_workspace_edits_by_language_server
3320 .insert(server_id, transaction);
3321 }
3322 })?;
3323 Ok(lsp::ApplyWorkspaceEditResponse {
3324 applied: true,
3325 failed_change: None,
3326 failure_reason: None,
3327 })
3328 }
3329
3330 fn on_lsp_progress(
3331 &mut self,
3332 progress: lsp::ProgressParams,
3333 language_server_id: LanguageServerId,
3334 disk_based_diagnostics_progress_token: Option<String>,
3335 cx: &mut ModelContext<Self>,
3336 ) {
3337 let token = match progress.token {
3338 lsp::NumberOrString::String(token) => token,
3339 lsp::NumberOrString::Number(token) => {
3340 log::info!("skipping numeric progress token {}", token);
3341 return;
3342 }
3343 };
3344
3345 let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
3346 let language_server_status =
3347 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3348 status
3349 } else {
3350 return;
3351 };
3352
3353 if !language_server_status.progress_tokens.contains(&token) {
3354 return;
3355 }
3356
3357 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
3358 .as_ref()
3359 .map_or(false, |disk_based_token| {
3360 token.starts_with(disk_based_token)
3361 });
3362
3363 match progress {
3364 lsp::WorkDoneProgress::Begin(report) => {
3365 if is_disk_based_diagnostics_progress {
3366 self.disk_based_diagnostics_started(language_server_id, cx);
3367 }
3368 self.on_lsp_work_start(
3369 language_server_id,
3370 token.clone(),
3371 LanguageServerProgress {
3372 title: Some(report.title),
3373 is_disk_based_diagnostics_progress,
3374 is_cancellable: report.cancellable.unwrap_or(false),
3375 message: report.message.clone(),
3376 percentage: report.percentage.map(|p| p as usize),
3377 last_update_at: cx.background_executor().now(),
3378 },
3379 cx,
3380 );
3381 }
3382 lsp::WorkDoneProgress::Report(report) => {
3383 if self.on_lsp_work_progress(
3384 language_server_id,
3385 token.clone(),
3386 LanguageServerProgress {
3387 title: None,
3388 is_disk_based_diagnostics_progress,
3389 is_cancellable: report.cancellable.unwrap_or(false),
3390 message: report.message.clone(),
3391 percentage: report.percentage.map(|p| p as usize),
3392 last_update_at: cx.background_executor().now(),
3393 },
3394 cx,
3395 ) {
3396 cx.emit(LspStoreEvent::LanguageServerUpdate {
3397 language_server_id,
3398 message: proto::update_language_server::Variant::WorkProgress(
3399 proto::LspWorkProgress {
3400 token,
3401 message: report.message,
3402 percentage: report.percentage,
3403 },
3404 ),
3405 })
3406 }
3407 }
3408 lsp::WorkDoneProgress::End(_) => {
3409 language_server_status.progress_tokens.remove(&token);
3410 self.on_lsp_work_end(language_server_id, token.clone(), cx);
3411 if is_disk_based_diagnostics_progress {
3412 self.disk_based_diagnostics_finished(language_server_id, cx);
3413 }
3414 }
3415 }
3416 }
3417
3418 fn on_lsp_work_start(
3419 &mut self,
3420 language_server_id: LanguageServerId,
3421 token: String,
3422 progress: LanguageServerProgress,
3423 cx: &mut ModelContext<Self>,
3424 ) {
3425 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3426 status.pending_work.insert(token.clone(), progress.clone());
3427 cx.notify();
3428 }
3429 cx.emit(LspStoreEvent::LanguageServerUpdate {
3430 language_server_id,
3431 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
3432 token,
3433 title: progress.title,
3434 message: progress.message,
3435 percentage: progress.percentage.map(|p| p as u32),
3436 }),
3437 })
3438 }
3439
3440 fn on_lsp_work_progress(
3441 &mut self,
3442 language_server_id: LanguageServerId,
3443 token: String,
3444 progress: LanguageServerProgress,
3445 cx: &mut ModelContext<Self>,
3446 ) -> bool {
3447 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3448 match status.pending_work.entry(token) {
3449 btree_map::Entry::Vacant(entry) => {
3450 entry.insert(progress);
3451 cx.notify();
3452 return true;
3453 }
3454 btree_map::Entry::Occupied(mut entry) => {
3455 let entry = entry.get_mut();
3456 if (progress.last_update_at - entry.last_update_at)
3457 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
3458 {
3459 entry.last_update_at = progress.last_update_at;
3460 if progress.message.is_some() {
3461 entry.message = progress.message;
3462 }
3463 if progress.percentage.is_some() {
3464 entry.percentage = progress.percentage;
3465 }
3466 cx.notify();
3467 return true;
3468 }
3469 }
3470 }
3471 }
3472
3473 false
3474 }
3475
3476 fn on_lsp_work_end(
3477 &mut self,
3478 language_server_id: LanguageServerId,
3479 token: String,
3480 cx: &mut ModelContext<Self>,
3481 ) {
3482 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3483 if let Some(work) = status.pending_work.remove(&token) {
3484 if !work.is_disk_based_diagnostics_progress {
3485 cx.emit(LspStoreEvent::RefreshInlayHints);
3486 }
3487 }
3488 cx.notify();
3489 }
3490
3491 cx.emit(LspStoreEvent::LanguageServerUpdate {
3492 language_server_id,
3493 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
3494 })
3495 }
3496
3497 fn on_lsp_did_change_watched_files(
3498 &mut self,
3499 language_server_id: LanguageServerId,
3500 registration_id: &str,
3501 params: DidChangeWatchedFilesRegistrationOptions,
3502 cx: &mut ModelContext<Self>,
3503 ) {
3504 let registrations = self
3505 .language_server_watcher_registrations
3506 .entry(language_server_id)
3507 .or_default();
3508
3509 registrations.insert(registration_id.to_string(), params.watchers);
3510
3511 self.rebuild_watched_paths(language_server_id, cx);
3512 }
3513
3514 fn on_lsp_unregister_did_change_watched_files(
3515 &mut self,
3516 language_server_id: LanguageServerId,
3517 registration_id: &str,
3518 cx: &mut ModelContext<Self>,
3519 ) {
3520 let registrations = self
3521 .language_server_watcher_registrations
3522 .entry(language_server_id)
3523 .or_default();
3524
3525 if registrations.remove(registration_id).is_some() {
3526 log::info!(
3527 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3528 language_server_id,
3529 registration_id
3530 );
3531 } else {
3532 log::warn!(
3533 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3534 language_server_id,
3535 registration_id
3536 );
3537 }
3538
3539 self.rebuild_watched_paths(language_server_id, cx);
3540 }
3541
3542 #[allow(clippy::type_complexity)]
3543 pub(crate) fn edits_from_lsp(
3544 &mut self,
3545 buffer: &Model<Buffer>,
3546 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3547 server_id: LanguageServerId,
3548 version: Option<i32>,
3549 cx: &mut ModelContext<Self>,
3550 ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
3551 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3552 cx.background_executor().spawn(async move {
3553 let snapshot = snapshot?;
3554 let mut lsp_edits = lsp_edits
3555 .into_iter()
3556 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3557 .collect::<Vec<_>>();
3558 lsp_edits.sort_by_key(|(range, _)| range.start);
3559
3560 let mut lsp_edits = lsp_edits.into_iter().peekable();
3561 let mut edits = Vec::new();
3562 while let Some((range, mut new_text)) = lsp_edits.next() {
3563 // Clip invalid ranges provided by the language server.
3564 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3565 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3566
3567 // Combine any LSP edits that are adjacent.
3568 //
3569 // Also, combine LSP edits that are separated from each other by only
3570 // a newline. This is important because for some code actions,
3571 // Rust-analyzer rewrites the entire buffer via a series of edits that
3572 // are separated by unchanged newline characters.
3573 //
3574 // In order for the diffing logic below to work properly, any edits that
3575 // cancel each other out must be combined into one.
3576 while let Some((next_range, next_text)) = lsp_edits.peek() {
3577 if next_range.start.0 > range.end {
3578 if next_range.start.0.row > range.end.row + 1
3579 || next_range.start.0.column > 0
3580 || snapshot.clip_point_utf16(
3581 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3582 Bias::Left,
3583 ) > range.end
3584 {
3585 break;
3586 }
3587 new_text.push('\n');
3588 }
3589 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3590 new_text.push_str(next_text);
3591 lsp_edits.next();
3592 }
3593
3594 // For multiline edits, perform a diff of the old and new text so that
3595 // we can identify the changes more precisely, preserving the locations
3596 // of any anchors positioned in the unchanged regions.
3597 if range.end.row > range.start.row {
3598 let mut offset = range.start.to_offset(&snapshot);
3599 let old_text = snapshot.text_for_range(range).collect::<String>();
3600
3601 let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
3602 let mut moved_since_edit = true;
3603 for change in diff.iter_all_changes() {
3604 let tag = change.tag();
3605 let value = change.value();
3606 match tag {
3607 ChangeTag::Equal => {
3608 offset += value.len();
3609 moved_since_edit = true;
3610 }
3611 ChangeTag::Delete => {
3612 let start = snapshot.anchor_after(offset);
3613 let end = snapshot.anchor_before(offset + value.len());
3614 if moved_since_edit {
3615 edits.push((start..end, String::new()));
3616 } else {
3617 edits.last_mut().unwrap().0.end = end;
3618 }
3619 offset += value.len();
3620 moved_since_edit = false;
3621 }
3622 ChangeTag::Insert => {
3623 if moved_since_edit {
3624 let anchor = snapshot.anchor_after(offset);
3625 edits.push((anchor..anchor, value.to_string()));
3626 } else {
3627 edits.last_mut().unwrap().1.push_str(value);
3628 }
3629 moved_since_edit = false;
3630 }
3631 }
3632 }
3633 } else if range.end == range.start {
3634 let anchor = snapshot.anchor_after(range.start);
3635 edits.push((anchor..anchor, new_text));
3636 } else {
3637 let edit_start = snapshot.anchor_after(range.start);
3638 let edit_end = snapshot.anchor_before(range.end);
3639 edits.push((edit_start..edit_end, new_text));
3640 }
3641 }
3642
3643 Ok(edits)
3644 })
3645 }
3646
3647 pub async fn handle_resolve_completion_documentation(
3648 this: Model<Self>,
3649 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
3650 mut cx: AsyncAppContext,
3651 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
3652 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
3653
3654 let completion = this
3655 .read_with(&mut cx, |this, _| {
3656 let id = LanguageServerId(envelope.payload.language_server_id as usize);
3657 let Some(server) = this.language_server_for_id(id) else {
3658 return Err(anyhow!("No language server {id}"));
3659 };
3660
3661 Ok(server.request::<lsp::request::ResolveCompletionItem>(lsp_completion))
3662 })??
3663 .await?;
3664
3665 let mut documentation_is_markdown = false;
3666 let documentation = match completion.documentation {
3667 Some(lsp::Documentation::String(text)) => text,
3668
3669 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
3670 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
3671 value
3672 }
3673
3674 _ => String::new(),
3675 };
3676
3677 // If we have a new buffer_id, that means we're talking to a new client
3678 // and want to check for new text_edits in the completion too.
3679 let mut old_start = None;
3680 let mut old_end = None;
3681 let mut new_text = String::default();
3682 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
3683 let buffer_snapshot = this.update(&mut cx, |this, cx| {
3684 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3685 anyhow::Ok(buffer.read(cx).snapshot())
3686 })??;
3687
3688 if let Some(text_edit) = completion.text_edit.as_ref() {
3689 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
3690
3691 if let Some((old_range, mut text_edit_new_text)) = edit {
3692 LineEnding::normalize(&mut text_edit_new_text);
3693
3694 new_text = text_edit_new_text;
3695 old_start = Some(serialize_anchor(&old_range.start));
3696 old_end = Some(serialize_anchor(&old_range.end));
3697 }
3698 }
3699 }
3700
3701 Ok(proto::ResolveCompletionDocumentationResponse {
3702 documentation,
3703 documentation_is_markdown,
3704 old_start,
3705 old_end,
3706 new_text,
3707 })
3708 }
3709
3710 async fn handle_on_type_formatting(
3711 this: Model<Self>,
3712 envelope: TypedEnvelope<proto::OnTypeFormatting>,
3713 mut cx: AsyncAppContext,
3714 ) -> Result<proto::OnTypeFormattingResponse> {
3715 let on_type_formatting = this.update(&mut cx, |this, cx| {
3716 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3717 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3718 let position = envelope
3719 .payload
3720 .position
3721 .and_then(deserialize_anchor)
3722 .ok_or_else(|| anyhow!("invalid position"))?;
3723 Ok::<_, anyhow::Error>(this.apply_on_type_formatting(
3724 buffer,
3725 position,
3726 envelope.payload.trigger.clone(),
3727 cx,
3728 ))
3729 })??;
3730
3731 let transaction = on_type_formatting
3732 .await?
3733 .as_ref()
3734 .map(language::proto::serialize_transaction);
3735 Ok(proto::OnTypeFormattingResponse { transaction })
3736 }
3737
3738 async fn handle_refresh_inlay_hints(
3739 this: Model<Self>,
3740 _: TypedEnvelope<proto::RefreshInlayHints>,
3741 mut cx: AsyncAppContext,
3742 ) -> Result<proto::Ack> {
3743 this.update(&mut cx, |_, cx| {
3744 cx.emit(LspStoreEvent::RefreshInlayHints);
3745 })?;
3746 Ok(proto::Ack {})
3747 }
3748
3749 async fn handle_inlay_hints(
3750 this: Model<Self>,
3751 envelope: TypedEnvelope<proto::InlayHints>,
3752 mut cx: AsyncAppContext,
3753 ) -> Result<proto::InlayHintsResponse> {
3754 let sender_id = envelope.original_sender_id()?;
3755 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3756 let buffer = this.update(&mut cx, |this, cx| {
3757 this.buffer_store.read(cx).get_existing(buffer_id)
3758 })??;
3759 buffer
3760 .update(&mut cx, |buffer, _| {
3761 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
3762 })?
3763 .await
3764 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
3765
3766 let start = envelope
3767 .payload
3768 .start
3769 .and_then(deserialize_anchor)
3770 .context("missing range start")?;
3771 let end = envelope
3772 .payload
3773 .end
3774 .and_then(deserialize_anchor)
3775 .context("missing range end")?;
3776 let buffer_hints = this
3777 .update(&mut cx, |lsp_store, cx| {
3778 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
3779 })?
3780 .await
3781 .context("inlay hints fetch")?;
3782
3783 this.update(&mut cx, |project, cx| {
3784 InlayHints::response_to_proto(
3785 buffer_hints,
3786 project,
3787 sender_id,
3788 &buffer.read(cx).version(),
3789 cx,
3790 )
3791 })
3792 }
3793
3794 async fn handle_resolve_inlay_hint(
3795 this: Model<Self>,
3796 envelope: TypedEnvelope<proto::ResolveInlayHint>,
3797 mut cx: AsyncAppContext,
3798 ) -> Result<proto::ResolveInlayHintResponse> {
3799 let proto_hint = envelope
3800 .payload
3801 .hint
3802 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
3803 let hint = InlayHints::proto_to_project_hint(proto_hint)
3804 .context("resolved proto inlay hint conversion")?;
3805 let buffer = this.update(&mut cx, |this, cx| {
3806 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3807 this.buffer_store.read(cx).get_existing(buffer_id)
3808 })??;
3809 let response_hint = this
3810 .update(&mut cx, |this, cx| {
3811 this.resolve_inlay_hint(
3812 hint,
3813 buffer,
3814 LanguageServerId(envelope.payload.language_server_id as usize),
3815 cx,
3816 )
3817 })?
3818 .await
3819 .context("inlay hints fetch")?;
3820 Ok(proto::ResolveInlayHintResponse {
3821 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
3822 })
3823 }
3824
3825 async fn handle_open_buffer_for_symbol(
3826 this: Model<Self>,
3827 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
3828 mut cx: AsyncAppContext,
3829 ) -> Result<proto::OpenBufferForSymbolResponse> {
3830 let peer_id = envelope.original_sender_id()?;
3831 let symbol = envelope
3832 .payload
3833 .symbol
3834 .ok_or_else(|| anyhow!("invalid symbol"))?;
3835 let symbol = Self::deserialize_symbol(symbol)?;
3836 let symbol = this.update(&mut cx, |this, _| {
3837 let signature = this.symbol_signature(&symbol.path);
3838 if signature == symbol.signature {
3839 Ok(symbol)
3840 } else {
3841 Err(anyhow!("invalid symbol signature"))
3842 }
3843 })??;
3844 let buffer = this
3845 .update(&mut cx, |this, cx| {
3846 this.open_buffer_for_symbol(
3847 &Symbol {
3848 language_server_name: symbol.language_server_name,
3849 source_worktree_id: symbol.source_worktree_id,
3850 path: symbol.path,
3851 name: symbol.name,
3852 kind: symbol.kind,
3853 range: symbol.range,
3854 signature: symbol.signature,
3855 label: CodeLabel {
3856 text: Default::default(),
3857 runs: Default::default(),
3858 filter_range: Default::default(),
3859 },
3860 },
3861 cx,
3862 )
3863 })?
3864 .await?;
3865
3866 this.update(&mut cx, |this, cx| {
3867 let is_private = buffer
3868 .read(cx)
3869 .file()
3870 .map(|f| f.is_private())
3871 .unwrap_or_default();
3872 if is_private {
3873 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
3874 } else {
3875 this.buffer_store
3876 .update(cx, |buffer_store, cx| {
3877 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
3878 })
3879 .detach_and_log_err(cx);
3880 let buffer_id = buffer.read(cx).remote_id().to_proto();
3881 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
3882 }
3883 })?
3884 }
3885
3886 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
3887 let mut hasher = Sha256::new();
3888 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
3889 hasher.update(project_path.path.to_string_lossy().as_bytes());
3890 hasher.update(self.nonce.to_be_bytes());
3891 hasher.finalize().as_slice().try_into().unwrap()
3892 }
3893
3894 pub async fn handle_get_project_symbols(
3895 this: Model<Self>,
3896 envelope: TypedEnvelope<proto::GetProjectSymbols>,
3897 mut cx: AsyncAppContext,
3898 ) -> Result<proto::GetProjectSymbolsResponse> {
3899 let symbols = this
3900 .update(&mut cx, |this, cx| {
3901 this.symbols(&envelope.payload.query, cx)
3902 })?
3903 .await?;
3904
3905 Ok(proto::GetProjectSymbolsResponse {
3906 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
3907 })
3908 }
3909
3910 pub async fn handle_restart_language_servers(
3911 this: Model<Self>,
3912 envelope: TypedEnvelope<proto::RestartLanguageServers>,
3913 mut cx: AsyncAppContext,
3914 ) -> Result<proto::Ack> {
3915 this.update(&mut cx, |this, cx| {
3916 let buffers: Vec<_> = envelope
3917 .payload
3918 .buffer_ids
3919 .into_iter()
3920 .flat_map(|buffer_id| {
3921 this.buffer_store
3922 .read(cx)
3923 .get(BufferId::new(buffer_id).log_err()?)
3924 })
3925 .collect();
3926 this.restart_language_servers_for_buffers(buffers, cx)
3927 })?;
3928
3929 Ok(proto::Ack {})
3930 }
3931
3932 async fn handle_apply_additional_edits_for_completion(
3933 this: Model<Self>,
3934 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
3935 mut cx: AsyncAppContext,
3936 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
3937 let (buffer, completion) = this.update(&mut cx, |this, cx| {
3938 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3939 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3940 let completion = Self::deserialize_completion(
3941 envelope
3942 .payload
3943 .completion
3944 .ok_or_else(|| anyhow!("invalid completion"))?,
3945 )?;
3946 anyhow::Ok((buffer, completion))
3947 })??;
3948
3949 let apply_additional_edits = this.update(&mut cx, |this, cx| {
3950 this.apply_additional_edits_for_completion(
3951 buffer,
3952 Completion {
3953 old_range: completion.old_range,
3954 new_text: completion.new_text,
3955 lsp_completion: completion.lsp_completion,
3956 server_id: completion.server_id,
3957 documentation: None,
3958 label: CodeLabel {
3959 text: Default::default(),
3960 runs: Default::default(),
3961 filter_range: Default::default(),
3962 },
3963 confirm: None,
3964 },
3965 false,
3966 cx,
3967 )
3968 })?;
3969
3970 Ok(proto::ApplyCompletionAdditionalEditsResponse {
3971 transaction: apply_additional_edits
3972 .await?
3973 .as_ref()
3974 .map(language::proto::serialize_transaction),
3975 })
3976 }
3977
3978 pub fn start_language_servers(
3979 &mut self,
3980 worktree: &Model<Worktree>,
3981 language: Arc<Language>,
3982 cx: &mut ModelContext<Self>,
3983 ) {
3984 let (root_file, is_local) =
3985 worktree.update(cx, |tree, cx| (tree.root_file(cx), tree.is_local()));
3986 let settings = language_settings(Some(&language), root_file.map(|f| f as _).as_ref(), cx);
3987 if !settings.enable_language_server || !is_local {
3988 return;
3989 }
3990
3991 let available_lsp_adapters = self.languages.clone().lsp_adapters(&language);
3992 let available_language_servers = available_lsp_adapters
3993 .iter()
3994 .map(|lsp_adapter| lsp_adapter.name.clone())
3995 .collect::<Vec<_>>();
3996
3997 let desired_language_servers =
3998 settings.customized_language_servers(&available_language_servers);
3999
4000 let mut enabled_lsp_adapters: Vec<Arc<CachedLspAdapter>> = Vec::new();
4001 for desired_language_server in desired_language_servers {
4002 if let Some(adapter) = available_lsp_adapters
4003 .iter()
4004 .find(|adapter| adapter.name == desired_language_server)
4005 {
4006 enabled_lsp_adapters.push(adapter.clone());
4007 continue;
4008 }
4009
4010 if let Some(adapter) = self
4011 .languages
4012 .load_available_lsp_adapter(&desired_language_server)
4013 {
4014 self.languages
4015 .register_lsp_adapter(language.name(), adapter.adapter.clone());
4016 enabled_lsp_adapters.push(adapter);
4017 continue;
4018 }
4019
4020 log::warn!(
4021 "no language server found matching '{}'",
4022 desired_language_server.0
4023 );
4024 }
4025
4026 log::info!(
4027 "starting language servers for {language}: {adapters}",
4028 language = language.name(),
4029 adapters = enabled_lsp_adapters
4030 .iter()
4031 .map(|adapter| adapter.name.0.as_ref())
4032 .join(", ")
4033 );
4034
4035 for adapter in &enabled_lsp_adapters {
4036 self.start_language_server(worktree, adapter.clone(), language.clone(), cx);
4037 }
4038
4039 // After starting all the language servers, reorder them to reflect the desired order
4040 // based on the settings.
4041 //
4042 // This is done, in part, to ensure that language servers loaded at different points
4043 // (e.g., native vs extension) still end up in the right order at the end, rather than
4044 // it being based on which language server happened to be loaded in first.
4045 self.languages
4046 .reorder_language_servers(&language, enabled_lsp_adapters);
4047 }
4048
4049 fn start_language_server(
4050 &mut self,
4051 worktree_handle: &Model<Worktree>,
4052 adapter: Arc<CachedLspAdapter>,
4053 language: Arc<Language>,
4054 cx: &mut ModelContext<Self>,
4055 ) {
4056 if adapter.reinstall_attempt_count.load(SeqCst) > MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
4057 return;
4058 }
4059
4060 let worktree = worktree_handle.read(cx);
4061 let worktree_id = worktree.id();
4062 let worktree_path = worktree.abs_path();
4063 let key = (worktree_id, adapter.name.clone());
4064 if self.language_server_ids.contains_key(&key) {
4065 return;
4066 }
4067
4068 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
4069 let lsp_adapter_delegate = ProjectLspAdapterDelegate::new(self, worktree_handle, cx);
4070 let cli_environment = self
4071 .environment
4072 .as_ref()
4073 .and_then(|environment| environment.read(cx).get_cli_environment());
4074 let pending_server = match self.languages.create_pending_language_server(
4075 stderr_capture.clone(),
4076 language.clone(),
4077 adapter.clone(),
4078 Arc::clone(&worktree_path),
4079 lsp_adapter_delegate.clone(),
4080 cli_environment,
4081 cx,
4082 ) {
4083 Some(pending_server) => pending_server,
4084 None => return,
4085 };
4086
4087 let project_settings = ProjectSettings::get(
4088 Some(SettingsLocation {
4089 worktree_id: worktree_id.to_proto() as usize,
4090 path: Path::new(""),
4091 }),
4092 cx,
4093 );
4094 let lsp = project_settings.lsp.get(&adapter.name.0);
4095 let override_options = lsp.and_then(|s| s.initialization_options.clone());
4096
4097 let server_id = pending_server.server_id;
4098 let container_dir = pending_server.container_dir.clone();
4099 let state = LanguageServerState::Starting({
4100 let adapter = adapter.clone();
4101 let server_name = adapter.name.0.clone();
4102 let language = language.clone();
4103 let key = key.clone();
4104
4105 cx.spawn(move |this, mut cx| async move {
4106 let result = Self::setup_and_insert_language_server(
4107 this.clone(),
4108 lsp_adapter_delegate,
4109 override_options,
4110 pending_server,
4111 adapter.clone(),
4112 language.clone(),
4113 server_id,
4114 key,
4115 &mut cx,
4116 )
4117 .await;
4118
4119 match result {
4120 Ok(server) => {
4121 stderr_capture.lock().take();
4122 server
4123 }
4124
4125 Err(err) => {
4126 log::error!("failed to start language server {server_name:?}: {err}");
4127 log::error!("server stderr: {:?}", stderr_capture.lock().take());
4128
4129 let this = this.upgrade()?;
4130 let container_dir = container_dir?;
4131
4132 let attempt_count = adapter.reinstall_attempt_count.fetch_add(1, SeqCst);
4133 if attempt_count >= MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
4134 let max = MAX_SERVER_REINSTALL_ATTEMPT_COUNT;
4135 log::error!("Hit {max} reinstallation attempts for {server_name:?}");
4136 return None;
4137 }
4138
4139 log::info!(
4140 "retrying installation of language server {server_name:?} in {}s",
4141 SERVER_REINSTALL_DEBOUNCE_TIMEOUT.as_secs()
4142 );
4143 cx.background_executor()
4144 .timer(SERVER_REINSTALL_DEBOUNCE_TIMEOUT)
4145 .await;
4146
4147 let installation_test_binary = adapter
4148 .installation_test_binary(container_dir.to_path_buf())
4149 .await;
4150
4151 this.update(&mut cx, |_, cx| {
4152 Self::check_errored_server(
4153 language,
4154 adapter,
4155 server_id,
4156 installation_test_binary,
4157 cx,
4158 )
4159 })
4160 .ok();
4161
4162 None
4163 }
4164 }
4165 })
4166 });
4167
4168 self.language_servers.insert(server_id, state);
4169 self.language_server_ids.insert(key, server_id);
4170 }
4171
4172 #[allow(clippy::too_many_arguments)]
4173 async fn setup_and_insert_language_server(
4174 this: WeakModel<Self>,
4175 delegate: Arc<dyn LspAdapterDelegate>,
4176 override_initialization_options: Option<serde_json::Value>,
4177 pending_server: PendingLanguageServer,
4178 adapter: Arc<CachedLspAdapter>,
4179 language: Arc<Language>,
4180 server_id: LanguageServerId,
4181 key: (WorktreeId, LanguageServerName),
4182 cx: &mut AsyncAppContext,
4183 ) -> Result<Option<Arc<LanguageServer>>> {
4184 let language_server = Self::setup_pending_language_server(
4185 this.clone(),
4186 override_initialization_options,
4187 pending_server,
4188 delegate,
4189 adapter.clone(),
4190 server_id,
4191 cx,
4192 )
4193 .await?;
4194
4195 let this = match this.upgrade() {
4196 Some(this) => this,
4197 None => return Err(anyhow!("failed to upgrade project handle")),
4198 };
4199
4200 this.update(cx, |this, cx| {
4201 this.insert_newly_running_language_server(
4202 language,
4203 adapter,
4204 language_server.clone(),
4205 server_id,
4206 key,
4207 cx,
4208 )
4209 })??;
4210
4211 Ok(Some(language_server))
4212 }
4213
4214 fn reinstall_language_server(
4215 &mut self,
4216 language: Arc<Language>,
4217 adapter: Arc<CachedLspAdapter>,
4218 server_id: LanguageServerId,
4219 cx: &mut ModelContext<Self>,
4220 ) -> Option<Task<()>> {
4221 log::info!("beginning to reinstall server");
4222
4223 let existing_server = match self.language_servers.remove(&server_id) {
4224 Some(LanguageServerState::Running { server, .. }) => Some(server),
4225 _ => None,
4226 };
4227
4228 self.worktree_store.update(cx, |store, cx| {
4229 for worktree in store.worktrees() {
4230 let key = (worktree.read(cx).id(), adapter.name.clone());
4231 self.language_server_ids.remove(&key);
4232 }
4233 });
4234
4235 Some(cx.spawn(move |this, mut cx| async move {
4236 if let Some(task) = existing_server.and_then(|server| server.shutdown()) {
4237 log::info!("shutting down existing server");
4238 task.await;
4239 }
4240
4241 // TODO: This is race-safe with regards to preventing new instances from
4242 // starting while deleting, but existing instances in other projects are going
4243 // to be very confused and messed up
4244 let Some(task) = this
4245 .update(&mut cx, |this, cx| {
4246 this.languages.delete_server_container(adapter.clone(), cx)
4247 })
4248 .log_err()
4249 else {
4250 return;
4251 };
4252 task.await;
4253
4254 this.update(&mut cx, |this, cx| {
4255 for worktree in this.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
4256 this.start_language_server(&worktree, adapter.clone(), language.clone(), cx);
4257 }
4258 })
4259 .ok();
4260 }))
4261 }
4262
4263 async fn shutdown_language_server(
4264 server_state: Option<LanguageServerState>,
4265 name: Arc<str>,
4266 cx: AsyncAppContext,
4267 ) {
4268 let server = match server_state {
4269 Some(LanguageServerState::Starting(task)) => {
4270 let mut timer = cx
4271 .background_executor()
4272 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
4273 .fuse();
4274
4275 select! {
4276 server = task.fuse() => server,
4277 _ = timer => {
4278 log::info!(
4279 "timeout waiting for language server {} to finish launching before stopping",
4280 name
4281 );
4282 None
4283 },
4284 }
4285 }
4286
4287 Some(LanguageServerState::Running { server, .. }) => Some(server),
4288
4289 None => None,
4290 };
4291
4292 if let Some(server) = server {
4293 if let Some(shutdown) = server.shutdown() {
4294 shutdown.await;
4295 }
4296 }
4297 }
4298
4299 // Returns a list of all of the worktrees which no longer have a language server and the root path
4300 // for the stopped server
4301 pub fn stop_language_server(
4302 &mut self,
4303 worktree_id: WorktreeId,
4304 adapter_name: LanguageServerName,
4305 cx: &mut ModelContext<Self>,
4306 ) -> Task<Vec<WorktreeId>> {
4307 let key = (worktree_id, adapter_name);
4308 if let Some(server_id) = self.language_server_ids.remove(&key) {
4309 let name = key.1 .0;
4310 log::info!("stopping language server {name}");
4311
4312 // Remove other entries for this language server as well
4313 let mut orphaned_worktrees = vec![worktree_id];
4314 let other_keys = self.language_server_ids.keys().cloned().collect::<Vec<_>>();
4315 for other_key in other_keys {
4316 if self.language_server_ids.get(&other_key) == Some(&server_id) {
4317 self.language_server_ids.remove(&other_key);
4318 orphaned_worktrees.push(other_key.0);
4319 }
4320 }
4321
4322 self.buffer_store.update(cx, |buffer_store, cx| {
4323 for buffer in buffer_store.buffers() {
4324 buffer.update(cx, |buffer, cx| {
4325 buffer.update_diagnostics(server_id, Default::default(), cx);
4326 });
4327 }
4328 });
4329
4330 let project_id = self.project_id;
4331 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
4332 summaries.retain(|path, summaries_by_server_id| {
4333 if summaries_by_server_id.remove(&server_id).is_some() {
4334 if let Some(downstream_client) = self.downstream_client.clone() {
4335 downstream_client
4336 .send(proto::UpdateDiagnosticSummary {
4337 project_id,
4338 worktree_id: worktree_id.to_proto(),
4339 summary: Some(proto::DiagnosticSummary {
4340 path: path.to_string_lossy().to_string(),
4341 language_server_id: server_id.0 as u64,
4342 error_count: 0,
4343 warning_count: 0,
4344 }),
4345 })
4346 .log_err();
4347 }
4348 !summaries_by_server_id.is_empty()
4349 } else {
4350 true
4351 }
4352 });
4353 }
4354
4355 for diagnostics in self.diagnostics.values_mut() {
4356 diagnostics.retain(|_, diagnostics_by_server_id| {
4357 if let Ok(ix) =
4358 diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0)
4359 {
4360 diagnostics_by_server_id.remove(ix);
4361 !diagnostics_by_server_id.is_empty()
4362 } else {
4363 true
4364 }
4365 });
4366 }
4367
4368 self.language_server_watched_paths.remove(&server_id);
4369 self.language_server_statuses.remove(&server_id);
4370 cx.notify();
4371
4372 let server_state = self.language_servers.remove(&server_id);
4373 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
4374 cx.spawn(move |_, cx| async move {
4375 Self::shutdown_language_server(server_state, name, cx).await;
4376 orphaned_worktrees
4377 })
4378 } else {
4379 Task::ready(Vec::new())
4380 }
4381 }
4382
4383 pub fn restart_language_servers_for_buffers(
4384 &mut self,
4385 buffers: impl IntoIterator<Item = Model<Buffer>>,
4386 cx: &mut ModelContext<Self>,
4387 ) {
4388 if let Some(client) = self.upstream_client.clone() {
4389 let request = client.request(proto::RestartLanguageServers {
4390 project_id: self.project_id,
4391 buffer_ids: buffers
4392 .into_iter()
4393 .map(|b| b.read(cx).remote_id().to_proto())
4394 .collect(),
4395 });
4396 cx.background_executor()
4397 .spawn(request)
4398 .detach_and_log_err(cx);
4399 } else {
4400 #[allow(clippy::mutable_key_type)]
4401 let language_server_lookup_info: HashSet<(Model<Worktree>, Arc<Language>)> = buffers
4402 .into_iter()
4403 .filter_map(|buffer| {
4404 let buffer = buffer.read(cx);
4405 let file = buffer.file()?;
4406 let worktree = File::from_dyn(Some(file))?.worktree.clone();
4407 let language = self
4408 .languages
4409 .language_for_file(file, Some(buffer.as_rope()), cx)
4410 .now_or_never()?
4411 .ok()?;
4412 Some((worktree, language))
4413 })
4414 .collect();
4415
4416 for (worktree, language) in language_server_lookup_info {
4417 self.restart_language_servers(worktree, language, cx);
4418 }
4419 }
4420 }
4421
4422 pub fn restart_language_servers(
4423 &mut self,
4424 worktree: Model<Worktree>,
4425 language: Arc<Language>,
4426 cx: &mut ModelContext<Self>,
4427 ) {
4428 let worktree_id = worktree.read(cx).id();
4429
4430 let stop_tasks = self
4431 .languages
4432 .clone()
4433 .lsp_adapters(&language)
4434 .iter()
4435 .map(|adapter| {
4436 let stop_task = self.stop_language_server(worktree_id, adapter.name.clone(), cx);
4437 (stop_task, adapter.name.clone())
4438 })
4439 .collect::<Vec<_>>();
4440 if stop_tasks.is_empty() {
4441 return;
4442 }
4443
4444 cx.spawn(move |this, mut cx| async move {
4445 // For each stopped language server, record all of the worktrees with which
4446 // it was associated.
4447 let mut affected_worktrees = Vec::new();
4448 for (stop_task, language_server_name) in stop_tasks {
4449 for affected_worktree_id in stop_task.await {
4450 affected_worktrees.push((affected_worktree_id, language_server_name.clone()));
4451 }
4452 }
4453
4454 this.update(&mut cx, |this, cx| {
4455 // Restart the language server for the given worktree.
4456 this.start_language_servers(&worktree, language.clone(), cx);
4457
4458 // Lookup new server ids and set them for each of the orphaned worktrees
4459 for (affected_worktree_id, language_server_name) in affected_worktrees {
4460 if let Some(new_server_id) = this
4461 .language_server_ids
4462 .get(&(worktree_id, language_server_name.clone()))
4463 .cloned()
4464 {
4465 this.language_server_ids
4466 .insert((affected_worktree_id, language_server_name), new_server_id);
4467 }
4468 }
4469 })
4470 .ok();
4471 })
4472 .detach();
4473 }
4474
4475 fn check_errored_server(
4476 language: Arc<Language>,
4477 adapter: Arc<CachedLspAdapter>,
4478 server_id: LanguageServerId,
4479 installation_test_binary: Option<LanguageServerBinary>,
4480 cx: &mut ModelContext<Self>,
4481 ) {
4482 if !adapter.can_be_reinstalled() {
4483 log::info!(
4484 "Validation check requested for {:?} but it cannot be reinstalled",
4485 adapter.name.0
4486 );
4487 return;
4488 }
4489
4490 cx.spawn(move |this, mut cx| async move {
4491 log::info!("About to spawn test binary");
4492
4493 // A lack of test binary counts as a failure
4494 let process = installation_test_binary.and_then(|binary| {
4495 smol::process::Command::new(&binary.path)
4496 .current_dir(&binary.path)
4497 .args(binary.arguments)
4498 .stdin(Stdio::piped())
4499 .stdout(Stdio::piped())
4500 .stderr(Stdio::inherit())
4501 .kill_on_drop(true)
4502 .spawn()
4503 .ok()
4504 });
4505
4506 const PROCESS_TIMEOUT: Duration = Duration::from_secs(5);
4507 let mut timeout = cx.background_executor().timer(PROCESS_TIMEOUT).fuse();
4508
4509 let mut errored = false;
4510 if let Some(mut process) = process {
4511 futures::select! {
4512 status = process.status().fuse() => match status {
4513 Ok(status) => errored = !status.success(),
4514 Err(_) => errored = true,
4515 },
4516
4517 _ = timeout => {
4518 log::info!("test binary time-ed out, this counts as a success");
4519 _ = process.kill();
4520 }
4521 }
4522 } else {
4523 log::warn!("test binary failed to launch");
4524 errored = true;
4525 }
4526
4527 if errored {
4528 log::warn!("test binary check failed");
4529 let task = this
4530 .update(&mut cx, move |this, cx| {
4531 this.reinstall_language_server(language, adapter, server_id, cx)
4532 })
4533 .ok()
4534 .flatten();
4535
4536 if let Some(task) = task {
4537 task.await;
4538 }
4539 }
4540 })
4541 .detach();
4542 }
4543
4544 async fn setup_pending_language_server(
4545 this: WeakModel<Self>,
4546 override_options: Option<serde_json::Value>,
4547 pending_server: PendingLanguageServer,
4548 delegate: Arc<dyn LspAdapterDelegate>,
4549 adapter: Arc<CachedLspAdapter>,
4550 server_id: LanguageServerId,
4551 cx: &mut AsyncAppContext,
4552 ) -> Result<Arc<LanguageServer>> {
4553 let workspace_config = adapter
4554 .adapter
4555 .clone()
4556 .workspace_configuration(&delegate, cx)
4557 .await?;
4558 let (language_server, mut initialization_options) = pending_server.task.await?;
4559
4560 let name = language_server.name();
4561 language_server
4562 .on_notification::<lsp::notification::PublishDiagnostics, _>({
4563 let adapter = adapter.clone();
4564 let this = this.clone();
4565 move |mut params, mut cx| {
4566 let adapter = adapter.clone();
4567 if let Some(this) = this.upgrade() {
4568 adapter.process_diagnostics(&mut params);
4569 this.update(&mut cx, |this, cx| {
4570 this.update_diagnostics(
4571 server_id,
4572 params,
4573 &adapter.disk_based_diagnostic_sources,
4574 cx,
4575 )
4576 .log_err();
4577 })
4578 .ok();
4579 }
4580 }
4581 })
4582 .detach();
4583
4584 language_server
4585 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
4586 let adapter = adapter.adapter.clone();
4587 let delegate = delegate.clone();
4588 move |params, mut cx| {
4589 let adapter = adapter.clone();
4590 let delegate = delegate.clone();
4591 async move {
4592 let workspace_config =
4593 adapter.workspace_configuration(&delegate, &mut cx).await?;
4594 Ok(params
4595 .items
4596 .into_iter()
4597 .map(|item| {
4598 if let Some(section) = &item.section {
4599 workspace_config
4600 .get(section)
4601 .cloned()
4602 .unwrap_or(serde_json::Value::Null)
4603 } else {
4604 workspace_config.clone()
4605 }
4606 })
4607 .collect())
4608 }
4609 }
4610 })
4611 .detach();
4612
4613 // Even though we don't have handling for these requests, respond to them to
4614 // avoid stalling any language server like `gopls` which waits for a response
4615 // to these requests when initializing.
4616 language_server
4617 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
4618 let this = this.clone();
4619 move |params, mut cx| {
4620 let this = this.clone();
4621 async move {
4622 this.update(&mut cx, |this, _| {
4623 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
4624 {
4625 if let lsp::NumberOrString::String(token) = params.token {
4626 status.progress_tokens.insert(token);
4627 }
4628 }
4629 })?;
4630
4631 Ok(())
4632 }
4633 }
4634 })
4635 .detach();
4636
4637 language_server
4638 .on_request::<lsp::request::RegisterCapability, _, _>({
4639 let this = this.clone();
4640 move |params, mut cx| {
4641 let this = this.clone();
4642 async move {
4643 for reg in params.registrations {
4644 match reg.method.as_str() {
4645 "workspace/didChangeWatchedFiles" => {
4646 if let Some(options) = reg.register_options {
4647 let options = serde_json::from_value(options)?;
4648 this.update(&mut cx, |this, cx| {
4649 this.on_lsp_did_change_watched_files(
4650 server_id, ®.id, options, cx,
4651 );
4652 })?;
4653 }
4654 }
4655 "textDocument/rangeFormatting" => {
4656 this.update(&mut cx, |this, _| {
4657 if let Some(server) = this.language_server_for_id(server_id)
4658 {
4659 let options = reg
4660 .register_options
4661 .map(|options| {
4662 serde_json::from_value::<
4663 lsp::DocumentRangeFormattingOptions,
4664 >(
4665 options
4666 )
4667 })
4668 .transpose()?;
4669 let provider = match options {
4670 None => OneOf::Left(true),
4671 Some(options) => OneOf::Right(options),
4672 };
4673 server.update_capabilities(|capabilities| {
4674 capabilities.document_range_formatting_provider =
4675 Some(provider);
4676 })
4677 }
4678 anyhow::Ok(())
4679 })??;
4680 }
4681 "textDocument/onTypeFormatting" => {
4682 this.update(&mut cx, |this, _| {
4683 if let Some(server) = this.language_server_for_id(server_id)
4684 {
4685 let options = reg
4686 .register_options
4687 .map(|options| {
4688 serde_json::from_value::<
4689 lsp::DocumentOnTypeFormattingOptions,
4690 >(
4691 options
4692 )
4693 })
4694 .transpose()?;
4695 if let Some(options) = options {
4696 server.update_capabilities(|capabilities| {
4697 capabilities
4698 .document_on_type_formatting_provider =
4699 Some(options);
4700 })
4701 }
4702 }
4703 anyhow::Ok(())
4704 })??;
4705 }
4706 "textDocument/formatting" => {
4707 this.update(&mut cx, |this, _| {
4708 if let Some(server) = this.language_server_for_id(server_id)
4709 {
4710 let options = reg
4711 .register_options
4712 .map(|options| {
4713 serde_json::from_value::<
4714 lsp::DocumentFormattingOptions,
4715 >(
4716 options
4717 )
4718 })
4719 .transpose()?;
4720 let provider = match options {
4721 None => OneOf::Left(true),
4722 Some(options) => OneOf::Right(options),
4723 };
4724 server.update_capabilities(|capabilities| {
4725 capabilities.document_formatting_provider =
4726 Some(provider);
4727 })
4728 }
4729 anyhow::Ok(())
4730 })??;
4731 }
4732 _ => log::warn!("unhandled capability registration: {reg:?}"),
4733 }
4734 }
4735 Ok(())
4736 }
4737 }
4738 })
4739 .detach();
4740
4741 language_server
4742 .on_request::<lsp::request::UnregisterCapability, _, _>({
4743 let this = this.clone();
4744 move |params, mut cx| {
4745 let this = this.clone();
4746 async move {
4747 for unreg in params.unregisterations.iter() {
4748 match unreg.method.as_str() {
4749 "workspace/didChangeWatchedFiles" => {
4750 this.update(&mut cx, |this, cx| {
4751 this.on_lsp_unregister_did_change_watched_files(
4752 server_id, &unreg.id, cx,
4753 );
4754 })?;
4755 }
4756 "textDocument/rangeFormatting" => {
4757 this.update(&mut cx, |this, _| {
4758 if let Some(server) = this.language_server_for_id(server_id)
4759 {
4760 server.update_capabilities(|capabilities| {
4761 capabilities.document_range_formatting_provider =
4762 None
4763 })
4764 }
4765 })?;
4766 }
4767 "textDocument/onTypeFormatting" => {
4768 this.update(&mut cx, |this, _| {
4769 if let Some(server) = this.language_server_for_id(server_id)
4770 {
4771 server.update_capabilities(|capabilities| {
4772 capabilities.document_on_type_formatting_provider =
4773 None;
4774 })
4775 }
4776 })?;
4777 }
4778 "textDocument/formatting" => {
4779 this.update(&mut cx, |this, _| {
4780 if let Some(server) = this.language_server_for_id(server_id)
4781 {
4782 server.update_capabilities(|capabilities| {
4783 capabilities.document_formatting_provider = None;
4784 })
4785 }
4786 })?;
4787 }
4788 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
4789 }
4790 }
4791 Ok(())
4792 }
4793 }
4794 })
4795 .detach();
4796
4797 language_server
4798 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
4799 let adapter = adapter.clone();
4800 let this = this.clone();
4801 move |params, cx| {
4802 Self::on_lsp_workspace_edit(
4803 this.clone(),
4804 params,
4805 server_id,
4806 adapter.clone(),
4807 cx,
4808 )
4809 }
4810 })
4811 .detach();
4812
4813 language_server
4814 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
4815 let this = this.clone();
4816 move |(), mut cx| {
4817 let this = this.clone();
4818 async move {
4819 this.update(&mut cx, |this, cx| {
4820 cx.emit(LspStoreEvent::RefreshInlayHints);
4821 this.downstream_client.as_ref().map(|client| {
4822 client.send(proto::RefreshInlayHints {
4823 project_id: this.project_id,
4824 })
4825 })
4826 })?
4827 .transpose()?;
4828 Ok(())
4829 }
4830 }
4831 })
4832 .detach();
4833
4834 language_server
4835 .on_request::<lsp::request::ShowMessageRequest, _, _>({
4836 let this = this.clone();
4837 let name = name.to_string();
4838 move |params, mut cx| {
4839 let this = this.clone();
4840 let name = name.to_string();
4841 async move {
4842 let actions = params.actions.unwrap_or_default();
4843 let (tx, mut rx) = smol::channel::bounded(1);
4844 let request = LanguageServerPromptRequest {
4845 level: match params.typ {
4846 lsp::MessageType::ERROR => PromptLevel::Critical,
4847 lsp::MessageType::WARNING => PromptLevel::Warning,
4848 _ => PromptLevel::Info,
4849 },
4850 message: params.message,
4851 actions,
4852 response_channel: tx,
4853 lsp_name: name.clone(),
4854 };
4855
4856 if let Ok(_) = this.update(&mut cx, |_, cx| {
4857 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
4858 }) {
4859 let response = rx.next().await;
4860
4861 Ok(response)
4862 } else {
4863 Ok(None)
4864 }
4865 }
4866 }
4867 })
4868 .detach();
4869
4870 let disk_based_diagnostics_progress_token =
4871 adapter.disk_based_diagnostics_progress_token.clone();
4872
4873 language_server
4874 .on_notification::<ServerStatus, _>({
4875 let this = this.clone();
4876 let name = name.to_string();
4877 move |params, mut cx| {
4878 let this = this.clone();
4879 let name = name.to_string();
4880 if let Some(ref message) = params.message {
4881 let message = message.trim();
4882 if !message.is_empty() {
4883 let formatted_message = format!(
4884 "Language server {name} (id {server_id}) status update: {message}"
4885 );
4886 match params.health {
4887 ServerHealthStatus::Ok => log::info!("{}", formatted_message),
4888 ServerHealthStatus::Warning => log::warn!("{}", formatted_message),
4889 ServerHealthStatus::Error => {
4890 log::error!("{}", formatted_message);
4891 let (tx, _rx) = smol::channel::bounded(1);
4892 let request = LanguageServerPromptRequest {
4893 level: PromptLevel::Critical,
4894 message: params.message.unwrap_or_default(),
4895 actions: Vec::new(),
4896 response_channel: tx,
4897 lsp_name: name.clone(),
4898 };
4899 let _ = this
4900 .update(&mut cx, |_, cx| {
4901 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
4902 })
4903 .ok();
4904 }
4905 ServerHealthStatus::Other(status) => {
4906 log::info!(
4907 "Unknown server health: {status}\n{formatted_message}"
4908 )
4909 }
4910 }
4911 }
4912 }
4913 }
4914 })
4915 .detach();
4916 language_server
4917 .on_notification::<lsp::notification::ShowMessage, _>({
4918 let this = this.clone();
4919 let name = name.to_string();
4920 move |params, mut cx| {
4921 let this = this.clone();
4922 let name = name.to_string();
4923
4924 let (tx, _) = smol::channel::bounded(1);
4925 let request = LanguageServerPromptRequest {
4926 level: match params.typ {
4927 lsp::MessageType::ERROR => PromptLevel::Critical,
4928 lsp::MessageType::WARNING => PromptLevel::Warning,
4929 _ => PromptLevel::Info,
4930 },
4931 message: params.message,
4932 actions: vec![],
4933 response_channel: tx,
4934 lsp_name: name.clone(),
4935 };
4936
4937 let _ = this.update(&mut cx, |_, cx| {
4938 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
4939 });
4940 }
4941 })
4942 .detach();
4943 language_server
4944 .on_notification::<lsp::notification::Progress, _>({
4945 let this = this.clone();
4946 move |params, mut cx| {
4947 if let Some(this) = this.upgrade() {
4948 this.update(&mut cx, |this, cx| {
4949 this.on_lsp_progress(
4950 params,
4951 server_id,
4952 disk_based_diagnostics_progress_token.clone(),
4953 cx,
4954 );
4955 })
4956 .ok();
4957 }
4958 }
4959 })
4960 .detach();
4961
4962 language_server
4963 .on_notification::<lsp::notification::LogMessage, _>({
4964 let this = this.clone();
4965 move |params, mut cx| {
4966 if let Some(this) = this.upgrade() {
4967 this.update(&mut cx, |_, cx| {
4968 cx.emit(LspStoreEvent::LanguageServerLog(
4969 server_id,
4970 LanguageServerLogType::Log(params.typ),
4971 params.message,
4972 ));
4973 })
4974 .ok();
4975 }
4976 }
4977 })
4978 .detach();
4979
4980 language_server
4981 .on_notification::<lsp::notification::LogTrace, _>({
4982 let this = this.clone();
4983 move |params, mut cx| {
4984 if let Some(this) = this.upgrade() {
4985 this.update(&mut cx, |_, cx| {
4986 cx.emit(LspStoreEvent::LanguageServerLog(
4987 server_id,
4988 LanguageServerLogType::Trace(params.verbose),
4989 params.message,
4990 ));
4991 })
4992 .ok();
4993 }
4994 }
4995 })
4996 .detach();
4997
4998 match (&mut initialization_options, override_options) {
4999 (Some(initialization_options), Some(override_options)) => {
5000 merge_json_value_into(override_options, initialization_options);
5001 }
5002 (None, override_options) => initialization_options = override_options,
5003 _ => {}
5004 }
5005
5006 let language_server = cx
5007 .update(|cx| language_server.initialize(initialization_options, cx))?
5008 .await
5009 .inspect_err(|_| {
5010 if let Some(this) = this.upgrade() {
5011 this.update(cx, |_, cx| {
5012 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
5013 })
5014 .ok();
5015 }
5016 })?;
5017
5018 language_server
5019 .notify::<lsp::notification::DidChangeConfiguration>(
5020 lsp::DidChangeConfigurationParams {
5021 settings: workspace_config,
5022 },
5023 )
5024 .ok();
5025
5026 Ok(language_server)
5027 }
5028
5029 pub fn update_diagnostics(
5030 &mut self,
5031 language_server_id: LanguageServerId,
5032 mut params: lsp::PublishDiagnosticsParams,
5033 disk_based_sources: &[String],
5034 cx: &mut ModelContext<Self>,
5035 ) -> Result<()> {
5036 let abs_path = params
5037 .uri
5038 .to_file_path()
5039 .map_err(|_| anyhow!("URI is not a file"))?;
5040 let mut diagnostics = Vec::default();
5041 let mut primary_diagnostic_group_ids = HashMap::default();
5042 let mut sources_by_group_id = HashMap::default();
5043 let mut supporting_diagnostics = HashMap::default();
5044
5045 // Ensure that primary diagnostics are always the most severe
5046 params.diagnostics.sort_by_key(|item| item.severity);
5047
5048 for diagnostic in ¶ms.diagnostics {
5049 let source = diagnostic.source.as_ref();
5050 let code = diagnostic.code.as_ref().map(|code| match code {
5051 lsp::NumberOrString::Number(code) => code.to_string(),
5052 lsp::NumberOrString::String(code) => code.clone(),
5053 });
5054 let range = range_from_lsp(diagnostic.range);
5055 let is_supporting = diagnostic
5056 .related_information
5057 .as_ref()
5058 .map_or(false, |infos| {
5059 infos.iter().any(|info| {
5060 primary_diagnostic_group_ids.contains_key(&(
5061 source,
5062 code.clone(),
5063 range_from_lsp(info.location.range),
5064 ))
5065 })
5066 });
5067
5068 let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
5069 tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
5070 });
5071
5072 if is_supporting {
5073 supporting_diagnostics.insert(
5074 (source, code.clone(), range),
5075 (diagnostic.severity, is_unnecessary),
5076 );
5077 } else {
5078 let group_id = post_inc(&mut self.next_diagnostic_group_id);
5079 let is_disk_based =
5080 source.map_or(false, |source| disk_based_sources.contains(source));
5081
5082 sources_by_group_id.insert(group_id, source);
5083 primary_diagnostic_group_ids
5084 .insert((source, code.clone(), range.clone()), group_id);
5085
5086 diagnostics.push(DiagnosticEntry {
5087 range,
5088 diagnostic: Diagnostic {
5089 source: diagnostic.source.clone(),
5090 code: code.clone(),
5091 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
5092 message: diagnostic.message.trim().to_string(),
5093 group_id,
5094 is_primary: true,
5095 is_disk_based,
5096 is_unnecessary,
5097 data: diagnostic.data.clone(),
5098 },
5099 });
5100 if let Some(infos) = &diagnostic.related_information {
5101 for info in infos {
5102 if info.location.uri == params.uri && !info.message.is_empty() {
5103 let range = range_from_lsp(info.location.range);
5104 diagnostics.push(DiagnosticEntry {
5105 range,
5106 diagnostic: Diagnostic {
5107 source: diagnostic.source.clone(),
5108 code: code.clone(),
5109 severity: DiagnosticSeverity::INFORMATION,
5110 message: info.message.trim().to_string(),
5111 group_id,
5112 is_primary: false,
5113 is_disk_based,
5114 is_unnecessary: false,
5115 data: diagnostic.data.clone(),
5116 },
5117 });
5118 }
5119 }
5120 }
5121 }
5122 }
5123
5124 for entry in &mut diagnostics {
5125 let diagnostic = &mut entry.diagnostic;
5126 if !diagnostic.is_primary {
5127 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
5128 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
5129 source,
5130 diagnostic.code.clone(),
5131 entry.range.clone(),
5132 )) {
5133 if let Some(severity) = severity {
5134 diagnostic.severity = severity;
5135 }
5136 diagnostic.is_unnecessary = is_unnecessary;
5137 }
5138 }
5139 }
5140
5141 self.update_diagnostic_entries(
5142 language_server_id,
5143 abs_path,
5144 params.version,
5145 diagnostics,
5146 cx,
5147 )?;
5148 Ok(())
5149 }
5150
5151 fn insert_newly_running_language_server(
5152 &mut self,
5153 language: Arc<Language>,
5154 adapter: Arc<CachedLspAdapter>,
5155 language_server: Arc<LanguageServer>,
5156 server_id: LanguageServerId,
5157 key: (WorktreeId, LanguageServerName),
5158 cx: &mut ModelContext<Self>,
5159 ) -> Result<()> {
5160 // If the language server for this key doesn't match the server id, don't store the
5161 // server. Which will cause it to be dropped, killing the process
5162 if self
5163 .language_server_ids
5164 .get(&key)
5165 .map(|id| id != &server_id)
5166 .unwrap_or(false)
5167 {
5168 return Ok(());
5169 }
5170
5171 // Update language_servers collection with Running variant of LanguageServerState
5172 // indicating that the server is up and running and ready
5173 self.language_servers.insert(
5174 server_id,
5175 LanguageServerState::Running {
5176 adapter: adapter.clone(),
5177 language: language.clone(),
5178 server: language_server.clone(),
5179 simulate_disk_based_diagnostics_completion: None,
5180 },
5181 );
5182
5183 self.language_server_statuses.insert(
5184 server_id,
5185 LanguageServerStatus {
5186 name: language_server.name().to_string(),
5187 pending_work: Default::default(),
5188 has_pending_diagnostic_updates: false,
5189 progress_tokens: Default::default(),
5190 },
5191 );
5192
5193 cx.emit(LspStoreEvent::LanguageServerAdded(server_id));
5194
5195 if let Some(downstream_client) = self.downstream_client.as_ref() {
5196 downstream_client.send(proto::StartLanguageServer {
5197 project_id: self.project_id,
5198 server: Some(proto::LanguageServer {
5199 id: server_id.0 as u64,
5200 name: language_server.name().to_string(),
5201 }),
5202 })?;
5203 }
5204
5205 // Tell the language server about every open buffer in the worktree that matches the language.
5206 self.buffer_store.update(cx, |buffer_store, cx| {
5207 for buffer_handle in buffer_store.buffers() {
5208 let buffer = buffer_handle.read(cx);
5209 let file = match File::from_dyn(buffer.file()) {
5210 Some(file) => file,
5211 None => continue,
5212 };
5213 let language = match buffer.language() {
5214 Some(language) => language,
5215 None => continue,
5216 };
5217
5218 if file.worktree.read(cx).id() != key.0
5219 || !self
5220 .languages
5221 .lsp_adapters(&language)
5222 .iter()
5223 .any(|a| a.name == key.1)
5224 {
5225 continue;
5226 }
5227
5228 let file = match file.as_local() {
5229 Some(file) => file,
5230 None => continue,
5231 };
5232
5233 let versions = self
5234 .buffer_snapshots
5235 .entry(buffer.remote_id())
5236 .or_default()
5237 .entry(server_id)
5238 .or_insert_with(|| {
5239 vec![LspBufferSnapshot {
5240 version: 0,
5241 snapshot: buffer.text_snapshot(),
5242 }]
5243 });
5244
5245 let snapshot = versions.last().unwrap();
5246 let version = snapshot.version;
5247 let initial_snapshot = &snapshot.snapshot;
5248 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
5249 language_server.notify::<lsp::notification::DidOpenTextDocument>(
5250 lsp::DidOpenTextDocumentParams {
5251 text_document: lsp::TextDocumentItem::new(
5252 uri,
5253 adapter.language_id(&language),
5254 version,
5255 initial_snapshot.text(),
5256 ),
5257 },
5258 )?;
5259
5260 buffer_handle.update(cx, |buffer, cx| {
5261 buffer.set_completion_triggers(
5262 language_server
5263 .capabilities()
5264 .completion_provider
5265 .as_ref()
5266 .and_then(|provider| provider.trigger_characters.clone())
5267 .unwrap_or_default(),
5268 cx,
5269 )
5270 });
5271 }
5272 anyhow::Ok(())
5273 })?;
5274
5275 cx.notify();
5276 Ok(())
5277 }
5278
5279 fn buffer_snapshot_for_lsp_version(
5280 &mut self,
5281 buffer: &Model<Buffer>,
5282 server_id: LanguageServerId,
5283 version: Option<i32>,
5284 cx: &AppContext,
5285 ) -> Result<TextBufferSnapshot> {
5286 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5287
5288 if let Some(version) = version {
5289 let buffer_id = buffer.read(cx).remote_id();
5290 let snapshots = self
5291 .buffer_snapshots
5292 .get_mut(&buffer_id)
5293 .and_then(|m| m.get_mut(&server_id))
5294 .ok_or_else(|| {
5295 anyhow!("no snapshots found for buffer {buffer_id} and server {server_id}")
5296 })?;
5297
5298 let found_snapshot = snapshots
5299 .binary_search_by_key(&version, |e| e.version)
5300 .map(|ix| snapshots[ix].snapshot.clone())
5301 .map_err(|_| {
5302 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
5303 })?;
5304
5305 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
5306 Ok(found_snapshot)
5307 } else {
5308 Ok((buffer.read(cx)).text_snapshot())
5309 }
5310 }
5311
5312 pub fn language_servers_running_disk_based_diagnostics(
5313 &self,
5314 ) -> impl Iterator<Item = LanguageServerId> + '_ {
5315 self.language_server_statuses
5316 .iter()
5317 .filter_map(|(id, status)| {
5318 if status.has_pending_diagnostic_updates {
5319 Some(*id)
5320 } else {
5321 None
5322 }
5323 })
5324 }
5325
5326 pub(crate) fn language_servers_for_buffer<'a>(
5327 &'a self,
5328 buffer: &'a Buffer,
5329 cx: &'a AppContext,
5330 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
5331 self.language_server_ids_for_buffer(buffer, cx)
5332 .into_iter()
5333 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
5334 LanguageServerState::Running {
5335 adapter, server, ..
5336 } => Some((adapter, server)),
5337 _ => None,
5338 })
5339 }
5340
5341 pub(crate) fn cancel_language_server_work_for_buffers(
5342 &mut self,
5343 buffers: impl IntoIterator<Item = Model<Buffer>>,
5344 cx: &mut ModelContext<Self>,
5345 ) {
5346 let servers = buffers
5347 .into_iter()
5348 .flat_map(|buffer| {
5349 self.language_server_ids_for_buffer(buffer.read(cx), cx)
5350 .into_iter()
5351 })
5352 .collect::<HashSet<_>>();
5353
5354 for server_id in servers {
5355 self.cancel_language_server_work(server_id, None, cx);
5356 }
5357 }
5358
5359 pub fn language_servers(
5360 &self,
5361 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
5362 self.language_server_ids
5363 .iter()
5364 .map(|((worktree_id, server_name), server_id)| {
5365 (*server_id, server_name.clone(), *worktree_id)
5366 })
5367 }
5368
5369 pub fn register_supplementary_language_server(
5370 &mut self,
5371 id: LanguageServerId,
5372 name: LanguageServerName,
5373 server: Arc<LanguageServer>,
5374 cx: &mut ModelContext<Self>,
5375 ) {
5376 self.supplementary_language_servers
5377 .insert(id, (name, server));
5378 cx.emit(LspStoreEvent::LanguageServerAdded(id));
5379 }
5380
5381 pub fn unregister_supplementary_language_server(
5382 &mut self,
5383 id: LanguageServerId,
5384 cx: &mut ModelContext<Self>,
5385 ) {
5386 self.supplementary_language_servers.remove(&id);
5387 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
5388 }
5389
5390 pub fn supplementary_language_servers(
5391 &self,
5392 ) -> impl '_ + Iterator<Item = (&LanguageServerId, &LanguageServerName)> {
5393 self.supplementary_language_servers
5394 .iter()
5395 .map(|(id, (name, _))| (id, name))
5396 }
5397
5398 pub fn language_server_adapter_for_id(
5399 &self,
5400 id: LanguageServerId,
5401 ) -> Option<Arc<CachedLspAdapter>> {
5402 if let Some(LanguageServerState::Running { adapter, .. }) = self.language_servers.get(&id) {
5403 Some(adapter.clone())
5404 } else {
5405 None
5406 }
5407 }
5408
5409 pub fn update_local_worktree_language_servers(
5410 &mut self,
5411 worktree_handle: &Model<Worktree>,
5412 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
5413 cx: &mut ModelContext<Self>,
5414 ) {
5415 if changes.is_empty() {
5416 return;
5417 }
5418
5419 let worktree_id = worktree_handle.read(cx).id();
5420 let mut language_server_ids = self
5421 .language_server_ids
5422 .iter()
5423 .filter_map(|((server_worktree_id, _), server_id)| {
5424 (*server_worktree_id == worktree_id).then_some(*server_id)
5425 })
5426 .collect::<Vec<_>>();
5427 language_server_ids.sort();
5428 language_server_ids.dedup();
5429
5430 let abs_path = worktree_handle.read(cx).abs_path();
5431 for server_id in &language_server_ids {
5432 if let Some(LanguageServerState::Running { server, .. }) =
5433 self.language_servers.get(server_id)
5434 {
5435 if let Some(watched_paths) = self
5436 .language_server_watched_paths
5437 .get(&server_id)
5438 .and_then(|paths| paths.get(&worktree_id))
5439 {
5440 let params = lsp::DidChangeWatchedFilesParams {
5441 changes: changes
5442 .iter()
5443 .filter_map(|(path, _, change)| {
5444 if !watched_paths.is_match(&path) {
5445 return None;
5446 }
5447 let typ = match change {
5448 PathChange::Loaded => return None,
5449 PathChange::Added => lsp::FileChangeType::CREATED,
5450 PathChange::Removed => lsp::FileChangeType::DELETED,
5451 PathChange::Updated => lsp::FileChangeType::CHANGED,
5452 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
5453 };
5454 Some(lsp::FileEvent {
5455 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
5456 typ,
5457 })
5458 })
5459 .collect(),
5460 };
5461 if !params.changes.is_empty() {
5462 server
5463 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
5464 .log_err();
5465 }
5466 }
5467 }
5468 }
5469 }
5470
5471 pub(crate) fn cancel_language_server_work(
5472 &mut self,
5473 server_id: LanguageServerId,
5474 token_to_cancel: Option<String>,
5475 _cx: &mut ModelContext<Self>,
5476 ) {
5477 let status = self.language_server_statuses.get(&server_id);
5478 let server = self.language_servers.get(&server_id);
5479 if let Some((server, status)) = server.zip(status) {
5480 if let LanguageServerState::Running { server, .. } = server {
5481 for (token, progress) in &status.pending_work {
5482 if let Some(token_to_cancel) = token_to_cancel.as_ref() {
5483 if token != token_to_cancel {
5484 continue;
5485 }
5486 }
5487 if progress.is_cancellable {
5488 server
5489 .notify::<lsp::notification::WorkDoneProgressCancel>(
5490 WorkDoneProgressCancelParams {
5491 token: lsp::NumberOrString::String(token.clone()),
5492 },
5493 )
5494 .ok();
5495 }
5496 }
5497 }
5498 }
5499 }
5500
5501 pub fn wait_for_remote_buffer(
5502 &mut self,
5503 id: BufferId,
5504 cx: &mut ModelContext<Self>,
5505 ) -> Task<Result<Model<Buffer>>> {
5506 self.buffer_store.update(cx, |buffer_store, cx| {
5507 buffer_store.wait_for_remote_buffer(id, cx)
5508 })
5509 }
5510
5511 pub(crate) fn language_server_ids_for_buffer(
5512 &self,
5513 buffer: &Buffer,
5514 cx: &AppContext,
5515 ) -> Vec<LanguageServerId> {
5516 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
5517 let worktree_id = file.worktree_id(cx);
5518 self.languages
5519 .lsp_adapters(&language)
5520 .iter()
5521 .flat_map(|adapter| {
5522 let key = (worktree_id, adapter.name.clone());
5523 self.language_server_ids.get(&key).copied()
5524 })
5525 .collect()
5526 } else {
5527 Vec::new()
5528 }
5529 }
5530
5531 pub async fn deserialize_text_edits(
5532 this: Model<Self>,
5533 buffer_to_edit: Model<Buffer>,
5534 edits: Vec<lsp::TextEdit>,
5535 push_to_history: bool,
5536 _: Arc<CachedLspAdapter>,
5537 language_server: Arc<LanguageServer>,
5538 cx: &mut AsyncAppContext,
5539 ) -> Result<Option<Transaction>> {
5540 let edits = this
5541 .update(cx, |this, cx| {
5542 this.edits_from_lsp(
5543 &buffer_to_edit,
5544 edits,
5545 language_server.server_id(),
5546 None,
5547 cx,
5548 )
5549 })?
5550 .await?;
5551
5552 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
5553 buffer.finalize_last_transaction();
5554 buffer.start_transaction();
5555 for (range, text) in edits {
5556 buffer.edit([(range, text)], None, cx);
5557 }
5558
5559 if buffer.end_transaction(cx).is_some() {
5560 let transaction = buffer.finalize_last_transaction().unwrap().clone();
5561 if !push_to_history {
5562 buffer.forget_transaction(transaction.id);
5563 }
5564 Some(transaction)
5565 } else {
5566 None
5567 }
5568 })?;
5569
5570 Ok(transaction)
5571 }
5572
5573 pub async fn deserialize_workspace_edit(
5574 this: Model<Self>,
5575 edit: lsp::WorkspaceEdit,
5576 push_to_history: bool,
5577 lsp_adapter: Arc<CachedLspAdapter>,
5578 language_server: Arc<LanguageServer>,
5579 cx: &mut AsyncAppContext,
5580 ) -> Result<ProjectTransaction> {
5581 let fs = this.update(cx, |this, _| this.fs.clone())?;
5582 let mut operations = Vec::new();
5583 if let Some(document_changes) = edit.document_changes {
5584 match document_changes {
5585 lsp::DocumentChanges::Edits(edits) => {
5586 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
5587 }
5588 lsp::DocumentChanges::Operations(ops) => operations = ops,
5589 }
5590 } else if let Some(changes) = edit.changes {
5591 operations.extend(changes.into_iter().map(|(uri, edits)| {
5592 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
5593 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
5594 uri,
5595 version: None,
5596 },
5597 edits: edits.into_iter().map(Edit::Plain).collect(),
5598 })
5599 }));
5600 }
5601
5602 let mut project_transaction = ProjectTransaction::default();
5603 for operation in operations {
5604 match operation {
5605 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
5606 let abs_path = op
5607 .uri
5608 .to_file_path()
5609 .map_err(|_| anyhow!("can't convert URI to path"))?;
5610
5611 if let Some(parent_path) = abs_path.parent() {
5612 fs.create_dir(parent_path).await?;
5613 }
5614 if abs_path.ends_with("/") {
5615 fs.create_dir(&abs_path).await?;
5616 } else {
5617 fs.create_file(
5618 &abs_path,
5619 op.options
5620 .map(|options| fs::CreateOptions {
5621 overwrite: options.overwrite.unwrap_or(false),
5622 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
5623 })
5624 .unwrap_or_default(),
5625 )
5626 .await?;
5627 }
5628 }
5629
5630 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
5631 let source_abs_path = op
5632 .old_uri
5633 .to_file_path()
5634 .map_err(|_| anyhow!("can't convert URI to path"))?;
5635 let target_abs_path = op
5636 .new_uri
5637 .to_file_path()
5638 .map_err(|_| anyhow!("can't convert URI to path"))?;
5639 fs.rename(
5640 &source_abs_path,
5641 &target_abs_path,
5642 op.options
5643 .map(|options| fs::RenameOptions {
5644 overwrite: options.overwrite.unwrap_or(false),
5645 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
5646 })
5647 .unwrap_or_default(),
5648 )
5649 .await?;
5650 }
5651
5652 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
5653 let abs_path = op
5654 .uri
5655 .to_file_path()
5656 .map_err(|_| anyhow!("can't convert URI to path"))?;
5657 let options = op
5658 .options
5659 .map(|options| fs::RemoveOptions {
5660 recursive: options.recursive.unwrap_or(false),
5661 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
5662 })
5663 .unwrap_or_default();
5664 if abs_path.ends_with("/") {
5665 fs.remove_dir(&abs_path, options).await?;
5666 } else {
5667 fs.remove_file(&abs_path, options).await?;
5668 }
5669 }
5670
5671 lsp::DocumentChangeOperation::Edit(op) => {
5672 let buffer_to_edit = this
5673 .update(cx, |this, cx| {
5674 this.open_local_buffer_via_lsp(
5675 op.text_document.uri.clone(),
5676 language_server.server_id(),
5677 lsp_adapter.name.clone(),
5678 cx,
5679 )
5680 })?
5681 .await?;
5682
5683 let edits = this
5684 .update(cx, |this, cx| {
5685 let path = buffer_to_edit.read(cx).project_path(cx);
5686 let active_entry = this.active_entry;
5687 let is_active_entry = path.clone().map_or(false, |project_path| {
5688 this.worktree_store
5689 .read(cx)
5690 .entry_for_path(&project_path, cx)
5691 .map_or(false, |entry| Some(entry.id) == active_entry)
5692 });
5693
5694 let (mut edits, mut snippet_edits) = (vec![], vec![]);
5695 for edit in op.edits {
5696 match edit {
5697 Edit::Plain(edit) => edits.push(edit),
5698 Edit::Annotated(edit) => edits.push(edit.text_edit),
5699 Edit::Snippet(edit) => {
5700 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
5701 else {
5702 continue;
5703 };
5704
5705 if is_active_entry {
5706 snippet_edits.push((edit.range, snippet));
5707 } else {
5708 // Since this buffer is not focused, apply a normal edit.
5709 edits.push(TextEdit {
5710 range: edit.range,
5711 new_text: snippet.text,
5712 });
5713 }
5714 }
5715 }
5716 }
5717 if !snippet_edits.is_empty() {
5718 if let Some(buffer_version) = op.text_document.version {
5719 let buffer_id = buffer_to_edit.read(cx).remote_id();
5720 // Check if the edit that triggered that edit has been made by this participant.
5721 let most_recent_edit = this
5722 .buffer_snapshots
5723 .get(&buffer_id)
5724 .and_then(|server_to_snapshots| {
5725 let all_snapshots = server_to_snapshots
5726 .get(&language_server.server_id())?;
5727 all_snapshots
5728 .binary_search_by_key(&buffer_version, |snapshot| {
5729 snapshot.version
5730 })
5731 .ok()
5732 .and_then(|index| all_snapshots.get(index))
5733 })
5734 .and_then(|lsp_snapshot| {
5735 let version = lsp_snapshot.snapshot.version();
5736 version.iter().max_by_key(|timestamp| timestamp.value)
5737 });
5738 if let Some(most_recent_edit) = most_recent_edit {
5739 cx.emit(LspStoreEvent::SnippetEdit {
5740 buffer_id,
5741 edits: snippet_edits,
5742 most_recent_edit,
5743 });
5744 }
5745 }
5746 }
5747
5748 this.edits_from_lsp(
5749 &buffer_to_edit,
5750 edits,
5751 language_server.server_id(),
5752 op.text_document.version,
5753 cx,
5754 )
5755 })?
5756 .await?;
5757
5758 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
5759 buffer.finalize_last_transaction();
5760 buffer.start_transaction();
5761 for (range, text) in edits {
5762 buffer.edit([(range, text)], None, cx);
5763 }
5764 let transaction = if buffer.end_transaction(cx).is_some() {
5765 let transaction = buffer.finalize_last_transaction().unwrap().clone();
5766 if !push_to_history {
5767 buffer.forget_transaction(transaction.id);
5768 }
5769 Some(transaction)
5770 } else {
5771 None
5772 };
5773
5774 transaction
5775 })?;
5776 if let Some(transaction) = transaction {
5777 project_transaction.0.insert(buffer_to_edit, transaction);
5778 }
5779 }
5780 }
5781 }
5782
5783 Ok(project_transaction)
5784 }
5785
5786 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
5787 proto::Symbol {
5788 language_server_name: symbol.language_server_name.0.to_string(),
5789 source_worktree_id: symbol.source_worktree_id.to_proto(),
5790 worktree_id: symbol.path.worktree_id.to_proto(),
5791 path: symbol.path.path.to_string_lossy().to_string(),
5792 name: symbol.name.clone(),
5793 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
5794 start: Some(proto::PointUtf16 {
5795 row: symbol.range.start.0.row,
5796 column: symbol.range.start.0.column,
5797 }),
5798 end: Some(proto::PointUtf16 {
5799 row: symbol.range.end.0.row,
5800 column: symbol.range.end.0.column,
5801 }),
5802 signature: symbol.signature.to_vec(),
5803 }
5804 }
5805
5806 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
5807 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
5808 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
5809 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
5810 let path = ProjectPath {
5811 worktree_id,
5812 path: PathBuf::from(serialized_symbol.path).into(),
5813 };
5814
5815 let start = serialized_symbol
5816 .start
5817 .ok_or_else(|| anyhow!("invalid start"))?;
5818 let end = serialized_symbol
5819 .end
5820 .ok_or_else(|| anyhow!("invalid end"))?;
5821 Ok(CoreSymbol {
5822 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
5823 source_worktree_id,
5824 path,
5825 name: serialized_symbol.name,
5826 range: Unclipped(PointUtf16::new(start.row, start.column))
5827 ..Unclipped(PointUtf16::new(end.row, end.column)),
5828 kind,
5829 signature: serialized_symbol
5830 .signature
5831 .try_into()
5832 .map_err(|_| anyhow!("invalid signature"))?,
5833 })
5834 }
5835
5836 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
5837 proto::Completion {
5838 old_start: Some(serialize_anchor(&completion.old_range.start)),
5839 old_end: Some(serialize_anchor(&completion.old_range.end)),
5840 new_text: completion.new_text.clone(),
5841 server_id: completion.server_id.0 as u64,
5842 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
5843 }
5844 }
5845
5846 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
5847 let old_start = completion
5848 .old_start
5849 .and_then(deserialize_anchor)
5850 .ok_or_else(|| anyhow!("invalid old start"))?;
5851 let old_end = completion
5852 .old_end
5853 .and_then(deserialize_anchor)
5854 .ok_or_else(|| anyhow!("invalid old end"))?;
5855 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
5856
5857 Ok(CoreCompletion {
5858 old_range: old_start..old_end,
5859 new_text: completion.new_text,
5860 server_id: LanguageServerId(completion.server_id as usize),
5861 lsp_completion,
5862 })
5863 }
5864
5865 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
5866 proto::CodeAction {
5867 server_id: action.server_id.0 as u64,
5868 start: Some(serialize_anchor(&action.range.start)),
5869 end: Some(serialize_anchor(&action.range.end)),
5870 lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
5871 }
5872 }
5873
5874 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
5875 let start = action
5876 .start
5877 .and_then(deserialize_anchor)
5878 .ok_or_else(|| anyhow!("invalid start"))?;
5879 let end = action
5880 .end
5881 .and_then(deserialize_anchor)
5882 .ok_or_else(|| anyhow!("invalid end"))?;
5883 let lsp_action = serde_json::from_slice(&action.lsp_action)?;
5884 Ok(CodeAction {
5885 server_id: LanguageServerId(action.server_id as usize),
5886 range: start..end,
5887 lsp_action,
5888 })
5889 }
5890}
5891
5892impl EventEmitter<LspStoreEvent> for LspStore {}
5893
5894fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
5895 hover
5896 .contents
5897 .retain(|hover_block| !hover_block.text.trim().is_empty());
5898 if hover.contents.is_empty() {
5899 None
5900 } else {
5901 Some(hover)
5902 }
5903}
5904
5905async fn populate_labels_for_completions(
5906 mut new_completions: Vec<CoreCompletion>,
5907 language_registry: &Arc<LanguageRegistry>,
5908 language: Option<Arc<Language>>,
5909 lsp_adapter: Option<Arc<CachedLspAdapter>>,
5910 completions: &mut Vec<Completion>,
5911) {
5912 let lsp_completions = new_completions
5913 .iter_mut()
5914 .map(|completion| mem::take(&mut completion.lsp_completion))
5915 .collect::<Vec<_>>();
5916
5917 let labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
5918 lsp_adapter
5919 .labels_for_completions(&lsp_completions, language)
5920 .await
5921 .log_err()
5922 .unwrap_or_default()
5923 } else {
5924 Vec::new()
5925 };
5926
5927 for ((completion, lsp_completion), label) in new_completions
5928 .into_iter()
5929 .zip(lsp_completions)
5930 .zip(labels.into_iter().chain(iter::repeat(None)))
5931 {
5932 let documentation = if let Some(docs) = &lsp_completion.documentation {
5933 Some(prepare_completion_documentation(docs, &language_registry, language.clone()).await)
5934 } else {
5935 None
5936 };
5937
5938 completions.push(Completion {
5939 old_range: completion.old_range,
5940 new_text: completion.new_text,
5941 label: label.unwrap_or_else(|| {
5942 CodeLabel::plain(
5943 lsp_completion.label.clone(),
5944 lsp_completion.filter_text.as_deref(),
5945 )
5946 }),
5947 server_id: completion.server_id,
5948 documentation,
5949 lsp_completion,
5950 confirm: None,
5951 })
5952 }
5953}
5954
5955#[derive(Debug)]
5956pub enum LanguageServerToQuery {
5957 Primary,
5958 Other(LanguageServerId),
5959}
5960
5961struct LspBufferSnapshot {
5962 version: i32,
5963 snapshot: TextBufferSnapshot,
5964}
5965
5966/// A prompt requested by LSP server.
5967#[derive(Clone, Debug)]
5968pub struct LanguageServerPromptRequest {
5969 pub level: PromptLevel,
5970 pub message: String,
5971 pub actions: Vec<MessageActionItem>,
5972 pub lsp_name: String,
5973 pub(crate) response_channel: Sender<MessageActionItem>,
5974}
5975
5976impl LanguageServerPromptRequest {
5977 pub async fn respond(self, index: usize) -> Option<()> {
5978 if let Some(response) = self.actions.into_iter().nth(index) {
5979 self.response_channel.send(response).await.ok()
5980 } else {
5981 None
5982 }
5983 }
5984}
5985impl PartialEq for LanguageServerPromptRequest {
5986 fn eq(&self, other: &Self) -> bool {
5987 self.message == other.message && self.actions == other.actions
5988 }
5989}
5990
5991#[derive(Clone, Debug, PartialEq)]
5992pub enum LanguageServerLogType {
5993 Log(MessageType),
5994 Trace(Option<String>),
5995}
5996
5997pub enum LanguageServerState {
5998 Starting(Task<Option<Arc<LanguageServer>>>),
5999
6000 Running {
6001 language: Arc<Language>,
6002 adapter: Arc<CachedLspAdapter>,
6003 server: Arc<LanguageServer>,
6004 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
6005 },
6006}
6007
6008#[derive(Clone, Debug, Serialize)]
6009pub struct LanguageServerProgress {
6010 pub is_disk_based_diagnostics_progress: bool,
6011 pub is_cancellable: bool,
6012 pub title: Option<String>,
6013 pub message: Option<String>,
6014 pub percentage: Option<usize>,
6015 #[serde(skip_serializing)]
6016 pub last_update_at: Instant,
6017}
6018
6019#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
6020pub struct DiagnosticSummary {
6021 pub error_count: usize,
6022 pub warning_count: usize,
6023}
6024
6025impl DiagnosticSummary {
6026 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
6027 let mut this = Self {
6028 error_count: 0,
6029 warning_count: 0,
6030 };
6031
6032 for entry in diagnostics {
6033 if entry.diagnostic.is_primary {
6034 match entry.diagnostic.severity {
6035 DiagnosticSeverity::ERROR => this.error_count += 1,
6036 DiagnosticSeverity::WARNING => this.warning_count += 1,
6037 _ => {}
6038 }
6039 }
6040 }
6041
6042 this
6043 }
6044
6045 pub fn is_empty(&self) -> bool {
6046 self.error_count == 0 && self.warning_count == 0
6047 }
6048
6049 pub fn to_proto(
6050 &self,
6051 language_server_id: LanguageServerId,
6052 path: &Path,
6053 ) -> proto::DiagnosticSummary {
6054 proto::DiagnosticSummary {
6055 path: path.to_string_lossy().to_string(),
6056 language_server_id: language_server_id.0 as u64,
6057 error_count: self.error_count as u32,
6058 warning_count: self.warning_count as u32,
6059 }
6060 }
6061}
6062
6063fn glob_literal_prefix(glob: &str) -> &str {
6064 let mut literal_end = 0;
6065 for (i, part) in glob.split(path::MAIN_SEPARATOR).enumerate() {
6066 if part.contains(&['*', '?', '{', '}']) {
6067 break;
6068 } else {
6069 if i > 0 {
6070 // Account for separator prior to this part
6071 literal_end += path::MAIN_SEPARATOR.len_utf8();
6072 }
6073 literal_end += part.len();
6074 }
6075 }
6076 &glob[..literal_end]
6077}
6078
6079pub struct ProjectLspAdapterDelegate {
6080 lsp_store: WeakModel<LspStore>,
6081 worktree: worktree::Snapshot,
6082 fs: Arc<dyn Fs>,
6083 http_client: Arc<dyn HttpClient>,
6084 language_registry: Arc<LanguageRegistry>,
6085 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
6086}
6087
6088impl ProjectLspAdapterDelegate {
6089 pub fn new(
6090 lsp_store: &LspStore,
6091 worktree: &Model<Worktree>,
6092 cx: &mut ModelContext<LspStore>,
6093 ) -> Arc<Self> {
6094 let worktree_id = worktree.read(cx).id();
6095 let worktree_abs_path = worktree.read(cx).abs_path();
6096 let load_shell_env_task = if let Some(environment) = &lsp_store.environment {
6097 environment.update(cx, |env, cx| {
6098 env.get_environment(Some(worktree_id), Some(worktree_abs_path), cx)
6099 })
6100 } else {
6101 Task::ready(None).shared()
6102 };
6103
6104 Arc::new(Self {
6105 lsp_store: cx.weak_model(),
6106 worktree: worktree.read(cx).snapshot(),
6107 fs: lsp_store.fs.clone(),
6108 http_client: lsp_store.http_client.clone(),
6109 language_registry: lsp_store.languages.clone(),
6110 load_shell_env_task,
6111 })
6112 }
6113}
6114
6115#[async_trait]
6116impl LspAdapterDelegate for ProjectLspAdapterDelegate {
6117 fn show_notification(&self, message: &str, cx: &mut AppContext) {
6118 self.lsp_store
6119 .update(cx, |_, cx| {
6120 cx.emit(LspStoreEvent::Notification(message.to_owned()))
6121 })
6122 .ok();
6123 }
6124
6125 fn http_client(&self) -> Arc<dyn HttpClient> {
6126 self.http_client.clone()
6127 }
6128
6129 fn worktree_id(&self) -> u64 {
6130 self.worktree.id().to_proto()
6131 }
6132
6133 fn worktree_root_path(&self) -> &Path {
6134 self.worktree.abs_path().as_ref()
6135 }
6136
6137 async fn shell_env(&self) -> HashMap<String, String> {
6138 let task = self.load_shell_env_task.clone();
6139 task.await.unwrap_or_default()
6140 }
6141
6142 #[cfg(not(target_os = "windows"))]
6143 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
6144 let worktree_abs_path = self.worktree.abs_path();
6145 let shell_path = self.shell_env().await.get("PATH").cloned();
6146 which::which_in(command, shell_path.as_ref(), &worktree_abs_path).ok()
6147 }
6148
6149 #[cfg(target_os = "windows")]
6150 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
6151 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
6152 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
6153 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
6154 which::which(command).ok()
6155 }
6156
6157 fn update_status(
6158 &self,
6159 server_name: LanguageServerName,
6160 status: language::LanguageServerBinaryStatus,
6161 ) {
6162 self.language_registry
6163 .update_lsp_status(server_name, status);
6164 }
6165
6166 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
6167 if self.worktree.entry_for_path(&path).is_none() {
6168 return Err(anyhow!("no such path {path:?}"));
6169 }
6170 let path = self.worktree.absolutize(path.as_ref())?;
6171 let content = self.fs.load(&path).await?;
6172 Ok(content)
6173 }
6174}
6175
6176async fn populate_labels_for_symbols(
6177 symbols: Vec<CoreSymbol>,
6178 language_registry: &Arc<LanguageRegistry>,
6179 default_language: Option<Arc<Language>>,
6180 lsp_adapter: Option<Arc<CachedLspAdapter>>,
6181 output: &mut Vec<Symbol>,
6182) {
6183 #[allow(clippy::mutable_key_type)]
6184 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
6185
6186 let mut unknown_path = None;
6187 for symbol in symbols {
6188 let language = language_registry
6189 .language_for_file_path(&symbol.path.path)
6190 .await
6191 .ok()
6192 .or_else(|| {
6193 unknown_path.get_or_insert(symbol.path.path.clone());
6194 default_language.clone()
6195 });
6196 symbols_by_language
6197 .entry(language)
6198 .or_default()
6199 .push(symbol);
6200 }
6201
6202 if let Some(unknown_path) = unknown_path {
6203 log::info!(
6204 "no language found for symbol path {}",
6205 unknown_path.display()
6206 );
6207 }
6208
6209 let mut label_params = Vec::new();
6210 for (language, mut symbols) in symbols_by_language {
6211 label_params.clear();
6212 label_params.extend(
6213 symbols
6214 .iter_mut()
6215 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
6216 );
6217
6218 let mut labels = Vec::new();
6219 if let Some(language) = language {
6220 let lsp_adapter = lsp_adapter
6221 .clone()
6222 .or_else(|| language_registry.lsp_adapters(&language).first().cloned());
6223 if let Some(lsp_adapter) = lsp_adapter {
6224 labels = lsp_adapter
6225 .labels_for_symbols(&label_params, &language)
6226 .await
6227 .log_err()
6228 .unwrap_or_default();
6229 }
6230 }
6231
6232 for ((symbol, (name, _)), label) in symbols
6233 .into_iter()
6234 .zip(label_params.drain(..))
6235 .zip(labels.into_iter().chain(iter::repeat(None)))
6236 {
6237 output.push(Symbol {
6238 language_server_name: symbol.language_server_name,
6239 source_worktree_id: symbol.source_worktree_id,
6240 path: symbol.path,
6241 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
6242 name,
6243 kind: symbol.kind,
6244 range: symbol.range,
6245 signature: symbol.signature,
6246 });
6247 }
6248 }
6249}
6250
6251fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
6252 match server.capabilities().text_document_sync.as_ref()? {
6253 lsp::TextDocumentSyncCapability::Kind(kind) => match kind {
6254 &lsp::TextDocumentSyncKind::NONE => None,
6255 &lsp::TextDocumentSyncKind::FULL => Some(true),
6256 &lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
6257 _ => None,
6258 },
6259 lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
6260 lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
6261 if *supported {
6262 Some(true)
6263 } else {
6264 None
6265 }
6266 }
6267 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
6268 Some(save_options.include_text.unwrap_or(false))
6269 }
6270 },
6271 }
6272}
6273
6274#[cfg(test)]
6275#[test]
6276fn test_glob_literal_prefix() {
6277 assert_eq!(glob_literal_prefix("**/*.js"), "");
6278 assert_eq!(glob_literal_prefix("node_modules/**/*.js"), "node_modules");
6279 assert_eq!(glob_literal_prefix("foo/{bar,baz}.js"), "foo");
6280 assert_eq!(glob_literal_prefix("foo/bar/baz.js"), "foo/bar/baz.js");
6281}