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 if !completion_settings.lsp {
5821 return Task::ready(Ok(Vec::new()));
5822 }
5823
5824 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5825 local
5826 .language_servers_for_buffer(buffer, cx)
5827 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5828 .filter(|(adapter, _)| {
5829 scope
5830 .as_ref()
5831 .map(|scope| scope.language_allowed(&adapter.name))
5832 .unwrap_or(true)
5833 })
5834 .map(|(_, server)| server.server_id())
5835 .collect()
5836 });
5837
5838 let buffer = buffer.clone();
5839 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5840 let lsp_timeout = if lsp_timeout > 0 {
5841 Some(Duration::from_millis(lsp_timeout))
5842 } else {
5843 None
5844 };
5845 cx.spawn(async move |this, cx| {
5846 let mut tasks = Vec::with_capacity(server_ids.len());
5847 this.update(cx, |lsp_store, cx| {
5848 for server_id in server_ids {
5849 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5850 let lsp_timeout = lsp_timeout
5851 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5852 let mut timeout = cx.background_spawn(async move {
5853 match lsp_timeout {
5854 Some(lsp_timeout) => {
5855 lsp_timeout.await;
5856 true
5857 },
5858 None => false,
5859 }
5860 }).fuse();
5861 let mut lsp_request = lsp_store.request_lsp(
5862 buffer.clone(),
5863 LanguageServerToQuery::Other(server_id),
5864 GetCompletions {
5865 position,
5866 context: context.clone(),
5867 },
5868 cx,
5869 ).fuse();
5870 let new_task = cx.background_spawn(async move {
5871 select_biased! {
5872 response = lsp_request => anyhow::Ok(Some(response?)),
5873 timeout_happened = timeout => {
5874 if timeout_happened {
5875 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5876 Ok(None)
5877 } else {
5878 let completions = lsp_request.await?;
5879 Ok(Some(completions))
5880 }
5881 },
5882 }
5883 });
5884 tasks.push((lsp_adapter, new_task));
5885 }
5886 })?;
5887
5888 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5889 let completion_response = task.await.ok()??;
5890 let completions = populate_labels_for_completions(
5891 completion_response.completions,
5892 language.clone(),
5893 lsp_adapter,
5894 )
5895 .await;
5896 Some(CompletionResponse {
5897 completions,
5898 display_options: CompletionDisplayOptions::default(),
5899 is_incomplete: completion_response.is_incomplete,
5900 })
5901 });
5902
5903 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5904
5905 Ok(responses.into_iter().flatten().collect())
5906 })
5907 } else {
5908 Task::ready(Err(anyhow!("No upstream client or local language server")))
5909 }
5910 }
5911
5912 pub fn resolve_completions(
5913 &self,
5914 buffer: Entity<Buffer>,
5915 completion_indices: Vec<usize>,
5916 completions: Rc<RefCell<Box<[Completion]>>>,
5917 cx: &mut Context<Self>,
5918 ) -> Task<Result<bool>> {
5919 let client = self.upstream_client();
5920 let buffer_id = buffer.read(cx).remote_id();
5921 let buffer_snapshot = buffer.read(cx).snapshot();
5922
5923 if !self.check_if_capable_for_proto_request(
5924 &buffer,
5925 GetCompletions::can_resolve_completions,
5926 cx,
5927 ) {
5928 return Task::ready(Ok(false));
5929 }
5930 cx.spawn(async move |lsp_store, cx| {
5931 let mut did_resolve = false;
5932 if let Some((client, project_id)) = client {
5933 for completion_index in completion_indices {
5934 let server_id = {
5935 let completion = &completions.borrow()[completion_index];
5936 completion.source.server_id()
5937 };
5938 if let Some(server_id) = server_id {
5939 if Self::resolve_completion_remote(
5940 project_id,
5941 server_id,
5942 buffer_id,
5943 completions.clone(),
5944 completion_index,
5945 client.clone(),
5946 )
5947 .await
5948 .log_err()
5949 .is_some()
5950 {
5951 did_resolve = true;
5952 }
5953 } else {
5954 resolve_word_completion(
5955 &buffer_snapshot,
5956 &mut completions.borrow_mut()[completion_index],
5957 );
5958 }
5959 }
5960 } else {
5961 for completion_index in completion_indices {
5962 let server_id = {
5963 let completion = &completions.borrow()[completion_index];
5964 completion.source.server_id()
5965 };
5966 if let Some(server_id) = server_id {
5967 let server_and_adapter = lsp_store
5968 .read_with(cx, |lsp_store, _| {
5969 let server = lsp_store.language_server_for_id(server_id)?;
5970 let adapter =
5971 lsp_store.language_server_adapter_for_id(server.server_id())?;
5972 Some((server, adapter))
5973 })
5974 .ok()
5975 .flatten();
5976 let Some((server, adapter)) = server_and_adapter else {
5977 continue;
5978 };
5979
5980 let resolved = Self::resolve_completion_local(
5981 server,
5982 completions.clone(),
5983 completion_index,
5984 )
5985 .await
5986 .log_err()
5987 .is_some();
5988 if resolved {
5989 Self::regenerate_completion_labels(
5990 adapter,
5991 &buffer_snapshot,
5992 completions.clone(),
5993 completion_index,
5994 )
5995 .await
5996 .log_err();
5997 did_resolve = true;
5998 }
5999 } else {
6000 resolve_word_completion(
6001 &buffer_snapshot,
6002 &mut completions.borrow_mut()[completion_index],
6003 );
6004 }
6005 }
6006 }
6007
6008 Ok(did_resolve)
6009 })
6010 }
6011
6012 async fn resolve_completion_local(
6013 server: Arc<lsp::LanguageServer>,
6014 completions: Rc<RefCell<Box<[Completion]>>>,
6015 completion_index: usize,
6016 ) -> Result<()> {
6017 let server_id = server.server_id();
6018 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6019 return Ok(());
6020 }
6021
6022 let request = {
6023 let completion = &completions.borrow()[completion_index];
6024 match &completion.source {
6025 CompletionSource::Lsp {
6026 lsp_completion,
6027 resolved,
6028 server_id: completion_server_id,
6029 ..
6030 } => {
6031 if *resolved {
6032 return Ok(());
6033 }
6034 anyhow::ensure!(
6035 server_id == *completion_server_id,
6036 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6037 );
6038 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6039 }
6040 CompletionSource::BufferWord { .. }
6041 | CompletionSource::Dap { .. }
6042 | CompletionSource::Custom => {
6043 return Ok(());
6044 }
6045 }
6046 };
6047 let resolved_completion = request
6048 .await
6049 .into_response()
6050 .context("resolve completion")?;
6051
6052 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6053 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6054
6055 let mut completions = completions.borrow_mut();
6056 let completion = &mut completions[completion_index];
6057 if let CompletionSource::Lsp {
6058 lsp_completion,
6059 resolved,
6060 server_id: completion_server_id,
6061 ..
6062 } = &mut completion.source
6063 {
6064 if *resolved {
6065 return Ok(());
6066 }
6067 anyhow::ensure!(
6068 server_id == *completion_server_id,
6069 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6070 );
6071 *lsp_completion = Box::new(resolved_completion);
6072 *resolved = true;
6073 }
6074 Ok(())
6075 }
6076
6077 async fn regenerate_completion_labels(
6078 adapter: Arc<CachedLspAdapter>,
6079 snapshot: &BufferSnapshot,
6080 completions: Rc<RefCell<Box<[Completion]>>>,
6081 completion_index: usize,
6082 ) -> Result<()> {
6083 let completion_item = completions.borrow()[completion_index]
6084 .source
6085 .lsp_completion(true)
6086 .map(Cow::into_owned);
6087 if let Some(lsp_documentation) = completion_item
6088 .as_ref()
6089 .and_then(|completion_item| completion_item.documentation.clone())
6090 {
6091 let mut completions = completions.borrow_mut();
6092 let completion = &mut completions[completion_index];
6093 completion.documentation = Some(lsp_documentation.into());
6094 } else {
6095 let mut completions = completions.borrow_mut();
6096 let completion = &mut completions[completion_index];
6097 completion.documentation = Some(CompletionDocumentation::Undocumented);
6098 }
6099
6100 let mut new_label = match completion_item {
6101 Some(completion_item) => {
6102 // 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
6103 // So we have to update the label here anyway...
6104 let language = snapshot.language();
6105 match language {
6106 Some(language) => {
6107 adapter
6108 .labels_for_completions(
6109 std::slice::from_ref(&completion_item),
6110 language,
6111 )
6112 .await?
6113 }
6114 None => Vec::new(),
6115 }
6116 .pop()
6117 .flatten()
6118 .unwrap_or_else(|| {
6119 CodeLabel::fallback_for_completion(
6120 &completion_item,
6121 language.map(|language| language.as_ref()),
6122 )
6123 })
6124 }
6125 None => CodeLabel::plain(
6126 completions.borrow()[completion_index].new_text.clone(),
6127 None,
6128 ),
6129 };
6130 ensure_uniform_list_compatible_label(&mut new_label);
6131
6132 let mut completions = completions.borrow_mut();
6133 let completion = &mut completions[completion_index];
6134 if completion.label.filter_text() == new_label.filter_text() {
6135 completion.label = new_label;
6136 } else {
6137 log::error!(
6138 "Resolved completion changed display label from {} to {}. \
6139 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6140 completion.label.text(),
6141 new_label.text(),
6142 completion.label.filter_text(),
6143 new_label.filter_text()
6144 );
6145 }
6146
6147 Ok(())
6148 }
6149
6150 async fn resolve_completion_remote(
6151 project_id: u64,
6152 server_id: LanguageServerId,
6153 buffer_id: BufferId,
6154 completions: Rc<RefCell<Box<[Completion]>>>,
6155 completion_index: usize,
6156 client: AnyProtoClient,
6157 ) -> Result<()> {
6158 let lsp_completion = {
6159 let completion = &completions.borrow()[completion_index];
6160 match &completion.source {
6161 CompletionSource::Lsp {
6162 lsp_completion,
6163 resolved,
6164 server_id: completion_server_id,
6165 ..
6166 } => {
6167 anyhow::ensure!(
6168 server_id == *completion_server_id,
6169 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6170 );
6171 if *resolved {
6172 return Ok(());
6173 }
6174 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6175 }
6176 CompletionSource::Custom
6177 | CompletionSource::Dap { .. }
6178 | CompletionSource::BufferWord { .. } => {
6179 return Ok(());
6180 }
6181 }
6182 };
6183 let request = proto::ResolveCompletionDocumentation {
6184 project_id,
6185 language_server_id: server_id.0 as u64,
6186 lsp_completion,
6187 buffer_id: buffer_id.into(),
6188 };
6189
6190 let response = client
6191 .request(request)
6192 .await
6193 .context("completion documentation resolve proto request")?;
6194 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6195
6196 let documentation = if response.documentation.is_empty() {
6197 CompletionDocumentation::Undocumented
6198 } else if response.documentation_is_markdown {
6199 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6200 } else if response.documentation.lines().count() <= 1 {
6201 CompletionDocumentation::SingleLine(response.documentation.into())
6202 } else {
6203 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6204 };
6205
6206 let mut completions = completions.borrow_mut();
6207 let completion = &mut completions[completion_index];
6208 completion.documentation = Some(documentation);
6209 if let CompletionSource::Lsp {
6210 insert_range,
6211 lsp_completion,
6212 resolved,
6213 server_id: completion_server_id,
6214 lsp_defaults: _,
6215 } = &mut completion.source
6216 {
6217 let completion_insert_range = response
6218 .old_insert_start
6219 .and_then(deserialize_anchor)
6220 .zip(response.old_insert_end.and_then(deserialize_anchor));
6221 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6222
6223 if *resolved {
6224 return Ok(());
6225 }
6226 anyhow::ensure!(
6227 server_id == *completion_server_id,
6228 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6229 );
6230 *lsp_completion = Box::new(resolved_lsp_completion);
6231 *resolved = true;
6232 }
6233
6234 let replace_range = response
6235 .old_replace_start
6236 .and_then(deserialize_anchor)
6237 .zip(response.old_replace_end.and_then(deserialize_anchor));
6238 if let Some((old_replace_start, old_replace_end)) = replace_range
6239 && !response.new_text.is_empty()
6240 {
6241 completion.new_text = response.new_text;
6242 completion.replace_range = old_replace_start..old_replace_end;
6243 }
6244
6245 Ok(())
6246 }
6247
6248 pub fn apply_additional_edits_for_completion(
6249 &self,
6250 buffer_handle: Entity<Buffer>,
6251 completions: Rc<RefCell<Box<[Completion]>>>,
6252 completion_index: usize,
6253 push_to_history: bool,
6254 cx: &mut Context<Self>,
6255 ) -> Task<Result<Option<Transaction>>> {
6256 if let Some((client, project_id)) = self.upstream_client() {
6257 let buffer = buffer_handle.read(cx);
6258 let buffer_id = buffer.remote_id();
6259 cx.spawn(async move |_, cx| {
6260 let request = {
6261 let completion = completions.borrow()[completion_index].clone();
6262 proto::ApplyCompletionAdditionalEdits {
6263 project_id,
6264 buffer_id: buffer_id.into(),
6265 completion: Some(Self::serialize_completion(&CoreCompletion {
6266 replace_range: completion.replace_range,
6267 new_text: completion.new_text,
6268 source: completion.source,
6269 })),
6270 }
6271 };
6272
6273 if let Some(transaction) = client.request(request).await?.transaction {
6274 let transaction = language::proto::deserialize_transaction(transaction)?;
6275 buffer_handle
6276 .update(cx, |buffer, _| {
6277 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6278 })?
6279 .await?;
6280 if push_to_history {
6281 buffer_handle.update(cx, |buffer, _| {
6282 buffer.push_transaction(transaction.clone(), Instant::now());
6283 buffer.finalize_last_transaction();
6284 })?;
6285 }
6286 Ok(Some(transaction))
6287 } else {
6288 Ok(None)
6289 }
6290 })
6291 } else {
6292 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6293 let completion = &completions.borrow()[completion_index];
6294 let server_id = completion.source.server_id()?;
6295 Some(
6296 self.language_server_for_local_buffer(buffer, server_id, cx)?
6297 .1
6298 .clone(),
6299 )
6300 }) else {
6301 return Task::ready(Ok(None));
6302 };
6303
6304 cx.spawn(async move |this, cx| {
6305 Self::resolve_completion_local(
6306 server.clone(),
6307 completions.clone(),
6308 completion_index,
6309 )
6310 .await
6311 .context("resolving completion")?;
6312 let completion = completions.borrow()[completion_index].clone();
6313 let additional_text_edits = completion
6314 .source
6315 .lsp_completion(true)
6316 .as_ref()
6317 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6318 if let Some(edits) = additional_text_edits {
6319 let edits = this
6320 .update(cx, |this, cx| {
6321 this.as_local_mut().unwrap().edits_from_lsp(
6322 &buffer_handle,
6323 edits,
6324 server.server_id(),
6325 None,
6326 cx,
6327 )
6328 })?
6329 .await?;
6330
6331 buffer_handle.update(cx, |buffer, cx| {
6332 buffer.finalize_last_transaction();
6333 buffer.start_transaction();
6334
6335 for (range, text) in edits {
6336 let primary = &completion.replace_range;
6337
6338 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6339 // and the primary completion is just an insertion (empty range), then this is likely
6340 // an auto-import scenario and should not be considered overlapping
6341 // https://github.com/zed-industries/zed/issues/26136
6342 let is_file_start_auto_import = {
6343 let snapshot = buffer.snapshot();
6344 let primary_start_point = primary.start.to_point(&snapshot);
6345 let range_start_point = range.start.to_point(&snapshot);
6346
6347 let result = primary_start_point.row == 0
6348 && primary_start_point.column == 0
6349 && range_start_point.row == 0
6350 && range_start_point.column == 0;
6351
6352 result
6353 };
6354
6355 let has_overlap = if is_file_start_auto_import {
6356 false
6357 } else {
6358 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6359 && primary.end.cmp(&range.start, buffer).is_ge();
6360 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6361 && range.end.cmp(&primary.end, buffer).is_ge();
6362 let result = start_within || end_within;
6363 result
6364 };
6365
6366 //Skip additional edits which overlap with the primary completion edit
6367 //https://github.com/zed-industries/zed/pull/1871
6368 if !has_overlap {
6369 buffer.edit([(range, text)], None, cx);
6370 }
6371 }
6372
6373 let transaction = if buffer.end_transaction(cx).is_some() {
6374 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6375 if !push_to_history {
6376 buffer.forget_transaction(transaction.id);
6377 }
6378 Some(transaction)
6379 } else {
6380 None
6381 };
6382 Ok(transaction)
6383 })?
6384 } else {
6385 Ok(None)
6386 }
6387 })
6388 }
6389 }
6390
6391 pub fn pull_diagnostics(
6392 &mut self,
6393 buffer: Entity<Buffer>,
6394 cx: &mut Context<Self>,
6395 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6396 let buffer_id = buffer.read(cx).remote_id();
6397
6398 if let Some((client, upstream_project_id)) = self.upstream_client() {
6399 let request = GetDocumentDiagnostics {
6400 previous_result_id: None,
6401 };
6402 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6403 return Task::ready(Ok(None));
6404 }
6405 let request_task = client.request_lsp(
6406 upstream_project_id,
6407 LSP_REQUEST_TIMEOUT,
6408 cx.background_executor().clone(),
6409 request.to_proto(upstream_project_id, buffer.read(cx)),
6410 );
6411 cx.background_spawn(async move {
6412 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6413 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6414 // Do not attempt to further process the dummy responses here.
6415 let _response = request_task.await?;
6416 Ok(None)
6417 })
6418 } else {
6419 let server_ids = buffer.update(cx, |buffer, cx| {
6420 self.language_servers_for_local_buffer(buffer, cx)
6421 .map(|(_, server)| server.server_id())
6422 .collect::<Vec<_>>()
6423 });
6424 let pull_diagnostics = server_ids
6425 .into_iter()
6426 .map(|server_id| {
6427 let result_id = self.result_id(server_id, buffer_id, cx);
6428 self.request_lsp(
6429 buffer.clone(),
6430 LanguageServerToQuery::Other(server_id),
6431 GetDocumentDiagnostics {
6432 previous_result_id: result_id,
6433 },
6434 cx,
6435 )
6436 })
6437 .collect::<Vec<_>>();
6438
6439 cx.background_spawn(async move {
6440 let mut responses = Vec::new();
6441 for diagnostics in join_all(pull_diagnostics).await {
6442 responses.extend(diagnostics?);
6443 }
6444 Ok(Some(responses))
6445 })
6446 }
6447 }
6448
6449 pub fn inlay_hints(
6450 &mut self,
6451 buffer: Entity<Buffer>,
6452 range: Range<Anchor>,
6453 cx: &mut Context<Self>,
6454 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6455 let range_start = range.start;
6456 let range_end = range.end;
6457 let buffer_id = buffer.read(cx).remote_id().into();
6458 let request = InlayHints { range };
6459
6460 if let Some((client, project_id)) = self.upstream_client() {
6461 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6462 return Task::ready(Ok(Vec::new()));
6463 }
6464 let proto_request = proto::InlayHints {
6465 project_id,
6466 buffer_id,
6467 start: Some(serialize_anchor(&range_start)),
6468 end: Some(serialize_anchor(&range_end)),
6469 version: serialize_version(&buffer.read(cx).version()),
6470 };
6471 cx.spawn(async move |project, cx| {
6472 let response = client
6473 .request(proto_request)
6474 .await
6475 .context("inlay hints proto request")?;
6476 LspCommand::response_from_proto(
6477 request,
6478 response,
6479 project.upgrade().context("No project")?,
6480 buffer.clone(),
6481 cx.clone(),
6482 )
6483 .await
6484 .context("inlay hints proto response conversion")
6485 })
6486 } else {
6487 let lsp_request_task = self.request_lsp(
6488 buffer.clone(),
6489 LanguageServerToQuery::FirstCapable,
6490 request,
6491 cx,
6492 );
6493 cx.spawn(async move |_, cx| {
6494 buffer
6495 .update(cx, |buffer, _| {
6496 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6497 })?
6498 .await
6499 .context("waiting for inlay hint request range edits")?;
6500 lsp_request_task.await.context("inlay hints LSP request")
6501 })
6502 }
6503 }
6504
6505 pub fn pull_diagnostics_for_buffer(
6506 &mut self,
6507 buffer: Entity<Buffer>,
6508 cx: &mut Context<Self>,
6509 ) -> Task<anyhow::Result<()>> {
6510 let diagnostics = self.pull_diagnostics(buffer, cx);
6511 cx.spawn(async move |lsp_store, cx| {
6512 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6513 return Ok(());
6514 };
6515 lsp_store.update(cx, |lsp_store, cx| {
6516 if lsp_store.as_local().is_none() {
6517 return;
6518 }
6519
6520 let mut unchanged_buffers = HashSet::default();
6521 let mut changed_buffers = HashSet::default();
6522 let server_diagnostics_updates = diagnostics
6523 .into_iter()
6524 .filter_map(|diagnostics_set| match diagnostics_set {
6525 LspPullDiagnostics::Response {
6526 server_id,
6527 uri,
6528 diagnostics,
6529 } => Some((server_id, uri, diagnostics)),
6530 LspPullDiagnostics::Default => None,
6531 })
6532 .fold(
6533 HashMap::default(),
6534 |mut acc, (server_id, uri, diagnostics)| {
6535 let (result_id, diagnostics) = match diagnostics {
6536 PulledDiagnostics::Unchanged { result_id } => {
6537 unchanged_buffers.insert(uri.clone());
6538 (Some(result_id), Vec::new())
6539 }
6540 PulledDiagnostics::Changed {
6541 result_id,
6542 diagnostics,
6543 } => {
6544 changed_buffers.insert(uri.clone());
6545 (result_id, diagnostics)
6546 }
6547 };
6548 let disk_based_sources = Cow::Owned(
6549 lsp_store
6550 .language_server_adapter_for_id(server_id)
6551 .as_ref()
6552 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6553 .unwrap_or(&[])
6554 .to_vec(),
6555 );
6556 acc.entry(server_id).or_insert_with(Vec::new).push(
6557 DocumentDiagnosticsUpdate {
6558 server_id,
6559 diagnostics: lsp::PublishDiagnosticsParams {
6560 uri,
6561 diagnostics,
6562 version: None,
6563 },
6564 result_id,
6565 disk_based_sources,
6566 },
6567 );
6568 acc
6569 },
6570 );
6571
6572 for diagnostic_updates in server_diagnostics_updates.into_values() {
6573 lsp_store
6574 .merge_lsp_diagnostics(
6575 DiagnosticSourceKind::Pulled,
6576 diagnostic_updates,
6577 |buffer, old_diagnostic, cx| {
6578 File::from_dyn(buffer.file())
6579 .and_then(|file| {
6580 let abs_path = file.as_local()?.abs_path(cx);
6581 lsp::Uri::from_file_path(abs_path).ok()
6582 })
6583 .is_none_or(|buffer_uri| {
6584 unchanged_buffers.contains(&buffer_uri)
6585 || match old_diagnostic.source_kind {
6586 DiagnosticSourceKind::Pulled => {
6587 !changed_buffers.contains(&buffer_uri)
6588 }
6589 DiagnosticSourceKind::Other
6590 | DiagnosticSourceKind::Pushed => true,
6591 }
6592 })
6593 },
6594 cx,
6595 )
6596 .log_err();
6597 }
6598 })
6599 })
6600 }
6601
6602 pub fn document_colors(
6603 &mut self,
6604 fetch_strategy: LspFetchStrategy,
6605 buffer: Entity<Buffer>,
6606 cx: &mut Context<Self>,
6607 ) -> Option<DocumentColorTask> {
6608 let version_queried_for = buffer.read(cx).version();
6609 let buffer_id = buffer.read(cx).remote_id();
6610
6611 match fetch_strategy {
6612 LspFetchStrategy::IgnoreCache => {}
6613 LspFetchStrategy::UseCache {
6614 known_cache_version,
6615 } => {
6616 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6617 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6618 {
6619 let has_different_servers = self.as_local().is_some_and(|local| {
6620 local
6621 .buffers_opened_in_servers
6622 .get(&buffer_id)
6623 .cloned()
6624 .unwrap_or_default()
6625 != cached_data.colors.keys().copied().collect()
6626 });
6627 if !has_different_servers {
6628 if Some(cached_data.cache_version) == known_cache_version {
6629 return None;
6630 } else {
6631 return Some(
6632 Task::ready(Ok(DocumentColors {
6633 colors: cached_data
6634 .colors
6635 .values()
6636 .flatten()
6637 .cloned()
6638 .collect(),
6639 cache_version: Some(cached_data.cache_version),
6640 }))
6641 .shared(),
6642 );
6643 }
6644 }
6645 }
6646 }
6647 }
6648
6649 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6650 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6651 && !version_queried_for.changed_since(updating_for)
6652 {
6653 return Some(running_update.clone());
6654 }
6655 let query_version_queried_for = version_queried_for.clone();
6656 let new_task = cx
6657 .spawn(async move |lsp_store, cx| {
6658 cx.background_executor()
6659 .timer(Duration::from_millis(30))
6660 .await;
6661 let fetched_colors = lsp_store
6662 .update(cx, |lsp_store, cx| {
6663 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6664 })?
6665 .await
6666 .context("fetching document colors")
6667 .map_err(Arc::new);
6668 let fetched_colors = match fetched_colors {
6669 Ok(fetched_colors) => {
6670 if fetch_strategy != LspFetchStrategy::IgnoreCache
6671 && Some(true)
6672 == buffer
6673 .update(cx, |buffer, _| {
6674 buffer.version() != query_version_queried_for
6675 })
6676 .ok()
6677 {
6678 return Ok(DocumentColors::default());
6679 }
6680 fetched_colors
6681 }
6682 Err(e) => {
6683 lsp_store
6684 .update(cx, |lsp_store, _| {
6685 lsp_store
6686 .lsp_document_colors
6687 .entry(buffer_id)
6688 .or_default()
6689 .colors_update = None;
6690 })
6691 .ok();
6692 return Err(e);
6693 }
6694 };
6695
6696 lsp_store
6697 .update(cx, |lsp_store, _| {
6698 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6699
6700 if let Some(fetched_colors) = fetched_colors {
6701 if lsp_data.colors_for_version == query_version_queried_for {
6702 lsp_data.colors.extend(fetched_colors);
6703 lsp_data.cache_version += 1;
6704 } else if !lsp_data
6705 .colors_for_version
6706 .changed_since(&query_version_queried_for)
6707 {
6708 lsp_data.colors_for_version = query_version_queried_for;
6709 lsp_data.colors = fetched_colors;
6710 lsp_data.cache_version += 1;
6711 }
6712 }
6713 lsp_data.colors_update = None;
6714 let colors = lsp_data
6715 .colors
6716 .values()
6717 .flatten()
6718 .cloned()
6719 .collect::<HashSet<_>>();
6720 DocumentColors {
6721 colors,
6722 cache_version: Some(lsp_data.cache_version),
6723 }
6724 })
6725 .map_err(Arc::new)
6726 })
6727 .shared();
6728 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6729 Some(new_task)
6730 }
6731
6732 fn fetch_document_colors_for_buffer(
6733 &mut self,
6734 buffer: &Entity<Buffer>,
6735 cx: &mut Context<Self>,
6736 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
6737 if let Some((client, project_id)) = self.upstream_client() {
6738 let request = GetDocumentColor {};
6739 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6740 return Task::ready(Ok(None));
6741 }
6742
6743 let request_task = client.request_lsp(
6744 project_id,
6745 LSP_REQUEST_TIMEOUT,
6746 cx.background_executor().clone(),
6747 request.to_proto(project_id, buffer.read(cx)),
6748 );
6749 let buffer = buffer.clone();
6750 cx.spawn(async move |lsp_store, cx| {
6751 let Some(project) = lsp_store.upgrade() else {
6752 return Ok(None);
6753 };
6754 let colors = join_all(
6755 request_task
6756 .await
6757 .log_err()
6758 .flatten()
6759 .map(|response| response.payload)
6760 .unwrap_or_default()
6761 .into_iter()
6762 .map(|color_response| {
6763 let response = request.response_from_proto(
6764 color_response.response,
6765 project.clone(),
6766 buffer.clone(),
6767 cx.clone(),
6768 );
6769 async move {
6770 (
6771 LanguageServerId::from_proto(color_response.server_id),
6772 response.await.log_err().unwrap_or_default(),
6773 )
6774 }
6775 }),
6776 )
6777 .await
6778 .into_iter()
6779 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6780 acc.entry(server_id)
6781 .or_insert_with(HashSet::default)
6782 .extend(colors);
6783 acc
6784 });
6785 Ok(Some(colors))
6786 })
6787 } else {
6788 let document_colors_task =
6789 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6790 cx.background_spawn(async move {
6791 Ok(Some(
6792 document_colors_task
6793 .await
6794 .into_iter()
6795 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6796 acc.entry(server_id)
6797 .or_insert_with(HashSet::default)
6798 .extend(colors);
6799 acc
6800 })
6801 .into_iter()
6802 .collect(),
6803 ))
6804 })
6805 }
6806 }
6807
6808 pub fn signature_help<T: ToPointUtf16>(
6809 &mut self,
6810 buffer: &Entity<Buffer>,
6811 position: T,
6812 cx: &mut Context<Self>,
6813 ) -> Task<Option<Vec<SignatureHelp>>> {
6814 let position = position.to_point_utf16(buffer.read(cx));
6815
6816 if let Some((client, upstream_project_id)) = self.upstream_client() {
6817 let request = GetSignatureHelp { position };
6818 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6819 return Task::ready(None);
6820 }
6821 let request_task = client.request_lsp(
6822 upstream_project_id,
6823 LSP_REQUEST_TIMEOUT,
6824 cx.background_executor().clone(),
6825 request.to_proto(upstream_project_id, buffer.read(cx)),
6826 );
6827 let buffer = buffer.clone();
6828 cx.spawn(async move |weak_project, cx| {
6829 let project = weak_project.upgrade()?;
6830 let signatures = join_all(
6831 request_task
6832 .await
6833 .log_err()
6834 .flatten()
6835 .map(|response| response.payload)
6836 .unwrap_or_default()
6837 .into_iter()
6838 .map(|response| {
6839 let response = GetSignatureHelp { position }.response_from_proto(
6840 response.response,
6841 project.clone(),
6842 buffer.clone(),
6843 cx.clone(),
6844 );
6845 async move { response.await.log_err().flatten() }
6846 }),
6847 )
6848 .await
6849 .into_iter()
6850 .flatten()
6851 .collect();
6852 Some(signatures)
6853 })
6854 } else {
6855 let all_actions_task = self.request_multiple_lsp_locally(
6856 buffer,
6857 Some(position),
6858 GetSignatureHelp { position },
6859 cx,
6860 );
6861 cx.background_spawn(async move {
6862 Some(
6863 all_actions_task
6864 .await
6865 .into_iter()
6866 .flat_map(|(_, actions)| actions)
6867 .collect::<Vec<_>>(),
6868 )
6869 })
6870 }
6871 }
6872
6873 pub fn hover(
6874 &mut self,
6875 buffer: &Entity<Buffer>,
6876 position: PointUtf16,
6877 cx: &mut Context<Self>,
6878 ) -> Task<Option<Vec<Hover>>> {
6879 if let Some((client, upstream_project_id)) = self.upstream_client() {
6880 let request = GetHover { position };
6881 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6882 return Task::ready(None);
6883 }
6884 let request_task = client.request_lsp(
6885 upstream_project_id,
6886 LSP_REQUEST_TIMEOUT,
6887 cx.background_executor().clone(),
6888 request.to_proto(upstream_project_id, buffer.read(cx)),
6889 );
6890 let buffer = buffer.clone();
6891 cx.spawn(async move |weak_project, cx| {
6892 let project = weak_project.upgrade()?;
6893 let hovers = join_all(
6894 request_task
6895 .await
6896 .log_err()
6897 .flatten()
6898 .map(|response| response.payload)
6899 .unwrap_or_default()
6900 .into_iter()
6901 .map(|response| {
6902 let response = GetHover { position }.response_from_proto(
6903 response.response,
6904 project.clone(),
6905 buffer.clone(),
6906 cx.clone(),
6907 );
6908 async move {
6909 response
6910 .await
6911 .log_err()
6912 .flatten()
6913 .and_then(remove_empty_hover_blocks)
6914 }
6915 }),
6916 )
6917 .await
6918 .into_iter()
6919 .flatten()
6920 .collect();
6921 Some(hovers)
6922 })
6923 } else {
6924 let all_actions_task = self.request_multiple_lsp_locally(
6925 buffer,
6926 Some(position),
6927 GetHover { position },
6928 cx,
6929 );
6930 cx.background_spawn(async move {
6931 Some(
6932 all_actions_task
6933 .await
6934 .into_iter()
6935 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
6936 .collect::<Vec<Hover>>(),
6937 )
6938 })
6939 }
6940 }
6941
6942 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
6943 let language_registry = self.languages.clone();
6944
6945 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
6946 let request = upstream_client.request(proto::GetProjectSymbols {
6947 project_id: *project_id,
6948 query: query.to_string(),
6949 });
6950 cx.foreground_executor().spawn(async move {
6951 let response = request.await?;
6952 let mut symbols = Vec::new();
6953 let core_symbols = response
6954 .symbols
6955 .into_iter()
6956 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
6957 .collect::<Vec<_>>();
6958 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
6959 .await;
6960 Ok(symbols)
6961 })
6962 } else if let Some(local) = self.as_local() {
6963 struct WorkspaceSymbolsResult {
6964 server_id: LanguageServerId,
6965 lsp_adapter: Arc<CachedLspAdapter>,
6966 worktree: WeakEntity<Worktree>,
6967 worktree_abs_path: Arc<Path>,
6968 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
6969 }
6970
6971 let mut requests = Vec::new();
6972 let mut requested_servers = BTreeSet::new();
6973 for (seed, state) in local.language_server_ids.iter() {
6974 let Some(worktree_handle) = self
6975 .worktree_store
6976 .read(cx)
6977 .worktree_for_id(seed.worktree_id, cx)
6978 else {
6979 continue;
6980 };
6981 let worktree = worktree_handle.read(cx);
6982 if !worktree.is_visible() {
6983 continue;
6984 }
6985
6986 if !requested_servers.insert(state.id) {
6987 continue;
6988 }
6989
6990 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
6991 Some(LanguageServerState::Running {
6992 adapter, server, ..
6993 }) => (adapter.clone(), server),
6994
6995 _ => continue,
6996 };
6997 let supports_workspace_symbol_request =
6998 match server.capabilities().workspace_symbol_provider {
6999 Some(OneOf::Left(supported)) => supported,
7000 Some(OneOf::Right(_)) => true,
7001 None => false,
7002 };
7003 if !supports_workspace_symbol_request {
7004 continue;
7005 }
7006 let worktree_abs_path = worktree.abs_path().clone();
7007 let worktree_handle = worktree_handle.clone();
7008 let server_id = server.server_id();
7009 requests.push(
7010 server
7011 .request::<lsp::request::WorkspaceSymbolRequest>(
7012 lsp::WorkspaceSymbolParams {
7013 query: query.to_string(),
7014 ..Default::default()
7015 },
7016 )
7017 .map(move |response| {
7018 let lsp_symbols = response.into_response()
7019 .context("workspace symbols request")
7020 .log_err()
7021 .flatten()
7022 .map(|symbol_response| match symbol_response {
7023 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7024 flat_responses.into_iter().map(|lsp_symbol| {
7025 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7026 }).collect::<Vec<_>>()
7027 }
7028 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7029 nested_responses.into_iter().filter_map(|lsp_symbol| {
7030 let location = match lsp_symbol.location {
7031 OneOf::Left(location) => location,
7032 OneOf::Right(_) => {
7033 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7034 return None
7035 }
7036 };
7037 Some((lsp_symbol.name, lsp_symbol.kind, location))
7038 }).collect::<Vec<_>>()
7039 }
7040 }).unwrap_or_default();
7041
7042 WorkspaceSymbolsResult {
7043 server_id,
7044 lsp_adapter,
7045 worktree: worktree_handle.downgrade(),
7046 worktree_abs_path,
7047 lsp_symbols,
7048 }
7049 }),
7050 );
7051 }
7052
7053 cx.spawn(async move |this, cx| {
7054 let responses = futures::future::join_all(requests).await;
7055 let this = match this.upgrade() {
7056 Some(this) => this,
7057 None => return Ok(Vec::new()),
7058 };
7059
7060 let mut symbols = Vec::new();
7061 for result in responses {
7062 let core_symbols = this.update(cx, |this, cx| {
7063 result
7064 .lsp_symbols
7065 .into_iter()
7066 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7067 let abs_path = symbol_location.uri.to_file_path().ok()?;
7068 let source_worktree = result.worktree.upgrade()?;
7069 let source_worktree_id = source_worktree.read(cx).id();
7070
7071 let path;
7072 let worktree;
7073 if let Some((tree, rel_path)) =
7074 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7075 {
7076 worktree = tree;
7077 path = rel_path;
7078 } else {
7079 worktree = source_worktree;
7080 path = relativize_path(&result.worktree_abs_path, &abs_path);
7081 }
7082
7083 let worktree_id = worktree.read(cx).id();
7084 let project_path = ProjectPath {
7085 worktree_id,
7086 path: path.into(),
7087 };
7088 let signature = this.symbol_signature(&project_path);
7089 Some(CoreSymbol {
7090 source_language_server_id: result.server_id,
7091 language_server_name: result.lsp_adapter.name.clone(),
7092 source_worktree_id,
7093 path: project_path,
7094 kind: symbol_kind,
7095 name: symbol_name,
7096 range: range_from_lsp(symbol_location.range),
7097 signature,
7098 })
7099 })
7100 .collect()
7101 })?;
7102
7103 populate_labels_for_symbols(
7104 core_symbols,
7105 &language_registry,
7106 Some(result.lsp_adapter),
7107 &mut symbols,
7108 )
7109 .await;
7110 }
7111
7112 Ok(symbols)
7113 })
7114 } else {
7115 Task::ready(Err(anyhow!("No upstream client or local language server")))
7116 }
7117 }
7118
7119 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7120 let mut summary = DiagnosticSummary::default();
7121 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7122 summary.error_count += path_summary.error_count;
7123 summary.warning_count += path_summary.warning_count;
7124 }
7125 summary
7126 }
7127
7128 /// Returns the diagnostic summary for a specific project path.
7129 pub fn diagnostic_summary_for_path(
7130 &self,
7131 project_path: &ProjectPath,
7132 _: &App,
7133 ) -> DiagnosticSummary {
7134 if let Some(summaries) = self
7135 .diagnostic_summaries
7136 .get(&project_path.worktree_id)
7137 .and_then(|map| map.get(&project_path.path))
7138 {
7139 let (error_count, warning_count) = summaries.iter().fold(
7140 (0, 0),
7141 |(error_count, warning_count), (_language_server_id, summary)| {
7142 (
7143 error_count + summary.error_count,
7144 warning_count + summary.warning_count,
7145 )
7146 },
7147 );
7148
7149 DiagnosticSummary {
7150 error_count,
7151 warning_count,
7152 }
7153 } else {
7154 DiagnosticSummary::default()
7155 }
7156 }
7157
7158 pub fn diagnostic_summaries<'a>(
7159 &'a self,
7160 include_ignored: bool,
7161 cx: &'a App,
7162 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7163 self.worktree_store
7164 .read(cx)
7165 .visible_worktrees(cx)
7166 .filter_map(|worktree| {
7167 let worktree = worktree.read(cx);
7168 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7169 })
7170 .flat_map(move |(worktree, summaries)| {
7171 let worktree_id = worktree.id();
7172 summaries
7173 .iter()
7174 .filter(move |(path, _)| {
7175 include_ignored
7176 || worktree
7177 .entry_for_path(path.as_ref())
7178 .is_some_and(|entry| !entry.is_ignored)
7179 })
7180 .flat_map(move |(path, summaries)| {
7181 summaries.iter().map(move |(server_id, summary)| {
7182 (
7183 ProjectPath {
7184 worktree_id,
7185 path: path.clone(),
7186 },
7187 *server_id,
7188 *summary,
7189 )
7190 })
7191 })
7192 })
7193 }
7194
7195 pub fn on_buffer_edited(
7196 &mut self,
7197 buffer: Entity<Buffer>,
7198 cx: &mut Context<Self>,
7199 ) -> Option<()> {
7200 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7201 Some(
7202 self.as_local()?
7203 .language_servers_for_buffer(buffer, cx)
7204 .map(|i| i.1.clone())
7205 .collect(),
7206 )
7207 })?;
7208
7209 let buffer = buffer.read(cx);
7210 let file = File::from_dyn(buffer.file())?;
7211 let abs_path = file.as_local()?.abs_path(cx);
7212 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7213 let next_snapshot = buffer.text_snapshot();
7214 for language_server in language_servers {
7215 let language_server = language_server.clone();
7216
7217 let buffer_snapshots = self
7218 .as_local_mut()
7219 .unwrap()
7220 .buffer_snapshots
7221 .get_mut(&buffer.remote_id())
7222 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7223 let previous_snapshot = buffer_snapshots.last()?;
7224
7225 let build_incremental_change = || {
7226 buffer
7227 .edits_since::<Dimensions<PointUtf16, usize>>(
7228 previous_snapshot.snapshot.version(),
7229 )
7230 .map(|edit| {
7231 let edit_start = edit.new.start.0;
7232 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7233 let new_text = next_snapshot
7234 .text_for_range(edit.new.start.1..edit.new.end.1)
7235 .collect();
7236 lsp::TextDocumentContentChangeEvent {
7237 range: Some(lsp::Range::new(
7238 point_to_lsp(edit_start),
7239 point_to_lsp(edit_end),
7240 )),
7241 range_length: None,
7242 text: new_text,
7243 }
7244 })
7245 .collect()
7246 };
7247
7248 let document_sync_kind = language_server
7249 .capabilities()
7250 .text_document_sync
7251 .as_ref()
7252 .and_then(|sync| match sync {
7253 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7254 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7255 });
7256
7257 let content_changes: Vec<_> = match document_sync_kind {
7258 Some(lsp::TextDocumentSyncKind::FULL) => {
7259 vec![lsp::TextDocumentContentChangeEvent {
7260 range: None,
7261 range_length: None,
7262 text: next_snapshot.text(),
7263 }]
7264 }
7265 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7266 _ => {
7267 #[cfg(any(test, feature = "test-support"))]
7268 {
7269 build_incremental_change()
7270 }
7271
7272 #[cfg(not(any(test, feature = "test-support")))]
7273 {
7274 continue;
7275 }
7276 }
7277 };
7278
7279 let next_version = previous_snapshot.version + 1;
7280 buffer_snapshots.push(LspBufferSnapshot {
7281 version: next_version,
7282 snapshot: next_snapshot.clone(),
7283 });
7284
7285 language_server
7286 .notify::<lsp::notification::DidChangeTextDocument>(
7287 &lsp::DidChangeTextDocumentParams {
7288 text_document: lsp::VersionedTextDocumentIdentifier::new(
7289 uri.clone(),
7290 next_version,
7291 ),
7292 content_changes,
7293 },
7294 )
7295 .ok();
7296 self.pull_workspace_diagnostics(language_server.server_id());
7297 }
7298
7299 None
7300 }
7301
7302 pub fn on_buffer_saved(
7303 &mut self,
7304 buffer: Entity<Buffer>,
7305 cx: &mut Context<Self>,
7306 ) -> Option<()> {
7307 let file = File::from_dyn(buffer.read(cx).file())?;
7308 let worktree_id = file.worktree_id(cx);
7309 let abs_path = file.as_local()?.abs_path(cx);
7310 let text_document = lsp::TextDocumentIdentifier {
7311 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7312 };
7313 let local = self.as_local()?;
7314
7315 for server in local.language_servers_for_worktree(worktree_id) {
7316 if let Some(include_text) = include_text(server.as_ref()) {
7317 let text = if include_text {
7318 Some(buffer.read(cx).text())
7319 } else {
7320 None
7321 };
7322 server
7323 .notify::<lsp::notification::DidSaveTextDocument>(
7324 &lsp::DidSaveTextDocumentParams {
7325 text_document: text_document.clone(),
7326 text,
7327 },
7328 )
7329 .ok();
7330 }
7331 }
7332
7333 let language_servers = buffer.update(cx, |buffer, cx| {
7334 local.language_server_ids_for_buffer(buffer, cx)
7335 });
7336 for language_server_id in language_servers {
7337 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7338 }
7339
7340 None
7341 }
7342
7343 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7344 maybe!(async move {
7345 let mut refreshed_servers = HashSet::default();
7346 let servers = lsp_store
7347 .update(cx, |lsp_store, cx| {
7348 let local = lsp_store.as_local()?;
7349
7350 let servers = local
7351 .language_server_ids
7352 .iter()
7353 .filter_map(|(seed, state)| {
7354 let worktree = lsp_store
7355 .worktree_store
7356 .read(cx)
7357 .worktree_for_id(seed.worktree_id, cx);
7358 let delegate: Arc<dyn LspAdapterDelegate> =
7359 worktree.map(|worktree| {
7360 LocalLspAdapterDelegate::new(
7361 local.languages.clone(),
7362 &local.environment,
7363 cx.weak_entity(),
7364 &worktree,
7365 local.http_client.clone(),
7366 local.fs.clone(),
7367 cx,
7368 )
7369 })?;
7370 let server_id = state.id;
7371
7372 let states = local.language_servers.get(&server_id)?;
7373
7374 match states {
7375 LanguageServerState::Starting { .. } => None,
7376 LanguageServerState::Running {
7377 adapter, server, ..
7378 } => {
7379 let adapter = adapter.clone();
7380 let server = server.clone();
7381 refreshed_servers.insert(server.name());
7382 let toolchain = seed.toolchain.clone();
7383 Some(cx.spawn(async move |_, cx| {
7384 let settings =
7385 LocalLspStore::workspace_configuration_for_adapter(
7386 adapter.adapter.clone(),
7387 &delegate,
7388 toolchain,
7389 cx,
7390 )
7391 .await
7392 .ok()?;
7393 server
7394 .notify::<lsp::notification::DidChangeConfiguration>(
7395 &lsp::DidChangeConfigurationParams { settings },
7396 )
7397 .ok()?;
7398 Some(())
7399 }))
7400 }
7401 }
7402 })
7403 .collect::<Vec<_>>();
7404
7405 Some(servers)
7406 })
7407 .ok()
7408 .flatten()?;
7409
7410 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7411 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7412 // to stop and unregister its language server wrapper.
7413 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7414 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7415 let _: Vec<Option<()>> = join_all(servers).await;
7416
7417 Some(())
7418 })
7419 .await;
7420 }
7421
7422 fn maintain_workspace_config(
7423 external_refresh_requests: watch::Receiver<()>,
7424 cx: &mut Context<Self>,
7425 ) -> Task<Result<()>> {
7426 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7427 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7428
7429 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7430 *settings_changed_tx.borrow_mut() = ();
7431 });
7432
7433 let mut joint_future =
7434 futures::stream::select(settings_changed_rx, external_refresh_requests);
7435 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7436 // - 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).
7437 // - 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.
7438 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7439 // - 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,
7440 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7441 cx.spawn(async move |this, cx| {
7442 while let Some(()) = joint_future.next().await {
7443 this.update(cx, |this, cx| {
7444 this.refresh_server_tree(cx);
7445 })
7446 .ok();
7447
7448 Self::refresh_workspace_configurations(&this, cx).await;
7449 }
7450
7451 drop(settings_observation);
7452 anyhow::Ok(())
7453 })
7454 }
7455
7456 pub fn language_servers_for_local_buffer<'a>(
7457 &'a self,
7458 buffer: &Buffer,
7459 cx: &mut App,
7460 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7461 let local = self.as_local();
7462 let language_server_ids = local
7463 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7464 .unwrap_or_default();
7465
7466 language_server_ids
7467 .into_iter()
7468 .filter_map(
7469 move |server_id| match local?.language_servers.get(&server_id)? {
7470 LanguageServerState::Running {
7471 adapter, server, ..
7472 } => Some((adapter, server)),
7473 _ => None,
7474 },
7475 )
7476 }
7477
7478 pub fn language_server_for_local_buffer<'a>(
7479 &'a self,
7480 buffer: &'a Buffer,
7481 server_id: LanguageServerId,
7482 cx: &'a mut App,
7483 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7484 self.as_local()?
7485 .language_servers_for_buffer(buffer, cx)
7486 .find(|(_, s)| s.server_id() == server_id)
7487 }
7488
7489 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7490 self.diagnostic_summaries.remove(&id_to_remove);
7491 if let Some(local) = self.as_local_mut() {
7492 let to_remove = local.remove_worktree(id_to_remove, cx);
7493 for server in to_remove {
7494 self.language_server_statuses.remove(&server);
7495 }
7496 }
7497 }
7498
7499 pub fn shared(
7500 &mut self,
7501 project_id: u64,
7502 downstream_client: AnyProtoClient,
7503 _: &mut Context<Self>,
7504 ) {
7505 self.downstream_client = Some((downstream_client.clone(), project_id));
7506
7507 for (server_id, status) in &self.language_server_statuses {
7508 if let Some(server) = self.language_server_for_id(*server_id) {
7509 downstream_client
7510 .send(proto::StartLanguageServer {
7511 project_id,
7512 server: Some(proto::LanguageServer {
7513 id: server_id.to_proto(),
7514 name: status.name.to_string(),
7515 worktree_id: status.worktree.map(|id| id.to_proto()),
7516 }),
7517 capabilities: serde_json::to_string(&server.capabilities())
7518 .expect("serializing server LSP capabilities"),
7519 })
7520 .log_err();
7521 }
7522 }
7523 }
7524
7525 pub fn disconnected_from_host(&mut self) {
7526 self.downstream_client.take();
7527 }
7528
7529 pub fn disconnected_from_ssh_remote(&mut self) {
7530 if let LspStoreMode::Remote(RemoteLspStore {
7531 upstream_client, ..
7532 }) = &mut self.mode
7533 {
7534 upstream_client.take();
7535 }
7536 }
7537
7538 pub(crate) fn set_language_server_statuses_from_proto(
7539 &mut self,
7540 project: WeakEntity<Project>,
7541 language_servers: Vec<proto::LanguageServer>,
7542 server_capabilities: Vec<String>,
7543 cx: &mut Context<Self>,
7544 ) {
7545 let lsp_logs = cx
7546 .try_global::<GlobalLogStore>()
7547 .map(|lsp_store| lsp_store.0.clone());
7548
7549 self.language_server_statuses = language_servers
7550 .into_iter()
7551 .zip(server_capabilities)
7552 .map(|(server, server_capabilities)| {
7553 let server_id = LanguageServerId(server.id as usize);
7554 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7555 self.lsp_server_capabilities
7556 .insert(server_id, server_capabilities);
7557 }
7558
7559 let name = LanguageServerName::from_proto(server.name);
7560 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7561
7562 if let Some(lsp_logs) = &lsp_logs {
7563 lsp_logs.update(cx, |lsp_logs, cx| {
7564 lsp_logs.add_language_server(
7565 // Only remote clients get their language servers set from proto
7566 LanguageServerKind::Remote {
7567 project: project.clone(),
7568 },
7569 server_id,
7570 Some(name.clone()),
7571 worktree,
7572 None,
7573 cx,
7574 );
7575 });
7576 }
7577
7578 (
7579 server_id,
7580 LanguageServerStatus {
7581 name,
7582 pending_work: Default::default(),
7583 has_pending_diagnostic_updates: false,
7584 progress_tokens: Default::default(),
7585 worktree,
7586 },
7587 )
7588 })
7589 .collect();
7590 }
7591
7592 #[cfg(test)]
7593 pub fn update_diagnostic_entries(
7594 &mut self,
7595 server_id: LanguageServerId,
7596 abs_path: PathBuf,
7597 result_id: Option<String>,
7598 version: Option<i32>,
7599 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7600 cx: &mut Context<Self>,
7601 ) -> anyhow::Result<()> {
7602 self.merge_diagnostic_entries(
7603 vec![DocumentDiagnosticsUpdate {
7604 diagnostics: DocumentDiagnostics {
7605 diagnostics,
7606 document_abs_path: abs_path,
7607 version,
7608 },
7609 result_id,
7610 server_id,
7611 disk_based_sources: Cow::Borrowed(&[]),
7612 }],
7613 |_, _, _| false,
7614 cx,
7615 )?;
7616 Ok(())
7617 }
7618
7619 pub fn merge_diagnostic_entries<'a>(
7620 &mut self,
7621 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7622 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7623 cx: &mut Context<Self>,
7624 ) -> anyhow::Result<()> {
7625 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7626 let mut updated_diagnostics_paths = HashMap::default();
7627 for mut update in diagnostic_updates {
7628 let abs_path = &update.diagnostics.document_abs_path;
7629 let server_id = update.server_id;
7630 let Some((worktree, relative_path)) =
7631 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7632 else {
7633 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7634 return Ok(());
7635 };
7636
7637 let worktree_id = worktree.read(cx).id();
7638 let project_path = ProjectPath {
7639 worktree_id,
7640 path: relative_path.into(),
7641 };
7642
7643 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7644 let snapshot = buffer_handle.read(cx).snapshot();
7645 let buffer = buffer_handle.read(cx);
7646 let reused_diagnostics = buffer
7647 .buffer_diagnostics(Some(server_id))
7648 .iter()
7649 .filter(|v| merge(buffer, &v.diagnostic, cx))
7650 .map(|v| {
7651 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7652 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7653 DiagnosticEntry {
7654 range: start..end,
7655 diagnostic: v.diagnostic.clone(),
7656 }
7657 })
7658 .collect::<Vec<_>>();
7659
7660 self.as_local_mut()
7661 .context("cannot merge diagnostics on a remote LspStore")?
7662 .update_buffer_diagnostics(
7663 &buffer_handle,
7664 server_id,
7665 update.result_id,
7666 update.diagnostics.version,
7667 update.diagnostics.diagnostics.clone(),
7668 reused_diagnostics.clone(),
7669 cx,
7670 )?;
7671
7672 update.diagnostics.diagnostics.extend(reused_diagnostics);
7673 }
7674
7675 let updated = worktree.update(cx, |worktree, cx| {
7676 self.update_worktree_diagnostics(
7677 worktree.id(),
7678 server_id,
7679 project_path.path.clone(),
7680 update.diagnostics.diagnostics,
7681 cx,
7682 )
7683 })?;
7684 match updated {
7685 ControlFlow::Continue(new_summary) => {
7686 if let Some((project_id, new_summary)) = new_summary {
7687 match &mut diagnostics_summary {
7688 Some(diagnostics_summary) => {
7689 diagnostics_summary
7690 .more_summaries
7691 .push(proto::DiagnosticSummary {
7692 path: project_path.path.as_ref().to_proto(),
7693 language_server_id: server_id.0 as u64,
7694 error_count: new_summary.error_count,
7695 warning_count: new_summary.warning_count,
7696 })
7697 }
7698 None => {
7699 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7700 project_id,
7701 worktree_id: worktree_id.to_proto(),
7702 summary: Some(proto::DiagnosticSummary {
7703 path: project_path.path.as_ref().to_proto(),
7704 language_server_id: server_id.0 as u64,
7705 error_count: new_summary.error_count,
7706 warning_count: new_summary.warning_count,
7707 }),
7708 more_summaries: Vec::new(),
7709 })
7710 }
7711 }
7712 }
7713 updated_diagnostics_paths
7714 .entry(server_id)
7715 .or_insert_with(Vec::new)
7716 .push(project_path);
7717 }
7718 ControlFlow::Break(()) => {}
7719 }
7720 }
7721
7722 if let Some((diagnostics_summary, (downstream_client, _))) =
7723 diagnostics_summary.zip(self.downstream_client.as_ref())
7724 {
7725 downstream_client.send(diagnostics_summary).log_err();
7726 }
7727 for (server_id, paths) in updated_diagnostics_paths {
7728 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7729 }
7730 Ok(())
7731 }
7732
7733 fn update_worktree_diagnostics(
7734 &mut self,
7735 worktree_id: WorktreeId,
7736 server_id: LanguageServerId,
7737 path_in_worktree: Arc<Path>,
7738 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7739 _: &mut Context<Worktree>,
7740 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7741 let local = match &mut self.mode {
7742 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7743 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7744 };
7745
7746 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7747 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7748 let summaries_by_server_id = summaries_for_tree
7749 .entry(path_in_worktree.clone())
7750 .or_default();
7751
7752 let old_summary = summaries_by_server_id
7753 .remove(&server_id)
7754 .unwrap_or_default();
7755
7756 let new_summary = DiagnosticSummary::new(&diagnostics);
7757 if new_summary.is_empty() {
7758 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7759 {
7760 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7761 diagnostics_by_server_id.remove(ix);
7762 }
7763 if diagnostics_by_server_id.is_empty() {
7764 diagnostics_for_tree.remove(&path_in_worktree);
7765 }
7766 }
7767 } else {
7768 summaries_by_server_id.insert(server_id, new_summary);
7769 let diagnostics_by_server_id = diagnostics_for_tree
7770 .entry(path_in_worktree.clone())
7771 .or_default();
7772 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7773 Ok(ix) => {
7774 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7775 }
7776 Err(ix) => {
7777 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7778 }
7779 }
7780 }
7781
7782 if !old_summary.is_empty() || !new_summary.is_empty() {
7783 if let Some((_, project_id)) = &self.downstream_client {
7784 Ok(ControlFlow::Continue(Some((
7785 *project_id,
7786 proto::DiagnosticSummary {
7787 path: path_in_worktree.to_proto(),
7788 language_server_id: server_id.0 as u64,
7789 error_count: new_summary.error_count as u32,
7790 warning_count: new_summary.warning_count as u32,
7791 },
7792 ))))
7793 } else {
7794 Ok(ControlFlow::Continue(None))
7795 }
7796 } else {
7797 Ok(ControlFlow::Break(()))
7798 }
7799 }
7800
7801 pub fn open_buffer_for_symbol(
7802 &mut self,
7803 symbol: &Symbol,
7804 cx: &mut Context<Self>,
7805 ) -> Task<Result<Entity<Buffer>>> {
7806 if let Some((client, project_id)) = self.upstream_client() {
7807 let request = client.request(proto::OpenBufferForSymbol {
7808 project_id,
7809 symbol: Some(Self::serialize_symbol(symbol)),
7810 });
7811 cx.spawn(async move |this, cx| {
7812 let response = request.await?;
7813 let buffer_id = BufferId::new(response.buffer_id)?;
7814 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7815 .await
7816 })
7817 } else if let Some(local) = self.as_local() {
7818 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7819 seed.worktree_id == symbol.source_worktree_id
7820 && state.id == symbol.source_language_server_id
7821 && symbol.language_server_name == seed.name
7822 });
7823 if !is_valid {
7824 return Task::ready(Err(anyhow!(
7825 "language server for worktree and language not found"
7826 )));
7827 };
7828
7829 let worktree_abs_path = if let Some(worktree_abs_path) = self
7830 .worktree_store
7831 .read(cx)
7832 .worktree_for_id(symbol.path.worktree_id, cx)
7833 .map(|worktree| worktree.read(cx).abs_path())
7834 {
7835 worktree_abs_path
7836 } else {
7837 return Task::ready(Err(anyhow!("worktree not found for symbol")));
7838 };
7839
7840 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
7841 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
7842 uri
7843 } else {
7844 return Task::ready(Err(anyhow!("invalid symbol path")));
7845 };
7846
7847 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7848 } else {
7849 Task::ready(Err(anyhow!("no upstream client or local store")))
7850 }
7851 }
7852
7853 pub(crate) fn open_local_buffer_via_lsp(
7854 &mut self,
7855 abs_path: lsp::Uri,
7856 language_server_id: LanguageServerId,
7857 cx: &mut Context<Self>,
7858 ) -> Task<Result<Entity<Buffer>>> {
7859 cx.spawn(async move |lsp_store, cx| {
7860 // Escape percent-encoded string.
7861 let current_scheme = abs_path.scheme().to_owned();
7862 // Uri is immutable, so we can't modify the scheme
7863
7864 let abs_path = abs_path
7865 .to_file_path()
7866 .map_err(|()| anyhow!("can't convert URI to path"))?;
7867 let p = abs_path.clone();
7868 let yarn_worktree = lsp_store
7869 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7870 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7871 cx.spawn(async move |this, cx| {
7872 let t = this
7873 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7874 .ok()?;
7875 t.await
7876 })
7877 }),
7878 None => Task::ready(None),
7879 })?
7880 .await;
7881 let (worktree_root_target, known_relative_path) =
7882 if let Some((zip_root, relative_path)) = yarn_worktree {
7883 (zip_root, Some(relative_path))
7884 } else {
7885 (Arc::<Path>::from(abs_path.as_path()), None)
7886 };
7887 let (worktree, relative_path) = if let Some(result) =
7888 lsp_store.update(cx, |lsp_store, cx| {
7889 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7890 worktree_store.find_worktree(&worktree_root_target, cx)
7891 })
7892 })? {
7893 let relative_path =
7894 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
7895 (result.0, relative_path)
7896 } else {
7897 let worktree = lsp_store
7898 .update(cx, |lsp_store, cx| {
7899 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7900 worktree_store.create_worktree(&worktree_root_target, false, cx)
7901 })
7902 })?
7903 .await?;
7904 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
7905 lsp_store
7906 .update(cx, |lsp_store, cx| {
7907 if let Some(local) = lsp_store.as_local_mut() {
7908 local.register_language_server_for_invisible_worktree(
7909 &worktree,
7910 language_server_id,
7911 cx,
7912 )
7913 }
7914 })
7915 .ok();
7916 }
7917 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
7918 let relative_path = if let Some(known_path) = known_relative_path {
7919 known_path
7920 } else {
7921 abs_path.strip_prefix(worktree_root)?.into()
7922 };
7923 (worktree, relative_path)
7924 };
7925 let project_path = ProjectPath {
7926 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
7927 path: relative_path,
7928 };
7929 lsp_store
7930 .update(cx, |lsp_store, cx| {
7931 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
7932 buffer_store.open_buffer(project_path, cx)
7933 })
7934 })?
7935 .await
7936 })
7937 }
7938
7939 fn request_multiple_lsp_locally<P, R>(
7940 &mut self,
7941 buffer: &Entity<Buffer>,
7942 position: Option<P>,
7943 request: R,
7944 cx: &mut Context<Self>,
7945 ) -> Task<Vec<(LanguageServerId, R::Response)>>
7946 where
7947 P: ToOffset,
7948 R: LspCommand + Clone,
7949 <R::LspRequest as lsp::request::Request>::Result: Send,
7950 <R::LspRequest as lsp::request::Request>::Params: Send,
7951 {
7952 let Some(local) = self.as_local() else {
7953 return Task::ready(Vec::new());
7954 };
7955
7956 let snapshot = buffer.read(cx).snapshot();
7957 let scope = position.and_then(|position| snapshot.language_scope_at(position));
7958
7959 let server_ids = buffer.update(cx, |buffer, cx| {
7960 local
7961 .language_servers_for_buffer(buffer, cx)
7962 .filter(|(adapter, _)| {
7963 scope
7964 .as_ref()
7965 .map(|scope| scope.language_allowed(&adapter.name))
7966 .unwrap_or(true)
7967 })
7968 .map(|(_, server)| server.server_id())
7969 .filter(|server_id| {
7970 self.as_local().is_none_or(|local| {
7971 local
7972 .buffers_opened_in_servers
7973 .get(&snapshot.remote_id())
7974 .is_some_and(|servers| servers.contains(server_id))
7975 })
7976 })
7977 .collect::<Vec<_>>()
7978 });
7979
7980 let mut response_results = server_ids
7981 .into_iter()
7982 .map(|server_id| {
7983 let task = self.request_lsp(
7984 buffer.clone(),
7985 LanguageServerToQuery::Other(server_id),
7986 request.clone(),
7987 cx,
7988 );
7989 async move { (server_id, task.await) }
7990 })
7991 .collect::<FuturesUnordered<_>>();
7992
7993 cx.background_spawn(async move {
7994 let mut responses = Vec::with_capacity(response_results.len());
7995 while let Some((server_id, response_result)) = response_results.next().await {
7996 if let Some(response) = response_result.log_err() {
7997 responses.push((server_id, response));
7998 }
7999 }
8000 responses
8001 })
8002 }
8003
8004 async fn handle_lsp_command<T: LspCommand>(
8005 this: Entity<Self>,
8006 envelope: TypedEnvelope<T::ProtoRequest>,
8007 mut cx: AsyncApp,
8008 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8009 where
8010 <T::LspRequest as lsp::request::Request>::Params: Send,
8011 <T::LspRequest as lsp::request::Request>::Result: Send,
8012 {
8013 let sender_id = envelope.original_sender_id().unwrap_or_default();
8014 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8015 let buffer_handle = this.update(&mut cx, |this, cx| {
8016 this.buffer_store.read(cx).get_existing(buffer_id)
8017 })??;
8018 let request = T::from_proto(
8019 envelope.payload,
8020 this.clone(),
8021 buffer_handle.clone(),
8022 cx.clone(),
8023 )
8024 .await?;
8025 let response = this
8026 .update(&mut cx, |this, cx| {
8027 this.request_lsp(
8028 buffer_handle.clone(),
8029 LanguageServerToQuery::FirstCapable,
8030 request,
8031 cx,
8032 )
8033 })?
8034 .await?;
8035 this.update(&mut cx, |this, cx| {
8036 Ok(T::response_to_proto(
8037 response,
8038 this,
8039 sender_id,
8040 &buffer_handle.read(cx).version(),
8041 cx,
8042 ))
8043 })?
8044 }
8045
8046 async fn handle_lsp_query(
8047 lsp_store: Entity<Self>,
8048 envelope: TypedEnvelope<proto::LspQuery>,
8049 mut cx: AsyncApp,
8050 ) -> Result<proto::Ack> {
8051 use proto::lsp_query::Request;
8052 let sender_id = envelope.original_sender_id().unwrap_or_default();
8053 let lsp_query = envelope.payload;
8054 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8055 match lsp_query.request.context("invalid LSP query request")? {
8056 Request::GetReferences(get_references) => {
8057 let position = get_references.position.clone().and_then(deserialize_anchor);
8058 Self::query_lsp_locally::<GetReferences>(
8059 lsp_store,
8060 sender_id,
8061 lsp_request_id,
8062 get_references,
8063 position,
8064 cx.clone(),
8065 )
8066 .await?;
8067 }
8068 Request::GetDocumentColor(get_document_color) => {
8069 Self::query_lsp_locally::<GetDocumentColor>(
8070 lsp_store,
8071 sender_id,
8072 lsp_request_id,
8073 get_document_color,
8074 None,
8075 cx.clone(),
8076 )
8077 .await?;
8078 }
8079 Request::GetHover(get_hover) => {
8080 let position = get_hover.position.clone().and_then(deserialize_anchor);
8081 Self::query_lsp_locally::<GetHover>(
8082 lsp_store,
8083 sender_id,
8084 lsp_request_id,
8085 get_hover,
8086 position,
8087 cx.clone(),
8088 )
8089 .await?;
8090 }
8091 Request::GetCodeActions(get_code_actions) => {
8092 Self::query_lsp_locally::<GetCodeActions>(
8093 lsp_store,
8094 sender_id,
8095 lsp_request_id,
8096 get_code_actions,
8097 None,
8098 cx.clone(),
8099 )
8100 .await?;
8101 }
8102 Request::GetSignatureHelp(get_signature_help) => {
8103 let position = get_signature_help
8104 .position
8105 .clone()
8106 .and_then(deserialize_anchor);
8107 Self::query_lsp_locally::<GetSignatureHelp>(
8108 lsp_store,
8109 sender_id,
8110 lsp_request_id,
8111 get_signature_help,
8112 position,
8113 cx.clone(),
8114 )
8115 .await?;
8116 }
8117 Request::GetCodeLens(get_code_lens) => {
8118 Self::query_lsp_locally::<GetCodeLens>(
8119 lsp_store,
8120 sender_id,
8121 lsp_request_id,
8122 get_code_lens,
8123 None,
8124 cx.clone(),
8125 )
8126 .await?;
8127 }
8128 Request::GetDefinition(get_definition) => {
8129 let position = get_definition.position.clone().and_then(deserialize_anchor);
8130 Self::query_lsp_locally::<GetDefinitions>(
8131 lsp_store,
8132 sender_id,
8133 lsp_request_id,
8134 get_definition,
8135 position,
8136 cx.clone(),
8137 )
8138 .await?;
8139 }
8140 Request::GetDeclaration(get_declaration) => {
8141 let position = get_declaration
8142 .position
8143 .clone()
8144 .and_then(deserialize_anchor);
8145 Self::query_lsp_locally::<GetDeclarations>(
8146 lsp_store,
8147 sender_id,
8148 lsp_request_id,
8149 get_declaration,
8150 position,
8151 cx.clone(),
8152 )
8153 .await?;
8154 }
8155 Request::GetTypeDefinition(get_type_definition) => {
8156 let position = get_type_definition
8157 .position
8158 .clone()
8159 .and_then(deserialize_anchor);
8160 Self::query_lsp_locally::<GetTypeDefinitions>(
8161 lsp_store,
8162 sender_id,
8163 lsp_request_id,
8164 get_type_definition,
8165 position,
8166 cx.clone(),
8167 )
8168 .await?;
8169 }
8170 Request::GetImplementation(get_implementation) => {
8171 let position = get_implementation
8172 .position
8173 .clone()
8174 .and_then(deserialize_anchor);
8175 Self::query_lsp_locally::<GetImplementations>(
8176 lsp_store,
8177 sender_id,
8178 lsp_request_id,
8179 get_implementation,
8180 position,
8181 cx.clone(),
8182 )
8183 .await?;
8184 }
8185 // Diagnostics pull synchronizes internally via the buffer state, and cannot be handled generically as the other requests.
8186 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8187 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8188 let version = deserialize_version(get_document_diagnostics.buffer_version());
8189 let buffer = lsp_store.update(&mut cx, |this, cx| {
8190 this.buffer_store.read(cx).get_existing(buffer_id)
8191 })??;
8192 buffer
8193 .update(&mut cx, |buffer, _| {
8194 buffer.wait_for_version(version.clone())
8195 })?
8196 .await?;
8197 lsp_store.update(&mut cx, |lsp_store, cx| {
8198 let existing_queries = lsp_store
8199 .running_lsp_requests
8200 .entry(TypeId::of::<GetDocumentDiagnostics>())
8201 .or_default();
8202 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8203 ) || buffer.read(cx).version.changed_since(&existing_queries.0)
8204 {
8205 existing_queries.1.clear();
8206 }
8207 existing_queries.1.insert(
8208 lsp_request_id,
8209 cx.spawn(async move |lsp_store, cx| {
8210 let diagnostics_pull = lsp_store
8211 .update(cx, |lsp_store, cx| {
8212 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8213 })
8214 .ok();
8215 if let Some(diagnostics_pull) = diagnostics_pull {
8216 match diagnostics_pull.await {
8217 Ok(()) => {}
8218 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8219 };
8220 }
8221 }),
8222 );
8223 })?;
8224 }
8225 }
8226 Ok(proto::Ack {})
8227 }
8228
8229 async fn handle_lsp_query_response(
8230 lsp_store: Entity<Self>,
8231 envelope: TypedEnvelope<proto::LspQueryResponse>,
8232 cx: AsyncApp,
8233 ) -> Result<()> {
8234 lsp_store.read_with(&cx, |lsp_store, _| {
8235 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8236 upstream_client.handle_lsp_response(envelope.clone());
8237 }
8238 })?;
8239 Ok(())
8240 }
8241
8242 async fn handle_apply_code_action(
8243 this: Entity<Self>,
8244 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8245 mut cx: AsyncApp,
8246 ) -> Result<proto::ApplyCodeActionResponse> {
8247 let sender_id = envelope.original_sender_id().unwrap_or_default();
8248 let action =
8249 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8250 let apply_code_action = this.update(&mut cx, |this, cx| {
8251 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8252 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8253 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8254 })??;
8255
8256 let project_transaction = apply_code_action.await?;
8257 let project_transaction = this.update(&mut cx, |this, cx| {
8258 this.buffer_store.update(cx, |buffer_store, cx| {
8259 buffer_store.serialize_project_transaction_for_peer(
8260 project_transaction,
8261 sender_id,
8262 cx,
8263 )
8264 })
8265 })?;
8266 Ok(proto::ApplyCodeActionResponse {
8267 transaction: Some(project_transaction),
8268 })
8269 }
8270
8271 async fn handle_register_buffer_with_language_servers(
8272 this: Entity<Self>,
8273 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8274 mut cx: AsyncApp,
8275 ) -> Result<proto::Ack> {
8276 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8277 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8278 this.update(&mut cx, |this, cx| {
8279 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8280 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8281 project_id: upstream_project_id,
8282 buffer_id: buffer_id.to_proto(),
8283 only_servers: envelope.payload.only_servers,
8284 });
8285 }
8286
8287 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8288 anyhow::bail!("buffer is not open");
8289 };
8290
8291 let handle = this.register_buffer_with_language_servers(
8292 &buffer,
8293 envelope
8294 .payload
8295 .only_servers
8296 .into_iter()
8297 .filter_map(|selector| {
8298 Some(match selector.selector? {
8299 proto::language_server_selector::Selector::ServerId(server_id) => {
8300 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8301 }
8302 proto::language_server_selector::Selector::Name(name) => {
8303 LanguageServerSelector::Name(LanguageServerName(
8304 SharedString::from(name),
8305 ))
8306 }
8307 })
8308 })
8309 .collect(),
8310 false,
8311 cx,
8312 );
8313 this.buffer_store().update(cx, |buffer_store, _| {
8314 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8315 });
8316
8317 Ok(())
8318 })??;
8319 Ok(proto::Ack {})
8320 }
8321
8322 async fn handle_rename_project_entry(
8323 this: Entity<Self>,
8324 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8325 mut cx: AsyncApp,
8326 ) -> Result<proto::ProjectEntryResponse> {
8327 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8328 let (worktree_id, worktree, old_path, is_dir) = this
8329 .update(&mut cx, |this, cx| {
8330 this.worktree_store
8331 .read(cx)
8332 .worktree_and_entry_for_id(entry_id, cx)
8333 .map(|(worktree, entry)| {
8334 (
8335 worktree.read(cx).id(),
8336 worktree,
8337 entry.path.clone(),
8338 entry.is_dir(),
8339 )
8340 })
8341 })?
8342 .context("worktree not found")?;
8343 let (old_abs_path, new_abs_path) = {
8344 let root_path = worktree.read_with(&cx, |this, _| this.abs_path())?;
8345 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8346 (root_path.join(&old_path), root_path.join(&new_path))
8347 };
8348
8349 let _transaction = Self::will_rename_entry(
8350 this.downgrade(),
8351 worktree_id,
8352 &old_abs_path,
8353 &new_abs_path,
8354 is_dir,
8355 cx.clone(),
8356 )
8357 .await;
8358 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8359 this.read_with(&cx, |this, _| {
8360 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8361 })
8362 .ok();
8363 response
8364 }
8365
8366 async fn handle_update_diagnostic_summary(
8367 this: Entity<Self>,
8368 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8369 mut cx: AsyncApp,
8370 ) -> Result<()> {
8371 this.update(&mut cx, |lsp_store, cx| {
8372 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8373 let mut updated_diagnostics_paths = HashMap::default();
8374 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8375 for message_summary in envelope
8376 .payload
8377 .summary
8378 .into_iter()
8379 .chain(envelope.payload.more_summaries)
8380 {
8381 let project_path = ProjectPath {
8382 worktree_id,
8383 path: Arc::<Path>::from_proto(message_summary.path),
8384 };
8385 let path = project_path.path.clone();
8386 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8387 let summary = DiagnosticSummary {
8388 error_count: message_summary.error_count as usize,
8389 warning_count: message_summary.warning_count as usize,
8390 };
8391
8392 if summary.is_empty() {
8393 if let Some(worktree_summaries) =
8394 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8395 && let Some(summaries) = worktree_summaries.get_mut(&path)
8396 {
8397 summaries.remove(&server_id);
8398 if summaries.is_empty() {
8399 worktree_summaries.remove(&path);
8400 }
8401 }
8402 } else {
8403 lsp_store
8404 .diagnostic_summaries
8405 .entry(worktree_id)
8406 .or_default()
8407 .entry(path)
8408 .or_default()
8409 .insert(server_id, summary);
8410 }
8411
8412 if let Some((_, project_id)) = &lsp_store.downstream_client {
8413 match &mut diagnostics_summary {
8414 Some(diagnostics_summary) => {
8415 diagnostics_summary
8416 .more_summaries
8417 .push(proto::DiagnosticSummary {
8418 path: project_path.path.as_ref().to_proto(),
8419 language_server_id: server_id.0 as u64,
8420 error_count: summary.error_count as u32,
8421 warning_count: summary.warning_count as u32,
8422 })
8423 }
8424 None => {
8425 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8426 project_id: *project_id,
8427 worktree_id: worktree_id.to_proto(),
8428 summary: Some(proto::DiagnosticSummary {
8429 path: project_path.path.as_ref().to_proto(),
8430 language_server_id: server_id.0 as u64,
8431 error_count: summary.error_count as u32,
8432 warning_count: summary.warning_count as u32,
8433 }),
8434 more_summaries: Vec::new(),
8435 })
8436 }
8437 }
8438 }
8439 updated_diagnostics_paths
8440 .entry(server_id)
8441 .or_insert_with(Vec::new)
8442 .push(project_path);
8443 }
8444
8445 if let Some((diagnostics_summary, (downstream_client, _))) =
8446 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8447 {
8448 downstream_client.send(diagnostics_summary).log_err();
8449 }
8450 for (server_id, paths) in updated_diagnostics_paths {
8451 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8452 }
8453 Ok(())
8454 })?
8455 }
8456
8457 async fn handle_start_language_server(
8458 lsp_store: Entity<Self>,
8459 envelope: TypedEnvelope<proto::StartLanguageServer>,
8460 mut cx: AsyncApp,
8461 ) -> Result<()> {
8462 let server = envelope.payload.server.context("invalid server")?;
8463 let server_capabilities =
8464 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8465 .with_context(|| {
8466 format!(
8467 "incorrect server capabilities {}",
8468 envelope.payload.capabilities
8469 )
8470 })?;
8471 lsp_store.update(&mut cx, |lsp_store, cx| {
8472 let server_id = LanguageServerId(server.id as usize);
8473 let server_name = LanguageServerName::from_proto(server.name.clone());
8474 lsp_store
8475 .lsp_server_capabilities
8476 .insert(server_id, server_capabilities);
8477 lsp_store.language_server_statuses.insert(
8478 server_id,
8479 LanguageServerStatus {
8480 name: server_name.clone(),
8481 pending_work: Default::default(),
8482 has_pending_diagnostic_updates: false,
8483 progress_tokens: Default::default(),
8484 worktree: server.worktree_id.map(WorktreeId::from_proto),
8485 },
8486 );
8487 cx.emit(LspStoreEvent::LanguageServerAdded(
8488 server_id,
8489 server_name,
8490 server.worktree_id.map(WorktreeId::from_proto),
8491 ));
8492 cx.notify();
8493 })?;
8494 Ok(())
8495 }
8496
8497 async fn handle_update_language_server(
8498 lsp_store: Entity<Self>,
8499 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8500 mut cx: AsyncApp,
8501 ) -> Result<()> {
8502 lsp_store.update(&mut cx, |lsp_store, cx| {
8503 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8504
8505 match envelope.payload.variant.context("invalid variant")? {
8506 proto::update_language_server::Variant::WorkStart(payload) => {
8507 lsp_store.on_lsp_work_start(
8508 language_server_id,
8509 payload.token,
8510 LanguageServerProgress {
8511 title: payload.title,
8512 is_disk_based_diagnostics_progress: false,
8513 is_cancellable: payload.is_cancellable.unwrap_or(false),
8514 message: payload.message,
8515 percentage: payload.percentage.map(|p| p as usize),
8516 last_update_at: cx.background_executor().now(),
8517 },
8518 cx,
8519 );
8520 }
8521 proto::update_language_server::Variant::WorkProgress(payload) => {
8522 lsp_store.on_lsp_work_progress(
8523 language_server_id,
8524 payload.token,
8525 LanguageServerProgress {
8526 title: None,
8527 is_disk_based_diagnostics_progress: false,
8528 is_cancellable: payload.is_cancellable.unwrap_or(false),
8529 message: payload.message,
8530 percentage: payload.percentage.map(|p| p as usize),
8531 last_update_at: cx.background_executor().now(),
8532 },
8533 cx,
8534 );
8535 }
8536
8537 proto::update_language_server::Variant::WorkEnd(payload) => {
8538 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8539 }
8540
8541 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8542 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8543 }
8544
8545 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8546 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8547 }
8548
8549 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8550 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8551 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8552 cx.emit(LspStoreEvent::LanguageServerUpdate {
8553 language_server_id,
8554 name: envelope
8555 .payload
8556 .server_name
8557 .map(SharedString::new)
8558 .map(LanguageServerName),
8559 message: non_lsp,
8560 });
8561 }
8562 }
8563
8564 Ok(())
8565 })?
8566 }
8567
8568 async fn handle_language_server_log(
8569 this: Entity<Self>,
8570 envelope: TypedEnvelope<proto::LanguageServerLog>,
8571 mut cx: AsyncApp,
8572 ) -> Result<()> {
8573 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8574 let log_type = envelope
8575 .payload
8576 .log_type
8577 .map(LanguageServerLogType::from_proto)
8578 .context("invalid language server log type")?;
8579
8580 let message = envelope.payload.message;
8581
8582 this.update(&mut cx, |_, cx| {
8583 cx.emit(LspStoreEvent::LanguageServerLog(
8584 language_server_id,
8585 log_type,
8586 message,
8587 ));
8588 })
8589 }
8590
8591 async fn handle_lsp_ext_cancel_flycheck(
8592 lsp_store: Entity<Self>,
8593 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8594 cx: AsyncApp,
8595 ) -> Result<proto::Ack> {
8596 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8597 lsp_store.read_with(&cx, |lsp_store, _| {
8598 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8599 server
8600 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
8601 .context("handling lsp ext cancel flycheck")
8602 } else {
8603 anyhow::Ok(())
8604 }
8605 })??;
8606
8607 Ok(proto::Ack {})
8608 }
8609
8610 async fn handle_lsp_ext_run_flycheck(
8611 lsp_store: Entity<Self>,
8612 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8613 mut cx: AsyncApp,
8614 ) -> Result<proto::Ack> {
8615 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8616 lsp_store.update(&mut cx, |lsp_store, cx| {
8617 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8618 let text_document = if envelope.payload.current_file_only {
8619 let buffer_id = envelope
8620 .payload
8621 .buffer_id
8622 .map(|id| BufferId::new(id))
8623 .transpose()?;
8624 buffer_id
8625 .and_then(|buffer_id| {
8626 lsp_store
8627 .buffer_store()
8628 .read(cx)
8629 .get(buffer_id)
8630 .and_then(|buffer| {
8631 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
8632 })
8633 .map(|path| make_text_document_identifier(&path))
8634 })
8635 .transpose()?
8636 } else {
8637 None
8638 };
8639 server
8640 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
8641 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
8642 )
8643 .context("handling lsp ext run flycheck")
8644 } else {
8645 anyhow::Ok(())
8646 }
8647 })??;
8648
8649 Ok(proto::Ack {})
8650 }
8651
8652 async fn handle_lsp_ext_clear_flycheck(
8653 lsp_store: Entity<Self>,
8654 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
8655 cx: AsyncApp,
8656 ) -> Result<proto::Ack> {
8657 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8658 lsp_store.read_with(&cx, |lsp_store, _| {
8659 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8660 server
8661 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
8662 .context("handling lsp ext clear flycheck")
8663 } else {
8664 anyhow::Ok(())
8665 }
8666 })??;
8667
8668 Ok(proto::Ack {})
8669 }
8670
8671 pub fn disk_based_diagnostics_started(
8672 &mut self,
8673 language_server_id: LanguageServerId,
8674 cx: &mut Context<Self>,
8675 ) {
8676 if let Some(language_server_status) =
8677 self.language_server_statuses.get_mut(&language_server_id)
8678 {
8679 language_server_status.has_pending_diagnostic_updates = true;
8680 }
8681
8682 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
8683 cx.emit(LspStoreEvent::LanguageServerUpdate {
8684 language_server_id,
8685 name: self
8686 .language_server_adapter_for_id(language_server_id)
8687 .map(|adapter| adapter.name()),
8688 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
8689 Default::default(),
8690 ),
8691 })
8692 }
8693
8694 pub fn disk_based_diagnostics_finished(
8695 &mut self,
8696 language_server_id: LanguageServerId,
8697 cx: &mut Context<Self>,
8698 ) {
8699 if let Some(language_server_status) =
8700 self.language_server_statuses.get_mut(&language_server_id)
8701 {
8702 language_server_status.has_pending_diagnostic_updates = false;
8703 }
8704
8705 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
8706 cx.emit(LspStoreEvent::LanguageServerUpdate {
8707 language_server_id,
8708 name: self
8709 .language_server_adapter_for_id(language_server_id)
8710 .map(|adapter| adapter.name()),
8711 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
8712 Default::default(),
8713 ),
8714 })
8715 }
8716
8717 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
8718 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
8719 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
8720 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
8721 // the language server might take some time to publish diagnostics.
8722 fn simulate_disk_based_diagnostics_events_if_needed(
8723 &mut self,
8724 language_server_id: LanguageServerId,
8725 cx: &mut Context<Self>,
8726 ) {
8727 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
8728
8729 let Some(LanguageServerState::Running {
8730 simulate_disk_based_diagnostics_completion,
8731 adapter,
8732 ..
8733 }) = self
8734 .as_local_mut()
8735 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
8736 else {
8737 return;
8738 };
8739
8740 if adapter.disk_based_diagnostics_progress_token.is_some() {
8741 return;
8742 }
8743
8744 let prev_task =
8745 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
8746 cx.background_executor()
8747 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
8748 .await;
8749
8750 this.update(cx, |this, cx| {
8751 this.disk_based_diagnostics_finished(language_server_id, cx);
8752
8753 if let Some(LanguageServerState::Running {
8754 simulate_disk_based_diagnostics_completion,
8755 ..
8756 }) = this.as_local_mut().and_then(|local_store| {
8757 local_store.language_servers.get_mut(&language_server_id)
8758 }) {
8759 *simulate_disk_based_diagnostics_completion = None;
8760 }
8761 })
8762 .ok();
8763 }));
8764
8765 if prev_task.is_none() {
8766 self.disk_based_diagnostics_started(language_server_id, cx);
8767 }
8768 }
8769
8770 pub fn language_server_statuses(
8771 &self,
8772 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
8773 self.language_server_statuses
8774 .iter()
8775 .map(|(key, value)| (*key, value))
8776 }
8777
8778 pub(super) fn did_rename_entry(
8779 &self,
8780 worktree_id: WorktreeId,
8781 old_path: &Path,
8782 new_path: &Path,
8783 is_dir: bool,
8784 ) {
8785 maybe!({
8786 let local_store = self.as_local()?;
8787
8788 let old_uri = lsp::Uri::from_file_path(old_path)
8789 .ok()
8790 .map(|uri| uri.to_string())?;
8791 let new_uri = lsp::Uri::from_file_path(new_path)
8792 .ok()
8793 .map(|uri| uri.to_string())?;
8794
8795 for language_server in local_store.language_servers_for_worktree(worktree_id) {
8796 let Some(filter) = local_store
8797 .language_server_paths_watched_for_rename
8798 .get(&language_server.server_id())
8799 else {
8800 continue;
8801 };
8802
8803 if filter.should_send_did_rename(&old_uri, is_dir) {
8804 language_server
8805 .notify::<DidRenameFiles>(&RenameFilesParams {
8806 files: vec![FileRename {
8807 old_uri: old_uri.clone(),
8808 new_uri: new_uri.clone(),
8809 }],
8810 })
8811 .ok();
8812 }
8813 }
8814 Some(())
8815 });
8816 }
8817
8818 pub(super) fn will_rename_entry(
8819 this: WeakEntity<Self>,
8820 worktree_id: WorktreeId,
8821 old_path: &Path,
8822 new_path: &Path,
8823 is_dir: bool,
8824 cx: AsyncApp,
8825 ) -> Task<ProjectTransaction> {
8826 let old_uri = lsp::Uri::from_file_path(old_path)
8827 .ok()
8828 .map(|uri| uri.to_string());
8829 let new_uri = lsp::Uri::from_file_path(new_path)
8830 .ok()
8831 .map(|uri| uri.to_string());
8832 cx.spawn(async move |cx| {
8833 let mut tasks = vec![];
8834 this.update(cx, |this, cx| {
8835 let local_store = this.as_local()?;
8836 let old_uri = old_uri?;
8837 let new_uri = new_uri?;
8838 for language_server in local_store.language_servers_for_worktree(worktree_id) {
8839 let Some(filter) = local_store
8840 .language_server_paths_watched_for_rename
8841 .get(&language_server.server_id())
8842 else {
8843 continue;
8844 };
8845
8846 if filter.should_send_will_rename(&old_uri, is_dir) {
8847 let apply_edit = cx.spawn({
8848 let old_uri = old_uri.clone();
8849 let new_uri = new_uri.clone();
8850 let language_server = language_server.clone();
8851 async move |this, cx| {
8852 let edit = language_server
8853 .request::<WillRenameFiles>(RenameFilesParams {
8854 files: vec![FileRename { old_uri, new_uri }],
8855 })
8856 .await
8857 .into_response()
8858 .context("will rename files")
8859 .log_err()
8860 .flatten()?;
8861
8862 let transaction = LocalLspStore::deserialize_workspace_edit(
8863 this.upgrade()?,
8864 edit,
8865 false,
8866 language_server.clone(),
8867 cx,
8868 )
8869 .await
8870 .ok()?;
8871 Some(transaction)
8872 }
8873 });
8874 tasks.push(apply_edit);
8875 }
8876 }
8877 Some(())
8878 })
8879 .ok()
8880 .flatten();
8881 let mut merged_transaction = ProjectTransaction::default();
8882 for task in tasks {
8883 // Await on tasks sequentially so that the order of application of edits is deterministic
8884 // (at least with regards to the order of registration of language servers)
8885 if let Some(transaction) = task.await {
8886 for (buffer, buffer_transaction) in transaction.0 {
8887 merged_transaction.0.insert(buffer, buffer_transaction);
8888 }
8889 }
8890 }
8891 merged_transaction
8892 })
8893 }
8894
8895 fn lsp_notify_abs_paths_changed(
8896 &mut self,
8897 server_id: LanguageServerId,
8898 changes: Vec<PathEvent>,
8899 ) {
8900 maybe!({
8901 let server = self.language_server_for_id(server_id)?;
8902 let changes = changes
8903 .into_iter()
8904 .filter_map(|event| {
8905 let typ = match event.kind? {
8906 PathEventKind::Created => lsp::FileChangeType::CREATED,
8907 PathEventKind::Removed => lsp::FileChangeType::DELETED,
8908 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
8909 };
8910 Some(lsp::FileEvent {
8911 uri: file_path_to_lsp_url(&event.path).log_err()?,
8912 typ,
8913 })
8914 })
8915 .collect::<Vec<_>>();
8916 if !changes.is_empty() {
8917 server
8918 .notify::<lsp::notification::DidChangeWatchedFiles>(
8919 &lsp::DidChangeWatchedFilesParams { changes },
8920 )
8921 .ok();
8922 }
8923 Some(())
8924 });
8925 }
8926
8927 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
8928 self.as_local()?.language_server_for_id(id)
8929 }
8930
8931 fn on_lsp_progress(
8932 &mut self,
8933 progress: lsp::ProgressParams,
8934 language_server_id: LanguageServerId,
8935 disk_based_diagnostics_progress_token: Option<String>,
8936 cx: &mut Context<Self>,
8937 ) {
8938 let token = match progress.token {
8939 lsp::NumberOrString::String(token) => token,
8940 lsp::NumberOrString::Number(token) => {
8941 log::info!("skipping numeric progress token {}", token);
8942 return;
8943 }
8944 };
8945
8946 match progress.value {
8947 lsp::ProgressParamsValue::WorkDone(progress) => {
8948 self.handle_work_done_progress(
8949 progress,
8950 language_server_id,
8951 disk_based_diagnostics_progress_token,
8952 token,
8953 cx,
8954 );
8955 }
8956 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
8957 if let Some(LanguageServerState::Running {
8958 workspace_refresh_task: Some(workspace_refresh_task),
8959 ..
8960 }) = self
8961 .as_local_mut()
8962 .and_then(|local| local.language_servers.get_mut(&language_server_id))
8963 {
8964 workspace_refresh_task.progress_tx.try_send(()).ok();
8965 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
8966 }
8967 }
8968 }
8969 }
8970
8971 fn handle_work_done_progress(
8972 &mut self,
8973 progress: lsp::WorkDoneProgress,
8974 language_server_id: LanguageServerId,
8975 disk_based_diagnostics_progress_token: Option<String>,
8976 token: String,
8977 cx: &mut Context<Self>,
8978 ) {
8979 let language_server_status =
8980 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
8981 status
8982 } else {
8983 return;
8984 };
8985
8986 if !language_server_status.progress_tokens.contains(&token) {
8987 return;
8988 }
8989
8990 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
8991 .as_ref()
8992 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
8993
8994 match progress {
8995 lsp::WorkDoneProgress::Begin(report) => {
8996 if is_disk_based_diagnostics_progress {
8997 self.disk_based_diagnostics_started(language_server_id, cx);
8998 }
8999 self.on_lsp_work_start(
9000 language_server_id,
9001 token.clone(),
9002 LanguageServerProgress {
9003 title: Some(report.title),
9004 is_disk_based_diagnostics_progress,
9005 is_cancellable: report.cancellable.unwrap_or(false),
9006 message: report.message.clone(),
9007 percentage: report.percentage.map(|p| p as usize),
9008 last_update_at: cx.background_executor().now(),
9009 },
9010 cx,
9011 );
9012 }
9013 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9014 language_server_id,
9015 token,
9016 LanguageServerProgress {
9017 title: None,
9018 is_disk_based_diagnostics_progress,
9019 is_cancellable: report.cancellable.unwrap_or(false),
9020 message: report.message,
9021 percentage: report.percentage.map(|p| p as usize),
9022 last_update_at: cx.background_executor().now(),
9023 },
9024 cx,
9025 ),
9026 lsp::WorkDoneProgress::End(_) => {
9027 language_server_status.progress_tokens.remove(&token);
9028 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9029 if is_disk_based_diagnostics_progress {
9030 self.disk_based_diagnostics_finished(language_server_id, cx);
9031 }
9032 }
9033 }
9034 }
9035
9036 fn on_lsp_work_start(
9037 &mut self,
9038 language_server_id: LanguageServerId,
9039 token: String,
9040 progress: LanguageServerProgress,
9041 cx: &mut Context<Self>,
9042 ) {
9043 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9044 status.pending_work.insert(token.clone(), progress.clone());
9045 cx.notify();
9046 }
9047 cx.emit(LspStoreEvent::LanguageServerUpdate {
9048 language_server_id,
9049 name: self
9050 .language_server_adapter_for_id(language_server_id)
9051 .map(|adapter| adapter.name()),
9052 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9053 token,
9054 title: progress.title,
9055 message: progress.message,
9056 percentage: progress.percentage.map(|p| p as u32),
9057 is_cancellable: Some(progress.is_cancellable),
9058 }),
9059 })
9060 }
9061
9062 fn on_lsp_work_progress(
9063 &mut self,
9064 language_server_id: LanguageServerId,
9065 token: String,
9066 progress: LanguageServerProgress,
9067 cx: &mut Context<Self>,
9068 ) {
9069 let mut did_update = false;
9070 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9071 match status.pending_work.entry(token.clone()) {
9072 btree_map::Entry::Vacant(entry) => {
9073 entry.insert(progress.clone());
9074 did_update = true;
9075 }
9076 btree_map::Entry::Occupied(mut entry) => {
9077 let entry = entry.get_mut();
9078 if (progress.last_update_at - entry.last_update_at)
9079 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9080 {
9081 entry.last_update_at = progress.last_update_at;
9082 if progress.message.is_some() {
9083 entry.message = progress.message.clone();
9084 }
9085 if progress.percentage.is_some() {
9086 entry.percentage = progress.percentage;
9087 }
9088 if progress.is_cancellable != entry.is_cancellable {
9089 entry.is_cancellable = progress.is_cancellable;
9090 }
9091 did_update = true;
9092 }
9093 }
9094 }
9095 }
9096
9097 if did_update {
9098 cx.emit(LspStoreEvent::LanguageServerUpdate {
9099 language_server_id,
9100 name: self
9101 .language_server_adapter_for_id(language_server_id)
9102 .map(|adapter| adapter.name()),
9103 message: proto::update_language_server::Variant::WorkProgress(
9104 proto::LspWorkProgress {
9105 token,
9106 message: progress.message,
9107 percentage: progress.percentage.map(|p| p as u32),
9108 is_cancellable: Some(progress.is_cancellable),
9109 },
9110 ),
9111 })
9112 }
9113 }
9114
9115 fn on_lsp_work_end(
9116 &mut self,
9117 language_server_id: LanguageServerId,
9118 token: String,
9119 cx: &mut Context<Self>,
9120 ) {
9121 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9122 if let Some(work) = status.pending_work.remove(&token)
9123 && !work.is_disk_based_diagnostics_progress
9124 {
9125 cx.emit(LspStoreEvent::RefreshInlayHints);
9126 }
9127 cx.notify();
9128 }
9129
9130 cx.emit(LspStoreEvent::LanguageServerUpdate {
9131 language_server_id,
9132 name: self
9133 .language_server_adapter_for_id(language_server_id)
9134 .map(|adapter| adapter.name()),
9135 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9136 })
9137 }
9138
9139 pub async fn handle_resolve_completion_documentation(
9140 this: Entity<Self>,
9141 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9142 mut cx: AsyncApp,
9143 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9144 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9145
9146 let completion = this
9147 .read_with(&cx, |this, cx| {
9148 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9149 let server = this
9150 .language_server_for_id(id)
9151 .with_context(|| format!("No language server {id}"))?;
9152
9153 anyhow::Ok(cx.background_spawn(async move {
9154 let can_resolve = server
9155 .capabilities()
9156 .completion_provider
9157 .as_ref()
9158 .and_then(|options| options.resolve_provider)
9159 .unwrap_or(false);
9160 if can_resolve {
9161 server
9162 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9163 .await
9164 .into_response()
9165 .context("resolve completion item")
9166 } else {
9167 anyhow::Ok(lsp_completion)
9168 }
9169 }))
9170 })??
9171 .await?;
9172
9173 let mut documentation_is_markdown = false;
9174 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9175 let documentation = match completion.documentation {
9176 Some(lsp::Documentation::String(text)) => text,
9177
9178 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9179 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9180 value
9181 }
9182
9183 _ => String::new(),
9184 };
9185
9186 // If we have a new buffer_id, that means we're talking to a new client
9187 // and want to check for new text_edits in the completion too.
9188 let mut old_replace_start = None;
9189 let mut old_replace_end = None;
9190 let mut old_insert_start = None;
9191 let mut old_insert_end = None;
9192 let mut new_text = String::default();
9193 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9194 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9195 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9196 anyhow::Ok(buffer.read(cx).snapshot())
9197 })??;
9198
9199 if let Some(text_edit) = completion.text_edit.as_ref() {
9200 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9201
9202 if let Some(mut edit) = edit {
9203 LineEnding::normalize(&mut edit.new_text);
9204
9205 new_text = edit.new_text;
9206 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9207 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9208 if let Some(insert_range) = edit.insert_range {
9209 old_insert_start = Some(serialize_anchor(&insert_range.start));
9210 old_insert_end = Some(serialize_anchor(&insert_range.end));
9211 }
9212 }
9213 }
9214 }
9215
9216 Ok(proto::ResolveCompletionDocumentationResponse {
9217 documentation,
9218 documentation_is_markdown,
9219 old_replace_start,
9220 old_replace_end,
9221 new_text,
9222 lsp_completion,
9223 old_insert_start,
9224 old_insert_end,
9225 })
9226 }
9227
9228 async fn handle_on_type_formatting(
9229 this: Entity<Self>,
9230 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9231 mut cx: AsyncApp,
9232 ) -> Result<proto::OnTypeFormattingResponse> {
9233 let on_type_formatting = this.update(&mut cx, |this, cx| {
9234 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9235 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9236 let position = envelope
9237 .payload
9238 .position
9239 .and_then(deserialize_anchor)
9240 .context("invalid position")?;
9241 anyhow::Ok(this.apply_on_type_formatting(
9242 buffer,
9243 position,
9244 envelope.payload.trigger.clone(),
9245 cx,
9246 ))
9247 })??;
9248
9249 let transaction = on_type_formatting
9250 .await?
9251 .as_ref()
9252 .map(language::proto::serialize_transaction);
9253 Ok(proto::OnTypeFormattingResponse { transaction })
9254 }
9255
9256 async fn handle_refresh_inlay_hints(
9257 this: Entity<Self>,
9258 _: TypedEnvelope<proto::RefreshInlayHints>,
9259 mut cx: AsyncApp,
9260 ) -> Result<proto::Ack> {
9261 this.update(&mut cx, |_, cx| {
9262 cx.emit(LspStoreEvent::RefreshInlayHints);
9263 })?;
9264 Ok(proto::Ack {})
9265 }
9266
9267 async fn handle_pull_workspace_diagnostics(
9268 lsp_store: Entity<Self>,
9269 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9270 mut cx: AsyncApp,
9271 ) -> Result<proto::Ack> {
9272 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9273 lsp_store.update(&mut cx, |lsp_store, _| {
9274 lsp_store.pull_workspace_diagnostics(server_id);
9275 })?;
9276 Ok(proto::Ack {})
9277 }
9278
9279 async fn handle_inlay_hints(
9280 this: Entity<Self>,
9281 envelope: TypedEnvelope<proto::InlayHints>,
9282 mut cx: AsyncApp,
9283 ) -> Result<proto::InlayHintsResponse> {
9284 let sender_id = envelope.original_sender_id().unwrap_or_default();
9285 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9286 let buffer = this.update(&mut cx, |this, cx| {
9287 this.buffer_store.read(cx).get_existing(buffer_id)
9288 })??;
9289 buffer
9290 .update(&mut cx, |buffer, _| {
9291 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9292 })?
9293 .await
9294 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9295
9296 let start = envelope
9297 .payload
9298 .start
9299 .and_then(deserialize_anchor)
9300 .context("missing range start")?;
9301 let end = envelope
9302 .payload
9303 .end
9304 .and_then(deserialize_anchor)
9305 .context("missing range end")?;
9306 let buffer_hints = this
9307 .update(&mut cx, |lsp_store, cx| {
9308 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9309 })?
9310 .await
9311 .context("inlay hints fetch")?;
9312
9313 this.update(&mut cx, |project, cx| {
9314 InlayHints::response_to_proto(
9315 buffer_hints,
9316 project,
9317 sender_id,
9318 &buffer.read(cx).version(),
9319 cx,
9320 )
9321 })
9322 }
9323
9324 async fn handle_get_color_presentation(
9325 lsp_store: Entity<Self>,
9326 envelope: TypedEnvelope<proto::GetColorPresentation>,
9327 mut cx: AsyncApp,
9328 ) -> Result<proto::GetColorPresentationResponse> {
9329 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9330 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9331 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9332 })??;
9333
9334 let color = envelope
9335 .payload
9336 .color
9337 .context("invalid color resolve request")?;
9338 let start = color
9339 .lsp_range_start
9340 .context("invalid color resolve request")?;
9341 let end = color
9342 .lsp_range_end
9343 .context("invalid color resolve request")?;
9344
9345 let color = DocumentColor {
9346 lsp_range: lsp::Range {
9347 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9348 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9349 },
9350 color: lsp::Color {
9351 red: color.red,
9352 green: color.green,
9353 blue: color.blue,
9354 alpha: color.alpha,
9355 },
9356 resolved: false,
9357 color_presentations: Vec::new(),
9358 };
9359 let resolved_color = lsp_store
9360 .update(&mut cx, |lsp_store, cx| {
9361 lsp_store.resolve_color_presentation(
9362 color,
9363 buffer.clone(),
9364 LanguageServerId(envelope.payload.server_id as usize),
9365 cx,
9366 )
9367 })?
9368 .await
9369 .context("resolving color presentation")?;
9370
9371 Ok(proto::GetColorPresentationResponse {
9372 presentations: resolved_color
9373 .color_presentations
9374 .into_iter()
9375 .map(|presentation| proto::ColorPresentation {
9376 label: presentation.label.to_string(),
9377 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9378 additional_text_edits: presentation
9379 .additional_text_edits
9380 .into_iter()
9381 .map(serialize_lsp_edit)
9382 .collect(),
9383 })
9384 .collect(),
9385 })
9386 }
9387
9388 async fn handle_resolve_inlay_hint(
9389 this: Entity<Self>,
9390 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9391 mut cx: AsyncApp,
9392 ) -> Result<proto::ResolveInlayHintResponse> {
9393 let proto_hint = envelope
9394 .payload
9395 .hint
9396 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9397 let hint = InlayHints::proto_to_project_hint(proto_hint)
9398 .context("resolved proto inlay hint conversion")?;
9399 let buffer = this.update(&mut cx, |this, cx| {
9400 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9401 this.buffer_store.read(cx).get_existing(buffer_id)
9402 })??;
9403 let response_hint = this
9404 .update(&mut cx, |this, cx| {
9405 this.resolve_inlay_hint(
9406 hint,
9407 buffer,
9408 LanguageServerId(envelope.payload.language_server_id as usize),
9409 cx,
9410 )
9411 })?
9412 .await
9413 .context("inlay hints fetch")?;
9414 Ok(proto::ResolveInlayHintResponse {
9415 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9416 })
9417 }
9418
9419 async fn handle_refresh_code_lens(
9420 this: Entity<Self>,
9421 _: TypedEnvelope<proto::RefreshCodeLens>,
9422 mut cx: AsyncApp,
9423 ) -> Result<proto::Ack> {
9424 this.update(&mut cx, |_, cx| {
9425 cx.emit(LspStoreEvent::RefreshCodeLens);
9426 })?;
9427 Ok(proto::Ack {})
9428 }
9429
9430 async fn handle_open_buffer_for_symbol(
9431 this: Entity<Self>,
9432 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9433 mut cx: AsyncApp,
9434 ) -> Result<proto::OpenBufferForSymbolResponse> {
9435 let peer_id = envelope.original_sender_id().unwrap_or_default();
9436 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9437 let symbol = Self::deserialize_symbol(symbol)?;
9438 let symbol = this.read_with(&cx, |this, _| {
9439 let signature = this.symbol_signature(&symbol.path);
9440 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9441 Ok(symbol)
9442 })??;
9443 let buffer = this
9444 .update(&mut cx, |this, cx| {
9445 this.open_buffer_for_symbol(
9446 &Symbol {
9447 language_server_name: symbol.language_server_name,
9448 source_worktree_id: symbol.source_worktree_id,
9449 source_language_server_id: symbol.source_language_server_id,
9450 path: symbol.path,
9451 name: symbol.name,
9452 kind: symbol.kind,
9453 range: symbol.range,
9454 signature: symbol.signature,
9455 label: CodeLabel {
9456 text: Default::default(),
9457 runs: Default::default(),
9458 filter_range: Default::default(),
9459 },
9460 },
9461 cx,
9462 )
9463 })?
9464 .await?;
9465
9466 this.update(&mut cx, |this, cx| {
9467 let is_private = buffer
9468 .read(cx)
9469 .file()
9470 .map(|f| f.is_private())
9471 .unwrap_or_default();
9472 if is_private {
9473 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9474 } else {
9475 this.buffer_store
9476 .update(cx, |buffer_store, cx| {
9477 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9478 })
9479 .detach_and_log_err(cx);
9480 let buffer_id = buffer.read(cx).remote_id().to_proto();
9481 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9482 }
9483 })?
9484 }
9485
9486 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
9487 let mut hasher = Sha256::new();
9488 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
9489 hasher.update(project_path.path.to_string_lossy().as_bytes());
9490 hasher.update(self.nonce.to_be_bytes());
9491 hasher.finalize().as_slice().try_into().unwrap()
9492 }
9493
9494 pub async fn handle_get_project_symbols(
9495 this: Entity<Self>,
9496 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9497 mut cx: AsyncApp,
9498 ) -> Result<proto::GetProjectSymbolsResponse> {
9499 let symbols = this
9500 .update(&mut cx, |this, cx| {
9501 this.symbols(&envelope.payload.query, cx)
9502 })?
9503 .await?;
9504
9505 Ok(proto::GetProjectSymbolsResponse {
9506 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9507 })
9508 }
9509
9510 pub async fn handle_restart_language_servers(
9511 this: Entity<Self>,
9512 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9513 mut cx: AsyncApp,
9514 ) -> Result<proto::Ack> {
9515 this.update(&mut cx, |lsp_store, cx| {
9516 let buffers =
9517 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9518 lsp_store.restart_language_servers_for_buffers(
9519 buffers,
9520 envelope
9521 .payload
9522 .only_servers
9523 .into_iter()
9524 .filter_map(|selector| {
9525 Some(match selector.selector? {
9526 proto::language_server_selector::Selector::ServerId(server_id) => {
9527 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9528 }
9529 proto::language_server_selector::Selector::Name(name) => {
9530 LanguageServerSelector::Name(LanguageServerName(
9531 SharedString::from(name),
9532 ))
9533 }
9534 })
9535 })
9536 .collect(),
9537 cx,
9538 );
9539 })?;
9540
9541 Ok(proto::Ack {})
9542 }
9543
9544 pub async fn handle_stop_language_servers(
9545 lsp_store: Entity<Self>,
9546 envelope: TypedEnvelope<proto::StopLanguageServers>,
9547 mut cx: AsyncApp,
9548 ) -> Result<proto::Ack> {
9549 lsp_store.update(&mut cx, |lsp_store, cx| {
9550 if envelope.payload.all
9551 && envelope.payload.also_servers.is_empty()
9552 && envelope.payload.buffer_ids.is_empty()
9553 {
9554 lsp_store.stop_all_language_servers(cx);
9555 } else {
9556 let buffers =
9557 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9558 lsp_store
9559 .stop_language_servers_for_buffers(
9560 buffers,
9561 envelope
9562 .payload
9563 .also_servers
9564 .into_iter()
9565 .filter_map(|selector| {
9566 Some(match selector.selector? {
9567 proto::language_server_selector::Selector::ServerId(
9568 server_id,
9569 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9570 server_id,
9571 )),
9572 proto::language_server_selector::Selector::Name(name) => {
9573 LanguageServerSelector::Name(LanguageServerName(
9574 SharedString::from(name),
9575 ))
9576 }
9577 })
9578 })
9579 .collect(),
9580 cx,
9581 )
9582 .detach_and_log_err(cx);
9583 }
9584 })?;
9585
9586 Ok(proto::Ack {})
9587 }
9588
9589 pub async fn handle_cancel_language_server_work(
9590 this: Entity<Self>,
9591 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9592 mut cx: AsyncApp,
9593 ) -> Result<proto::Ack> {
9594 this.update(&mut cx, |this, cx| {
9595 if let Some(work) = envelope.payload.work {
9596 match work {
9597 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9598 let buffers =
9599 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9600 this.cancel_language_server_work_for_buffers(buffers, cx);
9601 }
9602 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9603 let server_id = LanguageServerId::from_proto(work.language_server_id);
9604 this.cancel_language_server_work(server_id, work.token, cx);
9605 }
9606 }
9607 }
9608 })?;
9609
9610 Ok(proto::Ack {})
9611 }
9612
9613 fn buffer_ids_to_buffers(
9614 &mut self,
9615 buffer_ids: impl Iterator<Item = u64>,
9616 cx: &mut Context<Self>,
9617 ) -> Vec<Entity<Buffer>> {
9618 buffer_ids
9619 .into_iter()
9620 .flat_map(|buffer_id| {
9621 self.buffer_store
9622 .read(cx)
9623 .get(BufferId::new(buffer_id).log_err()?)
9624 })
9625 .collect::<Vec<_>>()
9626 }
9627
9628 async fn handle_apply_additional_edits_for_completion(
9629 this: Entity<Self>,
9630 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9631 mut cx: AsyncApp,
9632 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9633 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9634 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9635 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9636 let completion = Self::deserialize_completion(
9637 envelope.payload.completion.context("invalid completion")?,
9638 )?;
9639 anyhow::Ok((buffer, completion))
9640 })??;
9641
9642 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9643 this.apply_additional_edits_for_completion(
9644 buffer,
9645 Rc::new(RefCell::new(Box::new([Completion {
9646 replace_range: completion.replace_range,
9647 new_text: completion.new_text,
9648 source: completion.source,
9649 documentation: None,
9650 label: CodeLabel {
9651 text: Default::default(),
9652 runs: Default::default(),
9653 filter_range: Default::default(),
9654 },
9655 insert_text_mode: None,
9656 icon_path: None,
9657 confirm: None,
9658 }]))),
9659 0,
9660 false,
9661 cx,
9662 )
9663 })?;
9664
9665 Ok(proto::ApplyCompletionAdditionalEditsResponse {
9666 transaction: apply_additional_edits
9667 .await?
9668 .as_ref()
9669 .map(language::proto::serialize_transaction),
9670 })
9671 }
9672
9673 pub fn last_formatting_failure(&self) -> Option<&str> {
9674 self.last_formatting_failure.as_deref()
9675 }
9676
9677 pub fn reset_last_formatting_failure(&mut self) {
9678 self.last_formatting_failure = None;
9679 }
9680
9681 pub fn environment_for_buffer(
9682 &self,
9683 buffer: &Entity<Buffer>,
9684 cx: &mut Context<Self>,
9685 ) -> Shared<Task<Option<HashMap<String, String>>>> {
9686 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
9687 environment.update(cx, |env, cx| {
9688 env.get_buffer_environment(buffer, &self.worktree_store, cx)
9689 })
9690 } else {
9691 Task::ready(None).shared()
9692 }
9693 }
9694
9695 pub fn format(
9696 &mut self,
9697 buffers: HashSet<Entity<Buffer>>,
9698 target: LspFormatTarget,
9699 push_to_history: bool,
9700 trigger: FormatTrigger,
9701 cx: &mut Context<Self>,
9702 ) -> Task<anyhow::Result<ProjectTransaction>> {
9703 let logger = zlog::scoped!("format");
9704 if self.as_local().is_some() {
9705 zlog::trace!(logger => "Formatting locally");
9706 let logger = zlog::scoped!(logger => "local");
9707 let buffers = buffers
9708 .into_iter()
9709 .map(|buffer_handle| {
9710 let buffer = buffer_handle.read(cx);
9711 let buffer_abs_path = File::from_dyn(buffer.file())
9712 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
9713
9714 (buffer_handle, buffer_abs_path, buffer.remote_id())
9715 })
9716 .collect::<Vec<_>>();
9717
9718 cx.spawn(async move |lsp_store, cx| {
9719 let mut formattable_buffers = Vec::with_capacity(buffers.len());
9720
9721 for (handle, abs_path, id) in buffers {
9722 let env = lsp_store
9723 .update(cx, |lsp_store, cx| {
9724 lsp_store.environment_for_buffer(&handle, cx)
9725 })?
9726 .await;
9727
9728 let ranges = match &target {
9729 LspFormatTarget::Buffers => None,
9730 LspFormatTarget::Ranges(ranges) => {
9731 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
9732 }
9733 };
9734
9735 formattable_buffers.push(FormattableBuffer {
9736 handle,
9737 abs_path,
9738 env,
9739 ranges,
9740 });
9741 }
9742 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
9743
9744 let format_timer = zlog::time!(logger => "Formatting buffers");
9745 let result = LocalLspStore::format_locally(
9746 lsp_store.clone(),
9747 formattable_buffers,
9748 push_to_history,
9749 trigger,
9750 logger,
9751 cx,
9752 )
9753 .await;
9754 format_timer.end();
9755
9756 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
9757
9758 lsp_store.update(cx, |lsp_store, _| {
9759 lsp_store.update_last_formatting_failure(&result);
9760 })?;
9761
9762 result
9763 })
9764 } else if let Some((client, project_id)) = self.upstream_client() {
9765 zlog::trace!(logger => "Formatting remotely");
9766 let logger = zlog::scoped!(logger => "remote");
9767 // Don't support formatting ranges via remote
9768 match target {
9769 LspFormatTarget::Buffers => {}
9770 LspFormatTarget::Ranges(_) => {
9771 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
9772 return Task::ready(Ok(ProjectTransaction::default()));
9773 }
9774 }
9775
9776 let buffer_store = self.buffer_store();
9777 cx.spawn(async move |lsp_store, cx| {
9778 zlog::trace!(logger => "Sending remote format request");
9779 let request_timer = zlog::time!(logger => "remote format request");
9780 let result = client
9781 .request(proto::FormatBuffers {
9782 project_id,
9783 trigger: trigger as i32,
9784 buffer_ids: buffers
9785 .iter()
9786 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
9787 .collect::<Result<_>>()?,
9788 })
9789 .await
9790 .and_then(|result| result.transaction.context("missing transaction"));
9791 request_timer.end();
9792
9793 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
9794
9795 lsp_store.update(cx, |lsp_store, _| {
9796 lsp_store.update_last_formatting_failure(&result);
9797 })?;
9798
9799 let transaction_response = result?;
9800 let _timer = zlog::time!(logger => "deserializing project transaction");
9801 buffer_store
9802 .update(cx, |buffer_store, cx| {
9803 buffer_store.deserialize_project_transaction(
9804 transaction_response,
9805 push_to_history,
9806 cx,
9807 )
9808 })?
9809 .await
9810 })
9811 } else {
9812 zlog::trace!(logger => "Not formatting");
9813 Task::ready(Ok(ProjectTransaction::default()))
9814 }
9815 }
9816
9817 async fn handle_format_buffers(
9818 this: Entity<Self>,
9819 envelope: TypedEnvelope<proto::FormatBuffers>,
9820 mut cx: AsyncApp,
9821 ) -> Result<proto::FormatBuffersResponse> {
9822 let sender_id = envelope.original_sender_id().unwrap_or_default();
9823 let format = this.update(&mut cx, |this, cx| {
9824 let mut buffers = HashSet::default();
9825 for buffer_id in &envelope.payload.buffer_ids {
9826 let buffer_id = BufferId::new(*buffer_id)?;
9827 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
9828 }
9829 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
9830 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
9831 })??;
9832
9833 let project_transaction = format.await?;
9834 let project_transaction = this.update(&mut cx, |this, cx| {
9835 this.buffer_store.update(cx, |buffer_store, cx| {
9836 buffer_store.serialize_project_transaction_for_peer(
9837 project_transaction,
9838 sender_id,
9839 cx,
9840 )
9841 })
9842 })?;
9843 Ok(proto::FormatBuffersResponse {
9844 transaction: Some(project_transaction),
9845 })
9846 }
9847
9848 async fn handle_apply_code_action_kind(
9849 this: Entity<Self>,
9850 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
9851 mut cx: AsyncApp,
9852 ) -> Result<proto::ApplyCodeActionKindResponse> {
9853 let sender_id = envelope.original_sender_id().unwrap_or_default();
9854 let format = this.update(&mut cx, |this, cx| {
9855 let mut buffers = HashSet::default();
9856 for buffer_id in &envelope.payload.buffer_ids {
9857 let buffer_id = BufferId::new(*buffer_id)?;
9858 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
9859 }
9860 let kind = match envelope.payload.kind.as_str() {
9861 "" => CodeActionKind::EMPTY,
9862 "quickfix" => CodeActionKind::QUICKFIX,
9863 "refactor" => CodeActionKind::REFACTOR,
9864 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
9865 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
9866 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
9867 "source" => CodeActionKind::SOURCE,
9868 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
9869 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
9870 _ => anyhow::bail!(
9871 "Invalid code action kind {}",
9872 envelope.payload.kind.as_str()
9873 ),
9874 };
9875 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
9876 })??;
9877
9878 let project_transaction = format.await?;
9879 let project_transaction = this.update(&mut cx, |this, cx| {
9880 this.buffer_store.update(cx, |buffer_store, cx| {
9881 buffer_store.serialize_project_transaction_for_peer(
9882 project_transaction,
9883 sender_id,
9884 cx,
9885 )
9886 })
9887 })?;
9888 Ok(proto::ApplyCodeActionKindResponse {
9889 transaction: Some(project_transaction),
9890 })
9891 }
9892
9893 async fn shutdown_language_server(
9894 server_state: Option<LanguageServerState>,
9895 name: LanguageServerName,
9896 cx: &mut AsyncApp,
9897 ) {
9898 let server = match server_state {
9899 Some(LanguageServerState::Starting { startup, .. }) => {
9900 let mut timer = cx
9901 .background_executor()
9902 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
9903 .fuse();
9904
9905 select! {
9906 server = startup.fuse() => server,
9907 () = timer => {
9908 log::info!("timeout waiting for language server {name} to finish launching before stopping");
9909 None
9910 },
9911 }
9912 }
9913
9914 Some(LanguageServerState::Running { server, .. }) => Some(server),
9915
9916 None => None,
9917 };
9918
9919 if let Some(server) = server
9920 && let Some(shutdown) = server.shutdown()
9921 {
9922 shutdown.await;
9923 }
9924 }
9925
9926 // Returns a list of all of the worktrees which no longer have a language server and the root path
9927 // for the stopped server
9928 fn stop_local_language_server(
9929 &mut self,
9930 server_id: LanguageServerId,
9931 cx: &mut Context<Self>,
9932 ) -> Task<()> {
9933 let local = match &mut self.mode {
9934 LspStoreMode::Local(local) => local,
9935 _ => {
9936 return Task::ready(());
9937 }
9938 };
9939
9940 // Remove this server ID from all entries in the given worktree.
9941 local
9942 .language_server_ids
9943 .retain(|_, state| state.id != server_id);
9944 self.buffer_store.update(cx, |buffer_store, cx| {
9945 for buffer in buffer_store.buffers() {
9946 buffer.update(cx, |buffer, cx| {
9947 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
9948 buffer.set_completion_triggers(server_id, Default::default(), cx);
9949 });
9950 }
9951 });
9952
9953 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
9954 summaries.retain(|path, summaries_by_server_id| {
9955 if summaries_by_server_id.remove(&server_id).is_some() {
9956 if let Some((client, project_id)) = self.downstream_client.clone() {
9957 client
9958 .send(proto::UpdateDiagnosticSummary {
9959 project_id,
9960 worktree_id: worktree_id.to_proto(),
9961 summary: Some(proto::DiagnosticSummary {
9962 path: path.as_ref().to_proto(),
9963 language_server_id: server_id.0 as u64,
9964 error_count: 0,
9965 warning_count: 0,
9966 }),
9967 more_summaries: Vec::new(),
9968 })
9969 .log_err();
9970 }
9971 !summaries_by_server_id.is_empty()
9972 } else {
9973 true
9974 }
9975 });
9976 }
9977
9978 let local = self.as_local_mut().unwrap();
9979 for diagnostics in local.diagnostics.values_mut() {
9980 diagnostics.retain(|_, diagnostics_by_server_id| {
9981 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
9982 diagnostics_by_server_id.remove(ix);
9983 !diagnostics_by_server_id.is_empty()
9984 } else {
9985 true
9986 }
9987 });
9988 }
9989 local.language_server_watched_paths.remove(&server_id);
9990
9991 let server_state = local.language_servers.remove(&server_id);
9992 self.cleanup_lsp_data(server_id);
9993 let name = self
9994 .language_server_statuses
9995 .remove(&server_id)
9996 .map(|status| status.name)
9997 .or_else(|| {
9998 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
9999 Some(adapter.name())
10000 } else {
10001 None
10002 }
10003 });
10004
10005 if let Some(name) = name {
10006 log::info!("stopping language server {name}");
10007 self.languages
10008 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10009 cx.notify();
10010
10011 return cx.spawn(async move |lsp_store, cx| {
10012 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10013 lsp_store
10014 .update(cx, |lsp_store, cx| {
10015 lsp_store
10016 .languages
10017 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10018 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10019 cx.notify();
10020 })
10021 .ok();
10022 });
10023 }
10024
10025 if server_state.is_some() {
10026 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10027 }
10028 Task::ready(())
10029 }
10030
10031 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10032 if let Some((client, project_id)) = self.upstream_client() {
10033 let request = client.request(proto::StopLanguageServers {
10034 project_id,
10035 buffer_ids: Vec::new(),
10036 also_servers: Vec::new(),
10037 all: true,
10038 });
10039 cx.background_spawn(request).detach_and_log_err(cx);
10040 } else {
10041 let Some(local) = self.as_local_mut() else {
10042 return;
10043 };
10044 let language_servers_to_stop = local
10045 .language_server_ids
10046 .values()
10047 .map(|state| state.id)
10048 .collect();
10049 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10050 let tasks = language_servers_to_stop
10051 .into_iter()
10052 .map(|server| self.stop_local_language_server(server, cx))
10053 .collect::<Vec<_>>();
10054 cx.background_spawn(async move {
10055 futures::future::join_all(tasks).await;
10056 })
10057 .detach();
10058 }
10059 }
10060
10061 pub fn restart_language_servers_for_buffers(
10062 &mut self,
10063 buffers: Vec<Entity<Buffer>>,
10064 only_restart_servers: HashSet<LanguageServerSelector>,
10065 cx: &mut Context<Self>,
10066 ) {
10067 if let Some((client, project_id)) = self.upstream_client() {
10068 let request = client.request(proto::RestartLanguageServers {
10069 project_id,
10070 buffer_ids: buffers
10071 .into_iter()
10072 .map(|b| b.read(cx).remote_id().to_proto())
10073 .collect(),
10074 only_servers: only_restart_servers
10075 .into_iter()
10076 .map(|selector| {
10077 let selector = match selector {
10078 LanguageServerSelector::Id(language_server_id) => {
10079 proto::language_server_selector::Selector::ServerId(
10080 language_server_id.to_proto(),
10081 )
10082 }
10083 LanguageServerSelector::Name(language_server_name) => {
10084 proto::language_server_selector::Selector::Name(
10085 language_server_name.to_string(),
10086 )
10087 }
10088 };
10089 proto::LanguageServerSelector {
10090 selector: Some(selector),
10091 }
10092 })
10093 .collect(),
10094 all: false,
10095 });
10096 cx.background_spawn(request).detach_and_log_err(cx);
10097 } else {
10098 let stop_task = if only_restart_servers.is_empty() {
10099 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10100 } else {
10101 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10102 };
10103 cx.spawn(async move |lsp_store, cx| {
10104 stop_task.await;
10105 lsp_store
10106 .update(cx, |lsp_store, cx| {
10107 for buffer in buffers {
10108 lsp_store.register_buffer_with_language_servers(
10109 &buffer,
10110 only_restart_servers.clone(),
10111 true,
10112 cx,
10113 );
10114 }
10115 })
10116 .ok()
10117 })
10118 .detach();
10119 }
10120 }
10121
10122 pub fn stop_language_servers_for_buffers(
10123 &mut self,
10124 buffers: Vec<Entity<Buffer>>,
10125 also_stop_servers: HashSet<LanguageServerSelector>,
10126 cx: &mut Context<Self>,
10127 ) -> Task<Result<()>> {
10128 if let Some((client, project_id)) = self.upstream_client() {
10129 let request = client.request(proto::StopLanguageServers {
10130 project_id,
10131 buffer_ids: buffers
10132 .into_iter()
10133 .map(|b| b.read(cx).remote_id().to_proto())
10134 .collect(),
10135 also_servers: also_stop_servers
10136 .into_iter()
10137 .map(|selector| {
10138 let selector = match selector {
10139 LanguageServerSelector::Id(language_server_id) => {
10140 proto::language_server_selector::Selector::ServerId(
10141 language_server_id.to_proto(),
10142 )
10143 }
10144 LanguageServerSelector::Name(language_server_name) => {
10145 proto::language_server_selector::Selector::Name(
10146 language_server_name.to_string(),
10147 )
10148 }
10149 };
10150 proto::LanguageServerSelector {
10151 selector: Some(selector),
10152 }
10153 })
10154 .collect(),
10155 all: false,
10156 });
10157 cx.background_spawn(async move {
10158 let _ = request.await?;
10159 Ok(())
10160 })
10161 } else {
10162 let task =
10163 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10164 cx.background_spawn(async move {
10165 task.await;
10166 Ok(())
10167 })
10168 }
10169 }
10170
10171 fn stop_local_language_servers_for_buffers(
10172 &mut self,
10173 buffers: &[Entity<Buffer>],
10174 also_stop_servers: HashSet<LanguageServerSelector>,
10175 cx: &mut Context<Self>,
10176 ) -> Task<()> {
10177 let Some(local) = self.as_local_mut() else {
10178 return Task::ready(());
10179 };
10180 let mut language_server_names_to_stop = BTreeSet::default();
10181 let mut language_servers_to_stop = also_stop_servers
10182 .into_iter()
10183 .flat_map(|selector| match selector {
10184 LanguageServerSelector::Id(id) => Some(id),
10185 LanguageServerSelector::Name(name) => {
10186 language_server_names_to_stop.insert(name);
10187 None
10188 }
10189 })
10190 .collect::<BTreeSet<_>>();
10191
10192 let mut covered_worktrees = HashSet::default();
10193 for buffer in buffers {
10194 buffer.update(cx, |buffer, cx| {
10195 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10196 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10197 && covered_worktrees.insert(worktree_id)
10198 {
10199 language_server_names_to_stop.retain(|name| {
10200 let old_ids_count = language_servers_to_stop.len();
10201 let all_language_servers_with_this_name = local
10202 .language_server_ids
10203 .iter()
10204 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10205 language_servers_to_stop.extend(all_language_servers_with_this_name);
10206 old_ids_count == language_servers_to_stop.len()
10207 });
10208 }
10209 });
10210 }
10211 for name in language_server_names_to_stop {
10212 language_servers_to_stop.extend(
10213 local
10214 .language_server_ids
10215 .iter()
10216 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10217 );
10218 }
10219
10220 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10221 let tasks = language_servers_to_stop
10222 .into_iter()
10223 .map(|server| self.stop_local_language_server(server, cx))
10224 .collect::<Vec<_>>();
10225
10226 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10227 }
10228
10229 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10230 let (worktree, relative_path) =
10231 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10232
10233 let project_path = ProjectPath {
10234 worktree_id: worktree.read(cx).id(),
10235 path: relative_path.into(),
10236 };
10237
10238 Some(
10239 self.buffer_store()
10240 .read(cx)
10241 .get_by_path(&project_path)?
10242 .read(cx),
10243 )
10244 }
10245
10246 #[cfg(any(test, feature = "test-support"))]
10247 pub fn update_diagnostics(
10248 &mut self,
10249 server_id: LanguageServerId,
10250 diagnostics: lsp::PublishDiagnosticsParams,
10251 result_id: Option<String>,
10252 source_kind: DiagnosticSourceKind,
10253 disk_based_sources: &[String],
10254 cx: &mut Context<Self>,
10255 ) -> Result<()> {
10256 self.merge_lsp_diagnostics(
10257 source_kind,
10258 vec![DocumentDiagnosticsUpdate {
10259 diagnostics,
10260 result_id,
10261 server_id,
10262 disk_based_sources: Cow::Borrowed(disk_based_sources),
10263 }],
10264 |_, _, _| false,
10265 cx,
10266 )
10267 }
10268
10269 pub fn merge_lsp_diagnostics(
10270 &mut self,
10271 source_kind: DiagnosticSourceKind,
10272 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10273 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10274 cx: &mut Context<Self>,
10275 ) -> Result<()> {
10276 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10277 let updates = lsp_diagnostics
10278 .into_iter()
10279 .filter_map(|update| {
10280 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10281 Some(DocumentDiagnosticsUpdate {
10282 diagnostics: self.lsp_to_document_diagnostics(
10283 abs_path,
10284 source_kind,
10285 update.server_id,
10286 update.diagnostics,
10287 &update.disk_based_sources,
10288 ),
10289 result_id: update.result_id,
10290 server_id: update.server_id,
10291 disk_based_sources: update.disk_based_sources,
10292 })
10293 })
10294 .collect();
10295 self.merge_diagnostic_entries(updates, merge, cx)?;
10296 Ok(())
10297 }
10298
10299 fn lsp_to_document_diagnostics(
10300 &mut self,
10301 document_abs_path: PathBuf,
10302 source_kind: DiagnosticSourceKind,
10303 server_id: LanguageServerId,
10304 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10305 disk_based_sources: &[String],
10306 ) -> DocumentDiagnostics {
10307 let mut diagnostics = Vec::default();
10308 let mut primary_diagnostic_group_ids = HashMap::default();
10309 let mut sources_by_group_id = HashMap::default();
10310 let mut supporting_diagnostics = HashMap::default();
10311
10312 let adapter = self.language_server_adapter_for_id(server_id);
10313
10314 // Ensure that primary diagnostics are always the most severe
10315 lsp_diagnostics
10316 .diagnostics
10317 .sort_by_key(|item| item.severity);
10318
10319 for diagnostic in &lsp_diagnostics.diagnostics {
10320 let source = diagnostic.source.as_ref();
10321 let range = range_from_lsp(diagnostic.range);
10322 let is_supporting = diagnostic
10323 .related_information
10324 .as_ref()
10325 .is_some_and(|infos| {
10326 infos.iter().any(|info| {
10327 primary_diagnostic_group_ids.contains_key(&(
10328 source,
10329 diagnostic.code.clone(),
10330 range_from_lsp(info.location.range),
10331 ))
10332 })
10333 });
10334
10335 let is_unnecessary = diagnostic
10336 .tags
10337 .as_ref()
10338 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10339
10340 let underline = self
10341 .language_server_adapter_for_id(server_id)
10342 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10343
10344 if is_supporting {
10345 supporting_diagnostics.insert(
10346 (source, diagnostic.code.clone(), range),
10347 (diagnostic.severity, is_unnecessary),
10348 );
10349 } else {
10350 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10351 let is_disk_based =
10352 source.is_some_and(|source| disk_based_sources.contains(source));
10353
10354 sources_by_group_id.insert(group_id, source);
10355 primary_diagnostic_group_ids
10356 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10357
10358 diagnostics.push(DiagnosticEntry {
10359 range,
10360 diagnostic: Diagnostic {
10361 source: diagnostic.source.clone(),
10362 source_kind,
10363 code: diagnostic.code.clone(),
10364 code_description: diagnostic
10365 .code_description
10366 .as_ref()
10367 .and_then(|d| d.href.clone()),
10368 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10369 markdown: adapter.as_ref().and_then(|adapter| {
10370 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10371 }),
10372 message: diagnostic.message.trim().to_string(),
10373 group_id,
10374 is_primary: true,
10375 is_disk_based,
10376 is_unnecessary,
10377 underline,
10378 data: diagnostic.data.clone(),
10379 },
10380 });
10381 if let Some(infos) = &diagnostic.related_information {
10382 for info in infos {
10383 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10384 let range = range_from_lsp(info.location.range);
10385 diagnostics.push(DiagnosticEntry {
10386 range,
10387 diagnostic: Diagnostic {
10388 source: diagnostic.source.clone(),
10389 source_kind,
10390 code: diagnostic.code.clone(),
10391 code_description: diagnostic
10392 .code_description
10393 .as_ref()
10394 .and_then(|d| d.href.clone()),
10395 severity: DiagnosticSeverity::INFORMATION,
10396 markdown: adapter.as_ref().and_then(|adapter| {
10397 adapter.diagnostic_message_to_markdown(&info.message)
10398 }),
10399 message: info.message.trim().to_string(),
10400 group_id,
10401 is_primary: false,
10402 is_disk_based,
10403 is_unnecessary: false,
10404 underline,
10405 data: diagnostic.data.clone(),
10406 },
10407 });
10408 }
10409 }
10410 }
10411 }
10412 }
10413
10414 for entry in &mut diagnostics {
10415 let diagnostic = &mut entry.diagnostic;
10416 if !diagnostic.is_primary {
10417 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10418 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10419 source,
10420 diagnostic.code.clone(),
10421 entry.range.clone(),
10422 )) {
10423 if let Some(severity) = severity {
10424 diagnostic.severity = severity;
10425 }
10426 diagnostic.is_unnecessary = is_unnecessary;
10427 }
10428 }
10429 }
10430
10431 DocumentDiagnostics {
10432 diagnostics,
10433 document_abs_path,
10434 version: lsp_diagnostics.version,
10435 }
10436 }
10437
10438 fn insert_newly_running_language_server(
10439 &mut self,
10440 adapter: Arc<CachedLspAdapter>,
10441 language_server: Arc<LanguageServer>,
10442 server_id: LanguageServerId,
10443 key: LanguageServerSeed,
10444 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10445 cx: &mut Context<Self>,
10446 ) {
10447 let Some(local) = self.as_local_mut() else {
10448 return;
10449 };
10450 // If the language server for this key doesn't match the server id, don't store the
10451 // server. Which will cause it to be dropped, killing the process
10452 if local
10453 .language_server_ids
10454 .get(&key)
10455 .map(|state| state.id != server_id)
10456 .unwrap_or(false)
10457 {
10458 return;
10459 }
10460
10461 // Update language_servers collection with Running variant of LanguageServerState
10462 // indicating that the server is up and running and ready
10463 let workspace_folders = workspace_folders.lock().clone();
10464 language_server.set_workspace_folders(workspace_folders);
10465
10466 local.language_servers.insert(
10467 server_id,
10468 LanguageServerState::Running {
10469 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10470 language_server.clone(),
10471 cx,
10472 ),
10473 adapter: adapter.clone(),
10474 server: language_server.clone(),
10475 simulate_disk_based_diagnostics_completion: None,
10476 },
10477 );
10478 local
10479 .languages
10480 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10481 if let Some(file_ops_caps) = language_server
10482 .capabilities()
10483 .workspace
10484 .as_ref()
10485 .and_then(|ws| ws.file_operations.as_ref())
10486 {
10487 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10488 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10489 if did_rename_caps.or(will_rename_caps).is_some() {
10490 let watcher = RenamePathsWatchedForServer::default()
10491 .with_did_rename_patterns(did_rename_caps)
10492 .with_will_rename_patterns(will_rename_caps);
10493 local
10494 .language_server_paths_watched_for_rename
10495 .insert(server_id, watcher);
10496 }
10497 }
10498
10499 self.language_server_statuses.insert(
10500 server_id,
10501 LanguageServerStatus {
10502 name: language_server.name(),
10503 pending_work: Default::default(),
10504 has_pending_diagnostic_updates: false,
10505 progress_tokens: Default::default(),
10506 worktree: Some(key.worktree_id),
10507 },
10508 );
10509
10510 cx.emit(LspStoreEvent::LanguageServerAdded(
10511 server_id,
10512 language_server.name(),
10513 Some(key.worktree_id),
10514 ));
10515 cx.emit(LspStoreEvent::RefreshInlayHints);
10516
10517 let server_capabilities = language_server.capabilities();
10518 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10519 downstream_client
10520 .send(proto::StartLanguageServer {
10521 project_id: *project_id,
10522 server: Some(proto::LanguageServer {
10523 id: server_id.to_proto(),
10524 name: language_server.name().to_string(),
10525 worktree_id: Some(key.worktree_id.to_proto()),
10526 }),
10527 capabilities: serde_json::to_string(&server_capabilities)
10528 .expect("serializing server LSP capabilities"),
10529 })
10530 .log_err();
10531 }
10532 self.lsp_server_capabilities
10533 .insert(server_id, server_capabilities);
10534
10535 // Tell the language server about every open buffer in the worktree that matches the language.
10536 // Also check for buffers in worktrees that reused this server
10537 let mut worktrees_using_server = vec![key.worktree_id];
10538 if let Some(local) = self.as_local() {
10539 // Find all worktrees that have this server in their language server tree
10540 for (worktree_id, servers) in &local.lsp_tree.instances {
10541 if *worktree_id != key.worktree_id {
10542 for server_map in servers.roots.values() {
10543 if server_map.contains_key(&key.name) {
10544 worktrees_using_server.push(*worktree_id);
10545 }
10546 }
10547 }
10548 }
10549 }
10550
10551 let mut buffer_paths_registered = Vec::new();
10552 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10553 for buffer_handle in buffer_store.buffers() {
10554 let buffer = buffer_handle.read(cx);
10555 let file = match File::from_dyn(buffer.file()) {
10556 Some(file) => file,
10557 None => continue,
10558 };
10559 let language = match buffer.language() {
10560 Some(language) => language,
10561 None => continue,
10562 };
10563
10564 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10565 || !self
10566 .languages
10567 .lsp_adapters(&language.name())
10568 .iter()
10569 .any(|a| a.name == key.name)
10570 {
10571 continue;
10572 }
10573 // didOpen
10574 let file = match file.as_local() {
10575 Some(file) => file,
10576 None => continue,
10577 };
10578
10579 let local = self.as_local_mut().unwrap();
10580
10581 let buffer_id = buffer.remote_id();
10582 if local.registered_buffers.contains_key(&buffer_id) {
10583 let versions = local
10584 .buffer_snapshots
10585 .entry(buffer_id)
10586 .or_default()
10587 .entry(server_id)
10588 .and_modify(|_| {
10589 assert!(
10590 false,
10591 "There should not be an existing snapshot for a newly inserted buffer"
10592 )
10593 })
10594 .or_insert_with(|| {
10595 vec![LspBufferSnapshot {
10596 version: 0,
10597 snapshot: buffer.text_snapshot(),
10598 }]
10599 });
10600
10601 let snapshot = versions.last().unwrap();
10602 let version = snapshot.version;
10603 let initial_snapshot = &snapshot.snapshot;
10604 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
10605 language_server.register_buffer(
10606 uri,
10607 adapter.language_id(&language.name()),
10608 version,
10609 initial_snapshot.text(),
10610 );
10611 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10612 local
10613 .buffers_opened_in_servers
10614 .entry(buffer_id)
10615 .or_default()
10616 .insert(server_id);
10617 }
10618 buffer_handle.update(cx, |buffer, cx| {
10619 buffer.set_completion_triggers(
10620 server_id,
10621 language_server
10622 .capabilities()
10623 .completion_provider
10624 .as_ref()
10625 .and_then(|provider| {
10626 provider
10627 .trigger_characters
10628 .as_ref()
10629 .map(|characters| characters.iter().cloned().collect())
10630 })
10631 .unwrap_or_default(),
10632 cx,
10633 )
10634 });
10635 }
10636 });
10637
10638 for (buffer_id, abs_path) in buffer_paths_registered {
10639 cx.emit(LspStoreEvent::LanguageServerUpdate {
10640 language_server_id: server_id,
10641 name: Some(adapter.name()),
10642 message: proto::update_language_server::Variant::RegisteredForBuffer(
10643 proto::RegisteredForBuffer {
10644 buffer_abs_path: abs_path.to_string_lossy().to_string(),
10645 buffer_id: buffer_id.to_proto(),
10646 },
10647 ),
10648 });
10649 }
10650
10651 cx.notify();
10652 }
10653
10654 pub fn language_servers_running_disk_based_diagnostics(
10655 &self,
10656 ) -> impl Iterator<Item = LanguageServerId> + '_ {
10657 self.language_server_statuses
10658 .iter()
10659 .filter_map(|(id, status)| {
10660 if status.has_pending_diagnostic_updates {
10661 Some(*id)
10662 } else {
10663 None
10664 }
10665 })
10666 }
10667
10668 pub(crate) fn cancel_language_server_work_for_buffers(
10669 &mut self,
10670 buffers: impl IntoIterator<Item = Entity<Buffer>>,
10671 cx: &mut Context<Self>,
10672 ) {
10673 if let Some((client, project_id)) = self.upstream_client() {
10674 let request = client.request(proto::CancelLanguageServerWork {
10675 project_id,
10676 work: Some(proto::cancel_language_server_work::Work::Buffers(
10677 proto::cancel_language_server_work::Buffers {
10678 buffer_ids: buffers
10679 .into_iter()
10680 .map(|b| b.read(cx).remote_id().to_proto())
10681 .collect(),
10682 },
10683 )),
10684 });
10685 cx.background_spawn(request).detach_and_log_err(cx);
10686 } else if let Some(local) = self.as_local() {
10687 let servers = buffers
10688 .into_iter()
10689 .flat_map(|buffer| {
10690 buffer.update(cx, |buffer, cx| {
10691 local.language_server_ids_for_buffer(buffer, cx).into_iter()
10692 })
10693 })
10694 .collect::<HashSet<_>>();
10695 for server_id in servers {
10696 self.cancel_language_server_work(server_id, None, cx);
10697 }
10698 }
10699 }
10700
10701 pub(crate) fn cancel_language_server_work(
10702 &mut self,
10703 server_id: LanguageServerId,
10704 token_to_cancel: Option<String>,
10705 cx: &mut Context<Self>,
10706 ) {
10707 if let Some(local) = self.as_local() {
10708 let status = self.language_server_statuses.get(&server_id);
10709 let server = local.language_servers.get(&server_id);
10710 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
10711 {
10712 for (token, progress) in &status.pending_work {
10713 if let Some(token_to_cancel) = token_to_cancel.as_ref()
10714 && token != token_to_cancel
10715 {
10716 continue;
10717 }
10718 if progress.is_cancellable {
10719 server
10720 .notify::<lsp::notification::WorkDoneProgressCancel>(
10721 &WorkDoneProgressCancelParams {
10722 token: lsp::NumberOrString::String(token.clone()),
10723 },
10724 )
10725 .ok();
10726 }
10727 }
10728 }
10729 } else if let Some((client, project_id)) = self.upstream_client() {
10730 let request = client.request(proto::CancelLanguageServerWork {
10731 project_id,
10732 work: Some(
10733 proto::cancel_language_server_work::Work::LanguageServerWork(
10734 proto::cancel_language_server_work::LanguageServerWork {
10735 language_server_id: server_id.to_proto(),
10736 token: token_to_cancel,
10737 },
10738 ),
10739 ),
10740 });
10741 cx.background_spawn(request).detach_and_log_err(cx);
10742 }
10743 }
10744
10745 fn register_supplementary_language_server(
10746 &mut self,
10747 id: LanguageServerId,
10748 name: LanguageServerName,
10749 server: Arc<LanguageServer>,
10750 cx: &mut Context<Self>,
10751 ) {
10752 if let Some(local) = self.as_local_mut() {
10753 local
10754 .supplementary_language_servers
10755 .insert(id, (name.clone(), server));
10756 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
10757 }
10758 }
10759
10760 fn unregister_supplementary_language_server(
10761 &mut self,
10762 id: LanguageServerId,
10763 cx: &mut Context<Self>,
10764 ) {
10765 if let Some(local) = self.as_local_mut() {
10766 local.supplementary_language_servers.remove(&id);
10767 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
10768 }
10769 }
10770
10771 pub(crate) fn supplementary_language_servers(
10772 &self,
10773 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
10774 self.as_local().into_iter().flat_map(|local| {
10775 local
10776 .supplementary_language_servers
10777 .iter()
10778 .map(|(id, (name, _))| (*id, name.clone()))
10779 })
10780 }
10781
10782 pub fn language_server_adapter_for_id(
10783 &self,
10784 id: LanguageServerId,
10785 ) -> Option<Arc<CachedLspAdapter>> {
10786 self.as_local()
10787 .and_then(|local| local.language_servers.get(&id))
10788 .and_then(|language_server_state| match language_server_state {
10789 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
10790 _ => None,
10791 })
10792 }
10793
10794 pub(super) fn update_local_worktree_language_servers(
10795 &mut self,
10796 worktree_handle: &Entity<Worktree>,
10797 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
10798 cx: &mut Context<Self>,
10799 ) {
10800 if changes.is_empty() {
10801 return;
10802 }
10803
10804 let Some(local) = self.as_local() else { return };
10805
10806 local.prettier_store.update(cx, |prettier_store, cx| {
10807 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
10808 });
10809
10810 let worktree_id = worktree_handle.read(cx).id();
10811 let mut language_server_ids = local
10812 .language_server_ids
10813 .iter()
10814 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
10815 .collect::<Vec<_>>();
10816 language_server_ids.sort();
10817 language_server_ids.dedup();
10818
10819 let abs_path = worktree_handle.read(cx).abs_path();
10820 for server_id in &language_server_ids {
10821 if let Some(LanguageServerState::Running { server, .. }) =
10822 local.language_servers.get(server_id)
10823 && let Some(watched_paths) = local
10824 .language_server_watched_paths
10825 .get(server_id)
10826 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
10827 {
10828 let params = lsp::DidChangeWatchedFilesParams {
10829 changes: changes
10830 .iter()
10831 .filter_map(|(path, _, change)| {
10832 if !watched_paths.is_match(path) {
10833 return None;
10834 }
10835 let typ = match change {
10836 PathChange::Loaded => return None,
10837 PathChange::Added => lsp::FileChangeType::CREATED,
10838 PathChange::Removed => lsp::FileChangeType::DELETED,
10839 PathChange::Updated => lsp::FileChangeType::CHANGED,
10840 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
10841 };
10842 Some(lsp::FileEvent {
10843 uri: lsp::Uri::from_file_path(abs_path.join(path)).unwrap(),
10844 typ,
10845 })
10846 })
10847 .collect(),
10848 };
10849 if !params.changes.is_empty() {
10850 server
10851 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
10852 .ok();
10853 }
10854 }
10855 }
10856 for (path, _, _) in changes {
10857 if let Some(file_name) = path.file_name().and_then(|file_name| file_name.to_str())
10858 && local.watched_manifest_filenames.contains(file_name)
10859 {
10860 self.request_workspace_config_refresh();
10861 break;
10862 }
10863 }
10864 }
10865
10866 pub fn wait_for_remote_buffer(
10867 &mut self,
10868 id: BufferId,
10869 cx: &mut Context<Self>,
10870 ) -> Task<Result<Entity<Buffer>>> {
10871 self.buffer_store.update(cx, |buffer_store, cx| {
10872 buffer_store.wait_for_remote_buffer(id, cx)
10873 })
10874 }
10875
10876 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
10877 proto::Symbol {
10878 language_server_name: symbol.language_server_name.0.to_string(),
10879 source_worktree_id: symbol.source_worktree_id.to_proto(),
10880 language_server_id: symbol.source_language_server_id.to_proto(),
10881 worktree_id: symbol.path.worktree_id.to_proto(),
10882 path: symbol.path.path.as_ref().to_proto(),
10883 name: symbol.name.clone(),
10884 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
10885 start: Some(proto::PointUtf16 {
10886 row: symbol.range.start.0.row,
10887 column: symbol.range.start.0.column,
10888 }),
10889 end: Some(proto::PointUtf16 {
10890 row: symbol.range.end.0.row,
10891 column: symbol.range.end.0.column,
10892 }),
10893 signature: symbol.signature.to_vec(),
10894 }
10895 }
10896
10897 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
10898 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
10899 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
10900 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
10901 let path = ProjectPath {
10902 worktree_id,
10903 path: Arc::<Path>::from_proto(serialized_symbol.path),
10904 };
10905
10906 let start = serialized_symbol.start.context("invalid start")?;
10907 let end = serialized_symbol.end.context("invalid end")?;
10908 Ok(CoreSymbol {
10909 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
10910 source_worktree_id,
10911 source_language_server_id: LanguageServerId::from_proto(
10912 serialized_symbol.language_server_id,
10913 ),
10914 path,
10915 name: serialized_symbol.name,
10916 range: Unclipped(PointUtf16::new(start.row, start.column))
10917 ..Unclipped(PointUtf16::new(end.row, end.column)),
10918 kind,
10919 signature: serialized_symbol
10920 .signature
10921 .try_into()
10922 .map_err(|_| anyhow!("invalid signature"))?,
10923 })
10924 }
10925
10926 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
10927 let mut serialized_completion = proto::Completion {
10928 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
10929 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
10930 new_text: completion.new_text.clone(),
10931 ..proto::Completion::default()
10932 };
10933 match &completion.source {
10934 CompletionSource::Lsp {
10935 insert_range,
10936 server_id,
10937 lsp_completion,
10938 lsp_defaults,
10939 resolved,
10940 } => {
10941 let (old_insert_start, old_insert_end) = insert_range
10942 .as_ref()
10943 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
10944 .unzip();
10945
10946 serialized_completion.old_insert_start = old_insert_start;
10947 serialized_completion.old_insert_end = old_insert_end;
10948 serialized_completion.source = proto::completion::Source::Lsp as i32;
10949 serialized_completion.server_id = server_id.0 as u64;
10950 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
10951 serialized_completion.lsp_defaults = lsp_defaults
10952 .as_deref()
10953 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
10954 serialized_completion.resolved = *resolved;
10955 }
10956 CompletionSource::BufferWord {
10957 word_range,
10958 resolved,
10959 } => {
10960 serialized_completion.source = proto::completion::Source::BufferWord as i32;
10961 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
10962 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
10963 serialized_completion.resolved = *resolved;
10964 }
10965 CompletionSource::Custom => {
10966 serialized_completion.source = proto::completion::Source::Custom as i32;
10967 serialized_completion.resolved = true;
10968 }
10969 CompletionSource::Dap { sort_text } => {
10970 serialized_completion.source = proto::completion::Source::Dap as i32;
10971 serialized_completion.sort_text = Some(sort_text.clone());
10972 }
10973 }
10974
10975 serialized_completion
10976 }
10977
10978 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
10979 let old_replace_start = completion
10980 .old_replace_start
10981 .and_then(deserialize_anchor)
10982 .context("invalid old start")?;
10983 let old_replace_end = completion
10984 .old_replace_end
10985 .and_then(deserialize_anchor)
10986 .context("invalid old end")?;
10987 let insert_range = {
10988 match completion.old_insert_start.zip(completion.old_insert_end) {
10989 Some((start, end)) => {
10990 let start = deserialize_anchor(start).context("invalid insert old start")?;
10991 let end = deserialize_anchor(end).context("invalid insert old end")?;
10992 Some(start..end)
10993 }
10994 None => None,
10995 }
10996 };
10997 Ok(CoreCompletion {
10998 replace_range: old_replace_start..old_replace_end,
10999 new_text: completion.new_text,
11000 source: match proto::completion::Source::from_i32(completion.source) {
11001 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11002 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11003 insert_range,
11004 server_id: LanguageServerId::from_proto(completion.server_id),
11005 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11006 lsp_defaults: completion
11007 .lsp_defaults
11008 .as_deref()
11009 .map(serde_json::from_slice)
11010 .transpose()?,
11011 resolved: completion.resolved,
11012 },
11013 Some(proto::completion::Source::BufferWord) => {
11014 let word_range = completion
11015 .buffer_word_start
11016 .and_then(deserialize_anchor)
11017 .context("invalid buffer word start")?
11018 ..completion
11019 .buffer_word_end
11020 .and_then(deserialize_anchor)
11021 .context("invalid buffer word end")?;
11022 CompletionSource::BufferWord {
11023 word_range,
11024 resolved: completion.resolved,
11025 }
11026 }
11027 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11028 sort_text: completion
11029 .sort_text
11030 .context("expected sort text to exist")?,
11031 },
11032 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11033 },
11034 })
11035 }
11036
11037 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11038 let (kind, lsp_action) = match &action.lsp_action {
11039 LspAction::Action(code_action) => (
11040 proto::code_action::Kind::Action as i32,
11041 serde_json::to_vec(code_action).unwrap(),
11042 ),
11043 LspAction::Command(command) => (
11044 proto::code_action::Kind::Command as i32,
11045 serde_json::to_vec(command).unwrap(),
11046 ),
11047 LspAction::CodeLens(code_lens) => (
11048 proto::code_action::Kind::CodeLens as i32,
11049 serde_json::to_vec(code_lens).unwrap(),
11050 ),
11051 };
11052
11053 proto::CodeAction {
11054 server_id: action.server_id.0 as u64,
11055 start: Some(serialize_anchor(&action.range.start)),
11056 end: Some(serialize_anchor(&action.range.end)),
11057 lsp_action,
11058 kind,
11059 resolved: action.resolved,
11060 }
11061 }
11062
11063 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11064 let start = action
11065 .start
11066 .and_then(deserialize_anchor)
11067 .context("invalid start")?;
11068 let end = action
11069 .end
11070 .and_then(deserialize_anchor)
11071 .context("invalid end")?;
11072 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11073 Some(proto::code_action::Kind::Action) => {
11074 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11075 }
11076 Some(proto::code_action::Kind::Command) => {
11077 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11078 }
11079 Some(proto::code_action::Kind::CodeLens) => {
11080 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11081 }
11082 None => anyhow::bail!("Unknown action kind {}", action.kind),
11083 };
11084 Ok(CodeAction {
11085 server_id: LanguageServerId(action.server_id as usize),
11086 range: start..end,
11087 resolved: action.resolved,
11088 lsp_action,
11089 })
11090 }
11091
11092 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11093 match &formatting_result {
11094 Ok(_) => self.last_formatting_failure = None,
11095 Err(error) => {
11096 let error_string = format!("{error:#}");
11097 log::error!("Formatting failed: {error_string}");
11098 self.last_formatting_failure
11099 .replace(error_string.lines().join(" "));
11100 }
11101 }
11102 }
11103
11104 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11105 self.lsp_server_capabilities.remove(&for_server);
11106 for buffer_colors in self.lsp_document_colors.values_mut() {
11107 buffer_colors.colors.remove(&for_server);
11108 buffer_colors.cache_version += 1;
11109 }
11110 for buffer_lens in self.lsp_code_lens.values_mut() {
11111 buffer_lens.lens.remove(&for_server);
11112 }
11113 if let Some(local) = self.as_local_mut() {
11114 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11115 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11116 buffer_servers.remove(&for_server);
11117 }
11118 }
11119 }
11120
11121 pub fn result_id(
11122 &self,
11123 server_id: LanguageServerId,
11124 buffer_id: BufferId,
11125 cx: &App,
11126 ) -> Option<String> {
11127 let abs_path = self
11128 .buffer_store
11129 .read(cx)
11130 .get(buffer_id)
11131 .and_then(|b| File::from_dyn(b.read(cx).file()))
11132 .map(|f| f.abs_path(cx))?;
11133 self.as_local()?
11134 .buffer_pull_diagnostics_result_ids
11135 .get(&server_id)?
11136 .get(&abs_path)?
11137 .clone()
11138 }
11139
11140 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11141 let Some(local) = self.as_local() else {
11142 return HashMap::default();
11143 };
11144 local
11145 .buffer_pull_diagnostics_result_ids
11146 .get(&server_id)
11147 .into_iter()
11148 .flatten()
11149 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11150 .collect()
11151 }
11152
11153 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11154 if let Some(LanguageServerState::Running {
11155 workspace_refresh_task: Some(workspace_refresh_task),
11156 ..
11157 }) = self
11158 .as_local_mut()
11159 .and_then(|local| local.language_servers.get_mut(&server_id))
11160 {
11161 workspace_refresh_task.refresh_tx.try_send(()).ok();
11162 }
11163 }
11164
11165 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11166 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11167 return;
11168 };
11169 let Some(local) = self.as_local_mut() else {
11170 return;
11171 };
11172
11173 for server_id in buffer.update(cx, |buffer, cx| {
11174 local.language_server_ids_for_buffer(buffer, cx)
11175 }) {
11176 if let Some(LanguageServerState::Running {
11177 workspace_refresh_task: Some(workspace_refresh_task),
11178 ..
11179 }) = local.language_servers.get_mut(&server_id)
11180 {
11181 workspace_refresh_task.refresh_tx.try_send(()).ok();
11182 }
11183 }
11184 }
11185
11186 fn apply_workspace_diagnostic_report(
11187 &mut self,
11188 server_id: LanguageServerId,
11189 report: lsp::WorkspaceDiagnosticReportResult,
11190 cx: &mut Context<Self>,
11191 ) {
11192 let workspace_diagnostics =
11193 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11194 let mut unchanged_buffers = HashSet::default();
11195 let mut changed_buffers = HashSet::default();
11196 let workspace_diagnostics_updates = workspace_diagnostics
11197 .into_iter()
11198 .filter_map(
11199 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11200 LspPullDiagnostics::Response {
11201 server_id,
11202 uri,
11203 diagnostics,
11204 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11205 LspPullDiagnostics::Default => None,
11206 },
11207 )
11208 .fold(
11209 HashMap::default(),
11210 |mut acc, (server_id, uri, diagnostics, version)| {
11211 let (result_id, diagnostics) = match diagnostics {
11212 PulledDiagnostics::Unchanged { result_id } => {
11213 unchanged_buffers.insert(uri.clone());
11214 (Some(result_id), Vec::new())
11215 }
11216 PulledDiagnostics::Changed {
11217 result_id,
11218 diagnostics,
11219 } => {
11220 changed_buffers.insert(uri.clone());
11221 (result_id, diagnostics)
11222 }
11223 };
11224 let disk_based_sources = Cow::Owned(
11225 self.language_server_adapter_for_id(server_id)
11226 .as_ref()
11227 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11228 .unwrap_or(&[])
11229 .to_vec(),
11230 );
11231 acc.entry(server_id)
11232 .or_insert_with(Vec::new)
11233 .push(DocumentDiagnosticsUpdate {
11234 server_id,
11235 diagnostics: lsp::PublishDiagnosticsParams {
11236 uri,
11237 diagnostics,
11238 version,
11239 },
11240 result_id,
11241 disk_based_sources,
11242 });
11243 acc
11244 },
11245 );
11246
11247 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11248 self.merge_lsp_diagnostics(
11249 DiagnosticSourceKind::Pulled,
11250 diagnostic_updates,
11251 |buffer, old_diagnostic, cx| {
11252 File::from_dyn(buffer.file())
11253 .and_then(|file| {
11254 let abs_path = file.as_local()?.abs_path(cx);
11255 lsp::Uri::from_file_path(abs_path).ok()
11256 })
11257 .is_none_or(|buffer_uri| {
11258 unchanged_buffers.contains(&buffer_uri)
11259 || match old_diagnostic.source_kind {
11260 DiagnosticSourceKind::Pulled => {
11261 !changed_buffers.contains(&buffer_uri)
11262 }
11263 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11264 true
11265 }
11266 }
11267 })
11268 },
11269 cx,
11270 )
11271 .log_err();
11272 }
11273 }
11274
11275 fn register_server_capabilities(
11276 &mut self,
11277 server_id: LanguageServerId,
11278 params: lsp::RegistrationParams,
11279 cx: &mut Context<Self>,
11280 ) -> anyhow::Result<()> {
11281 let server = self
11282 .language_server_for_id(server_id)
11283 .with_context(|| format!("no server {server_id} found"))?;
11284 for reg in params.registrations {
11285 match reg.method.as_str() {
11286 "workspace/didChangeWatchedFiles" => {
11287 if let Some(options) = reg.register_options {
11288 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11289 let caps = serde_json::from_value(options)?;
11290 local_lsp_store
11291 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11292 true
11293 } else {
11294 false
11295 };
11296 if notify {
11297 notify_server_capabilities_updated(&server, cx);
11298 }
11299 }
11300 }
11301 "workspace/didChangeConfiguration" => {
11302 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11303 }
11304 "workspace/didChangeWorkspaceFolders" => {
11305 // In this case register options is an empty object, we can ignore it
11306 let caps = lsp::WorkspaceFoldersServerCapabilities {
11307 supported: Some(true),
11308 change_notifications: Some(OneOf::Right(reg.id)),
11309 };
11310 server.update_capabilities(|capabilities| {
11311 capabilities
11312 .workspace
11313 .get_or_insert_default()
11314 .workspace_folders = Some(caps);
11315 });
11316 notify_server_capabilities_updated(&server, cx);
11317 }
11318 "workspace/symbol" => {
11319 let options = parse_register_capabilities(reg)?;
11320 server.update_capabilities(|capabilities| {
11321 capabilities.workspace_symbol_provider = Some(options);
11322 });
11323 notify_server_capabilities_updated(&server, cx);
11324 }
11325 "workspace/fileOperations" => {
11326 if let Some(options) = reg.register_options {
11327 let caps = serde_json::from_value(options)?;
11328 server.update_capabilities(|capabilities| {
11329 capabilities
11330 .workspace
11331 .get_or_insert_default()
11332 .file_operations = Some(caps);
11333 });
11334 notify_server_capabilities_updated(&server, cx);
11335 }
11336 }
11337 "workspace/executeCommand" => {
11338 if let Some(options) = reg.register_options {
11339 let options = serde_json::from_value(options)?;
11340 server.update_capabilities(|capabilities| {
11341 capabilities.execute_command_provider = Some(options);
11342 });
11343 notify_server_capabilities_updated(&server, cx);
11344 }
11345 }
11346 "textDocument/rangeFormatting" => {
11347 let options = parse_register_capabilities(reg)?;
11348 server.update_capabilities(|capabilities| {
11349 capabilities.document_range_formatting_provider = Some(options);
11350 });
11351 notify_server_capabilities_updated(&server, cx);
11352 }
11353 "textDocument/onTypeFormatting" => {
11354 if let Some(options) = reg
11355 .register_options
11356 .map(serde_json::from_value)
11357 .transpose()?
11358 {
11359 server.update_capabilities(|capabilities| {
11360 capabilities.document_on_type_formatting_provider = Some(options);
11361 });
11362 notify_server_capabilities_updated(&server, cx);
11363 }
11364 }
11365 "textDocument/formatting" => {
11366 let options = parse_register_capabilities(reg)?;
11367 server.update_capabilities(|capabilities| {
11368 capabilities.document_formatting_provider = Some(options);
11369 });
11370 notify_server_capabilities_updated(&server, cx);
11371 }
11372 "textDocument/rename" => {
11373 let options = parse_register_capabilities(reg)?;
11374 server.update_capabilities(|capabilities| {
11375 capabilities.rename_provider = Some(options);
11376 });
11377 notify_server_capabilities_updated(&server, cx);
11378 }
11379 "textDocument/inlayHint" => {
11380 let options = parse_register_capabilities(reg)?;
11381 server.update_capabilities(|capabilities| {
11382 capabilities.inlay_hint_provider = Some(options);
11383 });
11384 notify_server_capabilities_updated(&server, cx);
11385 }
11386 "textDocument/documentSymbol" => {
11387 let options = parse_register_capabilities(reg)?;
11388 server.update_capabilities(|capabilities| {
11389 capabilities.document_symbol_provider = Some(options);
11390 });
11391 notify_server_capabilities_updated(&server, cx);
11392 }
11393 "textDocument/codeAction" => {
11394 let options = parse_register_capabilities(reg)?;
11395 let provider = match options {
11396 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11397 OneOf::Right(caps) => caps,
11398 };
11399 server.update_capabilities(|capabilities| {
11400 capabilities.code_action_provider = Some(provider);
11401 });
11402 notify_server_capabilities_updated(&server, cx);
11403 }
11404 "textDocument/definition" => {
11405 let options = parse_register_capabilities(reg)?;
11406 server.update_capabilities(|capabilities| {
11407 capabilities.definition_provider = Some(options);
11408 });
11409 notify_server_capabilities_updated(&server, cx);
11410 }
11411 "textDocument/completion" => {
11412 if let Some(caps) = reg
11413 .register_options
11414 .map(serde_json::from_value)
11415 .transpose()?
11416 {
11417 server.update_capabilities(|capabilities| {
11418 capabilities.completion_provider = Some(caps);
11419 });
11420 notify_server_capabilities_updated(&server, cx);
11421 }
11422 }
11423 "textDocument/hover" => {
11424 let options = parse_register_capabilities(reg)?;
11425 let provider = match options {
11426 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11427 OneOf::Right(caps) => caps,
11428 };
11429 server.update_capabilities(|capabilities| {
11430 capabilities.hover_provider = Some(provider);
11431 });
11432 notify_server_capabilities_updated(&server, cx);
11433 }
11434 "textDocument/signatureHelp" => {
11435 if let Some(caps) = reg
11436 .register_options
11437 .map(serde_json::from_value)
11438 .transpose()?
11439 {
11440 server.update_capabilities(|capabilities| {
11441 capabilities.signature_help_provider = Some(caps);
11442 });
11443 notify_server_capabilities_updated(&server, cx);
11444 }
11445 }
11446 "textDocument/didChange" => {
11447 if let Some(sync_kind) = reg
11448 .register_options
11449 .and_then(|opts| opts.get("syncKind").cloned())
11450 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11451 .transpose()?
11452 {
11453 server.update_capabilities(|capabilities| {
11454 let mut sync_options =
11455 Self::take_text_document_sync_options(capabilities);
11456 sync_options.change = Some(sync_kind);
11457 capabilities.text_document_sync =
11458 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11459 });
11460 notify_server_capabilities_updated(&server, cx);
11461 }
11462 }
11463 "textDocument/didSave" => {
11464 if let Some(include_text) = reg
11465 .register_options
11466 .map(|opts| {
11467 let transpose = opts
11468 .get("includeText")
11469 .cloned()
11470 .map(serde_json::from_value::<Option<bool>>)
11471 .transpose();
11472 match transpose {
11473 Ok(value) => Ok(value.flatten()),
11474 Err(e) => Err(e),
11475 }
11476 })
11477 .transpose()?
11478 {
11479 server.update_capabilities(|capabilities| {
11480 let mut sync_options =
11481 Self::take_text_document_sync_options(capabilities);
11482 sync_options.save =
11483 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11484 include_text,
11485 }));
11486 capabilities.text_document_sync =
11487 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11488 });
11489 notify_server_capabilities_updated(&server, cx);
11490 }
11491 }
11492 "textDocument/codeLens" => {
11493 if let Some(caps) = reg
11494 .register_options
11495 .map(serde_json::from_value)
11496 .transpose()?
11497 {
11498 server.update_capabilities(|capabilities| {
11499 capabilities.code_lens_provider = Some(caps);
11500 });
11501 notify_server_capabilities_updated(&server, cx);
11502 }
11503 }
11504 "textDocument/diagnostic" => {
11505 if let Some(caps) = reg
11506 .register_options
11507 .map(serde_json::from_value)
11508 .transpose()?
11509 {
11510 server.update_capabilities(|capabilities| {
11511 capabilities.diagnostic_provider = Some(caps);
11512 });
11513 notify_server_capabilities_updated(&server, cx);
11514 }
11515 }
11516 "textDocument/documentColor" => {
11517 let options = parse_register_capabilities(reg)?;
11518 let provider = match options {
11519 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11520 OneOf::Right(caps) => caps,
11521 };
11522 server.update_capabilities(|capabilities| {
11523 capabilities.color_provider = Some(provider);
11524 });
11525 notify_server_capabilities_updated(&server, cx);
11526 }
11527 _ => log::warn!("unhandled capability registration: {reg:?}"),
11528 }
11529 }
11530
11531 Ok(())
11532 }
11533
11534 fn unregister_server_capabilities(
11535 &mut self,
11536 server_id: LanguageServerId,
11537 params: lsp::UnregistrationParams,
11538 cx: &mut Context<Self>,
11539 ) -> anyhow::Result<()> {
11540 let server = self
11541 .language_server_for_id(server_id)
11542 .with_context(|| format!("no server {server_id} found"))?;
11543 for unreg in params.unregisterations.iter() {
11544 match unreg.method.as_str() {
11545 "workspace/didChangeWatchedFiles" => {
11546 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11547 local_lsp_store
11548 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11549 true
11550 } else {
11551 false
11552 };
11553 if notify {
11554 notify_server_capabilities_updated(&server, cx);
11555 }
11556 }
11557 "workspace/didChangeConfiguration" => {
11558 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11559 }
11560 "workspace/didChangeWorkspaceFolders" => {
11561 server.update_capabilities(|capabilities| {
11562 capabilities
11563 .workspace
11564 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11565 workspace_folders: None,
11566 file_operations: None,
11567 })
11568 .workspace_folders = None;
11569 });
11570 notify_server_capabilities_updated(&server, cx);
11571 }
11572 "workspace/symbol" => {
11573 server.update_capabilities(|capabilities| {
11574 capabilities.workspace_symbol_provider = None
11575 });
11576 notify_server_capabilities_updated(&server, cx);
11577 }
11578 "workspace/fileOperations" => {
11579 server.update_capabilities(|capabilities| {
11580 capabilities
11581 .workspace
11582 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11583 workspace_folders: None,
11584 file_operations: None,
11585 })
11586 .file_operations = None;
11587 });
11588 notify_server_capabilities_updated(&server, cx);
11589 }
11590 "workspace/executeCommand" => {
11591 server.update_capabilities(|capabilities| {
11592 capabilities.execute_command_provider = None;
11593 });
11594 notify_server_capabilities_updated(&server, cx);
11595 }
11596 "textDocument/rangeFormatting" => {
11597 server.update_capabilities(|capabilities| {
11598 capabilities.document_range_formatting_provider = None
11599 });
11600 notify_server_capabilities_updated(&server, cx);
11601 }
11602 "textDocument/onTypeFormatting" => {
11603 server.update_capabilities(|capabilities| {
11604 capabilities.document_on_type_formatting_provider = None;
11605 });
11606 notify_server_capabilities_updated(&server, cx);
11607 }
11608 "textDocument/formatting" => {
11609 server.update_capabilities(|capabilities| {
11610 capabilities.document_formatting_provider = None;
11611 });
11612 notify_server_capabilities_updated(&server, cx);
11613 }
11614 "textDocument/rename" => {
11615 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11616 notify_server_capabilities_updated(&server, cx);
11617 }
11618 "textDocument/codeAction" => {
11619 server.update_capabilities(|capabilities| {
11620 capabilities.code_action_provider = None;
11621 });
11622 notify_server_capabilities_updated(&server, cx);
11623 }
11624 "textDocument/definition" => {
11625 server.update_capabilities(|capabilities| {
11626 capabilities.definition_provider = None;
11627 });
11628 notify_server_capabilities_updated(&server, cx);
11629 }
11630 "textDocument/completion" => {
11631 server.update_capabilities(|capabilities| {
11632 capabilities.completion_provider = None;
11633 });
11634 notify_server_capabilities_updated(&server, cx);
11635 }
11636 "textDocument/hover" => {
11637 server.update_capabilities(|capabilities| {
11638 capabilities.hover_provider = None;
11639 });
11640 notify_server_capabilities_updated(&server, cx);
11641 }
11642 "textDocument/signatureHelp" => {
11643 server.update_capabilities(|capabilities| {
11644 capabilities.signature_help_provider = None;
11645 });
11646 notify_server_capabilities_updated(&server, cx);
11647 }
11648 "textDocument/didChange" => {
11649 server.update_capabilities(|capabilities| {
11650 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11651 sync_options.change = None;
11652 capabilities.text_document_sync =
11653 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11654 });
11655 notify_server_capabilities_updated(&server, cx);
11656 }
11657 "textDocument/didSave" => {
11658 server.update_capabilities(|capabilities| {
11659 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11660 sync_options.save = None;
11661 capabilities.text_document_sync =
11662 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11663 });
11664 notify_server_capabilities_updated(&server, cx);
11665 }
11666 "textDocument/codeLens" => {
11667 server.update_capabilities(|capabilities| {
11668 capabilities.code_lens_provider = None;
11669 });
11670 notify_server_capabilities_updated(&server, cx);
11671 }
11672 "textDocument/diagnostic" => {
11673 server.update_capabilities(|capabilities| {
11674 capabilities.diagnostic_provider = None;
11675 });
11676 notify_server_capabilities_updated(&server, cx);
11677 }
11678 "textDocument/documentColor" => {
11679 server.update_capabilities(|capabilities| {
11680 capabilities.color_provider = None;
11681 });
11682 notify_server_capabilities_updated(&server, cx);
11683 }
11684 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
11685 }
11686 }
11687
11688 Ok(())
11689 }
11690
11691 async fn query_lsp_locally<T>(
11692 lsp_store: Entity<Self>,
11693 sender_id: proto::PeerId,
11694 lsp_request_id: LspRequestId,
11695 proto_request: T::ProtoRequest,
11696 position: Option<Anchor>,
11697 mut cx: AsyncApp,
11698 ) -> Result<()>
11699 where
11700 T: LspCommand + Clone,
11701 T::ProtoRequest: proto::LspRequestMessage,
11702 <T::ProtoRequest as proto::RequestMessage>::Response:
11703 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
11704 {
11705 let buffer_id = BufferId::new(proto_request.buffer_id())?;
11706 let version = deserialize_version(proto_request.buffer_version());
11707 let buffer = lsp_store.update(&mut cx, |this, cx| {
11708 this.buffer_store.read(cx).get_existing(buffer_id)
11709 })??;
11710 buffer
11711 .update(&mut cx, |buffer, _| {
11712 buffer.wait_for_version(version.clone())
11713 })?
11714 .await?;
11715 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
11716 let request =
11717 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
11718 lsp_store.update(&mut cx, |lsp_store, cx| {
11719 let request_task =
11720 lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx);
11721 let existing_queries = lsp_store
11722 .running_lsp_requests
11723 .entry(TypeId::of::<T>())
11724 .or_default();
11725 if T::ProtoRequest::stop_previous_requests()
11726 || buffer_version.changed_since(&existing_queries.0)
11727 {
11728 existing_queries.1.clear();
11729 }
11730 existing_queries.1.insert(
11731 lsp_request_id,
11732 cx.spawn(async move |lsp_store, cx| {
11733 let response = request_task.await;
11734 lsp_store
11735 .update(cx, |lsp_store, cx| {
11736 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
11737 {
11738 let response = response
11739 .into_iter()
11740 .map(|(server_id, response)| {
11741 (
11742 server_id.to_proto(),
11743 T::response_to_proto(
11744 response,
11745 lsp_store,
11746 sender_id,
11747 &buffer_version,
11748 cx,
11749 )
11750 .into(),
11751 )
11752 })
11753 .collect::<HashMap<_, _>>();
11754 match client.send_lsp_response::<T::ProtoRequest>(
11755 project_id,
11756 lsp_request_id,
11757 response,
11758 ) {
11759 Ok(()) => {}
11760 Err(e) => {
11761 log::error!("Failed to send LSP response: {e:#}",)
11762 }
11763 }
11764 }
11765 })
11766 .ok();
11767 }),
11768 );
11769 })?;
11770 Ok(())
11771 }
11772
11773 fn take_text_document_sync_options(
11774 capabilities: &mut lsp::ServerCapabilities,
11775 ) -> lsp::TextDocumentSyncOptions {
11776 match capabilities.text_document_sync.take() {
11777 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
11778 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
11779 let mut sync_options = lsp::TextDocumentSyncOptions::default();
11780 sync_options.change = Some(sync_kind);
11781 sync_options
11782 }
11783 None => lsp::TextDocumentSyncOptions::default(),
11784 }
11785 }
11786
11787 #[cfg(any(test, feature = "test-support"))]
11788 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
11789 let data = self.lsp_code_lens.get_mut(&buffer_id)?;
11790 Some(data.update.take()?.1)
11791 }
11792
11793 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
11794 self.downstream_client.clone()
11795 }
11796
11797 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
11798 self.worktree_store.clone()
11799 }
11800}
11801
11802// Registration with registerOptions as null, should fallback to true.
11803// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
11804fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
11805 reg: lsp::Registration,
11806) -> Result<OneOf<bool, T>> {
11807 Ok(match reg.register_options {
11808 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
11809 None => OneOf::Left(true),
11810 })
11811}
11812
11813fn subscribe_to_binary_statuses(
11814 languages: &Arc<LanguageRegistry>,
11815 cx: &mut Context<'_, LspStore>,
11816) -> Task<()> {
11817 let mut server_statuses = languages.language_server_binary_statuses();
11818 cx.spawn(async move |lsp_store, cx| {
11819 while let Some((server_name, binary_status)) = server_statuses.next().await {
11820 if lsp_store
11821 .update(cx, |_, cx| {
11822 let mut message = None;
11823 let binary_status = match binary_status {
11824 BinaryStatus::None => proto::ServerBinaryStatus::None,
11825 BinaryStatus::CheckingForUpdate => {
11826 proto::ServerBinaryStatus::CheckingForUpdate
11827 }
11828 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
11829 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
11830 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
11831 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
11832 BinaryStatus::Failed { error } => {
11833 message = Some(error);
11834 proto::ServerBinaryStatus::Failed
11835 }
11836 };
11837 cx.emit(LspStoreEvent::LanguageServerUpdate {
11838 // Binary updates are about the binary that might not have any language server id at that point.
11839 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
11840 language_server_id: LanguageServerId(0),
11841 name: Some(server_name),
11842 message: proto::update_language_server::Variant::StatusUpdate(
11843 proto::StatusUpdate {
11844 message,
11845 status: Some(proto::status_update::Status::Binary(
11846 binary_status as i32,
11847 )),
11848 },
11849 ),
11850 });
11851 })
11852 .is_err()
11853 {
11854 break;
11855 }
11856 }
11857 })
11858}
11859
11860fn lsp_workspace_diagnostics_refresh(
11861 server: Arc<LanguageServer>,
11862 cx: &mut Context<'_, LspStore>,
11863) -> Option<WorkspaceRefreshTask> {
11864 let identifier = match server.capabilities().diagnostic_provider? {
11865 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
11866 if !diagnostic_options.workspace_diagnostics {
11867 return None;
11868 }
11869 diagnostic_options.identifier
11870 }
11871 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
11872 let diagnostic_options = registration_options.diagnostic_options;
11873 if !diagnostic_options.workspace_diagnostics {
11874 return None;
11875 }
11876 diagnostic_options.identifier
11877 }
11878 };
11879
11880 let (progress_tx, mut progress_rx) = mpsc::channel(1);
11881 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
11882 refresh_tx.try_send(()).ok();
11883
11884 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
11885 let mut attempts = 0;
11886 let max_attempts = 50;
11887 let mut requests = 0;
11888
11889 loop {
11890 let Some(()) = refresh_rx.recv().await else {
11891 return;
11892 };
11893
11894 'request: loop {
11895 requests += 1;
11896 if attempts > max_attempts {
11897 log::error!(
11898 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
11899 );
11900 return;
11901 }
11902 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
11903 cx.background_executor()
11904 .timer(Duration::from_millis(backoff_millis))
11905 .await;
11906 attempts += 1;
11907
11908 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
11909 lsp_store
11910 .all_result_ids(server.server_id())
11911 .into_iter()
11912 .filter_map(|(abs_path, result_id)| {
11913 let uri = file_path_to_lsp_url(&abs_path).ok()?;
11914 Some(lsp::PreviousResultId {
11915 uri,
11916 value: result_id,
11917 })
11918 })
11919 .collect()
11920 }) else {
11921 return;
11922 };
11923
11924 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
11925
11926 progress_rx.try_recv().ok();
11927 let timer =
11928 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
11929 let progress = pin!(progress_rx.recv().fuse());
11930 let response_result = server
11931 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
11932 lsp::WorkspaceDiagnosticParams {
11933 previous_result_ids,
11934 identifier: identifier.clone(),
11935 work_done_progress_params: Default::default(),
11936 partial_result_params: lsp::PartialResultParams {
11937 partial_result_token: Some(lsp::ProgressToken::String(token)),
11938 },
11939 },
11940 select(timer, progress).then(|either| match either {
11941 Either::Left((message, ..)) => ready(message).left_future(),
11942 Either::Right(..) => pending::<String>().right_future(),
11943 }),
11944 )
11945 .await;
11946
11947 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
11948 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
11949 match response_result {
11950 ConnectionResult::Timeout => {
11951 log::error!("Timeout during workspace diagnostics pull");
11952 continue 'request;
11953 }
11954 ConnectionResult::ConnectionReset => {
11955 log::error!("Server closed a workspace diagnostics pull request");
11956 continue 'request;
11957 }
11958 ConnectionResult::Result(Err(e)) => {
11959 log::error!("Error during workspace diagnostics pull: {e:#}");
11960 break 'request;
11961 }
11962 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
11963 attempts = 0;
11964 if lsp_store
11965 .update(cx, |lsp_store, cx| {
11966 lsp_store.apply_workspace_diagnostic_report(
11967 server.server_id(),
11968 pulled_diagnostics,
11969 cx,
11970 )
11971 })
11972 .is_err()
11973 {
11974 return;
11975 }
11976 break 'request;
11977 }
11978 }
11979 }
11980 }
11981 });
11982
11983 Some(WorkspaceRefreshTask {
11984 refresh_tx,
11985 progress_tx,
11986 task: workspace_query_language_server,
11987 })
11988}
11989
11990fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
11991 let CompletionSource::BufferWord {
11992 word_range,
11993 resolved,
11994 } = &mut completion.source
11995 else {
11996 return;
11997 };
11998 if *resolved {
11999 return;
12000 }
12001
12002 if completion.new_text
12003 != snapshot
12004 .text_for_range(word_range.clone())
12005 .collect::<String>()
12006 {
12007 return;
12008 }
12009
12010 let mut offset = 0;
12011 for chunk in snapshot.chunks(word_range.clone(), true) {
12012 let end_offset = offset + chunk.text.len();
12013 if let Some(highlight_id) = chunk.syntax_highlight_id {
12014 completion
12015 .label
12016 .runs
12017 .push((offset..end_offset, highlight_id));
12018 }
12019 offset = end_offset;
12020 }
12021 *resolved = true;
12022}
12023
12024impl EventEmitter<LspStoreEvent> for LspStore {}
12025
12026fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12027 hover
12028 .contents
12029 .retain(|hover_block| !hover_block.text.trim().is_empty());
12030 if hover.contents.is_empty() {
12031 None
12032 } else {
12033 Some(hover)
12034 }
12035}
12036
12037async fn populate_labels_for_completions(
12038 new_completions: Vec<CoreCompletion>,
12039 language: Option<Arc<Language>>,
12040 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12041) -> Vec<Completion> {
12042 let lsp_completions = new_completions
12043 .iter()
12044 .filter_map(|new_completion| {
12045 new_completion
12046 .source
12047 .lsp_completion(true)
12048 .map(|lsp_completion| lsp_completion.into_owned())
12049 })
12050 .collect::<Vec<_>>();
12051
12052 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12053 lsp_adapter
12054 .labels_for_completions(&lsp_completions, language)
12055 .await
12056 .log_err()
12057 .unwrap_or_default()
12058 } else {
12059 Vec::new()
12060 }
12061 .into_iter()
12062 .fuse();
12063
12064 let mut completions = Vec::new();
12065 for completion in new_completions {
12066 match completion.source.lsp_completion(true) {
12067 Some(lsp_completion) => {
12068 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12069
12070 let mut label = labels.next().flatten().unwrap_or_else(|| {
12071 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12072 });
12073 ensure_uniform_list_compatible_label(&mut label);
12074 completions.push(Completion {
12075 label,
12076 documentation,
12077 replace_range: completion.replace_range,
12078 new_text: completion.new_text,
12079 insert_text_mode: lsp_completion.insert_text_mode,
12080 source: completion.source,
12081 icon_path: None,
12082 confirm: None,
12083 });
12084 }
12085 None => {
12086 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12087 ensure_uniform_list_compatible_label(&mut label);
12088 completions.push(Completion {
12089 label,
12090 documentation: None,
12091 replace_range: completion.replace_range,
12092 new_text: completion.new_text,
12093 source: completion.source,
12094 insert_text_mode: None,
12095 icon_path: None,
12096 confirm: None,
12097 });
12098 }
12099 }
12100 }
12101 completions
12102}
12103
12104#[derive(Debug)]
12105pub enum LanguageServerToQuery {
12106 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12107 FirstCapable,
12108 /// Query a specific language server.
12109 Other(LanguageServerId),
12110}
12111
12112#[derive(Default)]
12113struct RenamePathsWatchedForServer {
12114 did_rename: Vec<RenameActionPredicate>,
12115 will_rename: Vec<RenameActionPredicate>,
12116}
12117
12118impl RenamePathsWatchedForServer {
12119 fn with_did_rename_patterns(
12120 mut self,
12121 did_rename: Option<&FileOperationRegistrationOptions>,
12122 ) -> Self {
12123 if let Some(did_rename) = did_rename {
12124 self.did_rename = did_rename
12125 .filters
12126 .iter()
12127 .filter_map(|filter| filter.try_into().log_err())
12128 .collect();
12129 }
12130 self
12131 }
12132 fn with_will_rename_patterns(
12133 mut self,
12134 will_rename: Option<&FileOperationRegistrationOptions>,
12135 ) -> Self {
12136 if let Some(will_rename) = will_rename {
12137 self.will_rename = will_rename
12138 .filters
12139 .iter()
12140 .filter_map(|filter| filter.try_into().log_err())
12141 .collect();
12142 }
12143 self
12144 }
12145
12146 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12147 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12148 }
12149 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12150 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12151 }
12152}
12153
12154impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12155 type Error = globset::Error;
12156 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12157 Ok(Self {
12158 kind: ops.pattern.matches.clone(),
12159 glob: GlobBuilder::new(&ops.pattern.glob)
12160 .case_insensitive(
12161 ops.pattern
12162 .options
12163 .as_ref()
12164 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12165 )
12166 .build()?
12167 .compile_matcher(),
12168 })
12169 }
12170}
12171struct RenameActionPredicate {
12172 glob: GlobMatcher,
12173 kind: Option<FileOperationPatternKind>,
12174}
12175
12176impl RenameActionPredicate {
12177 // Returns true if language server should be notified
12178 fn eval(&self, path: &str, is_dir: bool) -> bool {
12179 self.kind.as_ref().is_none_or(|kind| {
12180 let expected_kind = if is_dir {
12181 FileOperationPatternKind::Folder
12182 } else {
12183 FileOperationPatternKind::File
12184 };
12185 kind == &expected_kind
12186 }) && self.glob.is_match(path)
12187 }
12188}
12189
12190#[derive(Default)]
12191struct LanguageServerWatchedPaths {
12192 worktree_paths: HashMap<WorktreeId, GlobSet>,
12193 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12194}
12195
12196#[derive(Default)]
12197struct LanguageServerWatchedPathsBuilder {
12198 worktree_paths: HashMap<WorktreeId, GlobSet>,
12199 abs_paths: HashMap<Arc<Path>, GlobSet>,
12200}
12201
12202impl LanguageServerWatchedPathsBuilder {
12203 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12204 self.worktree_paths.insert(worktree_id, glob_set);
12205 }
12206 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12207 self.abs_paths.insert(path, glob_set);
12208 }
12209 fn build(
12210 self,
12211 fs: Arc<dyn Fs>,
12212 language_server_id: LanguageServerId,
12213 cx: &mut Context<LspStore>,
12214 ) -> LanguageServerWatchedPaths {
12215 let project = cx.weak_entity();
12216
12217 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12218 let abs_paths = self
12219 .abs_paths
12220 .into_iter()
12221 .map(|(abs_path, globset)| {
12222 let task = cx.spawn({
12223 let abs_path = abs_path.clone();
12224 let fs = fs.clone();
12225
12226 let lsp_store = project.clone();
12227 async move |_, cx| {
12228 maybe!(async move {
12229 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12230 while let Some(update) = push_updates.0.next().await {
12231 let action = lsp_store
12232 .update(cx, |this, _| {
12233 let Some(local) = this.as_local() else {
12234 return ControlFlow::Break(());
12235 };
12236 let Some(watcher) = local
12237 .language_server_watched_paths
12238 .get(&language_server_id)
12239 else {
12240 return ControlFlow::Break(());
12241 };
12242 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12243 "Watched abs path is not registered with a watcher",
12244 );
12245 let matching_entries = update
12246 .into_iter()
12247 .filter(|event| globs.is_match(&event.path))
12248 .collect::<Vec<_>>();
12249 this.lsp_notify_abs_paths_changed(
12250 language_server_id,
12251 matching_entries,
12252 );
12253 ControlFlow::Continue(())
12254 })
12255 .ok()?;
12256
12257 if action.is_break() {
12258 break;
12259 }
12260 }
12261 Some(())
12262 })
12263 .await;
12264 }
12265 });
12266 (abs_path, (globset, task))
12267 })
12268 .collect();
12269 LanguageServerWatchedPaths {
12270 worktree_paths: self.worktree_paths,
12271 abs_paths,
12272 }
12273 }
12274}
12275
12276struct LspBufferSnapshot {
12277 version: i32,
12278 snapshot: TextBufferSnapshot,
12279}
12280
12281/// A prompt requested by LSP server.
12282#[derive(Clone, Debug)]
12283pub struct LanguageServerPromptRequest {
12284 pub level: PromptLevel,
12285 pub message: String,
12286 pub actions: Vec<MessageActionItem>,
12287 pub lsp_name: String,
12288 pub(crate) response_channel: Sender<MessageActionItem>,
12289}
12290
12291impl LanguageServerPromptRequest {
12292 pub async fn respond(self, index: usize) -> Option<()> {
12293 if let Some(response) = self.actions.into_iter().nth(index) {
12294 self.response_channel.send(response).await.ok()
12295 } else {
12296 None
12297 }
12298 }
12299}
12300impl PartialEq for LanguageServerPromptRequest {
12301 fn eq(&self, other: &Self) -> bool {
12302 self.message == other.message && self.actions == other.actions
12303 }
12304}
12305
12306#[derive(Clone, Debug, PartialEq)]
12307pub enum LanguageServerLogType {
12308 Log(MessageType),
12309 Trace { verbose_info: Option<String> },
12310 Rpc { received: bool },
12311}
12312
12313impl LanguageServerLogType {
12314 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12315 match self {
12316 Self::Log(log_type) => {
12317 use proto::log_message::LogLevel;
12318 let level = match *log_type {
12319 MessageType::ERROR => LogLevel::Error,
12320 MessageType::WARNING => LogLevel::Warning,
12321 MessageType::INFO => LogLevel::Info,
12322 MessageType::LOG => LogLevel::Log,
12323 other => {
12324 log::warn!("Unknown lsp log message type: {other:?}");
12325 LogLevel::Log
12326 }
12327 };
12328 proto::language_server_log::LogType::Log(proto::LogMessage {
12329 level: level as i32,
12330 })
12331 }
12332 Self::Trace { verbose_info } => {
12333 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12334 verbose_info: verbose_info.to_owned(),
12335 })
12336 }
12337 Self::Rpc { received } => {
12338 let kind = if *received {
12339 proto::rpc_message::Kind::Received
12340 } else {
12341 proto::rpc_message::Kind::Sent
12342 };
12343 let kind = kind as i32;
12344 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12345 }
12346 }
12347 }
12348
12349 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12350 use proto::log_message::LogLevel;
12351 use proto::rpc_message;
12352 match log_type {
12353 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12354 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12355 LogLevel::Error => MessageType::ERROR,
12356 LogLevel::Warning => MessageType::WARNING,
12357 LogLevel::Info => MessageType::INFO,
12358 LogLevel::Log => MessageType::LOG,
12359 },
12360 ),
12361 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12362 verbose_info: trace_message.verbose_info,
12363 },
12364 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12365 received: match rpc_message::Kind::from_i32(message.kind)
12366 .unwrap_or(rpc_message::Kind::Received)
12367 {
12368 rpc_message::Kind::Received => true,
12369 rpc_message::Kind::Sent => false,
12370 },
12371 },
12372 }
12373 }
12374}
12375
12376pub struct WorkspaceRefreshTask {
12377 refresh_tx: mpsc::Sender<()>,
12378 progress_tx: mpsc::Sender<()>,
12379 #[allow(dead_code)]
12380 task: Task<()>,
12381}
12382
12383pub enum LanguageServerState {
12384 Starting {
12385 startup: Task<Option<Arc<LanguageServer>>>,
12386 /// List of language servers that will be added to the workspace once it's initialization completes.
12387 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12388 },
12389
12390 Running {
12391 adapter: Arc<CachedLspAdapter>,
12392 server: Arc<LanguageServer>,
12393 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12394 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12395 },
12396}
12397
12398impl LanguageServerState {
12399 fn add_workspace_folder(&self, uri: Uri) {
12400 match self {
12401 LanguageServerState::Starting {
12402 pending_workspace_folders,
12403 ..
12404 } => {
12405 pending_workspace_folders.lock().insert(uri);
12406 }
12407 LanguageServerState::Running { server, .. } => {
12408 server.add_workspace_folder(uri);
12409 }
12410 }
12411 }
12412 fn _remove_workspace_folder(&self, uri: Uri) {
12413 match self {
12414 LanguageServerState::Starting {
12415 pending_workspace_folders,
12416 ..
12417 } => {
12418 pending_workspace_folders.lock().remove(&uri);
12419 }
12420 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12421 }
12422 }
12423}
12424
12425impl std::fmt::Debug for LanguageServerState {
12426 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12427 match self {
12428 LanguageServerState::Starting { .. } => {
12429 f.debug_struct("LanguageServerState::Starting").finish()
12430 }
12431 LanguageServerState::Running { .. } => {
12432 f.debug_struct("LanguageServerState::Running").finish()
12433 }
12434 }
12435 }
12436}
12437
12438#[derive(Clone, Debug, Serialize)]
12439pub struct LanguageServerProgress {
12440 pub is_disk_based_diagnostics_progress: bool,
12441 pub is_cancellable: bool,
12442 pub title: Option<String>,
12443 pub message: Option<String>,
12444 pub percentage: Option<usize>,
12445 #[serde(skip_serializing)]
12446 pub last_update_at: Instant,
12447}
12448
12449#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12450pub struct DiagnosticSummary {
12451 pub error_count: usize,
12452 pub warning_count: usize,
12453}
12454
12455impl DiagnosticSummary {
12456 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12457 let mut this = Self {
12458 error_count: 0,
12459 warning_count: 0,
12460 };
12461
12462 for entry in diagnostics {
12463 if entry.diagnostic.is_primary {
12464 match entry.diagnostic.severity {
12465 DiagnosticSeverity::ERROR => this.error_count += 1,
12466 DiagnosticSeverity::WARNING => this.warning_count += 1,
12467 _ => {}
12468 }
12469 }
12470 }
12471
12472 this
12473 }
12474
12475 pub fn is_empty(&self) -> bool {
12476 self.error_count == 0 && self.warning_count == 0
12477 }
12478
12479 pub fn to_proto(
12480 self,
12481 language_server_id: LanguageServerId,
12482 path: &Path,
12483 ) -> proto::DiagnosticSummary {
12484 proto::DiagnosticSummary {
12485 path: path.to_proto(),
12486 language_server_id: language_server_id.0 as u64,
12487 error_count: self.error_count as u32,
12488 warning_count: self.warning_count as u32,
12489 }
12490 }
12491}
12492
12493#[derive(Clone, Debug)]
12494pub enum CompletionDocumentation {
12495 /// There is no documentation for this completion.
12496 Undocumented,
12497 /// A single line of documentation.
12498 SingleLine(SharedString),
12499 /// Multiple lines of plain text documentation.
12500 MultiLinePlainText(SharedString),
12501 /// Markdown documentation.
12502 MultiLineMarkdown(SharedString),
12503 /// Both single line and multiple lines of plain text documentation.
12504 SingleLineAndMultiLinePlainText {
12505 single_line: SharedString,
12506 plain_text: Option<SharedString>,
12507 },
12508}
12509
12510impl CompletionDocumentation {
12511 #[cfg(any(test, feature = "test-support"))]
12512 pub fn text(&self) -> SharedString {
12513 match self {
12514 CompletionDocumentation::Undocumented => "".into(),
12515 CompletionDocumentation::SingleLine(s) => s.clone(),
12516 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
12517 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
12518 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
12519 single_line.clone()
12520 }
12521 }
12522 }
12523}
12524
12525impl From<lsp::Documentation> for CompletionDocumentation {
12526 fn from(docs: lsp::Documentation) -> Self {
12527 match docs {
12528 lsp::Documentation::String(text) => {
12529 if text.lines().count() <= 1 {
12530 CompletionDocumentation::SingleLine(text.into())
12531 } else {
12532 CompletionDocumentation::MultiLinePlainText(text.into())
12533 }
12534 }
12535
12536 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12537 lsp::MarkupKind::PlainText => {
12538 if value.lines().count() <= 1 {
12539 CompletionDocumentation::SingleLine(value.into())
12540 } else {
12541 CompletionDocumentation::MultiLinePlainText(value.into())
12542 }
12543 }
12544
12545 lsp::MarkupKind::Markdown => {
12546 CompletionDocumentation::MultiLineMarkdown(value.into())
12547 }
12548 },
12549 }
12550 }
12551}
12552
12553fn glob_literal_prefix(glob: &Path) -> PathBuf {
12554 glob.components()
12555 .take_while(|component| match component {
12556 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12557 _ => true,
12558 })
12559 .collect()
12560}
12561
12562pub struct SshLspAdapter {
12563 name: LanguageServerName,
12564 binary: LanguageServerBinary,
12565 initialization_options: Option<String>,
12566 code_action_kinds: Option<Vec<CodeActionKind>>,
12567}
12568
12569impl SshLspAdapter {
12570 pub fn new(
12571 name: LanguageServerName,
12572 binary: LanguageServerBinary,
12573 initialization_options: Option<String>,
12574 code_action_kinds: Option<String>,
12575 ) -> Self {
12576 Self {
12577 name,
12578 binary,
12579 initialization_options,
12580 code_action_kinds: code_action_kinds
12581 .as_ref()
12582 .and_then(|c| serde_json::from_str(c).ok()),
12583 }
12584 }
12585}
12586
12587impl LspInstaller for SshLspAdapter {
12588 type BinaryVersion = ();
12589 async fn check_if_user_installed(
12590 &self,
12591 _: &dyn LspAdapterDelegate,
12592 _: Option<Toolchain>,
12593 _: &AsyncApp,
12594 ) -> Option<LanguageServerBinary> {
12595 Some(self.binary.clone())
12596 }
12597
12598 async fn cached_server_binary(
12599 &self,
12600 _: PathBuf,
12601 _: &dyn LspAdapterDelegate,
12602 ) -> Option<LanguageServerBinary> {
12603 None
12604 }
12605
12606 async fn fetch_latest_server_version(
12607 &self,
12608 _: &dyn LspAdapterDelegate,
12609 _: bool,
12610 _: &mut AsyncApp,
12611 ) -> Result<()> {
12612 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12613 }
12614
12615 async fn fetch_server_binary(
12616 &self,
12617 _: (),
12618 _: PathBuf,
12619 _: &dyn LspAdapterDelegate,
12620 ) -> Result<LanguageServerBinary> {
12621 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12622 }
12623}
12624
12625#[async_trait(?Send)]
12626impl LspAdapter for SshLspAdapter {
12627 fn name(&self) -> LanguageServerName {
12628 self.name.clone()
12629 }
12630
12631 async fn initialization_options(
12632 self: Arc<Self>,
12633 _: &Arc<dyn LspAdapterDelegate>,
12634 ) -> Result<Option<serde_json::Value>> {
12635 let Some(options) = &self.initialization_options else {
12636 return Ok(None);
12637 };
12638 let result = serde_json::from_str(options)?;
12639 Ok(result)
12640 }
12641
12642 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12643 self.code_action_kinds.clone()
12644 }
12645}
12646
12647pub fn language_server_settings<'a>(
12648 delegate: &'a dyn LspAdapterDelegate,
12649 language: &LanguageServerName,
12650 cx: &'a App,
12651) -> Option<&'a LspSettings> {
12652 language_server_settings_for(
12653 SettingsLocation {
12654 worktree_id: delegate.worktree_id(),
12655 path: delegate.worktree_root_path(),
12656 },
12657 language,
12658 cx,
12659 )
12660}
12661
12662pub(crate) fn language_server_settings_for<'a>(
12663 location: SettingsLocation<'a>,
12664 language: &LanguageServerName,
12665 cx: &'a App,
12666) -> Option<&'a LspSettings> {
12667 ProjectSettings::get(Some(location), cx).lsp.get(language)
12668}
12669
12670pub struct LocalLspAdapterDelegate {
12671 lsp_store: WeakEntity<LspStore>,
12672 worktree: worktree::Snapshot,
12673 fs: Arc<dyn Fs>,
12674 http_client: Arc<dyn HttpClient>,
12675 language_registry: Arc<LanguageRegistry>,
12676 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
12677}
12678
12679impl LocalLspAdapterDelegate {
12680 pub fn new(
12681 language_registry: Arc<LanguageRegistry>,
12682 environment: &Entity<ProjectEnvironment>,
12683 lsp_store: WeakEntity<LspStore>,
12684 worktree: &Entity<Worktree>,
12685 http_client: Arc<dyn HttpClient>,
12686 fs: Arc<dyn Fs>,
12687 cx: &mut App,
12688 ) -> Arc<Self> {
12689 let load_shell_env_task = environment.update(cx, |env, cx| {
12690 env.get_worktree_environment(worktree.clone(), cx)
12691 });
12692
12693 Arc::new(Self {
12694 lsp_store,
12695 worktree: worktree.read(cx).snapshot(),
12696 fs,
12697 http_client,
12698 language_registry,
12699 load_shell_env_task,
12700 })
12701 }
12702
12703 fn from_local_lsp(
12704 local: &LocalLspStore,
12705 worktree: &Entity<Worktree>,
12706 cx: &mut App,
12707 ) -> Arc<Self> {
12708 Self::new(
12709 local.languages.clone(),
12710 &local.environment,
12711 local.weak.clone(),
12712 worktree,
12713 local.http_client.clone(),
12714 local.fs.clone(),
12715 cx,
12716 )
12717 }
12718}
12719
12720#[async_trait]
12721impl LspAdapterDelegate for LocalLspAdapterDelegate {
12722 fn show_notification(&self, message: &str, cx: &mut App) {
12723 self.lsp_store
12724 .update(cx, |_, cx| {
12725 cx.emit(LspStoreEvent::Notification(message.to_owned()))
12726 })
12727 .ok();
12728 }
12729
12730 fn http_client(&self) -> Arc<dyn HttpClient> {
12731 self.http_client.clone()
12732 }
12733
12734 fn worktree_id(&self) -> WorktreeId {
12735 self.worktree.id()
12736 }
12737
12738 fn worktree_root_path(&self) -> &Path {
12739 self.worktree.abs_path().as_ref()
12740 }
12741
12742 async fn shell_env(&self) -> HashMap<String, String> {
12743 let task = self.load_shell_env_task.clone();
12744 task.await.unwrap_or_default()
12745 }
12746
12747 async fn npm_package_installed_version(
12748 &self,
12749 package_name: &str,
12750 ) -> Result<Option<(PathBuf, String)>> {
12751 let local_package_directory = self.worktree_root_path();
12752 let node_modules_directory = local_package_directory.join("node_modules");
12753
12754 if let Some(version) =
12755 read_package_installed_version(node_modules_directory.clone(), package_name).await?
12756 {
12757 return Ok(Some((node_modules_directory, version)));
12758 }
12759 let Some(npm) = self.which("npm".as_ref()).await else {
12760 log::warn!(
12761 "Failed to find npm executable for {:?}",
12762 local_package_directory
12763 );
12764 return Ok(None);
12765 };
12766
12767 let env = self.shell_env().await;
12768 let output = util::command::new_smol_command(&npm)
12769 .args(["root", "-g"])
12770 .envs(env)
12771 .current_dir(local_package_directory)
12772 .output()
12773 .await?;
12774 let global_node_modules =
12775 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
12776
12777 if let Some(version) =
12778 read_package_installed_version(global_node_modules.clone(), package_name).await?
12779 {
12780 return Ok(Some((global_node_modules, version)));
12781 }
12782 return Ok(None);
12783 }
12784
12785 #[cfg(not(target_os = "windows"))]
12786 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12787 let worktree_abs_path = self.worktree.abs_path();
12788 let shell_path = self.shell_env().await.get("PATH").cloned();
12789 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
12790 }
12791
12792 #[cfg(target_os = "windows")]
12793 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12794 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
12795 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
12796 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
12797 which::which(command).ok()
12798 }
12799
12800 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
12801 let working_dir = self.worktree_root_path();
12802 let output = util::command::new_smol_command(&command.path)
12803 .args(command.arguments)
12804 .envs(command.env.clone().unwrap_or_default())
12805 .current_dir(working_dir)
12806 .output()
12807 .await?;
12808
12809 anyhow::ensure!(
12810 output.status.success(),
12811 "{}, stdout: {:?}, stderr: {:?}",
12812 output.status,
12813 String::from_utf8_lossy(&output.stdout),
12814 String::from_utf8_lossy(&output.stderr)
12815 );
12816 Ok(())
12817 }
12818
12819 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
12820 self.language_registry
12821 .update_lsp_binary_status(server_name, status);
12822 }
12823
12824 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
12825 self.language_registry
12826 .all_lsp_adapters()
12827 .into_iter()
12828 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
12829 .collect()
12830 }
12831
12832 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
12833 let dir = self.language_registry.language_server_download_dir(name)?;
12834
12835 if !dir.exists() {
12836 smol::fs::create_dir_all(&dir)
12837 .await
12838 .context("failed to create container directory")
12839 .log_err()?;
12840 }
12841
12842 Some(dir)
12843 }
12844
12845 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
12846 let entry = self
12847 .worktree
12848 .entry_for_path(&path)
12849 .with_context(|| format!("no worktree entry for path {path:?}"))?;
12850 let abs_path = self
12851 .worktree
12852 .absolutize(&entry.path)
12853 .with_context(|| format!("cannot absolutize path {path:?}"))?;
12854
12855 self.fs.load(&abs_path).await
12856 }
12857}
12858
12859async fn populate_labels_for_symbols(
12860 symbols: Vec<CoreSymbol>,
12861 language_registry: &Arc<LanguageRegistry>,
12862 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12863 output: &mut Vec<Symbol>,
12864) {
12865 #[allow(clippy::mutable_key_type)]
12866 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
12867
12868 let mut unknown_paths = BTreeSet::new();
12869 for symbol in symbols {
12870 let language = language_registry
12871 .language_for_file_path(&symbol.path.path)
12872 .await
12873 .ok()
12874 .or_else(|| {
12875 unknown_paths.insert(symbol.path.path.clone());
12876 None
12877 });
12878 symbols_by_language
12879 .entry(language)
12880 .or_default()
12881 .push(symbol);
12882 }
12883
12884 for unknown_path in unknown_paths {
12885 log::info!(
12886 "no language found for symbol path {}",
12887 unknown_path.display()
12888 );
12889 }
12890
12891 let mut label_params = Vec::new();
12892 for (language, mut symbols) in symbols_by_language {
12893 label_params.clear();
12894 label_params.extend(
12895 symbols
12896 .iter_mut()
12897 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
12898 );
12899
12900 let mut labels = Vec::new();
12901 if let Some(language) = language {
12902 let lsp_adapter = lsp_adapter.clone().or_else(|| {
12903 language_registry
12904 .lsp_adapters(&language.name())
12905 .first()
12906 .cloned()
12907 });
12908 if let Some(lsp_adapter) = lsp_adapter {
12909 labels = lsp_adapter
12910 .labels_for_symbols(&label_params, &language)
12911 .await
12912 .log_err()
12913 .unwrap_or_default();
12914 }
12915 }
12916
12917 for ((symbol, (name, _)), label) in symbols
12918 .into_iter()
12919 .zip(label_params.drain(..))
12920 .zip(labels.into_iter().chain(iter::repeat(None)))
12921 {
12922 output.push(Symbol {
12923 language_server_name: symbol.language_server_name,
12924 source_worktree_id: symbol.source_worktree_id,
12925 source_language_server_id: symbol.source_language_server_id,
12926 path: symbol.path,
12927 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
12928 name,
12929 kind: symbol.kind,
12930 range: symbol.range,
12931 signature: symbol.signature,
12932 });
12933 }
12934 }
12935}
12936
12937fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
12938 match server.capabilities().text_document_sync.as_ref()? {
12939 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
12940 // Server wants didSave but didn't specify includeText.
12941 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
12942 // Server doesn't want didSave at all.
12943 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
12944 // Server provided SaveOptions.
12945 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
12946 Some(save_options.include_text.unwrap_or(false))
12947 }
12948 },
12949 // We do not have any save info. Kind affects didChange only.
12950 lsp::TextDocumentSyncCapability::Kind(_) => None,
12951 }
12952}
12953
12954/// Completion items are displayed in a `UniformList`.
12955/// Usually, those items are single-line strings, but in LSP responses,
12956/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
12957/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
12958/// 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,
12959/// breaking the completions menu presentation.
12960///
12961/// 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.
12962fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
12963 let mut new_text = String::with_capacity(label.text.len());
12964 let mut offset_map = vec![0; label.text.len() + 1];
12965 let mut last_char_was_space = false;
12966 let mut new_idx = 0;
12967 let chars = label.text.char_indices().fuse();
12968 let mut newlines_removed = false;
12969
12970 for (idx, c) in chars {
12971 offset_map[idx] = new_idx;
12972
12973 match c {
12974 '\n' if last_char_was_space => {
12975 newlines_removed = true;
12976 }
12977 '\t' | ' ' if last_char_was_space => {}
12978 '\n' if !last_char_was_space => {
12979 new_text.push(' ');
12980 new_idx += 1;
12981 last_char_was_space = true;
12982 newlines_removed = true;
12983 }
12984 ' ' | '\t' => {
12985 new_text.push(' ');
12986 new_idx += 1;
12987 last_char_was_space = true;
12988 }
12989 _ => {
12990 new_text.push(c);
12991 new_idx += c.len_utf8();
12992 last_char_was_space = false;
12993 }
12994 }
12995 }
12996 offset_map[label.text.len()] = new_idx;
12997
12998 // Only modify the label if newlines were removed.
12999 if !newlines_removed {
13000 return;
13001 }
13002
13003 let last_index = new_idx;
13004 let mut run_ranges_errors = Vec::new();
13005 label.runs.retain_mut(|(range, _)| {
13006 match offset_map.get(range.start) {
13007 Some(&start) => range.start = start,
13008 None => {
13009 run_ranges_errors.push(range.clone());
13010 return false;
13011 }
13012 }
13013
13014 match offset_map.get(range.end) {
13015 Some(&end) => range.end = end,
13016 None => {
13017 run_ranges_errors.push(range.clone());
13018 range.end = last_index;
13019 }
13020 }
13021 true
13022 });
13023 if !run_ranges_errors.is_empty() {
13024 log::error!(
13025 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13026 label.text
13027 );
13028 }
13029
13030 let mut wrong_filter_range = None;
13031 if label.filter_range == (0..label.text.len()) {
13032 label.filter_range = 0..new_text.len();
13033 } else {
13034 let mut original_filter_range = Some(label.filter_range.clone());
13035 match offset_map.get(label.filter_range.start) {
13036 Some(&start) => label.filter_range.start = start,
13037 None => {
13038 wrong_filter_range = original_filter_range.take();
13039 label.filter_range.start = last_index;
13040 }
13041 }
13042
13043 match offset_map.get(label.filter_range.end) {
13044 Some(&end) => label.filter_range.end = end,
13045 None => {
13046 wrong_filter_range = original_filter_range.take();
13047 label.filter_range.end = last_index;
13048 }
13049 }
13050 }
13051 if let Some(wrong_filter_range) = wrong_filter_range {
13052 log::error!(
13053 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13054 label.text
13055 );
13056 }
13057
13058 label.text = new_text;
13059}
13060
13061#[cfg(test)]
13062mod tests {
13063 use language::HighlightId;
13064
13065 use super::*;
13066
13067 #[test]
13068 fn test_glob_literal_prefix() {
13069 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13070 assert_eq!(
13071 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13072 Path::new("node_modules")
13073 );
13074 assert_eq!(
13075 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13076 Path::new("foo")
13077 );
13078 assert_eq!(
13079 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13080 Path::new("foo/bar/baz.js")
13081 );
13082
13083 #[cfg(target_os = "windows")]
13084 {
13085 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13086 assert_eq!(
13087 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13088 Path::new("node_modules")
13089 );
13090 assert_eq!(
13091 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13092 Path::new("foo")
13093 );
13094 assert_eq!(
13095 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13096 Path::new("foo/bar/baz.js")
13097 );
13098 }
13099 }
13100
13101 #[test]
13102 fn test_multi_len_chars_normalization() {
13103 let mut label = CodeLabel {
13104 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13105 runs: vec![(0..6, HighlightId(1))],
13106 filter_range: 0..6,
13107 };
13108 ensure_uniform_list_compatible_label(&mut label);
13109 assert_eq!(
13110 label,
13111 CodeLabel {
13112 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13113 runs: vec![(0..6, HighlightId(1))],
13114 filter_range: 0..6,
13115 }
13116 );
13117 }
13118}