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