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