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