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