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