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