1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17
18use crate::{
19 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
20 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction,
21 LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
22 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
23 buffer_store::{BufferStore, BufferStoreEvent},
24 environment::ProjectEnvironment,
25 lsp_command::{self, *},
26 lsp_store::{
27 self,
28 log_store::{GlobalLogStore, LanguageServerKind},
29 },
30 manifest_tree::{
31 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
32 ManifestTree,
33 },
34 prettier_store::{self, PrettierStore, PrettierStoreEvent},
35 project_settings::{LspSettings, ProjectSettings},
36 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
37 worktree_store::{WorktreeStore, WorktreeStoreEvent},
38 yarn::YarnPathStore,
39};
40use anyhow::{Context as _, Result, anyhow};
41use async_trait::async_trait;
42use client::{TypedEnvelope, proto};
43use clock::Global;
44use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
45use futures::{
46 AsyncWriteExt, Future, FutureExt, StreamExt,
47 future::{Either, Shared, join_all, pending, select},
48 select, select_biased,
49 stream::FuturesUnordered,
50};
51use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
52use gpui::{
53 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
54 WeakEntity,
55};
56use http_client::HttpClient;
57use itertools::Itertools as _;
58use language::{
59 Bias, BinaryStatus, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
60 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
61 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
62 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
63 Transaction, Unclipped,
64 language_settings::{
65 FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,
66 },
67 point_to_lsp,
68 proto::{
69 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
70 serialize_lsp_edit, serialize_version,
71 },
72 range_from_lsp, range_to_lsp,
73};
74use lsp::{
75 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
76 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
77 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
78 LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
79 LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture,
80 MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
81 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
82 WorkspaceFolder, notification::DidRenameFiles,
83};
84use node_runtime::read_package_installed_version;
85use parking_lot::Mutex;
86use postage::{mpsc, sink::Sink, stream::Stream, watch};
87use rand::prelude::*;
88use rpc::{
89 AnyProtoClient,
90 proto::{LspRequestId, LspRequestMessage as _},
91};
92use serde::Serialize;
93use settings::{Settings, SettingsLocation, SettingsStore};
94use sha2::{Digest, Sha256};
95use smol::channel::Sender;
96use snippet::Snippet;
97use std::{
98 any::TypeId,
99 borrow::Cow,
100 cell::RefCell,
101 cmp::{Ordering, Reverse},
102 convert::TryInto,
103 ffi::OsStr,
104 future::ready,
105 iter, mem,
106 ops::{ControlFlow, Range},
107 path::{self, Path, PathBuf},
108 pin::pin,
109 rc::Rc,
110 sync::Arc,
111 time::{Duration, Instant},
112};
113use sum_tree::Dimensions;
114use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
115
116use util::{
117 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
118 paths::{PathStyle, SanitizedPath},
119 post_inc,
120 rel_path::RelPath,
121};
122
123pub use fs::*;
124pub use language::Location;
125#[cfg(any(test, feature = "test-support"))]
126pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
127pub use worktree::{
128 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
129 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
130};
131
132const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
133pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub enum FormatTrigger {
137 Save,
138 Manual,
139}
140
141pub enum LspFormatTarget {
142 Buffers,
143 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
144}
145
146pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
147
148impl FormatTrigger {
149 fn from_proto(value: i32) -> FormatTrigger {
150 match value {
151 0 => FormatTrigger::Save,
152 1 => FormatTrigger::Manual,
153 _ => FormatTrigger::Save,
154 }
155 }
156}
157
158#[derive(Clone)]
159struct UnifiedLanguageServer {
160 id: LanguageServerId,
161 project_roots: HashSet<Arc<RelPath>>,
162}
163
164#[derive(Clone, Hash, PartialEq, Eq)]
165struct LanguageServerSeed {
166 worktree_id: WorktreeId,
167 name: LanguageServerName,
168 toolchain: Option<Toolchain>,
169 settings: Arc<LspSettings>,
170}
171
172#[derive(Debug)]
173pub struct DocumentDiagnosticsUpdate<'a, D> {
174 pub diagnostics: D,
175 pub result_id: Option<String>,
176 pub server_id: LanguageServerId,
177 pub disk_based_sources: Cow<'a, [String]>,
178}
179
180pub struct DocumentDiagnostics {
181 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
182 document_abs_path: PathBuf,
183 version: Option<i32>,
184}
185
186pub struct LocalLspStore {
187 weak: WeakEntity<LspStore>,
188 worktree_store: Entity<WorktreeStore>,
189 toolchain_store: Entity<LocalToolchainStore>,
190 http_client: Arc<dyn HttpClient>,
191 environment: Entity<ProjectEnvironment>,
192 fs: Arc<dyn Fs>,
193 languages: Arc<LanguageRegistry>,
194 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
195 yarn: Entity<YarnPathStore>,
196 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
197 buffers_being_formatted: HashSet<BufferId>,
198 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
199 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
200 watched_manifest_filenames: HashSet<ManifestName>,
201 language_server_paths_watched_for_rename:
202 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
203 language_server_watcher_registrations:
204 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
205 supplementary_language_servers:
206 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
207 prettier_store: Entity<PrettierStore>,
208 next_diagnostic_group_id: usize,
209 diagnostics: HashMap<
210 WorktreeId,
211 HashMap<
212 Arc<RelPath>,
213 Vec<(
214 LanguageServerId,
215 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
216 )>,
217 >,
218 >,
219 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
220 _subscription: gpui::Subscription,
221 lsp_tree: LanguageServerTree,
222 registered_buffers: HashMap<BufferId, usize>,
223 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
224 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
225}
226
227impl LocalLspStore {
228 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
229 pub fn running_language_server_for_id(
230 &self,
231 id: LanguageServerId,
232 ) -> Option<&Arc<LanguageServer>> {
233 let language_server_state = self.language_servers.get(&id)?;
234
235 match language_server_state {
236 LanguageServerState::Running { server, .. } => Some(server),
237 LanguageServerState::Starting { .. } => None,
238 }
239 }
240
241 fn get_or_insert_language_server(
242 &mut self,
243 worktree_handle: &Entity<Worktree>,
244 delegate: Arc<LocalLspAdapterDelegate>,
245 disposition: &Arc<LaunchDisposition>,
246 language_name: &LanguageName,
247 cx: &mut App,
248 ) -> LanguageServerId {
249 let key = LanguageServerSeed {
250 worktree_id: worktree_handle.read(cx).id(),
251 name: disposition.server_name.clone(),
252 settings: disposition.settings.clone(),
253 toolchain: disposition.toolchain.clone(),
254 };
255 if let Some(state) = self.language_server_ids.get_mut(&key) {
256 state.project_roots.insert(disposition.path.path.clone());
257 state.id
258 } else {
259 let adapter = self
260 .languages
261 .lsp_adapters(language_name)
262 .into_iter()
263 .find(|adapter| adapter.name() == disposition.server_name)
264 .expect("To find LSP adapter");
265 let new_language_server_id = self.start_language_server(
266 worktree_handle,
267 delegate,
268 adapter,
269 disposition.settings.clone(),
270 key.clone(),
271 cx,
272 );
273 if let Some(state) = self.language_server_ids.get_mut(&key) {
274 state.project_roots.insert(disposition.path.path.clone());
275 } else {
276 debug_assert!(
277 false,
278 "Expected `start_language_server` to ensure that `key` exists in a map"
279 );
280 }
281 new_language_server_id
282 }
283 }
284
285 fn start_language_server(
286 &mut self,
287 worktree_handle: &Entity<Worktree>,
288 delegate: Arc<LocalLspAdapterDelegate>,
289 adapter: Arc<CachedLspAdapter>,
290 settings: Arc<LspSettings>,
291 key: LanguageServerSeed,
292 cx: &mut App,
293 ) -> LanguageServerId {
294 let worktree = worktree_handle.read(cx);
295
296 let root_path = worktree.abs_path();
297 let toolchain = key.toolchain.clone();
298 let override_options = settings.initialization_options.clone();
299
300 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
301
302 let server_id = self.languages.next_language_server_id();
303 log::trace!(
304 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
305 adapter.name.0
306 );
307
308 let binary = self.get_language_server_binary(
309 adapter.clone(),
310 settings,
311 toolchain.clone(),
312 delegate.clone(),
313 true,
314 cx,
315 );
316 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
317
318 let pending_server = cx.spawn({
319 let adapter = adapter.clone();
320 let server_name = adapter.name.clone();
321 let stderr_capture = stderr_capture.clone();
322 #[cfg(any(test, feature = "test-support"))]
323 let lsp_store = self.weak.clone();
324 let pending_workspace_folders = pending_workspace_folders.clone();
325 async move |cx| {
326 let binary = binary.await?;
327 #[cfg(any(test, feature = "test-support"))]
328 if let Some(server) = lsp_store
329 .update(&mut cx.clone(), |this, cx| {
330 this.languages.create_fake_language_server(
331 server_id,
332 &server_name,
333 binary.clone(),
334 &mut cx.to_async(),
335 )
336 })
337 .ok()
338 .flatten()
339 {
340 return Ok(server);
341 }
342
343 let code_action_kinds = adapter.code_action_kinds();
344 lsp::LanguageServer::new(
345 stderr_capture,
346 server_id,
347 server_name,
348 binary,
349 &root_path,
350 code_action_kinds,
351 Some(pending_workspace_folders),
352 cx,
353 )
354 }
355 });
356
357 let startup = {
358 let server_name = adapter.name.0.clone();
359 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
360 let key = key.clone();
361 let adapter = adapter.clone();
362 let lsp_store = self.weak.clone();
363 let pending_workspace_folders = pending_workspace_folders.clone();
364
365 let pull_diagnostics = ProjectSettings::get_global(cx)
366 .diagnostics
367 .lsp_pull_diagnostics
368 .enabled;
369 cx.spawn(async move |cx| {
370 let result = async {
371 let language_server = pending_server.await?;
372
373 let workspace_config = Self::workspace_configuration_for_adapter(
374 adapter.adapter.clone(),
375 &delegate,
376 toolchain,
377 cx,
378 )
379 .await?;
380
381 let mut initialization_options = Self::initialization_options_for_adapter(
382 adapter.adapter.clone(),
383 &delegate,
384 )
385 .await?;
386
387 match (&mut initialization_options, override_options) {
388 (Some(initialization_options), Some(override_options)) => {
389 merge_json_value_into(override_options, initialization_options);
390 }
391 (None, override_options) => initialization_options = override_options,
392 _ => {}
393 }
394
395 let initialization_params = cx.update(|cx| {
396 let mut params =
397 language_server.default_initialize_params(pull_diagnostics, cx);
398 params.initialization_options = initialization_options;
399 adapter.adapter.prepare_initialize_params(params, cx)
400 })??;
401
402 Self::setup_lsp_messages(
403 lsp_store.clone(),
404 &language_server,
405 delegate.clone(),
406 adapter.clone(),
407 );
408
409 let did_change_configuration_params =
410 Arc::new(lsp::DidChangeConfigurationParams {
411 settings: workspace_config,
412 });
413 let language_server = cx
414 .update(|cx| {
415 language_server.initialize(
416 initialization_params,
417 did_change_configuration_params.clone(),
418 cx,
419 )
420 })?
421 .await
422 .inspect_err(|_| {
423 if let Some(lsp_store) = lsp_store.upgrade() {
424 lsp_store
425 .update(cx, |lsp_store, cx| {
426 lsp_store.cleanup_lsp_data(server_id);
427 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
428 })
429 .ok();
430 }
431 })?;
432
433 language_server
434 .notify::<lsp::notification::DidChangeConfiguration>(
435 &did_change_configuration_params,
436 )
437 .ok();
438
439 anyhow::Ok(language_server)
440 }
441 .await;
442
443 match result {
444 Ok(server) => {
445 lsp_store
446 .update(cx, |lsp_store, cx| {
447 lsp_store.insert_newly_running_language_server(
448 adapter,
449 server.clone(),
450 server_id,
451 key,
452 pending_workspace_folders,
453 cx,
454 );
455 })
456 .ok();
457 stderr_capture.lock().take();
458 Some(server)
459 }
460
461 Err(err) => {
462 let log = stderr_capture.lock().take().unwrap_or_default();
463 delegate.update_status(
464 adapter.name(),
465 BinaryStatus::Failed {
466 error: if log.is_empty() {
467 format!("{err:#}")
468 } else {
469 format!("{err:#}\n-- stderr --\n{log}")
470 },
471 },
472 );
473 log::error!("Failed to start language server {server_name:?}: {err:?}");
474 if !log.is_empty() {
475 log::error!("server stderr: {log}");
476 }
477 None
478 }
479 }
480 })
481 };
482 let state = LanguageServerState::Starting {
483 startup,
484 pending_workspace_folders,
485 };
486
487 self.languages
488 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
489
490 self.language_servers.insert(server_id, state);
491 self.language_server_ids
492 .entry(key)
493 .or_insert(UnifiedLanguageServer {
494 id: server_id,
495 project_roots: Default::default(),
496 });
497 server_id
498 }
499
500 fn get_language_server_binary(
501 &self,
502 adapter: Arc<CachedLspAdapter>,
503 settings: Arc<LspSettings>,
504 toolchain: Option<Toolchain>,
505 delegate: Arc<dyn LspAdapterDelegate>,
506 allow_binary_download: bool,
507 cx: &mut App,
508 ) -> Task<Result<LanguageServerBinary>> {
509 if let Some(settings) = settings.binary.as_ref()
510 && settings.path.is_some()
511 {
512 let settings = settings.clone();
513
514 return cx.background_spawn(async move {
515 let mut env = delegate.shell_env().await;
516 env.extend(settings.env.unwrap_or_default());
517
518 Ok(LanguageServerBinary {
519 path: PathBuf::from(&settings.path.unwrap()),
520 env: Some(env),
521 arguments: settings
522 .arguments
523 .unwrap_or_default()
524 .iter()
525 .map(Into::into)
526 .collect(),
527 })
528 });
529 }
530 let lsp_binary_options = LanguageServerBinaryOptions {
531 allow_path_lookup: !settings
532 .binary
533 .as_ref()
534 .and_then(|b| b.ignore_system_version)
535 .unwrap_or_default(),
536 allow_binary_download,
537 pre_release: settings
538 .fetch
539 .as_ref()
540 .and_then(|f| f.pre_release)
541 .unwrap_or(false),
542 };
543
544 cx.spawn(async move |cx| {
545 let binary_result = adapter
546 .clone()
547 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
548 .await;
549
550 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
551
552 let mut binary = binary_result?;
553 let mut shell_env = delegate.shell_env().await;
554
555 shell_env.extend(binary.env.unwrap_or_default());
556
557 if let Some(settings) = settings.binary.as_ref() {
558 if let Some(arguments) = &settings.arguments {
559 binary.arguments = arguments.iter().map(Into::into).collect();
560 }
561 if let Some(env) = &settings.env {
562 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
563 }
564 }
565
566 binary.env = Some(shell_env);
567 Ok(binary)
568 })
569 }
570
571 fn setup_lsp_messages(
572 this: WeakEntity<LspStore>,
573
574 language_server: &LanguageServer,
575 delegate: Arc<dyn LspAdapterDelegate>,
576 adapter: Arc<CachedLspAdapter>,
577 ) {
578 let name = language_server.name();
579 let server_id = language_server.server_id();
580 language_server
581 .on_notification::<lsp::notification::PublishDiagnostics, _>({
582 let adapter = adapter.clone();
583 let this = this.clone();
584 move |mut params, cx| {
585 let adapter = adapter.clone();
586 if let Some(this) = this.upgrade() {
587 this.update(cx, |this, cx| {
588 {
589 let buffer = params
590 .uri
591 .to_file_path()
592 .map(|file_path| this.get_buffer(&file_path, cx))
593 .ok()
594 .flatten();
595 adapter.process_diagnostics(&mut params, server_id, buffer);
596 }
597
598 this.merge_lsp_diagnostics(
599 DiagnosticSourceKind::Pushed,
600 vec![DocumentDiagnosticsUpdate {
601 server_id,
602 diagnostics: params,
603 result_id: None,
604 disk_based_sources: Cow::Borrowed(
605 &adapter.disk_based_diagnostic_sources,
606 ),
607 }],
608 |_, diagnostic, cx| match diagnostic.source_kind {
609 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
610 adapter.retain_old_diagnostic(diagnostic, cx)
611 }
612 DiagnosticSourceKind::Pulled => true,
613 },
614 cx,
615 )
616 .log_err();
617 })
618 .ok();
619 }
620 }
621 })
622 .detach();
623 language_server
624 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
625 let adapter = adapter.adapter.clone();
626 let delegate = delegate.clone();
627 let this = this.clone();
628
629 move |params, cx| {
630 let adapter = adapter.clone();
631 let delegate = delegate.clone();
632 let this = this.clone();
633 let mut cx = cx.clone();
634 async move {
635 let toolchain_for_id = this
636 .update(&mut cx, |this, _| {
637 this.as_local()?.language_server_ids.iter().find_map(
638 |(seed, value)| {
639 (value.id == server_id).then(|| seed.toolchain.clone())
640 },
641 )
642 })?
643 .context("Expected the LSP store to be in a local mode")?;
644 let workspace_config = Self::workspace_configuration_for_adapter(
645 adapter.clone(),
646 &delegate,
647 toolchain_for_id,
648 &mut cx,
649 )
650 .await?;
651
652 Ok(params
653 .items
654 .into_iter()
655 .map(|item| {
656 if let Some(section) = &item.section {
657 workspace_config
658 .get(section)
659 .cloned()
660 .unwrap_or(serde_json::Value::Null)
661 } else {
662 workspace_config.clone()
663 }
664 })
665 .collect())
666 }
667 }
668 })
669 .detach();
670
671 language_server
672 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
673 let this = this.clone();
674 move |_, cx| {
675 let this = this.clone();
676 let cx = cx.clone();
677 async move {
678 let Some(server) =
679 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
680 else {
681 return Ok(None);
682 };
683 let root = server.workspace_folders();
684 Ok(Some(
685 root.into_iter()
686 .map(|uri| WorkspaceFolder {
687 uri,
688 name: Default::default(),
689 })
690 .collect(),
691 ))
692 }
693 }
694 })
695 .detach();
696 // Even though we don't have handling for these requests, respond to them to
697 // avoid stalling any language server like `gopls` which waits for a response
698 // to these requests when initializing.
699 language_server
700 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
701 let this = this.clone();
702 move |params, cx| {
703 let this = this.clone();
704 let mut cx = cx.clone();
705 async move {
706 this.update(&mut cx, |this, _| {
707 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
708 && let lsp::NumberOrString::String(token) = params.token
709 {
710 status.progress_tokens.insert(token);
711 }
712 })?;
713
714 Ok(())
715 }
716 }
717 })
718 .detach();
719
720 language_server
721 .on_request::<lsp::request::RegisterCapability, _, _>({
722 let lsp_store = this.clone();
723 move |params, cx| {
724 let lsp_store = lsp_store.clone();
725 let mut cx = cx.clone();
726 async move {
727 lsp_store
728 .update(&mut cx, |lsp_store, cx| {
729 if lsp_store.as_local().is_some() {
730 match lsp_store
731 .register_server_capabilities(server_id, params, cx)
732 {
733 Ok(()) => {}
734 Err(e) => {
735 log::error!(
736 "Failed to register server capabilities: {e:#}"
737 );
738 }
739 };
740 }
741 })
742 .ok();
743 Ok(())
744 }
745 }
746 })
747 .detach();
748
749 language_server
750 .on_request::<lsp::request::UnregisterCapability, _, _>({
751 let lsp_store = this.clone();
752 move |params, cx| {
753 let lsp_store = lsp_store.clone();
754 let mut cx = cx.clone();
755 async move {
756 lsp_store
757 .update(&mut cx, |lsp_store, cx| {
758 if lsp_store.as_local().is_some() {
759 match lsp_store
760 .unregister_server_capabilities(server_id, params, cx)
761 {
762 Ok(()) => {}
763 Err(e) => {
764 log::error!(
765 "Failed to unregister server capabilities: {e:#}"
766 );
767 }
768 }
769 }
770 })
771 .ok();
772 Ok(())
773 }
774 }
775 })
776 .detach();
777
778 language_server
779 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
780 let this = this.clone();
781 move |params, cx| {
782 let mut cx = cx.clone();
783 let this = this.clone();
784 async move {
785 LocalLspStore::on_lsp_workspace_edit(
786 this.clone(),
787 params,
788 server_id,
789 &mut cx,
790 )
791 .await
792 }
793 }
794 })
795 .detach();
796
797 language_server
798 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
799 let this = this.clone();
800 move |(), cx| {
801 let this = this.clone();
802 let mut cx = cx.clone();
803 async move {
804 this.update(&mut cx, |this, cx| {
805 cx.emit(LspStoreEvent::RefreshInlayHints);
806 this.downstream_client.as_ref().map(|(client, project_id)| {
807 client.send(proto::RefreshInlayHints {
808 project_id: *project_id,
809 })
810 })
811 })?
812 .transpose()?;
813 Ok(())
814 }
815 }
816 })
817 .detach();
818
819 language_server
820 .on_request::<lsp::request::CodeLensRefresh, _, _>({
821 let this = this.clone();
822 move |(), cx| {
823 let this = this.clone();
824 let mut cx = cx.clone();
825 async move {
826 this.update(&mut cx, |this, cx| {
827 cx.emit(LspStoreEvent::RefreshCodeLens);
828 this.downstream_client.as_ref().map(|(client, project_id)| {
829 client.send(proto::RefreshCodeLens {
830 project_id: *project_id,
831 })
832 })
833 })?
834 .transpose()?;
835 Ok(())
836 }
837 }
838 })
839 .detach();
840
841 language_server
842 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
843 let this = this.clone();
844 move |(), cx| {
845 let this = this.clone();
846 let mut cx = cx.clone();
847 async move {
848 this.update(&mut cx, |lsp_store, _| {
849 lsp_store.pull_workspace_diagnostics(server_id);
850 lsp_store
851 .downstream_client
852 .as_ref()
853 .map(|(client, project_id)| {
854 client.send(proto::PullWorkspaceDiagnostics {
855 project_id: *project_id,
856 server_id: server_id.to_proto(),
857 })
858 })
859 })?
860 .transpose()?;
861 Ok(())
862 }
863 }
864 })
865 .detach();
866
867 language_server
868 .on_request::<lsp::request::ShowMessageRequest, _, _>({
869 let this = this.clone();
870 let name = name.to_string();
871 move |params, cx| {
872 let this = this.clone();
873 let name = name.to_string();
874 let mut cx = cx.clone();
875 async move {
876 let actions = params.actions.unwrap_or_default();
877 let (tx, rx) = smol::channel::bounded(1);
878 let request = LanguageServerPromptRequest {
879 level: match params.typ {
880 lsp::MessageType::ERROR => PromptLevel::Critical,
881 lsp::MessageType::WARNING => PromptLevel::Warning,
882 _ => PromptLevel::Info,
883 },
884 message: params.message,
885 actions,
886 response_channel: tx,
887 lsp_name: name.clone(),
888 };
889
890 let did_update = this
891 .update(&mut cx, |_, cx| {
892 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
893 })
894 .is_ok();
895 if did_update {
896 let response = rx.recv().await.ok();
897 Ok(response)
898 } else {
899 Ok(None)
900 }
901 }
902 }
903 })
904 .detach();
905 language_server
906 .on_notification::<lsp::notification::ShowMessage, _>({
907 let this = this.clone();
908 let name = name.to_string();
909 move |params, cx| {
910 let this = this.clone();
911 let name = name.to_string();
912 let mut cx = cx.clone();
913
914 let (tx, _) = smol::channel::bounded(1);
915 let request = LanguageServerPromptRequest {
916 level: match params.typ {
917 lsp::MessageType::ERROR => PromptLevel::Critical,
918 lsp::MessageType::WARNING => PromptLevel::Warning,
919 _ => PromptLevel::Info,
920 },
921 message: params.message,
922 actions: vec![],
923 response_channel: tx,
924 lsp_name: name,
925 };
926
927 let _ = this.update(&mut cx, |_, cx| {
928 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
929 });
930 }
931 })
932 .detach();
933
934 let disk_based_diagnostics_progress_token =
935 adapter.disk_based_diagnostics_progress_token.clone();
936
937 language_server
938 .on_notification::<lsp::notification::Progress, _>({
939 let this = this.clone();
940 move |params, cx| {
941 if let Some(this) = this.upgrade() {
942 this.update(cx, |this, cx| {
943 this.on_lsp_progress(
944 params,
945 server_id,
946 disk_based_diagnostics_progress_token.clone(),
947 cx,
948 );
949 })
950 .ok();
951 }
952 }
953 })
954 .detach();
955
956 language_server
957 .on_notification::<lsp::notification::LogMessage, _>({
958 let this = this.clone();
959 move |params, cx| {
960 if let Some(this) = this.upgrade() {
961 this.update(cx, |_, cx| {
962 cx.emit(LspStoreEvent::LanguageServerLog(
963 server_id,
964 LanguageServerLogType::Log(params.typ),
965 params.message,
966 ));
967 })
968 .ok();
969 }
970 }
971 })
972 .detach();
973
974 language_server
975 .on_notification::<lsp::notification::LogTrace, _>({
976 let this = this.clone();
977 move |params, cx| {
978 let mut cx = cx.clone();
979 if let Some(this) = this.upgrade() {
980 this.update(&mut cx, |_, cx| {
981 cx.emit(LspStoreEvent::LanguageServerLog(
982 server_id,
983 LanguageServerLogType::Trace {
984 verbose_info: params.verbose,
985 },
986 params.message,
987 ));
988 })
989 .ok();
990 }
991 }
992 })
993 .detach();
994
995 json_language_server_ext::register_requests(this.clone(), language_server);
996 rust_analyzer_ext::register_notifications(this.clone(), language_server);
997 clangd_ext::register_notifications(this, language_server, adapter);
998 }
999
1000 fn shutdown_language_servers_on_quit(
1001 &mut self,
1002 _: &mut Context<LspStore>,
1003 ) -> impl Future<Output = ()> + use<> {
1004 let shutdown_futures = self
1005 .language_servers
1006 .drain()
1007 .map(|(_, server_state)| Self::shutdown_server(server_state))
1008 .collect::<Vec<_>>();
1009
1010 async move {
1011 join_all(shutdown_futures).await;
1012 }
1013 }
1014
1015 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1016 match server_state {
1017 LanguageServerState::Running { server, .. } => {
1018 if let Some(shutdown) = server.shutdown() {
1019 shutdown.await;
1020 }
1021 }
1022 LanguageServerState::Starting { startup, .. } => {
1023 if let Some(server) = startup.await
1024 && let Some(shutdown) = server.shutdown()
1025 {
1026 shutdown.await;
1027 }
1028 }
1029 }
1030 Ok(())
1031 }
1032
1033 fn language_servers_for_worktree(
1034 &self,
1035 worktree_id: WorktreeId,
1036 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1037 self.language_server_ids
1038 .iter()
1039 .filter_map(move |(seed, state)| {
1040 if seed.worktree_id != worktree_id {
1041 return None;
1042 }
1043
1044 if let Some(LanguageServerState::Running { server, .. }) =
1045 self.language_servers.get(&state.id)
1046 {
1047 Some(server)
1048 } else {
1049 None
1050 }
1051 })
1052 }
1053
1054 fn language_server_ids_for_project_path(
1055 &self,
1056 project_path: ProjectPath,
1057 language: &Language,
1058 cx: &mut App,
1059 ) -> Vec<LanguageServerId> {
1060 let Some(worktree) = self
1061 .worktree_store
1062 .read(cx)
1063 .worktree_for_id(project_path.worktree_id, cx)
1064 else {
1065 return Vec::new();
1066 };
1067 let delegate: Arc<dyn ManifestDelegate> =
1068 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1069
1070 self.lsp_tree
1071 .get(
1072 project_path,
1073 language.name(),
1074 language.manifest(),
1075 &delegate,
1076 cx,
1077 )
1078 .collect::<Vec<_>>()
1079 }
1080
1081 fn language_server_ids_for_buffer(
1082 &self,
1083 buffer: &Buffer,
1084 cx: &mut App,
1085 ) -> Vec<LanguageServerId> {
1086 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1087 let worktree_id = file.worktree_id(cx);
1088
1089 let path: Arc<RelPath> = file
1090 .path()
1091 .parent()
1092 .map(Arc::from)
1093 .unwrap_or_else(|| file.path().clone());
1094 let worktree_path = ProjectPath { worktree_id, path };
1095 self.language_server_ids_for_project_path(worktree_path, language, cx)
1096 } else {
1097 Vec::new()
1098 }
1099 }
1100
1101 fn language_servers_for_buffer<'a>(
1102 &'a self,
1103 buffer: &'a Buffer,
1104 cx: &'a mut App,
1105 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1106 self.language_server_ids_for_buffer(buffer, cx)
1107 .into_iter()
1108 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1109 LanguageServerState::Running {
1110 adapter, server, ..
1111 } => Some((adapter, server)),
1112 _ => None,
1113 })
1114 }
1115
1116 async fn execute_code_action_kind_locally(
1117 lsp_store: WeakEntity<LspStore>,
1118 mut buffers: Vec<Entity<Buffer>>,
1119 kind: CodeActionKind,
1120 push_to_history: bool,
1121 cx: &mut AsyncApp,
1122 ) -> anyhow::Result<ProjectTransaction> {
1123 // Do not allow multiple concurrent code actions requests for the
1124 // same buffer.
1125 lsp_store.update(cx, |this, cx| {
1126 let this = this.as_local_mut().unwrap();
1127 buffers.retain(|buffer| {
1128 this.buffers_being_formatted
1129 .insert(buffer.read(cx).remote_id())
1130 });
1131 })?;
1132 let _cleanup = defer({
1133 let this = lsp_store.clone();
1134 let mut cx = cx.clone();
1135 let buffers = &buffers;
1136 move || {
1137 this.update(&mut cx, |this, cx| {
1138 let this = this.as_local_mut().unwrap();
1139 for buffer in buffers {
1140 this.buffers_being_formatted
1141 .remove(&buffer.read(cx).remote_id());
1142 }
1143 })
1144 .ok();
1145 }
1146 });
1147 let mut project_transaction = ProjectTransaction::default();
1148
1149 for buffer in &buffers {
1150 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1151 buffer.update(cx, |buffer, cx| {
1152 lsp_store
1153 .as_local()
1154 .unwrap()
1155 .language_servers_for_buffer(buffer, cx)
1156 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1157 .collect::<Vec<_>>()
1158 })
1159 })?;
1160 for (_, language_server) in adapters_and_servers.iter() {
1161 let actions = Self::get_server_code_actions_from_action_kinds(
1162 &lsp_store,
1163 language_server.server_id(),
1164 vec![kind.clone()],
1165 buffer,
1166 cx,
1167 )
1168 .await?;
1169 Self::execute_code_actions_on_server(
1170 &lsp_store,
1171 language_server,
1172 actions,
1173 push_to_history,
1174 &mut project_transaction,
1175 cx,
1176 )
1177 .await?;
1178 }
1179 }
1180 Ok(project_transaction)
1181 }
1182
1183 async fn format_locally(
1184 lsp_store: WeakEntity<LspStore>,
1185 mut buffers: Vec<FormattableBuffer>,
1186 push_to_history: bool,
1187 trigger: FormatTrigger,
1188 logger: zlog::Logger,
1189 cx: &mut AsyncApp,
1190 ) -> anyhow::Result<ProjectTransaction> {
1191 // Do not allow multiple concurrent formatting requests for the
1192 // same buffer.
1193 lsp_store.update(cx, |this, cx| {
1194 let this = this.as_local_mut().unwrap();
1195 buffers.retain(|buffer| {
1196 this.buffers_being_formatted
1197 .insert(buffer.handle.read(cx).remote_id())
1198 });
1199 })?;
1200
1201 let _cleanup = defer({
1202 let this = lsp_store.clone();
1203 let mut cx = cx.clone();
1204 let buffers = &buffers;
1205 move || {
1206 this.update(&mut cx, |this, cx| {
1207 let this = this.as_local_mut().unwrap();
1208 for buffer in buffers {
1209 this.buffers_being_formatted
1210 .remove(&buffer.handle.read(cx).remote_id());
1211 }
1212 })
1213 .ok();
1214 }
1215 });
1216
1217 let mut project_transaction = ProjectTransaction::default();
1218
1219 for buffer in &buffers {
1220 zlog::debug!(
1221 logger =>
1222 "formatting buffer '{:?}'",
1223 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1224 );
1225 // Create an empty transaction to hold all of the formatting edits.
1226 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1227 // ensure no transactions created while formatting are
1228 // grouped with the previous transaction in the history
1229 // based on the transaction group interval
1230 buffer.finalize_last_transaction();
1231 buffer
1232 .start_transaction()
1233 .context("transaction already open")?;
1234 buffer.end_transaction(cx);
1235 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1236 buffer.finalize_last_transaction();
1237 anyhow::Ok(transaction_id)
1238 })??;
1239
1240 let result = Self::format_buffer_locally(
1241 lsp_store.clone(),
1242 buffer,
1243 formatting_transaction_id,
1244 trigger,
1245 logger,
1246 cx,
1247 )
1248 .await;
1249
1250 buffer.handle.update(cx, |buffer, cx| {
1251 let Some(formatting_transaction) =
1252 buffer.get_transaction(formatting_transaction_id).cloned()
1253 else {
1254 zlog::warn!(logger => "no formatting transaction");
1255 return;
1256 };
1257 if formatting_transaction.edit_ids.is_empty() {
1258 zlog::debug!(logger => "no changes made while formatting");
1259 buffer.forget_transaction(formatting_transaction_id);
1260 return;
1261 }
1262 if !push_to_history {
1263 zlog::trace!(logger => "forgetting format transaction");
1264 buffer.forget_transaction(formatting_transaction.id);
1265 }
1266 project_transaction
1267 .0
1268 .insert(cx.entity(), formatting_transaction);
1269 })?;
1270
1271 result?;
1272 }
1273
1274 Ok(project_transaction)
1275 }
1276
1277 async fn format_buffer_locally(
1278 lsp_store: WeakEntity<LspStore>,
1279 buffer: &FormattableBuffer,
1280 formatting_transaction_id: clock::Lamport,
1281 trigger: FormatTrigger,
1282 logger: zlog::Logger,
1283 cx: &mut AsyncApp,
1284 ) -> Result<()> {
1285 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1286 buffer.handle.update(cx, |buffer, cx| {
1287 let adapters_and_servers = lsp_store
1288 .as_local()
1289 .unwrap()
1290 .language_servers_for_buffer(buffer, cx)
1291 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1292 .collect::<Vec<_>>();
1293 let settings =
1294 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1295 .into_owned();
1296 (adapters_and_servers, settings)
1297 })
1298 })?;
1299
1300 /// Apply edits to the buffer that will become part of the formatting transaction.
1301 /// Fails if the buffer has been edited since the start of that transaction.
1302 fn extend_formatting_transaction(
1303 buffer: &FormattableBuffer,
1304 formatting_transaction_id: text::TransactionId,
1305 cx: &mut AsyncApp,
1306 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1307 ) -> anyhow::Result<()> {
1308 buffer.handle.update(cx, |buffer, cx| {
1309 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1310 if last_transaction_id != Some(formatting_transaction_id) {
1311 anyhow::bail!("Buffer edited while formatting. Aborting")
1312 }
1313 buffer.start_transaction();
1314 operation(buffer, cx);
1315 if let Some(transaction_id) = buffer.end_transaction(cx) {
1316 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1317 }
1318 Ok(())
1319 })?
1320 }
1321
1322 // handle whitespace formatting
1323 if settings.remove_trailing_whitespace_on_save {
1324 zlog::trace!(logger => "removing trailing whitespace");
1325 let diff = buffer
1326 .handle
1327 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1328 .await;
1329 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1330 buffer.apply_diff(diff, cx);
1331 })?;
1332 }
1333
1334 if settings.ensure_final_newline_on_save {
1335 zlog::trace!(logger => "ensuring final newline");
1336 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1337 buffer.ensure_final_newline(cx);
1338 })?;
1339 }
1340
1341 let formatters = match (trigger, &settings.format_on_save) {
1342 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1343 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1344 match &settings.formatter {
1345 SelectedFormatter::Auto => {
1346 if settings.prettier.allowed {
1347 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1348 std::slice::from_ref(&Formatter::Prettier)
1349 } else {
1350 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1351 std::slice::from_ref(&Formatter::LanguageServer { name: None })
1352 }
1353 }
1354 SelectedFormatter::List(formatter_list) => formatter_list.as_ref(),
1355 }
1356 }
1357 };
1358
1359 for formatter in formatters {
1360 match formatter {
1361 Formatter::Prettier => {
1362 let logger = zlog::scoped!(logger => "prettier");
1363 zlog::trace!(logger => "formatting");
1364 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1365
1366 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1367 lsp_store.prettier_store().unwrap().downgrade()
1368 })?;
1369 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1370 .await
1371 .transpose()?;
1372 let Some(diff) = diff else {
1373 zlog::trace!(logger => "No changes");
1374 continue;
1375 };
1376
1377 extend_formatting_transaction(
1378 buffer,
1379 formatting_transaction_id,
1380 cx,
1381 |buffer, cx| {
1382 buffer.apply_diff(diff, cx);
1383 },
1384 )?;
1385 }
1386 Formatter::External { command, arguments } => {
1387 let logger = zlog::scoped!(logger => "command");
1388 zlog::trace!(logger => "formatting");
1389 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1390
1391 let diff = Self::format_via_external_command(
1392 buffer,
1393 command.as_ref(),
1394 arguments.as_deref(),
1395 cx,
1396 )
1397 .await
1398 .with_context(|| {
1399 format!("Failed to format buffer via external command: {}", command)
1400 })?;
1401 let Some(diff) = diff else {
1402 zlog::trace!(logger => "No changes");
1403 continue;
1404 };
1405
1406 extend_formatting_transaction(
1407 buffer,
1408 formatting_transaction_id,
1409 cx,
1410 |buffer, cx| {
1411 buffer.apply_diff(diff, cx);
1412 },
1413 )?;
1414 }
1415 Formatter::LanguageServer { name } => {
1416 let logger = zlog::scoped!(logger => "language-server");
1417 zlog::trace!(logger => "formatting");
1418 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1419
1420 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1421 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1422 continue;
1423 };
1424
1425 let language_server = if let Some(name) = name.as_deref() {
1426 adapters_and_servers.iter().find_map(|(adapter, server)| {
1427 if adapter.name.0.as_ref() == name {
1428 Some(server.clone())
1429 } else {
1430 None
1431 }
1432 })
1433 } else {
1434 adapters_and_servers.first().map(|e| e.1.clone())
1435 };
1436
1437 let Some(language_server) = language_server else {
1438 log::debug!(
1439 "No language server found to format buffer '{:?}'. Skipping",
1440 buffer_path_abs.as_path().to_string_lossy()
1441 );
1442 continue;
1443 };
1444
1445 zlog::trace!(
1446 logger =>
1447 "Formatting buffer '{:?}' using language server '{:?}'",
1448 buffer_path_abs.as_path().to_string_lossy(),
1449 language_server.name()
1450 );
1451
1452 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1453 zlog::trace!(logger => "formatting ranges");
1454 Self::format_ranges_via_lsp(
1455 &lsp_store,
1456 &buffer.handle,
1457 ranges,
1458 buffer_path_abs,
1459 &language_server,
1460 &settings,
1461 cx,
1462 )
1463 .await
1464 .context("Failed to format ranges via language server")?
1465 } else {
1466 zlog::trace!(logger => "formatting full");
1467 Self::format_via_lsp(
1468 &lsp_store,
1469 &buffer.handle,
1470 buffer_path_abs,
1471 &language_server,
1472 &settings,
1473 cx,
1474 )
1475 .await
1476 .context("failed to format via language server")?
1477 };
1478
1479 if edits.is_empty() {
1480 zlog::trace!(logger => "No changes");
1481 continue;
1482 }
1483 extend_formatting_transaction(
1484 buffer,
1485 formatting_transaction_id,
1486 cx,
1487 |buffer, cx| {
1488 buffer.edit(edits, None, cx);
1489 },
1490 )?;
1491 }
1492 Formatter::CodeAction(code_action_name) => {
1493 let logger = zlog::scoped!(logger => "code-actions");
1494 zlog::trace!(logger => "formatting");
1495 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1496
1497 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1498 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1499 continue;
1500 };
1501
1502 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1503 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1504
1505 let mut actions_and_servers = Vec::new();
1506
1507 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1508 let actions_result = Self::get_server_code_actions_from_action_kinds(
1509 &lsp_store,
1510 language_server.server_id(),
1511 vec![code_action_kind.clone()],
1512 &buffer.handle,
1513 cx,
1514 )
1515 .await
1516 .with_context(|| {
1517 format!(
1518 "Failed to resolve code action {:?} with language server {}",
1519 code_action_kind,
1520 language_server.name()
1521 )
1522 });
1523 let Ok(actions) = actions_result else {
1524 // note: it may be better to set result to the error and break formatters here
1525 // but for now we try to execute the actions that we can resolve and skip the rest
1526 zlog::error!(
1527 logger =>
1528 "Failed to resolve code action {:?} with language server {}",
1529 code_action_kind,
1530 language_server.name()
1531 );
1532 continue;
1533 };
1534 for action in actions {
1535 actions_and_servers.push((action, index));
1536 }
1537 }
1538
1539 if actions_and_servers.is_empty() {
1540 zlog::warn!(logger => "No code actions were resolved, continuing");
1541 continue;
1542 }
1543
1544 'actions: for (mut action, server_index) in actions_and_servers {
1545 let server = &adapters_and_servers[server_index].1;
1546
1547 let describe_code_action = |action: &CodeAction| {
1548 format!(
1549 "code action '{}' with title \"{}\" on server {}",
1550 action
1551 .lsp_action
1552 .action_kind()
1553 .unwrap_or("unknown".into())
1554 .as_str(),
1555 action.lsp_action.title(),
1556 server.name(),
1557 )
1558 };
1559
1560 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1561
1562 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1563 zlog::error!(
1564 logger =>
1565 "Failed to resolve {}. Error: {}",
1566 describe_code_action(&action),
1567 err
1568 );
1569 continue;
1570 }
1571
1572 if let Some(edit) = action.lsp_action.edit().cloned() {
1573 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1574 // but filters out and logs warnings for code actions that require unreasonably
1575 // difficult handling on our part, such as:
1576 // - applying edits that call commands
1577 // which can result in arbitrary workspace edits being sent from the server that
1578 // have no way of being tied back to the command that initiated them (i.e. we
1579 // can't know which edits are part of the format request, or if the server is done sending
1580 // actions in response to the command)
1581 // - actions that create/delete/modify/rename files other than the one we are formatting
1582 // as we then would need to handle such changes correctly in the local history as well
1583 // as the remote history through the ProjectTransaction
1584 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1585 // Supporting these actions is not impossible, but not supported as of yet.
1586 if edit.changes.is_none() && edit.document_changes.is_none() {
1587 zlog::trace!(
1588 logger =>
1589 "No changes for code action. Skipping {}",
1590 describe_code_action(&action),
1591 );
1592 continue;
1593 }
1594
1595 let mut operations = Vec::new();
1596 if let Some(document_changes) = edit.document_changes {
1597 match document_changes {
1598 lsp::DocumentChanges::Edits(edits) => operations.extend(
1599 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1600 ),
1601 lsp::DocumentChanges::Operations(ops) => operations = ops,
1602 }
1603 } else if let Some(changes) = edit.changes {
1604 operations.extend(changes.into_iter().map(|(uri, edits)| {
1605 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1606 text_document:
1607 lsp::OptionalVersionedTextDocumentIdentifier {
1608 uri,
1609 version: None,
1610 },
1611 edits: edits.into_iter().map(Edit::Plain).collect(),
1612 })
1613 }));
1614 }
1615
1616 let mut edits = Vec::with_capacity(operations.len());
1617
1618 if operations.is_empty() {
1619 zlog::trace!(
1620 logger =>
1621 "No changes for code action. Skipping {}",
1622 describe_code_action(&action),
1623 );
1624 continue;
1625 }
1626 for operation in operations {
1627 let op = match operation {
1628 lsp::DocumentChangeOperation::Edit(op) => op,
1629 lsp::DocumentChangeOperation::Op(_) => {
1630 zlog::warn!(
1631 logger =>
1632 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1633 describe_code_action(&action),
1634 );
1635 continue 'actions;
1636 }
1637 };
1638 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1639 zlog::warn!(
1640 logger =>
1641 "Failed to convert URI '{:?}' to file path. Skipping {}",
1642 &op.text_document.uri,
1643 describe_code_action(&action),
1644 );
1645 continue 'actions;
1646 };
1647 if &file_path != buffer_path_abs {
1648 zlog::warn!(
1649 logger =>
1650 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1651 file_path,
1652 buffer_path_abs,
1653 describe_code_action(&action),
1654 );
1655 continue 'actions;
1656 }
1657
1658 let mut lsp_edits = Vec::new();
1659 for edit in op.edits {
1660 match edit {
1661 Edit::Plain(edit) => {
1662 if !lsp_edits.contains(&edit) {
1663 lsp_edits.push(edit);
1664 }
1665 }
1666 Edit::Annotated(edit) => {
1667 if !lsp_edits.contains(&edit.text_edit) {
1668 lsp_edits.push(edit.text_edit);
1669 }
1670 }
1671 Edit::Snippet(_) => {
1672 zlog::warn!(
1673 logger =>
1674 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1675 describe_code_action(&action),
1676 );
1677 continue 'actions;
1678 }
1679 }
1680 }
1681 let edits_result = lsp_store
1682 .update(cx, |lsp_store, cx| {
1683 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1684 &buffer.handle,
1685 lsp_edits,
1686 server.server_id(),
1687 op.text_document.version,
1688 cx,
1689 )
1690 })?
1691 .await;
1692 let Ok(resolved_edits) = edits_result else {
1693 zlog::warn!(
1694 logger =>
1695 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1696 buffer_path_abs.as_path(),
1697 describe_code_action(&action),
1698 );
1699 continue 'actions;
1700 };
1701 edits.extend(resolved_edits);
1702 }
1703
1704 if edits.is_empty() {
1705 zlog::warn!(logger => "No edits resolved from LSP");
1706 continue;
1707 }
1708
1709 extend_formatting_transaction(
1710 buffer,
1711 formatting_transaction_id,
1712 cx,
1713 |buffer, cx| {
1714 zlog::info!(
1715 "Applying edits {edits:?}. Content: {:?}",
1716 buffer.text()
1717 );
1718 buffer.edit(edits, None, cx);
1719 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1720 },
1721 )?;
1722 }
1723
1724 if let Some(command) = action.lsp_action.command() {
1725 zlog::warn!(
1726 logger =>
1727 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1728 &command.command,
1729 );
1730
1731 // bail early if command is invalid
1732 let server_capabilities = server.capabilities();
1733 let available_commands = server_capabilities
1734 .execute_command_provider
1735 .as_ref()
1736 .map(|options| options.commands.as_slice())
1737 .unwrap_or_default();
1738 if !available_commands.contains(&command.command) {
1739 zlog::warn!(
1740 logger =>
1741 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1742 command.command,
1743 server.name(),
1744 );
1745 continue;
1746 }
1747
1748 // noop so we just ensure buffer hasn't been edited since resolving code actions
1749 extend_formatting_transaction(
1750 buffer,
1751 formatting_transaction_id,
1752 cx,
1753 |_, _| {},
1754 )?;
1755 zlog::info!(logger => "Executing command {}", &command.command);
1756
1757 lsp_store.update(cx, |this, _| {
1758 this.as_local_mut()
1759 .unwrap()
1760 .last_workspace_edits_by_language_server
1761 .remove(&server.server_id());
1762 })?;
1763
1764 let execute_command_result = server
1765 .request::<lsp::request::ExecuteCommand>(
1766 lsp::ExecuteCommandParams {
1767 command: command.command.clone(),
1768 arguments: command.arguments.clone().unwrap_or_default(),
1769 ..Default::default()
1770 },
1771 )
1772 .await
1773 .into_response();
1774
1775 if execute_command_result.is_err() {
1776 zlog::error!(
1777 logger =>
1778 "Failed to execute command '{}' as part of {}",
1779 &command.command,
1780 describe_code_action(&action),
1781 );
1782 continue 'actions;
1783 }
1784
1785 let mut project_transaction_command =
1786 lsp_store.update(cx, |this, _| {
1787 this.as_local_mut()
1788 .unwrap()
1789 .last_workspace_edits_by_language_server
1790 .remove(&server.server_id())
1791 .unwrap_or_default()
1792 })?;
1793
1794 if let Some(transaction) =
1795 project_transaction_command.0.remove(&buffer.handle)
1796 {
1797 zlog::trace!(
1798 logger =>
1799 "Successfully captured {} edits that resulted from command {}",
1800 transaction.edit_ids.len(),
1801 &command.command,
1802 );
1803 let transaction_id_project_transaction = transaction.id;
1804 buffer.handle.update(cx, |buffer, _| {
1805 // it may have been removed from history if push_to_history was
1806 // false in deserialize_workspace_edit. If so push it so we
1807 // can merge it with the format transaction
1808 // and pop the combined transaction off the history stack
1809 // later if push_to_history is false
1810 if buffer.get_transaction(transaction.id).is_none() {
1811 buffer.push_transaction(transaction, Instant::now());
1812 }
1813 buffer.merge_transactions(
1814 transaction_id_project_transaction,
1815 formatting_transaction_id,
1816 );
1817 })?;
1818 }
1819
1820 if !project_transaction_command.0.is_empty() {
1821 let mut extra_buffers = String::new();
1822 for buffer in project_transaction_command.0.keys() {
1823 buffer
1824 .read_with(cx, |b, cx| {
1825 if let Some(path) = b.project_path(cx) {
1826 if !extra_buffers.is_empty() {
1827 extra_buffers.push_str(", ");
1828 }
1829 extra_buffers.push_str(path.path.as_unix_str());
1830 }
1831 })
1832 .ok();
1833 }
1834 zlog::warn!(
1835 logger =>
1836 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1837 &command.command,
1838 extra_buffers,
1839 );
1840 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1841 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1842 // add it so it's included, and merge it into the format transaction when its created later
1843 }
1844 }
1845 }
1846 }
1847 }
1848 }
1849
1850 Ok(())
1851 }
1852
1853 pub async fn format_ranges_via_lsp(
1854 this: &WeakEntity<LspStore>,
1855 buffer_handle: &Entity<Buffer>,
1856 ranges: &[Range<Anchor>],
1857 abs_path: &Path,
1858 language_server: &Arc<LanguageServer>,
1859 settings: &LanguageSettings,
1860 cx: &mut AsyncApp,
1861 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1862 let capabilities = &language_server.capabilities();
1863 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1864 if range_formatting_provider == Some(&OneOf::Left(false)) {
1865 anyhow::bail!(
1866 "{} language server does not support range formatting",
1867 language_server.name()
1868 );
1869 }
1870
1871 let uri = file_path_to_lsp_url(abs_path)?;
1872 let text_document = lsp::TextDocumentIdentifier::new(uri);
1873
1874 let lsp_edits = {
1875 let mut lsp_ranges = Vec::new();
1876 this.update(cx, |_this, cx| {
1877 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1878 // not have been sent to the language server. This seems like a fairly systemic
1879 // issue, though, the resolution probably is not specific to formatting.
1880 //
1881 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1882 // LSP.
1883 let snapshot = buffer_handle.read(cx).snapshot();
1884 for range in ranges {
1885 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1886 }
1887 anyhow::Ok(())
1888 })??;
1889
1890 let mut edits = None;
1891 for range in lsp_ranges {
1892 if let Some(mut edit) = language_server
1893 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1894 text_document: text_document.clone(),
1895 range,
1896 options: lsp_command::lsp_formatting_options(settings),
1897 work_done_progress_params: Default::default(),
1898 })
1899 .await
1900 .into_response()?
1901 {
1902 edits.get_or_insert_with(Vec::new).append(&mut edit);
1903 }
1904 }
1905 edits
1906 };
1907
1908 if let Some(lsp_edits) = lsp_edits {
1909 this.update(cx, |this, cx| {
1910 this.as_local_mut().unwrap().edits_from_lsp(
1911 buffer_handle,
1912 lsp_edits,
1913 language_server.server_id(),
1914 None,
1915 cx,
1916 )
1917 })?
1918 .await
1919 } else {
1920 Ok(Vec::with_capacity(0))
1921 }
1922 }
1923
1924 async fn format_via_lsp(
1925 this: &WeakEntity<LspStore>,
1926 buffer: &Entity<Buffer>,
1927 abs_path: &Path,
1928 language_server: &Arc<LanguageServer>,
1929 settings: &LanguageSettings,
1930 cx: &mut AsyncApp,
1931 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1932 let logger = zlog::scoped!("lsp_format");
1933 zlog::info!(logger => "Formatting via LSP");
1934
1935 let uri = file_path_to_lsp_url(abs_path)?;
1936 let text_document = lsp::TextDocumentIdentifier::new(uri);
1937 let capabilities = &language_server.capabilities();
1938
1939 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1940 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1941
1942 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1943 let _timer = zlog::time!(logger => "format-full");
1944 language_server
1945 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1946 text_document,
1947 options: lsp_command::lsp_formatting_options(settings),
1948 work_done_progress_params: Default::default(),
1949 })
1950 .await
1951 .into_response()?
1952 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1953 let _timer = zlog::time!(logger => "format-range");
1954 let buffer_start = lsp::Position::new(0, 0);
1955 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1956 language_server
1957 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1958 text_document: text_document.clone(),
1959 range: lsp::Range::new(buffer_start, buffer_end),
1960 options: lsp_command::lsp_formatting_options(settings),
1961 work_done_progress_params: Default::default(),
1962 })
1963 .await
1964 .into_response()?
1965 } else {
1966 None
1967 };
1968
1969 if let Some(lsp_edits) = lsp_edits {
1970 this.update(cx, |this, cx| {
1971 this.as_local_mut().unwrap().edits_from_lsp(
1972 buffer,
1973 lsp_edits,
1974 language_server.server_id(),
1975 None,
1976 cx,
1977 )
1978 })?
1979 .await
1980 } else {
1981 Ok(Vec::with_capacity(0))
1982 }
1983 }
1984
1985 async fn format_via_external_command(
1986 buffer: &FormattableBuffer,
1987 command: &str,
1988 arguments: Option<&[String]>,
1989 cx: &mut AsyncApp,
1990 ) -> Result<Option<Diff>> {
1991 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
1992 let file = File::from_dyn(buffer.file())?;
1993 let worktree = file.worktree.read(cx);
1994 let mut worktree_path = worktree.abs_path().to_path_buf();
1995 if worktree.root_entry()?.is_file() {
1996 worktree_path.pop();
1997 }
1998 Some(worktree_path)
1999 })?;
2000
2001 let mut child = util::command::new_smol_command(command);
2002
2003 if let Some(buffer_env) = buffer.env.as_ref() {
2004 child.envs(buffer_env);
2005 }
2006
2007 if let Some(working_dir_path) = working_dir_path {
2008 child.current_dir(working_dir_path);
2009 }
2010
2011 if let Some(arguments) = arguments {
2012 child.args(arguments.iter().map(|arg| {
2013 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2014 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2015 } else {
2016 arg.replace("{buffer_path}", "Untitled")
2017 }
2018 }));
2019 }
2020
2021 let mut child = child
2022 .stdin(smol::process::Stdio::piped())
2023 .stdout(smol::process::Stdio::piped())
2024 .stderr(smol::process::Stdio::piped())
2025 .spawn()?;
2026
2027 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2028 let text = buffer
2029 .handle
2030 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2031 for chunk in text.chunks() {
2032 stdin.write_all(chunk.as_bytes()).await?;
2033 }
2034 stdin.flush().await?;
2035
2036 let output = child.output().await?;
2037 anyhow::ensure!(
2038 output.status.success(),
2039 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2040 output.status.code(),
2041 String::from_utf8_lossy(&output.stdout),
2042 String::from_utf8_lossy(&output.stderr),
2043 );
2044
2045 let stdout = String::from_utf8(output.stdout)?;
2046 Ok(Some(
2047 buffer
2048 .handle
2049 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2050 .await,
2051 ))
2052 }
2053
2054 async fn try_resolve_code_action(
2055 lang_server: &LanguageServer,
2056 action: &mut CodeAction,
2057 ) -> anyhow::Result<()> {
2058 match &mut action.lsp_action {
2059 LspAction::Action(lsp_action) => {
2060 if !action.resolved
2061 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2062 && lsp_action.data.is_some()
2063 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2064 {
2065 *lsp_action = Box::new(
2066 lang_server
2067 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2068 .await
2069 .into_response()?,
2070 );
2071 }
2072 }
2073 LspAction::CodeLens(lens) => {
2074 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2075 *lens = lang_server
2076 .request::<lsp::request::CodeLensResolve>(lens.clone())
2077 .await
2078 .into_response()?;
2079 }
2080 }
2081 LspAction::Command(_) => {}
2082 }
2083
2084 action.resolved = true;
2085 anyhow::Ok(())
2086 }
2087
2088 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2089 let buffer = buffer_handle.read(cx);
2090
2091 let file = buffer.file().cloned();
2092
2093 let Some(file) = File::from_dyn(file.as_ref()) else {
2094 return;
2095 };
2096 if !file.is_local() {
2097 return;
2098 }
2099 let path = ProjectPath::from_file(file, cx);
2100 let worktree_id = file.worktree_id(cx);
2101 let language = buffer.language().cloned();
2102
2103 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2104 for (server_id, diagnostics) in
2105 diagnostics.get(file.path()).cloned().unwrap_or_default()
2106 {
2107 self.update_buffer_diagnostics(
2108 buffer_handle,
2109 server_id,
2110 None,
2111 None,
2112 diagnostics,
2113 Vec::new(),
2114 cx,
2115 )
2116 .log_err();
2117 }
2118 }
2119 let Some(language) = language else {
2120 return;
2121 };
2122 let Some(snapshot) = self
2123 .worktree_store
2124 .read(cx)
2125 .worktree_for_id(worktree_id, cx)
2126 .map(|worktree| worktree.read(cx).snapshot())
2127 else {
2128 return;
2129 };
2130 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2131
2132 for server_id in
2133 self.lsp_tree
2134 .get(path, language.name(), language.manifest(), &delegate, cx)
2135 {
2136 let server = self
2137 .language_servers
2138 .get(&server_id)
2139 .and_then(|server_state| {
2140 if let LanguageServerState::Running { server, .. } = server_state {
2141 Some(server.clone())
2142 } else {
2143 None
2144 }
2145 });
2146 let server = match server {
2147 Some(server) => server,
2148 None => continue,
2149 };
2150
2151 buffer_handle.update(cx, |buffer, cx| {
2152 buffer.set_completion_triggers(
2153 server.server_id(),
2154 server
2155 .capabilities()
2156 .completion_provider
2157 .as_ref()
2158 .and_then(|provider| {
2159 provider
2160 .trigger_characters
2161 .as_ref()
2162 .map(|characters| characters.iter().cloned().collect())
2163 })
2164 .unwrap_or_default(),
2165 cx,
2166 );
2167 });
2168 }
2169 }
2170
2171 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2172 buffer.update(cx, |buffer, cx| {
2173 let Some(language) = buffer.language() else {
2174 return;
2175 };
2176 let path = ProjectPath {
2177 worktree_id: old_file.worktree_id(cx),
2178 path: old_file.path.clone(),
2179 };
2180 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2181 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2182 buffer.set_completion_triggers(server_id, Default::default(), cx);
2183 }
2184 });
2185 }
2186
2187 fn update_buffer_diagnostics(
2188 &mut self,
2189 buffer: &Entity<Buffer>,
2190 server_id: LanguageServerId,
2191 result_id: Option<String>,
2192 version: Option<i32>,
2193 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2194 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2195 cx: &mut Context<LspStore>,
2196 ) -> Result<()> {
2197 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2198 Ordering::Equal
2199 .then_with(|| b.is_primary.cmp(&a.is_primary))
2200 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2201 .then_with(|| a.severity.cmp(&b.severity))
2202 .then_with(|| a.message.cmp(&b.message))
2203 }
2204
2205 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2206 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2207 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2208
2209 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2210 Ordering::Equal
2211 .then_with(|| a.range.start.cmp(&b.range.start))
2212 .then_with(|| b.range.end.cmp(&a.range.end))
2213 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2214 });
2215
2216 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2217
2218 let edits_since_save = std::cell::LazyCell::new(|| {
2219 let saved_version = buffer.read(cx).saved_version();
2220 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2221 });
2222
2223 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2224
2225 for (new_diagnostic, entry) in diagnostics {
2226 let start;
2227 let end;
2228 if new_diagnostic && entry.diagnostic.is_disk_based {
2229 // Some diagnostics are based on files on disk instead of buffers'
2230 // current contents. Adjust these diagnostics' ranges to reflect
2231 // any unsaved edits.
2232 // Do not alter the reused ones though, as their coordinates were stored as anchors
2233 // and were properly adjusted on reuse.
2234 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2235 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2236 } else {
2237 start = entry.range.start;
2238 end = entry.range.end;
2239 }
2240
2241 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2242 ..snapshot.clip_point_utf16(end, Bias::Right);
2243
2244 // Expand empty ranges by one codepoint
2245 if range.start == range.end {
2246 // This will be go to the next boundary when being clipped
2247 range.end.column += 1;
2248 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2249 if range.start == range.end && range.end.column > 0 {
2250 range.start.column -= 1;
2251 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2252 }
2253 }
2254
2255 sanitized_diagnostics.push(DiagnosticEntry {
2256 range,
2257 diagnostic: entry.diagnostic,
2258 });
2259 }
2260 drop(edits_since_save);
2261
2262 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2263 buffer.update(cx, |buffer, cx| {
2264 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2265 self.buffer_pull_diagnostics_result_ids
2266 .entry(server_id)
2267 .or_default()
2268 .insert(abs_path, result_id);
2269 }
2270
2271 buffer.update_diagnostics(server_id, set, cx)
2272 });
2273
2274 Ok(())
2275 }
2276
2277 fn register_language_server_for_invisible_worktree(
2278 &mut self,
2279 worktree: &Entity<Worktree>,
2280 language_server_id: LanguageServerId,
2281 cx: &mut App,
2282 ) {
2283 let worktree = worktree.read(cx);
2284 let worktree_id = worktree.id();
2285 debug_assert!(!worktree.is_visible());
2286 let Some(mut origin_seed) = self
2287 .language_server_ids
2288 .iter()
2289 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2290 else {
2291 return;
2292 };
2293 origin_seed.worktree_id = worktree_id;
2294 self.language_server_ids
2295 .entry(origin_seed)
2296 .or_insert_with(|| UnifiedLanguageServer {
2297 id: language_server_id,
2298 project_roots: Default::default(),
2299 });
2300 }
2301
2302 fn register_buffer_with_language_servers(
2303 &mut self,
2304 buffer_handle: &Entity<Buffer>,
2305 only_register_servers: HashSet<LanguageServerSelector>,
2306 cx: &mut Context<LspStore>,
2307 ) {
2308 let buffer = buffer_handle.read(cx);
2309 let buffer_id = buffer.remote_id();
2310
2311 let Some(file) = File::from_dyn(buffer.file()) else {
2312 return;
2313 };
2314 if !file.is_local() {
2315 return;
2316 }
2317
2318 let abs_path = file.abs_path(cx);
2319 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2320 return;
2321 };
2322 let initial_snapshot = buffer.text_snapshot();
2323 let worktree_id = file.worktree_id(cx);
2324
2325 let Some(language) = buffer.language().cloned() else {
2326 return;
2327 };
2328 let path: Arc<RelPath> = file
2329 .path()
2330 .parent()
2331 .map(Arc::from)
2332 .unwrap_or_else(|| file.path().clone());
2333 let Some(worktree) = self
2334 .worktree_store
2335 .read(cx)
2336 .worktree_for_id(worktree_id, cx)
2337 else {
2338 return;
2339 };
2340 let language_name = language.name();
2341 let (reused, delegate, servers) = self
2342 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2343 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2344 .unwrap_or_else(|| {
2345 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2346 let delegate: Arc<dyn ManifestDelegate> =
2347 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2348
2349 let servers = self
2350 .lsp_tree
2351 .walk(
2352 ProjectPath { worktree_id, path },
2353 language.name(),
2354 language.manifest(),
2355 &delegate,
2356 cx,
2357 )
2358 .collect::<Vec<_>>();
2359 (false, lsp_delegate, servers)
2360 });
2361 let servers_and_adapters = servers
2362 .into_iter()
2363 .filter_map(|server_node| {
2364 if reused && server_node.server_id().is_none() {
2365 return None;
2366 }
2367 if !only_register_servers.is_empty() {
2368 if let Some(server_id) = server_node.server_id()
2369 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2370 {
2371 return None;
2372 }
2373 if let Some(name) = server_node.name()
2374 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2375 {
2376 return None;
2377 }
2378 }
2379
2380 let server_id = server_node.server_id_or_init(|disposition| {
2381 let path = &disposition.path;
2382
2383 {
2384 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2385
2386 let server_id = self.get_or_insert_language_server(
2387 &worktree,
2388 delegate.clone(),
2389 disposition,
2390 &language_name,
2391 cx,
2392 );
2393
2394 if let Some(state) = self.language_servers.get(&server_id)
2395 && let Ok(uri) = uri
2396 {
2397 state.add_workspace_folder(uri);
2398 };
2399 server_id
2400 }
2401 })?;
2402 let server_state = self.language_servers.get(&server_id)?;
2403 if let LanguageServerState::Running {
2404 server, adapter, ..
2405 } = server_state
2406 {
2407 Some((server.clone(), adapter.clone()))
2408 } else {
2409 None
2410 }
2411 })
2412 .collect::<Vec<_>>();
2413 for (server, adapter) in servers_and_adapters {
2414 buffer_handle.update(cx, |buffer, cx| {
2415 buffer.set_completion_triggers(
2416 server.server_id(),
2417 server
2418 .capabilities()
2419 .completion_provider
2420 .as_ref()
2421 .and_then(|provider| {
2422 provider
2423 .trigger_characters
2424 .as_ref()
2425 .map(|characters| characters.iter().cloned().collect())
2426 })
2427 .unwrap_or_default(),
2428 cx,
2429 );
2430 });
2431
2432 let snapshot = LspBufferSnapshot {
2433 version: 0,
2434 snapshot: initial_snapshot.clone(),
2435 };
2436
2437 let mut registered = false;
2438 self.buffer_snapshots
2439 .entry(buffer_id)
2440 .or_default()
2441 .entry(server.server_id())
2442 .or_insert_with(|| {
2443 registered = true;
2444 server.register_buffer(
2445 uri.clone(),
2446 adapter.language_id(&language.name()),
2447 0,
2448 initial_snapshot.text(),
2449 );
2450
2451 vec![snapshot]
2452 });
2453
2454 self.buffers_opened_in_servers
2455 .entry(buffer_id)
2456 .or_default()
2457 .insert(server.server_id());
2458 if registered {
2459 cx.emit(LspStoreEvent::LanguageServerUpdate {
2460 language_server_id: server.server_id(),
2461 name: None,
2462 message: proto::update_language_server::Variant::RegisteredForBuffer(
2463 proto::RegisteredForBuffer {
2464 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2465 buffer_id: buffer_id.to_proto(),
2466 },
2467 ),
2468 });
2469 }
2470 }
2471 }
2472
2473 fn reuse_existing_language_server<'lang_name>(
2474 &self,
2475 server_tree: &LanguageServerTree,
2476 worktree: &Entity<Worktree>,
2477 language_name: &'lang_name LanguageName,
2478 cx: &mut App,
2479 ) -> Option<(
2480 Arc<LocalLspAdapterDelegate>,
2481 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2482 )> {
2483 if worktree.read(cx).is_visible() {
2484 return None;
2485 }
2486
2487 let worktree_store = self.worktree_store.read(cx);
2488 let servers = server_tree
2489 .instances
2490 .iter()
2491 .filter(|(worktree_id, _)| {
2492 worktree_store
2493 .worktree_for_id(**worktree_id, cx)
2494 .is_some_and(|worktree| worktree.read(cx).is_visible())
2495 })
2496 .flat_map(|(worktree_id, servers)| {
2497 servers
2498 .roots
2499 .iter()
2500 .flat_map(|(_, language_servers)| language_servers)
2501 .map(move |(_, (server_node, server_languages))| {
2502 (worktree_id, server_node, server_languages)
2503 })
2504 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2505 .map(|(worktree_id, server_node, _)| {
2506 (
2507 *worktree_id,
2508 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2509 )
2510 })
2511 })
2512 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2513 acc.entry(worktree_id)
2514 .or_insert_with(Vec::new)
2515 .push(server_node);
2516 acc
2517 })
2518 .into_values()
2519 .max_by_key(|servers| servers.len())?;
2520
2521 let worktree_id = worktree.read(cx).id();
2522 let apply = move |tree: &mut LanguageServerTree| {
2523 for server_node in &servers {
2524 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2525 }
2526 servers
2527 };
2528
2529 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2530 Some((delegate, apply))
2531 }
2532
2533 pub(crate) fn unregister_old_buffer_from_language_servers(
2534 &mut self,
2535 buffer: &Entity<Buffer>,
2536 old_file: &File,
2537 cx: &mut App,
2538 ) {
2539 let old_path = match old_file.as_local() {
2540 Some(local) => local.abs_path(cx),
2541 None => return,
2542 };
2543
2544 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2545 debug_panic!("{old_path:?} is not parseable as an URI");
2546 return;
2547 };
2548 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2549 }
2550
2551 pub(crate) fn unregister_buffer_from_language_servers(
2552 &mut self,
2553 buffer: &Entity<Buffer>,
2554 file_url: &lsp::Uri,
2555 cx: &mut App,
2556 ) {
2557 buffer.update(cx, |buffer, cx| {
2558 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2559
2560 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2561 language_server.unregister_buffer(file_url.clone());
2562 }
2563 });
2564 }
2565
2566 fn buffer_snapshot_for_lsp_version(
2567 &mut self,
2568 buffer: &Entity<Buffer>,
2569 server_id: LanguageServerId,
2570 version: Option<i32>,
2571 cx: &App,
2572 ) -> Result<TextBufferSnapshot> {
2573 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2574
2575 if let Some(version) = version {
2576 let buffer_id = buffer.read(cx).remote_id();
2577 let snapshots = if let Some(snapshots) = self
2578 .buffer_snapshots
2579 .get_mut(&buffer_id)
2580 .and_then(|m| m.get_mut(&server_id))
2581 {
2582 snapshots
2583 } else if version == 0 {
2584 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2585 // We detect this case and treat it as if the version was `None`.
2586 return Ok(buffer.read(cx).text_snapshot());
2587 } else {
2588 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2589 };
2590
2591 let found_snapshot = snapshots
2592 .binary_search_by_key(&version, |e| e.version)
2593 .map(|ix| snapshots[ix].snapshot.clone())
2594 .map_err(|_| {
2595 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2596 })?;
2597
2598 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2599 Ok(found_snapshot)
2600 } else {
2601 Ok((buffer.read(cx)).text_snapshot())
2602 }
2603 }
2604
2605 async fn get_server_code_actions_from_action_kinds(
2606 lsp_store: &WeakEntity<LspStore>,
2607 language_server_id: LanguageServerId,
2608 code_action_kinds: Vec<lsp::CodeActionKind>,
2609 buffer: &Entity<Buffer>,
2610 cx: &mut AsyncApp,
2611 ) -> Result<Vec<CodeAction>> {
2612 let actions = lsp_store
2613 .update(cx, move |this, cx| {
2614 let request = GetCodeActions {
2615 range: text::Anchor::MIN..text::Anchor::MAX,
2616 kinds: Some(code_action_kinds),
2617 };
2618 let server = LanguageServerToQuery::Other(language_server_id);
2619 this.request_lsp(buffer.clone(), server, request, cx)
2620 })?
2621 .await?;
2622 Ok(actions)
2623 }
2624
2625 pub async fn execute_code_actions_on_server(
2626 lsp_store: &WeakEntity<LspStore>,
2627 language_server: &Arc<LanguageServer>,
2628
2629 actions: Vec<CodeAction>,
2630 push_to_history: bool,
2631 project_transaction: &mut ProjectTransaction,
2632 cx: &mut AsyncApp,
2633 ) -> anyhow::Result<()> {
2634 for mut action in actions {
2635 Self::try_resolve_code_action(language_server, &mut action)
2636 .await
2637 .context("resolving a formatting code action")?;
2638
2639 if let Some(edit) = action.lsp_action.edit() {
2640 if edit.changes.is_none() && edit.document_changes.is_none() {
2641 continue;
2642 }
2643
2644 let new = Self::deserialize_workspace_edit(
2645 lsp_store.upgrade().context("project dropped")?,
2646 edit.clone(),
2647 push_to_history,
2648 language_server.clone(),
2649 cx,
2650 )
2651 .await?;
2652 project_transaction.0.extend(new.0);
2653 }
2654
2655 if let Some(command) = action.lsp_action.command() {
2656 let server_capabilities = language_server.capabilities();
2657 let available_commands = server_capabilities
2658 .execute_command_provider
2659 .as_ref()
2660 .map(|options| options.commands.as_slice())
2661 .unwrap_or_default();
2662 if available_commands.contains(&command.command) {
2663 lsp_store.update(cx, |lsp_store, _| {
2664 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2665 mode.last_workspace_edits_by_language_server
2666 .remove(&language_server.server_id());
2667 }
2668 })?;
2669
2670 language_server
2671 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2672 command: command.command.clone(),
2673 arguments: command.arguments.clone().unwrap_or_default(),
2674 ..Default::default()
2675 })
2676 .await
2677 .into_response()
2678 .context("execute command")?;
2679
2680 lsp_store.update(cx, |this, _| {
2681 if let LspStoreMode::Local(mode) = &mut this.mode {
2682 project_transaction.0.extend(
2683 mode.last_workspace_edits_by_language_server
2684 .remove(&language_server.server_id())
2685 .unwrap_or_default()
2686 .0,
2687 )
2688 }
2689 })?;
2690 } else {
2691 log::warn!(
2692 "Cannot execute a command {} not listed in the language server capabilities",
2693 command.command
2694 )
2695 }
2696 }
2697 }
2698 Ok(())
2699 }
2700
2701 pub async fn deserialize_text_edits(
2702 this: Entity<LspStore>,
2703 buffer_to_edit: Entity<Buffer>,
2704 edits: Vec<lsp::TextEdit>,
2705 push_to_history: bool,
2706 _: Arc<CachedLspAdapter>,
2707 language_server: Arc<LanguageServer>,
2708 cx: &mut AsyncApp,
2709 ) -> Result<Option<Transaction>> {
2710 let edits = this
2711 .update(cx, |this, cx| {
2712 this.as_local_mut().unwrap().edits_from_lsp(
2713 &buffer_to_edit,
2714 edits,
2715 language_server.server_id(),
2716 None,
2717 cx,
2718 )
2719 })?
2720 .await?;
2721
2722 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2723 buffer.finalize_last_transaction();
2724 buffer.start_transaction();
2725 for (range, text) in edits {
2726 buffer.edit([(range, text)], None, cx);
2727 }
2728
2729 if buffer.end_transaction(cx).is_some() {
2730 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2731 if !push_to_history {
2732 buffer.forget_transaction(transaction.id);
2733 }
2734 Some(transaction)
2735 } else {
2736 None
2737 }
2738 })?;
2739
2740 Ok(transaction)
2741 }
2742
2743 #[allow(clippy::type_complexity)]
2744 pub(crate) fn edits_from_lsp(
2745 &mut self,
2746 buffer: &Entity<Buffer>,
2747 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2748 server_id: LanguageServerId,
2749 version: Option<i32>,
2750 cx: &mut Context<LspStore>,
2751 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2752 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2753 cx.background_spawn(async move {
2754 let snapshot = snapshot?;
2755 let mut lsp_edits = lsp_edits
2756 .into_iter()
2757 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2758 .collect::<Vec<_>>();
2759
2760 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2761
2762 let mut lsp_edits = lsp_edits.into_iter().peekable();
2763 let mut edits = Vec::new();
2764 while let Some((range, mut new_text)) = lsp_edits.next() {
2765 // Clip invalid ranges provided by the language server.
2766 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2767 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2768
2769 // Combine any LSP edits that are adjacent.
2770 //
2771 // Also, combine LSP edits that are separated from each other by only
2772 // a newline. This is important because for some code actions,
2773 // Rust-analyzer rewrites the entire buffer via a series of edits that
2774 // are separated by unchanged newline characters.
2775 //
2776 // In order for the diffing logic below to work properly, any edits that
2777 // cancel each other out must be combined into one.
2778 while let Some((next_range, next_text)) = lsp_edits.peek() {
2779 if next_range.start.0 > range.end {
2780 if next_range.start.0.row > range.end.row + 1
2781 || next_range.start.0.column > 0
2782 || snapshot.clip_point_utf16(
2783 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2784 Bias::Left,
2785 ) > range.end
2786 {
2787 break;
2788 }
2789 new_text.push('\n');
2790 }
2791 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2792 new_text.push_str(next_text);
2793 lsp_edits.next();
2794 }
2795
2796 // For multiline edits, perform a diff of the old and new text so that
2797 // we can identify the changes more precisely, preserving the locations
2798 // of any anchors positioned in the unchanged regions.
2799 if range.end.row > range.start.row {
2800 let offset = range.start.to_offset(&snapshot);
2801 let old_text = snapshot.text_for_range(range).collect::<String>();
2802 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2803 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2804 (
2805 snapshot.anchor_after(offset + range.start)
2806 ..snapshot.anchor_before(offset + range.end),
2807 replacement,
2808 )
2809 }));
2810 } else if range.end == range.start {
2811 let anchor = snapshot.anchor_after(range.start);
2812 edits.push((anchor..anchor, new_text.into()));
2813 } else {
2814 let edit_start = snapshot.anchor_after(range.start);
2815 let edit_end = snapshot.anchor_before(range.end);
2816 edits.push((edit_start..edit_end, new_text.into()));
2817 }
2818 }
2819
2820 Ok(edits)
2821 })
2822 }
2823
2824 pub(crate) async fn deserialize_workspace_edit(
2825 this: Entity<LspStore>,
2826 edit: lsp::WorkspaceEdit,
2827 push_to_history: bool,
2828 language_server: Arc<LanguageServer>,
2829 cx: &mut AsyncApp,
2830 ) -> Result<ProjectTransaction> {
2831 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2832
2833 let mut operations = Vec::new();
2834 if let Some(document_changes) = edit.document_changes {
2835 match document_changes {
2836 lsp::DocumentChanges::Edits(edits) => {
2837 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2838 }
2839 lsp::DocumentChanges::Operations(ops) => operations = ops,
2840 }
2841 } else if let Some(changes) = edit.changes {
2842 operations.extend(changes.into_iter().map(|(uri, edits)| {
2843 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2844 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2845 uri,
2846 version: None,
2847 },
2848 edits: edits.into_iter().map(Edit::Plain).collect(),
2849 })
2850 }));
2851 }
2852
2853 let mut project_transaction = ProjectTransaction::default();
2854 for operation in operations {
2855 match operation {
2856 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2857 let abs_path = op
2858 .uri
2859 .to_file_path()
2860 .map_err(|()| anyhow!("can't convert URI to path"))?;
2861
2862 if let Some(parent_path) = abs_path.parent() {
2863 fs.create_dir(parent_path).await?;
2864 }
2865 if abs_path.ends_with("/") {
2866 fs.create_dir(&abs_path).await?;
2867 } else {
2868 fs.create_file(
2869 &abs_path,
2870 op.options
2871 .map(|options| fs::CreateOptions {
2872 overwrite: options.overwrite.unwrap_or(false),
2873 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2874 })
2875 .unwrap_or_default(),
2876 )
2877 .await?;
2878 }
2879 }
2880
2881 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2882 let source_abs_path = op
2883 .old_uri
2884 .to_file_path()
2885 .map_err(|()| anyhow!("can't convert URI to path"))?;
2886 let target_abs_path = op
2887 .new_uri
2888 .to_file_path()
2889 .map_err(|()| anyhow!("can't convert URI to path"))?;
2890 fs.rename(
2891 &source_abs_path,
2892 &target_abs_path,
2893 op.options
2894 .map(|options| fs::RenameOptions {
2895 overwrite: options.overwrite.unwrap_or(false),
2896 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2897 })
2898 .unwrap_or_default(),
2899 )
2900 .await?;
2901 }
2902
2903 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2904 let abs_path = op
2905 .uri
2906 .to_file_path()
2907 .map_err(|()| anyhow!("can't convert URI to path"))?;
2908 let options = op
2909 .options
2910 .map(|options| fs::RemoveOptions {
2911 recursive: options.recursive.unwrap_or(false),
2912 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
2913 })
2914 .unwrap_or_default();
2915 if abs_path.ends_with("/") {
2916 fs.remove_dir(&abs_path, options).await?;
2917 } else {
2918 fs.remove_file(&abs_path, options).await?;
2919 }
2920 }
2921
2922 lsp::DocumentChangeOperation::Edit(op) => {
2923 let buffer_to_edit = this
2924 .update(cx, |this, cx| {
2925 this.open_local_buffer_via_lsp(
2926 op.text_document.uri.clone(),
2927 language_server.server_id(),
2928 cx,
2929 )
2930 })?
2931 .await?;
2932
2933 let edits = this
2934 .update(cx, |this, cx| {
2935 let path = buffer_to_edit.read(cx).project_path(cx);
2936 let active_entry = this.active_entry;
2937 let is_active_entry = path.is_some_and(|project_path| {
2938 this.worktree_store
2939 .read(cx)
2940 .entry_for_path(&project_path, cx)
2941 .is_some_and(|entry| Some(entry.id) == active_entry)
2942 });
2943 let local = this.as_local_mut().unwrap();
2944
2945 let (mut edits, mut snippet_edits) = (vec![], vec![]);
2946 for edit in op.edits {
2947 match edit {
2948 Edit::Plain(edit) => {
2949 if !edits.contains(&edit) {
2950 edits.push(edit)
2951 }
2952 }
2953 Edit::Annotated(edit) => {
2954 if !edits.contains(&edit.text_edit) {
2955 edits.push(edit.text_edit)
2956 }
2957 }
2958 Edit::Snippet(edit) => {
2959 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
2960 else {
2961 continue;
2962 };
2963
2964 if is_active_entry {
2965 snippet_edits.push((edit.range, snippet));
2966 } else {
2967 // Since this buffer is not focused, apply a normal edit.
2968 let new_edit = TextEdit {
2969 range: edit.range,
2970 new_text: snippet.text,
2971 };
2972 if !edits.contains(&new_edit) {
2973 edits.push(new_edit);
2974 }
2975 }
2976 }
2977 }
2978 }
2979 if !snippet_edits.is_empty() {
2980 let buffer_id = buffer_to_edit.read(cx).remote_id();
2981 let version = if let Some(buffer_version) = op.text_document.version
2982 {
2983 local
2984 .buffer_snapshot_for_lsp_version(
2985 &buffer_to_edit,
2986 language_server.server_id(),
2987 Some(buffer_version),
2988 cx,
2989 )
2990 .ok()
2991 .map(|snapshot| snapshot.version)
2992 } else {
2993 Some(buffer_to_edit.read(cx).saved_version().clone())
2994 };
2995
2996 let most_recent_edit = version.and_then(|version| {
2997 version.iter().max_by_key(|timestamp| timestamp.value)
2998 });
2999 // Check if the edit that triggered that edit has been made by this participant.
3000
3001 if let Some(most_recent_edit) = most_recent_edit {
3002 cx.emit(LspStoreEvent::SnippetEdit {
3003 buffer_id,
3004 edits: snippet_edits,
3005 most_recent_edit,
3006 });
3007 }
3008 }
3009
3010 local.edits_from_lsp(
3011 &buffer_to_edit,
3012 edits,
3013 language_server.server_id(),
3014 op.text_document.version,
3015 cx,
3016 )
3017 })?
3018 .await?;
3019
3020 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3021 buffer.finalize_last_transaction();
3022 buffer.start_transaction();
3023 for (range, text) in edits {
3024 buffer.edit([(range, text)], None, cx);
3025 }
3026
3027 buffer.end_transaction(cx).and_then(|transaction_id| {
3028 if push_to_history {
3029 buffer.finalize_last_transaction();
3030 buffer.get_transaction(transaction_id).cloned()
3031 } else {
3032 buffer.forget_transaction(transaction_id)
3033 }
3034 })
3035 })?;
3036 if let Some(transaction) = transaction {
3037 project_transaction.0.insert(buffer_to_edit, transaction);
3038 }
3039 }
3040 }
3041 }
3042
3043 Ok(project_transaction)
3044 }
3045
3046 async fn on_lsp_workspace_edit(
3047 this: WeakEntity<LspStore>,
3048 params: lsp::ApplyWorkspaceEditParams,
3049 server_id: LanguageServerId,
3050 cx: &mut AsyncApp,
3051 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3052 let this = this.upgrade().context("project project closed")?;
3053 let language_server = this
3054 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3055 .context("language server not found")?;
3056 let transaction = Self::deserialize_workspace_edit(
3057 this.clone(),
3058 params.edit,
3059 true,
3060 language_server.clone(),
3061 cx,
3062 )
3063 .await
3064 .log_err();
3065 this.update(cx, |this, _| {
3066 if let Some(transaction) = transaction {
3067 this.as_local_mut()
3068 .unwrap()
3069 .last_workspace_edits_by_language_server
3070 .insert(server_id, transaction);
3071 }
3072 })?;
3073 Ok(lsp::ApplyWorkspaceEditResponse {
3074 applied: true,
3075 failed_change: None,
3076 failure_reason: None,
3077 })
3078 }
3079
3080 fn remove_worktree(
3081 &mut self,
3082 id_to_remove: WorktreeId,
3083 cx: &mut Context<LspStore>,
3084 ) -> Vec<LanguageServerId> {
3085 self.diagnostics.remove(&id_to_remove);
3086 self.prettier_store.update(cx, |prettier_store, cx| {
3087 prettier_store.remove_worktree(id_to_remove, cx);
3088 });
3089
3090 let mut servers_to_remove = BTreeSet::default();
3091 let mut servers_to_preserve = HashSet::default();
3092 for (seed, state) in &self.language_server_ids {
3093 if seed.worktree_id == id_to_remove {
3094 servers_to_remove.insert(state.id);
3095 } else {
3096 servers_to_preserve.insert(state.id);
3097 }
3098 }
3099 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3100 self.language_server_ids
3101 .retain(|_, state| !servers_to_remove.contains(&state.id));
3102 for server_id_to_remove in &servers_to_remove {
3103 self.language_server_watched_paths
3104 .remove(server_id_to_remove);
3105 self.language_server_paths_watched_for_rename
3106 .remove(server_id_to_remove);
3107 self.last_workspace_edits_by_language_server
3108 .remove(server_id_to_remove);
3109 self.language_servers.remove(server_id_to_remove);
3110 self.buffer_pull_diagnostics_result_ids
3111 .remove(server_id_to_remove);
3112 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3113 buffer_servers.remove(server_id_to_remove);
3114 }
3115 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3116 }
3117 servers_to_remove.into_iter().collect()
3118 }
3119
3120 fn rebuild_watched_paths_inner<'a>(
3121 &'a self,
3122 language_server_id: LanguageServerId,
3123 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3124 cx: &mut Context<LspStore>,
3125 ) -> LanguageServerWatchedPathsBuilder {
3126 let worktrees = self
3127 .worktree_store
3128 .read(cx)
3129 .worktrees()
3130 .filter_map(|worktree| {
3131 self.language_servers_for_worktree(worktree.read(cx).id())
3132 .find(|server| server.server_id() == language_server_id)
3133 .map(|_| worktree)
3134 })
3135 .collect::<Vec<_>>();
3136
3137 let mut worktree_globs = HashMap::default();
3138 let mut abs_globs = HashMap::default();
3139 log::trace!(
3140 "Processing new watcher paths for language server with id {}",
3141 language_server_id
3142 );
3143
3144 for watcher in watchers {
3145 if let Some((worktree, literal_prefix, pattern)) =
3146 self.worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3147 {
3148 worktree.update(cx, |worktree, _| {
3149 if let Some((tree, glob)) =
3150 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3151 {
3152 tree.add_path_prefix_to_scan(literal_prefix);
3153 worktree_globs
3154 .entry(tree.id())
3155 .or_insert_with(GlobSetBuilder::new)
3156 .add(glob);
3157 }
3158 });
3159 } else {
3160 let (path, pattern) = match &watcher.glob_pattern {
3161 lsp::GlobPattern::String(s) => {
3162 let watcher_path = SanitizedPath::new(s);
3163 let path = glob_literal_prefix(watcher_path.as_path());
3164 let pattern = watcher_path
3165 .as_path()
3166 .strip_prefix(&path)
3167 .map(|p| p.to_string_lossy().into_owned())
3168 .unwrap_or_else(|e| {
3169 debug_panic!(
3170 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3171 s,
3172 path.display(),
3173 e
3174 );
3175 watcher_path.as_path().to_string_lossy().into_owned()
3176 });
3177 (path, pattern)
3178 }
3179 lsp::GlobPattern::Relative(rp) => {
3180 let Ok(mut base_uri) = match &rp.base_uri {
3181 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3182 lsp::OneOf::Right(base_uri) => base_uri,
3183 }
3184 .to_file_path() else {
3185 continue;
3186 };
3187
3188 let path = glob_literal_prefix(Path::new(&rp.pattern));
3189 let pattern = Path::new(&rp.pattern)
3190 .strip_prefix(&path)
3191 .map(|p| p.to_string_lossy().into_owned())
3192 .unwrap_or_else(|e| {
3193 debug_panic!(
3194 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3195 rp.pattern,
3196 path.display(),
3197 e
3198 );
3199 rp.pattern.clone()
3200 });
3201 base_uri.push(path);
3202 (base_uri, pattern)
3203 }
3204 };
3205
3206 if let Some(glob) = Glob::new(&pattern).log_err() {
3207 if !path
3208 .components()
3209 .any(|c| matches!(c, path::Component::Normal(_)))
3210 {
3211 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3212 // rather than adding a new watcher for `/`.
3213 for worktree in &worktrees {
3214 worktree_globs
3215 .entry(worktree.read(cx).id())
3216 .or_insert_with(GlobSetBuilder::new)
3217 .add(glob.clone());
3218 }
3219 } else {
3220 abs_globs
3221 .entry(path.into())
3222 .or_insert_with(GlobSetBuilder::new)
3223 .add(glob);
3224 }
3225 }
3226 }
3227 }
3228
3229 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3230 for (worktree_id, builder) in worktree_globs {
3231 if let Ok(globset) = builder.build() {
3232 watch_builder.watch_worktree(worktree_id, globset);
3233 }
3234 }
3235 for (abs_path, builder) in abs_globs {
3236 if let Ok(globset) = builder.build() {
3237 watch_builder.watch_abs_path(abs_path, globset);
3238 }
3239 }
3240 watch_builder
3241 }
3242
3243 fn worktree_and_path_for_file_watcher(
3244 &self,
3245 worktrees: &[Entity<Worktree>],
3246 watcher: &FileSystemWatcher,
3247 cx: &App,
3248 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3249 worktrees.iter().find_map(|worktree| {
3250 let tree = worktree.read(cx);
3251 let worktree_root_path = tree.abs_path();
3252 let path_style = tree.path_style();
3253 match &watcher.glob_pattern {
3254 lsp::GlobPattern::String(s) => {
3255 let watcher_path = SanitizedPath::new(s);
3256 let relative = watcher_path
3257 .as_path()
3258 .strip_prefix(&worktree_root_path)
3259 .ok()?;
3260 let literal_prefix = glob_literal_prefix(relative);
3261 Some((
3262 worktree.clone(),
3263 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3264 relative.to_string_lossy().into_owned(),
3265 ))
3266 }
3267 lsp::GlobPattern::Relative(rp) => {
3268 let base_uri = match &rp.base_uri {
3269 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3270 lsp::OneOf::Right(base_uri) => base_uri,
3271 }
3272 .to_file_path()
3273 .ok()?;
3274 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3275 let mut literal_prefix = relative.to_owned();
3276 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3277 Some((
3278 worktree.clone(),
3279 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3280 rp.pattern.clone(),
3281 ))
3282 }
3283 }
3284 })
3285 }
3286
3287 fn rebuild_watched_paths(
3288 &mut self,
3289 language_server_id: LanguageServerId,
3290 cx: &mut Context<LspStore>,
3291 ) {
3292 let Some(watchers) = self
3293 .language_server_watcher_registrations
3294 .get(&language_server_id)
3295 else {
3296 return;
3297 };
3298
3299 let watch_builder =
3300 self.rebuild_watched_paths_inner(language_server_id, watchers.values().flatten(), cx);
3301 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3302 self.language_server_watched_paths
3303 .insert(language_server_id, watcher);
3304
3305 cx.notify();
3306 }
3307
3308 fn on_lsp_did_change_watched_files(
3309 &mut self,
3310 language_server_id: LanguageServerId,
3311 registration_id: &str,
3312 params: DidChangeWatchedFilesRegistrationOptions,
3313 cx: &mut Context<LspStore>,
3314 ) {
3315 let registrations = self
3316 .language_server_watcher_registrations
3317 .entry(language_server_id)
3318 .or_default();
3319
3320 registrations.insert(registration_id.to_string(), params.watchers);
3321
3322 self.rebuild_watched_paths(language_server_id, cx);
3323 }
3324
3325 fn on_lsp_unregister_did_change_watched_files(
3326 &mut self,
3327 language_server_id: LanguageServerId,
3328 registration_id: &str,
3329 cx: &mut Context<LspStore>,
3330 ) {
3331 let registrations = self
3332 .language_server_watcher_registrations
3333 .entry(language_server_id)
3334 .or_default();
3335
3336 if registrations.remove(registration_id).is_some() {
3337 log::info!(
3338 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3339 language_server_id,
3340 registration_id
3341 );
3342 } else {
3343 log::warn!(
3344 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3345 language_server_id,
3346 registration_id
3347 );
3348 }
3349
3350 self.rebuild_watched_paths(language_server_id, cx);
3351 }
3352
3353 async fn initialization_options_for_adapter(
3354 adapter: Arc<dyn LspAdapter>,
3355 delegate: &Arc<dyn LspAdapterDelegate>,
3356 ) -> Result<Option<serde_json::Value>> {
3357 let Some(mut initialization_config) =
3358 adapter.clone().initialization_options(delegate).await?
3359 else {
3360 return Ok(None);
3361 };
3362
3363 for other_adapter in delegate.registered_lsp_adapters() {
3364 if other_adapter.name() == adapter.name() {
3365 continue;
3366 }
3367 if let Ok(Some(target_config)) = other_adapter
3368 .clone()
3369 .additional_initialization_options(adapter.name(), delegate)
3370 .await
3371 {
3372 merge_json_value_into(target_config.clone(), &mut initialization_config);
3373 }
3374 }
3375
3376 Ok(Some(initialization_config))
3377 }
3378
3379 async fn workspace_configuration_for_adapter(
3380 adapter: Arc<dyn LspAdapter>,
3381 delegate: &Arc<dyn LspAdapterDelegate>,
3382 toolchain: Option<Toolchain>,
3383 cx: &mut AsyncApp,
3384 ) -> Result<serde_json::Value> {
3385 let mut workspace_config = adapter
3386 .clone()
3387 .workspace_configuration(delegate, toolchain, cx)
3388 .await?;
3389
3390 for other_adapter in delegate.registered_lsp_adapters() {
3391 if other_adapter.name() == adapter.name() {
3392 continue;
3393 }
3394 if let Ok(Some(target_config)) = other_adapter
3395 .clone()
3396 .additional_workspace_configuration(adapter.name(), delegate, cx)
3397 .await
3398 {
3399 merge_json_value_into(target_config.clone(), &mut workspace_config);
3400 }
3401 }
3402
3403 Ok(workspace_config)
3404 }
3405
3406 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3407 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3408 Some(server.clone())
3409 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3410 Some(Arc::clone(server))
3411 } else {
3412 None
3413 }
3414 }
3415}
3416
3417fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3418 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3419 cx.emit(LspStoreEvent::LanguageServerUpdate {
3420 language_server_id: server.server_id(),
3421 name: Some(server.name()),
3422 message: proto::update_language_server::Variant::MetadataUpdated(
3423 proto::ServerMetadataUpdated {
3424 capabilities: Some(capabilities),
3425 },
3426 ),
3427 });
3428 }
3429}
3430
3431#[derive(Debug)]
3432pub struct FormattableBuffer {
3433 handle: Entity<Buffer>,
3434 abs_path: Option<PathBuf>,
3435 env: Option<HashMap<String, String>>,
3436 ranges: Option<Vec<Range<Anchor>>>,
3437}
3438
3439pub struct RemoteLspStore {
3440 upstream_client: Option<AnyProtoClient>,
3441 upstream_project_id: u64,
3442}
3443
3444pub(crate) enum LspStoreMode {
3445 Local(LocalLspStore), // ssh host and collab host
3446 Remote(RemoteLspStore), // collab guest
3447}
3448
3449impl LspStoreMode {
3450 fn is_local(&self) -> bool {
3451 matches!(self, LspStoreMode::Local(_))
3452 }
3453}
3454
3455pub struct LspStore {
3456 mode: LspStoreMode,
3457 last_formatting_failure: Option<String>,
3458 downstream_client: Option<(AnyProtoClient, u64)>,
3459 nonce: u128,
3460 buffer_store: Entity<BufferStore>,
3461 worktree_store: Entity<WorktreeStore>,
3462 pub languages: Arc<LanguageRegistry>,
3463 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3464 active_entry: Option<ProjectEntryId>,
3465 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3466 _maintain_buffer_languages: Task<()>,
3467 diagnostic_summaries:
3468 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3469 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3470 lsp_document_colors: HashMap<BufferId, DocumentColorData>,
3471 lsp_code_lens: HashMap<BufferId, CodeLensData>,
3472 running_lsp_requests: HashMap<TypeId, (Global, HashMap<LspRequestId, Task<()>>)>,
3473}
3474
3475#[derive(Debug, Default, Clone)]
3476pub struct DocumentColors {
3477 pub colors: HashSet<DocumentColor>,
3478 pub cache_version: Option<usize>,
3479}
3480
3481type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3482type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3483
3484#[derive(Debug, Default)]
3485struct DocumentColorData {
3486 colors_for_version: Global,
3487 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3488 cache_version: usize,
3489 colors_update: Option<(Global, DocumentColorTask)>,
3490}
3491
3492#[derive(Debug, Default)]
3493struct CodeLensData {
3494 lens_for_version: Global,
3495 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3496 update: Option<(Global, CodeLensTask)>,
3497}
3498
3499#[derive(Debug, PartialEq, Eq, Clone, Copy)]
3500pub enum LspFetchStrategy {
3501 IgnoreCache,
3502 UseCache { known_cache_version: Option<usize> },
3503}
3504
3505#[derive(Debug)]
3506pub enum LspStoreEvent {
3507 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3508 LanguageServerRemoved(LanguageServerId),
3509 LanguageServerUpdate {
3510 language_server_id: LanguageServerId,
3511 name: Option<LanguageServerName>,
3512 message: proto::update_language_server::Variant,
3513 },
3514 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3515 LanguageServerPrompt(LanguageServerPromptRequest),
3516 LanguageDetected {
3517 buffer: Entity<Buffer>,
3518 new_language: Option<Arc<Language>>,
3519 },
3520 Notification(String),
3521 RefreshInlayHints,
3522 RefreshCodeLens,
3523 DiagnosticsUpdated {
3524 server_id: LanguageServerId,
3525 paths: Vec<ProjectPath>,
3526 },
3527 DiskBasedDiagnosticsStarted {
3528 language_server_id: LanguageServerId,
3529 },
3530 DiskBasedDiagnosticsFinished {
3531 language_server_id: LanguageServerId,
3532 },
3533 SnippetEdit {
3534 buffer_id: BufferId,
3535 edits: Vec<(lsp::Range, Snippet)>,
3536 most_recent_edit: clock::Lamport,
3537 },
3538}
3539
3540#[derive(Clone, Debug, Serialize)]
3541pub struct LanguageServerStatus {
3542 pub name: LanguageServerName,
3543 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3544 pub has_pending_diagnostic_updates: bool,
3545 progress_tokens: HashSet<String>,
3546 pub worktree: Option<WorktreeId>,
3547}
3548
3549#[derive(Clone, Debug)]
3550struct CoreSymbol {
3551 pub language_server_name: LanguageServerName,
3552 pub source_worktree_id: WorktreeId,
3553 pub source_language_server_id: LanguageServerId,
3554 pub path: SymbolLocation,
3555 pub name: String,
3556 pub kind: lsp::SymbolKind,
3557 pub range: Range<Unclipped<PointUtf16>>,
3558}
3559
3560#[derive(Clone, Debug, PartialEq, Eq)]
3561pub enum SymbolLocation {
3562 InProject(ProjectPath),
3563 OutsideProject {
3564 abs_path: Arc<Path>,
3565 signature: [u8; 32],
3566 },
3567}
3568
3569impl SymbolLocation {
3570 fn file_name(&self) -> Option<&str> {
3571 match self {
3572 Self::InProject(path) => path.path.file_name(),
3573 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3574 }
3575 }
3576}
3577
3578impl LspStore {
3579 pub fn init(client: &AnyProtoClient) {
3580 client.add_entity_request_handler(Self::handle_lsp_query);
3581 client.add_entity_message_handler(Self::handle_lsp_query_response);
3582 client.add_entity_request_handler(Self::handle_restart_language_servers);
3583 client.add_entity_request_handler(Self::handle_stop_language_servers);
3584 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3585 client.add_entity_message_handler(Self::handle_start_language_server);
3586 client.add_entity_message_handler(Self::handle_update_language_server);
3587 client.add_entity_message_handler(Self::handle_language_server_log);
3588 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3589 client.add_entity_request_handler(Self::handle_format_buffers);
3590 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3591 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3592 client.add_entity_request_handler(Self::handle_apply_code_action);
3593 client.add_entity_request_handler(Self::handle_inlay_hints);
3594 client.add_entity_request_handler(Self::handle_get_project_symbols);
3595 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3596 client.add_entity_request_handler(Self::handle_get_color_presentation);
3597 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3598 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3599 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3600 client.add_entity_request_handler(Self::handle_on_type_formatting);
3601 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3602 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3603 client.add_entity_request_handler(Self::handle_rename_project_entry);
3604 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3605 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3606 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3607 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3608 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3609 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3610 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3611
3612 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3613 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3614 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3615 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3616 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3617 client.add_entity_request_handler(
3618 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3619 );
3620 client.add_entity_request_handler(
3621 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3622 );
3623 client.add_entity_request_handler(
3624 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3625 );
3626 }
3627
3628 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3629 match &self.mode {
3630 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3631 _ => None,
3632 }
3633 }
3634
3635 pub fn as_local(&self) -> Option<&LocalLspStore> {
3636 match &self.mode {
3637 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3638 _ => None,
3639 }
3640 }
3641
3642 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3643 match &mut self.mode {
3644 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3645 _ => None,
3646 }
3647 }
3648
3649 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3650 match &self.mode {
3651 LspStoreMode::Remote(RemoteLspStore {
3652 upstream_client: Some(upstream_client),
3653 upstream_project_id,
3654 ..
3655 }) => Some((upstream_client.clone(), *upstream_project_id)),
3656
3657 LspStoreMode::Remote(RemoteLspStore {
3658 upstream_client: None,
3659 ..
3660 }) => None,
3661 LspStoreMode::Local(_) => None,
3662 }
3663 }
3664
3665 pub fn new_local(
3666 buffer_store: Entity<BufferStore>,
3667 worktree_store: Entity<WorktreeStore>,
3668 prettier_store: Entity<PrettierStore>,
3669 toolchain_store: Entity<LocalToolchainStore>,
3670 environment: Entity<ProjectEnvironment>,
3671 manifest_tree: Entity<ManifestTree>,
3672 languages: Arc<LanguageRegistry>,
3673 http_client: Arc<dyn HttpClient>,
3674 fs: Arc<dyn Fs>,
3675 cx: &mut Context<Self>,
3676 ) -> Self {
3677 let yarn = YarnPathStore::new(fs.clone(), cx);
3678 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3679 .detach();
3680 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3681 .detach();
3682 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3683 .detach();
3684 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3685 .detach();
3686 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3687 .detach();
3688 subscribe_to_binary_statuses(&languages, cx).detach();
3689
3690 let _maintain_workspace_config = {
3691 let (sender, receiver) = watch::channel();
3692 (Self::maintain_workspace_config(receiver, cx), sender)
3693 };
3694
3695 Self {
3696 mode: LspStoreMode::Local(LocalLspStore {
3697 weak: cx.weak_entity(),
3698 worktree_store: worktree_store.clone(),
3699
3700 supplementary_language_servers: Default::default(),
3701 languages: languages.clone(),
3702 language_server_ids: Default::default(),
3703 language_servers: Default::default(),
3704 last_workspace_edits_by_language_server: Default::default(),
3705 language_server_watched_paths: Default::default(),
3706 language_server_paths_watched_for_rename: Default::default(),
3707 language_server_watcher_registrations: Default::default(),
3708 buffers_being_formatted: Default::default(),
3709 buffer_snapshots: Default::default(),
3710 prettier_store,
3711 environment,
3712 http_client,
3713 fs,
3714 yarn,
3715 next_diagnostic_group_id: Default::default(),
3716 diagnostics: Default::default(),
3717 _subscription: cx.on_app_quit(|this, cx| {
3718 this.as_local_mut()
3719 .unwrap()
3720 .shutdown_language_servers_on_quit(cx)
3721 }),
3722 lsp_tree: LanguageServerTree::new(
3723 manifest_tree,
3724 languages.clone(),
3725 toolchain_store.clone(),
3726 ),
3727 toolchain_store,
3728 registered_buffers: HashMap::default(),
3729 buffers_opened_in_servers: HashMap::default(),
3730 buffer_pull_diagnostics_result_ids: HashMap::default(),
3731 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3732 .manifest_file_names(),
3733 }),
3734 last_formatting_failure: None,
3735 downstream_client: None,
3736 buffer_store,
3737 worktree_store,
3738 languages: languages.clone(),
3739 language_server_statuses: Default::default(),
3740 nonce: StdRng::from_os_rng().random(),
3741 diagnostic_summaries: HashMap::default(),
3742 lsp_server_capabilities: HashMap::default(),
3743 lsp_document_colors: HashMap::default(),
3744 lsp_code_lens: HashMap::default(),
3745 running_lsp_requests: HashMap::default(),
3746 active_entry: None,
3747 _maintain_workspace_config,
3748 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3749 }
3750 }
3751
3752 fn send_lsp_proto_request<R: LspCommand>(
3753 &self,
3754 buffer: Entity<Buffer>,
3755 client: AnyProtoClient,
3756 upstream_project_id: u64,
3757 request: R,
3758 cx: &mut Context<LspStore>,
3759 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3760 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3761 return Task::ready(Ok(R::Response::default()));
3762 }
3763 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3764 cx.spawn(async move |this, cx| {
3765 let response = client.request(message).await?;
3766 let this = this.upgrade().context("project dropped")?;
3767 request
3768 .response_from_proto(response, this, buffer, cx.clone())
3769 .await
3770 })
3771 }
3772
3773 pub(super) fn new_remote(
3774 buffer_store: Entity<BufferStore>,
3775 worktree_store: Entity<WorktreeStore>,
3776 languages: Arc<LanguageRegistry>,
3777 upstream_client: AnyProtoClient,
3778 project_id: u64,
3779 cx: &mut Context<Self>,
3780 ) -> Self {
3781 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3782 .detach();
3783 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3784 .detach();
3785 subscribe_to_binary_statuses(&languages, cx).detach();
3786 let _maintain_workspace_config = {
3787 let (sender, receiver) = watch::channel();
3788 (Self::maintain_workspace_config(receiver, cx), sender)
3789 };
3790 Self {
3791 mode: LspStoreMode::Remote(RemoteLspStore {
3792 upstream_client: Some(upstream_client),
3793 upstream_project_id: project_id,
3794 }),
3795 downstream_client: None,
3796 last_formatting_failure: None,
3797 buffer_store,
3798 worktree_store,
3799 languages: languages.clone(),
3800 language_server_statuses: Default::default(),
3801 nonce: StdRng::from_os_rng().random(),
3802 diagnostic_summaries: HashMap::default(),
3803 lsp_server_capabilities: HashMap::default(),
3804 lsp_document_colors: HashMap::default(),
3805 lsp_code_lens: HashMap::default(),
3806 running_lsp_requests: HashMap::default(),
3807 active_entry: None,
3808
3809 _maintain_workspace_config,
3810 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3811 }
3812 }
3813
3814 fn on_buffer_store_event(
3815 &mut self,
3816 _: Entity<BufferStore>,
3817 event: &BufferStoreEvent,
3818 cx: &mut Context<Self>,
3819 ) {
3820 match event {
3821 BufferStoreEvent::BufferAdded(buffer) => {
3822 self.on_buffer_added(buffer, cx).log_err();
3823 }
3824 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3825 let buffer_id = buffer.read(cx).remote_id();
3826 if let Some(local) = self.as_local_mut()
3827 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3828 {
3829 local.reset_buffer(buffer, old_file, cx);
3830
3831 if local.registered_buffers.contains_key(&buffer_id) {
3832 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3833 }
3834 }
3835
3836 self.detect_language_for_buffer(buffer, cx);
3837 if let Some(local) = self.as_local_mut() {
3838 local.initialize_buffer(buffer, cx);
3839 if local.registered_buffers.contains_key(&buffer_id) {
3840 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3841 }
3842 }
3843 }
3844 _ => {}
3845 }
3846 }
3847
3848 fn on_worktree_store_event(
3849 &mut self,
3850 _: Entity<WorktreeStore>,
3851 event: &WorktreeStoreEvent,
3852 cx: &mut Context<Self>,
3853 ) {
3854 match event {
3855 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3856 if !worktree.read(cx).is_local() {
3857 return;
3858 }
3859 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3860 worktree::Event::UpdatedEntries(changes) => {
3861 this.update_local_worktree_language_servers(&worktree, changes, cx);
3862 }
3863 worktree::Event::UpdatedGitRepositories(_)
3864 | worktree::Event::DeletedEntry(_) => {}
3865 })
3866 .detach()
3867 }
3868 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3869 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3870 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3871 }
3872 WorktreeStoreEvent::WorktreeReleased(..)
3873 | WorktreeStoreEvent::WorktreeOrderChanged
3874 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3875 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3876 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3877 }
3878 }
3879
3880 fn on_prettier_store_event(
3881 &mut self,
3882 _: Entity<PrettierStore>,
3883 event: &PrettierStoreEvent,
3884 cx: &mut Context<Self>,
3885 ) {
3886 match event {
3887 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3888 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3889 }
3890 PrettierStoreEvent::LanguageServerAdded {
3891 new_server_id,
3892 name,
3893 prettier_server,
3894 } => {
3895 self.register_supplementary_language_server(
3896 *new_server_id,
3897 name.clone(),
3898 prettier_server.clone(),
3899 cx,
3900 );
3901 }
3902 }
3903 }
3904
3905 fn on_toolchain_store_event(
3906 &mut self,
3907 _: Entity<LocalToolchainStore>,
3908 event: &ToolchainStoreEvent,
3909 _: &mut Context<Self>,
3910 ) {
3911 if let ToolchainStoreEvent::ToolchainActivated = event {
3912 self.request_workspace_config_refresh()
3913 }
3914 }
3915
3916 fn request_workspace_config_refresh(&mut self) {
3917 *self._maintain_workspace_config.1.borrow_mut() = ();
3918 }
3919
3920 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
3921 self.as_local().map(|local| local.prettier_store.clone())
3922 }
3923
3924 fn on_buffer_event(
3925 &mut self,
3926 buffer: Entity<Buffer>,
3927 event: &language::BufferEvent,
3928 cx: &mut Context<Self>,
3929 ) {
3930 match event {
3931 language::BufferEvent::Edited => {
3932 self.on_buffer_edited(buffer, cx);
3933 }
3934
3935 language::BufferEvent::Saved => {
3936 self.on_buffer_saved(buffer, cx);
3937 }
3938
3939 _ => {}
3940 }
3941 }
3942
3943 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
3944 buffer
3945 .read(cx)
3946 .set_language_registry(self.languages.clone());
3947
3948 cx.subscribe(buffer, |this, buffer, event, cx| {
3949 this.on_buffer_event(buffer, event, cx);
3950 })
3951 .detach();
3952
3953 self.detect_language_for_buffer(buffer, cx);
3954 if let Some(local) = self.as_local_mut() {
3955 local.initialize_buffer(buffer, cx);
3956 }
3957
3958 Ok(())
3959 }
3960
3961 pub(crate) fn register_buffer_with_language_servers(
3962 &mut self,
3963 buffer: &Entity<Buffer>,
3964 only_register_servers: HashSet<LanguageServerSelector>,
3965 ignore_refcounts: bool,
3966 cx: &mut Context<Self>,
3967 ) -> OpenLspBufferHandle {
3968 let buffer_id = buffer.read(cx).remote_id();
3969 let handle = cx.new(|_| buffer.clone());
3970 if let Some(local) = self.as_local_mut() {
3971 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
3972 if !ignore_refcounts {
3973 *refcount += 1;
3974 }
3975
3976 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
3977 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
3978 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
3979 // servers in practice (we don't support non-file URI schemes in our LSP impl).
3980 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
3981 return handle;
3982 };
3983 if !file.is_local() {
3984 return handle;
3985 }
3986
3987 if ignore_refcounts || *refcount == 1 {
3988 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
3989 }
3990 if !ignore_refcounts {
3991 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
3992 let refcount = {
3993 let local = lsp_store.as_local_mut().unwrap();
3994 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
3995 debug_panic!("bad refcounting");
3996 return;
3997 };
3998
3999 *refcount -= 1;
4000 *refcount
4001 };
4002 if refcount == 0 {
4003 lsp_store.lsp_document_colors.remove(&buffer_id);
4004 lsp_store.lsp_code_lens.remove(&buffer_id);
4005 let local = lsp_store.as_local_mut().unwrap();
4006 local.registered_buffers.remove(&buffer_id);
4007 local.buffers_opened_in_servers.remove(&buffer_id);
4008 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4009 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4010 }
4011 }
4012 })
4013 .detach();
4014 }
4015 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4016 let buffer_id = buffer.read(cx).remote_id().to_proto();
4017 cx.background_spawn(async move {
4018 upstream_client
4019 .request(proto::RegisterBufferWithLanguageServers {
4020 project_id: upstream_project_id,
4021 buffer_id,
4022 only_servers: only_register_servers
4023 .into_iter()
4024 .map(|selector| {
4025 let selector = match selector {
4026 LanguageServerSelector::Id(language_server_id) => {
4027 proto::language_server_selector::Selector::ServerId(
4028 language_server_id.to_proto(),
4029 )
4030 }
4031 LanguageServerSelector::Name(language_server_name) => {
4032 proto::language_server_selector::Selector::Name(
4033 language_server_name.to_string(),
4034 )
4035 }
4036 };
4037 proto::LanguageServerSelector {
4038 selector: Some(selector),
4039 }
4040 })
4041 .collect(),
4042 })
4043 .await
4044 })
4045 .detach();
4046 } else {
4047 panic!("oops!");
4048 }
4049 handle
4050 }
4051
4052 fn maintain_buffer_languages(
4053 languages: Arc<LanguageRegistry>,
4054 cx: &mut Context<Self>,
4055 ) -> Task<()> {
4056 let mut subscription = languages.subscribe();
4057 let mut prev_reload_count = languages.reload_count();
4058 cx.spawn(async move |this, cx| {
4059 while let Some(()) = subscription.next().await {
4060 if let Some(this) = this.upgrade() {
4061 // If the language registry has been reloaded, then remove and
4062 // re-assign the languages on all open buffers.
4063 let reload_count = languages.reload_count();
4064 if reload_count > prev_reload_count {
4065 prev_reload_count = reload_count;
4066 this.update(cx, |this, cx| {
4067 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4068 for buffer in buffer_store.buffers() {
4069 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4070 {
4071 buffer
4072 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4073 if let Some(local) = this.as_local_mut() {
4074 local.reset_buffer(&buffer, &f, cx);
4075
4076 if local
4077 .registered_buffers
4078 .contains_key(&buffer.read(cx).remote_id())
4079 && let Some(file_url) =
4080 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4081 {
4082 local.unregister_buffer_from_language_servers(
4083 &buffer, &file_url, cx,
4084 );
4085 }
4086 }
4087 }
4088 }
4089 });
4090 })
4091 .ok();
4092 }
4093
4094 this.update(cx, |this, cx| {
4095 let mut plain_text_buffers = Vec::new();
4096 let mut buffers_with_unknown_injections = Vec::new();
4097 for handle in this.buffer_store.read(cx).buffers() {
4098 let buffer = handle.read(cx);
4099 if buffer.language().is_none()
4100 || buffer.language() == Some(&*language::PLAIN_TEXT)
4101 {
4102 plain_text_buffers.push(handle);
4103 } else if buffer.contains_unknown_injections() {
4104 buffers_with_unknown_injections.push(handle);
4105 }
4106 }
4107
4108 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4109 // and reused later in the invisible worktrees.
4110 plain_text_buffers.sort_by_key(|buffer| {
4111 Reverse(
4112 File::from_dyn(buffer.read(cx).file())
4113 .map(|file| file.worktree.read(cx).is_visible()),
4114 )
4115 });
4116
4117 for buffer in plain_text_buffers {
4118 this.detect_language_for_buffer(&buffer, cx);
4119 if let Some(local) = this.as_local_mut() {
4120 local.initialize_buffer(&buffer, cx);
4121 if local
4122 .registered_buffers
4123 .contains_key(&buffer.read(cx).remote_id())
4124 {
4125 local.register_buffer_with_language_servers(
4126 &buffer,
4127 HashSet::default(),
4128 cx,
4129 );
4130 }
4131 }
4132 }
4133
4134 for buffer in buffers_with_unknown_injections {
4135 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4136 }
4137 })
4138 .ok();
4139 }
4140 }
4141 })
4142 }
4143
4144 fn detect_language_for_buffer(
4145 &mut self,
4146 buffer_handle: &Entity<Buffer>,
4147 cx: &mut Context<Self>,
4148 ) -> Option<language::AvailableLanguage> {
4149 // If the buffer has a language, set it and start the language server if we haven't already.
4150 let buffer = buffer_handle.read(cx);
4151 let file = buffer.file()?;
4152
4153 let content = buffer.as_rope();
4154 let available_language = self.languages.language_for_file(file, Some(content), cx);
4155 if let Some(available_language) = &available_language {
4156 if let Some(Ok(Ok(new_language))) = self
4157 .languages
4158 .load_language(available_language)
4159 .now_or_never()
4160 {
4161 self.set_language_for_buffer(buffer_handle, new_language, cx);
4162 }
4163 } else {
4164 cx.emit(LspStoreEvent::LanguageDetected {
4165 buffer: buffer_handle.clone(),
4166 new_language: None,
4167 });
4168 }
4169
4170 available_language
4171 }
4172
4173 pub(crate) fn set_language_for_buffer(
4174 &mut self,
4175 buffer_entity: &Entity<Buffer>,
4176 new_language: Arc<Language>,
4177 cx: &mut Context<Self>,
4178 ) {
4179 let buffer = buffer_entity.read(cx);
4180 let buffer_file = buffer.file().cloned();
4181 let buffer_id = buffer.remote_id();
4182 if let Some(local_store) = self.as_local_mut()
4183 && local_store.registered_buffers.contains_key(&buffer_id)
4184 && let Some(abs_path) =
4185 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4186 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4187 {
4188 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4189 }
4190 buffer_entity.update(cx, |buffer, cx| {
4191 if buffer
4192 .language()
4193 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4194 {
4195 buffer.set_language(Some(new_language.clone()), cx);
4196 }
4197 });
4198
4199 let settings =
4200 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4201 let buffer_file = File::from_dyn(buffer_file.as_ref());
4202
4203 let worktree_id = if let Some(file) = buffer_file {
4204 let worktree = file.worktree.clone();
4205
4206 if let Some(local) = self.as_local_mut()
4207 && local.registered_buffers.contains_key(&buffer_id)
4208 {
4209 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4210 }
4211 Some(worktree.read(cx).id())
4212 } else {
4213 None
4214 };
4215
4216 if settings.prettier.allowed
4217 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4218 {
4219 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4220 if let Some(prettier_store) = prettier_store {
4221 prettier_store.update(cx, |prettier_store, cx| {
4222 prettier_store.install_default_prettier(
4223 worktree_id,
4224 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4225 cx,
4226 )
4227 })
4228 }
4229 }
4230
4231 cx.emit(LspStoreEvent::LanguageDetected {
4232 buffer: buffer_entity.clone(),
4233 new_language: Some(new_language),
4234 })
4235 }
4236
4237 pub fn buffer_store(&self) -> Entity<BufferStore> {
4238 self.buffer_store.clone()
4239 }
4240
4241 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4242 self.active_entry = active_entry;
4243 }
4244
4245 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4246 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4247 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4248 {
4249 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4250 summaries
4251 .iter()
4252 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4253 });
4254 if let Some(summary) = summaries.next() {
4255 client
4256 .send(proto::UpdateDiagnosticSummary {
4257 project_id: downstream_project_id,
4258 worktree_id: worktree.id().to_proto(),
4259 summary: Some(summary),
4260 more_summaries: summaries.collect(),
4261 })
4262 .log_err();
4263 }
4264 }
4265 }
4266
4267 fn is_capable_for_proto_request<R>(
4268 &self,
4269 buffer: &Entity<Buffer>,
4270 request: &R,
4271 cx: &Context<Self>,
4272 ) -> bool
4273 where
4274 R: LspCommand,
4275 {
4276 self.check_if_capable_for_proto_request(
4277 buffer,
4278 |capabilities| {
4279 request.check_capabilities(AdapterServerCapabilities {
4280 server_capabilities: capabilities.clone(),
4281 code_action_kinds: None,
4282 })
4283 },
4284 cx,
4285 )
4286 }
4287
4288 fn check_if_capable_for_proto_request<F>(
4289 &self,
4290 buffer: &Entity<Buffer>,
4291 check: F,
4292 cx: &Context<Self>,
4293 ) -> bool
4294 where
4295 F: Fn(&lsp::ServerCapabilities) -> bool,
4296 {
4297 let Some(language) = buffer.read(cx).language().cloned() else {
4298 return false;
4299 };
4300 let relevant_language_servers = self
4301 .languages
4302 .lsp_adapters(&language.name())
4303 .into_iter()
4304 .map(|lsp_adapter| lsp_adapter.name())
4305 .collect::<HashSet<_>>();
4306 self.language_server_statuses
4307 .iter()
4308 .filter_map(|(server_id, server_status)| {
4309 relevant_language_servers
4310 .contains(&server_status.name)
4311 .then_some(server_id)
4312 })
4313 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4314 .any(check)
4315 }
4316
4317 pub fn request_lsp<R>(
4318 &mut self,
4319 buffer: Entity<Buffer>,
4320 server: LanguageServerToQuery,
4321 request: R,
4322 cx: &mut Context<Self>,
4323 ) -> Task<Result<R::Response>>
4324 where
4325 R: LspCommand,
4326 <R::LspRequest as lsp::request::Request>::Result: Send,
4327 <R::LspRequest as lsp::request::Request>::Params: Send,
4328 {
4329 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4330 return self.send_lsp_proto_request(
4331 buffer,
4332 upstream_client,
4333 upstream_project_id,
4334 request,
4335 cx,
4336 );
4337 }
4338
4339 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4340 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4341 local
4342 .language_servers_for_buffer(buffer, cx)
4343 .find(|(_, server)| {
4344 request.check_capabilities(server.adapter_server_capabilities())
4345 })
4346 .map(|(_, server)| server.clone())
4347 }),
4348 LanguageServerToQuery::Other(id) => self
4349 .language_server_for_local_buffer(buffer, id, cx)
4350 .and_then(|(_, server)| {
4351 request
4352 .check_capabilities(server.adapter_server_capabilities())
4353 .then(|| Arc::clone(server))
4354 }),
4355 }) else {
4356 return Task::ready(Ok(Default::default()));
4357 };
4358
4359 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4360
4361 let Some(file) = file else {
4362 return Task::ready(Ok(Default::default()));
4363 };
4364
4365 let lsp_params = match request.to_lsp_params_or_response(
4366 &file.abs_path(cx),
4367 buffer.read(cx),
4368 &language_server,
4369 cx,
4370 ) {
4371 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4372 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4373
4374 Err(err) => {
4375 let message = format!(
4376 "{} via {} failed: {}",
4377 request.display_name(),
4378 language_server.name(),
4379 err
4380 );
4381 log::warn!("{message}");
4382 return Task::ready(Err(anyhow!(message)));
4383 }
4384 };
4385
4386 let status = request.status();
4387 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4388 return Task::ready(Ok(Default::default()));
4389 }
4390 cx.spawn(async move |this, cx| {
4391 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4392
4393 let id = lsp_request.id();
4394 let _cleanup = if status.is_some() {
4395 cx.update(|cx| {
4396 this.update(cx, |this, cx| {
4397 this.on_lsp_work_start(
4398 language_server.server_id(),
4399 id.to_string(),
4400 LanguageServerProgress {
4401 is_disk_based_diagnostics_progress: false,
4402 is_cancellable: false,
4403 title: None,
4404 message: status.clone(),
4405 percentage: None,
4406 last_update_at: cx.background_executor().now(),
4407 },
4408 cx,
4409 );
4410 })
4411 })
4412 .log_err();
4413
4414 Some(defer(|| {
4415 cx.update(|cx| {
4416 this.update(cx, |this, cx| {
4417 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4418 })
4419 })
4420 .log_err();
4421 }))
4422 } else {
4423 None
4424 };
4425
4426 let result = lsp_request.await.into_response();
4427
4428 let response = result.map_err(|err| {
4429 let message = format!(
4430 "{} via {} failed: {}",
4431 request.display_name(),
4432 language_server.name(),
4433 err
4434 );
4435 log::warn!("{message}");
4436 anyhow::anyhow!(message)
4437 })?;
4438
4439 request
4440 .response_from_lsp(
4441 response,
4442 this.upgrade().context("no app context")?,
4443 buffer,
4444 language_server.server_id(),
4445 cx.clone(),
4446 )
4447 .await
4448 })
4449 }
4450
4451 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4452 let mut language_formatters_to_check = Vec::new();
4453 for buffer in self.buffer_store.read(cx).buffers() {
4454 let buffer = buffer.read(cx);
4455 let buffer_file = File::from_dyn(buffer.file());
4456 let buffer_language = buffer.language();
4457 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4458 if buffer_language.is_some() {
4459 language_formatters_to_check.push((
4460 buffer_file.map(|f| f.worktree_id(cx)),
4461 settings.into_owned(),
4462 ));
4463 }
4464 }
4465
4466 self.request_workspace_config_refresh();
4467
4468 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4469 prettier_store.update(cx, |prettier_store, cx| {
4470 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4471 })
4472 }
4473
4474 cx.notify();
4475 }
4476
4477 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4478 let buffer_store = self.buffer_store.clone();
4479 let Some(local) = self.as_local_mut() else {
4480 return;
4481 };
4482 let mut adapters = BTreeMap::default();
4483 let get_adapter = {
4484 let languages = local.languages.clone();
4485 let environment = local.environment.clone();
4486 let weak = local.weak.clone();
4487 let worktree_store = local.worktree_store.clone();
4488 let http_client = local.http_client.clone();
4489 let fs = local.fs.clone();
4490 move |worktree_id, cx: &mut App| {
4491 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4492 Some(LocalLspAdapterDelegate::new(
4493 languages.clone(),
4494 &environment,
4495 weak.clone(),
4496 &worktree,
4497 http_client.clone(),
4498 fs.clone(),
4499 cx,
4500 ))
4501 }
4502 };
4503
4504 let mut messages_to_report = Vec::new();
4505 let (new_tree, to_stop) = {
4506 let mut rebase = local.lsp_tree.rebase();
4507 let buffers = buffer_store
4508 .read(cx)
4509 .buffers()
4510 .filter_map(|buffer| {
4511 let raw_buffer = buffer.read(cx);
4512 if !local
4513 .registered_buffers
4514 .contains_key(&raw_buffer.remote_id())
4515 {
4516 return None;
4517 }
4518 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4519 let language = raw_buffer.language().cloned()?;
4520 Some((file, language, raw_buffer.remote_id()))
4521 })
4522 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4523 for (file, language, buffer_id) in buffers {
4524 let worktree_id = file.worktree_id(cx);
4525 let Some(worktree) = local
4526 .worktree_store
4527 .read(cx)
4528 .worktree_for_id(worktree_id, cx)
4529 else {
4530 continue;
4531 };
4532
4533 if let Some((_, apply)) = local.reuse_existing_language_server(
4534 rebase.server_tree(),
4535 &worktree,
4536 &language.name(),
4537 cx,
4538 ) {
4539 (apply)(rebase.server_tree());
4540 } else if let Some(lsp_delegate) = adapters
4541 .entry(worktree_id)
4542 .or_insert_with(|| get_adapter(worktree_id, cx))
4543 .clone()
4544 {
4545 let delegate =
4546 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4547 let path = file
4548 .path()
4549 .parent()
4550 .map(Arc::from)
4551 .unwrap_or_else(|| file.path().clone());
4552 let worktree_path = ProjectPath { worktree_id, path };
4553 let abs_path = file.abs_path(cx);
4554 let nodes = rebase
4555 .walk(
4556 worktree_path,
4557 language.name(),
4558 language.manifest(),
4559 delegate.clone(),
4560 cx,
4561 )
4562 .collect::<Vec<_>>();
4563 for node in nodes {
4564 let server_id = node.server_id_or_init(|disposition| {
4565 let path = &disposition.path;
4566 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4567 let key = LanguageServerSeed {
4568 worktree_id,
4569 name: disposition.server_name.clone(),
4570 settings: disposition.settings.clone(),
4571 toolchain: local.toolchain_store.read(cx).active_toolchain(
4572 path.worktree_id,
4573 &path.path,
4574 language.name(),
4575 ),
4576 };
4577 local.language_server_ids.remove(&key);
4578
4579 let server_id = local.get_or_insert_language_server(
4580 &worktree,
4581 lsp_delegate.clone(),
4582 disposition,
4583 &language.name(),
4584 cx,
4585 );
4586 if let Some(state) = local.language_servers.get(&server_id)
4587 && let Ok(uri) = uri
4588 {
4589 state.add_workspace_folder(uri);
4590 };
4591 server_id
4592 });
4593
4594 if let Some(language_server_id) = server_id {
4595 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4596 language_server_id,
4597 name: node.name(),
4598 message:
4599 proto::update_language_server::Variant::RegisteredForBuffer(
4600 proto::RegisteredForBuffer {
4601 buffer_abs_path: abs_path
4602 .to_string_lossy()
4603 .into_owned(),
4604 buffer_id: buffer_id.to_proto(),
4605 },
4606 ),
4607 });
4608 }
4609 }
4610 } else {
4611 continue;
4612 }
4613 }
4614 rebase.finish()
4615 };
4616 for message in messages_to_report {
4617 cx.emit(message);
4618 }
4619 local.lsp_tree = new_tree;
4620 for (id, _) in to_stop {
4621 self.stop_local_language_server(id, cx).detach();
4622 }
4623 }
4624
4625 pub fn apply_code_action(
4626 &self,
4627 buffer_handle: Entity<Buffer>,
4628 mut action: CodeAction,
4629 push_to_history: bool,
4630 cx: &mut Context<Self>,
4631 ) -> Task<Result<ProjectTransaction>> {
4632 if let Some((upstream_client, project_id)) = self.upstream_client() {
4633 let request = proto::ApplyCodeAction {
4634 project_id,
4635 buffer_id: buffer_handle.read(cx).remote_id().into(),
4636 action: Some(Self::serialize_code_action(&action)),
4637 };
4638 let buffer_store = self.buffer_store();
4639 cx.spawn(async move |_, cx| {
4640 let response = upstream_client
4641 .request(request)
4642 .await?
4643 .transaction
4644 .context("missing transaction")?;
4645
4646 buffer_store
4647 .update(cx, |buffer_store, cx| {
4648 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4649 })?
4650 .await
4651 })
4652 } else if self.mode.is_local() {
4653 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4654 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4655 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4656 }) else {
4657 return Task::ready(Ok(ProjectTransaction::default()));
4658 };
4659 cx.spawn(async move |this, cx| {
4660 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4661 .await
4662 .context("resolving a code action")?;
4663 if let Some(edit) = action.lsp_action.edit()
4664 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4665 return LocalLspStore::deserialize_workspace_edit(
4666 this.upgrade().context("no app present")?,
4667 edit.clone(),
4668 push_to_history,
4669
4670 lang_server.clone(),
4671 cx,
4672 )
4673 .await;
4674 }
4675
4676 if let Some(command) = action.lsp_action.command() {
4677 let server_capabilities = lang_server.capabilities();
4678 let available_commands = server_capabilities
4679 .execute_command_provider
4680 .as_ref()
4681 .map(|options| options.commands.as_slice())
4682 .unwrap_or_default();
4683 if available_commands.contains(&command.command) {
4684 this.update(cx, |this, _| {
4685 this.as_local_mut()
4686 .unwrap()
4687 .last_workspace_edits_by_language_server
4688 .remove(&lang_server.server_id());
4689 })?;
4690
4691 let _result = lang_server
4692 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4693 command: command.command.clone(),
4694 arguments: command.arguments.clone().unwrap_or_default(),
4695 ..lsp::ExecuteCommandParams::default()
4696 })
4697 .await.into_response()
4698 .context("execute command")?;
4699
4700 return this.update(cx, |this, _| {
4701 this.as_local_mut()
4702 .unwrap()
4703 .last_workspace_edits_by_language_server
4704 .remove(&lang_server.server_id())
4705 .unwrap_or_default()
4706 });
4707 } else {
4708 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4709 }
4710 }
4711
4712 Ok(ProjectTransaction::default())
4713 })
4714 } else {
4715 Task::ready(Err(anyhow!("no upstream client and not local")))
4716 }
4717 }
4718
4719 pub fn apply_code_action_kind(
4720 &mut self,
4721 buffers: HashSet<Entity<Buffer>>,
4722 kind: CodeActionKind,
4723 push_to_history: bool,
4724 cx: &mut Context<Self>,
4725 ) -> Task<anyhow::Result<ProjectTransaction>> {
4726 if self.as_local().is_some() {
4727 cx.spawn(async move |lsp_store, cx| {
4728 let buffers = buffers.into_iter().collect::<Vec<_>>();
4729 let result = LocalLspStore::execute_code_action_kind_locally(
4730 lsp_store.clone(),
4731 buffers,
4732 kind,
4733 push_to_history,
4734 cx,
4735 )
4736 .await;
4737 lsp_store.update(cx, |lsp_store, _| {
4738 lsp_store.update_last_formatting_failure(&result);
4739 })?;
4740 result
4741 })
4742 } else if let Some((client, project_id)) = self.upstream_client() {
4743 let buffer_store = self.buffer_store();
4744 cx.spawn(async move |lsp_store, cx| {
4745 let result = client
4746 .request(proto::ApplyCodeActionKind {
4747 project_id,
4748 kind: kind.as_str().to_owned(),
4749 buffer_ids: buffers
4750 .iter()
4751 .map(|buffer| {
4752 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4753 })
4754 .collect::<Result<_>>()?,
4755 })
4756 .await
4757 .and_then(|result| result.transaction.context("missing transaction"));
4758 lsp_store.update(cx, |lsp_store, _| {
4759 lsp_store.update_last_formatting_failure(&result);
4760 })?;
4761
4762 let transaction_response = result?;
4763 buffer_store
4764 .update(cx, |buffer_store, cx| {
4765 buffer_store.deserialize_project_transaction(
4766 transaction_response,
4767 push_to_history,
4768 cx,
4769 )
4770 })?
4771 .await
4772 })
4773 } else {
4774 Task::ready(Ok(ProjectTransaction::default()))
4775 }
4776 }
4777
4778 pub fn resolve_inlay_hint(
4779 &self,
4780 mut hint: InlayHint,
4781 buffer: Entity<Buffer>,
4782 server_id: LanguageServerId,
4783 cx: &mut Context<Self>,
4784 ) -> Task<anyhow::Result<InlayHint>> {
4785 if let Some((upstream_client, project_id)) = self.upstream_client() {
4786 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4787 {
4788 hint.resolve_state = ResolveState::Resolved;
4789 return Task::ready(Ok(hint));
4790 }
4791 let request = proto::ResolveInlayHint {
4792 project_id,
4793 buffer_id: buffer.read(cx).remote_id().into(),
4794 language_server_id: server_id.0 as u64,
4795 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4796 };
4797 cx.background_spawn(async move {
4798 let response = upstream_client
4799 .request(request)
4800 .await
4801 .context("inlay hints proto request")?;
4802 match response.hint {
4803 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4804 .context("inlay hints proto resolve response conversion"),
4805 None => Ok(hint),
4806 }
4807 })
4808 } else {
4809 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4810 self.language_server_for_local_buffer(buffer, server_id, cx)
4811 .map(|(_, server)| server.clone())
4812 }) else {
4813 return Task::ready(Ok(hint));
4814 };
4815 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4816 return Task::ready(Ok(hint));
4817 }
4818 let buffer_snapshot = buffer.read(cx).snapshot();
4819 cx.spawn(async move |_, cx| {
4820 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4821 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4822 );
4823 let resolved_hint = resolve_task
4824 .await
4825 .into_response()
4826 .context("inlay hint resolve LSP request")?;
4827 let resolved_hint = InlayHints::lsp_to_project_hint(
4828 resolved_hint,
4829 &buffer,
4830 server_id,
4831 ResolveState::Resolved,
4832 false,
4833 cx,
4834 )
4835 .await?;
4836 Ok(resolved_hint)
4837 })
4838 }
4839 }
4840
4841 pub fn resolve_color_presentation(
4842 &mut self,
4843 mut color: DocumentColor,
4844 buffer: Entity<Buffer>,
4845 server_id: LanguageServerId,
4846 cx: &mut Context<Self>,
4847 ) -> Task<Result<DocumentColor>> {
4848 if color.resolved {
4849 return Task::ready(Ok(color));
4850 }
4851
4852 if let Some((upstream_client, project_id)) = self.upstream_client() {
4853 let start = color.lsp_range.start;
4854 let end = color.lsp_range.end;
4855 let request = proto::GetColorPresentation {
4856 project_id,
4857 server_id: server_id.to_proto(),
4858 buffer_id: buffer.read(cx).remote_id().into(),
4859 color: Some(proto::ColorInformation {
4860 red: color.color.red,
4861 green: color.color.green,
4862 blue: color.color.blue,
4863 alpha: color.color.alpha,
4864 lsp_range_start: Some(proto::PointUtf16 {
4865 row: start.line,
4866 column: start.character,
4867 }),
4868 lsp_range_end: Some(proto::PointUtf16 {
4869 row: end.line,
4870 column: end.character,
4871 }),
4872 }),
4873 };
4874 cx.background_spawn(async move {
4875 let response = upstream_client
4876 .request(request)
4877 .await
4878 .context("color presentation proto request")?;
4879 color.resolved = true;
4880 color.color_presentations = response
4881 .presentations
4882 .into_iter()
4883 .map(|presentation| ColorPresentation {
4884 label: SharedString::from(presentation.label),
4885 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
4886 additional_text_edits: presentation
4887 .additional_text_edits
4888 .into_iter()
4889 .filter_map(deserialize_lsp_edit)
4890 .collect(),
4891 })
4892 .collect();
4893 Ok(color)
4894 })
4895 } else {
4896 let path = match buffer
4897 .update(cx, |buffer, cx| {
4898 Some(File::from_dyn(buffer.file())?.abs_path(cx))
4899 })
4900 .context("buffer with the missing path")
4901 {
4902 Ok(path) => path,
4903 Err(e) => return Task::ready(Err(e)),
4904 };
4905 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4906 self.language_server_for_local_buffer(buffer, server_id, cx)
4907 .map(|(_, server)| server.clone())
4908 }) else {
4909 return Task::ready(Ok(color));
4910 };
4911 cx.background_spawn(async move {
4912 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
4913 lsp::ColorPresentationParams {
4914 text_document: make_text_document_identifier(&path)?,
4915 color: color.color,
4916 range: color.lsp_range,
4917 work_done_progress_params: Default::default(),
4918 partial_result_params: Default::default(),
4919 },
4920 );
4921 color.color_presentations = resolve_task
4922 .await
4923 .into_response()
4924 .context("color presentation resolve LSP request")?
4925 .into_iter()
4926 .map(|presentation| ColorPresentation {
4927 label: SharedString::from(presentation.label),
4928 text_edit: presentation.text_edit,
4929 additional_text_edits: presentation
4930 .additional_text_edits
4931 .unwrap_or_default(),
4932 })
4933 .collect();
4934 color.resolved = true;
4935 Ok(color)
4936 })
4937 }
4938 }
4939
4940 pub(crate) fn linked_edits(
4941 &mut self,
4942 buffer: &Entity<Buffer>,
4943 position: Anchor,
4944 cx: &mut Context<Self>,
4945 ) -> Task<Result<Vec<Range<Anchor>>>> {
4946 let snapshot = buffer.read(cx).snapshot();
4947 let scope = snapshot.language_scope_at(position);
4948 let Some(server_id) = self
4949 .as_local()
4950 .and_then(|local| {
4951 buffer.update(cx, |buffer, cx| {
4952 local
4953 .language_servers_for_buffer(buffer, cx)
4954 .filter(|(_, server)| {
4955 LinkedEditingRange::check_server_capabilities(server.capabilities())
4956 })
4957 .filter(|(adapter, _)| {
4958 scope
4959 .as_ref()
4960 .map(|scope| scope.language_allowed(&adapter.name))
4961 .unwrap_or(true)
4962 })
4963 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
4964 .next()
4965 })
4966 })
4967 .or_else(|| {
4968 self.upstream_client()
4969 .is_some()
4970 .then_some(LanguageServerToQuery::FirstCapable)
4971 })
4972 .filter(|_| {
4973 maybe!({
4974 let language = buffer.read(cx).language_at(position)?;
4975 Some(
4976 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
4977 .linked_edits,
4978 )
4979 }) == Some(true)
4980 })
4981 else {
4982 return Task::ready(Ok(Vec::new()));
4983 };
4984
4985 self.request_lsp(
4986 buffer.clone(),
4987 server_id,
4988 LinkedEditingRange { position },
4989 cx,
4990 )
4991 }
4992
4993 fn apply_on_type_formatting(
4994 &mut self,
4995 buffer: Entity<Buffer>,
4996 position: Anchor,
4997 trigger: String,
4998 cx: &mut Context<Self>,
4999 ) -> Task<Result<Option<Transaction>>> {
5000 if let Some((client, project_id)) = self.upstream_client() {
5001 if !self.check_if_capable_for_proto_request(
5002 &buffer,
5003 |capabilities| {
5004 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5005 },
5006 cx,
5007 ) {
5008 return Task::ready(Ok(None));
5009 }
5010 let request = proto::OnTypeFormatting {
5011 project_id,
5012 buffer_id: buffer.read(cx).remote_id().into(),
5013 position: Some(serialize_anchor(&position)),
5014 trigger,
5015 version: serialize_version(&buffer.read(cx).version()),
5016 };
5017 cx.background_spawn(async move {
5018 client
5019 .request(request)
5020 .await?
5021 .transaction
5022 .map(language::proto::deserialize_transaction)
5023 .transpose()
5024 })
5025 } else if let Some(local) = self.as_local_mut() {
5026 let buffer_id = buffer.read(cx).remote_id();
5027 local.buffers_being_formatted.insert(buffer_id);
5028 cx.spawn(async move |this, cx| {
5029 let _cleanup = defer({
5030 let this = this.clone();
5031 let mut cx = cx.clone();
5032 move || {
5033 this.update(&mut cx, |this, _| {
5034 if let Some(local) = this.as_local_mut() {
5035 local.buffers_being_formatted.remove(&buffer_id);
5036 }
5037 })
5038 .ok();
5039 }
5040 });
5041
5042 buffer
5043 .update(cx, |buffer, _| {
5044 buffer.wait_for_edits(Some(position.timestamp))
5045 })?
5046 .await?;
5047 this.update(cx, |this, cx| {
5048 let position = position.to_point_utf16(buffer.read(cx));
5049 this.on_type_format(buffer, position, trigger, false, cx)
5050 })?
5051 .await
5052 })
5053 } else {
5054 Task::ready(Err(anyhow!("No upstream client or local language server")))
5055 }
5056 }
5057
5058 pub fn on_type_format<T: ToPointUtf16>(
5059 &mut self,
5060 buffer: Entity<Buffer>,
5061 position: T,
5062 trigger: String,
5063 push_to_history: bool,
5064 cx: &mut Context<Self>,
5065 ) -> Task<Result<Option<Transaction>>> {
5066 let position = position.to_point_utf16(buffer.read(cx));
5067 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5068 }
5069
5070 fn on_type_format_impl(
5071 &mut self,
5072 buffer: Entity<Buffer>,
5073 position: PointUtf16,
5074 trigger: String,
5075 push_to_history: bool,
5076 cx: &mut Context<Self>,
5077 ) -> Task<Result<Option<Transaction>>> {
5078 let options = buffer.update(cx, |buffer, cx| {
5079 lsp_command::lsp_formatting_options(
5080 language_settings(
5081 buffer.language_at(position).map(|l| l.name()),
5082 buffer.file(),
5083 cx,
5084 )
5085 .as_ref(),
5086 )
5087 });
5088
5089 cx.spawn(async move |this, cx| {
5090 if let Some(waiter) =
5091 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5092 {
5093 waiter.await?;
5094 }
5095 cx.update(|cx| {
5096 this.update(cx, |this, cx| {
5097 this.request_lsp(
5098 buffer.clone(),
5099 LanguageServerToQuery::FirstCapable,
5100 OnTypeFormatting {
5101 position,
5102 trigger,
5103 options,
5104 push_to_history,
5105 },
5106 cx,
5107 )
5108 })
5109 })??
5110 .await
5111 })
5112 }
5113
5114 pub fn definitions(
5115 &mut self,
5116 buffer: &Entity<Buffer>,
5117 position: PointUtf16,
5118 cx: &mut Context<Self>,
5119 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5120 if let Some((upstream_client, project_id)) = self.upstream_client() {
5121 let request = GetDefinitions { position };
5122 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5123 return Task::ready(Ok(None));
5124 }
5125 let request_task = upstream_client.request_lsp(
5126 project_id,
5127 LSP_REQUEST_TIMEOUT,
5128 cx.background_executor().clone(),
5129 request.to_proto(project_id, buffer.read(cx)),
5130 );
5131 let buffer = buffer.clone();
5132 cx.spawn(async move |weak_project, cx| {
5133 let Some(project) = weak_project.upgrade() else {
5134 return Ok(None);
5135 };
5136 let Some(responses) = request_task.await? else {
5137 return Ok(None);
5138 };
5139 let actions = join_all(responses.payload.into_iter().map(|response| {
5140 GetDefinitions { position }.response_from_proto(
5141 response.response,
5142 project.clone(),
5143 buffer.clone(),
5144 cx.clone(),
5145 )
5146 }))
5147 .await;
5148
5149 Ok(Some(
5150 actions
5151 .into_iter()
5152 .collect::<Result<Vec<Vec<_>>>>()?
5153 .into_iter()
5154 .flatten()
5155 .dedup()
5156 .collect(),
5157 ))
5158 })
5159 } else {
5160 let definitions_task = self.request_multiple_lsp_locally(
5161 buffer,
5162 Some(position),
5163 GetDefinitions { position },
5164 cx,
5165 );
5166 cx.background_spawn(async move {
5167 Ok(Some(
5168 definitions_task
5169 .await
5170 .into_iter()
5171 .flat_map(|(_, definitions)| definitions)
5172 .dedup()
5173 .collect(),
5174 ))
5175 })
5176 }
5177 }
5178
5179 pub fn declarations(
5180 &mut self,
5181 buffer: &Entity<Buffer>,
5182 position: PointUtf16,
5183 cx: &mut Context<Self>,
5184 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5185 if let Some((upstream_client, project_id)) = self.upstream_client() {
5186 let request = GetDeclarations { position };
5187 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5188 return Task::ready(Ok(None));
5189 }
5190 let request_task = upstream_client.request_lsp(
5191 project_id,
5192 LSP_REQUEST_TIMEOUT,
5193 cx.background_executor().clone(),
5194 request.to_proto(project_id, buffer.read(cx)),
5195 );
5196 let buffer = buffer.clone();
5197 cx.spawn(async move |weak_project, cx| {
5198 let Some(project) = weak_project.upgrade() else {
5199 return Ok(None);
5200 };
5201 let Some(responses) = request_task.await? else {
5202 return Ok(None);
5203 };
5204 let actions = join_all(responses.payload.into_iter().map(|response| {
5205 GetDeclarations { position }.response_from_proto(
5206 response.response,
5207 project.clone(),
5208 buffer.clone(),
5209 cx.clone(),
5210 )
5211 }))
5212 .await;
5213
5214 Ok(Some(
5215 actions
5216 .into_iter()
5217 .collect::<Result<Vec<Vec<_>>>>()?
5218 .into_iter()
5219 .flatten()
5220 .dedup()
5221 .collect(),
5222 ))
5223 })
5224 } else {
5225 let declarations_task = self.request_multiple_lsp_locally(
5226 buffer,
5227 Some(position),
5228 GetDeclarations { position },
5229 cx,
5230 );
5231 cx.background_spawn(async move {
5232 Ok(Some(
5233 declarations_task
5234 .await
5235 .into_iter()
5236 .flat_map(|(_, declarations)| declarations)
5237 .dedup()
5238 .collect(),
5239 ))
5240 })
5241 }
5242 }
5243
5244 pub fn type_definitions(
5245 &mut self,
5246 buffer: &Entity<Buffer>,
5247 position: PointUtf16,
5248 cx: &mut Context<Self>,
5249 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5250 if let Some((upstream_client, project_id)) = self.upstream_client() {
5251 let request = GetTypeDefinitions { position };
5252 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5253 return Task::ready(Ok(None));
5254 }
5255 let request_task = upstream_client.request_lsp(
5256 project_id,
5257 LSP_REQUEST_TIMEOUT,
5258 cx.background_executor().clone(),
5259 request.to_proto(project_id, buffer.read(cx)),
5260 );
5261 let buffer = buffer.clone();
5262 cx.spawn(async move |weak_project, cx| {
5263 let Some(project) = weak_project.upgrade() else {
5264 return Ok(None);
5265 };
5266 let Some(responses) = request_task.await? else {
5267 return Ok(None);
5268 };
5269 let actions = join_all(responses.payload.into_iter().map(|response| {
5270 GetTypeDefinitions { position }.response_from_proto(
5271 response.response,
5272 project.clone(),
5273 buffer.clone(),
5274 cx.clone(),
5275 )
5276 }))
5277 .await;
5278
5279 Ok(Some(
5280 actions
5281 .into_iter()
5282 .collect::<Result<Vec<Vec<_>>>>()?
5283 .into_iter()
5284 .flatten()
5285 .dedup()
5286 .collect(),
5287 ))
5288 })
5289 } else {
5290 let type_definitions_task = self.request_multiple_lsp_locally(
5291 buffer,
5292 Some(position),
5293 GetTypeDefinitions { position },
5294 cx,
5295 );
5296 cx.background_spawn(async move {
5297 Ok(Some(
5298 type_definitions_task
5299 .await
5300 .into_iter()
5301 .flat_map(|(_, type_definitions)| type_definitions)
5302 .dedup()
5303 .collect(),
5304 ))
5305 })
5306 }
5307 }
5308
5309 pub fn implementations(
5310 &mut self,
5311 buffer: &Entity<Buffer>,
5312 position: PointUtf16,
5313 cx: &mut Context<Self>,
5314 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5315 if let Some((upstream_client, project_id)) = self.upstream_client() {
5316 let request = GetImplementations { position };
5317 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5318 return Task::ready(Ok(None));
5319 }
5320 let request_task = upstream_client.request_lsp(
5321 project_id,
5322 LSP_REQUEST_TIMEOUT,
5323 cx.background_executor().clone(),
5324 request.to_proto(project_id, buffer.read(cx)),
5325 );
5326 let buffer = buffer.clone();
5327 cx.spawn(async move |weak_project, cx| {
5328 let Some(project) = weak_project.upgrade() else {
5329 return Ok(None);
5330 };
5331 let Some(responses) = request_task.await? else {
5332 return Ok(None);
5333 };
5334 let actions = join_all(responses.payload.into_iter().map(|response| {
5335 GetImplementations { position }.response_from_proto(
5336 response.response,
5337 project.clone(),
5338 buffer.clone(),
5339 cx.clone(),
5340 )
5341 }))
5342 .await;
5343
5344 Ok(Some(
5345 actions
5346 .into_iter()
5347 .collect::<Result<Vec<Vec<_>>>>()?
5348 .into_iter()
5349 .flatten()
5350 .dedup()
5351 .collect(),
5352 ))
5353 })
5354 } else {
5355 let implementations_task = self.request_multiple_lsp_locally(
5356 buffer,
5357 Some(position),
5358 GetImplementations { position },
5359 cx,
5360 );
5361 cx.background_spawn(async move {
5362 Ok(Some(
5363 implementations_task
5364 .await
5365 .into_iter()
5366 .flat_map(|(_, implementations)| implementations)
5367 .dedup()
5368 .collect(),
5369 ))
5370 })
5371 }
5372 }
5373
5374 pub fn references(
5375 &mut self,
5376 buffer: &Entity<Buffer>,
5377 position: PointUtf16,
5378 cx: &mut Context<Self>,
5379 ) -> Task<Result<Option<Vec<Location>>>> {
5380 if let Some((upstream_client, project_id)) = self.upstream_client() {
5381 let request = GetReferences { position };
5382 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5383 return Task::ready(Ok(None));
5384 }
5385
5386 let request_task = upstream_client.request_lsp(
5387 project_id,
5388 LSP_REQUEST_TIMEOUT,
5389 cx.background_executor().clone(),
5390 request.to_proto(project_id, buffer.read(cx)),
5391 );
5392 let buffer = buffer.clone();
5393 cx.spawn(async move |weak_project, cx| {
5394 let Some(project) = weak_project.upgrade() else {
5395 return Ok(None);
5396 };
5397 let Some(responses) = request_task.await? else {
5398 return Ok(None);
5399 };
5400
5401 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5402 GetReferences { position }.response_from_proto(
5403 lsp_response.response,
5404 project.clone(),
5405 buffer.clone(),
5406 cx.clone(),
5407 )
5408 }))
5409 .await
5410 .into_iter()
5411 .collect::<Result<Vec<Vec<_>>>>()?
5412 .into_iter()
5413 .flatten()
5414 .dedup()
5415 .collect();
5416 Ok(Some(locations))
5417 })
5418 } else {
5419 let references_task = self.request_multiple_lsp_locally(
5420 buffer,
5421 Some(position),
5422 GetReferences { position },
5423 cx,
5424 );
5425 cx.background_spawn(async move {
5426 Ok(Some(
5427 references_task
5428 .await
5429 .into_iter()
5430 .flat_map(|(_, references)| references)
5431 .dedup()
5432 .collect(),
5433 ))
5434 })
5435 }
5436 }
5437
5438 pub fn code_actions(
5439 &mut self,
5440 buffer: &Entity<Buffer>,
5441 range: Range<Anchor>,
5442 kinds: Option<Vec<CodeActionKind>>,
5443 cx: &mut Context<Self>,
5444 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5445 if let Some((upstream_client, project_id)) = self.upstream_client() {
5446 let request = GetCodeActions {
5447 range: range.clone(),
5448 kinds: kinds.clone(),
5449 };
5450 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5451 return Task::ready(Ok(None));
5452 }
5453 let request_task = upstream_client.request_lsp(
5454 project_id,
5455 LSP_REQUEST_TIMEOUT,
5456 cx.background_executor().clone(),
5457 request.to_proto(project_id, buffer.read(cx)),
5458 );
5459 let buffer = buffer.clone();
5460 cx.spawn(async move |weak_project, cx| {
5461 let Some(project) = weak_project.upgrade() else {
5462 return Ok(None);
5463 };
5464 let Some(responses) = request_task.await? else {
5465 return Ok(None);
5466 };
5467 let actions = join_all(responses.payload.into_iter().map(|response| {
5468 GetCodeActions {
5469 range: range.clone(),
5470 kinds: kinds.clone(),
5471 }
5472 .response_from_proto(
5473 response.response,
5474 project.clone(),
5475 buffer.clone(),
5476 cx.clone(),
5477 )
5478 }))
5479 .await;
5480
5481 Ok(Some(
5482 actions
5483 .into_iter()
5484 .collect::<Result<Vec<Vec<_>>>>()?
5485 .into_iter()
5486 .flatten()
5487 .collect(),
5488 ))
5489 })
5490 } else {
5491 let all_actions_task = self.request_multiple_lsp_locally(
5492 buffer,
5493 Some(range.start),
5494 GetCodeActions { range, kinds },
5495 cx,
5496 );
5497 cx.background_spawn(async move {
5498 Ok(Some(
5499 all_actions_task
5500 .await
5501 .into_iter()
5502 .flat_map(|(_, actions)| actions)
5503 .collect(),
5504 ))
5505 })
5506 }
5507 }
5508
5509 pub fn code_lens_actions(
5510 &mut self,
5511 buffer: &Entity<Buffer>,
5512 cx: &mut Context<Self>,
5513 ) -> CodeLensTask {
5514 let version_queried_for = buffer.read(cx).version();
5515 let buffer_id = buffer.read(cx).remote_id();
5516
5517 if let Some(cached_data) = self.lsp_code_lens.get(&buffer_id)
5518 && !version_queried_for.changed_since(&cached_data.lens_for_version)
5519 {
5520 let has_different_servers = self.as_local().is_some_and(|local| {
5521 local
5522 .buffers_opened_in_servers
5523 .get(&buffer_id)
5524 .cloned()
5525 .unwrap_or_default()
5526 != cached_data.lens.keys().copied().collect()
5527 });
5528 if !has_different_servers {
5529 return Task::ready(Ok(Some(
5530 cached_data.lens.values().flatten().cloned().collect(),
5531 )))
5532 .shared();
5533 }
5534 }
5535
5536 let lsp_data = self.lsp_code_lens.entry(buffer_id).or_default();
5537 if let Some((updating_for, running_update)) = &lsp_data.update
5538 && !version_queried_for.changed_since(updating_for)
5539 {
5540 return running_update.clone();
5541 }
5542 let buffer = buffer.clone();
5543 let query_version_queried_for = version_queried_for.clone();
5544 let new_task = cx
5545 .spawn(async move |lsp_store, cx| {
5546 cx.background_executor()
5547 .timer(Duration::from_millis(30))
5548 .await;
5549 let fetched_lens = lsp_store
5550 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5551 .map_err(Arc::new)?
5552 .await
5553 .context("fetching code lens")
5554 .map_err(Arc::new);
5555 let fetched_lens = match fetched_lens {
5556 Ok(fetched_lens) => fetched_lens,
5557 Err(e) => {
5558 lsp_store
5559 .update(cx, |lsp_store, _| {
5560 lsp_store.lsp_code_lens.entry(buffer_id).or_default().update = None;
5561 })
5562 .ok();
5563 return Err(e);
5564 }
5565 };
5566
5567 lsp_store
5568 .update(cx, |lsp_store, _| {
5569 let lsp_data = lsp_store.lsp_code_lens.entry(buffer_id).or_default();
5570 if let Some(fetched_lens) = fetched_lens {
5571 if lsp_data.lens_for_version == query_version_queried_for {
5572 lsp_data.lens.extend(fetched_lens);
5573 } else if !lsp_data
5574 .lens_for_version
5575 .changed_since(&query_version_queried_for)
5576 {
5577 lsp_data.lens_for_version = query_version_queried_for;
5578 lsp_data.lens = fetched_lens;
5579 }
5580 }
5581 lsp_data.update = None;
5582 Some(lsp_data.lens.values().flatten().cloned().collect())
5583 })
5584 .map_err(Arc::new)
5585 })
5586 .shared();
5587 lsp_data.update = Some((version_queried_for, new_task.clone()));
5588 new_task
5589 }
5590
5591 fn fetch_code_lens(
5592 &mut self,
5593 buffer: &Entity<Buffer>,
5594 cx: &mut Context<Self>,
5595 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5596 if let Some((upstream_client, project_id)) = self.upstream_client() {
5597 let request = GetCodeLens;
5598 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5599 return Task::ready(Ok(None));
5600 }
5601 let request_task = upstream_client.request_lsp(
5602 project_id,
5603 LSP_REQUEST_TIMEOUT,
5604 cx.background_executor().clone(),
5605 request.to_proto(project_id, buffer.read(cx)),
5606 );
5607 let buffer = buffer.clone();
5608 cx.spawn(async move |weak_lsp_store, cx| {
5609 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5610 return Ok(None);
5611 };
5612 let Some(responses) = request_task.await? else {
5613 return Ok(None);
5614 };
5615
5616 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5617 let lsp_store = lsp_store.clone();
5618 let buffer = buffer.clone();
5619 let cx = cx.clone();
5620 async move {
5621 (
5622 LanguageServerId::from_proto(response.server_id),
5623 GetCodeLens
5624 .response_from_proto(response.response, lsp_store, buffer, cx)
5625 .await,
5626 )
5627 }
5628 }))
5629 .await;
5630
5631 let mut has_errors = false;
5632 let code_lens_actions = code_lens_actions
5633 .into_iter()
5634 .filter_map(|(server_id, code_lens)| match code_lens {
5635 Ok(code_lens) => Some((server_id, code_lens)),
5636 Err(e) => {
5637 has_errors = true;
5638 log::error!("{e:#}");
5639 None
5640 }
5641 })
5642 .collect::<HashMap<_, _>>();
5643 anyhow::ensure!(
5644 !has_errors || !code_lens_actions.is_empty(),
5645 "Failed to fetch code lens"
5646 );
5647 Ok(Some(code_lens_actions))
5648 })
5649 } else {
5650 let code_lens_actions_task =
5651 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5652 cx.background_spawn(async move {
5653 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5654 })
5655 }
5656 }
5657
5658 #[inline(never)]
5659 pub fn completions(
5660 &self,
5661 buffer: &Entity<Buffer>,
5662 position: PointUtf16,
5663 context: CompletionContext,
5664 cx: &mut Context<Self>,
5665 ) -> Task<Result<Vec<CompletionResponse>>> {
5666 let language_registry = self.languages.clone();
5667
5668 if let Some((upstream_client, project_id)) = self.upstream_client() {
5669 let request = GetCompletions { position, context };
5670 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5671 return Task::ready(Ok(Vec::new()));
5672 }
5673 let task = self.send_lsp_proto_request(
5674 buffer.clone(),
5675 upstream_client,
5676 project_id,
5677 request,
5678 cx,
5679 );
5680 let language = buffer.read(cx).language().cloned();
5681
5682 // In the future, we should provide project guests with the names of LSP adapters,
5683 // so that they can use the correct LSP adapter when computing labels. For now,
5684 // guests just use the first LSP adapter associated with the buffer's language.
5685 let lsp_adapter = language.as_ref().and_then(|language| {
5686 language_registry
5687 .lsp_adapters(&language.name())
5688 .first()
5689 .cloned()
5690 });
5691
5692 cx.foreground_executor().spawn(async move {
5693 let completion_response = task.await?;
5694 let completions = populate_labels_for_completions(
5695 completion_response.completions,
5696 language,
5697 lsp_adapter,
5698 )
5699 .await;
5700 Ok(vec![CompletionResponse {
5701 completions,
5702 display_options: CompletionDisplayOptions::default(),
5703 is_incomplete: completion_response.is_incomplete,
5704 }])
5705 })
5706 } else if let Some(local) = self.as_local() {
5707 let snapshot = buffer.read(cx).snapshot();
5708 let offset = position.to_offset(&snapshot);
5709 let scope = snapshot.language_scope_at(offset);
5710 let language = snapshot.language().cloned();
5711 let completion_settings = language_settings(
5712 language.as_ref().map(|language| language.name()),
5713 buffer.read(cx).file(),
5714 cx,
5715 )
5716 .completions
5717 .clone();
5718 if !completion_settings.lsp {
5719 return Task::ready(Ok(Vec::new()));
5720 }
5721
5722 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5723 local
5724 .language_servers_for_buffer(buffer, cx)
5725 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5726 .filter(|(adapter, _)| {
5727 scope
5728 .as_ref()
5729 .map(|scope| scope.language_allowed(&adapter.name))
5730 .unwrap_or(true)
5731 })
5732 .map(|(_, server)| server.server_id())
5733 .collect()
5734 });
5735
5736 let buffer = buffer.clone();
5737 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5738 let lsp_timeout = if lsp_timeout > 0 {
5739 Some(Duration::from_millis(lsp_timeout))
5740 } else {
5741 None
5742 };
5743 cx.spawn(async move |this, cx| {
5744 let mut tasks = Vec::with_capacity(server_ids.len());
5745 this.update(cx, |lsp_store, cx| {
5746 for server_id in server_ids {
5747 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5748 let lsp_timeout = lsp_timeout
5749 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5750 let mut timeout = cx.background_spawn(async move {
5751 match lsp_timeout {
5752 Some(lsp_timeout) => {
5753 lsp_timeout.await;
5754 true
5755 },
5756 None => false,
5757 }
5758 }).fuse();
5759 let mut lsp_request = lsp_store.request_lsp(
5760 buffer.clone(),
5761 LanguageServerToQuery::Other(server_id),
5762 GetCompletions {
5763 position,
5764 context: context.clone(),
5765 },
5766 cx,
5767 ).fuse();
5768 let new_task = cx.background_spawn(async move {
5769 select_biased! {
5770 response = lsp_request => anyhow::Ok(Some(response?)),
5771 timeout_happened = timeout => {
5772 if timeout_happened {
5773 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5774 Ok(None)
5775 } else {
5776 let completions = lsp_request.await?;
5777 Ok(Some(completions))
5778 }
5779 },
5780 }
5781 });
5782 tasks.push((lsp_adapter, new_task));
5783 }
5784 })?;
5785
5786 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5787 let completion_response = task.await.ok()??;
5788 let completions = populate_labels_for_completions(
5789 completion_response.completions,
5790 language.clone(),
5791 lsp_adapter,
5792 )
5793 .await;
5794 Some(CompletionResponse {
5795 completions,
5796 display_options: CompletionDisplayOptions::default(),
5797 is_incomplete: completion_response.is_incomplete,
5798 })
5799 });
5800
5801 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5802
5803 Ok(responses.into_iter().flatten().collect())
5804 })
5805 } else {
5806 Task::ready(Err(anyhow!("No upstream client or local language server")))
5807 }
5808 }
5809
5810 pub fn resolve_completions(
5811 &self,
5812 buffer: Entity<Buffer>,
5813 completion_indices: Vec<usize>,
5814 completions: Rc<RefCell<Box<[Completion]>>>,
5815 cx: &mut Context<Self>,
5816 ) -> Task<Result<bool>> {
5817 let client = self.upstream_client();
5818 let buffer_id = buffer.read(cx).remote_id();
5819 let buffer_snapshot = buffer.read(cx).snapshot();
5820
5821 if !self.check_if_capable_for_proto_request(
5822 &buffer,
5823 GetCompletions::can_resolve_completions,
5824 cx,
5825 ) {
5826 return Task::ready(Ok(false));
5827 }
5828 cx.spawn(async move |lsp_store, cx| {
5829 let mut did_resolve = false;
5830 if let Some((client, project_id)) = client {
5831 for completion_index in completion_indices {
5832 let server_id = {
5833 let completion = &completions.borrow()[completion_index];
5834 completion.source.server_id()
5835 };
5836 if let Some(server_id) = server_id {
5837 if Self::resolve_completion_remote(
5838 project_id,
5839 server_id,
5840 buffer_id,
5841 completions.clone(),
5842 completion_index,
5843 client.clone(),
5844 )
5845 .await
5846 .log_err()
5847 .is_some()
5848 {
5849 did_resolve = true;
5850 }
5851 } else {
5852 resolve_word_completion(
5853 &buffer_snapshot,
5854 &mut completions.borrow_mut()[completion_index],
5855 );
5856 }
5857 }
5858 } else {
5859 for completion_index in completion_indices {
5860 let server_id = {
5861 let completion = &completions.borrow()[completion_index];
5862 completion.source.server_id()
5863 };
5864 if let Some(server_id) = server_id {
5865 let server_and_adapter = lsp_store
5866 .read_with(cx, |lsp_store, _| {
5867 let server = lsp_store.language_server_for_id(server_id)?;
5868 let adapter =
5869 lsp_store.language_server_adapter_for_id(server.server_id())?;
5870 Some((server, adapter))
5871 })
5872 .ok()
5873 .flatten();
5874 let Some((server, adapter)) = server_and_adapter else {
5875 continue;
5876 };
5877
5878 let resolved = Self::resolve_completion_local(
5879 server,
5880 completions.clone(),
5881 completion_index,
5882 )
5883 .await
5884 .log_err()
5885 .is_some();
5886 if resolved {
5887 Self::regenerate_completion_labels(
5888 adapter,
5889 &buffer_snapshot,
5890 completions.clone(),
5891 completion_index,
5892 )
5893 .await
5894 .log_err();
5895 did_resolve = true;
5896 }
5897 } else {
5898 resolve_word_completion(
5899 &buffer_snapshot,
5900 &mut completions.borrow_mut()[completion_index],
5901 );
5902 }
5903 }
5904 }
5905
5906 Ok(did_resolve)
5907 })
5908 }
5909
5910 async fn resolve_completion_local(
5911 server: Arc<lsp::LanguageServer>,
5912 completions: Rc<RefCell<Box<[Completion]>>>,
5913 completion_index: usize,
5914 ) -> Result<()> {
5915 let server_id = server.server_id();
5916 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
5917 return Ok(());
5918 }
5919
5920 let request = {
5921 let completion = &completions.borrow()[completion_index];
5922 match &completion.source {
5923 CompletionSource::Lsp {
5924 lsp_completion,
5925 resolved,
5926 server_id: completion_server_id,
5927 ..
5928 } => {
5929 if *resolved {
5930 return Ok(());
5931 }
5932 anyhow::ensure!(
5933 server_id == *completion_server_id,
5934 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
5935 );
5936 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
5937 }
5938 CompletionSource::BufferWord { .. }
5939 | CompletionSource::Dap { .. }
5940 | CompletionSource::Custom => {
5941 return Ok(());
5942 }
5943 }
5944 };
5945 let resolved_completion = request
5946 .await
5947 .into_response()
5948 .context("resolve completion")?;
5949
5950 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
5951 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
5952
5953 let mut completions = completions.borrow_mut();
5954 let completion = &mut completions[completion_index];
5955 if let CompletionSource::Lsp {
5956 lsp_completion,
5957 resolved,
5958 server_id: completion_server_id,
5959 ..
5960 } = &mut completion.source
5961 {
5962 if *resolved {
5963 return Ok(());
5964 }
5965 anyhow::ensure!(
5966 server_id == *completion_server_id,
5967 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
5968 );
5969 *lsp_completion = Box::new(resolved_completion);
5970 *resolved = true;
5971 }
5972 Ok(())
5973 }
5974
5975 async fn regenerate_completion_labels(
5976 adapter: Arc<CachedLspAdapter>,
5977 snapshot: &BufferSnapshot,
5978 completions: Rc<RefCell<Box<[Completion]>>>,
5979 completion_index: usize,
5980 ) -> Result<()> {
5981 let completion_item = completions.borrow()[completion_index]
5982 .source
5983 .lsp_completion(true)
5984 .map(Cow::into_owned);
5985 if let Some(lsp_documentation) = completion_item
5986 .as_ref()
5987 .and_then(|completion_item| completion_item.documentation.clone())
5988 {
5989 let mut completions = completions.borrow_mut();
5990 let completion = &mut completions[completion_index];
5991 completion.documentation = Some(lsp_documentation.into());
5992 } else {
5993 let mut completions = completions.borrow_mut();
5994 let completion = &mut completions[completion_index];
5995 completion.documentation = Some(CompletionDocumentation::Undocumented);
5996 }
5997
5998 let mut new_label = match completion_item {
5999 Some(completion_item) => {
6000 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6001 // So we have to update the label here anyway...
6002 let language = snapshot.language();
6003 match language {
6004 Some(language) => {
6005 adapter
6006 .labels_for_completions(
6007 std::slice::from_ref(&completion_item),
6008 language,
6009 )
6010 .await?
6011 }
6012 None => Vec::new(),
6013 }
6014 .pop()
6015 .flatten()
6016 .unwrap_or_else(|| {
6017 CodeLabel::fallback_for_completion(
6018 &completion_item,
6019 language.map(|language| language.as_ref()),
6020 )
6021 })
6022 }
6023 None => CodeLabel::plain(
6024 completions.borrow()[completion_index].new_text.clone(),
6025 None,
6026 ),
6027 };
6028 ensure_uniform_list_compatible_label(&mut new_label);
6029
6030 let mut completions = completions.borrow_mut();
6031 let completion = &mut completions[completion_index];
6032 if completion.label.filter_text() == new_label.filter_text() {
6033 completion.label = new_label;
6034 } else {
6035 log::error!(
6036 "Resolved completion changed display label from {} to {}. \
6037 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6038 completion.label.text(),
6039 new_label.text(),
6040 completion.label.filter_text(),
6041 new_label.filter_text()
6042 );
6043 }
6044
6045 Ok(())
6046 }
6047
6048 async fn resolve_completion_remote(
6049 project_id: u64,
6050 server_id: LanguageServerId,
6051 buffer_id: BufferId,
6052 completions: Rc<RefCell<Box<[Completion]>>>,
6053 completion_index: usize,
6054 client: AnyProtoClient,
6055 ) -> Result<()> {
6056 let lsp_completion = {
6057 let completion = &completions.borrow()[completion_index];
6058 match &completion.source {
6059 CompletionSource::Lsp {
6060 lsp_completion,
6061 resolved,
6062 server_id: completion_server_id,
6063 ..
6064 } => {
6065 anyhow::ensure!(
6066 server_id == *completion_server_id,
6067 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6068 );
6069 if *resolved {
6070 return Ok(());
6071 }
6072 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6073 }
6074 CompletionSource::Custom
6075 | CompletionSource::Dap { .. }
6076 | CompletionSource::BufferWord { .. } => {
6077 return Ok(());
6078 }
6079 }
6080 };
6081 let request = proto::ResolveCompletionDocumentation {
6082 project_id,
6083 language_server_id: server_id.0 as u64,
6084 lsp_completion,
6085 buffer_id: buffer_id.into(),
6086 };
6087
6088 let response = client
6089 .request(request)
6090 .await
6091 .context("completion documentation resolve proto request")?;
6092 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6093
6094 let documentation = if response.documentation.is_empty() {
6095 CompletionDocumentation::Undocumented
6096 } else if response.documentation_is_markdown {
6097 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6098 } else if response.documentation.lines().count() <= 1 {
6099 CompletionDocumentation::SingleLine(response.documentation.into())
6100 } else {
6101 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6102 };
6103
6104 let mut completions = completions.borrow_mut();
6105 let completion = &mut completions[completion_index];
6106 completion.documentation = Some(documentation);
6107 if let CompletionSource::Lsp {
6108 insert_range,
6109 lsp_completion,
6110 resolved,
6111 server_id: completion_server_id,
6112 lsp_defaults: _,
6113 } = &mut completion.source
6114 {
6115 let completion_insert_range = response
6116 .old_insert_start
6117 .and_then(deserialize_anchor)
6118 .zip(response.old_insert_end.and_then(deserialize_anchor));
6119 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6120
6121 if *resolved {
6122 return Ok(());
6123 }
6124 anyhow::ensure!(
6125 server_id == *completion_server_id,
6126 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6127 );
6128 *lsp_completion = Box::new(resolved_lsp_completion);
6129 *resolved = true;
6130 }
6131
6132 let replace_range = response
6133 .old_replace_start
6134 .and_then(deserialize_anchor)
6135 .zip(response.old_replace_end.and_then(deserialize_anchor));
6136 if let Some((old_replace_start, old_replace_end)) = replace_range
6137 && !response.new_text.is_empty()
6138 {
6139 completion.new_text = response.new_text;
6140 completion.replace_range = old_replace_start..old_replace_end;
6141 }
6142
6143 Ok(())
6144 }
6145
6146 pub fn apply_additional_edits_for_completion(
6147 &self,
6148 buffer_handle: Entity<Buffer>,
6149 completions: Rc<RefCell<Box<[Completion]>>>,
6150 completion_index: usize,
6151 push_to_history: bool,
6152 cx: &mut Context<Self>,
6153 ) -> Task<Result<Option<Transaction>>> {
6154 if let Some((client, project_id)) = self.upstream_client() {
6155 let buffer = buffer_handle.read(cx);
6156 let buffer_id = buffer.remote_id();
6157 cx.spawn(async move |_, cx| {
6158 let request = {
6159 let completion = completions.borrow()[completion_index].clone();
6160 proto::ApplyCompletionAdditionalEdits {
6161 project_id,
6162 buffer_id: buffer_id.into(),
6163 completion: Some(Self::serialize_completion(&CoreCompletion {
6164 replace_range: completion.replace_range,
6165 new_text: completion.new_text,
6166 source: completion.source,
6167 })),
6168 }
6169 };
6170
6171 if let Some(transaction) = client.request(request).await?.transaction {
6172 let transaction = language::proto::deserialize_transaction(transaction)?;
6173 buffer_handle
6174 .update(cx, |buffer, _| {
6175 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6176 })?
6177 .await?;
6178 if push_to_history {
6179 buffer_handle.update(cx, |buffer, _| {
6180 buffer.push_transaction(transaction.clone(), Instant::now());
6181 buffer.finalize_last_transaction();
6182 })?;
6183 }
6184 Ok(Some(transaction))
6185 } else {
6186 Ok(None)
6187 }
6188 })
6189 } else {
6190 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6191 let completion = &completions.borrow()[completion_index];
6192 let server_id = completion.source.server_id()?;
6193 Some(
6194 self.language_server_for_local_buffer(buffer, server_id, cx)?
6195 .1
6196 .clone(),
6197 )
6198 }) else {
6199 return Task::ready(Ok(None));
6200 };
6201
6202 cx.spawn(async move |this, cx| {
6203 Self::resolve_completion_local(
6204 server.clone(),
6205 completions.clone(),
6206 completion_index,
6207 )
6208 .await
6209 .context("resolving completion")?;
6210 let completion = completions.borrow()[completion_index].clone();
6211 let additional_text_edits = completion
6212 .source
6213 .lsp_completion(true)
6214 .as_ref()
6215 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6216 if let Some(edits) = additional_text_edits {
6217 let edits = this
6218 .update(cx, |this, cx| {
6219 this.as_local_mut().unwrap().edits_from_lsp(
6220 &buffer_handle,
6221 edits,
6222 server.server_id(),
6223 None,
6224 cx,
6225 )
6226 })?
6227 .await?;
6228
6229 buffer_handle.update(cx, |buffer, cx| {
6230 buffer.finalize_last_transaction();
6231 buffer.start_transaction();
6232
6233 for (range, text) in edits {
6234 let primary = &completion.replace_range;
6235
6236 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6237 // and the primary completion is just an insertion (empty range), then this is likely
6238 // an auto-import scenario and should not be considered overlapping
6239 // https://github.com/zed-industries/zed/issues/26136
6240 let is_file_start_auto_import = {
6241 let snapshot = buffer.snapshot();
6242 let primary_start_point = primary.start.to_point(&snapshot);
6243 let range_start_point = range.start.to_point(&snapshot);
6244
6245 let result = primary_start_point.row == 0
6246 && primary_start_point.column == 0
6247 && range_start_point.row == 0
6248 && range_start_point.column == 0;
6249
6250 result
6251 };
6252
6253 let has_overlap = if is_file_start_auto_import {
6254 false
6255 } else {
6256 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6257 && primary.end.cmp(&range.start, buffer).is_ge();
6258 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6259 && range.end.cmp(&primary.end, buffer).is_ge();
6260 let result = start_within || end_within;
6261 result
6262 };
6263
6264 //Skip additional edits which overlap with the primary completion edit
6265 //https://github.com/zed-industries/zed/pull/1871
6266 if !has_overlap {
6267 buffer.edit([(range, text)], None, cx);
6268 }
6269 }
6270
6271 let transaction = if buffer.end_transaction(cx).is_some() {
6272 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6273 if !push_to_history {
6274 buffer.forget_transaction(transaction.id);
6275 }
6276 Some(transaction)
6277 } else {
6278 None
6279 };
6280 Ok(transaction)
6281 })?
6282 } else {
6283 Ok(None)
6284 }
6285 })
6286 }
6287 }
6288
6289 pub fn pull_diagnostics(
6290 &mut self,
6291 buffer: Entity<Buffer>,
6292 cx: &mut Context<Self>,
6293 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6294 let buffer_id = buffer.read(cx).remote_id();
6295
6296 if let Some((client, upstream_project_id)) = self.upstream_client() {
6297 let request = GetDocumentDiagnostics {
6298 previous_result_id: None,
6299 };
6300 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6301 return Task::ready(Ok(None));
6302 }
6303 let request_task = client.request_lsp(
6304 upstream_project_id,
6305 LSP_REQUEST_TIMEOUT,
6306 cx.background_executor().clone(),
6307 request.to_proto(upstream_project_id, buffer.read(cx)),
6308 );
6309 cx.background_spawn(async move {
6310 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6311 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6312 // Do not attempt to further process the dummy responses here.
6313 let _response = request_task.await?;
6314 Ok(None)
6315 })
6316 } else {
6317 let server_ids = buffer.update(cx, |buffer, cx| {
6318 self.language_servers_for_local_buffer(buffer, cx)
6319 .map(|(_, server)| server.server_id())
6320 .collect::<Vec<_>>()
6321 });
6322 let pull_diagnostics = server_ids
6323 .into_iter()
6324 .map(|server_id| {
6325 let result_id = self.result_id(server_id, buffer_id, cx);
6326 self.request_lsp(
6327 buffer.clone(),
6328 LanguageServerToQuery::Other(server_id),
6329 GetDocumentDiagnostics {
6330 previous_result_id: result_id,
6331 },
6332 cx,
6333 )
6334 })
6335 .collect::<Vec<_>>();
6336
6337 cx.background_spawn(async move {
6338 let mut responses = Vec::new();
6339 for diagnostics in join_all(pull_diagnostics).await {
6340 responses.extend(diagnostics?);
6341 }
6342 Ok(Some(responses))
6343 })
6344 }
6345 }
6346
6347 pub fn inlay_hints(
6348 &mut self,
6349 buffer: Entity<Buffer>,
6350 range: Range<Anchor>,
6351 cx: &mut Context<Self>,
6352 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6353 let range_start = range.start;
6354 let range_end = range.end;
6355 let buffer_id = buffer.read(cx).remote_id().into();
6356 let request = InlayHints { range };
6357
6358 if let Some((client, project_id)) = self.upstream_client() {
6359 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6360 return Task::ready(Ok(Vec::new()));
6361 }
6362 let proto_request = proto::InlayHints {
6363 project_id,
6364 buffer_id,
6365 start: Some(serialize_anchor(&range_start)),
6366 end: Some(serialize_anchor(&range_end)),
6367 version: serialize_version(&buffer.read(cx).version()),
6368 };
6369 cx.spawn(async move |project, cx| {
6370 let response = client
6371 .request(proto_request)
6372 .await
6373 .context("inlay hints proto request")?;
6374 LspCommand::response_from_proto(
6375 request,
6376 response,
6377 project.upgrade().context("No project")?,
6378 buffer.clone(),
6379 cx.clone(),
6380 )
6381 .await
6382 .context("inlay hints proto response conversion")
6383 })
6384 } else {
6385 let lsp_request_task = self.request_lsp(
6386 buffer.clone(),
6387 LanguageServerToQuery::FirstCapable,
6388 request,
6389 cx,
6390 );
6391 cx.spawn(async move |_, cx| {
6392 buffer
6393 .update(cx, |buffer, _| {
6394 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6395 })?
6396 .await
6397 .context("waiting for inlay hint request range edits")?;
6398 lsp_request_task.await.context("inlay hints LSP request")
6399 })
6400 }
6401 }
6402
6403 pub fn pull_diagnostics_for_buffer(
6404 &mut self,
6405 buffer: Entity<Buffer>,
6406 cx: &mut Context<Self>,
6407 ) -> Task<anyhow::Result<()>> {
6408 let diagnostics = self.pull_diagnostics(buffer, cx);
6409 cx.spawn(async move |lsp_store, cx| {
6410 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6411 return Ok(());
6412 };
6413 lsp_store.update(cx, |lsp_store, cx| {
6414 if lsp_store.as_local().is_none() {
6415 return;
6416 }
6417
6418 let mut unchanged_buffers = HashSet::default();
6419 let mut changed_buffers = HashSet::default();
6420 let server_diagnostics_updates = diagnostics
6421 .into_iter()
6422 .filter_map(|diagnostics_set| match diagnostics_set {
6423 LspPullDiagnostics::Response {
6424 server_id,
6425 uri,
6426 diagnostics,
6427 } => Some((server_id, uri, diagnostics)),
6428 LspPullDiagnostics::Default => None,
6429 })
6430 .fold(
6431 HashMap::default(),
6432 |mut acc, (server_id, uri, diagnostics)| {
6433 let (result_id, diagnostics) = match diagnostics {
6434 PulledDiagnostics::Unchanged { result_id } => {
6435 unchanged_buffers.insert(uri.clone());
6436 (Some(result_id), Vec::new())
6437 }
6438 PulledDiagnostics::Changed {
6439 result_id,
6440 diagnostics,
6441 } => {
6442 changed_buffers.insert(uri.clone());
6443 (result_id, diagnostics)
6444 }
6445 };
6446 let disk_based_sources = Cow::Owned(
6447 lsp_store
6448 .language_server_adapter_for_id(server_id)
6449 .as_ref()
6450 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6451 .unwrap_or(&[])
6452 .to_vec(),
6453 );
6454 acc.entry(server_id).or_insert_with(Vec::new).push(
6455 DocumentDiagnosticsUpdate {
6456 server_id,
6457 diagnostics: lsp::PublishDiagnosticsParams {
6458 uri,
6459 diagnostics,
6460 version: None,
6461 },
6462 result_id,
6463 disk_based_sources,
6464 },
6465 );
6466 acc
6467 },
6468 );
6469
6470 for diagnostic_updates in server_diagnostics_updates.into_values() {
6471 lsp_store
6472 .merge_lsp_diagnostics(
6473 DiagnosticSourceKind::Pulled,
6474 diagnostic_updates,
6475 |buffer, old_diagnostic, cx| {
6476 File::from_dyn(buffer.file())
6477 .and_then(|file| {
6478 let abs_path = file.as_local()?.abs_path(cx);
6479 lsp::Uri::from_file_path(abs_path).ok()
6480 })
6481 .is_none_or(|buffer_uri| {
6482 unchanged_buffers.contains(&buffer_uri)
6483 || match old_diagnostic.source_kind {
6484 DiagnosticSourceKind::Pulled => {
6485 !changed_buffers.contains(&buffer_uri)
6486 }
6487 DiagnosticSourceKind::Other
6488 | DiagnosticSourceKind::Pushed => true,
6489 }
6490 })
6491 },
6492 cx,
6493 )
6494 .log_err();
6495 }
6496 })
6497 })
6498 }
6499
6500 pub fn document_colors(
6501 &mut self,
6502 fetch_strategy: LspFetchStrategy,
6503 buffer: Entity<Buffer>,
6504 cx: &mut Context<Self>,
6505 ) -> Option<DocumentColorTask> {
6506 let version_queried_for = buffer.read(cx).version();
6507 let buffer_id = buffer.read(cx).remote_id();
6508
6509 match fetch_strategy {
6510 LspFetchStrategy::IgnoreCache => {}
6511 LspFetchStrategy::UseCache {
6512 known_cache_version,
6513 } => {
6514 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6515 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6516 {
6517 let has_different_servers = self.as_local().is_some_and(|local| {
6518 local
6519 .buffers_opened_in_servers
6520 .get(&buffer_id)
6521 .cloned()
6522 .unwrap_or_default()
6523 != cached_data.colors.keys().copied().collect()
6524 });
6525 if !has_different_servers {
6526 if Some(cached_data.cache_version) == known_cache_version {
6527 return None;
6528 } else {
6529 return Some(
6530 Task::ready(Ok(DocumentColors {
6531 colors: cached_data
6532 .colors
6533 .values()
6534 .flatten()
6535 .cloned()
6536 .collect(),
6537 cache_version: Some(cached_data.cache_version),
6538 }))
6539 .shared(),
6540 );
6541 }
6542 }
6543 }
6544 }
6545 }
6546
6547 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6548 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6549 && !version_queried_for.changed_since(updating_for)
6550 {
6551 return Some(running_update.clone());
6552 }
6553 let query_version_queried_for = version_queried_for.clone();
6554 let new_task = cx
6555 .spawn(async move |lsp_store, cx| {
6556 cx.background_executor()
6557 .timer(Duration::from_millis(30))
6558 .await;
6559 let fetched_colors = lsp_store
6560 .update(cx, |lsp_store, cx| {
6561 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6562 })?
6563 .await
6564 .context("fetching document colors")
6565 .map_err(Arc::new);
6566 let fetched_colors = match fetched_colors {
6567 Ok(fetched_colors) => {
6568 if fetch_strategy != LspFetchStrategy::IgnoreCache
6569 && Some(true)
6570 == buffer
6571 .update(cx, |buffer, _| {
6572 buffer.version() != query_version_queried_for
6573 })
6574 .ok()
6575 {
6576 return Ok(DocumentColors::default());
6577 }
6578 fetched_colors
6579 }
6580 Err(e) => {
6581 lsp_store
6582 .update(cx, |lsp_store, _| {
6583 lsp_store
6584 .lsp_document_colors
6585 .entry(buffer_id)
6586 .or_default()
6587 .colors_update = None;
6588 })
6589 .ok();
6590 return Err(e);
6591 }
6592 };
6593
6594 lsp_store
6595 .update(cx, |lsp_store, _| {
6596 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6597
6598 if let Some(fetched_colors) = fetched_colors {
6599 if lsp_data.colors_for_version == query_version_queried_for {
6600 lsp_data.colors.extend(fetched_colors);
6601 lsp_data.cache_version += 1;
6602 } else if !lsp_data
6603 .colors_for_version
6604 .changed_since(&query_version_queried_for)
6605 {
6606 lsp_data.colors_for_version = query_version_queried_for;
6607 lsp_data.colors = fetched_colors;
6608 lsp_data.cache_version += 1;
6609 }
6610 }
6611 lsp_data.colors_update = None;
6612 let colors = lsp_data
6613 .colors
6614 .values()
6615 .flatten()
6616 .cloned()
6617 .collect::<HashSet<_>>();
6618 DocumentColors {
6619 colors,
6620 cache_version: Some(lsp_data.cache_version),
6621 }
6622 })
6623 .map_err(Arc::new)
6624 })
6625 .shared();
6626 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6627 Some(new_task)
6628 }
6629
6630 fn fetch_document_colors_for_buffer(
6631 &mut self,
6632 buffer: &Entity<Buffer>,
6633 cx: &mut Context<Self>,
6634 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
6635 if let Some((client, project_id)) = self.upstream_client() {
6636 let request = GetDocumentColor {};
6637 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6638 return Task::ready(Ok(None));
6639 }
6640
6641 let request_task = client.request_lsp(
6642 project_id,
6643 LSP_REQUEST_TIMEOUT,
6644 cx.background_executor().clone(),
6645 request.to_proto(project_id, buffer.read(cx)),
6646 );
6647 let buffer = buffer.clone();
6648 cx.spawn(async move |lsp_store, cx| {
6649 let Some(project) = lsp_store.upgrade() else {
6650 return Ok(None);
6651 };
6652 let colors = join_all(
6653 request_task
6654 .await
6655 .log_err()
6656 .flatten()
6657 .map(|response| response.payload)
6658 .unwrap_or_default()
6659 .into_iter()
6660 .map(|color_response| {
6661 let response = request.response_from_proto(
6662 color_response.response,
6663 project.clone(),
6664 buffer.clone(),
6665 cx.clone(),
6666 );
6667 async move {
6668 (
6669 LanguageServerId::from_proto(color_response.server_id),
6670 response.await.log_err().unwrap_or_default(),
6671 )
6672 }
6673 }),
6674 )
6675 .await
6676 .into_iter()
6677 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6678 acc.entry(server_id)
6679 .or_insert_with(HashSet::default)
6680 .extend(colors);
6681 acc
6682 });
6683 Ok(Some(colors))
6684 })
6685 } else {
6686 let document_colors_task =
6687 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6688 cx.background_spawn(async move {
6689 Ok(Some(
6690 document_colors_task
6691 .await
6692 .into_iter()
6693 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6694 acc.entry(server_id)
6695 .or_insert_with(HashSet::default)
6696 .extend(colors);
6697 acc
6698 })
6699 .into_iter()
6700 .collect(),
6701 ))
6702 })
6703 }
6704 }
6705
6706 pub fn signature_help<T: ToPointUtf16>(
6707 &mut self,
6708 buffer: &Entity<Buffer>,
6709 position: T,
6710 cx: &mut Context<Self>,
6711 ) -> Task<Option<Vec<SignatureHelp>>> {
6712 let position = position.to_point_utf16(buffer.read(cx));
6713
6714 if let Some((client, upstream_project_id)) = self.upstream_client() {
6715 let request = GetSignatureHelp { position };
6716 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6717 return Task::ready(None);
6718 }
6719 let request_task = client.request_lsp(
6720 upstream_project_id,
6721 LSP_REQUEST_TIMEOUT,
6722 cx.background_executor().clone(),
6723 request.to_proto(upstream_project_id, buffer.read(cx)),
6724 );
6725 let buffer = buffer.clone();
6726 cx.spawn(async move |weak_project, cx| {
6727 let project = weak_project.upgrade()?;
6728 let signatures = join_all(
6729 request_task
6730 .await
6731 .log_err()
6732 .flatten()
6733 .map(|response| response.payload)
6734 .unwrap_or_default()
6735 .into_iter()
6736 .map(|response| {
6737 let response = GetSignatureHelp { position }.response_from_proto(
6738 response.response,
6739 project.clone(),
6740 buffer.clone(),
6741 cx.clone(),
6742 );
6743 async move { response.await.log_err().flatten() }
6744 }),
6745 )
6746 .await
6747 .into_iter()
6748 .flatten()
6749 .collect();
6750 Some(signatures)
6751 })
6752 } else {
6753 let all_actions_task = self.request_multiple_lsp_locally(
6754 buffer,
6755 Some(position),
6756 GetSignatureHelp { position },
6757 cx,
6758 );
6759 cx.background_spawn(async move {
6760 Some(
6761 all_actions_task
6762 .await
6763 .into_iter()
6764 .flat_map(|(_, actions)| actions)
6765 .collect::<Vec<_>>(),
6766 )
6767 })
6768 }
6769 }
6770
6771 pub fn hover(
6772 &mut self,
6773 buffer: &Entity<Buffer>,
6774 position: PointUtf16,
6775 cx: &mut Context<Self>,
6776 ) -> Task<Option<Vec<Hover>>> {
6777 if let Some((client, upstream_project_id)) = self.upstream_client() {
6778 let request = GetHover { position };
6779 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6780 return Task::ready(None);
6781 }
6782 let request_task = client.request_lsp(
6783 upstream_project_id,
6784 LSP_REQUEST_TIMEOUT,
6785 cx.background_executor().clone(),
6786 request.to_proto(upstream_project_id, buffer.read(cx)),
6787 );
6788 let buffer = buffer.clone();
6789 cx.spawn(async move |weak_project, cx| {
6790 let project = weak_project.upgrade()?;
6791 let hovers = join_all(
6792 request_task
6793 .await
6794 .log_err()
6795 .flatten()
6796 .map(|response| response.payload)
6797 .unwrap_or_default()
6798 .into_iter()
6799 .map(|response| {
6800 let response = GetHover { position }.response_from_proto(
6801 response.response,
6802 project.clone(),
6803 buffer.clone(),
6804 cx.clone(),
6805 );
6806 async move {
6807 response
6808 .await
6809 .log_err()
6810 .flatten()
6811 .and_then(remove_empty_hover_blocks)
6812 }
6813 }),
6814 )
6815 .await
6816 .into_iter()
6817 .flatten()
6818 .collect();
6819 Some(hovers)
6820 })
6821 } else {
6822 let all_actions_task = self.request_multiple_lsp_locally(
6823 buffer,
6824 Some(position),
6825 GetHover { position },
6826 cx,
6827 );
6828 cx.background_spawn(async move {
6829 Some(
6830 all_actions_task
6831 .await
6832 .into_iter()
6833 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
6834 .collect::<Vec<Hover>>(),
6835 )
6836 })
6837 }
6838 }
6839
6840 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
6841 let language_registry = self.languages.clone();
6842
6843 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
6844 let request = upstream_client.request(proto::GetProjectSymbols {
6845 project_id: *project_id,
6846 query: query.to_string(),
6847 });
6848 cx.foreground_executor().spawn(async move {
6849 let response = request.await?;
6850 let mut symbols = Vec::new();
6851 let core_symbols = response
6852 .symbols
6853 .into_iter()
6854 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
6855 .collect::<Vec<_>>();
6856 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
6857 .await;
6858 Ok(symbols)
6859 })
6860 } else if let Some(local) = self.as_local() {
6861 struct WorkspaceSymbolsResult {
6862 server_id: LanguageServerId,
6863 lsp_adapter: Arc<CachedLspAdapter>,
6864 worktree: WeakEntity<Worktree>,
6865 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
6866 }
6867
6868 let mut requests = Vec::new();
6869 let mut requested_servers = BTreeSet::new();
6870 for (seed, state) in local.language_server_ids.iter() {
6871 let Some(worktree_handle) = self
6872 .worktree_store
6873 .read(cx)
6874 .worktree_for_id(seed.worktree_id, cx)
6875 else {
6876 continue;
6877 };
6878 let worktree = worktree_handle.read(cx);
6879 if !worktree.is_visible() {
6880 continue;
6881 }
6882
6883 if !requested_servers.insert(state.id) {
6884 continue;
6885 }
6886
6887 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
6888 Some(LanguageServerState::Running {
6889 adapter, server, ..
6890 }) => (adapter.clone(), server),
6891
6892 _ => continue,
6893 };
6894 let supports_workspace_symbol_request =
6895 match server.capabilities().workspace_symbol_provider {
6896 Some(OneOf::Left(supported)) => supported,
6897 Some(OneOf::Right(_)) => true,
6898 None => false,
6899 };
6900 if !supports_workspace_symbol_request {
6901 continue;
6902 }
6903 let worktree_handle = worktree_handle.clone();
6904 let server_id = server.server_id();
6905 requests.push(
6906 server
6907 .request::<lsp::request::WorkspaceSymbolRequest>(
6908 lsp::WorkspaceSymbolParams {
6909 query: query.to_string(),
6910 ..Default::default()
6911 },
6912 )
6913 .map(move |response| {
6914 let lsp_symbols = response.into_response()
6915 .context("workspace symbols request")
6916 .log_err()
6917 .flatten()
6918 .map(|symbol_response| match symbol_response {
6919 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
6920 flat_responses.into_iter().map(|lsp_symbol| {
6921 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
6922 }).collect::<Vec<_>>()
6923 }
6924 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
6925 nested_responses.into_iter().filter_map(|lsp_symbol| {
6926 let location = match lsp_symbol.location {
6927 OneOf::Left(location) => location,
6928 OneOf::Right(_) => {
6929 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
6930 return None
6931 }
6932 };
6933 Some((lsp_symbol.name, lsp_symbol.kind, location))
6934 }).collect::<Vec<_>>()
6935 }
6936 }).unwrap_or_default();
6937
6938 WorkspaceSymbolsResult {
6939 server_id,
6940 lsp_adapter,
6941 worktree: worktree_handle.downgrade(),
6942 lsp_symbols,
6943 }
6944 }),
6945 );
6946 }
6947
6948 cx.spawn(async move |this, cx| {
6949 let responses = futures::future::join_all(requests).await;
6950 let this = match this.upgrade() {
6951 Some(this) => this,
6952 None => return Ok(Vec::new()),
6953 };
6954
6955 let mut symbols = Vec::new();
6956 for result in responses {
6957 let core_symbols = this.update(cx, |this, cx| {
6958 result
6959 .lsp_symbols
6960 .into_iter()
6961 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
6962 let abs_path = symbol_location.uri.to_file_path().ok()?;
6963 let source_worktree = result.worktree.upgrade()?;
6964 let source_worktree_id = source_worktree.read(cx).id();
6965
6966 let path = if let Some((tree, rel_path)) =
6967 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
6968 {
6969 let worktree_id = tree.read(cx).id();
6970 SymbolLocation::InProject(ProjectPath {
6971 worktree_id,
6972 path: rel_path,
6973 })
6974 } else {
6975 SymbolLocation::OutsideProject {
6976 signature: this.symbol_signature(&abs_path),
6977 abs_path: abs_path.into(),
6978 }
6979 };
6980
6981 Some(CoreSymbol {
6982 source_language_server_id: result.server_id,
6983 language_server_name: result.lsp_adapter.name.clone(),
6984 source_worktree_id,
6985 path,
6986 kind: symbol_kind,
6987 name: symbol_name,
6988 range: range_from_lsp(symbol_location.range),
6989 })
6990 })
6991 .collect()
6992 })?;
6993
6994 populate_labels_for_symbols(
6995 core_symbols,
6996 &language_registry,
6997 Some(result.lsp_adapter),
6998 &mut symbols,
6999 )
7000 .await;
7001 }
7002
7003 Ok(symbols)
7004 })
7005 } else {
7006 Task::ready(Err(anyhow!("No upstream client or local language server")))
7007 }
7008 }
7009
7010 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7011 let mut summary = DiagnosticSummary::default();
7012 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7013 summary.error_count += path_summary.error_count;
7014 summary.warning_count += path_summary.warning_count;
7015 }
7016 summary
7017 }
7018
7019 /// Returns the diagnostic summary for a specific project path.
7020 pub fn diagnostic_summary_for_path(
7021 &self,
7022 project_path: &ProjectPath,
7023 _: &App,
7024 ) -> DiagnosticSummary {
7025 if let Some(summaries) = self
7026 .diagnostic_summaries
7027 .get(&project_path.worktree_id)
7028 .and_then(|map| map.get(&project_path.path))
7029 {
7030 let (error_count, warning_count) = summaries.iter().fold(
7031 (0, 0),
7032 |(error_count, warning_count), (_language_server_id, summary)| {
7033 (
7034 error_count + summary.error_count,
7035 warning_count + summary.warning_count,
7036 )
7037 },
7038 );
7039
7040 DiagnosticSummary {
7041 error_count,
7042 warning_count,
7043 }
7044 } else {
7045 DiagnosticSummary::default()
7046 }
7047 }
7048
7049 pub fn diagnostic_summaries<'a>(
7050 &'a self,
7051 include_ignored: bool,
7052 cx: &'a App,
7053 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7054 self.worktree_store
7055 .read(cx)
7056 .visible_worktrees(cx)
7057 .filter_map(|worktree| {
7058 let worktree = worktree.read(cx);
7059 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7060 })
7061 .flat_map(move |(worktree, summaries)| {
7062 let worktree_id = worktree.id();
7063 summaries
7064 .iter()
7065 .filter(move |(path, _)| {
7066 include_ignored
7067 || worktree
7068 .entry_for_path(path.as_ref())
7069 .is_some_and(|entry| !entry.is_ignored)
7070 })
7071 .flat_map(move |(path, summaries)| {
7072 summaries.iter().map(move |(server_id, summary)| {
7073 (
7074 ProjectPath {
7075 worktree_id,
7076 path: path.clone(),
7077 },
7078 *server_id,
7079 *summary,
7080 )
7081 })
7082 })
7083 })
7084 }
7085
7086 pub fn on_buffer_edited(
7087 &mut self,
7088 buffer: Entity<Buffer>,
7089 cx: &mut Context<Self>,
7090 ) -> Option<()> {
7091 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7092 Some(
7093 self.as_local()?
7094 .language_servers_for_buffer(buffer, cx)
7095 .map(|i| i.1.clone())
7096 .collect(),
7097 )
7098 })?;
7099
7100 let buffer = buffer.read(cx);
7101 let file = File::from_dyn(buffer.file())?;
7102 let abs_path = file.as_local()?.abs_path(cx);
7103 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7104 let next_snapshot = buffer.text_snapshot();
7105 for language_server in language_servers {
7106 let language_server = language_server.clone();
7107
7108 let buffer_snapshots = self
7109 .as_local_mut()
7110 .unwrap()
7111 .buffer_snapshots
7112 .get_mut(&buffer.remote_id())
7113 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7114 let previous_snapshot = buffer_snapshots.last()?;
7115
7116 let build_incremental_change = || {
7117 buffer
7118 .edits_since::<Dimensions<PointUtf16, usize>>(
7119 previous_snapshot.snapshot.version(),
7120 )
7121 .map(|edit| {
7122 let edit_start = edit.new.start.0;
7123 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7124 let new_text = next_snapshot
7125 .text_for_range(edit.new.start.1..edit.new.end.1)
7126 .collect();
7127 lsp::TextDocumentContentChangeEvent {
7128 range: Some(lsp::Range::new(
7129 point_to_lsp(edit_start),
7130 point_to_lsp(edit_end),
7131 )),
7132 range_length: None,
7133 text: new_text,
7134 }
7135 })
7136 .collect()
7137 };
7138
7139 let document_sync_kind = language_server
7140 .capabilities()
7141 .text_document_sync
7142 .as_ref()
7143 .and_then(|sync| match sync {
7144 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7145 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7146 });
7147
7148 let content_changes: Vec<_> = match document_sync_kind {
7149 Some(lsp::TextDocumentSyncKind::FULL) => {
7150 vec![lsp::TextDocumentContentChangeEvent {
7151 range: None,
7152 range_length: None,
7153 text: next_snapshot.text(),
7154 }]
7155 }
7156 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7157 _ => {
7158 #[cfg(any(test, feature = "test-support"))]
7159 {
7160 build_incremental_change()
7161 }
7162
7163 #[cfg(not(any(test, feature = "test-support")))]
7164 {
7165 continue;
7166 }
7167 }
7168 };
7169
7170 let next_version = previous_snapshot.version + 1;
7171 buffer_snapshots.push(LspBufferSnapshot {
7172 version: next_version,
7173 snapshot: next_snapshot.clone(),
7174 });
7175
7176 language_server
7177 .notify::<lsp::notification::DidChangeTextDocument>(
7178 &lsp::DidChangeTextDocumentParams {
7179 text_document: lsp::VersionedTextDocumentIdentifier::new(
7180 uri.clone(),
7181 next_version,
7182 ),
7183 content_changes,
7184 },
7185 )
7186 .ok();
7187 self.pull_workspace_diagnostics(language_server.server_id());
7188 }
7189
7190 None
7191 }
7192
7193 pub fn on_buffer_saved(
7194 &mut self,
7195 buffer: Entity<Buffer>,
7196 cx: &mut Context<Self>,
7197 ) -> Option<()> {
7198 let file = File::from_dyn(buffer.read(cx).file())?;
7199 let worktree_id = file.worktree_id(cx);
7200 let abs_path = file.as_local()?.abs_path(cx);
7201 let text_document = lsp::TextDocumentIdentifier {
7202 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7203 };
7204 let local = self.as_local()?;
7205
7206 for server in local.language_servers_for_worktree(worktree_id) {
7207 if let Some(include_text) = include_text(server.as_ref()) {
7208 let text = if include_text {
7209 Some(buffer.read(cx).text())
7210 } else {
7211 None
7212 };
7213 server
7214 .notify::<lsp::notification::DidSaveTextDocument>(
7215 &lsp::DidSaveTextDocumentParams {
7216 text_document: text_document.clone(),
7217 text,
7218 },
7219 )
7220 .ok();
7221 }
7222 }
7223
7224 let language_servers = buffer.update(cx, |buffer, cx| {
7225 local.language_server_ids_for_buffer(buffer, cx)
7226 });
7227 for language_server_id in language_servers {
7228 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7229 }
7230
7231 None
7232 }
7233
7234 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7235 maybe!(async move {
7236 let mut refreshed_servers = HashSet::default();
7237 let servers = lsp_store
7238 .update(cx, |lsp_store, cx| {
7239 let local = lsp_store.as_local()?;
7240
7241 let servers = local
7242 .language_server_ids
7243 .iter()
7244 .filter_map(|(seed, state)| {
7245 let worktree = lsp_store
7246 .worktree_store
7247 .read(cx)
7248 .worktree_for_id(seed.worktree_id, cx);
7249 let delegate: Arc<dyn LspAdapterDelegate> =
7250 worktree.map(|worktree| {
7251 LocalLspAdapterDelegate::new(
7252 local.languages.clone(),
7253 &local.environment,
7254 cx.weak_entity(),
7255 &worktree,
7256 local.http_client.clone(),
7257 local.fs.clone(),
7258 cx,
7259 )
7260 })?;
7261 let server_id = state.id;
7262
7263 let states = local.language_servers.get(&server_id)?;
7264
7265 match states {
7266 LanguageServerState::Starting { .. } => None,
7267 LanguageServerState::Running {
7268 adapter, server, ..
7269 } => {
7270 let adapter = adapter.clone();
7271 let server = server.clone();
7272 refreshed_servers.insert(server.name());
7273 let toolchain = seed.toolchain.clone();
7274 Some(cx.spawn(async move |_, cx| {
7275 let settings =
7276 LocalLspStore::workspace_configuration_for_adapter(
7277 adapter.adapter.clone(),
7278 &delegate,
7279 toolchain,
7280 cx,
7281 )
7282 .await
7283 .ok()?;
7284 server
7285 .notify::<lsp::notification::DidChangeConfiguration>(
7286 &lsp::DidChangeConfigurationParams { settings },
7287 )
7288 .ok()?;
7289 Some(())
7290 }))
7291 }
7292 }
7293 })
7294 .collect::<Vec<_>>();
7295
7296 Some(servers)
7297 })
7298 .ok()
7299 .flatten()?;
7300
7301 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7302 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7303 // to stop and unregister its language server wrapper.
7304 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7305 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7306 let _: Vec<Option<()>> = join_all(servers).await;
7307
7308 Some(())
7309 })
7310 .await;
7311 }
7312
7313 fn maintain_workspace_config(
7314 external_refresh_requests: watch::Receiver<()>,
7315 cx: &mut Context<Self>,
7316 ) -> Task<Result<()>> {
7317 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7318 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7319
7320 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7321 *settings_changed_tx.borrow_mut() = ();
7322 });
7323
7324 let mut joint_future =
7325 futures::stream::select(settings_changed_rx, external_refresh_requests);
7326 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7327 // - We might shut down a language server if it's no longer enabled for a given language (and there are no buffers using it otherwise).
7328 // - We might also shut it down when the workspace configuration of all of the users of a given language server converges onto that of the other.
7329 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7330 // - In the easiest case (where we're not wrangling the lifetime of a language server anyhow), if none of the roots of a single language server diverge in their configuration,
7331 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7332 cx.spawn(async move |this, cx| {
7333 while let Some(()) = joint_future.next().await {
7334 this.update(cx, |this, cx| {
7335 this.refresh_server_tree(cx);
7336 })
7337 .ok();
7338
7339 Self::refresh_workspace_configurations(&this, cx).await;
7340 }
7341
7342 drop(settings_observation);
7343 anyhow::Ok(())
7344 })
7345 }
7346
7347 pub fn language_servers_for_local_buffer<'a>(
7348 &'a self,
7349 buffer: &Buffer,
7350 cx: &mut App,
7351 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7352 let local = self.as_local();
7353 let language_server_ids = local
7354 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7355 .unwrap_or_default();
7356
7357 language_server_ids
7358 .into_iter()
7359 .filter_map(
7360 move |server_id| match local?.language_servers.get(&server_id)? {
7361 LanguageServerState::Running {
7362 adapter, server, ..
7363 } => Some((adapter, server)),
7364 _ => None,
7365 },
7366 )
7367 }
7368
7369 pub fn language_server_for_local_buffer<'a>(
7370 &'a self,
7371 buffer: &'a Buffer,
7372 server_id: LanguageServerId,
7373 cx: &'a mut App,
7374 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7375 self.as_local()?
7376 .language_servers_for_buffer(buffer, cx)
7377 .find(|(_, s)| s.server_id() == server_id)
7378 }
7379
7380 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7381 self.diagnostic_summaries.remove(&id_to_remove);
7382 if let Some(local) = self.as_local_mut() {
7383 let to_remove = local.remove_worktree(id_to_remove, cx);
7384 for server in to_remove {
7385 self.language_server_statuses.remove(&server);
7386 }
7387 }
7388 }
7389
7390 pub fn shared(
7391 &mut self,
7392 project_id: u64,
7393 downstream_client: AnyProtoClient,
7394 _: &mut Context<Self>,
7395 ) {
7396 self.downstream_client = Some((downstream_client.clone(), project_id));
7397
7398 for (server_id, status) in &self.language_server_statuses {
7399 if let Some(server) = self.language_server_for_id(*server_id) {
7400 downstream_client
7401 .send(proto::StartLanguageServer {
7402 project_id,
7403 server: Some(proto::LanguageServer {
7404 id: server_id.to_proto(),
7405 name: status.name.to_string(),
7406 worktree_id: status.worktree.map(|id| id.to_proto()),
7407 }),
7408 capabilities: serde_json::to_string(&server.capabilities())
7409 .expect("serializing server LSP capabilities"),
7410 })
7411 .log_err();
7412 }
7413 }
7414 }
7415
7416 pub fn disconnected_from_host(&mut self) {
7417 self.downstream_client.take();
7418 }
7419
7420 pub fn disconnected_from_ssh_remote(&mut self) {
7421 if let LspStoreMode::Remote(RemoteLspStore {
7422 upstream_client, ..
7423 }) = &mut self.mode
7424 {
7425 upstream_client.take();
7426 }
7427 }
7428
7429 pub(crate) fn set_language_server_statuses_from_proto(
7430 &mut self,
7431 project: WeakEntity<Project>,
7432 language_servers: Vec<proto::LanguageServer>,
7433 server_capabilities: Vec<String>,
7434 cx: &mut Context<Self>,
7435 ) {
7436 let lsp_logs = cx
7437 .try_global::<GlobalLogStore>()
7438 .map(|lsp_store| lsp_store.0.clone());
7439
7440 self.language_server_statuses = language_servers
7441 .into_iter()
7442 .zip(server_capabilities)
7443 .map(|(server, server_capabilities)| {
7444 let server_id = LanguageServerId(server.id as usize);
7445 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7446 self.lsp_server_capabilities
7447 .insert(server_id, server_capabilities);
7448 }
7449
7450 let name = LanguageServerName::from_proto(server.name);
7451 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7452
7453 if let Some(lsp_logs) = &lsp_logs {
7454 lsp_logs.update(cx, |lsp_logs, cx| {
7455 lsp_logs.add_language_server(
7456 // Only remote clients get their language servers set from proto
7457 LanguageServerKind::Remote {
7458 project: project.clone(),
7459 },
7460 server_id,
7461 Some(name.clone()),
7462 worktree,
7463 None,
7464 cx,
7465 );
7466 });
7467 }
7468
7469 (
7470 server_id,
7471 LanguageServerStatus {
7472 name,
7473 pending_work: Default::default(),
7474 has_pending_diagnostic_updates: false,
7475 progress_tokens: Default::default(),
7476 worktree,
7477 },
7478 )
7479 })
7480 .collect();
7481 }
7482
7483 #[cfg(test)]
7484 pub fn update_diagnostic_entries(
7485 &mut self,
7486 server_id: LanguageServerId,
7487 abs_path: PathBuf,
7488 result_id: Option<String>,
7489 version: Option<i32>,
7490 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7491 cx: &mut Context<Self>,
7492 ) -> anyhow::Result<()> {
7493 self.merge_diagnostic_entries(
7494 vec![DocumentDiagnosticsUpdate {
7495 diagnostics: DocumentDiagnostics {
7496 diagnostics,
7497 document_abs_path: abs_path,
7498 version,
7499 },
7500 result_id,
7501 server_id,
7502 disk_based_sources: Cow::Borrowed(&[]),
7503 }],
7504 |_, _, _| false,
7505 cx,
7506 )?;
7507 Ok(())
7508 }
7509
7510 pub fn merge_diagnostic_entries<'a>(
7511 &mut self,
7512 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7513 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7514 cx: &mut Context<Self>,
7515 ) -> anyhow::Result<()> {
7516 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7517 let mut updated_diagnostics_paths = HashMap::default();
7518 for mut update in diagnostic_updates {
7519 let abs_path = &update.diagnostics.document_abs_path;
7520 let server_id = update.server_id;
7521 let Some((worktree, relative_path)) =
7522 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7523 else {
7524 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7525 return Ok(());
7526 };
7527
7528 let worktree_id = worktree.read(cx).id();
7529 let project_path = ProjectPath {
7530 worktree_id,
7531 path: relative_path,
7532 };
7533
7534 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7535 let snapshot = buffer_handle.read(cx).snapshot();
7536 let buffer = buffer_handle.read(cx);
7537 let reused_diagnostics = buffer
7538 .buffer_diagnostics(Some(server_id))
7539 .iter()
7540 .filter(|v| merge(buffer, &v.diagnostic, cx))
7541 .map(|v| {
7542 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7543 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7544 DiagnosticEntry {
7545 range: start..end,
7546 diagnostic: v.diagnostic.clone(),
7547 }
7548 })
7549 .collect::<Vec<_>>();
7550
7551 self.as_local_mut()
7552 .context("cannot merge diagnostics on a remote LspStore")?
7553 .update_buffer_diagnostics(
7554 &buffer_handle,
7555 server_id,
7556 update.result_id,
7557 update.diagnostics.version,
7558 update.diagnostics.diagnostics.clone(),
7559 reused_diagnostics.clone(),
7560 cx,
7561 )?;
7562
7563 update.diagnostics.diagnostics.extend(reused_diagnostics);
7564 }
7565
7566 let updated = worktree.update(cx, |worktree, cx| {
7567 self.update_worktree_diagnostics(
7568 worktree.id(),
7569 server_id,
7570 project_path.path.clone(),
7571 update.diagnostics.diagnostics,
7572 cx,
7573 )
7574 })?;
7575 match updated {
7576 ControlFlow::Continue(new_summary) => {
7577 if let Some((project_id, new_summary)) = new_summary {
7578 match &mut diagnostics_summary {
7579 Some(diagnostics_summary) => {
7580 diagnostics_summary
7581 .more_summaries
7582 .push(proto::DiagnosticSummary {
7583 path: project_path.path.as_ref().to_proto(),
7584 language_server_id: server_id.0 as u64,
7585 error_count: new_summary.error_count,
7586 warning_count: new_summary.warning_count,
7587 })
7588 }
7589 None => {
7590 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7591 project_id,
7592 worktree_id: worktree_id.to_proto(),
7593 summary: Some(proto::DiagnosticSummary {
7594 path: project_path.path.as_ref().to_proto(),
7595 language_server_id: server_id.0 as u64,
7596 error_count: new_summary.error_count,
7597 warning_count: new_summary.warning_count,
7598 }),
7599 more_summaries: Vec::new(),
7600 })
7601 }
7602 }
7603 }
7604 updated_diagnostics_paths
7605 .entry(server_id)
7606 .or_insert_with(Vec::new)
7607 .push(project_path);
7608 }
7609 ControlFlow::Break(()) => {}
7610 }
7611 }
7612
7613 if let Some((diagnostics_summary, (downstream_client, _))) =
7614 diagnostics_summary.zip(self.downstream_client.as_ref())
7615 {
7616 downstream_client.send(diagnostics_summary).log_err();
7617 }
7618 for (server_id, paths) in updated_diagnostics_paths {
7619 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7620 }
7621 Ok(())
7622 }
7623
7624 fn update_worktree_diagnostics(
7625 &mut self,
7626 worktree_id: WorktreeId,
7627 server_id: LanguageServerId,
7628 path_in_worktree: Arc<RelPath>,
7629 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7630 _: &mut Context<Worktree>,
7631 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7632 let local = match &mut self.mode {
7633 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7634 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7635 };
7636
7637 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7638 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7639 let summaries_by_server_id = summaries_for_tree
7640 .entry(path_in_worktree.clone())
7641 .or_default();
7642
7643 let old_summary = summaries_by_server_id
7644 .remove(&server_id)
7645 .unwrap_or_default();
7646
7647 let new_summary = DiagnosticSummary::new(&diagnostics);
7648 if new_summary.is_empty() {
7649 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7650 {
7651 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7652 diagnostics_by_server_id.remove(ix);
7653 }
7654 if diagnostics_by_server_id.is_empty() {
7655 diagnostics_for_tree.remove(&path_in_worktree);
7656 }
7657 }
7658 } else {
7659 summaries_by_server_id.insert(server_id, new_summary);
7660 let diagnostics_by_server_id = diagnostics_for_tree
7661 .entry(path_in_worktree.clone())
7662 .or_default();
7663 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7664 Ok(ix) => {
7665 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7666 }
7667 Err(ix) => {
7668 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7669 }
7670 }
7671 }
7672
7673 if !old_summary.is_empty() || !new_summary.is_empty() {
7674 if let Some((_, project_id)) = &self.downstream_client {
7675 Ok(ControlFlow::Continue(Some((
7676 *project_id,
7677 proto::DiagnosticSummary {
7678 path: path_in_worktree.to_proto(),
7679 language_server_id: server_id.0 as u64,
7680 error_count: new_summary.error_count as u32,
7681 warning_count: new_summary.warning_count as u32,
7682 },
7683 ))))
7684 } else {
7685 Ok(ControlFlow::Continue(None))
7686 }
7687 } else {
7688 Ok(ControlFlow::Break(()))
7689 }
7690 }
7691
7692 pub fn open_buffer_for_symbol(
7693 &mut self,
7694 symbol: &Symbol,
7695 cx: &mut Context<Self>,
7696 ) -> Task<Result<Entity<Buffer>>> {
7697 if let Some((client, project_id)) = self.upstream_client() {
7698 let request = client.request(proto::OpenBufferForSymbol {
7699 project_id,
7700 symbol: Some(Self::serialize_symbol(symbol)),
7701 });
7702 cx.spawn(async move |this, cx| {
7703 let response = request.await?;
7704 let buffer_id = BufferId::new(response.buffer_id)?;
7705 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7706 .await
7707 })
7708 } else if let Some(local) = self.as_local() {
7709 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7710 seed.worktree_id == symbol.source_worktree_id
7711 && state.id == symbol.source_language_server_id
7712 && symbol.language_server_name == seed.name
7713 });
7714 if !is_valid {
7715 return Task::ready(Err(anyhow!(
7716 "language server for worktree and language not found"
7717 )));
7718 };
7719
7720 let symbol_abs_path = match &symbol.path {
7721 SymbolLocation::InProject(project_path) => self
7722 .worktree_store
7723 .read(cx)
7724 .absolutize(&project_path, cx)
7725 .context("no such worktree"),
7726 SymbolLocation::OutsideProject {
7727 abs_path,
7728 signature: _,
7729 } => Ok(abs_path.to_path_buf()),
7730 };
7731 let symbol_abs_path = match symbol_abs_path {
7732 Ok(abs_path) => abs_path,
7733 Err(err) => return Task::ready(Err(err)),
7734 };
7735 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
7736 uri
7737 } else {
7738 return Task::ready(Err(anyhow!("invalid symbol path")));
7739 };
7740
7741 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7742 } else {
7743 Task::ready(Err(anyhow!("no upstream client or local store")))
7744 }
7745 }
7746
7747 pub(crate) fn open_local_buffer_via_lsp(
7748 &mut self,
7749 abs_path: lsp::Uri,
7750 language_server_id: LanguageServerId,
7751 cx: &mut Context<Self>,
7752 ) -> Task<Result<Entity<Buffer>>> {
7753 cx.spawn(async move |lsp_store, cx| {
7754 // Escape percent-encoded string.
7755 let current_scheme = abs_path.scheme().to_owned();
7756 // Uri is immutable, so we can't modify the scheme
7757
7758 let abs_path = abs_path
7759 .to_file_path()
7760 .map_err(|()| anyhow!("can't convert URI to path"))?;
7761 let p = abs_path.clone();
7762 let yarn_worktree = lsp_store
7763 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7764 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7765 cx.spawn(async move |this, cx| {
7766 let t = this
7767 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7768 .ok()?;
7769 t.await
7770 })
7771 }),
7772 None => Task::ready(None),
7773 })?
7774 .await;
7775 let (worktree_root_target, known_relative_path) =
7776 if let Some((zip_root, relative_path)) = yarn_worktree {
7777 (zip_root, Some(relative_path))
7778 } else {
7779 (Arc::<Path>::from(abs_path.as_path()), None)
7780 };
7781 let (worktree, relative_path) = if let Some(result) =
7782 lsp_store.update(cx, |lsp_store, cx| {
7783 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7784 worktree_store.find_worktree(&worktree_root_target, cx)
7785 })
7786 })? {
7787 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
7788 (result.0, relative_path)
7789 } else {
7790 let worktree = lsp_store
7791 .update(cx, |lsp_store, cx| {
7792 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7793 worktree_store.create_worktree(&worktree_root_target, false, cx)
7794 })
7795 })?
7796 .await?;
7797 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
7798 lsp_store
7799 .update(cx, |lsp_store, cx| {
7800 if let Some(local) = lsp_store.as_local_mut() {
7801 local.register_language_server_for_invisible_worktree(
7802 &worktree,
7803 language_server_id,
7804 cx,
7805 )
7806 }
7807 })
7808 .ok();
7809 }
7810 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
7811 let relative_path = if let Some(known_path) = known_relative_path {
7812 known_path
7813 } else {
7814 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
7815 .into_arc()
7816 };
7817 (worktree, relative_path)
7818 };
7819 let project_path = ProjectPath {
7820 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
7821 path: relative_path,
7822 };
7823 lsp_store
7824 .update(cx, |lsp_store, cx| {
7825 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
7826 buffer_store.open_buffer(project_path, cx)
7827 })
7828 })?
7829 .await
7830 })
7831 }
7832
7833 fn request_multiple_lsp_locally<P, R>(
7834 &mut self,
7835 buffer: &Entity<Buffer>,
7836 position: Option<P>,
7837 request: R,
7838 cx: &mut Context<Self>,
7839 ) -> Task<Vec<(LanguageServerId, R::Response)>>
7840 where
7841 P: ToOffset,
7842 R: LspCommand + Clone,
7843 <R::LspRequest as lsp::request::Request>::Result: Send,
7844 <R::LspRequest as lsp::request::Request>::Params: Send,
7845 {
7846 let Some(local) = self.as_local() else {
7847 return Task::ready(Vec::new());
7848 };
7849
7850 let snapshot = buffer.read(cx).snapshot();
7851 let scope = position.and_then(|position| snapshot.language_scope_at(position));
7852
7853 let server_ids = buffer.update(cx, |buffer, cx| {
7854 local
7855 .language_servers_for_buffer(buffer, cx)
7856 .filter(|(adapter, _)| {
7857 scope
7858 .as_ref()
7859 .map(|scope| scope.language_allowed(&adapter.name))
7860 .unwrap_or(true)
7861 })
7862 .map(|(_, server)| server.server_id())
7863 .filter(|server_id| {
7864 self.as_local().is_none_or(|local| {
7865 local
7866 .buffers_opened_in_servers
7867 .get(&snapshot.remote_id())
7868 .is_some_and(|servers| servers.contains(server_id))
7869 })
7870 })
7871 .collect::<Vec<_>>()
7872 });
7873
7874 let mut response_results = server_ids
7875 .into_iter()
7876 .map(|server_id| {
7877 let task = self.request_lsp(
7878 buffer.clone(),
7879 LanguageServerToQuery::Other(server_id),
7880 request.clone(),
7881 cx,
7882 );
7883 async move { (server_id, task.await) }
7884 })
7885 .collect::<FuturesUnordered<_>>();
7886
7887 cx.background_spawn(async move {
7888 let mut responses = Vec::with_capacity(response_results.len());
7889 while let Some((server_id, response_result)) = response_results.next().await {
7890 if let Some(response) = response_result.log_err() {
7891 responses.push((server_id, response));
7892 }
7893 }
7894 responses
7895 })
7896 }
7897
7898 async fn handle_lsp_command<T: LspCommand>(
7899 this: Entity<Self>,
7900 envelope: TypedEnvelope<T::ProtoRequest>,
7901 mut cx: AsyncApp,
7902 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
7903 where
7904 <T::LspRequest as lsp::request::Request>::Params: Send,
7905 <T::LspRequest as lsp::request::Request>::Result: Send,
7906 {
7907 let sender_id = envelope.original_sender_id().unwrap_or_default();
7908 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
7909 let buffer_handle = this.update(&mut cx, |this, cx| {
7910 this.buffer_store.read(cx).get_existing(buffer_id)
7911 })??;
7912 let request = T::from_proto(
7913 envelope.payload,
7914 this.clone(),
7915 buffer_handle.clone(),
7916 cx.clone(),
7917 )
7918 .await?;
7919 let response = this
7920 .update(&mut cx, |this, cx| {
7921 this.request_lsp(
7922 buffer_handle.clone(),
7923 LanguageServerToQuery::FirstCapable,
7924 request,
7925 cx,
7926 )
7927 })?
7928 .await?;
7929 this.update(&mut cx, |this, cx| {
7930 Ok(T::response_to_proto(
7931 response,
7932 this,
7933 sender_id,
7934 &buffer_handle.read(cx).version(),
7935 cx,
7936 ))
7937 })?
7938 }
7939
7940 async fn handle_lsp_query(
7941 lsp_store: Entity<Self>,
7942 envelope: TypedEnvelope<proto::LspQuery>,
7943 mut cx: AsyncApp,
7944 ) -> Result<proto::Ack> {
7945 use proto::lsp_query::Request;
7946 let sender_id = envelope.original_sender_id().unwrap_or_default();
7947 let lsp_query = envelope.payload;
7948 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
7949 match lsp_query.request.context("invalid LSP query request")? {
7950 Request::GetReferences(get_references) => {
7951 let position = get_references.position.clone().and_then(deserialize_anchor);
7952 Self::query_lsp_locally::<GetReferences>(
7953 lsp_store,
7954 sender_id,
7955 lsp_request_id,
7956 get_references,
7957 position,
7958 cx.clone(),
7959 )
7960 .await?;
7961 }
7962 Request::GetDocumentColor(get_document_color) => {
7963 Self::query_lsp_locally::<GetDocumentColor>(
7964 lsp_store,
7965 sender_id,
7966 lsp_request_id,
7967 get_document_color,
7968 None,
7969 cx.clone(),
7970 )
7971 .await?;
7972 }
7973 Request::GetHover(get_hover) => {
7974 let position = get_hover.position.clone().and_then(deserialize_anchor);
7975 Self::query_lsp_locally::<GetHover>(
7976 lsp_store,
7977 sender_id,
7978 lsp_request_id,
7979 get_hover,
7980 position,
7981 cx.clone(),
7982 )
7983 .await?;
7984 }
7985 Request::GetCodeActions(get_code_actions) => {
7986 Self::query_lsp_locally::<GetCodeActions>(
7987 lsp_store,
7988 sender_id,
7989 lsp_request_id,
7990 get_code_actions,
7991 None,
7992 cx.clone(),
7993 )
7994 .await?;
7995 }
7996 Request::GetSignatureHelp(get_signature_help) => {
7997 let position = get_signature_help
7998 .position
7999 .clone()
8000 .and_then(deserialize_anchor);
8001 Self::query_lsp_locally::<GetSignatureHelp>(
8002 lsp_store,
8003 sender_id,
8004 lsp_request_id,
8005 get_signature_help,
8006 position,
8007 cx.clone(),
8008 )
8009 .await?;
8010 }
8011 Request::GetCodeLens(get_code_lens) => {
8012 Self::query_lsp_locally::<GetCodeLens>(
8013 lsp_store,
8014 sender_id,
8015 lsp_request_id,
8016 get_code_lens,
8017 None,
8018 cx.clone(),
8019 )
8020 .await?;
8021 }
8022 Request::GetDefinition(get_definition) => {
8023 let position = get_definition.position.clone().and_then(deserialize_anchor);
8024 Self::query_lsp_locally::<GetDefinitions>(
8025 lsp_store,
8026 sender_id,
8027 lsp_request_id,
8028 get_definition,
8029 position,
8030 cx.clone(),
8031 )
8032 .await?;
8033 }
8034 Request::GetDeclaration(get_declaration) => {
8035 let position = get_declaration
8036 .position
8037 .clone()
8038 .and_then(deserialize_anchor);
8039 Self::query_lsp_locally::<GetDeclarations>(
8040 lsp_store,
8041 sender_id,
8042 lsp_request_id,
8043 get_declaration,
8044 position,
8045 cx.clone(),
8046 )
8047 .await?;
8048 }
8049 Request::GetTypeDefinition(get_type_definition) => {
8050 let position = get_type_definition
8051 .position
8052 .clone()
8053 .and_then(deserialize_anchor);
8054 Self::query_lsp_locally::<GetTypeDefinitions>(
8055 lsp_store,
8056 sender_id,
8057 lsp_request_id,
8058 get_type_definition,
8059 position,
8060 cx.clone(),
8061 )
8062 .await?;
8063 }
8064 Request::GetImplementation(get_implementation) => {
8065 let position = get_implementation
8066 .position
8067 .clone()
8068 .and_then(deserialize_anchor);
8069 Self::query_lsp_locally::<GetImplementations>(
8070 lsp_store,
8071 sender_id,
8072 lsp_request_id,
8073 get_implementation,
8074 position,
8075 cx.clone(),
8076 )
8077 .await?;
8078 }
8079 // Diagnostics pull synchronizes internally via the buffer state, and cannot be handled generically as the other requests.
8080 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8081 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8082 let version = deserialize_version(get_document_diagnostics.buffer_version());
8083 let buffer = lsp_store.update(&mut cx, |this, cx| {
8084 this.buffer_store.read(cx).get_existing(buffer_id)
8085 })??;
8086 buffer
8087 .update(&mut cx, |buffer, _| {
8088 buffer.wait_for_version(version.clone())
8089 })?
8090 .await?;
8091 lsp_store.update(&mut cx, |lsp_store, cx| {
8092 let existing_queries = lsp_store
8093 .running_lsp_requests
8094 .entry(TypeId::of::<GetDocumentDiagnostics>())
8095 .or_default();
8096 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8097 ) || buffer.read(cx).version.changed_since(&existing_queries.0)
8098 {
8099 existing_queries.1.clear();
8100 }
8101 existing_queries.1.insert(
8102 lsp_request_id,
8103 cx.spawn(async move |lsp_store, cx| {
8104 let diagnostics_pull = lsp_store
8105 .update(cx, |lsp_store, cx| {
8106 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8107 })
8108 .ok();
8109 if let Some(diagnostics_pull) = diagnostics_pull {
8110 match diagnostics_pull.await {
8111 Ok(()) => {}
8112 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8113 };
8114 }
8115 }),
8116 );
8117 })?;
8118 }
8119 }
8120 Ok(proto::Ack {})
8121 }
8122
8123 async fn handle_lsp_query_response(
8124 lsp_store: Entity<Self>,
8125 envelope: TypedEnvelope<proto::LspQueryResponse>,
8126 cx: AsyncApp,
8127 ) -> Result<()> {
8128 lsp_store.read_with(&cx, |lsp_store, _| {
8129 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8130 upstream_client.handle_lsp_response(envelope.clone());
8131 }
8132 })?;
8133 Ok(())
8134 }
8135
8136 async fn handle_apply_code_action(
8137 this: Entity<Self>,
8138 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8139 mut cx: AsyncApp,
8140 ) -> Result<proto::ApplyCodeActionResponse> {
8141 let sender_id = envelope.original_sender_id().unwrap_or_default();
8142 let action =
8143 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8144 let apply_code_action = this.update(&mut cx, |this, cx| {
8145 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8146 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8147 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8148 })??;
8149
8150 let project_transaction = apply_code_action.await?;
8151 let project_transaction = this.update(&mut cx, |this, cx| {
8152 this.buffer_store.update(cx, |buffer_store, cx| {
8153 buffer_store.serialize_project_transaction_for_peer(
8154 project_transaction,
8155 sender_id,
8156 cx,
8157 )
8158 })
8159 })?;
8160 Ok(proto::ApplyCodeActionResponse {
8161 transaction: Some(project_transaction),
8162 })
8163 }
8164
8165 async fn handle_register_buffer_with_language_servers(
8166 this: Entity<Self>,
8167 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8168 mut cx: AsyncApp,
8169 ) -> Result<proto::Ack> {
8170 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8171 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8172 this.update(&mut cx, |this, cx| {
8173 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8174 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8175 project_id: upstream_project_id,
8176 buffer_id: buffer_id.to_proto(),
8177 only_servers: envelope.payload.only_servers,
8178 });
8179 }
8180
8181 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8182 anyhow::bail!("buffer is not open");
8183 };
8184
8185 let handle = this.register_buffer_with_language_servers(
8186 &buffer,
8187 envelope
8188 .payload
8189 .only_servers
8190 .into_iter()
8191 .filter_map(|selector| {
8192 Some(match selector.selector? {
8193 proto::language_server_selector::Selector::ServerId(server_id) => {
8194 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8195 }
8196 proto::language_server_selector::Selector::Name(name) => {
8197 LanguageServerSelector::Name(LanguageServerName(
8198 SharedString::from(name),
8199 ))
8200 }
8201 })
8202 })
8203 .collect(),
8204 false,
8205 cx,
8206 );
8207 this.buffer_store().update(cx, |buffer_store, _| {
8208 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8209 });
8210
8211 Ok(())
8212 })??;
8213 Ok(proto::Ack {})
8214 }
8215
8216 async fn handle_rename_project_entry(
8217 this: Entity<Self>,
8218 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8219 mut cx: AsyncApp,
8220 ) -> Result<proto::ProjectEntryResponse> {
8221 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8222 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8223 let new_path =
8224 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8225
8226 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8227 .update(&mut cx, |this, cx| {
8228 let (worktree, entry) = this
8229 .worktree_store
8230 .read(cx)
8231 .worktree_and_entry_for_id(entry_id, cx)?;
8232 let new_worktree = this
8233 .worktree_store
8234 .read(cx)
8235 .worktree_for_id(new_worktree_id, cx)?;
8236 Some((
8237 this.worktree_store.clone(),
8238 worktree,
8239 new_worktree,
8240 entry.clone(),
8241 ))
8242 })?
8243 .context("worktree not found")?;
8244 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8245 (worktree.absolutize(&old_entry.path), worktree.id())
8246 })?;
8247 let new_abs_path =
8248 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8249
8250 let _transaction = Self::will_rename_entry(
8251 this.downgrade(),
8252 old_worktree_id,
8253 &old_abs_path,
8254 &new_abs_path,
8255 old_entry.is_dir(),
8256 cx.clone(),
8257 )
8258 .await;
8259 let response = WorktreeStore::handle_rename_project_entry(
8260 worktree_store,
8261 envelope.payload,
8262 cx.clone(),
8263 )
8264 .await;
8265 this.read_with(&cx, |this, _| {
8266 this.did_rename_entry(
8267 old_worktree_id,
8268 &old_abs_path,
8269 &new_abs_path,
8270 old_entry.is_dir(),
8271 );
8272 })
8273 .ok();
8274 response
8275 }
8276
8277 async fn handle_update_diagnostic_summary(
8278 this: Entity<Self>,
8279 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8280 mut cx: AsyncApp,
8281 ) -> Result<()> {
8282 this.update(&mut cx, |lsp_store, cx| {
8283 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8284 let mut updated_diagnostics_paths = HashMap::default();
8285 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8286 for message_summary in envelope
8287 .payload
8288 .summary
8289 .into_iter()
8290 .chain(envelope.payload.more_summaries)
8291 {
8292 let project_path = ProjectPath {
8293 worktree_id,
8294 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8295 };
8296 let path = project_path.path.clone();
8297 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8298 let summary = DiagnosticSummary {
8299 error_count: message_summary.error_count as usize,
8300 warning_count: message_summary.warning_count as usize,
8301 };
8302
8303 if summary.is_empty() {
8304 if let Some(worktree_summaries) =
8305 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8306 && let Some(summaries) = worktree_summaries.get_mut(&path)
8307 {
8308 summaries.remove(&server_id);
8309 if summaries.is_empty() {
8310 worktree_summaries.remove(&path);
8311 }
8312 }
8313 } else {
8314 lsp_store
8315 .diagnostic_summaries
8316 .entry(worktree_id)
8317 .or_default()
8318 .entry(path)
8319 .or_default()
8320 .insert(server_id, summary);
8321 }
8322
8323 if let Some((_, project_id)) = &lsp_store.downstream_client {
8324 match &mut diagnostics_summary {
8325 Some(diagnostics_summary) => {
8326 diagnostics_summary
8327 .more_summaries
8328 .push(proto::DiagnosticSummary {
8329 path: project_path.path.as_ref().to_proto(),
8330 language_server_id: server_id.0 as u64,
8331 error_count: summary.error_count as u32,
8332 warning_count: summary.warning_count as u32,
8333 })
8334 }
8335 None => {
8336 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8337 project_id: *project_id,
8338 worktree_id: worktree_id.to_proto(),
8339 summary: Some(proto::DiagnosticSummary {
8340 path: project_path.path.as_ref().to_proto(),
8341 language_server_id: server_id.0 as u64,
8342 error_count: summary.error_count as u32,
8343 warning_count: summary.warning_count as u32,
8344 }),
8345 more_summaries: Vec::new(),
8346 })
8347 }
8348 }
8349 }
8350 updated_diagnostics_paths
8351 .entry(server_id)
8352 .or_insert_with(Vec::new)
8353 .push(project_path);
8354 }
8355
8356 if let Some((diagnostics_summary, (downstream_client, _))) =
8357 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8358 {
8359 downstream_client.send(diagnostics_summary).log_err();
8360 }
8361 for (server_id, paths) in updated_diagnostics_paths {
8362 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8363 }
8364 Ok(())
8365 })?
8366 }
8367
8368 async fn handle_start_language_server(
8369 lsp_store: Entity<Self>,
8370 envelope: TypedEnvelope<proto::StartLanguageServer>,
8371 mut cx: AsyncApp,
8372 ) -> Result<()> {
8373 let server = envelope.payload.server.context("invalid server")?;
8374 let server_capabilities =
8375 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8376 .with_context(|| {
8377 format!(
8378 "incorrect server capabilities {}",
8379 envelope.payload.capabilities
8380 )
8381 })?;
8382 lsp_store.update(&mut cx, |lsp_store, cx| {
8383 let server_id = LanguageServerId(server.id as usize);
8384 let server_name = LanguageServerName::from_proto(server.name.clone());
8385 lsp_store
8386 .lsp_server_capabilities
8387 .insert(server_id, server_capabilities);
8388 lsp_store.language_server_statuses.insert(
8389 server_id,
8390 LanguageServerStatus {
8391 name: server_name.clone(),
8392 pending_work: Default::default(),
8393 has_pending_diagnostic_updates: false,
8394 progress_tokens: Default::default(),
8395 worktree: server.worktree_id.map(WorktreeId::from_proto),
8396 },
8397 );
8398 cx.emit(LspStoreEvent::LanguageServerAdded(
8399 server_id,
8400 server_name,
8401 server.worktree_id.map(WorktreeId::from_proto),
8402 ));
8403 cx.notify();
8404 })?;
8405 Ok(())
8406 }
8407
8408 async fn handle_update_language_server(
8409 lsp_store: Entity<Self>,
8410 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8411 mut cx: AsyncApp,
8412 ) -> Result<()> {
8413 lsp_store.update(&mut cx, |lsp_store, cx| {
8414 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8415
8416 match envelope.payload.variant.context("invalid variant")? {
8417 proto::update_language_server::Variant::WorkStart(payload) => {
8418 lsp_store.on_lsp_work_start(
8419 language_server_id,
8420 payload.token,
8421 LanguageServerProgress {
8422 title: payload.title,
8423 is_disk_based_diagnostics_progress: false,
8424 is_cancellable: payload.is_cancellable.unwrap_or(false),
8425 message: payload.message,
8426 percentage: payload.percentage.map(|p| p as usize),
8427 last_update_at: cx.background_executor().now(),
8428 },
8429 cx,
8430 );
8431 }
8432 proto::update_language_server::Variant::WorkProgress(payload) => {
8433 lsp_store.on_lsp_work_progress(
8434 language_server_id,
8435 payload.token,
8436 LanguageServerProgress {
8437 title: None,
8438 is_disk_based_diagnostics_progress: false,
8439 is_cancellable: payload.is_cancellable.unwrap_or(false),
8440 message: payload.message,
8441 percentage: payload.percentage.map(|p| p as usize),
8442 last_update_at: cx.background_executor().now(),
8443 },
8444 cx,
8445 );
8446 }
8447
8448 proto::update_language_server::Variant::WorkEnd(payload) => {
8449 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8450 }
8451
8452 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8453 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8454 }
8455
8456 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8457 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8458 }
8459
8460 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8461 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8462 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8463 cx.emit(LspStoreEvent::LanguageServerUpdate {
8464 language_server_id,
8465 name: envelope
8466 .payload
8467 .server_name
8468 .map(SharedString::new)
8469 .map(LanguageServerName),
8470 message: non_lsp,
8471 });
8472 }
8473 }
8474
8475 Ok(())
8476 })?
8477 }
8478
8479 async fn handle_language_server_log(
8480 this: Entity<Self>,
8481 envelope: TypedEnvelope<proto::LanguageServerLog>,
8482 mut cx: AsyncApp,
8483 ) -> Result<()> {
8484 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8485 let log_type = envelope
8486 .payload
8487 .log_type
8488 .map(LanguageServerLogType::from_proto)
8489 .context("invalid language server log type")?;
8490
8491 let message = envelope.payload.message;
8492
8493 this.update(&mut cx, |_, cx| {
8494 cx.emit(LspStoreEvent::LanguageServerLog(
8495 language_server_id,
8496 log_type,
8497 message,
8498 ));
8499 })
8500 }
8501
8502 async fn handle_lsp_ext_cancel_flycheck(
8503 lsp_store: Entity<Self>,
8504 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8505 cx: AsyncApp,
8506 ) -> Result<proto::Ack> {
8507 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8508 lsp_store.read_with(&cx, |lsp_store, _| {
8509 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8510 server
8511 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
8512 .context("handling lsp ext cancel flycheck")
8513 } else {
8514 anyhow::Ok(())
8515 }
8516 })??;
8517
8518 Ok(proto::Ack {})
8519 }
8520
8521 async fn handle_lsp_ext_run_flycheck(
8522 lsp_store: Entity<Self>,
8523 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8524 mut cx: AsyncApp,
8525 ) -> Result<proto::Ack> {
8526 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8527 lsp_store.update(&mut cx, |lsp_store, cx| {
8528 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8529 let text_document = if envelope.payload.current_file_only {
8530 let buffer_id = envelope
8531 .payload
8532 .buffer_id
8533 .map(|id| BufferId::new(id))
8534 .transpose()?;
8535 buffer_id
8536 .and_then(|buffer_id| {
8537 lsp_store
8538 .buffer_store()
8539 .read(cx)
8540 .get(buffer_id)
8541 .and_then(|buffer| {
8542 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
8543 })
8544 .map(|path| make_text_document_identifier(&path))
8545 })
8546 .transpose()?
8547 } else {
8548 None
8549 };
8550 server
8551 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
8552 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
8553 )
8554 .context("handling lsp ext run flycheck")
8555 } else {
8556 anyhow::Ok(())
8557 }
8558 })??;
8559
8560 Ok(proto::Ack {})
8561 }
8562
8563 async fn handle_lsp_ext_clear_flycheck(
8564 lsp_store: Entity<Self>,
8565 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
8566 cx: AsyncApp,
8567 ) -> Result<proto::Ack> {
8568 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8569 lsp_store.read_with(&cx, |lsp_store, _| {
8570 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8571 server
8572 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
8573 .context("handling lsp ext clear flycheck")
8574 } else {
8575 anyhow::Ok(())
8576 }
8577 })??;
8578
8579 Ok(proto::Ack {})
8580 }
8581
8582 pub fn disk_based_diagnostics_started(
8583 &mut self,
8584 language_server_id: LanguageServerId,
8585 cx: &mut Context<Self>,
8586 ) {
8587 if let Some(language_server_status) =
8588 self.language_server_statuses.get_mut(&language_server_id)
8589 {
8590 language_server_status.has_pending_diagnostic_updates = true;
8591 }
8592
8593 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
8594 cx.emit(LspStoreEvent::LanguageServerUpdate {
8595 language_server_id,
8596 name: self
8597 .language_server_adapter_for_id(language_server_id)
8598 .map(|adapter| adapter.name()),
8599 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
8600 Default::default(),
8601 ),
8602 })
8603 }
8604
8605 pub fn disk_based_diagnostics_finished(
8606 &mut self,
8607 language_server_id: LanguageServerId,
8608 cx: &mut Context<Self>,
8609 ) {
8610 if let Some(language_server_status) =
8611 self.language_server_statuses.get_mut(&language_server_id)
8612 {
8613 language_server_status.has_pending_diagnostic_updates = false;
8614 }
8615
8616 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
8617 cx.emit(LspStoreEvent::LanguageServerUpdate {
8618 language_server_id,
8619 name: self
8620 .language_server_adapter_for_id(language_server_id)
8621 .map(|adapter| adapter.name()),
8622 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
8623 Default::default(),
8624 ),
8625 })
8626 }
8627
8628 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
8629 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
8630 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
8631 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
8632 // the language server might take some time to publish diagnostics.
8633 fn simulate_disk_based_diagnostics_events_if_needed(
8634 &mut self,
8635 language_server_id: LanguageServerId,
8636 cx: &mut Context<Self>,
8637 ) {
8638 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
8639
8640 let Some(LanguageServerState::Running {
8641 simulate_disk_based_diagnostics_completion,
8642 adapter,
8643 ..
8644 }) = self
8645 .as_local_mut()
8646 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
8647 else {
8648 return;
8649 };
8650
8651 if adapter.disk_based_diagnostics_progress_token.is_some() {
8652 return;
8653 }
8654
8655 let prev_task =
8656 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
8657 cx.background_executor()
8658 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
8659 .await;
8660
8661 this.update(cx, |this, cx| {
8662 this.disk_based_diagnostics_finished(language_server_id, cx);
8663
8664 if let Some(LanguageServerState::Running {
8665 simulate_disk_based_diagnostics_completion,
8666 ..
8667 }) = this.as_local_mut().and_then(|local_store| {
8668 local_store.language_servers.get_mut(&language_server_id)
8669 }) {
8670 *simulate_disk_based_diagnostics_completion = None;
8671 }
8672 })
8673 .ok();
8674 }));
8675
8676 if prev_task.is_none() {
8677 self.disk_based_diagnostics_started(language_server_id, cx);
8678 }
8679 }
8680
8681 pub fn language_server_statuses(
8682 &self,
8683 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
8684 self.language_server_statuses
8685 .iter()
8686 .map(|(key, value)| (*key, value))
8687 }
8688
8689 pub(super) fn did_rename_entry(
8690 &self,
8691 worktree_id: WorktreeId,
8692 old_path: &Path,
8693 new_path: &Path,
8694 is_dir: bool,
8695 ) {
8696 maybe!({
8697 let local_store = self.as_local()?;
8698
8699 let old_uri = lsp::Uri::from_file_path(old_path)
8700 .ok()
8701 .map(|uri| uri.to_string())?;
8702 let new_uri = lsp::Uri::from_file_path(new_path)
8703 .ok()
8704 .map(|uri| uri.to_string())?;
8705
8706 for language_server in local_store.language_servers_for_worktree(worktree_id) {
8707 let Some(filter) = local_store
8708 .language_server_paths_watched_for_rename
8709 .get(&language_server.server_id())
8710 else {
8711 continue;
8712 };
8713
8714 if filter.should_send_did_rename(&old_uri, is_dir) {
8715 language_server
8716 .notify::<DidRenameFiles>(&RenameFilesParams {
8717 files: vec![FileRename {
8718 old_uri: old_uri.clone(),
8719 new_uri: new_uri.clone(),
8720 }],
8721 })
8722 .ok();
8723 }
8724 }
8725 Some(())
8726 });
8727 }
8728
8729 pub(super) fn will_rename_entry(
8730 this: WeakEntity<Self>,
8731 worktree_id: WorktreeId,
8732 old_path: &Path,
8733 new_path: &Path,
8734 is_dir: bool,
8735 cx: AsyncApp,
8736 ) -> Task<ProjectTransaction> {
8737 let old_uri = lsp::Uri::from_file_path(old_path)
8738 .ok()
8739 .map(|uri| uri.to_string());
8740 let new_uri = lsp::Uri::from_file_path(new_path)
8741 .ok()
8742 .map(|uri| uri.to_string());
8743 cx.spawn(async move |cx| {
8744 let mut tasks = vec![];
8745 this.update(cx, |this, cx| {
8746 let local_store = this.as_local()?;
8747 let old_uri = old_uri?;
8748 let new_uri = new_uri?;
8749 for language_server in local_store.language_servers_for_worktree(worktree_id) {
8750 let Some(filter) = local_store
8751 .language_server_paths_watched_for_rename
8752 .get(&language_server.server_id())
8753 else {
8754 continue;
8755 };
8756
8757 if filter.should_send_will_rename(&old_uri, is_dir) {
8758 let apply_edit = cx.spawn({
8759 let old_uri = old_uri.clone();
8760 let new_uri = new_uri.clone();
8761 let language_server = language_server.clone();
8762 async move |this, cx| {
8763 let edit = language_server
8764 .request::<WillRenameFiles>(RenameFilesParams {
8765 files: vec![FileRename { old_uri, new_uri }],
8766 })
8767 .await
8768 .into_response()
8769 .context("will rename files")
8770 .log_err()
8771 .flatten()?;
8772
8773 let transaction = LocalLspStore::deserialize_workspace_edit(
8774 this.upgrade()?,
8775 edit,
8776 false,
8777 language_server.clone(),
8778 cx,
8779 )
8780 .await
8781 .ok()?;
8782 Some(transaction)
8783 }
8784 });
8785 tasks.push(apply_edit);
8786 }
8787 }
8788 Some(())
8789 })
8790 .ok()
8791 .flatten();
8792 let mut merged_transaction = ProjectTransaction::default();
8793 for task in tasks {
8794 // Await on tasks sequentially so that the order of application of edits is deterministic
8795 // (at least with regards to the order of registration of language servers)
8796 if let Some(transaction) = task.await {
8797 for (buffer, buffer_transaction) in transaction.0 {
8798 merged_transaction.0.insert(buffer, buffer_transaction);
8799 }
8800 }
8801 }
8802 merged_transaction
8803 })
8804 }
8805
8806 fn lsp_notify_abs_paths_changed(
8807 &mut self,
8808 server_id: LanguageServerId,
8809 changes: Vec<PathEvent>,
8810 ) {
8811 maybe!({
8812 let server = self.language_server_for_id(server_id)?;
8813 let changes = changes
8814 .into_iter()
8815 .filter_map(|event| {
8816 let typ = match event.kind? {
8817 PathEventKind::Created => lsp::FileChangeType::CREATED,
8818 PathEventKind::Removed => lsp::FileChangeType::DELETED,
8819 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
8820 };
8821 Some(lsp::FileEvent {
8822 uri: file_path_to_lsp_url(&event.path).log_err()?,
8823 typ,
8824 })
8825 })
8826 .collect::<Vec<_>>();
8827 if !changes.is_empty() {
8828 server
8829 .notify::<lsp::notification::DidChangeWatchedFiles>(
8830 &lsp::DidChangeWatchedFilesParams { changes },
8831 )
8832 .ok();
8833 }
8834 Some(())
8835 });
8836 }
8837
8838 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
8839 self.as_local()?.language_server_for_id(id)
8840 }
8841
8842 fn on_lsp_progress(
8843 &mut self,
8844 progress: lsp::ProgressParams,
8845 language_server_id: LanguageServerId,
8846 disk_based_diagnostics_progress_token: Option<String>,
8847 cx: &mut Context<Self>,
8848 ) {
8849 let token = match progress.token {
8850 lsp::NumberOrString::String(token) => token,
8851 lsp::NumberOrString::Number(token) => {
8852 log::info!("skipping numeric progress token {}", token);
8853 return;
8854 }
8855 };
8856
8857 match progress.value {
8858 lsp::ProgressParamsValue::WorkDone(progress) => {
8859 self.handle_work_done_progress(
8860 progress,
8861 language_server_id,
8862 disk_based_diagnostics_progress_token,
8863 token,
8864 cx,
8865 );
8866 }
8867 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
8868 if let Some(LanguageServerState::Running {
8869 workspace_refresh_task: Some(workspace_refresh_task),
8870 ..
8871 }) = self
8872 .as_local_mut()
8873 .and_then(|local| local.language_servers.get_mut(&language_server_id))
8874 {
8875 workspace_refresh_task.progress_tx.try_send(()).ok();
8876 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
8877 }
8878 }
8879 }
8880 }
8881
8882 fn handle_work_done_progress(
8883 &mut self,
8884 progress: lsp::WorkDoneProgress,
8885 language_server_id: LanguageServerId,
8886 disk_based_diagnostics_progress_token: Option<String>,
8887 token: String,
8888 cx: &mut Context<Self>,
8889 ) {
8890 let language_server_status =
8891 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
8892 status
8893 } else {
8894 return;
8895 };
8896
8897 if !language_server_status.progress_tokens.contains(&token) {
8898 return;
8899 }
8900
8901 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
8902 .as_ref()
8903 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
8904
8905 match progress {
8906 lsp::WorkDoneProgress::Begin(report) => {
8907 if is_disk_based_diagnostics_progress {
8908 self.disk_based_diagnostics_started(language_server_id, cx);
8909 }
8910 self.on_lsp_work_start(
8911 language_server_id,
8912 token.clone(),
8913 LanguageServerProgress {
8914 title: Some(report.title),
8915 is_disk_based_diagnostics_progress,
8916 is_cancellable: report.cancellable.unwrap_or(false),
8917 message: report.message.clone(),
8918 percentage: report.percentage.map(|p| p as usize),
8919 last_update_at: cx.background_executor().now(),
8920 },
8921 cx,
8922 );
8923 }
8924 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
8925 language_server_id,
8926 token,
8927 LanguageServerProgress {
8928 title: None,
8929 is_disk_based_diagnostics_progress,
8930 is_cancellable: report.cancellable.unwrap_or(false),
8931 message: report.message,
8932 percentage: report.percentage.map(|p| p as usize),
8933 last_update_at: cx.background_executor().now(),
8934 },
8935 cx,
8936 ),
8937 lsp::WorkDoneProgress::End(_) => {
8938 language_server_status.progress_tokens.remove(&token);
8939 self.on_lsp_work_end(language_server_id, token.clone(), cx);
8940 if is_disk_based_diagnostics_progress {
8941 self.disk_based_diagnostics_finished(language_server_id, cx);
8942 }
8943 }
8944 }
8945 }
8946
8947 fn on_lsp_work_start(
8948 &mut self,
8949 language_server_id: LanguageServerId,
8950 token: String,
8951 progress: LanguageServerProgress,
8952 cx: &mut Context<Self>,
8953 ) {
8954 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
8955 status.pending_work.insert(token.clone(), progress.clone());
8956 cx.notify();
8957 }
8958 cx.emit(LspStoreEvent::LanguageServerUpdate {
8959 language_server_id,
8960 name: self
8961 .language_server_adapter_for_id(language_server_id)
8962 .map(|adapter| adapter.name()),
8963 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
8964 token,
8965 title: progress.title,
8966 message: progress.message,
8967 percentage: progress.percentage.map(|p| p as u32),
8968 is_cancellable: Some(progress.is_cancellable),
8969 }),
8970 })
8971 }
8972
8973 fn on_lsp_work_progress(
8974 &mut self,
8975 language_server_id: LanguageServerId,
8976 token: String,
8977 progress: LanguageServerProgress,
8978 cx: &mut Context<Self>,
8979 ) {
8980 let mut did_update = false;
8981 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
8982 match status.pending_work.entry(token.clone()) {
8983 btree_map::Entry::Vacant(entry) => {
8984 entry.insert(progress.clone());
8985 did_update = true;
8986 }
8987 btree_map::Entry::Occupied(mut entry) => {
8988 let entry = entry.get_mut();
8989 if (progress.last_update_at - entry.last_update_at)
8990 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
8991 {
8992 entry.last_update_at = progress.last_update_at;
8993 if progress.message.is_some() {
8994 entry.message = progress.message.clone();
8995 }
8996 if progress.percentage.is_some() {
8997 entry.percentage = progress.percentage;
8998 }
8999 if progress.is_cancellable != entry.is_cancellable {
9000 entry.is_cancellable = progress.is_cancellable;
9001 }
9002 did_update = true;
9003 }
9004 }
9005 }
9006 }
9007
9008 if did_update {
9009 cx.emit(LspStoreEvent::LanguageServerUpdate {
9010 language_server_id,
9011 name: self
9012 .language_server_adapter_for_id(language_server_id)
9013 .map(|adapter| adapter.name()),
9014 message: proto::update_language_server::Variant::WorkProgress(
9015 proto::LspWorkProgress {
9016 token,
9017 message: progress.message,
9018 percentage: progress.percentage.map(|p| p as u32),
9019 is_cancellable: Some(progress.is_cancellable),
9020 },
9021 ),
9022 })
9023 }
9024 }
9025
9026 fn on_lsp_work_end(
9027 &mut self,
9028 language_server_id: LanguageServerId,
9029 token: String,
9030 cx: &mut Context<Self>,
9031 ) {
9032 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9033 if let Some(work) = status.pending_work.remove(&token)
9034 && !work.is_disk_based_diagnostics_progress
9035 {
9036 cx.emit(LspStoreEvent::RefreshInlayHints);
9037 }
9038 cx.notify();
9039 }
9040
9041 cx.emit(LspStoreEvent::LanguageServerUpdate {
9042 language_server_id,
9043 name: self
9044 .language_server_adapter_for_id(language_server_id)
9045 .map(|adapter| adapter.name()),
9046 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9047 })
9048 }
9049
9050 pub async fn handle_resolve_completion_documentation(
9051 this: Entity<Self>,
9052 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9053 mut cx: AsyncApp,
9054 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9055 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9056
9057 let completion = this
9058 .read_with(&cx, |this, cx| {
9059 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9060 let server = this
9061 .language_server_for_id(id)
9062 .with_context(|| format!("No language server {id}"))?;
9063
9064 anyhow::Ok(cx.background_spawn(async move {
9065 let can_resolve = server
9066 .capabilities()
9067 .completion_provider
9068 .as_ref()
9069 .and_then(|options| options.resolve_provider)
9070 .unwrap_or(false);
9071 if can_resolve {
9072 server
9073 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9074 .await
9075 .into_response()
9076 .context("resolve completion item")
9077 } else {
9078 anyhow::Ok(lsp_completion)
9079 }
9080 }))
9081 })??
9082 .await?;
9083
9084 let mut documentation_is_markdown = false;
9085 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9086 let documentation = match completion.documentation {
9087 Some(lsp::Documentation::String(text)) => text,
9088
9089 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9090 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9091 value
9092 }
9093
9094 _ => String::new(),
9095 };
9096
9097 // If we have a new buffer_id, that means we're talking to a new client
9098 // and want to check for new text_edits in the completion too.
9099 let mut old_replace_start = None;
9100 let mut old_replace_end = None;
9101 let mut old_insert_start = None;
9102 let mut old_insert_end = None;
9103 let mut new_text = String::default();
9104 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9105 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9106 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9107 anyhow::Ok(buffer.read(cx).snapshot())
9108 })??;
9109
9110 if let Some(text_edit) = completion.text_edit.as_ref() {
9111 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9112
9113 if let Some(mut edit) = edit {
9114 LineEnding::normalize(&mut edit.new_text);
9115
9116 new_text = edit.new_text;
9117 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9118 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9119 if let Some(insert_range) = edit.insert_range {
9120 old_insert_start = Some(serialize_anchor(&insert_range.start));
9121 old_insert_end = Some(serialize_anchor(&insert_range.end));
9122 }
9123 }
9124 }
9125 }
9126
9127 Ok(proto::ResolveCompletionDocumentationResponse {
9128 documentation,
9129 documentation_is_markdown,
9130 old_replace_start,
9131 old_replace_end,
9132 new_text,
9133 lsp_completion,
9134 old_insert_start,
9135 old_insert_end,
9136 })
9137 }
9138
9139 async fn handle_on_type_formatting(
9140 this: Entity<Self>,
9141 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9142 mut cx: AsyncApp,
9143 ) -> Result<proto::OnTypeFormattingResponse> {
9144 let on_type_formatting = this.update(&mut cx, |this, cx| {
9145 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9146 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9147 let position = envelope
9148 .payload
9149 .position
9150 .and_then(deserialize_anchor)
9151 .context("invalid position")?;
9152 anyhow::Ok(this.apply_on_type_formatting(
9153 buffer,
9154 position,
9155 envelope.payload.trigger.clone(),
9156 cx,
9157 ))
9158 })??;
9159
9160 let transaction = on_type_formatting
9161 .await?
9162 .as_ref()
9163 .map(language::proto::serialize_transaction);
9164 Ok(proto::OnTypeFormattingResponse { transaction })
9165 }
9166
9167 async fn handle_refresh_inlay_hints(
9168 this: Entity<Self>,
9169 _: TypedEnvelope<proto::RefreshInlayHints>,
9170 mut cx: AsyncApp,
9171 ) -> Result<proto::Ack> {
9172 this.update(&mut cx, |_, cx| {
9173 cx.emit(LspStoreEvent::RefreshInlayHints);
9174 })?;
9175 Ok(proto::Ack {})
9176 }
9177
9178 async fn handle_pull_workspace_diagnostics(
9179 lsp_store: Entity<Self>,
9180 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9181 mut cx: AsyncApp,
9182 ) -> Result<proto::Ack> {
9183 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9184 lsp_store.update(&mut cx, |lsp_store, _| {
9185 lsp_store.pull_workspace_diagnostics(server_id);
9186 })?;
9187 Ok(proto::Ack {})
9188 }
9189
9190 async fn handle_inlay_hints(
9191 this: Entity<Self>,
9192 envelope: TypedEnvelope<proto::InlayHints>,
9193 mut cx: AsyncApp,
9194 ) -> Result<proto::InlayHintsResponse> {
9195 let sender_id = envelope.original_sender_id().unwrap_or_default();
9196 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9197 let buffer = this.update(&mut cx, |this, cx| {
9198 this.buffer_store.read(cx).get_existing(buffer_id)
9199 })??;
9200 buffer
9201 .update(&mut cx, |buffer, _| {
9202 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9203 })?
9204 .await
9205 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9206
9207 let start = envelope
9208 .payload
9209 .start
9210 .and_then(deserialize_anchor)
9211 .context("missing range start")?;
9212 let end = envelope
9213 .payload
9214 .end
9215 .and_then(deserialize_anchor)
9216 .context("missing range end")?;
9217 let buffer_hints = this
9218 .update(&mut cx, |lsp_store, cx| {
9219 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9220 })?
9221 .await
9222 .context("inlay hints fetch")?;
9223
9224 this.update(&mut cx, |project, cx| {
9225 InlayHints::response_to_proto(
9226 buffer_hints,
9227 project,
9228 sender_id,
9229 &buffer.read(cx).version(),
9230 cx,
9231 )
9232 })
9233 }
9234
9235 async fn handle_get_color_presentation(
9236 lsp_store: Entity<Self>,
9237 envelope: TypedEnvelope<proto::GetColorPresentation>,
9238 mut cx: AsyncApp,
9239 ) -> Result<proto::GetColorPresentationResponse> {
9240 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9241 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9242 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9243 })??;
9244
9245 let color = envelope
9246 .payload
9247 .color
9248 .context("invalid color resolve request")?;
9249 let start = color
9250 .lsp_range_start
9251 .context("invalid color resolve request")?;
9252 let end = color
9253 .lsp_range_end
9254 .context("invalid color resolve request")?;
9255
9256 let color = DocumentColor {
9257 lsp_range: lsp::Range {
9258 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9259 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9260 },
9261 color: lsp::Color {
9262 red: color.red,
9263 green: color.green,
9264 blue: color.blue,
9265 alpha: color.alpha,
9266 },
9267 resolved: false,
9268 color_presentations: Vec::new(),
9269 };
9270 let resolved_color = lsp_store
9271 .update(&mut cx, |lsp_store, cx| {
9272 lsp_store.resolve_color_presentation(
9273 color,
9274 buffer.clone(),
9275 LanguageServerId(envelope.payload.server_id as usize),
9276 cx,
9277 )
9278 })?
9279 .await
9280 .context("resolving color presentation")?;
9281
9282 Ok(proto::GetColorPresentationResponse {
9283 presentations: resolved_color
9284 .color_presentations
9285 .into_iter()
9286 .map(|presentation| proto::ColorPresentation {
9287 label: presentation.label.to_string(),
9288 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9289 additional_text_edits: presentation
9290 .additional_text_edits
9291 .into_iter()
9292 .map(serialize_lsp_edit)
9293 .collect(),
9294 })
9295 .collect(),
9296 })
9297 }
9298
9299 async fn handle_resolve_inlay_hint(
9300 this: Entity<Self>,
9301 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9302 mut cx: AsyncApp,
9303 ) -> Result<proto::ResolveInlayHintResponse> {
9304 let proto_hint = envelope
9305 .payload
9306 .hint
9307 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9308 let hint = InlayHints::proto_to_project_hint(proto_hint)
9309 .context("resolved proto inlay hint conversion")?;
9310 let buffer = this.update(&mut cx, |this, cx| {
9311 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9312 this.buffer_store.read(cx).get_existing(buffer_id)
9313 })??;
9314 let response_hint = this
9315 .update(&mut cx, |this, cx| {
9316 this.resolve_inlay_hint(
9317 hint,
9318 buffer,
9319 LanguageServerId(envelope.payload.language_server_id as usize),
9320 cx,
9321 )
9322 })?
9323 .await
9324 .context("inlay hints fetch")?;
9325 Ok(proto::ResolveInlayHintResponse {
9326 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9327 })
9328 }
9329
9330 async fn handle_refresh_code_lens(
9331 this: Entity<Self>,
9332 _: TypedEnvelope<proto::RefreshCodeLens>,
9333 mut cx: AsyncApp,
9334 ) -> Result<proto::Ack> {
9335 this.update(&mut cx, |_, cx| {
9336 cx.emit(LspStoreEvent::RefreshCodeLens);
9337 })?;
9338 Ok(proto::Ack {})
9339 }
9340
9341 async fn handle_open_buffer_for_symbol(
9342 this: Entity<Self>,
9343 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9344 mut cx: AsyncApp,
9345 ) -> Result<proto::OpenBufferForSymbolResponse> {
9346 let peer_id = envelope.original_sender_id().unwrap_or_default();
9347 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9348 let symbol = Self::deserialize_symbol(symbol)?;
9349 this.read_with(&cx, |this, _| {
9350 if let SymbolLocation::OutsideProject {
9351 abs_path,
9352 signature,
9353 } = &symbol.path
9354 {
9355 let new_signature = this.symbol_signature(&abs_path);
9356 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9357 }
9358 Ok(())
9359 })??;
9360 let buffer = this
9361 .update(&mut cx, |this, cx| {
9362 this.open_buffer_for_symbol(
9363 &Symbol {
9364 language_server_name: symbol.language_server_name,
9365 source_worktree_id: symbol.source_worktree_id,
9366 source_language_server_id: symbol.source_language_server_id,
9367 path: symbol.path,
9368 name: symbol.name,
9369 kind: symbol.kind,
9370 range: symbol.range,
9371 label: CodeLabel {
9372 text: Default::default(),
9373 runs: Default::default(),
9374 filter_range: Default::default(),
9375 },
9376 },
9377 cx,
9378 )
9379 })?
9380 .await?;
9381
9382 this.update(&mut cx, |this, cx| {
9383 let is_private = buffer
9384 .read(cx)
9385 .file()
9386 .map(|f| f.is_private())
9387 .unwrap_or_default();
9388 if is_private {
9389 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9390 } else {
9391 this.buffer_store
9392 .update(cx, |buffer_store, cx| {
9393 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9394 })
9395 .detach_and_log_err(cx);
9396 let buffer_id = buffer.read(cx).remote_id().to_proto();
9397 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9398 }
9399 })?
9400 }
9401
9402 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9403 let mut hasher = Sha256::new();
9404 hasher.update(abs_path.to_string_lossy().as_bytes());
9405 hasher.update(self.nonce.to_be_bytes());
9406 hasher.finalize().as_slice().try_into().unwrap()
9407 }
9408
9409 pub async fn handle_get_project_symbols(
9410 this: Entity<Self>,
9411 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9412 mut cx: AsyncApp,
9413 ) -> Result<proto::GetProjectSymbolsResponse> {
9414 let symbols = this
9415 .update(&mut cx, |this, cx| {
9416 this.symbols(&envelope.payload.query, cx)
9417 })?
9418 .await?;
9419
9420 Ok(proto::GetProjectSymbolsResponse {
9421 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9422 })
9423 }
9424
9425 pub async fn handle_restart_language_servers(
9426 this: Entity<Self>,
9427 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9428 mut cx: AsyncApp,
9429 ) -> Result<proto::Ack> {
9430 this.update(&mut cx, |lsp_store, cx| {
9431 let buffers =
9432 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9433 lsp_store.restart_language_servers_for_buffers(
9434 buffers,
9435 envelope
9436 .payload
9437 .only_servers
9438 .into_iter()
9439 .filter_map(|selector| {
9440 Some(match selector.selector? {
9441 proto::language_server_selector::Selector::ServerId(server_id) => {
9442 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9443 }
9444 proto::language_server_selector::Selector::Name(name) => {
9445 LanguageServerSelector::Name(LanguageServerName(
9446 SharedString::from(name),
9447 ))
9448 }
9449 })
9450 })
9451 .collect(),
9452 cx,
9453 );
9454 })?;
9455
9456 Ok(proto::Ack {})
9457 }
9458
9459 pub async fn handle_stop_language_servers(
9460 lsp_store: Entity<Self>,
9461 envelope: TypedEnvelope<proto::StopLanguageServers>,
9462 mut cx: AsyncApp,
9463 ) -> Result<proto::Ack> {
9464 lsp_store.update(&mut cx, |lsp_store, cx| {
9465 if envelope.payload.all
9466 && envelope.payload.also_servers.is_empty()
9467 && envelope.payload.buffer_ids.is_empty()
9468 {
9469 lsp_store.stop_all_language_servers(cx);
9470 } else {
9471 let buffers =
9472 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9473 lsp_store
9474 .stop_language_servers_for_buffers(
9475 buffers,
9476 envelope
9477 .payload
9478 .also_servers
9479 .into_iter()
9480 .filter_map(|selector| {
9481 Some(match selector.selector? {
9482 proto::language_server_selector::Selector::ServerId(
9483 server_id,
9484 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9485 server_id,
9486 )),
9487 proto::language_server_selector::Selector::Name(name) => {
9488 LanguageServerSelector::Name(LanguageServerName(
9489 SharedString::from(name),
9490 ))
9491 }
9492 })
9493 })
9494 .collect(),
9495 cx,
9496 )
9497 .detach_and_log_err(cx);
9498 }
9499 })?;
9500
9501 Ok(proto::Ack {})
9502 }
9503
9504 pub async fn handle_cancel_language_server_work(
9505 this: Entity<Self>,
9506 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9507 mut cx: AsyncApp,
9508 ) -> Result<proto::Ack> {
9509 this.update(&mut cx, |this, cx| {
9510 if let Some(work) = envelope.payload.work {
9511 match work {
9512 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9513 let buffers =
9514 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9515 this.cancel_language_server_work_for_buffers(buffers, cx);
9516 }
9517 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9518 let server_id = LanguageServerId::from_proto(work.language_server_id);
9519 this.cancel_language_server_work(server_id, work.token, cx);
9520 }
9521 }
9522 }
9523 })?;
9524
9525 Ok(proto::Ack {})
9526 }
9527
9528 fn buffer_ids_to_buffers(
9529 &mut self,
9530 buffer_ids: impl Iterator<Item = u64>,
9531 cx: &mut Context<Self>,
9532 ) -> Vec<Entity<Buffer>> {
9533 buffer_ids
9534 .into_iter()
9535 .flat_map(|buffer_id| {
9536 self.buffer_store
9537 .read(cx)
9538 .get(BufferId::new(buffer_id).log_err()?)
9539 })
9540 .collect::<Vec<_>>()
9541 }
9542
9543 async fn handle_apply_additional_edits_for_completion(
9544 this: Entity<Self>,
9545 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9546 mut cx: AsyncApp,
9547 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9548 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9549 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9550 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9551 let completion = Self::deserialize_completion(
9552 envelope.payload.completion.context("invalid completion")?,
9553 )?;
9554 anyhow::Ok((buffer, completion))
9555 })??;
9556
9557 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9558 this.apply_additional_edits_for_completion(
9559 buffer,
9560 Rc::new(RefCell::new(Box::new([Completion {
9561 replace_range: completion.replace_range,
9562 new_text: completion.new_text,
9563 source: completion.source,
9564 documentation: None,
9565 label: CodeLabel {
9566 text: Default::default(),
9567 runs: Default::default(),
9568 filter_range: Default::default(),
9569 },
9570 insert_text_mode: None,
9571 icon_path: None,
9572 confirm: None,
9573 }]))),
9574 0,
9575 false,
9576 cx,
9577 )
9578 })?;
9579
9580 Ok(proto::ApplyCompletionAdditionalEditsResponse {
9581 transaction: apply_additional_edits
9582 .await?
9583 .as_ref()
9584 .map(language::proto::serialize_transaction),
9585 })
9586 }
9587
9588 pub fn last_formatting_failure(&self) -> Option<&str> {
9589 self.last_formatting_failure.as_deref()
9590 }
9591
9592 pub fn reset_last_formatting_failure(&mut self) {
9593 self.last_formatting_failure = None;
9594 }
9595
9596 pub fn environment_for_buffer(
9597 &self,
9598 buffer: &Entity<Buffer>,
9599 cx: &mut Context<Self>,
9600 ) -> Shared<Task<Option<HashMap<String, String>>>> {
9601 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
9602 environment.update(cx, |env, cx| {
9603 env.get_buffer_environment(buffer, &self.worktree_store, cx)
9604 })
9605 } else {
9606 Task::ready(None).shared()
9607 }
9608 }
9609
9610 pub fn format(
9611 &mut self,
9612 buffers: HashSet<Entity<Buffer>>,
9613 target: LspFormatTarget,
9614 push_to_history: bool,
9615 trigger: FormatTrigger,
9616 cx: &mut Context<Self>,
9617 ) -> Task<anyhow::Result<ProjectTransaction>> {
9618 let logger = zlog::scoped!("format");
9619 if self.as_local().is_some() {
9620 zlog::trace!(logger => "Formatting locally");
9621 let logger = zlog::scoped!(logger => "local");
9622 let buffers = buffers
9623 .into_iter()
9624 .map(|buffer_handle| {
9625 let buffer = buffer_handle.read(cx);
9626 let buffer_abs_path = File::from_dyn(buffer.file())
9627 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
9628
9629 (buffer_handle, buffer_abs_path, buffer.remote_id())
9630 })
9631 .collect::<Vec<_>>();
9632
9633 cx.spawn(async move |lsp_store, cx| {
9634 let mut formattable_buffers = Vec::with_capacity(buffers.len());
9635
9636 for (handle, abs_path, id) in buffers {
9637 let env = lsp_store
9638 .update(cx, |lsp_store, cx| {
9639 lsp_store.environment_for_buffer(&handle, cx)
9640 })?
9641 .await;
9642
9643 let ranges = match &target {
9644 LspFormatTarget::Buffers => None,
9645 LspFormatTarget::Ranges(ranges) => {
9646 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
9647 }
9648 };
9649
9650 formattable_buffers.push(FormattableBuffer {
9651 handle,
9652 abs_path,
9653 env,
9654 ranges,
9655 });
9656 }
9657 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
9658
9659 let format_timer = zlog::time!(logger => "Formatting buffers");
9660 let result = LocalLspStore::format_locally(
9661 lsp_store.clone(),
9662 formattable_buffers,
9663 push_to_history,
9664 trigger,
9665 logger,
9666 cx,
9667 )
9668 .await;
9669 format_timer.end();
9670
9671 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
9672
9673 lsp_store.update(cx, |lsp_store, _| {
9674 lsp_store.update_last_formatting_failure(&result);
9675 })?;
9676
9677 result
9678 })
9679 } else if let Some((client, project_id)) = self.upstream_client() {
9680 zlog::trace!(logger => "Formatting remotely");
9681 let logger = zlog::scoped!(logger => "remote");
9682 // Don't support formatting ranges via remote
9683 match target {
9684 LspFormatTarget::Buffers => {}
9685 LspFormatTarget::Ranges(_) => {
9686 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
9687 return Task::ready(Ok(ProjectTransaction::default()));
9688 }
9689 }
9690
9691 let buffer_store = self.buffer_store();
9692 cx.spawn(async move |lsp_store, cx| {
9693 zlog::trace!(logger => "Sending remote format request");
9694 let request_timer = zlog::time!(logger => "remote format request");
9695 let result = client
9696 .request(proto::FormatBuffers {
9697 project_id,
9698 trigger: trigger as i32,
9699 buffer_ids: buffers
9700 .iter()
9701 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
9702 .collect::<Result<_>>()?,
9703 })
9704 .await
9705 .and_then(|result| result.transaction.context("missing transaction"));
9706 request_timer.end();
9707
9708 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
9709
9710 lsp_store.update(cx, |lsp_store, _| {
9711 lsp_store.update_last_formatting_failure(&result);
9712 })?;
9713
9714 let transaction_response = result?;
9715 let _timer = zlog::time!(logger => "deserializing project transaction");
9716 buffer_store
9717 .update(cx, |buffer_store, cx| {
9718 buffer_store.deserialize_project_transaction(
9719 transaction_response,
9720 push_to_history,
9721 cx,
9722 )
9723 })?
9724 .await
9725 })
9726 } else {
9727 zlog::trace!(logger => "Not formatting");
9728 Task::ready(Ok(ProjectTransaction::default()))
9729 }
9730 }
9731
9732 async fn handle_format_buffers(
9733 this: Entity<Self>,
9734 envelope: TypedEnvelope<proto::FormatBuffers>,
9735 mut cx: AsyncApp,
9736 ) -> Result<proto::FormatBuffersResponse> {
9737 let sender_id = envelope.original_sender_id().unwrap_or_default();
9738 let format = this.update(&mut cx, |this, cx| {
9739 let mut buffers = HashSet::default();
9740 for buffer_id in &envelope.payload.buffer_ids {
9741 let buffer_id = BufferId::new(*buffer_id)?;
9742 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
9743 }
9744 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
9745 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
9746 })??;
9747
9748 let project_transaction = format.await?;
9749 let project_transaction = this.update(&mut cx, |this, cx| {
9750 this.buffer_store.update(cx, |buffer_store, cx| {
9751 buffer_store.serialize_project_transaction_for_peer(
9752 project_transaction,
9753 sender_id,
9754 cx,
9755 )
9756 })
9757 })?;
9758 Ok(proto::FormatBuffersResponse {
9759 transaction: Some(project_transaction),
9760 })
9761 }
9762
9763 async fn handle_apply_code_action_kind(
9764 this: Entity<Self>,
9765 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
9766 mut cx: AsyncApp,
9767 ) -> Result<proto::ApplyCodeActionKindResponse> {
9768 let sender_id = envelope.original_sender_id().unwrap_or_default();
9769 let format = this.update(&mut cx, |this, cx| {
9770 let mut buffers = HashSet::default();
9771 for buffer_id in &envelope.payload.buffer_ids {
9772 let buffer_id = BufferId::new(*buffer_id)?;
9773 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
9774 }
9775 let kind = match envelope.payload.kind.as_str() {
9776 "" => CodeActionKind::EMPTY,
9777 "quickfix" => CodeActionKind::QUICKFIX,
9778 "refactor" => CodeActionKind::REFACTOR,
9779 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
9780 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
9781 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
9782 "source" => CodeActionKind::SOURCE,
9783 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
9784 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
9785 _ => anyhow::bail!(
9786 "Invalid code action kind {}",
9787 envelope.payload.kind.as_str()
9788 ),
9789 };
9790 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
9791 })??;
9792
9793 let project_transaction = format.await?;
9794 let project_transaction = this.update(&mut cx, |this, cx| {
9795 this.buffer_store.update(cx, |buffer_store, cx| {
9796 buffer_store.serialize_project_transaction_for_peer(
9797 project_transaction,
9798 sender_id,
9799 cx,
9800 )
9801 })
9802 })?;
9803 Ok(proto::ApplyCodeActionKindResponse {
9804 transaction: Some(project_transaction),
9805 })
9806 }
9807
9808 async fn shutdown_language_server(
9809 server_state: Option<LanguageServerState>,
9810 name: LanguageServerName,
9811 cx: &mut AsyncApp,
9812 ) {
9813 let server = match server_state {
9814 Some(LanguageServerState::Starting { startup, .. }) => {
9815 let mut timer = cx
9816 .background_executor()
9817 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
9818 .fuse();
9819
9820 select! {
9821 server = startup.fuse() => server,
9822 () = timer => {
9823 log::info!("timeout waiting for language server {name} to finish launching before stopping");
9824 None
9825 },
9826 }
9827 }
9828
9829 Some(LanguageServerState::Running { server, .. }) => Some(server),
9830
9831 None => None,
9832 };
9833
9834 if let Some(server) = server
9835 && let Some(shutdown) = server.shutdown()
9836 {
9837 shutdown.await;
9838 }
9839 }
9840
9841 // Returns a list of all of the worktrees which no longer have a language server and the root path
9842 // for the stopped server
9843 fn stop_local_language_server(
9844 &mut self,
9845 server_id: LanguageServerId,
9846 cx: &mut Context<Self>,
9847 ) -> Task<()> {
9848 let local = match &mut self.mode {
9849 LspStoreMode::Local(local) => local,
9850 _ => {
9851 return Task::ready(());
9852 }
9853 };
9854
9855 // Remove this server ID from all entries in the given worktree.
9856 local
9857 .language_server_ids
9858 .retain(|_, state| state.id != server_id);
9859 self.buffer_store.update(cx, |buffer_store, cx| {
9860 for buffer in buffer_store.buffers() {
9861 buffer.update(cx, |buffer, cx| {
9862 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
9863 buffer.set_completion_triggers(server_id, Default::default(), cx);
9864 });
9865 }
9866 });
9867
9868 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
9869 summaries.retain(|path, summaries_by_server_id| {
9870 if summaries_by_server_id.remove(&server_id).is_some() {
9871 if let Some((client, project_id)) = self.downstream_client.clone() {
9872 client
9873 .send(proto::UpdateDiagnosticSummary {
9874 project_id,
9875 worktree_id: worktree_id.to_proto(),
9876 summary: Some(proto::DiagnosticSummary {
9877 path: path.as_ref().to_proto(),
9878 language_server_id: server_id.0 as u64,
9879 error_count: 0,
9880 warning_count: 0,
9881 }),
9882 more_summaries: Vec::new(),
9883 })
9884 .log_err();
9885 }
9886 !summaries_by_server_id.is_empty()
9887 } else {
9888 true
9889 }
9890 });
9891 }
9892
9893 let local = self.as_local_mut().unwrap();
9894 for diagnostics in local.diagnostics.values_mut() {
9895 diagnostics.retain(|_, diagnostics_by_server_id| {
9896 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
9897 diagnostics_by_server_id.remove(ix);
9898 !diagnostics_by_server_id.is_empty()
9899 } else {
9900 true
9901 }
9902 });
9903 }
9904 local.language_server_watched_paths.remove(&server_id);
9905
9906 let server_state = local.language_servers.remove(&server_id);
9907 self.cleanup_lsp_data(server_id);
9908 let name = self
9909 .language_server_statuses
9910 .remove(&server_id)
9911 .map(|status| status.name)
9912 .or_else(|| {
9913 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
9914 Some(adapter.name())
9915 } else {
9916 None
9917 }
9918 });
9919
9920 if let Some(name) = name {
9921 log::info!("stopping language server {name}");
9922 self.languages
9923 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
9924 cx.notify();
9925
9926 return cx.spawn(async move |lsp_store, cx| {
9927 Self::shutdown_language_server(server_state, name.clone(), cx).await;
9928 lsp_store
9929 .update(cx, |lsp_store, cx| {
9930 lsp_store
9931 .languages
9932 .update_lsp_binary_status(name, BinaryStatus::Stopped);
9933 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
9934 cx.notify();
9935 })
9936 .ok();
9937 });
9938 }
9939
9940 if server_state.is_some() {
9941 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
9942 }
9943 Task::ready(())
9944 }
9945
9946 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
9947 if let Some((client, project_id)) = self.upstream_client() {
9948 let request = client.request(proto::StopLanguageServers {
9949 project_id,
9950 buffer_ids: Vec::new(),
9951 also_servers: Vec::new(),
9952 all: true,
9953 });
9954 cx.background_spawn(request).detach_and_log_err(cx);
9955 } else {
9956 let Some(local) = self.as_local_mut() else {
9957 return;
9958 };
9959 let language_servers_to_stop = local
9960 .language_server_ids
9961 .values()
9962 .map(|state| state.id)
9963 .collect();
9964 local.lsp_tree.remove_nodes(&language_servers_to_stop);
9965 let tasks = language_servers_to_stop
9966 .into_iter()
9967 .map(|server| self.stop_local_language_server(server, cx))
9968 .collect::<Vec<_>>();
9969 cx.background_spawn(async move {
9970 futures::future::join_all(tasks).await;
9971 })
9972 .detach();
9973 }
9974 }
9975
9976 pub fn restart_language_servers_for_buffers(
9977 &mut self,
9978 buffers: Vec<Entity<Buffer>>,
9979 only_restart_servers: HashSet<LanguageServerSelector>,
9980 cx: &mut Context<Self>,
9981 ) {
9982 if let Some((client, project_id)) = self.upstream_client() {
9983 let request = client.request(proto::RestartLanguageServers {
9984 project_id,
9985 buffer_ids: buffers
9986 .into_iter()
9987 .map(|b| b.read(cx).remote_id().to_proto())
9988 .collect(),
9989 only_servers: only_restart_servers
9990 .into_iter()
9991 .map(|selector| {
9992 let selector = match selector {
9993 LanguageServerSelector::Id(language_server_id) => {
9994 proto::language_server_selector::Selector::ServerId(
9995 language_server_id.to_proto(),
9996 )
9997 }
9998 LanguageServerSelector::Name(language_server_name) => {
9999 proto::language_server_selector::Selector::Name(
10000 language_server_name.to_string(),
10001 )
10002 }
10003 };
10004 proto::LanguageServerSelector {
10005 selector: Some(selector),
10006 }
10007 })
10008 .collect(),
10009 all: false,
10010 });
10011 cx.background_spawn(request).detach_and_log_err(cx);
10012 } else {
10013 let stop_task = if only_restart_servers.is_empty() {
10014 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10015 } else {
10016 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10017 };
10018 cx.spawn(async move |lsp_store, cx| {
10019 stop_task.await;
10020 lsp_store
10021 .update(cx, |lsp_store, cx| {
10022 for buffer in buffers {
10023 lsp_store.register_buffer_with_language_servers(
10024 &buffer,
10025 only_restart_servers.clone(),
10026 true,
10027 cx,
10028 );
10029 }
10030 })
10031 .ok()
10032 })
10033 .detach();
10034 }
10035 }
10036
10037 pub fn stop_language_servers_for_buffers(
10038 &mut self,
10039 buffers: Vec<Entity<Buffer>>,
10040 also_stop_servers: HashSet<LanguageServerSelector>,
10041 cx: &mut Context<Self>,
10042 ) -> Task<Result<()>> {
10043 if let Some((client, project_id)) = self.upstream_client() {
10044 let request = client.request(proto::StopLanguageServers {
10045 project_id,
10046 buffer_ids: buffers
10047 .into_iter()
10048 .map(|b| b.read(cx).remote_id().to_proto())
10049 .collect(),
10050 also_servers: also_stop_servers
10051 .into_iter()
10052 .map(|selector| {
10053 let selector = match selector {
10054 LanguageServerSelector::Id(language_server_id) => {
10055 proto::language_server_selector::Selector::ServerId(
10056 language_server_id.to_proto(),
10057 )
10058 }
10059 LanguageServerSelector::Name(language_server_name) => {
10060 proto::language_server_selector::Selector::Name(
10061 language_server_name.to_string(),
10062 )
10063 }
10064 };
10065 proto::LanguageServerSelector {
10066 selector: Some(selector),
10067 }
10068 })
10069 .collect(),
10070 all: false,
10071 });
10072 cx.background_spawn(async move {
10073 let _ = request.await?;
10074 Ok(())
10075 })
10076 } else {
10077 let task =
10078 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10079 cx.background_spawn(async move {
10080 task.await;
10081 Ok(())
10082 })
10083 }
10084 }
10085
10086 fn stop_local_language_servers_for_buffers(
10087 &mut self,
10088 buffers: &[Entity<Buffer>],
10089 also_stop_servers: HashSet<LanguageServerSelector>,
10090 cx: &mut Context<Self>,
10091 ) -> Task<()> {
10092 let Some(local) = self.as_local_mut() else {
10093 return Task::ready(());
10094 };
10095 let mut language_server_names_to_stop = BTreeSet::default();
10096 let mut language_servers_to_stop = also_stop_servers
10097 .into_iter()
10098 .flat_map(|selector| match selector {
10099 LanguageServerSelector::Id(id) => Some(id),
10100 LanguageServerSelector::Name(name) => {
10101 language_server_names_to_stop.insert(name);
10102 None
10103 }
10104 })
10105 .collect::<BTreeSet<_>>();
10106
10107 let mut covered_worktrees = HashSet::default();
10108 for buffer in buffers {
10109 buffer.update(cx, |buffer, cx| {
10110 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10111 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10112 && covered_worktrees.insert(worktree_id)
10113 {
10114 language_server_names_to_stop.retain(|name| {
10115 let old_ids_count = language_servers_to_stop.len();
10116 let all_language_servers_with_this_name = local
10117 .language_server_ids
10118 .iter()
10119 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10120 language_servers_to_stop.extend(all_language_servers_with_this_name);
10121 old_ids_count == language_servers_to_stop.len()
10122 });
10123 }
10124 });
10125 }
10126 for name in language_server_names_to_stop {
10127 language_servers_to_stop.extend(
10128 local
10129 .language_server_ids
10130 .iter()
10131 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10132 );
10133 }
10134
10135 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10136 let tasks = language_servers_to_stop
10137 .into_iter()
10138 .map(|server| self.stop_local_language_server(server, cx))
10139 .collect::<Vec<_>>();
10140
10141 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10142 }
10143
10144 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10145 let (worktree, relative_path) =
10146 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10147
10148 let project_path = ProjectPath {
10149 worktree_id: worktree.read(cx).id(),
10150 path: relative_path,
10151 };
10152
10153 Some(
10154 self.buffer_store()
10155 .read(cx)
10156 .get_by_path(&project_path)?
10157 .read(cx),
10158 )
10159 }
10160
10161 #[cfg(any(test, feature = "test-support"))]
10162 pub fn update_diagnostics(
10163 &mut self,
10164 server_id: LanguageServerId,
10165 diagnostics: lsp::PublishDiagnosticsParams,
10166 result_id: Option<String>,
10167 source_kind: DiagnosticSourceKind,
10168 disk_based_sources: &[String],
10169 cx: &mut Context<Self>,
10170 ) -> Result<()> {
10171 self.merge_lsp_diagnostics(
10172 source_kind,
10173 vec![DocumentDiagnosticsUpdate {
10174 diagnostics,
10175 result_id,
10176 server_id,
10177 disk_based_sources: Cow::Borrowed(disk_based_sources),
10178 }],
10179 |_, _, _| false,
10180 cx,
10181 )
10182 }
10183
10184 pub fn merge_lsp_diagnostics(
10185 &mut self,
10186 source_kind: DiagnosticSourceKind,
10187 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10188 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10189 cx: &mut Context<Self>,
10190 ) -> Result<()> {
10191 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10192 let updates = lsp_diagnostics
10193 .into_iter()
10194 .filter_map(|update| {
10195 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10196 Some(DocumentDiagnosticsUpdate {
10197 diagnostics: self.lsp_to_document_diagnostics(
10198 abs_path,
10199 source_kind,
10200 update.server_id,
10201 update.diagnostics,
10202 &update.disk_based_sources,
10203 ),
10204 result_id: update.result_id,
10205 server_id: update.server_id,
10206 disk_based_sources: update.disk_based_sources,
10207 })
10208 })
10209 .collect();
10210 self.merge_diagnostic_entries(updates, merge, cx)?;
10211 Ok(())
10212 }
10213
10214 fn lsp_to_document_diagnostics(
10215 &mut self,
10216 document_abs_path: PathBuf,
10217 source_kind: DiagnosticSourceKind,
10218 server_id: LanguageServerId,
10219 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10220 disk_based_sources: &[String],
10221 ) -> DocumentDiagnostics {
10222 let mut diagnostics = Vec::default();
10223 let mut primary_diagnostic_group_ids = HashMap::default();
10224 let mut sources_by_group_id = HashMap::default();
10225 let mut supporting_diagnostics = HashMap::default();
10226
10227 let adapter = self.language_server_adapter_for_id(server_id);
10228
10229 // Ensure that primary diagnostics are always the most severe
10230 lsp_diagnostics
10231 .diagnostics
10232 .sort_by_key(|item| item.severity);
10233
10234 for diagnostic in &lsp_diagnostics.diagnostics {
10235 let source = diagnostic.source.as_ref();
10236 let range = range_from_lsp(diagnostic.range);
10237 let is_supporting = diagnostic
10238 .related_information
10239 .as_ref()
10240 .is_some_and(|infos| {
10241 infos.iter().any(|info| {
10242 primary_diagnostic_group_ids.contains_key(&(
10243 source,
10244 diagnostic.code.clone(),
10245 range_from_lsp(info.location.range),
10246 ))
10247 })
10248 });
10249
10250 let is_unnecessary = diagnostic
10251 .tags
10252 .as_ref()
10253 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10254
10255 let underline = self
10256 .language_server_adapter_for_id(server_id)
10257 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10258
10259 if is_supporting {
10260 supporting_diagnostics.insert(
10261 (source, diagnostic.code.clone(), range),
10262 (diagnostic.severity, is_unnecessary),
10263 );
10264 } else {
10265 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10266 let is_disk_based =
10267 source.is_some_and(|source| disk_based_sources.contains(source));
10268
10269 sources_by_group_id.insert(group_id, source);
10270 primary_diagnostic_group_ids
10271 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10272
10273 diagnostics.push(DiagnosticEntry {
10274 range,
10275 diagnostic: Diagnostic {
10276 source: diagnostic.source.clone(),
10277 source_kind,
10278 code: diagnostic.code.clone(),
10279 code_description: diagnostic
10280 .code_description
10281 .as_ref()
10282 .and_then(|d| d.href.clone()),
10283 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10284 markdown: adapter.as_ref().and_then(|adapter| {
10285 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10286 }),
10287 message: diagnostic.message.trim().to_string(),
10288 group_id,
10289 is_primary: true,
10290 is_disk_based,
10291 is_unnecessary,
10292 underline,
10293 data: diagnostic.data.clone(),
10294 },
10295 });
10296 if let Some(infos) = &diagnostic.related_information {
10297 for info in infos {
10298 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10299 let range = range_from_lsp(info.location.range);
10300 diagnostics.push(DiagnosticEntry {
10301 range,
10302 diagnostic: Diagnostic {
10303 source: diagnostic.source.clone(),
10304 source_kind,
10305 code: diagnostic.code.clone(),
10306 code_description: diagnostic
10307 .code_description
10308 .as_ref()
10309 .and_then(|d| d.href.clone()),
10310 severity: DiagnosticSeverity::INFORMATION,
10311 markdown: adapter.as_ref().and_then(|adapter| {
10312 adapter.diagnostic_message_to_markdown(&info.message)
10313 }),
10314 message: info.message.trim().to_string(),
10315 group_id,
10316 is_primary: false,
10317 is_disk_based,
10318 is_unnecessary: false,
10319 underline,
10320 data: diagnostic.data.clone(),
10321 },
10322 });
10323 }
10324 }
10325 }
10326 }
10327 }
10328
10329 for entry in &mut diagnostics {
10330 let diagnostic = &mut entry.diagnostic;
10331 if !diagnostic.is_primary {
10332 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10333 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10334 source,
10335 diagnostic.code.clone(),
10336 entry.range.clone(),
10337 )) {
10338 if let Some(severity) = severity {
10339 diagnostic.severity = severity;
10340 }
10341 diagnostic.is_unnecessary = is_unnecessary;
10342 }
10343 }
10344 }
10345
10346 DocumentDiagnostics {
10347 diagnostics,
10348 document_abs_path,
10349 version: lsp_diagnostics.version,
10350 }
10351 }
10352
10353 fn insert_newly_running_language_server(
10354 &mut self,
10355 adapter: Arc<CachedLspAdapter>,
10356 language_server: Arc<LanguageServer>,
10357 server_id: LanguageServerId,
10358 key: LanguageServerSeed,
10359 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10360 cx: &mut Context<Self>,
10361 ) {
10362 let Some(local) = self.as_local_mut() else {
10363 return;
10364 };
10365 // If the language server for this key doesn't match the server id, don't store the
10366 // server. Which will cause it to be dropped, killing the process
10367 if local
10368 .language_server_ids
10369 .get(&key)
10370 .map(|state| state.id != server_id)
10371 .unwrap_or(false)
10372 {
10373 return;
10374 }
10375
10376 // Update language_servers collection with Running variant of LanguageServerState
10377 // indicating that the server is up and running and ready
10378 let workspace_folders = workspace_folders.lock().clone();
10379 language_server.set_workspace_folders(workspace_folders);
10380
10381 local.language_servers.insert(
10382 server_id,
10383 LanguageServerState::Running {
10384 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10385 language_server.clone(),
10386 cx,
10387 ),
10388 adapter: adapter.clone(),
10389 server: language_server.clone(),
10390 simulate_disk_based_diagnostics_completion: None,
10391 },
10392 );
10393 local
10394 .languages
10395 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10396 if let Some(file_ops_caps) = language_server
10397 .capabilities()
10398 .workspace
10399 .as_ref()
10400 .and_then(|ws| ws.file_operations.as_ref())
10401 {
10402 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10403 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10404 if did_rename_caps.or(will_rename_caps).is_some() {
10405 let watcher = RenamePathsWatchedForServer::default()
10406 .with_did_rename_patterns(did_rename_caps)
10407 .with_will_rename_patterns(will_rename_caps);
10408 local
10409 .language_server_paths_watched_for_rename
10410 .insert(server_id, watcher);
10411 }
10412 }
10413
10414 self.language_server_statuses.insert(
10415 server_id,
10416 LanguageServerStatus {
10417 name: language_server.name(),
10418 pending_work: Default::default(),
10419 has_pending_diagnostic_updates: false,
10420 progress_tokens: Default::default(),
10421 worktree: Some(key.worktree_id),
10422 },
10423 );
10424
10425 cx.emit(LspStoreEvent::LanguageServerAdded(
10426 server_id,
10427 language_server.name(),
10428 Some(key.worktree_id),
10429 ));
10430 cx.emit(LspStoreEvent::RefreshInlayHints);
10431
10432 let server_capabilities = language_server.capabilities();
10433 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10434 downstream_client
10435 .send(proto::StartLanguageServer {
10436 project_id: *project_id,
10437 server: Some(proto::LanguageServer {
10438 id: server_id.to_proto(),
10439 name: language_server.name().to_string(),
10440 worktree_id: Some(key.worktree_id.to_proto()),
10441 }),
10442 capabilities: serde_json::to_string(&server_capabilities)
10443 .expect("serializing server LSP capabilities"),
10444 })
10445 .log_err();
10446 }
10447 self.lsp_server_capabilities
10448 .insert(server_id, server_capabilities);
10449
10450 // Tell the language server about every open buffer in the worktree that matches the language.
10451 // Also check for buffers in worktrees that reused this server
10452 let mut worktrees_using_server = vec![key.worktree_id];
10453 if let Some(local) = self.as_local() {
10454 // Find all worktrees that have this server in their language server tree
10455 for (worktree_id, servers) in &local.lsp_tree.instances {
10456 if *worktree_id != key.worktree_id {
10457 for server_map in servers.roots.values() {
10458 if server_map
10459 .values()
10460 .any(|(node, _)| node.id() == Some(server_id))
10461 {
10462 worktrees_using_server.push(*worktree_id);
10463 }
10464 }
10465 }
10466 }
10467 }
10468
10469 let mut buffer_paths_registered = Vec::new();
10470 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10471 let mut lsp_adapters = HashMap::default();
10472 for buffer_handle in buffer_store.buffers() {
10473 let buffer = buffer_handle.read(cx);
10474 let file = match File::from_dyn(buffer.file()) {
10475 Some(file) => file,
10476 None => continue,
10477 };
10478 let language = match buffer.language() {
10479 Some(language) => language,
10480 None => continue,
10481 };
10482
10483 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10484 || !lsp_adapters
10485 .entry(language.name())
10486 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
10487 .iter()
10488 .any(|a| a.name == key.name)
10489 {
10490 continue;
10491 }
10492 // didOpen
10493 let file = match file.as_local() {
10494 Some(file) => file,
10495 None => continue,
10496 };
10497
10498 let local = self.as_local_mut().unwrap();
10499
10500 let buffer_id = buffer.remote_id();
10501 if local.registered_buffers.contains_key(&buffer_id) {
10502 let versions = local
10503 .buffer_snapshots
10504 .entry(buffer_id)
10505 .or_default()
10506 .entry(server_id)
10507 .and_modify(|_| {
10508 assert!(
10509 false,
10510 "There should not be an existing snapshot for a newly inserted buffer"
10511 )
10512 })
10513 .or_insert_with(|| {
10514 vec![LspBufferSnapshot {
10515 version: 0,
10516 snapshot: buffer.text_snapshot(),
10517 }]
10518 });
10519
10520 let snapshot = versions.last().unwrap();
10521 let version = snapshot.version;
10522 let initial_snapshot = &snapshot.snapshot;
10523 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
10524 language_server.register_buffer(
10525 uri,
10526 adapter.language_id(&language.name()),
10527 version,
10528 initial_snapshot.text(),
10529 );
10530 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10531 local
10532 .buffers_opened_in_servers
10533 .entry(buffer_id)
10534 .or_default()
10535 .insert(server_id);
10536 }
10537 buffer_handle.update(cx, |buffer, cx| {
10538 buffer.set_completion_triggers(
10539 server_id,
10540 language_server
10541 .capabilities()
10542 .completion_provider
10543 .as_ref()
10544 .and_then(|provider| {
10545 provider
10546 .trigger_characters
10547 .as_ref()
10548 .map(|characters| characters.iter().cloned().collect())
10549 })
10550 .unwrap_or_default(),
10551 cx,
10552 )
10553 });
10554 }
10555 });
10556
10557 for (buffer_id, abs_path) in buffer_paths_registered {
10558 cx.emit(LspStoreEvent::LanguageServerUpdate {
10559 language_server_id: server_id,
10560 name: Some(adapter.name()),
10561 message: proto::update_language_server::Variant::RegisteredForBuffer(
10562 proto::RegisteredForBuffer {
10563 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
10564 buffer_id: buffer_id.to_proto(),
10565 },
10566 ),
10567 });
10568 }
10569
10570 cx.notify();
10571 }
10572
10573 pub fn language_servers_running_disk_based_diagnostics(
10574 &self,
10575 ) -> impl Iterator<Item = LanguageServerId> + '_ {
10576 self.language_server_statuses
10577 .iter()
10578 .filter_map(|(id, status)| {
10579 if status.has_pending_diagnostic_updates {
10580 Some(*id)
10581 } else {
10582 None
10583 }
10584 })
10585 }
10586
10587 pub(crate) fn cancel_language_server_work_for_buffers(
10588 &mut self,
10589 buffers: impl IntoIterator<Item = Entity<Buffer>>,
10590 cx: &mut Context<Self>,
10591 ) {
10592 if let Some((client, project_id)) = self.upstream_client() {
10593 let request = client.request(proto::CancelLanguageServerWork {
10594 project_id,
10595 work: Some(proto::cancel_language_server_work::Work::Buffers(
10596 proto::cancel_language_server_work::Buffers {
10597 buffer_ids: buffers
10598 .into_iter()
10599 .map(|b| b.read(cx).remote_id().to_proto())
10600 .collect(),
10601 },
10602 )),
10603 });
10604 cx.background_spawn(request).detach_and_log_err(cx);
10605 } else if let Some(local) = self.as_local() {
10606 let servers = buffers
10607 .into_iter()
10608 .flat_map(|buffer| {
10609 buffer.update(cx, |buffer, cx| {
10610 local.language_server_ids_for_buffer(buffer, cx).into_iter()
10611 })
10612 })
10613 .collect::<HashSet<_>>();
10614 for server_id in servers {
10615 self.cancel_language_server_work(server_id, None, cx);
10616 }
10617 }
10618 }
10619
10620 pub(crate) fn cancel_language_server_work(
10621 &mut self,
10622 server_id: LanguageServerId,
10623 token_to_cancel: Option<String>,
10624 cx: &mut Context<Self>,
10625 ) {
10626 if let Some(local) = self.as_local() {
10627 let status = self.language_server_statuses.get(&server_id);
10628 let server = local.language_servers.get(&server_id);
10629 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
10630 {
10631 for (token, progress) in &status.pending_work {
10632 if let Some(token_to_cancel) = token_to_cancel.as_ref()
10633 && token != token_to_cancel
10634 {
10635 continue;
10636 }
10637 if progress.is_cancellable {
10638 server
10639 .notify::<lsp::notification::WorkDoneProgressCancel>(
10640 &WorkDoneProgressCancelParams {
10641 token: lsp::NumberOrString::String(token.clone()),
10642 },
10643 )
10644 .ok();
10645 }
10646 }
10647 }
10648 } else if let Some((client, project_id)) = self.upstream_client() {
10649 let request = client.request(proto::CancelLanguageServerWork {
10650 project_id,
10651 work: Some(
10652 proto::cancel_language_server_work::Work::LanguageServerWork(
10653 proto::cancel_language_server_work::LanguageServerWork {
10654 language_server_id: server_id.to_proto(),
10655 token: token_to_cancel,
10656 },
10657 ),
10658 ),
10659 });
10660 cx.background_spawn(request).detach_and_log_err(cx);
10661 }
10662 }
10663
10664 fn register_supplementary_language_server(
10665 &mut self,
10666 id: LanguageServerId,
10667 name: LanguageServerName,
10668 server: Arc<LanguageServer>,
10669 cx: &mut Context<Self>,
10670 ) {
10671 if let Some(local) = self.as_local_mut() {
10672 local
10673 .supplementary_language_servers
10674 .insert(id, (name.clone(), server));
10675 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
10676 }
10677 }
10678
10679 fn unregister_supplementary_language_server(
10680 &mut self,
10681 id: LanguageServerId,
10682 cx: &mut Context<Self>,
10683 ) {
10684 if let Some(local) = self.as_local_mut() {
10685 local.supplementary_language_servers.remove(&id);
10686 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
10687 }
10688 }
10689
10690 pub(crate) fn supplementary_language_servers(
10691 &self,
10692 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
10693 self.as_local().into_iter().flat_map(|local| {
10694 local
10695 .supplementary_language_servers
10696 .iter()
10697 .map(|(id, (name, _))| (*id, name.clone()))
10698 })
10699 }
10700
10701 pub fn language_server_adapter_for_id(
10702 &self,
10703 id: LanguageServerId,
10704 ) -> Option<Arc<CachedLspAdapter>> {
10705 self.as_local()
10706 .and_then(|local| local.language_servers.get(&id))
10707 .and_then(|language_server_state| match language_server_state {
10708 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
10709 _ => None,
10710 })
10711 }
10712
10713 pub(super) fn update_local_worktree_language_servers(
10714 &mut self,
10715 worktree_handle: &Entity<Worktree>,
10716 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
10717 cx: &mut Context<Self>,
10718 ) {
10719 if changes.is_empty() {
10720 return;
10721 }
10722
10723 let Some(local) = self.as_local() else { return };
10724
10725 local.prettier_store.update(cx, |prettier_store, cx| {
10726 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
10727 });
10728
10729 let worktree_id = worktree_handle.read(cx).id();
10730 let mut language_server_ids = local
10731 .language_server_ids
10732 .iter()
10733 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
10734 .collect::<Vec<_>>();
10735 language_server_ids.sort();
10736 language_server_ids.dedup();
10737
10738 // let abs_path = worktree_handle.read(cx).abs_path();
10739 for server_id in &language_server_ids {
10740 if let Some(LanguageServerState::Running { server, .. }) =
10741 local.language_servers.get(server_id)
10742 && let Some(watched_paths) = local
10743 .language_server_watched_paths
10744 .get(server_id)
10745 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
10746 {
10747 let params = lsp::DidChangeWatchedFilesParams {
10748 changes: changes
10749 .iter()
10750 .filter_map(|(path, _, change)| {
10751 if !watched_paths.is_match(path.as_std_path()) {
10752 return None;
10753 }
10754 let typ = match change {
10755 PathChange::Loaded => return None,
10756 PathChange::Added => lsp::FileChangeType::CREATED,
10757 PathChange::Removed => lsp::FileChangeType::DELETED,
10758 PathChange::Updated => lsp::FileChangeType::CHANGED,
10759 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
10760 };
10761 let uri = lsp::Uri::from_file_path(
10762 worktree_handle.read(cx).absolutize(&path),
10763 )
10764 .ok()?;
10765 Some(lsp::FileEvent { uri, typ })
10766 })
10767 .collect(),
10768 };
10769 if !params.changes.is_empty() {
10770 server
10771 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
10772 .ok();
10773 }
10774 }
10775 }
10776 for (path, _, _) in changes {
10777 if let Some(file_name) = path.file_name()
10778 && local.watched_manifest_filenames.contains(file_name)
10779 {
10780 self.request_workspace_config_refresh();
10781 break;
10782 }
10783 }
10784 }
10785
10786 pub fn wait_for_remote_buffer(
10787 &mut self,
10788 id: BufferId,
10789 cx: &mut Context<Self>,
10790 ) -> Task<Result<Entity<Buffer>>> {
10791 self.buffer_store.update(cx, |buffer_store, cx| {
10792 buffer_store.wait_for_remote_buffer(id, cx)
10793 })
10794 }
10795
10796 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
10797 let mut result = proto::Symbol {
10798 language_server_name: symbol.language_server_name.0.to_string(),
10799 source_worktree_id: symbol.source_worktree_id.to_proto(),
10800 language_server_id: symbol.source_language_server_id.to_proto(),
10801 name: symbol.name.clone(),
10802 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
10803 start: Some(proto::PointUtf16 {
10804 row: symbol.range.start.0.row,
10805 column: symbol.range.start.0.column,
10806 }),
10807 end: Some(proto::PointUtf16 {
10808 row: symbol.range.end.0.row,
10809 column: symbol.range.end.0.column,
10810 }),
10811 worktree_id: Default::default(),
10812 path: Default::default(),
10813 signature: Default::default(),
10814 };
10815 match &symbol.path {
10816 SymbolLocation::InProject(path) => {
10817 result.worktree_id = path.worktree_id.to_proto();
10818 result.path = path.path.to_proto();
10819 }
10820 SymbolLocation::OutsideProject {
10821 abs_path,
10822 signature,
10823 } => {
10824 result.path = abs_path.to_string_lossy().into_owned();
10825 result.signature = signature.to_vec();
10826 }
10827 }
10828 result
10829 }
10830
10831 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
10832 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
10833 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
10834 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
10835
10836 let path = if serialized_symbol.signature.is_empty() {
10837 SymbolLocation::InProject(ProjectPath {
10838 worktree_id,
10839 path: RelPath::from_proto(&serialized_symbol.path)
10840 .context("invalid symbol path")?,
10841 })
10842 } else {
10843 SymbolLocation::OutsideProject {
10844 abs_path: Path::new(&serialized_symbol.path).into(),
10845 signature: serialized_symbol
10846 .signature
10847 .try_into()
10848 .map_err(|_| anyhow!("invalid signature"))?,
10849 }
10850 };
10851
10852 let start = serialized_symbol.start.context("invalid start")?;
10853 let end = serialized_symbol.end.context("invalid end")?;
10854 Ok(CoreSymbol {
10855 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
10856 source_worktree_id,
10857 source_language_server_id: LanguageServerId::from_proto(
10858 serialized_symbol.language_server_id,
10859 ),
10860 path,
10861 name: serialized_symbol.name,
10862 range: Unclipped(PointUtf16::new(start.row, start.column))
10863 ..Unclipped(PointUtf16::new(end.row, end.column)),
10864 kind,
10865 })
10866 }
10867
10868 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
10869 let mut serialized_completion = proto::Completion {
10870 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
10871 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
10872 new_text: completion.new_text.clone(),
10873 ..proto::Completion::default()
10874 };
10875 match &completion.source {
10876 CompletionSource::Lsp {
10877 insert_range,
10878 server_id,
10879 lsp_completion,
10880 lsp_defaults,
10881 resolved,
10882 } => {
10883 let (old_insert_start, old_insert_end) = insert_range
10884 .as_ref()
10885 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
10886 .unzip();
10887
10888 serialized_completion.old_insert_start = old_insert_start;
10889 serialized_completion.old_insert_end = old_insert_end;
10890 serialized_completion.source = proto::completion::Source::Lsp as i32;
10891 serialized_completion.server_id = server_id.0 as u64;
10892 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
10893 serialized_completion.lsp_defaults = lsp_defaults
10894 .as_deref()
10895 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
10896 serialized_completion.resolved = *resolved;
10897 }
10898 CompletionSource::BufferWord {
10899 word_range,
10900 resolved,
10901 } => {
10902 serialized_completion.source = proto::completion::Source::BufferWord as i32;
10903 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
10904 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
10905 serialized_completion.resolved = *resolved;
10906 }
10907 CompletionSource::Custom => {
10908 serialized_completion.source = proto::completion::Source::Custom as i32;
10909 serialized_completion.resolved = true;
10910 }
10911 CompletionSource::Dap { sort_text } => {
10912 serialized_completion.source = proto::completion::Source::Dap as i32;
10913 serialized_completion.sort_text = Some(sort_text.clone());
10914 }
10915 }
10916
10917 serialized_completion
10918 }
10919
10920 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
10921 let old_replace_start = completion
10922 .old_replace_start
10923 .and_then(deserialize_anchor)
10924 .context("invalid old start")?;
10925 let old_replace_end = completion
10926 .old_replace_end
10927 .and_then(deserialize_anchor)
10928 .context("invalid old end")?;
10929 let insert_range = {
10930 match completion.old_insert_start.zip(completion.old_insert_end) {
10931 Some((start, end)) => {
10932 let start = deserialize_anchor(start).context("invalid insert old start")?;
10933 let end = deserialize_anchor(end).context("invalid insert old end")?;
10934 Some(start..end)
10935 }
10936 None => None,
10937 }
10938 };
10939 Ok(CoreCompletion {
10940 replace_range: old_replace_start..old_replace_end,
10941 new_text: completion.new_text,
10942 source: match proto::completion::Source::from_i32(completion.source) {
10943 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
10944 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
10945 insert_range,
10946 server_id: LanguageServerId::from_proto(completion.server_id),
10947 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
10948 lsp_defaults: completion
10949 .lsp_defaults
10950 .as_deref()
10951 .map(serde_json::from_slice)
10952 .transpose()?,
10953 resolved: completion.resolved,
10954 },
10955 Some(proto::completion::Source::BufferWord) => {
10956 let word_range = completion
10957 .buffer_word_start
10958 .and_then(deserialize_anchor)
10959 .context("invalid buffer word start")?
10960 ..completion
10961 .buffer_word_end
10962 .and_then(deserialize_anchor)
10963 .context("invalid buffer word end")?;
10964 CompletionSource::BufferWord {
10965 word_range,
10966 resolved: completion.resolved,
10967 }
10968 }
10969 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
10970 sort_text: completion
10971 .sort_text
10972 .context("expected sort text to exist")?,
10973 },
10974 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
10975 },
10976 })
10977 }
10978
10979 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
10980 let (kind, lsp_action) = match &action.lsp_action {
10981 LspAction::Action(code_action) => (
10982 proto::code_action::Kind::Action as i32,
10983 serde_json::to_vec(code_action).unwrap(),
10984 ),
10985 LspAction::Command(command) => (
10986 proto::code_action::Kind::Command as i32,
10987 serde_json::to_vec(command).unwrap(),
10988 ),
10989 LspAction::CodeLens(code_lens) => (
10990 proto::code_action::Kind::CodeLens as i32,
10991 serde_json::to_vec(code_lens).unwrap(),
10992 ),
10993 };
10994
10995 proto::CodeAction {
10996 server_id: action.server_id.0 as u64,
10997 start: Some(serialize_anchor(&action.range.start)),
10998 end: Some(serialize_anchor(&action.range.end)),
10999 lsp_action,
11000 kind,
11001 resolved: action.resolved,
11002 }
11003 }
11004
11005 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11006 let start = action
11007 .start
11008 .and_then(deserialize_anchor)
11009 .context("invalid start")?;
11010 let end = action
11011 .end
11012 .and_then(deserialize_anchor)
11013 .context("invalid end")?;
11014 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11015 Some(proto::code_action::Kind::Action) => {
11016 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11017 }
11018 Some(proto::code_action::Kind::Command) => {
11019 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11020 }
11021 Some(proto::code_action::Kind::CodeLens) => {
11022 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11023 }
11024 None => anyhow::bail!("Unknown action kind {}", action.kind),
11025 };
11026 Ok(CodeAction {
11027 server_id: LanguageServerId(action.server_id as usize),
11028 range: start..end,
11029 resolved: action.resolved,
11030 lsp_action,
11031 })
11032 }
11033
11034 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11035 match &formatting_result {
11036 Ok(_) => self.last_formatting_failure = None,
11037 Err(error) => {
11038 let error_string = format!("{error:#}");
11039 log::error!("Formatting failed: {error_string}");
11040 self.last_formatting_failure
11041 .replace(error_string.lines().join(" "));
11042 }
11043 }
11044 }
11045
11046 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11047 self.lsp_server_capabilities.remove(&for_server);
11048 for buffer_colors in self.lsp_document_colors.values_mut() {
11049 buffer_colors.colors.remove(&for_server);
11050 buffer_colors.cache_version += 1;
11051 }
11052 for buffer_lens in self.lsp_code_lens.values_mut() {
11053 buffer_lens.lens.remove(&for_server);
11054 }
11055 if let Some(local) = self.as_local_mut() {
11056 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11057 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11058 buffer_servers.remove(&for_server);
11059 }
11060 }
11061 }
11062
11063 pub fn result_id(
11064 &self,
11065 server_id: LanguageServerId,
11066 buffer_id: BufferId,
11067 cx: &App,
11068 ) -> Option<String> {
11069 let abs_path = self
11070 .buffer_store
11071 .read(cx)
11072 .get(buffer_id)
11073 .and_then(|b| File::from_dyn(b.read(cx).file()))
11074 .map(|f| f.abs_path(cx))?;
11075 self.as_local()?
11076 .buffer_pull_diagnostics_result_ids
11077 .get(&server_id)?
11078 .get(&abs_path)?
11079 .clone()
11080 }
11081
11082 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11083 let Some(local) = self.as_local() else {
11084 return HashMap::default();
11085 };
11086 local
11087 .buffer_pull_diagnostics_result_ids
11088 .get(&server_id)
11089 .into_iter()
11090 .flatten()
11091 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11092 .collect()
11093 }
11094
11095 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11096 if let Some(LanguageServerState::Running {
11097 workspace_refresh_task: Some(workspace_refresh_task),
11098 ..
11099 }) = self
11100 .as_local_mut()
11101 .and_then(|local| local.language_servers.get_mut(&server_id))
11102 {
11103 workspace_refresh_task.refresh_tx.try_send(()).ok();
11104 }
11105 }
11106
11107 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11108 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11109 return;
11110 };
11111 let Some(local) = self.as_local_mut() else {
11112 return;
11113 };
11114
11115 for server_id in buffer.update(cx, |buffer, cx| {
11116 local.language_server_ids_for_buffer(buffer, cx)
11117 }) {
11118 if let Some(LanguageServerState::Running {
11119 workspace_refresh_task: Some(workspace_refresh_task),
11120 ..
11121 }) = local.language_servers.get_mut(&server_id)
11122 {
11123 workspace_refresh_task.refresh_tx.try_send(()).ok();
11124 }
11125 }
11126 }
11127
11128 fn apply_workspace_diagnostic_report(
11129 &mut self,
11130 server_id: LanguageServerId,
11131 report: lsp::WorkspaceDiagnosticReportResult,
11132 cx: &mut Context<Self>,
11133 ) {
11134 let workspace_diagnostics =
11135 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11136 let mut unchanged_buffers = HashSet::default();
11137 let mut changed_buffers = HashSet::default();
11138 let workspace_diagnostics_updates = workspace_diagnostics
11139 .into_iter()
11140 .filter_map(
11141 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11142 LspPullDiagnostics::Response {
11143 server_id,
11144 uri,
11145 diagnostics,
11146 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11147 LspPullDiagnostics::Default => None,
11148 },
11149 )
11150 .fold(
11151 HashMap::default(),
11152 |mut acc, (server_id, uri, diagnostics, version)| {
11153 let (result_id, diagnostics) = match diagnostics {
11154 PulledDiagnostics::Unchanged { result_id } => {
11155 unchanged_buffers.insert(uri.clone());
11156 (Some(result_id), Vec::new())
11157 }
11158 PulledDiagnostics::Changed {
11159 result_id,
11160 diagnostics,
11161 } => {
11162 changed_buffers.insert(uri.clone());
11163 (result_id, diagnostics)
11164 }
11165 };
11166 let disk_based_sources = Cow::Owned(
11167 self.language_server_adapter_for_id(server_id)
11168 .as_ref()
11169 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11170 .unwrap_or(&[])
11171 .to_vec(),
11172 );
11173 acc.entry(server_id)
11174 .or_insert_with(Vec::new)
11175 .push(DocumentDiagnosticsUpdate {
11176 server_id,
11177 diagnostics: lsp::PublishDiagnosticsParams {
11178 uri,
11179 diagnostics,
11180 version,
11181 },
11182 result_id,
11183 disk_based_sources,
11184 });
11185 acc
11186 },
11187 );
11188
11189 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11190 self.merge_lsp_diagnostics(
11191 DiagnosticSourceKind::Pulled,
11192 diagnostic_updates,
11193 |buffer, old_diagnostic, cx| {
11194 File::from_dyn(buffer.file())
11195 .and_then(|file| {
11196 let abs_path = file.as_local()?.abs_path(cx);
11197 lsp::Uri::from_file_path(abs_path).ok()
11198 })
11199 .is_none_or(|buffer_uri| {
11200 unchanged_buffers.contains(&buffer_uri)
11201 || match old_diagnostic.source_kind {
11202 DiagnosticSourceKind::Pulled => {
11203 !changed_buffers.contains(&buffer_uri)
11204 }
11205 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11206 true
11207 }
11208 }
11209 })
11210 },
11211 cx,
11212 )
11213 .log_err();
11214 }
11215 }
11216
11217 fn register_server_capabilities(
11218 &mut self,
11219 server_id: LanguageServerId,
11220 params: lsp::RegistrationParams,
11221 cx: &mut Context<Self>,
11222 ) -> anyhow::Result<()> {
11223 let server = self
11224 .language_server_for_id(server_id)
11225 .with_context(|| format!("no server {server_id} found"))?;
11226 for reg in params.registrations {
11227 match reg.method.as_str() {
11228 "workspace/didChangeWatchedFiles" => {
11229 if let Some(options) = reg.register_options {
11230 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11231 let caps = serde_json::from_value(options)?;
11232 local_lsp_store
11233 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11234 true
11235 } else {
11236 false
11237 };
11238 if notify {
11239 notify_server_capabilities_updated(&server, cx);
11240 }
11241 }
11242 }
11243 "workspace/didChangeConfiguration" => {
11244 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11245 }
11246 "workspace/didChangeWorkspaceFolders" => {
11247 // In this case register options is an empty object, we can ignore it
11248 let caps = lsp::WorkspaceFoldersServerCapabilities {
11249 supported: Some(true),
11250 change_notifications: Some(OneOf::Right(reg.id)),
11251 };
11252 server.update_capabilities(|capabilities| {
11253 capabilities
11254 .workspace
11255 .get_or_insert_default()
11256 .workspace_folders = Some(caps);
11257 });
11258 notify_server_capabilities_updated(&server, cx);
11259 }
11260 "workspace/symbol" => {
11261 let options = parse_register_capabilities(reg)?;
11262 server.update_capabilities(|capabilities| {
11263 capabilities.workspace_symbol_provider = Some(options);
11264 });
11265 notify_server_capabilities_updated(&server, cx);
11266 }
11267 "workspace/fileOperations" => {
11268 if let Some(options) = reg.register_options {
11269 let caps = serde_json::from_value(options)?;
11270 server.update_capabilities(|capabilities| {
11271 capabilities
11272 .workspace
11273 .get_or_insert_default()
11274 .file_operations = Some(caps);
11275 });
11276 notify_server_capabilities_updated(&server, cx);
11277 }
11278 }
11279 "workspace/executeCommand" => {
11280 if let Some(options) = reg.register_options {
11281 let options = serde_json::from_value(options)?;
11282 server.update_capabilities(|capabilities| {
11283 capabilities.execute_command_provider = Some(options);
11284 });
11285 notify_server_capabilities_updated(&server, cx);
11286 }
11287 }
11288 "textDocument/rangeFormatting" => {
11289 let options = parse_register_capabilities(reg)?;
11290 server.update_capabilities(|capabilities| {
11291 capabilities.document_range_formatting_provider = Some(options);
11292 });
11293 notify_server_capabilities_updated(&server, cx);
11294 }
11295 "textDocument/onTypeFormatting" => {
11296 if let Some(options) = reg
11297 .register_options
11298 .map(serde_json::from_value)
11299 .transpose()?
11300 {
11301 server.update_capabilities(|capabilities| {
11302 capabilities.document_on_type_formatting_provider = Some(options);
11303 });
11304 notify_server_capabilities_updated(&server, cx);
11305 }
11306 }
11307 "textDocument/formatting" => {
11308 let options = parse_register_capabilities(reg)?;
11309 server.update_capabilities(|capabilities| {
11310 capabilities.document_formatting_provider = Some(options);
11311 });
11312 notify_server_capabilities_updated(&server, cx);
11313 }
11314 "textDocument/rename" => {
11315 let options = parse_register_capabilities(reg)?;
11316 server.update_capabilities(|capabilities| {
11317 capabilities.rename_provider = Some(options);
11318 });
11319 notify_server_capabilities_updated(&server, cx);
11320 }
11321 "textDocument/inlayHint" => {
11322 let options = parse_register_capabilities(reg)?;
11323 server.update_capabilities(|capabilities| {
11324 capabilities.inlay_hint_provider = Some(options);
11325 });
11326 notify_server_capabilities_updated(&server, cx);
11327 }
11328 "textDocument/documentSymbol" => {
11329 let options = parse_register_capabilities(reg)?;
11330 server.update_capabilities(|capabilities| {
11331 capabilities.document_symbol_provider = Some(options);
11332 });
11333 notify_server_capabilities_updated(&server, cx);
11334 }
11335 "textDocument/codeAction" => {
11336 let options = parse_register_capabilities(reg)?;
11337 let provider = match options {
11338 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11339 OneOf::Right(caps) => caps,
11340 };
11341 server.update_capabilities(|capabilities| {
11342 capabilities.code_action_provider = Some(provider);
11343 });
11344 notify_server_capabilities_updated(&server, cx);
11345 }
11346 "textDocument/definition" => {
11347 let options = parse_register_capabilities(reg)?;
11348 server.update_capabilities(|capabilities| {
11349 capabilities.definition_provider = Some(options);
11350 });
11351 notify_server_capabilities_updated(&server, cx);
11352 }
11353 "textDocument/completion" => {
11354 if let Some(caps) = reg
11355 .register_options
11356 .map(serde_json::from_value)
11357 .transpose()?
11358 {
11359 server.update_capabilities(|capabilities| {
11360 capabilities.completion_provider = Some(caps);
11361 });
11362 notify_server_capabilities_updated(&server, cx);
11363 }
11364 }
11365 "textDocument/hover" => {
11366 let options = parse_register_capabilities(reg)?;
11367 let provider = match options {
11368 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11369 OneOf::Right(caps) => caps,
11370 };
11371 server.update_capabilities(|capabilities| {
11372 capabilities.hover_provider = Some(provider);
11373 });
11374 notify_server_capabilities_updated(&server, cx);
11375 }
11376 "textDocument/signatureHelp" => {
11377 if let Some(caps) = reg
11378 .register_options
11379 .map(serde_json::from_value)
11380 .transpose()?
11381 {
11382 server.update_capabilities(|capabilities| {
11383 capabilities.signature_help_provider = Some(caps);
11384 });
11385 notify_server_capabilities_updated(&server, cx);
11386 }
11387 }
11388 "textDocument/didChange" => {
11389 if let Some(sync_kind) = reg
11390 .register_options
11391 .and_then(|opts| opts.get("syncKind").cloned())
11392 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11393 .transpose()?
11394 {
11395 server.update_capabilities(|capabilities| {
11396 let mut sync_options =
11397 Self::take_text_document_sync_options(capabilities);
11398 sync_options.change = Some(sync_kind);
11399 capabilities.text_document_sync =
11400 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11401 });
11402 notify_server_capabilities_updated(&server, cx);
11403 }
11404 }
11405 "textDocument/didSave" => {
11406 if let Some(include_text) = reg
11407 .register_options
11408 .map(|opts| {
11409 let transpose = opts
11410 .get("includeText")
11411 .cloned()
11412 .map(serde_json::from_value::<Option<bool>>)
11413 .transpose();
11414 match transpose {
11415 Ok(value) => Ok(value.flatten()),
11416 Err(e) => Err(e),
11417 }
11418 })
11419 .transpose()?
11420 {
11421 server.update_capabilities(|capabilities| {
11422 let mut sync_options =
11423 Self::take_text_document_sync_options(capabilities);
11424 sync_options.save =
11425 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11426 include_text,
11427 }));
11428 capabilities.text_document_sync =
11429 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11430 });
11431 notify_server_capabilities_updated(&server, cx);
11432 }
11433 }
11434 "textDocument/codeLens" => {
11435 if let Some(caps) = reg
11436 .register_options
11437 .map(serde_json::from_value)
11438 .transpose()?
11439 {
11440 server.update_capabilities(|capabilities| {
11441 capabilities.code_lens_provider = Some(caps);
11442 });
11443 notify_server_capabilities_updated(&server, cx);
11444 }
11445 }
11446 "textDocument/diagnostic" => {
11447 if let Some(caps) = reg
11448 .register_options
11449 .map(serde_json::from_value)
11450 .transpose()?
11451 {
11452 let state = self
11453 .as_local_mut()
11454 .context("Expected LSP Store to be local")?
11455 .language_servers
11456 .get_mut(&server_id)
11457 .context("Could not obtain Language Servers state")?;
11458 server.update_capabilities(|capabilities| {
11459 capabilities.diagnostic_provider = Some(caps);
11460 });
11461 if let LanguageServerState::Running {
11462 workspace_refresh_task,
11463 ..
11464 } = state
11465 && workspace_refresh_task.is_none()
11466 {
11467 *workspace_refresh_task =
11468 lsp_workspace_diagnostics_refresh(server.clone(), cx)
11469 }
11470
11471 notify_server_capabilities_updated(&server, cx);
11472 }
11473 }
11474 "textDocument/documentColor" => {
11475 let options = parse_register_capabilities(reg)?;
11476 let provider = match options {
11477 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11478 OneOf::Right(caps) => caps,
11479 };
11480 server.update_capabilities(|capabilities| {
11481 capabilities.color_provider = Some(provider);
11482 });
11483 notify_server_capabilities_updated(&server, cx);
11484 }
11485 _ => log::warn!("unhandled capability registration: {reg:?}"),
11486 }
11487 }
11488
11489 Ok(())
11490 }
11491
11492 fn unregister_server_capabilities(
11493 &mut self,
11494 server_id: LanguageServerId,
11495 params: lsp::UnregistrationParams,
11496 cx: &mut Context<Self>,
11497 ) -> anyhow::Result<()> {
11498 let server = self
11499 .language_server_for_id(server_id)
11500 .with_context(|| format!("no server {server_id} found"))?;
11501 for unreg in params.unregisterations.iter() {
11502 match unreg.method.as_str() {
11503 "workspace/didChangeWatchedFiles" => {
11504 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11505 local_lsp_store
11506 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11507 true
11508 } else {
11509 false
11510 };
11511 if notify {
11512 notify_server_capabilities_updated(&server, cx);
11513 }
11514 }
11515 "workspace/didChangeConfiguration" => {
11516 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11517 }
11518 "workspace/didChangeWorkspaceFolders" => {
11519 server.update_capabilities(|capabilities| {
11520 capabilities
11521 .workspace
11522 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11523 workspace_folders: None,
11524 file_operations: None,
11525 })
11526 .workspace_folders = None;
11527 });
11528 notify_server_capabilities_updated(&server, cx);
11529 }
11530 "workspace/symbol" => {
11531 server.update_capabilities(|capabilities| {
11532 capabilities.workspace_symbol_provider = None
11533 });
11534 notify_server_capabilities_updated(&server, cx);
11535 }
11536 "workspace/fileOperations" => {
11537 server.update_capabilities(|capabilities| {
11538 capabilities
11539 .workspace
11540 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11541 workspace_folders: None,
11542 file_operations: None,
11543 })
11544 .file_operations = None;
11545 });
11546 notify_server_capabilities_updated(&server, cx);
11547 }
11548 "workspace/executeCommand" => {
11549 server.update_capabilities(|capabilities| {
11550 capabilities.execute_command_provider = None;
11551 });
11552 notify_server_capabilities_updated(&server, cx);
11553 }
11554 "textDocument/rangeFormatting" => {
11555 server.update_capabilities(|capabilities| {
11556 capabilities.document_range_formatting_provider = None
11557 });
11558 notify_server_capabilities_updated(&server, cx);
11559 }
11560 "textDocument/onTypeFormatting" => {
11561 server.update_capabilities(|capabilities| {
11562 capabilities.document_on_type_formatting_provider = None;
11563 });
11564 notify_server_capabilities_updated(&server, cx);
11565 }
11566 "textDocument/formatting" => {
11567 server.update_capabilities(|capabilities| {
11568 capabilities.document_formatting_provider = None;
11569 });
11570 notify_server_capabilities_updated(&server, cx);
11571 }
11572 "textDocument/rename" => {
11573 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11574 notify_server_capabilities_updated(&server, cx);
11575 }
11576 "textDocument/codeAction" => {
11577 server.update_capabilities(|capabilities| {
11578 capabilities.code_action_provider = None;
11579 });
11580 notify_server_capabilities_updated(&server, cx);
11581 }
11582 "textDocument/definition" => {
11583 server.update_capabilities(|capabilities| {
11584 capabilities.definition_provider = None;
11585 });
11586 notify_server_capabilities_updated(&server, cx);
11587 }
11588 "textDocument/completion" => {
11589 server.update_capabilities(|capabilities| {
11590 capabilities.completion_provider = None;
11591 });
11592 notify_server_capabilities_updated(&server, cx);
11593 }
11594 "textDocument/hover" => {
11595 server.update_capabilities(|capabilities| {
11596 capabilities.hover_provider = None;
11597 });
11598 notify_server_capabilities_updated(&server, cx);
11599 }
11600 "textDocument/signatureHelp" => {
11601 server.update_capabilities(|capabilities| {
11602 capabilities.signature_help_provider = None;
11603 });
11604 notify_server_capabilities_updated(&server, cx);
11605 }
11606 "textDocument/didChange" => {
11607 server.update_capabilities(|capabilities| {
11608 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11609 sync_options.change = None;
11610 capabilities.text_document_sync =
11611 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11612 });
11613 notify_server_capabilities_updated(&server, cx);
11614 }
11615 "textDocument/didSave" => {
11616 server.update_capabilities(|capabilities| {
11617 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11618 sync_options.save = None;
11619 capabilities.text_document_sync =
11620 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11621 });
11622 notify_server_capabilities_updated(&server, cx);
11623 }
11624 "textDocument/codeLens" => {
11625 server.update_capabilities(|capabilities| {
11626 capabilities.code_lens_provider = None;
11627 });
11628 notify_server_capabilities_updated(&server, cx);
11629 }
11630 "textDocument/diagnostic" => {
11631 server.update_capabilities(|capabilities| {
11632 capabilities.diagnostic_provider = None;
11633 });
11634 let state = self
11635 .as_local_mut()
11636 .context("Expected LSP Store to be local")?
11637 .language_servers
11638 .get_mut(&server_id)
11639 .context("Could not obtain Language Servers state")?;
11640 if let LanguageServerState::Running {
11641 workspace_refresh_task,
11642 ..
11643 } = state
11644 {
11645 _ = workspace_refresh_task.take();
11646 }
11647 notify_server_capabilities_updated(&server, cx);
11648 }
11649 "textDocument/documentColor" => {
11650 server.update_capabilities(|capabilities| {
11651 capabilities.color_provider = None;
11652 });
11653 notify_server_capabilities_updated(&server, cx);
11654 }
11655 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
11656 }
11657 }
11658
11659 Ok(())
11660 }
11661
11662 async fn query_lsp_locally<T>(
11663 lsp_store: Entity<Self>,
11664 sender_id: proto::PeerId,
11665 lsp_request_id: LspRequestId,
11666 proto_request: T::ProtoRequest,
11667 position: Option<Anchor>,
11668 mut cx: AsyncApp,
11669 ) -> Result<()>
11670 where
11671 T: LspCommand + Clone,
11672 T::ProtoRequest: proto::LspRequestMessage,
11673 <T::ProtoRequest as proto::RequestMessage>::Response:
11674 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
11675 {
11676 let buffer_id = BufferId::new(proto_request.buffer_id())?;
11677 let version = deserialize_version(proto_request.buffer_version());
11678 let buffer = lsp_store.update(&mut cx, |this, cx| {
11679 this.buffer_store.read(cx).get_existing(buffer_id)
11680 })??;
11681 buffer
11682 .update(&mut cx, |buffer, _| {
11683 buffer.wait_for_version(version.clone())
11684 })?
11685 .await?;
11686 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
11687 let request =
11688 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
11689 lsp_store.update(&mut cx, |lsp_store, cx| {
11690 let request_task =
11691 lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx);
11692 let existing_queries = lsp_store
11693 .running_lsp_requests
11694 .entry(TypeId::of::<T>())
11695 .or_default();
11696 if T::ProtoRequest::stop_previous_requests()
11697 || buffer_version.changed_since(&existing_queries.0)
11698 {
11699 existing_queries.1.clear();
11700 }
11701 existing_queries.1.insert(
11702 lsp_request_id,
11703 cx.spawn(async move |lsp_store, cx| {
11704 let response = request_task.await;
11705 lsp_store
11706 .update(cx, |lsp_store, cx| {
11707 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
11708 {
11709 let response = response
11710 .into_iter()
11711 .map(|(server_id, response)| {
11712 (
11713 server_id.to_proto(),
11714 T::response_to_proto(
11715 response,
11716 lsp_store,
11717 sender_id,
11718 &buffer_version,
11719 cx,
11720 )
11721 .into(),
11722 )
11723 })
11724 .collect::<HashMap<_, _>>();
11725 match client.send_lsp_response::<T::ProtoRequest>(
11726 project_id,
11727 lsp_request_id,
11728 response,
11729 ) {
11730 Ok(()) => {}
11731 Err(e) => {
11732 log::error!("Failed to send LSP response: {e:#}",)
11733 }
11734 }
11735 }
11736 })
11737 .ok();
11738 }),
11739 );
11740 })?;
11741 Ok(())
11742 }
11743
11744 fn take_text_document_sync_options(
11745 capabilities: &mut lsp::ServerCapabilities,
11746 ) -> lsp::TextDocumentSyncOptions {
11747 match capabilities.text_document_sync.take() {
11748 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
11749 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
11750 let mut sync_options = lsp::TextDocumentSyncOptions::default();
11751 sync_options.change = Some(sync_kind);
11752 sync_options
11753 }
11754 None => lsp::TextDocumentSyncOptions::default(),
11755 }
11756 }
11757
11758 #[cfg(any(test, feature = "test-support"))]
11759 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
11760 let data = self.lsp_code_lens.get_mut(&buffer_id)?;
11761 Some(data.update.take()?.1)
11762 }
11763
11764 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
11765 self.downstream_client.clone()
11766 }
11767
11768 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
11769 self.worktree_store.clone()
11770 }
11771}
11772
11773// Registration with registerOptions as null, should fallback to true.
11774// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
11775fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
11776 reg: lsp::Registration,
11777) -> Result<OneOf<bool, T>> {
11778 Ok(match reg.register_options {
11779 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
11780 None => OneOf::Left(true),
11781 })
11782}
11783
11784fn subscribe_to_binary_statuses(
11785 languages: &Arc<LanguageRegistry>,
11786 cx: &mut Context<'_, LspStore>,
11787) -> Task<()> {
11788 let mut server_statuses = languages.language_server_binary_statuses();
11789 cx.spawn(async move |lsp_store, cx| {
11790 while let Some((server_name, binary_status)) = server_statuses.next().await {
11791 if lsp_store
11792 .update(cx, |_, cx| {
11793 let mut message = None;
11794 let binary_status = match binary_status {
11795 BinaryStatus::None => proto::ServerBinaryStatus::None,
11796 BinaryStatus::CheckingForUpdate => {
11797 proto::ServerBinaryStatus::CheckingForUpdate
11798 }
11799 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
11800 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
11801 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
11802 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
11803 BinaryStatus::Failed { error } => {
11804 message = Some(error);
11805 proto::ServerBinaryStatus::Failed
11806 }
11807 };
11808 cx.emit(LspStoreEvent::LanguageServerUpdate {
11809 // Binary updates are about the binary that might not have any language server id at that point.
11810 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
11811 language_server_id: LanguageServerId(0),
11812 name: Some(server_name),
11813 message: proto::update_language_server::Variant::StatusUpdate(
11814 proto::StatusUpdate {
11815 message,
11816 status: Some(proto::status_update::Status::Binary(
11817 binary_status as i32,
11818 )),
11819 },
11820 ),
11821 });
11822 })
11823 .is_err()
11824 {
11825 break;
11826 }
11827 }
11828 })
11829}
11830
11831fn lsp_workspace_diagnostics_refresh(
11832 server: Arc<LanguageServer>,
11833 cx: &mut Context<'_, LspStore>,
11834) -> Option<WorkspaceRefreshTask> {
11835 let identifier = match server.capabilities().diagnostic_provider? {
11836 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
11837 if !diagnostic_options.workspace_diagnostics {
11838 return None;
11839 }
11840 diagnostic_options.identifier
11841 }
11842 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
11843 let diagnostic_options = registration_options.diagnostic_options;
11844 if !diagnostic_options.workspace_diagnostics {
11845 return None;
11846 }
11847 diagnostic_options.identifier
11848 }
11849 };
11850
11851 let (progress_tx, mut progress_rx) = mpsc::channel(1);
11852 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
11853 refresh_tx.try_send(()).ok();
11854
11855 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
11856 let mut attempts = 0;
11857 let max_attempts = 50;
11858 let mut requests = 0;
11859
11860 loop {
11861 let Some(()) = refresh_rx.recv().await else {
11862 return;
11863 };
11864
11865 'request: loop {
11866 requests += 1;
11867 if attempts > max_attempts {
11868 log::error!(
11869 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
11870 );
11871 return;
11872 }
11873 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
11874 cx.background_executor()
11875 .timer(Duration::from_millis(backoff_millis))
11876 .await;
11877 attempts += 1;
11878
11879 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
11880 lsp_store
11881 .all_result_ids(server.server_id())
11882 .into_iter()
11883 .filter_map(|(abs_path, result_id)| {
11884 let uri = file_path_to_lsp_url(&abs_path).ok()?;
11885 Some(lsp::PreviousResultId {
11886 uri,
11887 value: result_id,
11888 })
11889 })
11890 .collect()
11891 }) else {
11892 return;
11893 };
11894
11895 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
11896
11897 progress_rx.try_recv().ok();
11898 let timer =
11899 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
11900 let progress = pin!(progress_rx.recv().fuse());
11901 let response_result = server
11902 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
11903 lsp::WorkspaceDiagnosticParams {
11904 previous_result_ids,
11905 identifier: identifier.clone(),
11906 work_done_progress_params: Default::default(),
11907 partial_result_params: lsp::PartialResultParams {
11908 partial_result_token: Some(lsp::ProgressToken::String(token)),
11909 },
11910 },
11911 select(timer, progress).then(|either| match either {
11912 Either::Left((message, ..)) => ready(message).left_future(),
11913 Either::Right(..) => pending::<String>().right_future(),
11914 }),
11915 )
11916 .await;
11917
11918 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
11919 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
11920 match response_result {
11921 ConnectionResult::Timeout => {
11922 log::error!("Timeout during workspace diagnostics pull");
11923 continue 'request;
11924 }
11925 ConnectionResult::ConnectionReset => {
11926 log::error!("Server closed a workspace diagnostics pull request");
11927 continue 'request;
11928 }
11929 ConnectionResult::Result(Err(e)) => {
11930 log::error!("Error during workspace diagnostics pull: {e:#}");
11931 break 'request;
11932 }
11933 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
11934 attempts = 0;
11935 if lsp_store
11936 .update(cx, |lsp_store, cx| {
11937 lsp_store.apply_workspace_diagnostic_report(
11938 server.server_id(),
11939 pulled_diagnostics,
11940 cx,
11941 )
11942 })
11943 .is_err()
11944 {
11945 return;
11946 }
11947 break 'request;
11948 }
11949 }
11950 }
11951 }
11952 });
11953
11954 Some(WorkspaceRefreshTask {
11955 refresh_tx,
11956 progress_tx,
11957 task: workspace_query_language_server,
11958 })
11959}
11960
11961fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
11962 let CompletionSource::BufferWord {
11963 word_range,
11964 resolved,
11965 } = &mut completion.source
11966 else {
11967 return;
11968 };
11969 if *resolved {
11970 return;
11971 }
11972
11973 if completion.new_text
11974 != snapshot
11975 .text_for_range(word_range.clone())
11976 .collect::<String>()
11977 {
11978 return;
11979 }
11980
11981 let mut offset = 0;
11982 for chunk in snapshot.chunks(word_range.clone(), true) {
11983 let end_offset = offset + chunk.text.len();
11984 if let Some(highlight_id) = chunk.syntax_highlight_id {
11985 completion
11986 .label
11987 .runs
11988 .push((offset..end_offset, highlight_id));
11989 }
11990 offset = end_offset;
11991 }
11992 *resolved = true;
11993}
11994
11995impl EventEmitter<LspStoreEvent> for LspStore {}
11996
11997fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
11998 hover
11999 .contents
12000 .retain(|hover_block| !hover_block.text.trim().is_empty());
12001 if hover.contents.is_empty() {
12002 None
12003 } else {
12004 Some(hover)
12005 }
12006}
12007
12008async fn populate_labels_for_completions(
12009 new_completions: Vec<CoreCompletion>,
12010 language: Option<Arc<Language>>,
12011 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12012) -> Vec<Completion> {
12013 let lsp_completions = new_completions
12014 .iter()
12015 .filter_map(|new_completion| {
12016 new_completion
12017 .source
12018 .lsp_completion(true)
12019 .map(|lsp_completion| lsp_completion.into_owned())
12020 })
12021 .collect::<Vec<_>>();
12022
12023 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12024 lsp_adapter
12025 .labels_for_completions(&lsp_completions, language)
12026 .await
12027 .log_err()
12028 .unwrap_or_default()
12029 } else {
12030 Vec::new()
12031 }
12032 .into_iter()
12033 .fuse();
12034
12035 let mut completions = Vec::new();
12036 for completion in new_completions {
12037 match completion.source.lsp_completion(true) {
12038 Some(lsp_completion) => {
12039 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12040
12041 let mut label = labels.next().flatten().unwrap_or_else(|| {
12042 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12043 });
12044 ensure_uniform_list_compatible_label(&mut label);
12045 completions.push(Completion {
12046 label,
12047 documentation,
12048 replace_range: completion.replace_range,
12049 new_text: completion.new_text,
12050 insert_text_mode: lsp_completion.insert_text_mode,
12051 source: completion.source,
12052 icon_path: None,
12053 confirm: None,
12054 });
12055 }
12056 None => {
12057 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12058 ensure_uniform_list_compatible_label(&mut label);
12059 completions.push(Completion {
12060 label,
12061 documentation: None,
12062 replace_range: completion.replace_range,
12063 new_text: completion.new_text,
12064 source: completion.source,
12065 insert_text_mode: None,
12066 icon_path: None,
12067 confirm: None,
12068 });
12069 }
12070 }
12071 }
12072 completions
12073}
12074
12075#[derive(Debug)]
12076pub enum LanguageServerToQuery {
12077 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12078 FirstCapable,
12079 /// Query a specific language server.
12080 Other(LanguageServerId),
12081}
12082
12083#[derive(Default)]
12084struct RenamePathsWatchedForServer {
12085 did_rename: Vec<RenameActionPredicate>,
12086 will_rename: Vec<RenameActionPredicate>,
12087}
12088
12089impl RenamePathsWatchedForServer {
12090 fn with_did_rename_patterns(
12091 mut self,
12092 did_rename: Option<&FileOperationRegistrationOptions>,
12093 ) -> Self {
12094 if let Some(did_rename) = did_rename {
12095 self.did_rename = did_rename
12096 .filters
12097 .iter()
12098 .filter_map(|filter| filter.try_into().log_err())
12099 .collect();
12100 }
12101 self
12102 }
12103 fn with_will_rename_patterns(
12104 mut self,
12105 will_rename: Option<&FileOperationRegistrationOptions>,
12106 ) -> Self {
12107 if let Some(will_rename) = will_rename {
12108 self.will_rename = will_rename
12109 .filters
12110 .iter()
12111 .filter_map(|filter| filter.try_into().log_err())
12112 .collect();
12113 }
12114 self
12115 }
12116
12117 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12118 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12119 }
12120 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12121 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12122 }
12123}
12124
12125impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12126 type Error = globset::Error;
12127 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12128 Ok(Self {
12129 kind: ops.pattern.matches.clone(),
12130 glob: GlobBuilder::new(&ops.pattern.glob)
12131 .case_insensitive(
12132 ops.pattern
12133 .options
12134 .as_ref()
12135 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12136 )
12137 .build()?
12138 .compile_matcher(),
12139 })
12140 }
12141}
12142struct RenameActionPredicate {
12143 glob: GlobMatcher,
12144 kind: Option<FileOperationPatternKind>,
12145}
12146
12147impl RenameActionPredicate {
12148 // Returns true if language server should be notified
12149 fn eval(&self, path: &str, is_dir: bool) -> bool {
12150 self.kind.as_ref().is_none_or(|kind| {
12151 let expected_kind = if is_dir {
12152 FileOperationPatternKind::Folder
12153 } else {
12154 FileOperationPatternKind::File
12155 };
12156 kind == &expected_kind
12157 }) && self.glob.is_match(path)
12158 }
12159}
12160
12161#[derive(Default)]
12162struct LanguageServerWatchedPaths {
12163 worktree_paths: HashMap<WorktreeId, GlobSet>,
12164 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12165}
12166
12167#[derive(Default)]
12168struct LanguageServerWatchedPathsBuilder {
12169 worktree_paths: HashMap<WorktreeId, GlobSet>,
12170 abs_paths: HashMap<Arc<Path>, GlobSet>,
12171}
12172
12173impl LanguageServerWatchedPathsBuilder {
12174 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12175 self.worktree_paths.insert(worktree_id, glob_set);
12176 }
12177 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12178 self.abs_paths.insert(path, glob_set);
12179 }
12180 fn build(
12181 self,
12182 fs: Arc<dyn Fs>,
12183 language_server_id: LanguageServerId,
12184 cx: &mut Context<LspStore>,
12185 ) -> LanguageServerWatchedPaths {
12186 let project = cx.weak_entity();
12187
12188 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12189 let abs_paths = self
12190 .abs_paths
12191 .into_iter()
12192 .map(|(abs_path, globset)| {
12193 let task = cx.spawn({
12194 let abs_path = abs_path.clone();
12195 let fs = fs.clone();
12196
12197 let lsp_store = project.clone();
12198 async move |_, cx| {
12199 maybe!(async move {
12200 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12201 while let Some(update) = push_updates.0.next().await {
12202 let action = lsp_store
12203 .update(cx, |this, _| {
12204 let Some(local) = this.as_local() else {
12205 return ControlFlow::Break(());
12206 };
12207 let Some(watcher) = local
12208 .language_server_watched_paths
12209 .get(&language_server_id)
12210 else {
12211 return ControlFlow::Break(());
12212 };
12213 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12214 "Watched abs path is not registered with a watcher",
12215 );
12216 let matching_entries = update
12217 .into_iter()
12218 .filter(|event| globs.is_match(&event.path))
12219 .collect::<Vec<_>>();
12220 this.lsp_notify_abs_paths_changed(
12221 language_server_id,
12222 matching_entries,
12223 );
12224 ControlFlow::Continue(())
12225 })
12226 .ok()?;
12227
12228 if action.is_break() {
12229 break;
12230 }
12231 }
12232 Some(())
12233 })
12234 .await;
12235 }
12236 });
12237 (abs_path, (globset, task))
12238 })
12239 .collect();
12240 LanguageServerWatchedPaths {
12241 worktree_paths: self.worktree_paths,
12242 abs_paths,
12243 }
12244 }
12245}
12246
12247struct LspBufferSnapshot {
12248 version: i32,
12249 snapshot: TextBufferSnapshot,
12250}
12251
12252/// A prompt requested by LSP server.
12253#[derive(Clone, Debug)]
12254pub struct LanguageServerPromptRequest {
12255 pub level: PromptLevel,
12256 pub message: String,
12257 pub actions: Vec<MessageActionItem>,
12258 pub lsp_name: String,
12259 pub(crate) response_channel: Sender<MessageActionItem>,
12260}
12261
12262impl LanguageServerPromptRequest {
12263 pub async fn respond(self, index: usize) -> Option<()> {
12264 if let Some(response) = self.actions.into_iter().nth(index) {
12265 self.response_channel.send(response).await.ok()
12266 } else {
12267 None
12268 }
12269 }
12270}
12271impl PartialEq for LanguageServerPromptRequest {
12272 fn eq(&self, other: &Self) -> bool {
12273 self.message == other.message && self.actions == other.actions
12274 }
12275}
12276
12277#[derive(Clone, Debug, PartialEq)]
12278pub enum LanguageServerLogType {
12279 Log(MessageType),
12280 Trace { verbose_info: Option<String> },
12281 Rpc { received: bool },
12282}
12283
12284impl LanguageServerLogType {
12285 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12286 match self {
12287 Self::Log(log_type) => {
12288 use proto::log_message::LogLevel;
12289 let level = match *log_type {
12290 MessageType::ERROR => LogLevel::Error,
12291 MessageType::WARNING => LogLevel::Warning,
12292 MessageType::INFO => LogLevel::Info,
12293 MessageType::LOG => LogLevel::Log,
12294 other => {
12295 log::warn!("Unknown lsp log message type: {other:?}");
12296 LogLevel::Log
12297 }
12298 };
12299 proto::language_server_log::LogType::Log(proto::LogMessage {
12300 level: level as i32,
12301 })
12302 }
12303 Self::Trace { verbose_info } => {
12304 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12305 verbose_info: verbose_info.to_owned(),
12306 })
12307 }
12308 Self::Rpc { received } => {
12309 let kind = if *received {
12310 proto::rpc_message::Kind::Received
12311 } else {
12312 proto::rpc_message::Kind::Sent
12313 };
12314 let kind = kind as i32;
12315 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12316 }
12317 }
12318 }
12319
12320 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12321 use proto::log_message::LogLevel;
12322 use proto::rpc_message;
12323 match log_type {
12324 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12325 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12326 LogLevel::Error => MessageType::ERROR,
12327 LogLevel::Warning => MessageType::WARNING,
12328 LogLevel::Info => MessageType::INFO,
12329 LogLevel::Log => MessageType::LOG,
12330 },
12331 ),
12332 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12333 verbose_info: trace_message.verbose_info,
12334 },
12335 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12336 received: match rpc_message::Kind::from_i32(message.kind)
12337 .unwrap_or(rpc_message::Kind::Received)
12338 {
12339 rpc_message::Kind::Received => true,
12340 rpc_message::Kind::Sent => false,
12341 },
12342 },
12343 }
12344 }
12345}
12346
12347pub struct WorkspaceRefreshTask {
12348 refresh_tx: mpsc::Sender<()>,
12349 progress_tx: mpsc::Sender<()>,
12350 #[allow(dead_code)]
12351 task: Task<()>,
12352}
12353
12354pub enum LanguageServerState {
12355 Starting {
12356 startup: Task<Option<Arc<LanguageServer>>>,
12357 /// List of language servers that will be added to the workspace once it's initialization completes.
12358 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12359 },
12360
12361 Running {
12362 adapter: Arc<CachedLspAdapter>,
12363 server: Arc<LanguageServer>,
12364 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12365 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12366 },
12367}
12368
12369impl LanguageServerState {
12370 fn add_workspace_folder(&self, uri: Uri) {
12371 match self {
12372 LanguageServerState::Starting {
12373 pending_workspace_folders,
12374 ..
12375 } => {
12376 pending_workspace_folders.lock().insert(uri);
12377 }
12378 LanguageServerState::Running { server, .. } => {
12379 server.add_workspace_folder(uri);
12380 }
12381 }
12382 }
12383 fn _remove_workspace_folder(&self, uri: Uri) {
12384 match self {
12385 LanguageServerState::Starting {
12386 pending_workspace_folders,
12387 ..
12388 } => {
12389 pending_workspace_folders.lock().remove(&uri);
12390 }
12391 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12392 }
12393 }
12394}
12395
12396impl std::fmt::Debug for LanguageServerState {
12397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12398 match self {
12399 LanguageServerState::Starting { .. } => {
12400 f.debug_struct("LanguageServerState::Starting").finish()
12401 }
12402 LanguageServerState::Running { .. } => {
12403 f.debug_struct("LanguageServerState::Running").finish()
12404 }
12405 }
12406 }
12407}
12408
12409#[derive(Clone, Debug, Serialize)]
12410pub struct LanguageServerProgress {
12411 pub is_disk_based_diagnostics_progress: bool,
12412 pub is_cancellable: bool,
12413 pub title: Option<String>,
12414 pub message: Option<String>,
12415 pub percentage: Option<usize>,
12416 #[serde(skip_serializing)]
12417 pub last_update_at: Instant,
12418}
12419
12420#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12421pub struct DiagnosticSummary {
12422 pub error_count: usize,
12423 pub warning_count: usize,
12424}
12425
12426impl DiagnosticSummary {
12427 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12428 let mut this = Self {
12429 error_count: 0,
12430 warning_count: 0,
12431 };
12432
12433 for entry in diagnostics {
12434 if entry.diagnostic.is_primary {
12435 match entry.diagnostic.severity {
12436 DiagnosticSeverity::ERROR => this.error_count += 1,
12437 DiagnosticSeverity::WARNING => this.warning_count += 1,
12438 _ => {}
12439 }
12440 }
12441 }
12442
12443 this
12444 }
12445
12446 pub fn is_empty(&self) -> bool {
12447 self.error_count == 0 && self.warning_count == 0
12448 }
12449
12450 pub fn to_proto(
12451 self,
12452 language_server_id: LanguageServerId,
12453 path: &RelPath,
12454 ) -> proto::DiagnosticSummary {
12455 proto::DiagnosticSummary {
12456 path: path.to_proto(),
12457 language_server_id: language_server_id.0 as u64,
12458 error_count: self.error_count as u32,
12459 warning_count: self.warning_count as u32,
12460 }
12461 }
12462}
12463
12464#[derive(Clone, Debug)]
12465pub enum CompletionDocumentation {
12466 /// There is no documentation for this completion.
12467 Undocumented,
12468 /// A single line of documentation.
12469 SingleLine(SharedString),
12470 /// Multiple lines of plain text documentation.
12471 MultiLinePlainText(SharedString),
12472 /// Markdown documentation.
12473 MultiLineMarkdown(SharedString),
12474 /// Both single line and multiple lines of plain text documentation.
12475 SingleLineAndMultiLinePlainText {
12476 single_line: SharedString,
12477 plain_text: Option<SharedString>,
12478 },
12479}
12480
12481impl CompletionDocumentation {
12482 #[cfg(any(test, feature = "test-support"))]
12483 pub fn text(&self) -> SharedString {
12484 match self {
12485 CompletionDocumentation::Undocumented => "".into(),
12486 CompletionDocumentation::SingleLine(s) => s.clone(),
12487 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
12488 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
12489 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
12490 single_line.clone()
12491 }
12492 }
12493 }
12494}
12495
12496impl From<lsp::Documentation> for CompletionDocumentation {
12497 fn from(docs: lsp::Documentation) -> Self {
12498 match docs {
12499 lsp::Documentation::String(text) => {
12500 if text.lines().count() <= 1 {
12501 CompletionDocumentation::SingleLine(text.into())
12502 } else {
12503 CompletionDocumentation::MultiLinePlainText(text.into())
12504 }
12505 }
12506
12507 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12508 lsp::MarkupKind::PlainText => {
12509 if value.lines().count() <= 1 {
12510 CompletionDocumentation::SingleLine(value.into())
12511 } else {
12512 CompletionDocumentation::MultiLinePlainText(value.into())
12513 }
12514 }
12515
12516 lsp::MarkupKind::Markdown => {
12517 CompletionDocumentation::MultiLineMarkdown(value.into())
12518 }
12519 },
12520 }
12521 }
12522}
12523
12524fn glob_literal_prefix(glob: &Path) -> PathBuf {
12525 glob.components()
12526 .take_while(|component| match component {
12527 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12528 _ => true,
12529 })
12530 .collect()
12531}
12532
12533pub struct SshLspAdapter {
12534 name: LanguageServerName,
12535 binary: LanguageServerBinary,
12536 initialization_options: Option<String>,
12537 code_action_kinds: Option<Vec<CodeActionKind>>,
12538}
12539
12540impl SshLspAdapter {
12541 pub fn new(
12542 name: LanguageServerName,
12543 binary: LanguageServerBinary,
12544 initialization_options: Option<String>,
12545 code_action_kinds: Option<String>,
12546 ) -> Self {
12547 Self {
12548 name,
12549 binary,
12550 initialization_options,
12551 code_action_kinds: code_action_kinds
12552 .as_ref()
12553 .and_then(|c| serde_json::from_str(c).ok()),
12554 }
12555 }
12556}
12557
12558impl LspInstaller for SshLspAdapter {
12559 type BinaryVersion = ();
12560 async fn check_if_user_installed(
12561 &self,
12562 _: &dyn LspAdapterDelegate,
12563 _: Option<Toolchain>,
12564 _: &AsyncApp,
12565 ) -> Option<LanguageServerBinary> {
12566 Some(self.binary.clone())
12567 }
12568
12569 async fn cached_server_binary(
12570 &self,
12571 _: PathBuf,
12572 _: &dyn LspAdapterDelegate,
12573 ) -> Option<LanguageServerBinary> {
12574 None
12575 }
12576
12577 async fn fetch_latest_server_version(
12578 &self,
12579 _: &dyn LspAdapterDelegate,
12580 _: bool,
12581 _: &mut AsyncApp,
12582 ) -> Result<()> {
12583 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12584 }
12585
12586 async fn fetch_server_binary(
12587 &self,
12588 _: (),
12589 _: PathBuf,
12590 _: &dyn LspAdapterDelegate,
12591 ) -> Result<LanguageServerBinary> {
12592 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12593 }
12594}
12595
12596#[async_trait(?Send)]
12597impl LspAdapter for SshLspAdapter {
12598 fn name(&self) -> LanguageServerName {
12599 self.name.clone()
12600 }
12601
12602 async fn initialization_options(
12603 self: Arc<Self>,
12604 _: &Arc<dyn LspAdapterDelegate>,
12605 ) -> Result<Option<serde_json::Value>> {
12606 let Some(options) = &self.initialization_options else {
12607 return Ok(None);
12608 };
12609 let result = serde_json::from_str(options)?;
12610 Ok(result)
12611 }
12612
12613 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12614 self.code_action_kinds.clone()
12615 }
12616}
12617
12618pub fn language_server_settings<'a>(
12619 delegate: &'a dyn LspAdapterDelegate,
12620 language: &LanguageServerName,
12621 cx: &'a App,
12622) -> Option<&'a LspSettings> {
12623 language_server_settings_for(
12624 SettingsLocation {
12625 worktree_id: delegate.worktree_id(),
12626 path: RelPath::empty(),
12627 },
12628 language,
12629 cx,
12630 )
12631}
12632
12633pub(crate) fn language_server_settings_for<'a>(
12634 location: SettingsLocation<'a>,
12635 language: &LanguageServerName,
12636 cx: &'a App,
12637) -> Option<&'a LspSettings> {
12638 ProjectSettings::get(Some(location), cx).lsp.get(language)
12639}
12640
12641pub struct LocalLspAdapterDelegate {
12642 lsp_store: WeakEntity<LspStore>,
12643 worktree: worktree::Snapshot,
12644 fs: Arc<dyn Fs>,
12645 http_client: Arc<dyn HttpClient>,
12646 language_registry: Arc<LanguageRegistry>,
12647 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
12648}
12649
12650impl LocalLspAdapterDelegate {
12651 pub fn new(
12652 language_registry: Arc<LanguageRegistry>,
12653 environment: &Entity<ProjectEnvironment>,
12654 lsp_store: WeakEntity<LspStore>,
12655 worktree: &Entity<Worktree>,
12656 http_client: Arc<dyn HttpClient>,
12657 fs: Arc<dyn Fs>,
12658 cx: &mut App,
12659 ) -> Arc<Self> {
12660 let load_shell_env_task = environment.update(cx, |env, cx| {
12661 env.get_worktree_environment(worktree.clone(), cx)
12662 });
12663
12664 Arc::new(Self {
12665 lsp_store,
12666 worktree: worktree.read(cx).snapshot(),
12667 fs,
12668 http_client,
12669 language_registry,
12670 load_shell_env_task,
12671 })
12672 }
12673
12674 fn from_local_lsp(
12675 local: &LocalLspStore,
12676 worktree: &Entity<Worktree>,
12677 cx: &mut App,
12678 ) -> Arc<Self> {
12679 Self::new(
12680 local.languages.clone(),
12681 &local.environment,
12682 local.weak.clone(),
12683 worktree,
12684 local.http_client.clone(),
12685 local.fs.clone(),
12686 cx,
12687 )
12688 }
12689}
12690
12691#[async_trait]
12692impl LspAdapterDelegate for LocalLspAdapterDelegate {
12693 fn show_notification(&self, message: &str, cx: &mut App) {
12694 self.lsp_store
12695 .update(cx, |_, cx| {
12696 cx.emit(LspStoreEvent::Notification(message.to_owned()))
12697 })
12698 .ok();
12699 }
12700
12701 fn http_client(&self) -> Arc<dyn HttpClient> {
12702 self.http_client.clone()
12703 }
12704
12705 fn worktree_id(&self) -> WorktreeId {
12706 self.worktree.id()
12707 }
12708
12709 fn worktree_root_path(&self) -> &Path {
12710 self.worktree.abs_path().as_ref()
12711 }
12712
12713 async fn shell_env(&self) -> HashMap<String, String> {
12714 let task = self.load_shell_env_task.clone();
12715 task.await.unwrap_or_default()
12716 }
12717
12718 async fn npm_package_installed_version(
12719 &self,
12720 package_name: &str,
12721 ) -> Result<Option<(PathBuf, String)>> {
12722 let local_package_directory = self.worktree_root_path();
12723 let node_modules_directory = local_package_directory.join("node_modules");
12724
12725 if let Some(version) =
12726 read_package_installed_version(node_modules_directory.clone(), package_name).await?
12727 {
12728 return Ok(Some((node_modules_directory, version)));
12729 }
12730 let Some(npm) = self.which("npm".as_ref()).await else {
12731 log::warn!(
12732 "Failed to find npm executable for {:?}",
12733 local_package_directory
12734 );
12735 return Ok(None);
12736 };
12737
12738 let env = self.shell_env().await;
12739 let output = util::command::new_smol_command(&npm)
12740 .args(["root", "-g"])
12741 .envs(env)
12742 .current_dir(local_package_directory)
12743 .output()
12744 .await?;
12745 let global_node_modules =
12746 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
12747
12748 if let Some(version) =
12749 read_package_installed_version(global_node_modules.clone(), package_name).await?
12750 {
12751 return Ok(Some((global_node_modules, version)));
12752 }
12753 return Ok(None);
12754 }
12755
12756 #[cfg(not(target_os = "windows"))]
12757 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12758 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
12759 if self.fs.is_file(&worktree_abs_path).await {
12760 worktree_abs_path.pop();
12761 }
12762 let shell_path = self.shell_env().await.get("PATH").cloned();
12763 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
12764 }
12765
12766 #[cfg(target_os = "windows")]
12767 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12768 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
12769 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
12770 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
12771 which::which(command).ok()
12772 }
12773
12774 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
12775 let mut working_dir = self.worktree_root_path().to_path_buf();
12776 if self.fs.is_file(&working_dir).await {
12777 working_dir.pop();
12778 }
12779 let output = util::command::new_smol_command(&command.path)
12780 .args(command.arguments)
12781 .envs(command.env.clone().unwrap_or_default())
12782 .current_dir(working_dir)
12783 .output()
12784 .await?;
12785
12786 anyhow::ensure!(
12787 output.status.success(),
12788 "{}, stdout: {:?}, stderr: {:?}",
12789 output.status,
12790 String::from_utf8_lossy(&output.stdout),
12791 String::from_utf8_lossy(&output.stderr)
12792 );
12793 Ok(())
12794 }
12795
12796 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
12797 self.language_registry
12798 .update_lsp_binary_status(server_name, status);
12799 }
12800
12801 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
12802 self.language_registry
12803 .all_lsp_adapters()
12804 .into_iter()
12805 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
12806 .collect()
12807 }
12808
12809 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
12810 let dir = self.language_registry.language_server_download_dir(name)?;
12811
12812 if !dir.exists() {
12813 smol::fs::create_dir_all(&dir)
12814 .await
12815 .context("failed to create container directory")
12816 .log_err()?;
12817 }
12818
12819 Some(dir)
12820 }
12821
12822 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
12823 let entry = self
12824 .worktree
12825 .entry_for_path(path)
12826 .with_context(|| format!("no worktree entry for path {path:?}"))?;
12827 let abs_path = self.worktree.absolutize(&entry.path);
12828 self.fs.load(&abs_path).await
12829 }
12830}
12831
12832async fn populate_labels_for_symbols(
12833 symbols: Vec<CoreSymbol>,
12834 language_registry: &Arc<LanguageRegistry>,
12835 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12836 output: &mut Vec<Symbol>,
12837) {
12838 #[allow(clippy::mutable_key_type)]
12839 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
12840
12841 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
12842 for symbol in symbols {
12843 let Some(file_name) = symbol.path.file_name() else {
12844 continue;
12845 };
12846 let language = language_registry
12847 .load_language_for_file_path(Path::new(file_name))
12848 .await
12849 .ok()
12850 .or_else(|| {
12851 unknown_paths.insert(file_name.into());
12852 None
12853 });
12854 symbols_by_language
12855 .entry(language)
12856 .or_default()
12857 .push(symbol);
12858 }
12859
12860 for unknown_path in unknown_paths {
12861 log::info!("no language found for symbol in file {unknown_path:?}");
12862 }
12863
12864 let mut label_params = Vec::new();
12865 for (language, mut symbols) in symbols_by_language {
12866 label_params.clear();
12867 label_params.extend(
12868 symbols
12869 .iter_mut()
12870 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
12871 );
12872
12873 let mut labels = Vec::new();
12874 if let Some(language) = language {
12875 let lsp_adapter = lsp_adapter.clone().or_else(|| {
12876 language_registry
12877 .lsp_adapters(&language.name())
12878 .first()
12879 .cloned()
12880 });
12881 if let Some(lsp_adapter) = lsp_adapter {
12882 labels = lsp_adapter
12883 .labels_for_symbols(&label_params, &language)
12884 .await
12885 .log_err()
12886 .unwrap_or_default();
12887 }
12888 }
12889
12890 for ((symbol, (name, _)), label) in symbols
12891 .into_iter()
12892 .zip(label_params.drain(..))
12893 .zip(labels.into_iter().chain(iter::repeat(None)))
12894 {
12895 output.push(Symbol {
12896 language_server_name: symbol.language_server_name,
12897 source_worktree_id: symbol.source_worktree_id,
12898 source_language_server_id: symbol.source_language_server_id,
12899 path: symbol.path,
12900 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
12901 name,
12902 kind: symbol.kind,
12903 range: symbol.range,
12904 });
12905 }
12906 }
12907}
12908
12909fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
12910 match server.capabilities().text_document_sync.as_ref()? {
12911 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
12912 // Server wants didSave but didn't specify includeText.
12913 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
12914 // Server doesn't want didSave at all.
12915 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
12916 // Server provided SaveOptions.
12917 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
12918 Some(save_options.include_text.unwrap_or(false))
12919 }
12920 },
12921 // We do not have any save info. Kind affects didChange only.
12922 lsp::TextDocumentSyncCapability::Kind(_) => None,
12923 }
12924}
12925
12926/// Completion items are displayed in a `UniformList`.
12927/// Usually, those items are single-line strings, but in LSP responses,
12928/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
12929/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
12930/// All that may lead to a newline being inserted into resulting `CodeLabel.text`, which will force `UniformList` to bloat each entry to occupy more space,
12931/// breaking the completions menu presentation.
12932///
12933/// Sanitize the text to ensure there are no newlines, or, if there are some, remove them and also remove long space sequences if there were newlines.
12934fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
12935 let mut new_text = String::with_capacity(label.text.len());
12936 let mut offset_map = vec![0; label.text.len() + 1];
12937 let mut last_char_was_space = false;
12938 let mut new_idx = 0;
12939 let chars = label.text.char_indices().fuse();
12940 let mut newlines_removed = false;
12941
12942 for (idx, c) in chars {
12943 offset_map[idx] = new_idx;
12944
12945 match c {
12946 '\n' if last_char_was_space => {
12947 newlines_removed = true;
12948 }
12949 '\t' | ' ' if last_char_was_space => {}
12950 '\n' if !last_char_was_space => {
12951 new_text.push(' ');
12952 new_idx += 1;
12953 last_char_was_space = true;
12954 newlines_removed = true;
12955 }
12956 ' ' | '\t' => {
12957 new_text.push(' ');
12958 new_idx += 1;
12959 last_char_was_space = true;
12960 }
12961 _ => {
12962 new_text.push(c);
12963 new_idx += c.len_utf8();
12964 last_char_was_space = false;
12965 }
12966 }
12967 }
12968 offset_map[label.text.len()] = new_idx;
12969
12970 // Only modify the label if newlines were removed.
12971 if !newlines_removed {
12972 return;
12973 }
12974
12975 let last_index = new_idx;
12976 let mut run_ranges_errors = Vec::new();
12977 label.runs.retain_mut(|(range, _)| {
12978 match offset_map.get(range.start) {
12979 Some(&start) => range.start = start,
12980 None => {
12981 run_ranges_errors.push(range.clone());
12982 return false;
12983 }
12984 }
12985
12986 match offset_map.get(range.end) {
12987 Some(&end) => range.end = end,
12988 None => {
12989 run_ranges_errors.push(range.clone());
12990 range.end = last_index;
12991 }
12992 }
12993 true
12994 });
12995 if !run_ranges_errors.is_empty() {
12996 log::error!(
12997 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
12998 label.text
12999 );
13000 }
13001
13002 let mut wrong_filter_range = None;
13003 if label.filter_range == (0..label.text.len()) {
13004 label.filter_range = 0..new_text.len();
13005 } else {
13006 let mut original_filter_range = Some(label.filter_range.clone());
13007 match offset_map.get(label.filter_range.start) {
13008 Some(&start) => label.filter_range.start = start,
13009 None => {
13010 wrong_filter_range = original_filter_range.take();
13011 label.filter_range.start = last_index;
13012 }
13013 }
13014
13015 match offset_map.get(label.filter_range.end) {
13016 Some(&end) => label.filter_range.end = end,
13017 None => {
13018 wrong_filter_range = original_filter_range.take();
13019 label.filter_range.end = last_index;
13020 }
13021 }
13022 }
13023 if let Some(wrong_filter_range) = wrong_filter_range {
13024 log::error!(
13025 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13026 label.text
13027 );
13028 }
13029
13030 label.text = new_text;
13031}
13032
13033#[cfg(test)]
13034mod tests {
13035 use language::HighlightId;
13036
13037 use super::*;
13038
13039 #[test]
13040 fn test_glob_literal_prefix() {
13041 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13042 assert_eq!(
13043 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13044 Path::new("node_modules")
13045 );
13046 assert_eq!(
13047 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13048 Path::new("foo")
13049 );
13050 assert_eq!(
13051 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13052 Path::new("foo/bar/baz.js")
13053 );
13054
13055 #[cfg(target_os = "windows")]
13056 {
13057 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13058 assert_eq!(
13059 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13060 Path::new("node_modules")
13061 );
13062 assert_eq!(
13063 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13064 Path::new("foo")
13065 );
13066 assert_eq!(
13067 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13068 Path::new("foo/bar/baz.js")
13069 );
13070 }
13071 }
13072
13073 #[test]
13074 fn test_multi_len_chars_normalization() {
13075 let mut label = CodeLabel {
13076 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13077 runs: vec![(0..6, HighlightId(1))],
13078 filter_range: 0..6,
13079 };
13080 ensure_uniform_list_compatible_label(&mut label);
13081 assert_eq!(
13082 label,
13083 CodeLabel {
13084 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13085 runs: vec![(0..6, HighlightId(1))],
13086 filter_range: 0..6,
13087 }
13088 );
13089 }
13090}