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