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;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 worktree_store::{WorktreeStore, WorktreeStoreEvent},
42 yarn::YarnPathStore,
43};
44use anyhow::{Context as _, Result, anyhow};
45use async_trait::async_trait;
46use client::{TypedEnvelope, proto};
47use clock::Global;
48use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
49use futures::{
50 AsyncWriteExt, Future, FutureExt, StreamExt,
51 future::{Either, Shared, join_all, pending, select},
52 select, select_biased,
53 stream::FuturesUnordered,
54};
55use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
56use gpui::{
57 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
58 WeakEntity,
59};
60use http_client::HttpClient;
61use itertools::Itertools as _;
62use language::{
63 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
64 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
65 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
66 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
67 Transaction, Unclipped,
68 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
69 point_to_lsp,
70 proto::{
71 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
72 serialize_lsp_edit, serialize_version,
73 },
74 range_from_lsp, range_to_lsp,
75 row_chunk::RowChunk,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use serde_json::Value;
97use settings::{Settings, SettingsLocation, SettingsStore};
98use sha2::{Digest, Sha256};
99use smol::channel::Sender;
100use snippet::Snippet;
101use std::{
102 any::TypeId,
103 borrow::Cow,
104 cell::RefCell,
105 cmp::{Ordering, Reverse},
106 convert::TryInto,
107 ffi::OsStr,
108 future::ready,
109 iter, mem,
110 ops::{ControlFlow, Range},
111 path::{self, Path, PathBuf},
112 pin::pin,
113 rc::Rc,
114 sync::{
115 Arc,
116 atomic::{self, AtomicUsize},
117 },
118 time::{Duration, Instant},
119 vec,
120};
121use sum_tree::Dimensions;
122use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
123
124use util::{
125 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
126 paths::{PathStyle, SanitizedPath},
127 post_inc,
128 rel_path::RelPath,
129};
130
131pub use fs::*;
132pub use language::Location;
133pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
134#[cfg(any(test, feature = "test-support"))]
135pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
136pub use worktree::{
137 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
138 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
139};
140
141const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
142pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
143const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
144const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
145
146#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
147pub enum ProgressToken {
148 Number(i32),
149 String(SharedString),
150}
151
152impl std::fmt::Display for ProgressToken {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 match self {
155 Self::Number(number) => write!(f, "{number}"),
156 Self::String(string) => write!(f, "{string}"),
157 }
158 }
159}
160
161impl ProgressToken {
162 fn from_lsp(value: lsp::NumberOrString) -> Self {
163 match value {
164 lsp::NumberOrString::Number(number) => Self::Number(number),
165 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
166 }
167 }
168
169 fn to_lsp(&self) -> lsp::NumberOrString {
170 match self {
171 Self::Number(number) => lsp::NumberOrString::Number(*number),
172 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
173 }
174 }
175
176 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
177 Some(match value.value? {
178 proto::progress_token::Value::Number(number) => Self::Number(number),
179 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
180 })
181 }
182
183 fn to_proto(&self) -> proto::ProgressToken {
184 proto::ProgressToken {
185 value: Some(match self {
186 Self::Number(number) => proto::progress_token::Value::Number(*number),
187 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
188 }),
189 }
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194pub enum FormatTrigger {
195 Save,
196 Manual,
197}
198
199pub enum LspFormatTarget {
200 Buffers,
201 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
202}
203
204pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
205
206impl FormatTrigger {
207 fn from_proto(value: i32) -> FormatTrigger {
208 match value {
209 0 => FormatTrigger::Save,
210 1 => FormatTrigger::Manual,
211 _ => FormatTrigger::Save,
212 }
213 }
214}
215
216#[derive(Clone)]
217struct UnifiedLanguageServer {
218 id: LanguageServerId,
219 project_roots: HashSet<Arc<RelPath>>,
220}
221
222#[derive(Clone, Hash, PartialEq, Eq)]
223struct LanguageServerSeed {
224 worktree_id: WorktreeId,
225 name: LanguageServerName,
226 toolchain: Option<Toolchain>,
227 settings: Arc<LspSettings>,
228}
229
230#[derive(Debug)]
231pub struct DocumentDiagnosticsUpdate<'a, D> {
232 pub diagnostics: D,
233 pub result_id: Option<SharedString>,
234 pub registration_id: Option<SharedString>,
235 pub server_id: LanguageServerId,
236 pub disk_based_sources: Cow<'a, [String]>,
237}
238
239pub struct DocumentDiagnostics {
240 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
241 document_abs_path: PathBuf,
242 version: Option<i32>,
243}
244
245#[derive(Default, Debug)]
246struct DynamicRegistrations {
247 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
248 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
249}
250
251pub struct LocalLspStore {
252 weak: WeakEntity<LspStore>,
253 worktree_store: Entity<WorktreeStore>,
254 toolchain_store: Entity<LocalToolchainStore>,
255 http_client: Arc<dyn HttpClient>,
256 environment: Entity<ProjectEnvironment>,
257 fs: Arc<dyn Fs>,
258 languages: Arc<LanguageRegistry>,
259 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
260 yarn: Entity<YarnPathStore>,
261 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
262 buffers_being_formatted: HashSet<BufferId>,
263 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
264 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
265 watched_manifest_filenames: HashSet<ManifestName>,
266 language_server_paths_watched_for_rename:
267 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
268 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
269 supplementary_language_servers:
270 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
271 prettier_store: Entity<PrettierStore>,
272 next_diagnostic_group_id: usize,
273 diagnostics: HashMap<
274 WorktreeId,
275 HashMap<
276 Arc<RelPath>,
277 Vec<(
278 LanguageServerId,
279 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
280 )>,
281 >,
282 >,
283 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
284 _subscription: gpui::Subscription,
285 lsp_tree: LanguageServerTree,
286 registered_buffers: HashMap<BufferId, usize>,
287 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
288 buffer_pull_diagnostics_result_ids: HashMap<
289 LanguageServerId,
290 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
291 >,
292 workspace_pull_diagnostics_result_ids: HashMap<
293 LanguageServerId,
294 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
295 >,
296}
297
298impl LocalLspStore {
299 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
300 pub fn running_language_server_for_id(
301 &self,
302 id: LanguageServerId,
303 ) -> Option<&Arc<LanguageServer>> {
304 let language_server_state = self.language_servers.get(&id)?;
305
306 match language_server_state {
307 LanguageServerState::Running { server, .. } => Some(server),
308 LanguageServerState::Starting { .. } => None,
309 }
310 }
311
312 fn get_or_insert_language_server(
313 &mut self,
314 worktree_handle: &Entity<Worktree>,
315 delegate: Arc<LocalLspAdapterDelegate>,
316 disposition: &Arc<LaunchDisposition>,
317 language_name: &LanguageName,
318 cx: &mut App,
319 ) -> LanguageServerId {
320 let key = LanguageServerSeed {
321 worktree_id: worktree_handle.read(cx).id(),
322 name: disposition.server_name.clone(),
323 settings: disposition.settings.clone(),
324 toolchain: disposition.toolchain.clone(),
325 };
326 if let Some(state) = self.language_server_ids.get_mut(&key) {
327 state.project_roots.insert(disposition.path.path.clone());
328 state.id
329 } else {
330 let adapter = self
331 .languages
332 .lsp_adapters(language_name)
333 .into_iter()
334 .find(|adapter| adapter.name() == disposition.server_name)
335 .expect("To find LSP adapter");
336 let new_language_server_id = self.start_language_server(
337 worktree_handle,
338 delegate,
339 adapter,
340 disposition.settings.clone(),
341 key.clone(),
342 cx,
343 );
344 if let Some(state) = self.language_server_ids.get_mut(&key) {
345 state.project_roots.insert(disposition.path.path.clone());
346 } else {
347 debug_assert!(
348 false,
349 "Expected `start_language_server` to ensure that `key` exists in a map"
350 );
351 }
352 new_language_server_id
353 }
354 }
355
356 fn start_language_server(
357 &mut self,
358 worktree_handle: &Entity<Worktree>,
359 delegate: Arc<LocalLspAdapterDelegate>,
360 adapter: Arc<CachedLspAdapter>,
361 settings: Arc<LspSettings>,
362 key: LanguageServerSeed,
363 cx: &mut App,
364 ) -> LanguageServerId {
365 let worktree = worktree_handle.read(cx);
366
367 let root_path = worktree.abs_path();
368 let toolchain = key.toolchain.clone();
369 let override_options = settings.initialization_options.clone();
370
371 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
372
373 let server_id = self.languages.next_language_server_id();
374 log::trace!(
375 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
376 adapter.name.0
377 );
378
379 let binary = self.get_language_server_binary(
380 adapter.clone(),
381 settings,
382 toolchain.clone(),
383 delegate.clone(),
384 true,
385 cx,
386 );
387 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
388
389 let pending_server = cx.spawn({
390 let adapter = adapter.clone();
391 let server_name = adapter.name.clone();
392 let stderr_capture = stderr_capture.clone();
393 #[cfg(any(test, feature = "test-support"))]
394 let lsp_store = self.weak.clone();
395 let pending_workspace_folders = pending_workspace_folders.clone();
396 async move |cx| {
397 let binary = binary.await?;
398 #[cfg(any(test, feature = "test-support"))]
399 if let Some(server) = lsp_store
400 .update(&mut cx.clone(), |this, cx| {
401 this.languages.create_fake_language_server(
402 server_id,
403 &server_name,
404 binary.clone(),
405 &mut cx.to_async(),
406 )
407 })
408 .ok()
409 .flatten()
410 {
411 return Ok(server);
412 }
413
414 let code_action_kinds = adapter.code_action_kinds();
415 lsp::LanguageServer::new(
416 stderr_capture,
417 server_id,
418 server_name,
419 binary,
420 &root_path,
421 code_action_kinds,
422 Some(pending_workspace_folders),
423 cx,
424 )
425 }
426 });
427
428 let startup = {
429 let server_name = adapter.name.0.clone();
430 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
431 let key = key.clone();
432 let adapter = adapter.clone();
433 let lsp_store = self.weak.clone();
434 let pending_workspace_folders = pending_workspace_folders.clone();
435
436 let pull_diagnostics = ProjectSettings::get_global(cx)
437 .diagnostics
438 .lsp_pull_diagnostics
439 .enabled;
440 cx.spawn(async move |cx| {
441 let result = async {
442 let language_server = pending_server.await?;
443
444 let workspace_config = Self::workspace_configuration_for_adapter(
445 adapter.adapter.clone(),
446 &delegate,
447 toolchain,
448 None,
449 cx,
450 )
451 .await?;
452
453 let mut initialization_options = Self::initialization_options_for_adapter(
454 adapter.adapter.clone(),
455 &delegate,
456 )
457 .await?;
458
459 match (&mut initialization_options, override_options) {
460 (Some(initialization_options), Some(override_options)) => {
461 merge_json_value_into(override_options, initialization_options);
462 }
463 (None, override_options) => initialization_options = override_options,
464 _ => {}
465 }
466
467 let initialization_params = cx.update(|cx| {
468 let mut params =
469 language_server.default_initialize_params(pull_diagnostics, cx);
470 params.initialization_options = initialization_options;
471 adapter.adapter.prepare_initialize_params(params, cx)
472 })??;
473
474 Self::setup_lsp_messages(
475 lsp_store.clone(),
476 &language_server,
477 delegate.clone(),
478 adapter.clone(),
479 );
480
481 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
482 settings: workspace_config,
483 };
484 let language_server = cx
485 .update(|cx| {
486 language_server.initialize(
487 initialization_params,
488 Arc::new(did_change_configuration_params.clone()),
489 cx,
490 )
491 })?
492 .await
493 .inspect_err(|_| {
494 if let Some(lsp_store) = lsp_store.upgrade() {
495 lsp_store
496 .update(cx, |lsp_store, cx| {
497 lsp_store.cleanup_lsp_data(server_id);
498 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
499 })
500 .ok();
501 }
502 })?;
503
504 language_server.notify::<lsp::notification::DidChangeConfiguration>(
505 did_change_configuration_params,
506 )?;
507
508 anyhow::Ok(language_server)
509 }
510 .await;
511
512 match result {
513 Ok(server) => {
514 lsp_store
515 .update(cx, |lsp_store, cx| {
516 lsp_store.insert_newly_running_language_server(
517 adapter,
518 server.clone(),
519 server_id,
520 key,
521 pending_workspace_folders,
522 cx,
523 );
524 })
525 .ok();
526 stderr_capture.lock().take();
527 Some(server)
528 }
529
530 Err(err) => {
531 let log = stderr_capture.lock().take().unwrap_or_default();
532 delegate.update_status(
533 adapter.name(),
534 BinaryStatus::Failed {
535 error: if log.is_empty() {
536 format!("{err:#}")
537 } else {
538 format!("{err:#}\n-- stderr --\n{log}")
539 },
540 },
541 );
542 log::error!("Failed to start language server {server_name:?}: {err:?}");
543 if !log.is_empty() {
544 log::error!("server stderr: {log}");
545 }
546 None
547 }
548 }
549 })
550 };
551 let state = LanguageServerState::Starting {
552 startup,
553 pending_workspace_folders,
554 };
555
556 self.languages
557 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
558
559 self.language_servers.insert(server_id, state);
560 self.language_server_ids
561 .entry(key)
562 .or_insert(UnifiedLanguageServer {
563 id: server_id,
564 project_roots: Default::default(),
565 });
566 server_id
567 }
568
569 fn get_language_server_binary(
570 &self,
571 adapter: Arc<CachedLspAdapter>,
572 settings: Arc<LspSettings>,
573 toolchain: Option<Toolchain>,
574 delegate: Arc<dyn LspAdapterDelegate>,
575 allow_binary_download: bool,
576 cx: &mut App,
577 ) -> Task<Result<LanguageServerBinary>> {
578 if let Some(settings) = &settings.binary
579 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
580 {
581 let settings = settings.clone();
582
583 return cx.background_spawn(async move {
584 let mut env = delegate.shell_env().await;
585 env.extend(settings.env.unwrap_or_default());
586
587 Ok(LanguageServerBinary {
588 path: delegate.resolve_executable_path(path),
589 env: Some(env),
590 arguments: settings
591 .arguments
592 .unwrap_or_default()
593 .iter()
594 .map(Into::into)
595 .collect(),
596 })
597 });
598 }
599 let lsp_binary_options = LanguageServerBinaryOptions {
600 allow_path_lookup: !settings
601 .binary
602 .as_ref()
603 .and_then(|b| b.ignore_system_version)
604 .unwrap_or_default(),
605 allow_binary_download,
606 pre_release: settings
607 .fetch
608 .as_ref()
609 .and_then(|f| f.pre_release)
610 .unwrap_or(false),
611 };
612
613 cx.spawn(async move |cx| {
614 let (existing_binary, maybe_download_binary) = adapter
615 .clone()
616 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
617 .await
618 .await;
619
620 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
621
622 let mut binary = match (existing_binary, maybe_download_binary) {
623 (binary, None) => binary?,
624 (Err(_), Some(downloader)) => downloader.await?,
625 (Ok(existing_binary), Some(downloader)) => {
626 let mut download_timeout = cx
627 .background_executor()
628 .timer(SERVER_DOWNLOAD_TIMEOUT)
629 .fuse();
630 let mut downloader = downloader.fuse();
631 futures::select! {
632 _ = download_timeout => {
633 // Return existing binary and kick the existing work to the background.
634 cx.spawn(async move |_| downloader.await).detach();
635 Ok(existing_binary)
636 },
637 downloaded_or_existing_binary = downloader => {
638 // If download fails, this results in the existing binary.
639 downloaded_or_existing_binary
640 }
641 }?
642 }
643 };
644 let mut shell_env = delegate.shell_env().await;
645
646 shell_env.extend(binary.env.unwrap_or_default());
647
648 if let Some(settings) = settings.binary.as_ref() {
649 if let Some(arguments) = &settings.arguments {
650 binary.arguments = arguments.iter().map(Into::into).collect();
651 }
652 if let Some(env) = &settings.env {
653 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
654 }
655 }
656
657 binary.env = Some(shell_env);
658 Ok(binary)
659 })
660 }
661
662 fn setup_lsp_messages(
663 lsp_store: WeakEntity<LspStore>,
664 language_server: &LanguageServer,
665 delegate: Arc<dyn LspAdapterDelegate>,
666 adapter: Arc<CachedLspAdapter>,
667 ) {
668 let name = language_server.name();
669 let server_id = language_server.server_id();
670 language_server
671 .on_notification::<lsp::notification::PublishDiagnostics, _>({
672 let adapter = adapter.clone();
673 let this = lsp_store.clone();
674 move |mut params, cx| {
675 let adapter = adapter.clone();
676 if let Some(this) = this.upgrade() {
677 this.update(cx, |this, cx| {
678 {
679 let buffer = params
680 .uri
681 .to_file_path()
682 .map(|file_path| this.get_buffer(&file_path, cx))
683 .ok()
684 .flatten();
685 adapter.process_diagnostics(&mut params, server_id, buffer);
686 }
687
688 this.merge_lsp_diagnostics(
689 DiagnosticSourceKind::Pushed,
690 vec![DocumentDiagnosticsUpdate {
691 server_id,
692 diagnostics: params,
693 result_id: None,
694 disk_based_sources: Cow::Borrowed(
695 &adapter.disk_based_diagnostic_sources,
696 ),
697 registration_id: None,
698 }],
699 |_, diagnostic, cx| match diagnostic.source_kind {
700 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
701 adapter.retain_old_diagnostic(diagnostic, cx)
702 }
703 DiagnosticSourceKind::Pulled => true,
704 },
705 cx,
706 )
707 .log_err();
708 })
709 .ok();
710 }
711 }
712 })
713 .detach();
714 language_server
715 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
716 let adapter = adapter.adapter.clone();
717 let delegate = delegate.clone();
718 let this = lsp_store.clone();
719 move |params, cx| {
720 let adapter = adapter.clone();
721 let delegate = delegate.clone();
722 let this = this.clone();
723 let mut cx = cx.clone();
724 async move {
725 let toolchain_for_id = this
726 .update(&mut cx, |this, _| {
727 this.as_local()?.language_server_ids.iter().find_map(
728 |(seed, value)| {
729 (value.id == server_id).then(|| seed.toolchain.clone())
730 },
731 )
732 })?
733 .context("Expected the LSP store to be in a local mode")?;
734
735 let mut scope_uri_to_workspace_config = BTreeMap::new();
736 for item in ¶ms.items {
737 let scope_uri = item.scope_uri.clone();
738 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
739 scope_uri_to_workspace_config.entry(scope_uri.clone())
740 else {
741 // We've already queried workspace configuration of this URI.
742 continue;
743 };
744 let workspace_config = Self::workspace_configuration_for_adapter(
745 adapter.clone(),
746 &delegate,
747 toolchain_for_id.clone(),
748 scope_uri,
749 &mut cx,
750 )
751 .await?;
752 new_scope_uri.insert(workspace_config);
753 }
754
755 Ok(params
756 .items
757 .into_iter()
758 .filter_map(|item| {
759 let workspace_config =
760 scope_uri_to_workspace_config.get(&item.scope_uri)?;
761 if let Some(section) = &item.section {
762 Some(
763 workspace_config
764 .get(section)
765 .cloned()
766 .unwrap_or(serde_json::Value::Null),
767 )
768 } else {
769 Some(workspace_config.clone())
770 }
771 })
772 .collect())
773 }
774 }
775 })
776 .detach();
777
778 language_server
779 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
780 let this = lsp_store.clone();
781 move |_, cx| {
782 let this = this.clone();
783 let cx = cx.clone();
784 async move {
785 let Some(server) =
786 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
787 else {
788 return Ok(None);
789 };
790 let root = server.workspace_folders();
791 Ok(Some(
792 root.into_iter()
793 .map(|uri| WorkspaceFolder {
794 uri,
795 name: Default::default(),
796 })
797 .collect(),
798 ))
799 }
800 }
801 })
802 .detach();
803 // Even though we don't have handling for these requests, respond to them to
804 // avoid stalling any language server like `gopls` which waits for a response
805 // to these requests when initializing.
806 language_server
807 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
808 let this = lsp_store.clone();
809 move |params, cx| {
810 let this = this.clone();
811 let mut cx = cx.clone();
812 async move {
813 this.update(&mut cx, |this, _| {
814 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
815 {
816 status
817 .progress_tokens
818 .insert(ProgressToken::from_lsp(params.token));
819 }
820 })?;
821
822 Ok(())
823 }
824 }
825 })
826 .detach();
827
828 language_server
829 .on_request::<lsp::request::RegisterCapability, _, _>({
830 let lsp_store = lsp_store.clone();
831 move |params, cx| {
832 let lsp_store = lsp_store.clone();
833 let mut cx = cx.clone();
834 async move {
835 lsp_store
836 .update(&mut cx, |lsp_store, cx| {
837 if lsp_store.as_local().is_some() {
838 match lsp_store
839 .register_server_capabilities(server_id, params, cx)
840 {
841 Ok(()) => {}
842 Err(e) => {
843 log::error!(
844 "Failed to register server capabilities: {e:#}"
845 );
846 }
847 };
848 }
849 })
850 .ok();
851 Ok(())
852 }
853 }
854 })
855 .detach();
856
857 language_server
858 .on_request::<lsp::request::UnregisterCapability, _, _>({
859 let lsp_store = lsp_store.clone();
860 move |params, cx| {
861 let lsp_store = lsp_store.clone();
862 let mut cx = cx.clone();
863 async move {
864 lsp_store
865 .update(&mut cx, |lsp_store, cx| {
866 if lsp_store.as_local().is_some() {
867 match lsp_store
868 .unregister_server_capabilities(server_id, params, cx)
869 {
870 Ok(()) => {}
871 Err(e) => {
872 log::error!(
873 "Failed to unregister server capabilities: {e:#}"
874 );
875 }
876 }
877 }
878 })
879 .ok();
880 Ok(())
881 }
882 }
883 })
884 .detach();
885
886 language_server
887 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
888 let this = lsp_store.clone();
889 move |params, cx| {
890 let mut cx = cx.clone();
891 let this = this.clone();
892 async move {
893 LocalLspStore::on_lsp_workspace_edit(
894 this.clone(),
895 params,
896 server_id,
897 &mut cx,
898 )
899 .await
900 }
901 }
902 })
903 .detach();
904
905 language_server
906 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
907 let lsp_store = lsp_store.clone();
908 let request_id = Arc::new(AtomicUsize::new(0));
909 move |(), cx| {
910 let lsp_store = lsp_store.clone();
911 let request_id = request_id.clone();
912 let mut cx = cx.clone();
913 async move {
914 lsp_store
915 .update(&mut cx, |lsp_store, cx| {
916 let request_id =
917 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
918 cx.emit(LspStoreEvent::RefreshInlayHints {
919 server_id,
920 request_id,
921 });
922 lsp_store
923 .downstream_client
924 .as_ref()
925 .map(|(client, project_id)| {
926 client.send(proto::RefreshInlayHints {
927 project_id: *project_id,
928 server_id: server_id.to_proto(),
929 request_id: request_id.map(|id| id as u64),
930 })
931 })
932 })?
933 .transpose()?;
934 Ok(())
935 }
936 }
937 })
938 .detach();
939
940 language_server
941 .on_request::<lsp::request::CodeLensRefresh, _, _>({
942 let this = lsp_store.clone();
943 move |(), cx| {
944 let this = this.clone();
945 let mut cx = cx.clone();
946 async move {
947 this.update(&mut cx, |this, cx| {
948 cx.emit(LspStoreEvent::RefreshCodeLens);
949 this.downstream_client.as_ref().map(|(client, project_id)| {
950 client.send(proto::RefreshCodeLens {
951 project_id: *project_id,
952 })
953 })
954 })?
955 .transpose()?;
956 Ok(())
957 }
958 }
959 })
960 .detach();
961
962 language_server
963 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
964 let this = lsp_store.clone();
965 move |(), cx| {
966 let this = this.clone();
967 let mut cx = cx.clone();
968 async move {
969 this.update(&mut cx, |lsp_store, _| {
970 lsp_store.pull_workspace_diagnostics(server_id);
971 lsp_store
972 .downstream_client
973 .as_ref()
974 .map(|(client, project_id)| {
975 client.send(proto::PullWorkspaceDiagnostics {
976 project_id: *project_id,
977 server_id: server_id.to_proto(),
978 })
979 })
980 })?
981 .transpose()?;
982 Ok(())
983 }
984 }
985 })
986 .detach();
987
988 language_server
989 .on_request::<lsp::request::ShowMessageRequest, _, _>({
990 let this = lsp_store.clone();
991 let name = name.to_string();
992 move |params, cx| {
993 let this = this.clone();
994 let name = name.to_string();
995 let mut cx = cx.clone();
996 async move {
997 let actions = params.actions.unwrap_or_default();
998 let (tx, rx) = smol::channel::bounded(1);
999 let request = LanguageServerPromptRequest {
1000 level: match params.typ {
1001 lsp::MessageType::ERROR => PromptLevel::Critical,
1002 lsp::MessageType::WARNING => PromptLevel::Warning,
1003 _ => PromptLevel::Info,
1004 },
1005 message: params.message,
1006 actions,
1007 response_channel: tx,
1008 lsp_name: name.clone(),
1009 };
1010
1011 let did_update = this
1012 .update(&mut cx, |_, cx| {
1013 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1014 })
1015 .is_ok();
1016 if did_update {
1017 let response = rx.recv().await.ok();
1018 Ok(response)
1019 } else {
1020 Ok(None)
1021 }
1022 }
1023 }
1024 })
1025 .detach();
1026 language_server
1027 .on_notification::<lsp::notification::ShowMessage, _>({
1028 let this = lsp_store.clone();
1029 let name = name.to_string();
1030 move |params, cx| {
1031 let this = this.clone();
1032 let name = name.to_string();
1033 let mut cx = cx.clone();
1034
1035 let (tx, _) = smol::channel::bounded(1);
1036 let request = LanguageServerPromptRequest {
1037 level: match params.typ {
1038 lsp::MessageType::ERROR => PromptLevel::Critical,
1039 lsp::MessageType::WARNING => PromptLevel::Warning,
1040 _ => PromptLevel::Info,
1041 },
1042 message: params.message,
1043 actions: vec![],
1044 response_channel: tx,
1045 lsp_name: name,
1046 };
1047
1048 let _ = this.update(&mut cx, |_, cx| {
1049 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1050 });
1051 }
1052 })
1053 .detach();
1054
1055 let disk_based_diagnostics_progress_token =
1056 adapter.disk_based_diagnostics_progress_token.clone();
1057
1058 language_server
1059 .on_notification::<lsp::notification::Progress, _>({
1060 let this = lsp_store.clone();
1061 move |params, cx| {
1062 if let Some(this) = this.upgrade() {
1063 this.update(cx, |this, cx| {
1064 this.on_lsp_progress(
1065 params,
1066 server_id,
1067 disk_based_diagnostics_progress_token.clone(),
1068 cx,
1069 );
1070 })
1071 .ok();
1072 }
1073 }
1074 })
1075 .detach();
1076
1077 language_server
1078 .on_notification::<lsp::notification::LogMessage, _>({
1079 let this = lsp_store.clone();
1080 move |params, cx| {
1081 if let Some(this) = this.upgrade() {
1082 this.update(cx, |_, cx| {
1083 cx.emit(LspStoreEvent::LanguageServerLog(
1084 server_id,
1085 LanguageServerLogType::Log(params.typ),
1086 params.message,
1087 ));
1088 })
1089 .ok();
1090 }
1091 }
1092 })
1093 .detach();
1094
1095 language_server
1096 .on_notification::<lsp::notification::LogTrace, _>({
1097 let this = lsp_store.clone();
1098 move |params, cx| {
1099 let mut cx = cx.clone();
1100 if let Some(this) = this.upgrade() {
1101 this.update(&mut cx, |_, cx| {
1102 cx.emit(LspStoreEvent::LanguageServerLog(
1103 server_id,
1104 LanguageServerLogType::Trace {
1105 verbose_info: params.verbose,
1106 },
1107 params.message,
1108 ));
1109 })
1110 .ok();
1111 }
1112 }
1113 })
1114 .detach();
1115
1116 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1117 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1118 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1119 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1120 }
1121
1122 fn shutdown_language_servers_on_quit(
1123 &mut self,
1124 _: &mut Context<LspStore>,
1125 ) -> impl Future<Output = ()> + use<> {
1126 let shutdown_futures = self
1127 .language_servers
1128 .drain()
1129 .map(|(_, server_state)| Self::shutdown_server(server_state))
1130 .collect::<Vec<_>>();
1131
1132 async move {
1133 join_all(shutdown_futures).await;
1134 }
1135 }
1136
1137 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1138 match server_state {
1139 LanguageServerState::Running { server, .. } => {
1140 if let Some(shutdown) = server.shutdown() {
1141 shutdown.await;
1142 }
1143 }
1144 LanguageServerState::Starting { startup, .. } => {
1145 if let Some(server) = startup.await
1146 && let Some(shutdown) = server.shutdown()
1147 {
1148 shutdown.await;
1149 }
1150 }
1151 }
1152 Ok(())
1153 }
1154
1155 fn language_servers_for_worktree(
1156 &self,
1157 worktree_id: WorktreeId,
1158 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1159 self.language_server_ids
1160 .iter()
1161 .filter_map(move |(seed, state)| {
1162 if seed.worktree_id != worktree_id {
1163 return None;
1164 }
1165
1166 if let Some(LanguageServerState::Running { server, .. }) =
1167 self.language_servers.get(&state.id)
1168 {
1169 Some(server)
1170 } else {
1171 None
1172 }
1173 })
1174 }
1175
1176 fn language_server_ids_for_project_path(
1177 &self,
1178 project_path: ProjectPath,
1179 language: &Language,
1180 cx: &mut App,
1181 ) -> Vec<LanguageServerId> {
1182 let Some(worktree) = self
1183 .worktree_store
1184 .read(cx)
1185 .worktree_for_id(project_path.worktree_id, cx)
1186 else {
1187 return Vec::new();
1188 };
1189 let delegate: Arc<dyn ManifestDelegate> =
1190 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1191
1192 self.lsp_tree
1193 .get(
1194 project_path,
1195 language.name(),
1196 language.manifest(),
1197 &delegate,
1198 cx,
1199 )
1200 .collect::<Vec<_>>()
1201 }
1202
1203 fn language_server_ids_for_buffer(
1204 &self,
1205 buffer: &Buffer,
1206 cx: &mut App,
1207 ) -> Vec<LanguageServerId> {
1208 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1209 let worktree_id = file.worktree_id(cx);
1210
1211 let path: Arc<RelPath> = file
1212 .path()
1213 .parent()
1214 .map(Arc::from)
1215 .unwrap_or_else(|| file.path().clone());
1216 let worktree_path = ProjectPath { worktree_id, path };
1217 self.language_server_ids_for_project_path(worktree_path, language, cx)
1218 } else {
1219 Vec::new()
1220 }
1221 }
1222
1223 fn language_servers_for_buffer<'a>(
1224 &'a self,
1225 buffer: &'a Buffer,
1226 cx: &'a mut App,
1227 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1228 self.language_server_ids_for_buffer(buffer, cx)
1229 .into_iter()
1230 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1231 LanguageServerState::Running {
1232 adapter, server, ..
1233 } => Some((adapter, server)),
1234 _ => None,
1235 })
1236 }
1237
1238 async fn execute_code_action_kind_locally(
1239 lsp_store: WeakEntity<LspStore>,
1240 mut buffers: Vec<Entity<Buffer>>,
1241 kind: CodeActionKind,
1242 push_to_history: bool,
1243 cx: &mut AsyncApp,
1244 ) -> anyhow::Result<ProjectTransaction> {
1245 // Do not allow multiple concurrent code actions requests for the
1246 // same buffer.
1247 lsp_store.update(cx, |this, cx| {
1248 let this = this.as_local_mut().unwrap();
1249 buffers.retain(|buffer| {
1250 this.buffers_being_formatted
1251 .insert(buffer.read(cx).remote_id())
1252 });
1253 })?;
1254 let _cleanup = defer({
1255 let this = lsp_store.clone();
1256 let mut cx = cx.clone();
1257 let buffers = &buffers;
1258 move || {
1259 this.update(&mut cx, |this, cx| {
1260 let this = this.as_local_mut().unwrap();
1261 for buffer in buffers {
1262 this.buffers_being_formatted
1263 .remove(&buffer.read(cx).remote_id());
1264 }
1265 })
1266 .ok();
1267 }
1268 });
1269 let mut project_transaction = ProjectTransaction::default();
1270
1271 for buffer in &buffers {
1272 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1273 buffer.update(cx, |buffer, cx| {
1274 lsp_store
1275 .as_local()
1276 .unwrap()
1277 .language_servers_for_buffer(buffer, cx)
1278 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1279 .collect::<Vec<_>>()
1280 })
1281 })?;
1282 for (_, language_server) in adapters_and_servers.iter() {
1283 let actions = Self::get_server_code_actions_from_action_kinds(
1284 &lsp_store,
1285 language_server.server_id(),
1286 vec![kind.clone()],
1287 buffer,
1288 cx,
1289 )
1290 .await?;
1291 Self::execute_code_actions_on_server(
1292 &lsp_store,
1293 language_server,
1294 actions,
1295 push_to_history,
1296 &mut project_transaction,
1297 cx,
1298 )
1299 .await?;
1300 }
1301 }
1302 Ok(project_transaction)
1303 }
1304
1305 async fn format_locally(
1306 lsp_store: WeakEntity<LspStore>,
1307 mut buffers: Vec<FormattableBuffer>,
1308 push_to_history: bool,
1309 trigger: FormatTrigger,
1310 logger: zlog::Logger,
1311 cx: &mut AsyncApp,
1312 ) -> anyhow::Result<ProjectTransaction> {
1313 // Do not allow multiple concurrent formatting requests for the
1314 // same buffer.
1315 lsp_store.update(cx, |this, cx| {
1316 let this = this.as_local_mut().unwrap();
1317 buffers.retain(|buffer| {
1318 this.buffers_being_formatted
1319 .insert(buffer.handle.read(cx).remote_id())
1320 });
1321 })?;
1322
1323 let _cleanup = defer({
1324 let this = lsp_store.clone();
1325 let mut cx = cx.clone();
1326 let buffers = &buffers;
1327 move || {
1328 this.update(&mut cx, |this, cx| {
1329 let this = this.as_local_mut().unwrap();
1330 for buffer in buffers {
1331 this.buffers_being_formatted
1332 .remove(&buffer.handle.read(cx).remote_id());
1333 }
1334 })
1335 .ok();
1336 }
1337 });
1338
1339 let mut project_transaction = ProjectTransaction::default();
1340
1341 for buffer in &buffers {
1342 zlog::debug!(
1343 logger =>
1344 "formatting buffer '{:?}'",
1345 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1346 );
1347 // Create an empty transaction to hold all of the formatting edits.
1348 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1349 // ensure no transactions created while formatting are
1350 // grouped with the previous transaction in the history
1351 // based on the transaction group interval
1352 buffer.finalize_last_transaction();
1353 buffer
1354 .start_transaction()
1355 .context("transaction already open")?;
1356 buffer.end_transaction(cx);
1357 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1358 buffer.finalize_last_transaction();
1359 anyhow::Ok(transaction_id)
1360 })??;
1361
1362 let result = Self::format_buffer_locally(
1363 lsp_store.clone(),
1364 buffer,
1365 formatting_transaction_id,
1366 trigger,
1367 logger,
1368 cx,
1369 )
1370 .await;
1371
1372 buffer.handle.update(cx, |buffer, cx| {
1373 let Some(formatting_transaction) =
1374 buffer.get_transaction(formatting_transaction_id).cloned()
1375 else {
1376 zlog::warn!(logger => "no formatting transaction");
1377 return;
1378 };
1379 if formatting_transaction.edit_ids.is_empty() {
1380 zlog::debug!(logger => "no changes made while formatting");
1381 buffer.forget_transaction(formatting_transaction_id);
1382 return;
1383 }
1384 if !push_to_history {
1385 zlog::trace!(logger => "forgetting format transaction");
1386 buffer.forget_transaction(formatting_transaction.id);
1387 }
1388 project_transaction
1389 .0
1390 .insert(cx.entity(), formatting_transaction);
1391 })?;
1392
1393 result?;
1394 }
1395
1396 Ok(project_transaction)
1397 }
1398
1399 async fn format_buffer_locally(
1400 lsp_store: WeakEntity<LspStore>,
1401 buffer: &FormattableBuffer,
1402 formatting_transaction_id: clock::Lamport,
1403 trigger: FormatTrigger,
1404 logger: zlog::Logger,
1405 cx: &mut AsyncApp,
1406 ) -> Result<()> {
1407 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1408 buffer.handle.update(cx, |buffer, cx| {
1409 let adapters_and_servers = lsp_store
1410 .as_local()
1411 .unwrap()
1412 .language_servers_for_buffer(buffer, cx)
1413 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1414 .collect::<Vec<_>>();
1415 let settings =
1416 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1417 .into_owned();
1418 (adapters_and_servers, settings)
1419 })
1420 })?;
1421
1422 /// Apply edits to the buffer that will become part of the formatting transaction.
1423 /// Fails if the buffer has been edited since the start of that transaction.
1424 fn extend_formatting_transaction(
1425 buffer: &FormattableBuffer,
1426 formatting_transaction_id: text::TransactionId,
1427 cx: &mut AsyncApp,
1428 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1429 ) -> anyhow::Result<()> {
1430 buffer.handle.update(cx, |buffer, cx| {
1431 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1432 if last_transaction_id != Some(formatting_transaction_id) {
1433 anyhow::bail!("Buffer edited while formatting. Aborting")
1434 }
1435 buffer.start_transaction();
1436 operation(buffer, cx);
1437 if let Some(transaction_id) = buffer.end_transaction(cx) {
1438 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1439 }
1440 Ok(())
1441 })?
1442 }
1443
1444 // handle whitespace formatting
1445 if settings.remove_trailing_whitespace_on_save {
1446 zlog::trace!(logger => "removing trailing whitespace");
1447 let diff = buffer
1448 .handle
1449 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1450 .await;
1451 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1452 buffer.apply_diff(diff, cx);
1453 })?;
1454 }
1455
1456 if settings.ensure_final_newline_on_save {
1457 zlog::trace!(logger => "ensuring final newline");
1458 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1459 buffer.ensure_final_newline(cx);
1460 })?;
1461 }
1462
1463 // Formatter for `code_actions_on_format` that runs before
1464 // the rest of the formatters
1465 let mut code_actions_on_format_formatters = None;
1466 let should_run_code_actions_on_format = !matches!(
1467 (trigger, &settings.format_on_save),
1468 (FormatTrigger::Save, &FormatOnSave::Off)
1469 );
1470 if should_run_code_actions_on_format {
1471 let have_code_actions_to_run_on_format = settings
1472 .code_actions_on_format
1473 .values()
1474 .any(|enabled| *enabled);
1475 if have_code_actions_to_run_on_format {
1476 zlog::trace!(logger => "going to run code actions on format");
1477 code_actions_on_format_formatters = Some(
1478 settings
1479 .code_actions_on_format
1480 .iter()
1481 .filter_map(|(action, enabled)| enabled.then_some(action))
1482 .cloned()
1483 .map(Formatter::CodeAction)
1484 .collect::<Vec<_>>(),
1485 );
1486 }
1487 }
1488
1489 let formatters = match (trigger, &settings.format_on_save) {
1490 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1491 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1492 settings.formatter.as_ref()
1493 }
1494 };
1495
1496 let formatters = code_actions_on_format_formatters
1497 .iter()
1498 .flatten()
1499 .chain(formatters);
1500
1501 for formatter in formatters {
1502 let formatter = if formatter == &Formatter::Auto {
1503 if settings.prettier.allowed {
1504 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1505 &Formatter::Prettier
1506 } else {
1507 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1508 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1509 }
1510 } else {
1511 formatter
1512 };
1513 match formatter {
1514 Formatter::Auto => unreachable!("Auto resolved above"),
1515 Formatter::Prettier => {
1516 let logger = zlog::scoped!(logger => "prettier");
1517 zlog::trace!(logger => "formatting");
1518 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1519
1520 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1521 lsp_store.prettier_store().unwrap().downgrade()
1522 })?;
1523 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1524 .await
1525 .transpose()?;
1526 let Some(diff) = diff else {
1527 zlog::trace!(logger => "No changes");
1528 continue;
1529 };
1530
1531 extend_formatting_transaction(
1532 buffer,
1533 formatting_transaction_id,
1534 cx,
1535 |buffer, cx| {
1536 buffer.apply_diff(diff, cx);
1537 },
1538 )?;
1539 }
1540 Formatter::External { command, arguments } => {
1541 let logger = zlog::scoped!(logger => "command");
1542 zlog::trace!(logger => "formatting");
1543 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1544
1545 let diff = Self::format_via_external_command(
1546 buffer,
1547 command.as_ref(),
1548 arguments.as_deref(),
1549 cx,
1550 )
1551 .await
1552 .with_context(|| {
1553 format!("Failed to format buffer via external command: {}", command)
1554 })?;
1555 let Some(diff) = diff else {
1556 zlog::trace!(logger => "No changes");
1557 continue;
1558 };
1559
1560 extend_formatting_transaction(
1561 buffer,
1562 formatting_transaction_id,
1563 cx,
1564 |buffer, cx| {
1565 buffer.apply_diff(diff, cx);
1566 },
1567 )?;
1568 }
1569 Formatter::LanguageServer(specifier) => {
1570 let logger = zlog::scoped!(logger => "language-server");
1571 zlog::trace!(logger => "formatting");
1572 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1573
1574 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1575 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1576 continue;
1577 };
1578
1579 let language_server = match specifier {
1580 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1581 adapters_and_servers.iter().find_map(|(adapter, server)| {
1582 if adapter.name.0.as_ref() == name {
1583 Some(server.clone())
1584 } else {
1585 None
1586 }
1587 })
1588 }
1589 settings::LanguageServerFormatterSpecifier::Current => {
1590 adapters_and_servers.first().map(|e| e.1.clone())
1591 }
1592 };
1593
1594 let Some(language_server) = language_server else {
1595 log::debug!(
1596 "No language server found to format buffer '{:?}'. Skipping",
1597 buffer_path_abs.as_path().to_string_lossy()
1598 );
1599 continue;
1600 };
1601
1602 zlog::trace!(
1603 logger =>
1604 "Formatting buffer '{:?}' using language server '{:?}'",
1605 buffer_path_abs.as_path().to_string_lossy(),
1606 language_server.name()
1607 );
1608
1609 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1610 zlog::trace!(logger => "formatting ranges");
1611 Self::format_ranges_via_lsp(
1612 &lsp_store,
1613 &buffer.handle,
1614 ranges,
1615 buffer_path_abs,
1616 &language_server,
1617 &settings,
1618 cx,
1619 )
1620 .await
1621 .context("Failed to format ranges via language server")?
1622 } else {
1623 zlog::trace!(logger => "formatting full");
1624 Self::format_via_lsp(
1625 &lsp_store,
1626 &buffer.handle,
1627 buffer_path_abs,
1628 &language_server,
1629 &settings,
1630 cx,
1631 )
1632 .await
1633 .context("failed to format via language server")?
1634 };
1635
1636 if edits.is_empty() {
1637 zlog::trace!(logger => "No changes");
1638 continue;
1639 }
1640 extend_formatting_transaction(
1641 buffer,
1642 formatting_transaction_id,
1643 cx,
1644 |buffer, cx| {
1645 buffer.edit(edits, None, cx);
1646 },
1647 )?;
1648 }
1649 Formatter::CodeAction(code_action_name) => {
1650 let logger = zlog::scoped!(logger => "code-actions");
1651 zlog::trace!(logger => "formatting");
1652 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1653
1654 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1655 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1656 continue;
1657 };
1658
1659 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1660 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1661
1662 let mut actions_and_servers = Vec::new();
1663
1664 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1665 let actions_result = Self::get_server_code_actions_from_action_kinds(
1666 &lsp_store,
1667 language_server.server_id(),
1668 vec![code_action_kind.clone()],
1669 &buffer.handle,
1670 cx,
1671 )
1672 .await
1673 .with_context(|| {
1674 format!(
1675 "Failed to resolve code action {:?} with language server {}",
1676 code_action_kind,
1677 language_server.name()
1678 )
1679 });
1680 let Ok(actions) = actions_result else {
1681 // note: it may be better to set result to the error and break formatters here
1682 // but for now we try to execute the actions that we can resolve and skip the rest
1683 zlog::error!(
1684 logger =>
1685 "Failed to resolve code action {:?} with language server {}",
1686 code_action_kind,
1687 language_server.name()
1688 );
1689 continue;
1690 };
1691 for action in actions {
1692 actions_and_servers.push((action, index));
1693 }
1694 }
1695
1696 if actions_and_servers.is_empty() {
1697 zlog::warn!(logger => "No code actions were resolved, continuing");
1698 continue;
1699 }
1700
1701 'actions: for (mut action, server_index) in actions_and_servers {
1702 let server = &adapters_and_servers[server_index].1;
1703
1704 let describe_code_action = |action: &CodeAction| {
1705 format!(
1706 "code action '{}' with title \"{}\" on server {}",
1707 action
1708 .lsp_action
1709 .action_kind()
1710 .unwrap_or("unknown".into())
1711 .as_str(),
1712 action.lsp_action.title(),
1713 server.name(),
1714 )
1715 };
1716
1717 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1718
1719 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1720 zlog::error!(
1721 logger =>
1722 "Failed to resolve {}. Error: {}",
1723 describe_code_action(&action),
1724 err
1725 );
1726 continue;
1727 }
1728
1729 if let Some(edit) = action.lsp_action.edit().cloned() {
1730 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1731 // but filters out and logs warnings for code actions that require unreasonably
1732 // difficult handling on our part, such as:
1733 // - applying edits that call commands
1734 // which can result in arbitrary workspace edits being sent from the server that
1735 // have no way of being tied back to the command that initiated them (i.e. we
1736 // can't know which edits are part of the format request, or if the server is done sending
1737 // actions in response to the command)
1738 // - actions that create/delete/modify/rename files other than the one we are formatting
1739 // as we then would need to handle such changes correctly in the local history as well
1740 // as the remote history through the ProjectTransaction
1741 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1742 // Supporting these actions is not impossible, but not supported as of yet.
1743 if edit.changes.is_none() && edit.document_changes.is_none() {
1744 zlog::trace!(
1745 logger =>
1746 "No changes for code action. Skipping {}",
1747 describe_code_action(&action),
1748 );
1749 continue;
1750 }
1751
1752 let mut operations = Vec::new();
1753 if let Some(document_changes) = edit.document_changes {
1754 match document_changes {
1755 lsp::DocumentChanges::Edits(edits) => operations.extend(
1756 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1757 ),
1758 lsp::DocumentChanges::Operations(ops) => operations = ops,
1759 }
1760 } else if let Some(changes) = edit.changes {
1761 operations.extend(changes.into_iter().map(|(uri, edits)| {
1762 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1763 text_document:
1764 lsp::OptionalVersionedTextDocumentIdentifier {
1765 uri,
1766 version: None,
1767 },
1768 edits: edits.into_iter().map(Edit::Plain).collect(),
1769 })
1770 }));
1771 }
1772
1773 let mut edits = Vec::with_capacity(operations.len());
1774
1775 if operations.is_empty() {
1776 zlog::trace!(
1777 logger =>
1778 "No changes for code action. Skipping {}",
1779 describe_code_action(&action),
1780 );
1781 continue;
1782 }
1783 for operation in operations {
1784 let op = match operation {
1785 lsp::DocumentChangeOperation::Edit(op) => op,
1786 lsp::DocumentChangeOperation::Op(_) => {
1787 zlog::warn!(
1788 logger =>
1789 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1790 describe_code_action(&action),
1791 );
1792 continue 'actions;
1793 }
1794 };
1795 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1796 zlog::warn!(
1797 logger =>
1798 "Failed to convert URI '{:?}' to file path. Skipping {}",
1799 &op.text_document.uri,
1800 describe_code_action(&action),
1801 );
1802 continue 'actions;
1803 };
1804 if &file_path != buffer_path_abs {
1805 zlog::warn!(
1806 logger =>
1807 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1808 file_path,
1809 buffer_path_abs,
1810 describe_code_action(&action),
1811 );
1812 continue 'actions;
1813 }
1814
1815 let mut lsp_edits = Vec::new();
1816 for edit in op.edits {
1817 match edit {
1818 Edit::Plain(edit) => {
1819 if !lsp_edits.contains(&edit) {
1820 lsp_edits.push(edit);
1821 }
1822 }
1823 Edit::Annotated(edit) => {
1824 if !lsp_edits.contains(&edit.text_edit) {
1825 lsp_edits.push(edit.text_edit);
1826 }
1827 }
1828 Edit::Snippet(_) => {
1829 zlog::warn!(
1830 logger =>
1831 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1832 describe_code_action(&action),
1833 );
1834 continue 'actions;
1835 }
1836 }
1837 }
1838 let edits_result = lsp_store
1839 .update(cx, |lsp_store, cx| {
1840 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1841 &buffer.handle,
1842 lsp_edits,
1843 server.server_id(),
1844 op.text_document.version,
1845 cx,
1846 )
1847 })?
1848 .await;
1849 let Ok(resolved_edits) = edits_result else {
1850 zlog::warn!(
1851 logger =>
1852 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1853 buffer_path_abs.as_path(),
1854 describe_code_action(&action),
1855 );
1856 continue 'actions;
1857 };
1858 edits.extend(resolved_edits);
1859 }
1860
1861 if edits.is_empty() {
1862 zlog::warn!(logger => "No edits resolved from LSP");
1863 continue;
1864 }
1865
1866 extend_formatting_transaction(
1867 buffer,
1868 formatting_transaction_id,
1869 cx,
1870 |buffer, cx| {
1871 zlog::info!(
1872 "Applying edits {edits:?}. Content: {:?}",
1873 buffer.text()
1874 );
1875 buffer.edit(edits, None, cx);
1876 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1877 },
1878 )?;
1879 }
1880
1881 if let Some(command) = action.lsp_action.command() {
1882 zlog::warn!(
1883 logger =>
1884 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1885 &command.command,
1886 );
1887
1888 // bail early if command is invalid
1889 let server_capabilities = server.capabilities();
1890 let available_commands = server_capabilities
1891 .execute_command_provider
1892 .as_ref()
1893 .map(|options| options.commands.as_slice())
1894 .unwrap_or_default();
1895 if !available_commands.contains(&command.command) {
1896 zlog::warn!(
1897 logger =>
1898 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1899 command.command,
1900 server.name(),
1901 );
1902 continue;
1903 }
1904
1905 // noop so we just ensure buffer hasn't been edited since resolving code actions
1906 extend_formatting_transaction(
1907 buffer,
1908 formatting_transaction_id,
1909 cx,
1910 |_, _| {},
1911 )?;
1912 zlog::info!(logger => "Executing command {}", &command.command);
1913
1914 lsp_store.update(cx, |this, _| {
1915 this.as_local_mut()
1916 .unwrap()
1917 .last_workspace_edits_by_language_server
1918 .remove(&server.server_id());
1919 })?;
1920
1921 let execute_command_result = server
1922 .request::<lsp::request::ExecuteCommand>(
1923 lsp::ExecuteCommandParams {
1924 command: command.command.clone(),
1925 arguments: command.arguments.clone().unwrap_or_default(),
1926 ..Default::default()
1927 },
1928 )
1929 .await
1930 .into_response();
1931
1932 if execute_command_result.is_err() {
1933 zlog::error!(
1934 logger =>
1935 "Failed to execute command '{}' as part of {}",
1936 &command.command,
1937 describe_code_action(&action),
1938 );
1939 continue 'actions;
1940 }
1941
1942 let mut project_transaction_command =
1943 lsp_store.update(cx, |this, _| {
1944 this.as_local_mut()
1945 .unwrap()
1946 .last_workspace_edits_by_language_server
1947 .remove(&server.server_id())
1948 .unwrap_or_default()
1949 })?;
1950
1951 if let Some(transaction) =
1952 project_transaction_command.0.remove(&buffer.handle)
1953 {
1954 zlog::trace!(
1955 logger =>
1956 "Successfully captured {} edits that resulted from command {}",
1957 transaction.edit_ids.len(),
1958 &command.command,
1959 );
1960 let transaction_id_project_transaction = transaction.id;
1961 buffer.handle.update(cx, |buffer, _| {
1962 // it may have been removed from history if push_to_history was
1963 // false in deserialize_workspace_edit. If so push it so we
1964 // can merge it with the format transaction
1965 // and pop the combined transaction off the history stack
1966 // later if push_to_history is false
1967 if buffer.get_transaction(transaction.id).is_none() {
1968 buffer.push_transaction(transaction, Instant::now());
1969 }
1970 buffer.merge_transactions(
1971 transaction_id_project_transaction,
1972 formatting_transaction_id,
1973 );
1974 })?;
1975 }
1976
1977 if !project_transaction_command.0.is_empty() {
1978 let mut extra_buffers = String::new();
1979 for buffer in project_transaction_command.0.keys() {
1980 buffer
1981 .read_with(cx, |b, cx| {
1982 if let Some(path) = b.project_path(cx) {
1983 if !extra_buffers.is_empty() {
1984 extra_buffers.push_str(", ");
1985 }
1986 extra_buffers.push_str(path.path.as_unix_str());
1987 }
1988 })
1989 .ok();
1990 }
1991 zlog::warn!(
1992 logger =>
1993 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1994 &command.command,
1995 extra_buffers,
1996 );
1997 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1998 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1999 // add it so it's included, and merge it into the format transaction when its created later
2000 }
2001 }
2002 }
2003 }
2004 }
2005 }
2006
2007 Ok(())
2008 }
2009
2010 pub async fn format_ranges_via_lsp(
2011 this: &WeakEntity<LspStore>,
2012 buffer_handle: &Entity<Buffer>,
2013 ranges: &[Range<Anchor>],
2014 abs_path: &Path,
2015 language_server: &Arc<LanguageServer>,
2016 settings: &LanguageSettings,
2017 cx: &mut AsyncApp,
2018 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2019 let capabilities = &language_server.capabilities();
2020 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2021 if range_formatting_provider == Some(&OneOf::Left(false)) {
2022 anyhow::bail!(
2023 "{} language server does not support range formatting",
2024 language_server.name()
2025 );
2026 }
2027
2028 let uri = file_path_to_lsp_url(abs_path)?;
2029 let text_document = lsp::TextDocumentIdentifier::new(uri);
2030
2031 let lsp_edits = {
2032 let mut lsp_ranges = Vec::new();
2033 this.update(cx, |_this, cx| {
2034 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2035 // not have been sent to the language server. This seems like a fairly systemic
2036 // issue, though, the resolution probably is not specific to formatting.
2037 //
2038 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2039 // LSP.
2040 let snapshot = buffer_handle.read(cx).snapshot();
2041 for range in ranges {
2042 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2043 }
2044 anyhow::Ok(())
2045 })??;
2046
2047 let mut edits = None;
2048 for range in lsp_ranges {
2049 if let Some(mut edit) = language_server
2050 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2051 text_document: text_document.clone(),
2052 range,
2053 options: lsp_command::lsp_formatting_options(settings),
2054 work_done_progress_params: Default::default(),
2055 })
2056 .await
2057 .into_response()?
2058 {
2059 edits.get_or_insert_with(Vec::new).append(&mut edit);
2060 }
2061 }
2062 edits
2063 };
2064
2065 if let Some(lsp_edits) = lsp_edits {
2066 this.update(cx, |this, cx| {
2067 this.as_local_mut().unwrap().edits_from_lsp(
2068 buffer_handle,
2069 lsp_edits,
2070 language_server.server_id(),
2071 None,
2072 cx,
2073 )
2074 })?
2075 .await
2076 } else {
2077 Ok(Vec::with_capacity(0))
2078 }
2079 }
2080
2081 async fn format_via_lsp(
2082 this: &WeakEntity<LspStore>,
2083 buffer: &Entity<Buffer>,
2084 abs_path: &Path,
2085 language_server: &Arc<LanguageServer>,
2086 settings: &LanguageSettings,
2087 cx: &mut AsyncApp,
2088 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2089 let logger = zlog::scoped!("lsp_format");
2090 zlog::debug!(logger => "Formatting via LSP");
2091
2092 let uri = file_path_to_lsp_url(abs_path)?;
2093 let text_document = lsp::TextDocumentIdentifier::new(uri);
2094 let capabilities = &language_server.capabilities();
2095
2096 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2097 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2098
2099 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2100 let _timer = zlog::time!(logger => "format-full");
2101 language_server
2102 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2103 text_document,
2104 options: lsp_command::lsp_formatting_options(settings),
2105 work_done_progress_params: Default::default(),
2106 })
2107 .await
2108 .into_response()?
2109 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2110 let _timer = zlog::time!(logger => "format-range");
2111 let buffer_start = lsp::Position::new(0, 0);
2112 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2113 language_server
2114 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2115 text_document: text_document.clone(),
2116 range: lsp::Range::new(buffer_start, buffer_end),
2117 options: lsp_command::lsp_formatting_options(settings),
2118 work_done_progress_params: Default::default(),
2119 })
2120 .await
2121 .into_response()?
2122 } else {
2123 None
2124 };
2125
2126 if let Some(lsp_edits) = lsp_edits {
2127 this.update(cx, |this, cx| {
2128 this.as_local_mut().unwrap().edits_from_lsp(
2129 buffer,
2130 lsp_edits,
2131 language_server.server_id(),
2132 None,
2133 cx,
2134 )
2135 })?
2136 .await
2137 } else {
2138 Ok(Vec::with_capacity(0))
2139 }
2140 }
2141
2142 async fn format_via_external_command(
2143 buffer: &FormattableBuffer,
2144 command: &str,
2145 arguments: Option<&[String]>,
2146 cx: &mut AsyncApp,
2147 ) -> Result<Option<Diff>> {
2148 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2149 let file = File::from_dyn(buffer.file())?;
2150 let worktree = file.worktree.read(cx);
2151 let mut worktree_path = worktree.abs_path().to_path_buf();
2152 if worktree.root_entry()?.is_file() {
2153 worktree_path.pop();
2154 }
2155 Some(worktree_path)
2156 })?;
2157
2158 let mut child = util::command::new_smol_command(command);
2159
2160 if let Some(buffer_env) = buffer.env.as_ref() {
2161 child.envs(buffer_env);
2162 }
2163
2164 if let Some(working_dir_path) = working_dir_path {
2165 child.current_dir(working_dir_path);
2166 }
2167
2168 if let Some(arguments) = arguments {
2169 child.args(arguments.iter().map(|arg| {
2170 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2171 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2172 } else {
2173 arg.replace("{buffer_path}", "Untitled")
2174 }
2175 }));
2176 }
2177
2178 let mut child = child
2179 .stdin(smol::process::Stdio::piped())
2180 .stdout(smol::process::Stdio::piped())
2181 .stderr(smol::process::Stdio::piped())
2182 .spawn()?;
2183
2184 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2185 let text = buffer
2186 .handle
2187 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2188 for chunk in text.chunks() {
2189 stdin.write_all(chunk.as_bytes()).await?;
2190 }
2191 stdin.flush().await?;
2192
2193 let output = child.output().await?;
2194 anyhow::ensure!(
2195 output.status.success(),
2196 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2197 output.status.code(),
2198 String::from_utf8_lossy(&output.stdout),
2199 String::from_utf8_lossy(&output.stderr),
2200 );
2201
2202 let stdout = String::from_utf8(output.stdout)?;
2203 Ok(Some(
2204 buffer
2205 .handle
2206 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2207 .await,
2208 ))
2209 }
2210
2211 async fn try_resolve_code_action(
2212 lang_server: &LanguageServer,
2213 action: &mut CodeAction,
2214 ) -> anyhow::Result<()> {
2215 match &mut action.lsp_action {
2216 LspAction::Action(lsp_action) => {
2217 if !action.resolved
2218 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2219 && lsp_action.data.is_some()
2220 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2221 {
2222 *lsp_action = Box::new(
2223 lang_server
2224 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2225 .await
2226 .into_response()?,
2227 );
2228 }
2229 }
2230 LspAction::CodeLens(lens) => {
2231 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2232 *lens = lang_server
2233 .request::<lsp::request::CodeLensResolve>(lens.clone())
2234 .await
2235 .into_response()?;
2236 }
2237 }
2238 LspAction::Command(_) => {}
2239 }
2240
2241 action.resolved = true;
2242 anyhow::Ok(())
2243 }
2244
2245 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2246 let buffer = buffer_handle.read(cx);
2247
2248 let file = buffer.file().cloned();
2249
2250 let Some(file) = File::from_dyn(file.as_ref()) else {
2251 return;
2252 };
2253 if !file.is_local() {
2254 return;
2255 }
2256 let path = ProjectPath::from_file(file, cx);
2257 let worktree_id = file.worktree_id(cx);
2258 let language = buffer.language().cloned();
2259
2260 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2261 for (server_id, diagnostics) in
2262 diagnostics.get(file.path()).cloned().unwrap_or_default()
2263 {
2264 self.update_buffer_diagnostics(
2265 buffer_handle,
2266 server_id,
2267 None,
2268 None,
2269 None,
2270 Vec::new(),
2271 diagnostics,
2272 cx,
2273 )
2274 .log_err();
2275 }
2276 }
2277 let Some(language) = language else {
2278 return;
2279 };
2280 let Some(snapshot) = self
2281 .worktree_store
2282 .read(cx)
2283 .worktree_for_id(worktree_id, cx)
2284 .map(|worktree| worktree.read(cx).snapshot())
2285 else {
2286 return;
2287 };
2288 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2289
2290 for server_id in
2291 self.lsp_tree
2292 .get(path, language.name(), language.manifest(), &delegate, cx)
2293 {
2294 let server = self
2295 .language_servers
2296 .get(&server_id)
2297 .and_then(|server_state| {
2298 if let LanguageServerState::Running { server, .. } = server_state {
2299 Some(server.clone())
2300 } else {
2301 None
2302 }
2303 });
2304 let server = match server {
2305 Some(server) => server,
2306 None => continue,
2307 };
2308
2309 buffer_handle.update(cx, |buffer, cx| {
2310 buffer.set_completion_triggers(
2311 server.server_id(),
2312 server
2313 .capabilities()
2314 .completion_provider
2315 .as_ref()
2316 .and_then(|provider| {
2317 provider
2318 .trigger_characters
2319 .as_ref()
2320 .map(|characters| characters.iter().cloned().collect())
2321 })
2322 .unwrap_or_default(),
2323 cx,
2324 );
2325 });
2326 }
2327 }
2328
2329 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2330 buffer.update(cx, |buffer, cx| {
2331 let Some(language) = buffer.language() else {
2332 return;
2333 };
2334 let path = ProjectPath {
2335 worktree_id: old_file.worktree_id(cx),
2336 path: old_file.path.clone(),
2337 };
2338 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2339 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2340 buffer.set_completion_triggers(server_id, Default::default(), cx);
2341 }
2342 });
2343 }
2344
2345 fn update_buffer_diagnostics(
2346 &mut self,
2347 buffer: &Entity<Buffer>,
2348 server_id: LanguageServerId,
2349 registration_id: Option<Option<SharedString>>,
2350 result_id: Option<SharedString>,
2351 version: Option<i32>,
2352 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2353 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2354 cx: &mut Context<LspStore>,
2355 ) -> Result<()> {
2356 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2357 Ordering::Equal
2358 .then_with(|| b.is_primary.cmp(&a.is_primary))
2359 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2360 .then_with(|| a.severity.cmp(&b.severity))
2361 .then_with(|| a.message.cmp(&b.message))
2362 }
2363
2364 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2365 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2366 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2367
2368 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2369 Ordering::Equal
2370 .then_with(|| a.range.start.cmp(&b.range.start))
2371 .then_with(|| b.range.end.cmp(&a.range.end))
2372 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2373 });
2374
2375 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2376
2377 let edits_since_save = std::cell::LazyCell::new(|| {
2378 let saved_version = buffer.read(cx).saved_version();
2379 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2380 });
2381
2382 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2383
2384 for (new_diagnostic, entry) in diagnostics {
2385 let start;
2386 let end;
2387 if new_diagnostic && entry.diagnostic.is_disk_based {
2388 // Some diagnostics are based on files on disk instead of buffers'
2389 // current contents. Adjust these diagnostics' ranges to reflect
2390 // any unsaved edits.
2391 // Do not alter the reused ones though, as their coordinates were stored as anchors
2392 // and were properly adjusted on reuse.
2393 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2394 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2395 } else {
2396 start = entry.range.start;
2397 end = entry.range.end;
2398 }
2399
2400 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2401 ..snapshot.clip_point_utf16(end, Bias::Right);
2402
2403 // Expand empty ranges by one codepoint
2404 if range.start == range.end {
2405 // This will be go to the next boundary when being clipped
2406 range.end.column += 1;
2407 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2408 if range.start == range.end && range.end.column > 0 {
2409 range.start.column -= 1;
2410 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2411 }
2412 }
2413
2414 sanitized_diagnostics.push(DiagnosticEntry {
2415 range,
2416 diagnostic: entry.diagnostic,
2417 });
2418 }
2419 drop(edits_since_save);
2420
2421 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2422 buffer.update(cx, |buffer, cx| {
2423 if let Some(registration_id) = registration_id {
2424 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2425 self.buffer_pull_diagnostics_result_ids
2426 .entry(server_id)
2427 .or_default()
2428 .entry(registration_id)
2429 .or_default()
2430 .insert(abs_path, result_id);
2431 }
2432 }
2433
2434 buffer.update_diagnostics(server_id, set, cx)
2435 });
2436
2437 Ok(())
2438 }
2439
2440 fn register_language_server_for_invisible_worktree(
2441 &mut self,
2442 worktree: &Entity<Worktree>,
2443 language_server_id: LanguageServerId,
2444 cx: &mut App,
2445 ) {
2446 let worktree = worktree.read(cx);
2447 let worktree_id = worktree.id();
2448 debug_assert!(!worktree.is_visible());
2449 let Some(mut origin_seed) = self
2450 .language_server_ids
2451 .iter()
2452 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2453 else {
2454 return;
2455 };
2456 origin_seed.worktree_id = worktree_id;
2457 self.language_server_ids
2458 .entry(origin_seed)
2459 .or_insert_with(|| UnifiedLanguageServer {
2460 id: language_server_id,
2461 project_roots: Default::default(),
2462 });
2463 }
2464
2465 fn register_buffer_with_language_servers(
2466 &mut self,
2467 buffer_handle: &Entity<Buffer>,
2468 only_register_servers: HashSet<LanguageServerSelector>,
2469 cx: &mut Context<LspStore>,
2470 ) {
2471 let buffer = buffer_handle.read(cx);
2472 let buffer_id = buffer.remote_id();
2473
2474 let Some(file) = File::from_dyn(buffer.file()) else {
2475 return;
2476 };
2477 if !file.is_local() {
2478 return;
2479 }
2480
2481 let abs_path = file.abs_path(cx);
2482 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2483 return;
2484 };
2485 let initial_snapshot = buffer.text_snapshot();
2486 let worktree_id = file.worktree_id(cx);
2487
2488 let Some(language) = buffer.language().cloned() else {
2489 return;
2490 };
2491 let path: Arc<RelPath> = file
2492 .path()
2493 .parent()
2494 .map(Arc::from)
2495 .unwrap_or_else(|| file.path().clone());
2496 let Some(worktree) = self
2497 .worktree_store
2498 .read(cx)
2499 .worktree_for_id(worktree_id, cx)
2500 else {
2501 return;
2502 };
2503 let language_name = language.name();
2504 let (reused, delegate, servers) = self
2505 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2506 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2507 .unwrap_or_else(|| {
2508 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2509 let delegate: Arc<dyn ManifestDelegate> =
2510 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2511
2512 let servers = self
2513 .lsp_tree
2514 .walk(
2515 ProjectPath { worktree_id, path },
2516 language.name(),
2517 language.manifest(),
2518 &delegate,
2519 cx,
2520 )
2521 .collect::<Vec<_>>();
2522 (false, lsp_delegate, servers)
2523 });
2524 let servers_and_adapters = servers
2525 .into_iter()
2526 .filter_map(|server_node| {
2527 if reused && server_node.server_id().is_none() {
2528 return None;
2529 }
2530 if !only_register_servers.is_empty() {
2531 if let Some(server_id) = server_node.server_id()
2532 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2533 {
2534 return None;
2535 }
2536 if let Some(name) = server_node.name()
2537 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2538 {
2539 return None;
2540 }
2541 }
2542
2543 let server_id = server_node.server_id_or_init(|disposition| {
2544 let path = &disposition.path;
2545
2546 {
2547 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2548
2549 let server_id = self.get_or_insert_language_server(
2550 &worktree,
2551 delegate.clone(),
2552 disposition,
2553 &language_name,
2554 cx,
2555 );
2556
2557 if let Some(state) = self.language_servers.get(&server_id)
2558 && let Ok(uri) = uri
2559 {
2560 state.add_workspace_folder(uri);
2561 };
2562 server_id
2563 }
2564 })?;
2565 let server_state = self.language_servers.get(&server_id)?;
2566 if let LanguageServerState::Running {
2567 server, adapter, ..
2568 } = server_state
2569 {
2570 Some((server.clone(), adapter.clone()))
2571 } else {
2572 None
2573 }
2574 })
2575 .collect::<Vec<_>>();
2576 for (server, adapter) in servers_and_adapters {
2577 buffer_handle.update(cx, |buffer, cx| {
2578 buffer.set_completion_triggers(
2579 server.server_id(),
2580 server
2581 .capabilities()
2582 .completion_provider
2583 .as_ref()
2584 .and_then(|provider| {
2585 provider
2586 .trigger_characters
2587 .as_ref()
2588 .map(|characters| characters.iter().cloned().collect())
2589 })
2590 .unwrap_or_default(),
2591 cx,
2592 );
2593 });
2594
2595 let snapshot = LspBufferSnapshot {
2596 version: 0,
2597 snapshot: initial_snapshot.clone(),
2598 };
2599
2600 let mut registered = false;
2601 self.buffer_snapshots
2602 .entry(buffer_id)
2603 .or_default()
2604 .entry(server.server_id())
2605 .or_insert_with(|| {
2606 registered = true;
2607 server.register_buffer(
2608 uri.clone(),
2609 adapter.language_id(&language.name()),
2610 0,
2611 initial_snapshot.text(),
2612 );
2613
2614 vec![snapshot]
2615 });
2616
2617 self.buffers_opened_in_servers
2618 .entry(buffer_id)
2619 .or_default()
2620 .insert(server.server_id());
2621 if registered {
2622 cx.emit(LspStoreEvent::LanguageServerUpdate {
2623 language_server_id: server.server_id(),
2624 name: None,
2625 message: proto::update_language_server::Variant::RegisteredForBuffer(
2626 proto::RegisteredForBuffer {
2627 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2628 buffer_id: buffer_id.to_proto(),
2629 },
2630 ),
2631 });
2632 }
2633 }
2634 }
2635
2636 fn reuse_existing_language_server<'lang_name>(
2637 &self,
2638 server_tree: &LanguageServerTree,
2639 worktree: &Entity<Worktree>,
2640 language_name: &'lang_name LanguageName,
2641 cx: &mut App,
2642 ) -> Option<(
2643 Arc<LocalLspAdapterDelegate>,
2644 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2645 )> {
2646 if worktree.read(cx).is_visible() {
2647 return None;
2648 }
2649
2650 let worktree_store = self.worktree_store.read(cx);
2651 let servers = server_tree
2652 .instances
2653 .iter()
2654 .filter(|(worktree_id, _)| {
2655 worktree_store
2656 .worktree_for_id(**worktree_id, cx)
2657 .is_some_and(|worktree| worktree.read(cx).is_visible())
2658 })
2659 .flat_map(|(worktree_id, servers)| {
2660 servers
2661 .roots
2662 .iter()
2663 .flat_map(|(_, language_servers)| language_servers)
2664 .map(move |(_, (server_node, server_languages))| {
2665 (worktree_id, server_node, server_languages)
2666 })
2667 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2668 .map(|(worktree_id, server_node, _)| {
2669 (
2670 *worktree_id,
2671 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2672 )
2673 })
2674 })
2675 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2676 acc.entry(worktree_id)
2677 .or_insert_with(Vec::new)
2678 .push(server_node);
2679 acc
2680 })
2681 .into_values()
2682 .max_by_key(|servers| servers.len())?;
2683
2684 let worktree_id = worktree.read(cx).id();
2685 let apply = move |tree: &mut LanguageServerTree| {
2686 for server_node in &servers {
2687 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2688 }
2689 servers
2690 };
2691
2692 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2693 Some((delegate, apply))
2694 }
2695
2696 pub(crate) fn unregister_old_buffer_from_language_servers(
2697 &mut self,
2698 buffer: &Entity<Buffer>,
2699 old_file: &File,
2700 cx: &mut App,
2701 ) {
2702 let old_path = match old_file.as_local() {
2703 Some(local) => local.abs_path(cx),
2704 None => return,
2705 };
2706
2707 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2708 debug_panic!("{old_path:?} is not parseable as an URI");
2709 return;
2710 };
2711 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2712 }
2713
2714 pub(crate) fn unregister_buffer_from_language_servers(
2715 &mut self,
2716 buffer: &Entity<Buffer>,
2717 file_url: &lsp::Uri,
2718 cx: &mut App,
2719 ) {
2720 buffer.update(cx, |buffer, cx| {
2721 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2722
2723 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2724 if snapshots
2725 .as_mut()
2726 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2727 {
2728 language_server.unregister_buffer(file_url.clone());
2729 }
2730 }
2731 });
2732 }
2733
2734 fn buffer_snapshot_for_lsp_version(
2735 &mut self,
2736 buffer: &Entity<Buffer>,
2737 server_id: LanguageServerId,
2738 version: Option<i32>,
2739 cx: &App,
2740 ) -> Result<TextBufferSnapshot> {
2741 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2742
2743 if let Some(version) = version {
2744 let buffer_id = buffer.read(cx).remote_id();
2745 let snapshots = if let Some(snapshots) = self
2746 .buffer_snapshots
2747 .get_mut(&buffer_id)
2748 .and_then(|m| m.get_mut(&server_id))
2749 {
2750 snapshots
2751 } else if version == 0 {
2752 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2753 // We detect this case and treat it as if the version was `None`.
2754 return Ok(buffer.read(cx).text_snapshot());
2755 } else {
2756 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2757 };
2758
2759 let found_snapshot = snapshots
2760 .binary_search_by_key(&version, |e| e.version)
2761 .map(|ix| snapshots[ix].snapshot.clone())
2762 .map_err(|_| {
2763 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2764 })?;
2765
2766 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2767 Ok(found_snapshot)
2768 } else {
2769 Ok((buffer.read(cx)).text_snapshot())
2770 }
2771 }
2772
2773 async fn get_server_code_actions_from_action_kinds(
2774 lsp_store: &WeakEntity<LspStore>,
2775 language_server_id: LanguageServerId,
2776 code_action_kinds: Vec<lsp::CodeActionKind>,
2777 buffer: &Entity<Buffer>,
2778 cx: &mut AsyncApp,
2779 ) -> Result<Vec<CodeAction>> {
2780 let actions = lsp_store
2781 .update(cx, move |this, cx| {
2782 let request = GetCodeActions {
2783 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2784 kinds: Some(code_action_kinds),
2785 };
2786 let server = LanguageServerToQuery::Other(language_server_id);
2787 this.request_lsp(buffer.clone(), server, request, cx)
2788 })?
2789 .await?;
2790 Ok(actions)
2791 }
2792
2793 pub async fn execute_code_actions_on_server(
2794 lsp_store: &WeakEntity<LspStore>,
2795 language_server: &Arc<LanguageServer>,
2796
2797 actions: Vec<CodeAction>,
2798 push_to_history: bool,
2799 project_transaction: &mut ProjectTransaction,
2800 cx: &mut AsyncApp,
2801 ) -> anyhow::Result<()> {
2802 for mut action in actions {
2803 Self::try_resolve_code_action(language_server, &mut action)
2804 .await
2805 .context("resolving a formatting code action")?;
2806
2807 if let Some(edit) = action.lsp_action.edit() {
2808 if edit.changes.is_none() && edit.document_changes.is_none() {
2809 continue;
2810 }
2811
2812 let new = Self::deserialize_workspace_edit(
2813 lsp_store.upgrade().context("project dropped")?,
2814 edit.clone(),
2815 push_to_history,
2816 language_server.clone(),
2817 cx,
2818 )
2819 .await?;
2820 project_transaction.0.extend(new.0);
2821 }
2822
2823 if let Some(command) = action.lsp_action.command() {
2824 let server_capabilities = language_server.capabilities();
2825 let available_commands = server_capabilities
2826 .execute_command_provider
2827 .as_ref()
2828 .map(|options| options.commands.as_slice())
2829 .unwrap_or_default();
2830 if available_commands.contains(&command.command) {
2831 lsp_store.update(cx, |lsp_store, _| {
2832 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2833 mode.last_workspace_edits_by_language_server
2834 .remove(&language_server.server_id());
2835 }
2836 })?;
2837
2838 language_server
2839 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2840 command: command.command.clone(),
2841 arguments: command.arguments.clone().unwrap_or_default(),
2842 ..Default::default()
2843 })
2844 .await
2845 .into_response()
2846 .context("execute command")?;
2847
2848 lsp_store.update(cx, |this, _| {
2849 if let LspStoreMode::Local(mode) = &mut this.mode {
2850 project_transaction.0.extend(
2851 mode.last_workspace_edits_by_language_server
2852 .remove(&language_server.server_id())
2853 .unwrap_or_default()
2854 .0,
2855 )
2856 }
2857 })?;
2858 } else {
2859 log::warn!(
2860 "Cannot execute a command {} not listed in the language server capabilities",
2861 command.command
2862 )
2863 }
2864 }
2865 }
2866 Ok(())
2867 }
2868
2869 pub async fn deserialize_text_edits(
2870 this: Entity<LspStore>,
2871 buffer_to_edit: Entity<Buffer>,
2872 edits: Vec<lsp::TextEdit>,
2873 push_to_history: bool,
2874 _: Arc<CachedLspAdapter>,
2875 language_server: Arc<LanguageServer>,
2876 cx: &mut AsyncApp,
2877 ) -> Result<Option<Transaction>> {
2878 let edits = this
2879 .update(cx, |this, cx| {
2880 this.as_local_mut().unwrap().edits_from_lsp(
2881 &buffer_to_edit,
2882 edits,
2883 language_server.server_id(),
2884 None,
2885 cx,
2886 )
2887 })?
2888 .await?;
2889
2890 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2891 buffer.finalize_last_transaction();
2892 buffer.start_transaction();
2893 for (range, text) in edits {
2894 buffer.edit([(range, text)], None, cx);
2895 }
2896
2897 if buffer.end_transaction(cx).is_some() {
2898 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2899 if !push_to_history {
2900 buffer.forget_transaction(transaction.id);
2901 }
2902 Some(transaction)
2903 } else {
2904 None
2905 }
2906 })?;
2907
2908 Ok(transaction)
2909 }
2910
2911 #[allow(clippy::type_complexity)]
2912 pub(crate) fn edits_from_lsp(
2913 &mut self,
2914 buffer: &Entity<Buffer>,
2915 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2916 server_id: LanguageServerId,
2917 version: Option<i32>,
2918 cx: &mut Context<LspStore>,
2919 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2920 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2921 cx.background_spawn(async move {
2922 let snapshot = snapshot?;
2923 let mut lsp_edits = lsp_edits
2924 .into_iter()
2925 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2926 .collect::<Vec<_>>();
2927
2928 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2929
2930 let mut lsp_edits = lsp_edits.into_iter().peekable();
2931 let mut edits = Vec::new();
2932 while let Some((range, mut new_text)) = lsp_edits.next() {
2933 // Clip invalid ranges provided by the language server.
2934 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2935 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2936
2937 // Combine any LSP edits that are adjacent.
2938 //
2939 // Also, combine LSP edits that are separated from each other by only
2940 // a newline. This is important because for some code actions,
2941 // Rust-analyzer rewrites the entire buffer via a series of edits that
2942 // are separated by unchanged newline characters.
2943 //
2944 // In order for the diffing logic below to work properly, any edits that
2945 // cancel each other out must be combined into one.
2946 while let Some((next_range, next_text)) = lsp_edits.peek() {
2947 if next_range.start.0 > range.end {
2948 if next_range.start.0.row > range.end.row + 1
2949 || next_range.start.0.column > 0
2950 || snapshot.clip_point_utf16(
2951 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2952 Bias::Left,
2953 ) > range.end
2954 {
2955 break;
2956 }
2957 new_text.push('\n');
2958 }
2959 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2960 new_text.push_str(next_text);
2961 lsp_edits.next();
2962 }
2963
2964 // For multiline edits, perform a diff of the old and new text so that
2965 // we can identify the changes more precisely, preserving the locations
2966 // of any anchors positioned in the unchanged regions.
2967 if range.end.row > range.start.row {
2968 let offset = range.start.to_offset(&snapshot);
2969 let old_text = snapshot.text_for_range(range).collect::<String>();
2970 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2971 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2972 (
2973 snapshot.anchor_after(offset + range.start)
2974 ..snapshot.anchor_before(offset + range.end),
2975 replacement,
2976 )
2977 }));
2978 } else if range.end == range.start {
2979 let anchor = snapshot.anchor_after(range.start);
2980 edits.push((anchor..anchor, new_text.into()));
2981 } else {
2982 let edit_start = snapshot.anchor_after(range.start);
2983 let edit_end = snapshot.anchor_before(range.end);
2984 edits.push((edit_start..edit_end, new_text.into()));
2985 }
2986 }
2987
2988 Ok(edits)
2989 })
2990 }
2991
2992 pub(crate) async fn deserialize_workspace_edit(
2993 this: Entity<LspStore>,
2994 edit: lsp::WorkspaceEdit,
2995 push_to_history: bool,
2996 language_server: Arc<LanguageServer>,
2997 cx: &mut AsyncApp,
2998 ) -> Result<ProjectTransaction> {
2999 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3000
3001 let mut operations = Vec::new();
3002 if let Some(document_changes) = edit.document_changes {
3003 match document_changes {
3004 lsp::DocumentChanges::Edits(edits) => {
3005 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3006 }
3007 lsp::DocumentChanges::Operations(ops) => operations = ops,
3008 }
3009 } else if let Some(changes) = edit.changes {
3010 operations.extend(changes.into_iter().map(|(uri, edits)| {
3011 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3012 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3013 uri,
3014 version: None,
3015 },
3016 edits: edits.into_iter().map(Edit::Plain).collect(),
3017 })
3018 }));
3019 }
3020
3021 let mut project_transaction = ProjectTransaction::default();
3022 for operation in operations {
3023 match operation {
3024 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3025 let abs_path = op
3026 .uri
3027 .to_file_path()
3028 .map_err(|()| anyhow!("can't convert URI to path"))?;
3029
3030 if let Some(parent_path) = abs_path.parent() {
3031 fs.create_dir(parent_path).await?;
3032 }
3033 if abs_path.ends_with("/") {
3034 fs.create_dir(&abs_path).await?;
3035 } else {
3036 fs.create_file(
3037 &abs_path,
3038 op.options
3039 .map(|options| fs::CreateOptions {
3040 overwrite: options.overwrite.unwrap_or(false),
3041 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3042 })
3043 .unwrap_or_default(),
3044 )
3045 .await?;
3046 }
3047 }
3048
3049 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3050 let source_abs_path = op
3051 .old_uri
3052 .to_file_path()
3053 .map_err(|()| anyhow!("can't convert URI to path"))?;
3054 let target_abs_path = op
3055 .new_uri
3056 .to_file_path()
3057 .map_err(|()| anyhow!("can't convert URI to path"))?;
3058
3059 let options = fs::RenameOptions {
3060 overwrite: op
3061 .options
3062 .as_ref()
3063 .and_then(|options| options.overwrite)
3064 .unwrap_or(false),
3065 ignore_if_exists: op
3066 .options
3067 .as_ref()
3068 .and_then(|options| options.ignore_if_exists)
3069 .unwrap_or(false),
3070 create_parents: true,
3071 };
3072
3073 fs.rename(&source_abs_path, &target_abs_path, options)
3074 .await?;
3075 }
3076
3077 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3078 let abs_path = op
3079 .uri
3080 .to_file_path()
3081 .map_err(|()| anyhow!("can't convert URI to path"))?;
3082 let options = op
3083 .options
3084 .map(|options| fs::RemoveOptions {
3085 recursive: options.recursive.unwrap_or(false),
3086 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3087 })
3088 .unwrap_or_default();
3089 if abs_path.ends_with("/") {
3090 fs.remove_dir(&abs_path, options).await?;
3091 } else {
3092 fs.remove_file(&abs_path, options).await?;
3093 }
3094 }
3095
3096 lsp::DocumentChangeOperation::Edit(op) => {
3097 let buffer_to_edit = this
3098 .update(cx, |this, cx| {
3099 this.open_local_buffer_via_lsp(
3100 op.text_document.uri.clone(),
3101 language_server.server_id(),
3102 cx,
3103 )
3104 })?
3105 .await?;
3106
3107 let edits = this
3108 .update(cx, |this, cx| {
3109 let path = buffer_to_edit.read(cx).project_path(cx);
3110 let active_entry = this.active_entry;
3111 let is_active_entry = path.is_some_and(|project_path| {
3112 this.worktree_store
3113 .read(cx)
3114 .entry_for_path(&project_path, cx)
3115 .is_some_and(|entry| Some(entry.id) == active_entry)
3116 });
3117 let local = this.as_local_mut().unwrap();
3118
3119 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3120 for edit in op.edits {
3121 match edit {
3122 Edit::Plain(edit) => {
3123 if !edits.contains(&edit) {
3124 edits.push(edit)
3125 }
3126 }
3127 Edit::Annotated(edit) => {
3128 if !edits.contains(&edit.text_edit) {
3129 edits.push(edit.text_edit)
3130 }
3131 }
3132 Edit::Snippet(edit) => {
3133 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3134 else {
3135 continue;
3136 };
3137
3138 if is_active_entry {
3139 snippet_edits.push((edit.range, snippet));
3140 } else {
3141 // Since this buffer is not focused, apply a normal edit.
3142 let new_edit = TextEdit {
3143 range: edit.range,
3144 new_text: snippet.text,
3145 };
3146 if !edits.contains(&new_edit) {
3147 edits.push(new_edit);
3148 }
3149 }
3150 }
3151 }
3152 }
3153 if !snippet_edits.is_empty() {
3154 let buffer_id = buffer_to_edit.read(cx).remote_id();
3155 let version = if let Some(buffer_version) = op.text_document.version
3156 {
3157 local
3158 .buffer_snapshot_for_lsp_version(
3159 &buffer_to_edit,
3160 language_server.server_id(),
3161 Some(buffer_version),
3162 cx,
3163 )
3164 .ok()
3165 .map(|snapshot| snapshot.version)
3166 } else {
3167 Some(buffer_to_edit.read(cx).saved_version().clone())
3168 };
3169
3170 let most_recent_edit =
3171 version.and_then(|version| version.most_recent());
3172 // Check if the edit that triggered that edit has been made by this participant.
3173
3174 if let Some(most_recent_edit) = most_recent_edit {
3175 cx.emit(LspStoreEvent::SnippetEdit {
3176 buffer_id,
3177 edits: snippet_edits,
3178 most_recent_edit,
3179 });
3180 }
3181 }
3182
3183 local.edits_from_lsp(
3184 &buffer_to_edit,
3185 edits,
3186 language_server.server_id(),
3187 op.text_document.version,
3188 cx,
3189 )
3190 })?
3191 .await?;
3192
3193 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3194 buffer.finalize_last_transaction();
3195 buffer.start_transaction();
3196 for (range, text) in edits {
3197 buffer.edit([(range, text)], None, cx);
3198 }
3199
3200 buffer.end_transaction(cx).and_then(|transaction_id| {
3201 if push_to_history {
3202 buffer.finalize_last_transaction();
3203 buffer.get_transaction(transaction_id).cloned()
3204 } else {
3205 buffer.forget_transaction(transaction_id)
3206 }
3207 })
3208 })?;
3209 if let Some(transaction) = transaction {
3210 project_transaction.0.insert(buffer_to_edit, transaction);
3211 }
3212 }
3213 }
3214 }
3215
3216 Ok(project_transaction)
3217 }
3218
3219 async fn on_lsp_workspace_edit(
3220 this: WeakEntity<LspStore>,
3221 params: lsp::ApplyWorkspaceEditParams,
3222 server_id: LanguageServerId,
3223 cx: &mut AsyncApp,
3224 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3225 let this = this.upgrade().context("project project closed")?;
3226 let language_server = this
3227 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3228 .context("language server not found")?;
3229 let transaction = Self::deserialize_workspace_edit(
3230 this.clone(),
3231 params.edit,
3232 true,
3233 language_server.clone(),
3234 cx,
3235 )
3236 .await
3237 .log_err();
3238 this.update(cx, |this, _| {
3239 if let Some(transaction) = transaction {
3240 this.as_local_mut()
3241 .unwrap()
3242 .last_workspace_edits_by_language_server
3243 .insert(server_id, transaction);
3244 }
3245 })?;
3246 Ok(lsp::ApplyWorkspaceEditResponse {
3247 applied: true,
3248 failed_change: None,
3249 failure_reason: None,
3250 })
3251 }
3252
3253 fn remove_worktree(
3254 &mut self,
3255 id_to_remove: WorktreeId,
3256 cx: &mut Context<LspStore>,
3257 ) -> Vec<LanguageServerId> {
3258 self.diagnostics.remove(&id_to_remove);
3259 self.prettier_store.update(cx, |prettier_store, cx| {
3260 prettier_store.remove_worktree(id_to_remove, cx);
3261 });
3262
3263 let mut servers_to_remove = BTreeSet::default();
3264 let mut servers_to_preserve = HashSet::default();
3265 for (seed, state) in &self.language_server_ids {
3266 if seed.worktree_id == id_to_remove {
3267 servers_to_remove.insert(state.id);
3268 } else {
3269 servers_to_preserve.insert(state.id);
3270 }
3271 }
3272 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3273 self.language_server_ids
3274 .retain(|_, state| !servers_to_remove.contains(&state.id));
3275 for server_id_to_remove in &servers_to_remove {
3276 self.language_server_watched_paths
3277 .remove(server_id_to_remove);
3278 self.language_server_paths_watched_for_rename
3279 .remove(server_id_to_remove);
3280 self.last_workspace_edits_by_language_server
3281 .remove(server_id_to_remove);
3282 self.language_servers.remove(server_id_to_remove);
3283 self.buffer_pull_diagnostics_result_ids
3284 .remove(server_id_to_remove);
3285 self.workspace_pull_diagnostics_result_ids
3286 .remove(server_id_to_remove);
3287 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3288 buffer_servers.remove(server_id_to_remove);
3289 }
3290 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3291 }
3292 servers_to_remove.into_iter().collect()
3293 }
3294
3295 fn rebuild_watched_paths_inner<'a>(
3296 &'a self,
3297 language_server_id: LanguageServerId,
3298 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3299 cx: &mut Context<LspStore>,
3300 ) -> LanguageServerWatchedPathsBuilder {
3301 let worktrees = self
3302 .worktree_store
3303 .read(cx)
3304 .worktrees()
3305 .filter_map(|worktree| {
3306 self.language_servers_for_worktree(worktree.read(cx).id())
3307 .find(|server| server.server_id() == language_server_id)
3308 .map(|_| worktree)
3309 })
3310 .collect::<Vec<_>>();
3311
3312 let mut worktree_globs = HashMap::default();
3313 let mut abs_globs = HashMap::default();
3314 log::trace!(
3315 "Processing new watcher paths for language server with id {}",
3316 language_server_id
3317 );
3318
3319 for watcher in watchers {
3320 if let Some((worktree, literal_prefix, pattern)) =
3321 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3322 {
3323 worktree.update(cx, |worktree, _| {
3324 if let Some((tree, glob)) =
3325 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3326 {
3327 tree.add_path_prefix_to_scan(literal_prefix);
3328 worktree_globs
3329 .entry(tree.id())
3330 .or_insert_with(GlobSetBuilder::new)
3331 .add(glob);
3332 }
3333 });
3334 } else {
3335 let (path, pattern) = match &watcher.glob_pattern {
3336 lsp::GlobPattern::String(s) => {
3337 let watcher_path = SanitizedPath::new(s);
3338 let path = glob_literal_prefix(watcher_path.as_path());
3339 let pattern = watcher_path
3340 .as_path()
3341 .strip_prefix(&path)
3342 .map(|p| p.to_string_lossy().into_owned())
3343 .unwrap_or_else(|e| {
3344 debug_panic!(
3345 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3346 s,
3347 path.display(),
3348 e
3349 );
3350 watcher_path.as_path().to_string_lossy().into_owned()
3351 });
3352 (path, pattern)
3353 }
3354 lsp::GlobPattern::Relative(rp) => {
3355 let Ok(mut base_uri) = match &rp.base_uri {
3356 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3357 lsp::OneOf::Right(base_uri) => base_uri,
3358 }
3359 .to_file_path() else {
3360 continue;
3361 };
3362
3363 let path = glob_literal_prefix(Path::new(&rp.pattern));
3364 let pattern = Path::new(&rp.pattern)
3365 .strip_prefix(&path)
3366 .map(|p| p.to_string_lossy().into_owned())
3367 .unwrap_or_else(|e| {
3368 debug_panic!(
3369 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3370 rp.pattern,
3371 path.display(),
3372 e
3373 );
3374 rp.pattern.clone()
3375 });
3376 base_uri.push(path);
3377 (base_uri, pattern)
3378 }
3379 };
3380
3381 if let Some(glob) = Glob::new(&pattern).log_err() {
3382 if !path
3383 .components()
3384 .any(|c| matches!(c, path::Component::Normal(_)))
3385 {
3386 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3387 // rather than adding a new watcher for `/`.
3388 for worktree in &worktrees {
3389 worktree_globs
3390 .entry(worktree.read(cx).id())
3391 .or_insert_with(GlobSetBuilder::new)
3392 .add(glob.clone());
3393 }
3394 } else {
3395 abs_globs
3396 .entry(path.into())
3397 .or_insert_with(GlobSetBuilder::new)
3398 .add(glob);
3399 }
3400 }
3401 }
3402 }
3403
3404 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3405 for (worktree_id, builder) in worktree_globs {
3406 if let Ok(globset) = builder.build() {
3407 watch_builder.watch_worktree(worktree_id, globset);
3408 }
3409 }
3410 for (abs_path, builder) in abs_globs {
3411 if let Ok(globset) = builder.build() {
3412 watch_builder.watch_abs_path(abs_path, globset);
3413 }
3414 }
3415 watch_builder
3416 }
3417
3418 fn worktree_and_path_for_file_watcher(
3419 worktrees: &[Entity<Worktree>],
3420 watcher: &FileSystemWatcher,
3421 cx: &App,
3422 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3423 worktrees.iter().find_map(|worktree| {
3424 let tree = worktree.read(cx);
3425 let worktree_root_path = tree.abs_path();
3426 let path_style = tree.path_style();
3427 match &watcher.glob_pattern {
3428 lsp::GlobPattern::String(s) => {
3429 let watcher_path = SanitizedPath::new(s);
3430 let relative = watcher_path
3431 .as_path()
3432 .strip_prefix(&worktree_root_path)
3433 .ok()?;
3434 let literal_prefix = glob_literal_prefix(relative);
3435 Some((
3436 worktree.clone(),
3437 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3438 relative.to_string_lossy().into_owned(),
3439 ))
3440 }
3441 lsp::GlobPattern::Relative(rp) => {
3442 let base_uri = match &rp.base_uri {
3443 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3444 lsp::OneOf::Right(base_uri) => base_uri,
3445 }
3446 .to_file_path()
3447 .ok()?;
3448 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3449 let mut literal_prefix = relative.to_owned();
3450 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3451 Some((
3452 worktree.clone(),
3453 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3454 rp.pattern.clone(),
3455 ))
3456 }
3457 }
3458 })
3459 }
3460
3461 fn rebuild_watched_paths(
3462 &mut self,
3463 language_server_id: LanguageServerId,
3464 cx: &mut Context<LspStore>,
3465 ) {
3466 let Some(registrations) = self
3467 .language_server_dynamic_registrations
3468 .get(&language_server_id)
3469 else {
3470 return;
3471 };
3472
3473 let watch_builder = self.rebuild_watched_paths_inner(
3474 language_server_id,
3475 registrations.did_change_watched_files.values().flatten(),
3476 cx,
3477 );
3478 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3479 self.language_server_watched_paths
3480 .insert(language_server_id, watcher);
3481
3482 cx.notify();
3483 }
3484
3485 fn on_lsp_did_change_watched_files(
3486 &mut self,
3487 language_server_id: LanguageServerId,
3488 registration_id: &str,
3489 params: DidChangeWatchedFilesRegistrationOptions,
3490 cx: &mut Context<LspStore>,
3491 ) {
3492 let registrations = self
3493 .language_server_dynamic_registrations
3494 .entry(language_server_id)
3495 .or_default();
3496
3497 registrations
3498 .did_change_watched_files
3499 .insert(registration_id.to_string(), params.watchers);
3500
3501 self.rebuild_watched_paths(language_server_id, cx);
3502 }
3503
3504 fn on_lsp_unregister_did_change_watched_files(
3505 &mut self,
3506 language_server_id: LanguageServerId,
3507 registration_id: &str,
3508 cx: &mut Context<LspStore>,
3509 ) {
3510 let registrations = self
3511 .language_server_dynamic_registrations
3512 .entry(language_server_id)
3513 .or_default();
3514
3515 if registrations
3516 .did_change_watched_files
3517 .remove(registration_id)
3518 .is_some()
3519 {
3520 log::info!(
3521 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3522 language_server_id,
3523 registration_id
3524 );
3525 } else {
3526 log::warn!(
3527 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3528 language_server_id,
3529 registration_id
3530 );
3531 }
3532
3533 self.rebuild_watched_paths(language_server_id, cx);
3534 }
3535
3536 async fn initialization_options_for_adapter(
3537 adapter: Arc<dyn LspAdapter>,
3538 delegate: &Arc<dyn LspAdapterDelegate>,
3539 ) -> Result<Option<serde_json::Value>> {
3540 let Some(mut initialization_config) =
3541 adapter.clone().initialization_options(delegate).await?
3542 else {
3543 return Ok(None);
3544 };
3545
3546 for other_adapter in delegate.registered_lsp_adapters() {
3547 if other_adapter.name() == adapter.name() {
3548 continue;
3549 }
3550 if let Ok(Some(target_config)) = other_adapter
3551 .clone()
3552 .additional_initialization_options(adapter.name(), delegate)
3553 .await
3554 {
3555 merge_json_value_into(target_config.clone(), &mut initialization_config);
3556 }
3557 }
3558
3559 Ok(Some(initialization_config))
3560 }
3561
3562 async fn workspace_configuration_for_adapter(
3563 adapter: Arc<dyn LspAdapter>,
3564 delegate: &Arc<dyn LspAdapterDelegate>,
3565 toolchain: Option<Toolchain>,
3566 requested_uri: Option<Uri>,
3567 cx: &mut AsyncApp,
3568 ) -> Result<serde_json::Value> {
3569 let mut workspace_config = adapter
3570 .clone()
3571 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3572 .await?;
3573
3574 for other_adapter in delegate.registered_lsp_adapters() {
3575 if other_adapter.name() == adapter.name() {
3576 continue;
3577 }
3578 if let Ok(Some(target_config)) = other_adapter
3579 .clone()
3580 .additional_workspace_configuration(adapter.name(), delegate, cx)
3581 .await
3582 {
3583 merge_json_value_into(target_config.clone(), &mut workspace_config);
3584 }
3585 }
3586
3587 Ok(workspace_config)
3588 }
3589
3590 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3591 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3592 Some(server.clone())
3593 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3594 Some(Arc::clone(server))
3595 } else {
3596 None
3597 }
3598 }
3599}
3600
3601fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3602 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3603 cx.emit(LspStoreEvent::LanguageServerUpdate {
3604 language_server_id: server.server_id(),
3605 name: Some(server.name()),
3606 message: proto::update_language_server::Variant::MetadataUpdated(
3607 proto::ServerMetadataUpdated {
3608 capabilities: Some(capabilities),
3609 binary: Some(proto::LanguageServerBinaryInfo {
3610 path: server.binary().path.to_string_lossy().into_owned(),
3611 arguments: server
3612 .binary()
3613 .arguments
3614 .iter()
3615 .map(|arg| arg.to_string_lossy().into_owned())
3616 .collect(),
3617 }),
3618 configuration: serde_json::to_string(server.configuration()).ok(),
3619 workspace_folders: server
3620 .workspace_folders()
3621 .iter()
3622 .map(|uri| uri.to_string())
3623 .collect(),
3624 },
3625 ),
3626 });
3627 }
3628}
3629
3630#[derive(Debug)]
3631pub struct FormattableBuffer {
3632 handle: Entity<Buffer>,
3633 abs_path: Option<PathBuf>,
3634 env: Option<HashMap<String, String>>,
3635 ranges: Option<Vec<Range<Anchor>>>,
3636}
3637
3638pub struct RemoteLspStore {
3639 upstream_client: Option<AnyProtoClient>,
3640 upstream_project_id: u64,
3641}
3642
3643pub(crate) enum LspStoreMode {
3644 Local(LocalLspStore), // ssh host and collab host
3645 Remote(RemoteLspStore), // collab guest
3646}
3647
3648impl LspStoreMode {
3649 fn is_local(&self) -> bool {
3650 matches!(self, LspStoreMode::Local(_))
3651 }
3652}
3653
3654pub struct LspStore {
3655 mode: LspStoreMode,
3656 last_formatting_failure: Option<String>,
3657 downstream_client: Option<(AnyProtoClient, u64)>,
3658 nonce: u128,
3659 buffer_store: Entity<BufferStore>,
3660 worktree_store: Entity<WorktreeStore>,
3661 pub languages: Arc<LanguageRegistry>,
3662 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3663 active_entry: Option<ProjectEntryId>,
3664 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3665 _maintain_buffer_languages: Task<()>,
3666 diagnostic_summaries:
3667 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3668 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3669 lsp_data: HashMap<BufferId, BufferLspData>,
3670 next_hint_id: Arc<AtomicUsize>,
3671}
3672
3673#[derive(Debug)]
3674pub struct BufferLspData {
3675 buffer_version: Global,
3676 document_colors: Option<DocumentColorData>,
3677 code_lens: Option<CodeLensData>,
3678 inlay_hints: BufferInlayHints,
3679 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3680 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3681}
3682
3683#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3684struct LspKey {
3685 request_type: TypeId,
3686 server_queried: Option<LanguageServerId>,
3687}
3688
3689impl BufferLspData {
3690 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3691 Self {
3692 buffer_version: buffer.read(cx).version(),
3693 document_colors: None,
3694 code_lens: None,
3695 inlay_hints: BufferInlayHints::new(buffer, cx),
3696 lsp_requests: HashMap::default(),
3697 chunk_lsp_requests: HashMap::default(),
3698 }
3699 }
3700
3701 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3702 if let Some(document_colors) = &mut self.document_colors {
3703 document_colors.colors.remove(&for_server);
3704 document_colors.cache_version += 1;
3705 }
3706
3707 if let Some(code_lens) = &mut self.code_lens {
3708 code_lens.lens.remove(&for_server);
3709 }
3710
3711 self.inlay_hints.remove_server_data(for_server);
3712 }
3713
3714 #[cfg(any(test, feature = "test-support"))]
3715 pub fn inlay_hints(&self) -> &BufferInlayHints {
3716 &self.inlay_hints
3717 }
3718}
3719
3720#[derive(Debug, Default, Clone)]
3721pub struct DocumentColors {
3722 pub colors: HashSet<DocumentColor>,
3723 pub cache_version: Option<usize>,
3724}
3725
3726type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3727type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3728
3729#[derive(Debug, Default)]
3730struct DocumentColorData {
3731 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3732 cache_version: usize,
3733 colors_update: Option<(Global, DocumentColorTask)>,
3734}
3735
3736#[derive(Debug, Default)]
3737struct CodeLensData {
3738 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3739 update: Option<(Global, CodeLensTask)>,
3740}
3741
3742#[derive(Debug)]
3743pub enum LspStoreEvent {
3744 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3745 LanguageServerRemoved(LanguageServerId),
3746 LanguageServerUpdate {
3747 language_server_id: LanguageServerId,
3748 name: Option<LanguageServerName>,
3749 message: proto::update_language_server::Variant,
3750 },
3751 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3752 LanguageServerPrompt(LanguageServerPromptRequest),
3753 LanguageDetected {
3754 buffer: Entity<Buffer>,
3755 new_language: Option<Arc<Language>>,
3756 },
3757 Notification(String),
3758 RefreshInlayHints {
3759 server_id: LanguageServerId,
3760 request_id: Option<usize>,
3761 },
3762 RefreshCodeLens,
3763 DiagnosticsUpdated {
3764 server_id: LanguageServerId,
3765 paths: Vec<ProjectPath>,
3766 },
3767 DiskBasedDiagnosticsStarted {
3768 language_server_id: LanguageServerId,
3769 },
3770 DiskBasedDiagnosticsFinished {
3771 language_server_id: LanguageServerId,
3772 },
3773 SnippetEdit {
3774 buffer_id: BufferId,
3775 edits: Vec<(lsp::Range, Snippet)>,
3776 most_recent_edit: clock::Lamport,
3777 },
3778}
3779
3780#[derive(Clone, Debug, Serialize)]
3781pub struct LanguageServerStatus {
3782 pub name: LanguageServerName,
3783 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3784 pub has_pending_diagnostic_updates: bool,
3785 pub progress_tokens: HashSet<ProgressToken>,
3786 pub worktree: Option<WorktreeId>,
3787 pub binary: Option<LanguageServerBinary>,
3788 pub configuration: Option<Value>,
3789 pub workspace_folders: BTreeSet<Uri>,
3790}
3791
3792#[derive(Clone, Debug)]
3793struct CoreSymbol {
3794 pub language_server_name: LanguageServerName,
3795 pub source_worktree_id: WorktreeId,
3796 pub source_language_server_id: LanguageServerId,
3797 pub path: SymbolLocation,
3798 pub name: String,
3799 pub kind: lsp::SymbolKind,
3800 pub range: Range<Unclipped<PointUtf16>>,
3801}
3802
3803#[derive(Clone, Debug, PartialEq, Eq)]
3804pub enum SymbolLocation {
3805 InProject(ProjectPath),
3806 OutsideProject {
3807 abs_path: Arc<Path>,
3808 signature: [u8; 32],
3809 },
3810}
3811
3812impl SymbolLocation {
3813 fn file_name(&self) -> Option<&str> {
3814 match self {
3815 Self::InProject(path) => path.path.file_name(),
3816 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3817 }
3818 }
3819}
3820
3821impl LspStore {
3822 pub fn init(client: &AnyProtoClient) {
3823 client.add_entity_request_handler(Self::handle_lsp_query);
3824 client.add_entity_message_handler(Self::handle_lsp_query_response);
3825 client.add_entity_request_handler(Self::handle_restart_language_servers);
3826 client.add_entity_request_handler(Self::handle_stop_language_servers);
3827 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3828 client.add_entity_message_handler(Self::handle_start_language_server);
3829 client.add_entity_message_handler(Self::handle_update_language_server);
3830 client.add_entity_message_handler(Self::handle_language_server_log);
3831 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3832 client.add_entity_request_handler(Self::handle_format_buffers);
3833 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3834 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3835 client.add_entity_request_handler(Self::handle_apply_code_action);
3836 client.add_entity_request_handler(Self::handle_get_project_symbols);
3837 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3838 client.add_entity_request_handler(Self::handle_get_color_presentation);
3839 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3840 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3841 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3842 client.add_entity_request_handler(Self::handle_on_type_formatting);
3843 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3844 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3845 client.add_entity_request_handler(Self::handle_rename_project_entry);
3846 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3847 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3848 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3849 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3850 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3851 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3852 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3853
3854 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3855 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3856 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3857 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3858 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3859 client.add_entity_request_handler(
3860 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3861 );
3862 client.add_entity_request_handler(
3863 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3864 );
3865 client.add_entity_request_handler(
3866 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3867 );
3868 }
3869
3870 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3871 match &self.mode {
3872 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3873 _ => None,
3874 }
3875 }
3876
3877 pub fn as_local(&self) -> Option<&LocalLspStore> {
3878 match &self.mode {
3879 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3880 _ => None,
3881 }
3882 }
3883
3884 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3885 match &mut self.mode {
3886 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3887 _ => None,
3888 }
3889 }
3890
3891 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3892 match &self.mode {
3893 LspStoreMode::Remote(RemoteLspStore {
3894 upstream_client: Some(upstream_client),
3895 upstream_project_id,
3896 ..
3897 }) => Some((upstream_client.clone(), *upstream_project_id)),
3898
3899 LspStoreMode::Remote(RemoteLspStore {
3900 upstream_client: None,
3901 ..
3902 }) => None,
3903 LspStoreMode::Local(_) => None,
3904 }
3905 }
3906
3907 pub fn new_local(
3908 buffer_store: Entity<BufferStore>,
3909 worktree_store: Entity<WorktreeStore>,
3910 prettier_store: Entity<PrettierStore>,
3911 toolchain_store: Entity<LocalToolchainStore>,
3912 environment: Entity<ProjectEnvironment>,
3913 manifest_tree: Entity<ManifestTree>,
3914 languages: Arc<LanguageRegistry>,
3915 http_client: Arc<dyn HttpClient>,
3916 fs: Arc<dyn Fs>,
3917 cx: &mut Context<Self>,
3918 ) -> Self {
3919 let yarn = YarnPathStore::new(fs.clone(), cx);
3920 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3921 .detach();
3922 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3923 .detach();
3924 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3925 .detach();
3926 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3927 .detach();
3928 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3929 .detach();
3930 subscribe_to_binary_statuses(&languages, cx).detach();
3931
3932 let _maintain_workspace_config = {
3933 let (sender, receiver) = watch::channel();
3934 (Self::maintain_workspace_config(receiver, cx), sender)
3935 };
3936
3937 Self {
3938 mode: LspStoreMode::Local(LocalLspStore {
3939 weak: cx.weak_entity(),
3940 worktree_store: worktree_store.clone(),
3941
3942 supplementary_language_servers: Default::default(),
3943 languages: languages.clone(),
3944 language_server_ids: Default::default(),
3945 language_servers: Default::default(),
3946 last_workspace_edits_by_language_server: Default::default(),
3947 language_server_watched_paths: Default::default(),
3948 language_server_paths_watched_for_rename: Default::default(),
3949 language_server_dynamic_registrations: Default::default(),
3950 buffers_being_formatted: Default::default(),
3951 buffer_snapshots: Default::default(),
3952 prettier_store,
3953 environment,
3954 http_client,
3955 fs,
3956 yarn,
3957 next_diagnostic_group_id: Default::default(),
3958 diagnostics: Default::default(),
3959 _subscription: cx.on_app_quit(|this, cx| {
3960 this.as_local_mut()
3961 .unwrap()
3962 .shutdown_language_servers_on_quit(cx)
3963 }),
3964 lsp_tree: LanguageServerTree::new(
3965 manifest_tree,
3966 languages.clone(),
3967 toolchain_store.clone(),
3968 ),
3969 toolchain_store,
3970 registered_buffers: HashMap::default(),
3971 buffers_opened_in_servers: HashMap::default(),
3972 buffer_pull_diagnostics_result_ids: HashMap::default(),
3973 workspace_pull_diagnostics_result_ids: HashMap::default(),
3974 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3975 .manifest_file_names(),
3976 }),
3977 last_formatting_failure: None,
3978 downstream_client: None,
3979 buffer_store,
3980 worktree_store,
3981 languages: languages.clone(),
3982 language_server_statuses: Default::default(),
3983 nonce: StdRng::from_os_rng().random(),
3984 diagnostic_summaries: HashMap::default(),
3985 lsp_server_capabilities: HashMap::default(),
3986 lsp_data: HashMap::default(),
3987 next_hint_id: Arc::default(),
3988 active_entry: None,
3989 _maintain_workspace_config,
3990 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3991 }
3992 }
3993
3994 fn send_lsp_proto_request<R: LspCommand>(
3995 &self,
3996 buffer: Entity<Buffer>,
3997 client: AnyProtoClient,
3998 upstream_project_id: u64,
3999 request: R,
4000 cx: &mut Context<LspStore>,
4001 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4002 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4003 return Task::ready(Ok(R::Response::default()));
4004 }
4005 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4006 cx.spawn(async move |this, cx| {
4007 let response = client.request(message).await?;
4008 let this = this.upgrade().context("project dropped")?;
4009 request
4010 .response_from_proto(response, this, buffer, cx.clone())
4011 .await
4012 })
4013 }
4014
4015 pub(super) fn new_remote(
4016 buffer_store: Entity<BufferStore>,
4017 worktree_store: Entity<WorktreeStore>,
4018 languages: Arc<LanguageRegistry>,
4019 upstream_client: AnyProtoClient,
4020 project_id: u64,
4021 cx: &mut Context<Self>,
4022 ) -> Self {
4023 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4024 .detach();
4025 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4026 .detach();
4027 subscribe_to_binary_statuses(&languages, cx).detach();
4028 let _maintain_workspace_config = {
4029 let (sender, receiver) = watch::channel();
4030 (Self::maintain_workspace_config(receiver, cx), sender)
4031 };
4032 Self {
4033 mode: LspStoreMode::Remote(RemoteLspStore {
4034 upstream_client: Some(upstream_client),
4035 upstream_project_id: project_id,
4036 }),
4037 downstream_client: None,
4038 last_formatting_failure: None,
4039 buffer_store,
4040 worktree_store,
4041 languages: languages.clone(),
4042 language_server_statuses: Default::default(),
4043 nonce: StdRng::from_os_rng().random(),
4044 diagnostic_summaries: HashMap::default(),
4045 lsp_server_capabilities: HashMap::default(),
4046 next_hint_id: Arc::default(),
4047 lsp_data: HashMap::default(),
4048 active_entry: None,
4049
4050 _maintain_workspace_config,
4051 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4052 }
4053 }
4054
4055 fn on_buffer_store_event(
4056 &mut self,
4057 _: Entity<BufferStore>,
4058 event: &BufferStoreEvent,
4059 cx: &mut Context<Self>,
4060 ) {
4061 match event {
4062 BufferStoreEvent::BufferAdded(buffer) => {
4063 self.on_buffer_added(buffer, cx).log_err();
4064 }
4065 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4066 let buffer_id = buffer.read(cx).remote_id();
4067 if let Some(local) = self.as_local_mut()
4068 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4069 {
4070 local.reset_buffer(buffer, old_file, cx);
4071
4072 if local.registered_buffers.contains_key(&buffer_id) {
4073 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4074 }
4075 }
4076
4077 self.detect_language_for_buffer(buffer, cx);
4078 if let Some(local) = self.as_local_mut() {
4079 local.initialize_buffer(buffer, cx);
4080 if local.registered_buffers.contains_key(&buffer_id) {
4081 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4082 }
4083 }
4084 }
4085 _ => {}
4086 }
4087 }
4088
4089 fn on_worktree_store_event(
4090 &mut self,
4091 _: Entity<WorktreeStore>,
4092 event: &WorktreeStoreEvent,
4093 cx: &mut Context<Self>,
4094 ) {
4095 match event {
4096 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4097 if !worktree.read(cx).is_local() {
4098 return;
4099 }
4100 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4101 worktree::Event::UpdatedEntries(changes) => {
4102 this.update_local_worktree_language_servers(&worktree, changes, cx);
4103 }
4104 worktree::Event::UpdatedGitRepositories(_)
4105 | worktree::Event::DeletedEntry(_) => {}
4106 })
4107 .detach()
4108 }
4109 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4110 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4111 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4112 }
4113 WorktreeStoreEvent::WorktreeReleased(..)
4114 | WorktreeStoreEvent::WorktreeOrderChanged
4115 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4116 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4117 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4118 }
4119 }
4120
4121 fn on_prettier_store_event(
4122 &mut self,
4123 _: Entity<PrettierStore>,
4124 event: &PrettierStoreEvent,
4125 cx: &mut Context<Self>,
4126 ) {
4127 match event {
4128 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4129 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4130 }
4131 PrettierStoreEvent::LanguageServerAdded {
4132 new_server_id,
4133 name,
4134 prettier_server,
4135 } => {
4136 self.register_supplementary_language_server(
4137 *new_server_id,
4138 name.clone(),
4139 prettier_server.clone(),
4140 cx,
4141 );
4142 }
4143 }
4144 }
4145
4146 fn on_toolchain_store_event(
4147 &mut self,
4148 _: Entity<LocalToolchainStore>,
4149 event: &ToolchainStoreEvent,
4150 _: &mut Context<Self>,
4151 ) {
4152 if let ToolchainStoreEvent::ToolchainActivated = event {
4153 self.request_workspace_config_refresh()
4154 }
4155 }
4156
4157 fn request_workspace_config_refresh(&mut self) {
4158 *self._maintain_workspace_config.1.borrow_mut() = ();
4159 }
4160
4161 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4162 self.as_local().map(|local| local.prettier_store.clone())
4163 }
4164
4165 fn on_buffer_event(
4166 &mut self,
4167 buffer: Entity<Buffer>,
4168 event: &language::BufferEvent,
4169 cx: &mut Context<Self>,
4170 ) {
4171 match event {
4172 language::BufferEvent::Edited => {
4173 self.on_buffer_edited(buffer, cx);
4174 }
4175
4176 language::BufferEvent::Saved => {
4177 self.on_buffer_saved(buffer, cx);
4178 }
4179
4180 _ => {}
4181 }
4182 }
4183
4184 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4185 buffer
4186 .read(cx)
4187 .set_language_registry(self.languages.clone());
4188
4189 cx.subscribe(buffer, |this, buffer, event, cx| {
4190 this.on_buffer_event(buffer, event, cx);
4191 })
4192 .detach();
4193
4194 self.detect_language_for_buffer(buffer, cx);
4195 if let Some(local) = self.as_local_mut() {
4196 local.initialize_buffer(buffer, cx);
4197 }
4198
4199 Ok(())
4200 }
4201
4202 pub(crate) fn register_buffer_with_language_servers(
4203 &mut self,
4204 buffer: &Entity<Buffer>,
4205 only_register_servers: HashSet<LanguageServerSelector>,
4206 ignore_refcounts: bool,
4207 cx: &mut Context<Self>,
4208 ) -> OpenLspBufferHandle {
4209 let buffer_id = buffer.read(cx).remote_id();
4210 let handle = cx.new(|_| buffer.clone());
4211 if let Some(local) = self.as_local_mut() {
4212 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4213 if !ignore_refcounts {
4214 *refcount += 1;
4215 }
4216
4217 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4218 // 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
4219 // 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
4220 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4221 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4222 return handle;
4223 };
4224 if !file.is_local() {
4225 return handle;
4226 }
4227
4228 if ignore_refcounts || *refcount == 1 {
4229 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4230 }
4231 if !ignore_refcounts {
4232 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4233 let refcount = {
4234 let local = lsp_store.as_local_mut().unwrap();
4235 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4236 debug_panic!("bad refcounting");
4237 return;
4238 };
4239
4240 *refcount -= 1;
4241 *refcount
4242 };
4243 if refcount == 0 {
4244 lsp_store.lsp_data.remove(&buffer_id);
4245 let local = lsp_store.as_local_mut().unwrap();
4246 local.registered_buffers.remove(&buffer_id);
4247
4248 local.buffers_opened_in_servers.remove(&buffer_id);
4249 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4250 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4251
4252 let buffer_abs_path = file.abs_path(cx);
4253 for (_, buffer_pull_diagnostics_result_ids) in
4254 &mut local.buffer_pull_diagnostics_result_ids
4255 {
4256 buffer_pull_diagnostics_result_ids.retain(
4257 |_, buffer_result_ids| {
4258 buffer_result_ids.remove(&buffer_abs_path);
4259 !buffer_result_ids.is_empty()
4260 },
4261 );
4262 }
4263
4264 let diagnostic_updates = local
4265 .language_servers
4266 .keys()
4267 .cloned()
4268 .map(|server_id| DocumentDiagnosticsUpdate {
4269 diagnostics: DocumentDiagnostics {
4270 document_abs_path: buffer_abs_path.clone(),
4271 version: None,
4272 diagnostics: Vec::new(),
4273 },
4274 result_id: None,
4275 registration_id: None,
4276 server_id: server_id,
4277 disk_based_sources: Cow::Borrowed(&[]),
4278 })
4279 .collect::<Vec<_>>();
4280
4281 lsp_store
4282 .merge_diagnostic_entries(
4283 diagnostic_updates,
4284 |_, diagnostic, _| {
4285 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4286 },
4287 cx,
4288 )
4289 .context("Clearing diagnostics for the closed buffer")
4290 .log_err();
4291 }
4292 }
4293 })
4294 .detach();
4295 }
4296 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4297 let buffer_id = buffer.read(cx).remote_id().to_proto();
4298 cx.background_spawn(async move {
4299 upstream_client
4300 .request(proto::RegisterBufferWithLanguageServers {
4301 project_id: upstream_project_id,
4302 buffer_id,
4303 only_servers: only_register_servers
4304 .into_iter()
4305 .map(|selector| {
4306 let selector = match selector {
4307 LanguageServerSelector::Id(language_server_id) => {
4308 proto::language_server_selector::Selector::ServerId(
4309 language_server_id.to_proto(),
4310 )
4311 }
4312 LanguageServerSelector::Name(language_server_name) => {
4313 proto::language_server_selector::Selector::Name(
4314 language_server_name.to_string(),
4315 )
4316 }
4317 };
4318 proto::LanguageServerSelector {
4319 selector: Some(selector),
4320 }
4321 })
4322 .collect(),
4323 })
4324 .await
4325 })
4326 .detach();
4327 } else {
4328 // Our remote connection got closed
4329 }
4330 handle
4331 }
4332
4333 fn maintain_buffer_languages(
4334 languages: Arc<LanguageRegistry>,
4335 cx: &mut Context<Self>,
4336 ) -> Task<()> {
4337 let mut subscription = languages.subscribe();
4338 let mut prev_reload_count = languages.reload_count();
4339 cx.spawn(async move |this, cx| {
4340 while let Some(()) = subscription.next().await {
4341 if let Some(this) = this.upgrade() {
4342 // If the language registry has been reloaded, then remove and
4343 // re-assign the languages on all open buffers.
4344 let reload_count = languages.reload_count();
4345 if reload_count > prev_reload_count {
4346 prev_reload_count = reload_count;
4347 this.update(cx, |this, cx| {
4348 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4349 for buffer in buffer_store.buffers() {
4350 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4351 {
4352 buffer.update(cx, |buffer, cx| {
4353 buffer.set_language_async(None, cx)
4354 });
4355 if let Some(local) = this.as_local_mut() {
4356 local.reset_buffer(&buffer, &f, cx);
4357
4358 if local
4359 .registered_buffers
4360 .contains_key(&buffer.read(cx).remote_id())
4361 && let Some(file_url) =
4362 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4363 {
4364 local.unregister_buffer_from_language_servers(
4365 &buffer, &file_url, cx,
4366 );
4367 }
4368 }
4369 }
4370 }
4371 });
4372 })
4373 .ok();
4374 }
4375
4376 this.update(cx, |this, cx| {
4377 let mut plain_text_buffers = Vec::new();
4378 let mut buffers_with_unknown_injections = Vec::new();
4379 for handle in this.buffer_store.read(cx).buffers() {
4380 let buffer = handle.read(cx);
4381 if buffer.language().is_none()
4382 || buffer.language() == Some(&*language::PLAIN_TEXT)
4383 {
4384 plain_text_buffers.push(handle);
4385 } else if buffer.contains_unknown_injections() {
4386 buffers_with_unknown_injections.push(handle);
4387 }
4388 }
4389
4390 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4391 // and reused later in the invisible worktrees.
4392 plain_text_buffers.sort_by_key(|buffer| {
4393 Reverse(
4394 File::from_dyn(buffer.read(cx).file())
4395 .map(|file| file.worktree.read(cx).is_visible()),
4396 )
4397 });
4398
4399 for buffer in plain_text_buffers {
4400 this.detect_language_for_buffer(&buffer, cx);
4401 if let Some(local) = this.as_local_mut() {
4402 local.initialize_buffer(&buffer, cx);
4403 if local
4404 .registered_buffers
4405 .contains_key(&buffer.read(cx).remote_id())
4406 {
4407 local.register_buffer_with_language_servers(
4408 &buffer,
4409 HashSet::default(),
4410 cx,
4411 );
4412 }
4413 }
4414 }
4415
4416 for buffer in buffers_with_unknown_injections {
4417 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4418 }
4419 })
4420 .ok();
4421 }
4422 }
4423 })
4424 }
4425
4426 fn detect_language_for_buffer(
4427 &mut self,
4428 buffer_handle: &Entity<Buffer>,
4429 cx: &mut Context<Self>,
4430 ) -> Option<language::AvailableLanguage> {
4431 // If the buffer has a language, set it and start the language server if we haven't already.
4432 let buffer = buffer_handle.read(cx);
4433 let file = buffer.file()?;
4434
4435 let content = buffer.as_rope();
4436 let available_language = self.languages.language_for_file(file, Some(content), cx);
4437 if let Some(available_language) = &available_language {
4438 if let Some(Ok(Ok(new_language))) = self
4439 .languages
4440 .load_language(available_language)
4441 .now_or_never()
4442 {
4443 self.set_language_for_buffer(buffer_handle, new_language, cx);
4444 }
4445 } else {
4446 cx.emit(LspStoreEvent::LanguageDetected {
4447 buffer: buffer_handle.clone(),
4448 new_language: None,
4449 });
4450 }
4451
4452 available_language
4453 }
4454
4455 pub(crate) fn set_language_for_buffer(
4456 &mut self,
4457 buffer_entity: &Entity<Buffer>,
4458 new_language: Arc<Language>,
4459 cx: &mut Context<Self>,
4460 ) {
4461 let buffer = buffer_entity.read(cx);
4462 let buffer_file = buffer.file().cloned();
4463 let buffer_id = buffer.remote_id();
4464 if let Some(local_store) = self.as_local_mut()
4465 && local_store.registered_buffers.contains_key(&buffer_id)
4466 && let Some(abs_path) =
4467 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4468 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4469 {
4470 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4471 }
4472 buffer_entity.update(cx, |buffer, cx| {
4473 if buffer
4474 .language()
4475 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4476 {
4477 buffer.set_language_async(Some(new_language.clone()), cx);
4478 }
4479 });
4480
4481 let settings =
4482 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4483 let buffer_file = File::from_dyn(buffer_file.as_ref());
4484
4485 let worktree_id = if let Some(file) = buffer_file {
4486 let worktree = file.worktree.clone();
4487
4488 if let Some(local) = self.as_local_mut()
4489 && local.registered_buffers.contains_key(&buffer_id)
4490 {
4491 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4492 }
4493 Some(worktree.read(cx).id())
4494 } else {
4495 None
4496 };
4497
4498 if settings.prettier.allowed
4499 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4500 {
4501 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4502 if let Some(prettier_store) = prettier_store {
4503 prettier_store.update(cx, |prettier_store, cx| {
4504 prettier_store.install_default_prettier(
4505 worktree_id,
4506 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4507 cx,
4508 )
4509 })
4510 }
4511 }
4512
4513 cx.emit(LspStoreEvent::LanguageDetected {
4514 buffer: buffer_entity.clone(),
4515 new_language: Some(new_language),
4516 })
4517 }
4518
4519 pub fn buffer_store(&self) -> Entity<BufferStore> {
4520 self.buffer_store.clone()
4521 }
4522
4523 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4524 self.active_entry = active_entry;
4525 }
4526
4527 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4528 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4529 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4530 {
4531 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4532 summaries
4533 .iter()
4534 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4535 });
4536 if let Some(summary) = summaries.next() {
4537 client
4538 .send(proto::UpdateDiagnosticSummary {
4539 project_id: downstream_project_id,
4540 worktree_id: worktree.id().to_proto(),
4541 summary: Some(summary),
4542 more_summaries: summaries.collect(),
4543 })
4544 .log_err();
4545 }
4546 }
4547 }
4548
4549 fn is_capable_for_proto_request<R>(
4550 &self,
4551 buffer: &Entity<Buffer>,
4552 request: &R,
4553 cx: &App,
4554 ) -> bool
4555 where
4556 R: LspCommand,
4557 {
4558 self.check_if_capable_for_proto_request(
4559 buffer,
4560 |capabilities| {
4561 request.check_capabilities(AdapterServerCapabilities {
4562 server_capabilities: capabilities.clone(),
4563 code_action_kinds: None,
4564 })
4565 },
4566 cx,
4567 )
4568 }
4569
4570 fn check_if_capable_for_proto_request<F>(
4571 &self,
4572 buffer: &Entity<Buffer>,
4573 check: F,
4574 cx: &App,
4575 ) -> bool
4576 where
4577 F: FnMut(&lsp::ServerCapabilities) -> bool,
4578 {
4579 let Some(language) = buffer.read(cx).language().cloned() else {
4580 return false;
4581 };
4582 let relevant_language_servers = self
4583 .languages
4584 .lsp_adapters(&language.name())
4585 .into_iter()
4586 .map(|lsp_adapter| lsp_adapter.name())
4587 .collect::<HashSet<_>>();
4588 self.language_server_statuses
4589 .iter()
4590 .filter_map(|(server_id, server_status)| {
4591 relevant_language_servers
4592 .contains(&server_status.name)
4593 .then_some(server_id)
4594 })
4595 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4596 .any(check)
4597 }
4598
4599 fn all_capable_for_proto_request<F>(
4600 &self,
4601 buffer: &Entity<Buffer>,
4602 mut check: F,
4603 cx: &App,
4604 ) -> Vec<lsp::LanguageServerId>
4605 where
4606 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4607 {
4608 let Some(language) = buffer.read(cx).language().cloned() else {
4609 return Vec::default();
4610 };
4611 let relevant_language_servers = self
4612 .languages
4613 .lsp_adapters(&language.name())
4614 .into_iter()
4615 .map(|lsp_adapter| lsp_adapter.name())
4616 .collect::<HashSet<_>>();
4617 self.language_server_statuses
4618 .iter()
4619 .filter_map(|(server_id, server_status)| {
4620 relevant_language_servers
4621 .contains(&server_status.name)
4622 .then_some((server_id, &server_status.name))
4623 })
4624 .filter_map(|(server_id, server_name)| {
4625 self.lsp_server_capabilities
4626 .get(server_id)
4627 .map(|c| (server_id, server_name, c))
4628 })
4629 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4630 .map(|(server_id, _, _)| *server_id)
4631 .collect()
4632 }
4633
4634 pub fn request_lsp<R>(
4635 &mut self,
4636 buffer: Entity<Buffer>,
4637 server: LanguageServerToQuery,
4638 request: R,
4639 cx: &mut Context<Self>,
4640 ) -> Task<Result<R::Response>>
4641 where
4642 R: LspCommand,
4643 <R::LspRequest as lsp::request::Request>::Result: Send,
4644 <R::LspRequest as lsp::request::Request>::Params: Send,
4645 {
4646 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4647 return self.send_lsp_proto_request(
4648 buffer,
4649 upstream_client,
4650 upstream_project_id,
4651 request,
4652 cx,
4653 );
4654 }
4655
4656 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4657 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4658 local
4659 .language_servers_for_buffer(buffer, cx)
4660 .find(|(_, server)| {
4661 request.check_capabilities(server.adapter_server_capabilities())
4662 })
4663 .map(|(_, server)| server.clone())
4664 }),
4665 LanguageServerToQuery::Other(id) => self
4666 .language_server_for_local_buffer(buffer, id, cx)
4667 .and_then(|(_, server)| {
4668 request
4669 .check_capabilities(server.adapter_server_capabilities())
4670 .then(|| Arc::clone(server))
4671 }),
4672 }) else {
4673 return Task::ready(Ok(Default::default()));
4674 };
4675
4676 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4677
4678 let Some(file) = file else {
4679 return Task::ready(Ok(Default::default()));
4680 };
4681
4682 let lsp_params = match request.to_lsp_params_or_response(
4683 &file.abs_path(cx),
4684 buffer.read(cx),
4685 &language_server,
4686 cx,
4687 ) {
4688 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4689 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4690 Err(err) => {
4691 let message = format!(
4692 "{} via {} failed: {}",
4693 request.display_name(),
4694 language_server.name(),
4695 err
4696 );
4697 // rust-analyzer likes to error with this when its still loading up
4698 if !message.ends_with("content modified") {
4699 log::warn!("{message}");
4700 }
4701 return Task::ready(Err(anyhow!(message)));
4702 }
4703 };
4704
4705 let status = request.status();
4706 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4707 return Task::ready(Ok(Default::default()));
4708 }
4709 cx.spawn(async move |this, cx| {
4710 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4711
4712 let id = lsp_request.id();
4713 let _cleanup = if status.is_some() {
4714 cx.update(|cx| {
4715 this.update(cx, |this, cx| {
4716 this.on_lsp_work_start(
4717 language_server.server_id(),
4718 ProgressToken::Number(id),
4719 LanguageServerProgress {
4720 is_disk_based_diagnostics_progress: false,
4721 is_cancellable: false,
4722 title: None,
4723 message: status.clone(),
4724 percentage: None,
4725 last_update_at: cx.background_executor().now(),
4726 },
4727 cx,
4728 );
4729 })
4730 })
4731 .log_err();
4732
4733 Some(defer(|| {
4734 cx.update(|cx| {
4735 this.update(cx, |this, cx| {
4736 this.on_lsp_work_end(
4737 language_server.server_id(),
4738 ProgressToken::Number(id),
4739 cx,
4740 );
4741 })
4742 })
4743 .log_err();
4744 }))
4745 } else {
4746 None
4747 };
4748
4749 let result = lsp_request.await.into_response();
4750
4751 let response = result.map_err(|err| {
4752 let message = format!(
4753 "{} via {} failed: {}",
4754 request.display_name(),
4755 language_server.name(),
4756 err
4757 );
4758 // rust-analyzer likes to error with this when its still loading up
4759 if !message.ends_with("content modified") {
4760 log::warn!("{message}");
4761 }
4762 anyhow::anyhow!(message)
4763 })?;
4764
4765 request
4766 .response_from_lsp(
4767 response,
4768 this.upgrade().context("no app context")?,
4769 buffer,
4770 language_server.server_id(),
4771 cx.clone(),
4772 )
4773 .await
4774 })
4775 }
4776
4777 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4778 let mut language_formatters_to_check = Vec::new();
4779 for buffer in self.buffer_store.read(cx).buffers() {
4780 let buffer = buffer.read(cx);
4781 let buffer_file = File::from_dyn(buffer.file());
4782 let buffer_language = buffer.language();
4783 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4784 if buffer_language.is_some() {
4785 language_formatters_to_check.push((
4786 buffer_file.map(|f| f.worktree_id(cx)),
4787 settings.into_owned(),
4788 ));
4789 }
4790 }
4791
4792 self.request_workspace_config_refresh();
4793
4794 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4795 prettier_store.update(cx, |prettier_store, cx| {
4796 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4797 })
4798 }
4799
4800 cx.notify();
4801 }
4802
4803 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4804 let buffer_store = self.buffer_store.clone();
4805 let Some(local) = self.as_local_mut() else {
4806 return;
4807 };
4808 let mut adapters = BTreeMap::default();
4809 let get_adapter = {
4810 let languages = local.languages.clone();
4811 let environment = local.environment.clone();
4812 let weak = local.weak.clone();
4813 let worktree_store = local.worktree_store.clone();
4814 let http_client = local.http_client.clone();
4815 let fs = local.fs.clone();
4816 move |worktree_id, cx: &mut App| {
4817 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4818 Some(LocalLspAdapterDelegate::new(
4819 languages.clone(),
4820 &environment,
4821 weak.clone(),
4822 &worktree,
4823 http_client.clone(),
4824 fs.clone(),
4825 cx,
4826 ))
4827 }
4828 };
4829
4830 let mut messages_to_report = Vec::new();
4831 let (new_tree, to_stop) = {
4832 let mut rebase = local.lsp_tree.rebase();
4833 let buffers = buffer_store
4834 .read(cx)
4835 .buffers()
4836 .filter_map(|buffer| {
4837 let raw_buffer = buffer.read(cx);
4838 if !local
4839 .registered_buffers
4840 .contains_key(&raw_buffer.remote_id())
4841 {
4842 return None;
4843 }
4844 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4845 let language = raw_buffer.language().cloned()?;
4846 Some((file, language, raw_buffer.remote_id()))
4847 })
4848 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4849 for (file, language, buffer_id) in buffers {
4850 let worktree_id = file.worktree_id(cx);
4851 let Some(worktree) = local
4852 .worktree_store
4853 .read(cx)
4854 .worktree_for_id(worktree_id, cx)
4855 else {
4856 continue;
4857 };
4858
4859 if let Some((_, apply)) = local.reuse_existing_language_server(
4860 rebase.server_tree(),
4861 &worktree,
4862 &language.name(),
4863 cx,
4864 ) {
4865 (apply)(rebase.server_tree());
4866 } else if let Some(lsp_delegate) = adapters
4867 .entry(worktree_id)
4868 .or_insert_with(|| get_adapter(worktree_id, cx))
4869 .clone()
4870 {
4871 let delegate =
4872 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4873 let path = file
4874 .path()
4875 .parent()
4876 .map(Arc::from)
4877 .unwrap_or_else(|| file.path().clone());
4878 let worktree_path = ProjectPath { worktree_id, path };
4879 let abs_path = file.abs_path(cx);
4880 let nodes = rebase
4881 .walk(
4882 worktree_path,
4883 language.name(),
4884 language.manifest(),
4885 delegate.clone(),
4886 cx,
4887 )
4888 .collect::<Vec<_>>();
4889 for node in nodes {
4890 let server_id = node.server_id_or_init(|disposition| {
4891 let path = &disposition.path;
4892 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4893 let key = LanguageServerSeed {
4894 worktree_id,
4895 name: disposition.server_name.clone(),
4896 settings: disposition.settings.clone(),
4897 toolchain: local.toolchain_store.read(cx).active_toolchain(
4898 path.worktree_id,
4899 &path.path,
4900 language.name(),
4901 ),
4902 };
4903 local.language_server_ids.remove(&key);
4904
4905 let server_id = local.get_or_insert_language_server(
4906 &worktree,
4907 lsp_delegate.clone(),
4908 disposition,
4909 &language.name(),
4910 cx,
4911 );
4912 if let Some(state) = local.language_servers.get(&server_id)
4913 && let Ok(uri) = uri
4914 {
4915 state.add_workspace_folder(uri);
4916 };
4917 server_id
4918 });
4919
4920 if let Some(language_server_id) = server_id {
4921 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4922 language_server_id,
4923 name: node.name(),
4924 message:
4925 proto::update_language_server::Variant::RegisteredForBuffer(
4926 proto::RegisteredForBuffer {
4927 buffer_abs_path: abs_path
4928 .to_string_lossy()
4929 .into_owned(),
4930 buffer_id: buffer_id.to_proto(),
4931 },
4932 ),
4933 });
4934 }
4935 }
4936 } else {
4937 continue;
4938 }
4939 }
4940 rebase.finish()
4941 };
4942 for message in messages_to_report {
4943 cx.emit(message);
4944 }
4945 local.lsp_tree = new_tree;
4946 for (id, _) in to_stop {
4947 self.stop_local_language_server(id, cx).detach();
4948 }
4949 }
4950
4951 pub fn apply_code_action(
4952 &self,
4953 buffer_handle: Entity<Buffer>,
4954 mut action: CodeAction,
4955 push_to_history: bool,
4956 cx: &mut Context<Self>,
4957 ) -> Task<Result<ProjectTransaction>> {
4958 if let Some((upstream_client, project_id)) = self.upstream_client() {
4959 let request = proto::ApplyCodeAction {
4960 project_id,
4961 buffer_id: buffer_handle.read(cx).remote_id().into(),
4962 action: Some(Self::serialize_code_action(&action)),
4963 };
4964 let buffer_store = self.buffer_store();
4965 cx.spawn(async move |_, cx| {
4966 let response = upstream_client
4967 .request(request)
4968 .await?
4969 .transaction
4970 .context("missing transaction")?;
4971
4972 buffer_store
4973 .update(cx, |buffer_store, cx| {
4974 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4975 })?
4976 .await
4977 })
4978 } else if self.mode.is_local() {
4979 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4980 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4981 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4982 }) else {
4983 return Task::ready(Ok(ProjectTransaction::default()));
4984 };
4985 cx.spawn(async move |this, cx| {
4986 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4987 .await
4988 .context("resolving a code action")?;
4989 if let Some(edit) = action.lsp_action.edit()
4990 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4991 return LocalLspStore::deserialize_workspace_edit(
4992 this.upgrade().context("no app present")?,
4993 edit.clone(),
4994 push_to_history,
4995
4996 lang_server.clone(),
4997 cx,
4998 )
4999 .await;
5000 }
5001
5002 if let Some(command) = action.lsp_action.command() {
5003 let server_capabilities = lang_server.capabilities();
5004 let available_commands = server_capabilities
5005 .execute_command_provider
5006 .as_ref()
5007 .map(|options| options.commands.as_slice())
5008 .unwrap_or_default();
5009 if available_commands.contains(&command.command) {
5010 this.update(cx, |this, _| {
5011 this.as_local_mut()
5012 .unwrap()
5013 .last_workspace_edits_by_language_server
5014 .remove(&lang_server.server_id());
5015 })?;
5016
5017 let _result = lang_server
5018 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5019 command: command.command.clone(),
5020 arguments: command.arguments.clone().unwrap_or_default(),
5021 ..lsp::ExecuteCommandParams::default()
5022 })
5023 .await.into_response()
5024 .context("execute command")?;
5025
5026 return this.update(cx, |this, _| {
5027 this.as_local_mut()
5028 .unwrap()
5029 .last_workspace_edits_by_language_server
5030 .remove(&lang_server.server_id())
5031 .unwrap_or_default()
5032 });
5033 } else {
5034 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5035 }
5036 }
5037
5038 Ok(ProjectTransaction::default())
5039 })
5040 } else {
5041 Task::ready(Err(anyhow!("no upstream client and not local")))
5042 }
5043 }
5044
5045 pub fn apply_code_action_kind(
5046 &mut self,
5047 buffers: HashSet<Entity<Buffer>>,
5048 kind: CodeActionKind,
5049 push_to_history: bool,
5050 cx: &mut Context<Self>,
5051 ) -> Task<anyhow::Result<ProjectTransaction>> {
5052 if self.as_local().is_some() {
5053 cx.spawn(async move |lsp_store, cx| {
5054 let buffers = buffers.into_iter().collect::<Vec<_>>();
5055 let result = LocalLspStore::execute_code_action_kind_locally(
5056 lsp_store.clone(),
5057 buffers,
5058 kind,
5059 push_to_history,
5060 cx,
5061 )
5062 .await;
5063 lsp_store.update(cx, |lsp_store, _| {
5064 lsp_store.update_last_formatting_failure(&result);
5065 })?;
5066 result
5067 })
5068 } else if let Some((client, project_id)) = self.upstream_client() {
5069 let buffer_store = self.buffer_store();
5070 cx.spawn(async move |lsp_store, cx| {
5071 let result = client
5072 .request(proto::ApplyCodeActionKind {
5073 project_id,
5074 kind: kind.as_str().to_owned(),
5075 buffer_ids: buffers
5076 .iter()
5077 .map(|buffer| {
5078 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5079 })
5080 .collect::<Result<_>>()?,
5081 })
5082 .await
5083 .and_then(|result| result.transaction.context("missing transaction"));
5084 lsp_store.update(cx, |lsp_store, _| {
5085 lsp_store.update_last_formatting_failure(&result);
5086 })?;
5087
5088 let transaction_response = result?;
5089 buffer_store
5090 .update(cx, |buffer_store, cx| {
5091 buffer_store.deserialize_project_transaction(
5092 transaction_response,
5093 push_to_history,
5094 cx,
5095 )
5096 })?
5097 .await
5098 })
5099 } else {
5100 Task::ready(Ok(ProjectTransaction::default()))
5101 }
5102 }
5103
5104 pub fn resolved_hint(
5105 &mut self,
5106 buffer_id: BufferId,
5107 id: InlayId,
5108 cx: &mut Context<Self>,
5109 ) -> Option<ResolvedHint> {
5110 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5111
5112 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5113 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5114 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5115 let (server_id, resolve_data) = match &hint.resolve_state {
5116 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5117 ResolveState::Resolving => {
5118 return Some(ResolvedHint::Resolving(
5119 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5120 ));
5121 }
5122 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5123 };
5124
5125 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5126 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5127 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5128 id,
5129 cx.spawn(async move |lsp_store, cx| {
5130 let resolved_hint = resolve_task.await;
5131 lsp_store
5132 .update(cx, |lsp_store, _| {
5133 if let Some(old_inlay_hint) = lsp_store
5134 .lsp_data
5135 .get_mut(&buffer_id)
5136 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5137 {
5138 match resolved_hint {
5139 Ok(resolved_hint) => {
5140 *old_inlay_hint = resolved_hint;
5141 }
5142 Err(e) => {
5143 old_inlay_hint.resolve_state =
5144 ResolveState::CanResolve(server_id, resolve_data);
5145 log::error!("Inlay hint resolve failed: {e:#}");
5146 }
5147 }
5148 }
5149 })
5150 .ok();
5151 })
5152 .shared(),
5153 );
5154 debug_assert!(
5155 previous_task.is_none(),
5156 "Did not change hint's resolve state after spawning its resolve"
5157 );
5158 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5159 None
5160 }
5161
5162 fn resolve_inlay_hint(
5163 &self,
5164 mut hint: InlayHint,
5165 buffer: Entity<Buffer>,
5166 server_id: LanguageServerId,
5167 cx: &mut Context<Self>,
5168 ) -> Task<anyhow::Result<InlayHint>> {
5169 if let Some((upstream_client, project_id)) = self.upstream_client() {
5170 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5171 {
5172 hint.resolve_state = ResolveState::Resolved;
5173 return Task::ready(Ok(hint));
5174 }
5175 let request = proto::ResolveInlayHint {
5176 project_id,
5177 buffer_id: buffer.read(cx).remote_id().into(),
5178 language_server_id: server_id.0 as u64,
5179 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5180 };
5181 cx.background_spawn(async move {
5182 let response = upstream_client
5183 .request(request)
5184 .await
5185 .context("inlay hints proto request")?;
5186 match response.hint {
5187 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5188 .context("inlay hints proto resolve response conversion"),
5189 None => Ok(hint),
5190 }
5191 })
5192 } else {
5193 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5194 self.language_server_for_local_buffer(buffer, server_id, cx)
5195 .map(|(_, server)| server.clone())
5196 }) else {
5197 return Task::ready(Ok(hint));
5198 };
5199 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5200 return Task::ready(Ok(hint));
5201 }
5202 let buffer_snapshot = buffer.read(cx).snapshot();
5203 cx.spawn(async move |_, cx| {
5204 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5205 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5206 );
5207 let resolved_hint = resolve_task
5208 .await
5209 .into_response()
5210 .context("inlay hint resolve LSP request")?;
5211 let resolved_hint = InlayHints::lsp_to_project_hint(
5212 resolved_hint,
5213 &buffer,
5214 server_id,
5215 ResolveState::Resolved,
5216 false,
5217 cx,
5218 )
5219 .await?;
5220 Ok(resolved_hint)
5221 })
5222 }
5223 }
5224
5225 pub fn resolve_color_presentation(
5226 &mut self,
5227 mut color: DocumentColor,
5228 buffer: Entity<Buffer>,
5229 server_id: LanguageServerId,
5230 cx: &mut Context<Self>,
5231 ) -> Task<Result<DocumentColor>> {
5232 if color.resolved {
5233 return Task::ready(Ok(color));
5234 }
5235
5236 if let Some((upstream_client, project_id)) = self.upstream_client() {
5237 let start = color.lsp_range.start;
5238 let end = color.lsp_range.end;
5239 let request = proto::GetColorPresentation {
5240 project_id,
5241 server_id: server_id.to_proto(),
5242 buffer_id: buffer.read(cx).remote_id().into(),
5243 color: Some(proto::ColorInformation {
5244 red: color.color.red,
5245 green: color.color.green,
5246 blue: color.color.blue,
5247 alpha: color.color.alpha,
5248 lsp_range_start: Some(proto::PointUtf16 {
5249 row: start.line,
5250 column: start.character,
5251 }),
5252 lsp_range_end: Some(proto::PointUtf16 {
5253 row: end.line,
5254 column: end.character,
5255 }),
5256 }),
5257 };
5258 cx.background_spawn(async move {
5259 let response = upstream_client
5260 .request(request)
5261 .await
5262 .context("color presentation proto request")?;
5263 color.resolved = true;
5264 color.color_presentations = response
5265 .presentations
5266 .into_iter()
5267 .map(|presentation| ColorPresentation {
5268 label: SharedString::from(presentation.label),
5269 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5270 additional_text_edits: presentation
5271 .additional_text_edits
5272 .into_iter()
5273 .filter_map(deserialize_lsp_edit)
5274 .collect(),
5275 })
5276 .collect();
5277 Ok(color)
5278 })
5279 } else {
5280 let path = match buffer
5281 .update(cx, |buffer, cx| {
5282 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5283 })
5284 .context("buffer with the missing path")
5285 {
5286 Ok(path) => path,
5287 Err(e) => return Task::ready(Err(e)),
5288 };
5289 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5290 self.language_server_for_local_buffer(buffer, server_id, cx)
5291 .map(|(_, server)| server.clone())
5292 }) else {
5293 return Task::ready(Ok(color));
5294 };
5295 cx.background_spawn(async move {
5296 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5297 lsp::ColorPresentationParams {
5298 text_document: make_text_document_identifier(&path)?,
5299 color: color.color,
5300 range: color.lsp_range,
5301 work_done_progress_params: Default::default(),
5302 partial_result_params: Default::default(),
5303 },
5304 );
5305 color.color_presentations = resolve_task
5306 .await
5307 .into_response()
5308 .context("color presentation resolve LSP request")?
5309 .into_iter()
5310 .map(|presentation| ColorPresentation {
5311 label: SharedString::from(presentation.label),
5312 text_edit: presentation.text_edit,
5313 additional_text_edits: presentation
5314 .additional_text_edits
5315 .unwrap_or_default(),
5316 })
5317 .collect();
5318 color.resolved = true;
5319 Ok(color)
5320 })
5321 }
5322 }
5323
5324 pub(crate) fn linked_edits(
5325 &mut self,
5326 buffer: &Entity<Buffer>,
5327 position: Anchor,
5328 cx: &mut Context<Self>,
5329 ) -> Task<Result<Vec<Range<Anchor>>>> {
5330 let snapshot = buffer.read(cx).snapshot();
5331 let scope = snapshot.language_scope_at(position);
5332 let Some(server_id) = self
5333 .as_local()
5334 .and_then(|local| {
5335 buffer.update(cx, |buffer, cx| {
5336 local
5337 .language_servers_for_buffer(buffer, cx)
5338 .filter(|(_, server)| {
5339 LinkedEditingRange::check_server_capabilities(server.capabilities())
5340 })
5341 .filter(|(adapter, _)| {
5342 scope
5343 .as_ref()
5344 .map(|scope| scope.language_allowed(&adapter.name))
5345 .unwrap_or(true)
5346 })
5347 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5348 .next()
5349 })
5350 })
5351 .or_else(|| {
5352 self.upstream_client()
5353 .is_some()
5354 .then_some(LanguageServerToQuery::FirstCapable)
5355 })
5356 .filter(|_| {
5357 maybe!({
5358 let language = buffer.read(cx).language_at(position)?;
5359 Some(
5360 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5361 .linked_edits,
5362 )
5363 }) == Some(true)
5364 })
5365 else {
5366 return Task::ready(Ok(Vec::new()));
5367 };
5368
5369 self.request_lsp(
5370 buffer.clone(),
5371 server_id,
5372 LinkedEditingRange { position },
5373 cx,
5374 )
5375 }
5376
5377 fn apply_on_type_formatting(
5378 &mut self,
5379 buffer: Entity<Buffer>,
5380 position: Anchor,
5381 trigger: String,
5382 cx: &mut Context<Self>,
5383 ) -> Task<Result<Option<Transaction>>> {
5384 if let Some((client, project_id)) = self.upstream_client() {
5385 if !self.check_if_capable_for_proto_request(
5386 &buffer,
5387 |capabilities| {
5388 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5389 },
5390 cx,
5391 ) {
5392 return Task::ready(Ok(None));
5393 }
5394 let request = proto::OnTypeFormatting {
5395 project_id,
5396 buffer_id: buffer.read(cx).remote_id().into(),
5397 position: Some(serialize_anchor(&position)),
5398 trigger,
5399 version: serialize_version(&buffer.read(cx).version()),
5400 };
5401 cx.background_spawn(async move {
5402 client
5403 .request(request)
5404 .await?
5405 .transaction
5406 .map(language::proto::deserialize_transaction)
5407 .transpose()
5408 })
5409 } else if let Some(local) = self.as_local_mut() {
5410 let buffer_id = buffer.read(cx).remote_id();
5411 local.buffers_being_formatted.insert(buffer_id);
5412 cx.spawn(async move |this, cx| {
5413 let _cleanup = defer({
5414 let this = this.clone();
5415 let mut cx = cx.clone();
5416 move || {
5417 this.update(&mut cx, |this, _| {
5418 if let Some(local) = this.as_local_mut() {
5419 local.buffers_being_formatted.remove(&buffer_id);
5420 }
5421 })
5422 .ok();
5423 }
5424 });
5425
5426 buffer
5427 .update(cx, |buffer, _| {
5428 buffer.wait_for_edits(Some(position.timestamp))
5429 })?
5430 .await?;
5431 this.update(cx, |this, cx| {
5432 let position = position.to_point_utf16(buffer.read(cx));
5433 this.on_type_format(buffer, position, trigger, false, cx)
5434 })?
5435 .await
5436 })
5437 } else {
5438 Task::ready(Err(anyhow!("No upstream client or local language server")))
5439 }
5440 }
5441
5442 pub fn on_type_format<T: ToPointUtf16>(
5443 &mut self,
5444 buffer: Entity<Buffer>,
5445 position: T,
5446 trigger: String,
5447 push_to_history: bool,
5448 cx: &mut Context<Self>,
5449 ) -> Task<Result<Option<Transaction>>> {
5450 let position = position.to_point_utf16(buffer.read(cx));
5451 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5452 }
5453
5454 fn on_type_format_impl(
5455 &mut self,
5456 buffer: Entity<Buffer>,
5457 position: PointUtf16,
5458 trigger: String,
5459 push_to_history: bool,
5460 cx: &mut Context<Self>,
5461 ) -> Task<Result<Option<Transaction>>> {
5462 let options = buffer.update(cx, |buffer, cx| {
5463 lsp_command::lsp_formatting_options(
5464 language_settings(
5465 buffer.language_at(position).map(|l| l.name()),
5466 buffer.file(),
5467 cx,
5468 )
5469 .as_ref(),
5470 )
5471 });
5472
5473 cx.spawn(async move |this, cx| {
5474 if let Some(waiter) =
5475 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5476 {
5477 waiter.await?;
5478 }
5479 cx.update(|cx| {
5480 this.update(cx, |this, cx| {
5481 this.request_lsp(
5482 buffer.clone(),
5483 LanguageServerToQuery::FirstCapable,
5484 OnTypeFormatting {
5485 position,
5486 trigger,
5487 options,
5488 push_to_history,
5489 },
5490 cx,
5491 )
5492 })
5493 })??
5494 .await
5495 })
5496 }
5497
5498 pub fn definitions(
5499 &mut self,
5500 buffer: &Entity<Buffer>,
5501 position: PointUtf16,
5502 cx: &mut Context<Self>,
5503 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5504 if let Some((upstream_client, project_id)) = self.upstream_client() {
5505 let request = GetDefinitions { position };
5506 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5507 return Task::ready(Ok(None));
5508 }
5509 let request_task = upstream_client.request_lsp(
5510 project_id,
5511 None,
5512 LSP_REQUEST_TIMEOUT,
5513 cx.background_executor().clone(),
5514 request.to_proto(project_id, buffer.read(cx)),
5515 );
5516 let buffer = buffer.clone();
5517 cx.spawn(async move |weak_lsp_store, cx| {
5518 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5519 return Ok(None);
5520 };
5521 let Some(responses) = request_task.await? else {
5522 return Ok(None);
5523 };
5524 let actions = join_all(responses.payload.into_iter().map(|response| {
5525 GetDefinitions { position }.response_from_proto(
5526 response.response,
5527 lsp_store.clone(),
5528 buffer.clone(),
5529 cx.clone(),
5530 )
5531 }))
5532 .await;
5533
5534 Ok(Some(
5535 actions
5536 .into_iter()
5537 .collect::<Result<Vec<Vec<_>>>>()?
5538 .into_iter()
5539 .flatten()
5540 .dedup()
5541 .collect(),
5542 ))
5543 })
5544 } else {
5545 let definitions_task = self.request_multiple_lsp_locally(
5546 buffer,
5547 Some(position),
5548 GetDefinitions { position },
5549 cx,
5550 );
5551 cx.background_spawn(async move {
5552 Ok(Some(
5553 definitions_task
5554 .await
5555 .into_iter()
5556 .flat_map(|(_, definitions)| definitions)
5557 .dedup()
5558 .collect(),
5559 ))
5560 })
5561 }
5562 }
5563
5564 pub fn declarations(
5565 &mut self,
5566 buffer: &Entity<Buffer>,
5567 position: PointUtf16,
5568 cx: &mut Context<Self>,
5569 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5570 if let Some((upstream_client, project_id)) = self.upstream_client() {
5571 let request = GetDeclarations { position };
5572 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5573 return Task::ready(Ok(None));
5574 }
5575 let request_task = upstream_client.request_lsp(
5576 project_id,
5577 None,
5578 LSP_REQUEST_TIMEOUT,
5579 cx.background_executor().clone(),
5580 request.to_proto(project_id, buffer.read(cx)),
5581 );
5582 let buffer = buffer.clone();
5583 cx.spawn(async move |weak_lsp_store, cx| {
5584 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5585 return Ok(None);
5586 };
5587 let Some(responses) = request_task.await? else {
5588 return Ok(None);
5589 };
5590 let actions = join_all(responses.payload.into_iter().map(|response| {
5591 GetDeclarations { position }.response_from_proto(
5592 response.response,
5593 lsp_store.clone(),
5594 buffer.clone(),
5595 cx.clone(),
5596 )
5597 }))
5598 .await;
5599
5600 Ok(Some(
5601 actions
5602 .into_iter()
5603 .collect::<Result<Vec<Vec<_>>>>()?
5604 .into_iter()
5605 .flatten()
5606 .dedup()
5607 .collect(),
5608 ))
5609 })
5610 } else {
5611 let declarations_task = self.request_multiple_lsp_locally(
5612 buffer,
5613 Some(position),
5614 GetDeclarations { position },
5615 cx,
5616 );
5617 cx.background_spawn(async move {
5618 Ok(Some(
5619 declarations_task
5620 .await
5621 .into_iter()
5622 .flat_map(|(_, declarations)| declarations)
5623 .dedup()
5624 .collect(),
5625 ))
5626 })
5627 }
5628 }
5629
5630 pub fn type_definitions(
5631 &mut self,
5632 buffer: &Entity<Buffer>,
5633 position: PointUtf16,
5634 cx: &mut Context<Self>,
5635 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5636 if let Some((upstream_client, project_id)) = self.upstream_client() {
5637 let request = GetTypeDefinitions { position };
5638 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5639 return Task::ready(Ok(None));
5640 }
5641 let request_task = upstream_client.request_lsp(
5642 project_id,
5643 None,
5644 LSP_REQUEST_TIMEOUT,
5645 cx.background_executor().clone(),
5646 request.to_proto(project_id, buffer.read(cx)),
5647 );
5648 let buffer = buffer.clone();
5649 cx.spawn(async move |weak_lsp_store, cx| {
5650 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5651 return Ok(None);
5652 };
5653 let Some(responses) = request_task.await? else {
5654 return Ok(None);
5655 };
5656 let actions = join_all(responses.payload.into_iter().map(|response| {
5657 GetTypeDefinitions { position }.response_from_proto(
5658 response.response,
5659 lsp_store.clone(),
5660 buffer.clone(),
5661 cx.clone(),
5662 )
5663 }))
5664 .await;
5665
5666 Ok(Some(
5667 actions
5668 .into_iter()
5669 .collect::<Result<Vec<Vec<_>>>>()?
5670 .into_iter()
5671 .flatten()
5672 .dedup()
5673 .collect(),
5674 ))
5675 })
5676 } else {
5677 let type_definitions_task = self.request_multiple_lsp_locally(
5678 buffer,
5679 Some(position),
5680 GetTypeDefinitions { position },
5681 cx,
5682 );
5683 cx.background_spawn(async move {
5684 Ok(Some(
5685 type_definitions_task
5686 .await
5687 .into_iter()
5688 .flat_map(|(_, type_definitions)| type_definitions)
5689 .dedup()
5690 .collect(),
5691 ))
5692 })
5693 }
5694 }
5695
5696 pub fn implementations(
5697 &mut self,
5698 buffer: &Entity<Buffer>,
5699 position: PointUtf16,
5700 cx: &mut Context<Self>,
5701 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5702 if let Some((upstream_client, project_id)) = self.upstream_client() {
5703 let request = GetImplementations { position };
5704 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5705 return Task::ready(Ok(None));
5706 }
5707 let request_task = upstream_client.request_lsp(
5708 project_id,
5709 None,
5710 LSP_REQUEST_TIMEOUT,
5711 cx.background_executor().clone(),
5712 request.to_proto(project_id, buffer.read(cx)),
5713 );
5714 let buffer = buffer.clone();
5715 cx.spawn(async move |weak_lsp_store, cx| {
5716 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5717 return Ok(None);
5718 };
5719 let Some(responses) = request_task.await? else {
5720 return Ok(None);
5721 };
5722 let actions = join_all(responses.payload.into_iter().map(|response| {
5723 GetImplementations { position }.response_from_proto(
5724 response.response,
5725 lsp_store.clone(),
5726 buffer.clone(),
5727 cx.clone(),
5728 )
5729 }))
5730 .await;
5731
5732 Ok(Some(
5733 actions
5734 .into_iter()
5735 .collect::<Result<Vec<Vec<_>>>>()?
5736 .into_iter()
5737 .flatten()
5738 .dedup()
5739 .collect(),
5740 ))
5741 })
5742 } else {
5743 let implementations_task = self.request_multiple_lsp_locally(
5744 buffer,
5745 Some(position),
5746 GetImplementations { position },
5747 cx,
5748 );
5749 cx.background_spawn(async move {
5750 Ok(Some(
5751 implementations_task
5752 .await
5753 .into_iter()
5754 .flat_map(|(_, implementations)| implementations)
5755 .dedup()
5756 .collect(),
5757 ))
5758 })
5759 }
5760 }
5761
5762 pub fn references(
5763 &mut self,
5764 buffer: &Entity<Buffer>,
5765 position: PointUtf16,
5766 cx: &mut Context<Self>,
5767 ) -> Task<Result<Option<Vec<Location>>>> {
5768 if let Some((upstream_client, project_id)) = self.upstream_client() {
5769 let request = GetReferences { position };
5770 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5771 return Task::ready(Ok(None));
5772 }
5773
5774 let request_task = upstream_client.request_lsp(
5775 project_id,
5776 None,
5777 LSP_REQUEST_TIMEOUT,
5778 cx.background_executor().clone(),
5779 request.to_proto(project_id, buffer.read(cx)),
5780 );
5781 let buffer = buffer.clone();
5782 cx.spawn(async move |weak_lsp_store, cx| {
5783 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5784 return Ok(None);
5785 };
5786 let Some(responses) = request_task.await? else {
5787 return Ok(None);
5788 };
5789
5790 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5791 GetReferences { position }.response_from_proto(
5792 lsp_response.response,
5793 lsp_store.clone(),
5794 buffer.clone(),
5795 cx.clone(),
5796 )
5797 }))
5798 .await
5799 .into_iter()
5800 .collect::<Result<Vec<Vec<_>>>>()?
5801 .into_iter()
5802 .flatten()
5803 .dedup()
5804 .collect();
5805 Ok(Some(locations))
5806 })
5807 } else {
5808 let references_task = self.request_multiple_lsp_locally(
5809 buffer,
5810 Some(position),
5811 GetReferences { position },
5812 cx,
5813 );
5814 cx.background_spawn(async move {
5815 Ok(Some(
5816 references_task
5817 .await
5818 .into_iter()
5819 .flat_map(|(_, references)| references)
5820 .dedup()
5821 .collect(),
5822 ))
5823 })
5824 }
5825 }
5826
5827 pub fn code_actions(
5828 &mut self,
5829 buffer: &Entity<Buffer>,
5830 range: Range<Anchor>,
5831 kinds: Option<Vec<CodeActionKind>>,
5832 cx: &mut Context<Self>,
5833 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5834 if let Some((upstream_client, project_id)) = self.upstream_client() {
5835 let request = GetCodeActions {
5836 range: range.clone(),
5837 kinds: kinds.clone(),
5838 };
5839 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5840 return Task::ready(Ok(None));
5841 }
5842 let request_task = upstream_client.request_lsp(
5843 project_id,
5844 None,
5845 LSP_REQUEST_TIMEOUT,
5846 cx.background_executor().clone(),
5847 request.to_proto(project_id, buffer.read(cx)),
5848 );
5849 let buffer = buffer.clone();
5850 cx.spawn(async move |weak_lsp_store, cx| {
5851 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5852 return Ok(None);
5853 };
5854 let Some(responses) = request_task.await? else {
5855 return Ok(None);
5856 };
5857 let actions = join_all(responses.payload.into_iter().map(|response| {
5858 GetCodeActions {
5859 range: range.clone(),
5860 kinds: kinds.clone(),
5861 }
5862 .response_from_proto(
5863 response.response,
5864 lsp_store.clone(),
5865 buffer.clone(),
5866 cx.clone(),
5867 )
5868 }))
5869 .await;
5870
5871 Ok(Some(
5872 actions
5873 .into_iter()
5874 .collect::<Result<Vec<Vec<_>>>>()?
5875 .into_iter()
5876 .flatten()
5877 .collect(),
5878 ))
5879 })
5880 } else {
5881 let all_actions_task = self.request_multiple_lsp_locally(
5882 buffer,
5883 Some(range.start),
5884 GetCodeActions { range, kinds },
5885 cx,
5886 );
5887 cx.background_spawn(async move {
5888 Ok(Some(
5889 all_actions_task
5890 .await
5891 .into_iter()
5892 .flat_map(|(_, actions)| actions)
5893 .collect(),
5894 ))
5895 })
5896 }
5897 }
5898
5899 pub fn code_lens_actions(
5900 &mut self,
5901 buffer: &Entity<Buffer>,
5902 cx: &mut Context<Self>,
5903 ) -> CodeLensTask {
5904 let version_queried_for = buffer.read(cx).version();
5905 let buffer_id = buffer.read(cx).remote_id();
5906 let existing_servers = self.as_local().map(|local| {
5907 local
5908 .buffers_opened_in_servers
5909 .get(&buffer_id)
5910 .cloned()
5911 .unwrap_or_default()
5912 });
5913
5914 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5915 if let Some(cached_lens) = &lsp_data.code_lens {
5916 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5917 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5918 existing_servers != cached_lens.lens.keys().copied().collect()
5919 });
5920 if !has_different_servers {
5921 return Task::ready(Ok(Some(
5922 cached_lens.lens.values().flatten().cloned().collect(),
5923 )))
5924 .shared();
5925 }
5926 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5927 if !version_queried_for.changed_since(updating_for) {
5928 return running_update.clone();
5929 }
5930 }
5931 }
5932 }
5933
5934 let lens_lsp_data = self
5935 .latest_lsp_data(buffer, cx)
5936 .code_lens
5937 .get_or_insert_default();
5938 let buffer = buffer.clone();
5939 let query_version_queried_for = version_queried_for.clone();
5940 let new_task = cx
5941 .spawn(async move |lsp_store, cx| {
5942 cx.background_executor()
5943 .timer(Duration::from_millis(30))
5944 .await;
5945 let fetched_lens = lsp_store
5946 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5947 .map_err(Arc::new)?
5948 .await
5949 .context("fetching code lens")
5950 .map_err(Arc::new);
5951 let fetched_lens = match fetched_lens {
5952 Ok(fetched_lens) => fetched_lens,
5953 Err(e) => {
5954 lsp_store
5955 .update(cx, |lsp_store, _| {
5956 if let Some(lens_lsp_data) = lsp_store
5957 .lsp_data
5958 .get_mut(&buffer_id)
5959 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5960 {
5961 lens_lsp_data.update = None;
5962 }
5963 })
5964 .ok();
5965 return Err(e);
5966 }
5967 };
5968
5969 lsp_store
5970 .update(cx, |lsp_store, _| {
5971 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5972 let code_lens = lsp_data.code_lens.as_mut()?;
5973 if let Some(fetched_lens) = fetched_lens {
5974 if lsp_data.buffer_version == query_version_queried_for {
5975 code_lens.lens.extend(fetched_lens);
5976 } else if !lsp_data
5977 .buffer_version
5978 .changed_since(&query_version_queried_for)
5979 {
5980 lsp_data.buffer_version = query_version_queried_for;
5981 code_lens.lens = fetched_lens;
5982 }
5983 }
5984 code_lens.update = None;
5985 Some(code_lens.lens.values().flatten().cloned().collect())
5986 })
5987 .map_err(Arc::new)
5988 })
5989 .shared();
5990 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5991 new_task
5992 }
5993
5994 fn fetch_code_lens(
5995 &mut self,
5996 buffer: &Entity<Buffer>,
5997 cx: &mut Context<Self>,
5998 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5999 if let Some((upstream_client, project_id)) = self.upstream_client() {
6000 let request = GetCodeLens;
6001 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6002 return Task::ready(Ok(None));
6003 }
6004 let request_task = upstream_client.request_lsp(
6005 project_id,
6006 None,
6007 LSP_REQUEST_TIMEOUT,
6008 cx.background_executor().clone(),
6009 request.to_proto(project_id, buffer.read(cx)),
6010 );
6011 let buffer = buffer.clone();
6012 cx.spawn(async move |weak_lsp_store, cx| {
6013 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6014 return Ok(None);
6015 };
6016 let Some(responses) = request_task.await? else {
6017 return Ok(None);
6018 };
6019
6020 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6021 let lsp_store = lsp_store.clone();
6022 let buffer = buffer.clone();
6023 let cx = cx.clone();
6024 async move {
6025 (
6026 LanguageServerId::from_proto(response.server_id),
6027 GetCodeLens
6028 .response_from_proto(response.response, lsp_store, buffer, cx)
6029 .await,
6030 )
6031 }
6032 }))
6033 .await;
6034
6035 let mut has_errors = false;
6036 let code_lens_actions = code_lens_actions
6037 .into_iter()
6038 .filter_map(|(server_id, code_lens)| match code_lens {
6039 Ok(code_lens) => Some((server_id, code_lens)),
6040 Err(e) => {
6041 has_errors = true;
6042 log::error!("{e:#}");
6043 None
6044 }
6045 })
6046 .collect::<HashMap<_, _>>();
6047 anyhow::ensure!(
6048 !has_errors || !code_lens_actions.is_empty(),
6049 "Failed to fetch code lens"
6050 );
6051 Ok(Some(code_lens_actions))
6052 })
6053 } else {
6054 let code_lens_actions_task =
6055 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6056 cx.background_spawn(async move {
6057 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6058 })
6059 }
6060 }
6061
6062 #[inline(never)]
6063 pub fn completions(
6064 &self,
6065 buffer: &Entity<Buffer>,
6066 position: PointUtf16,
6067 context: CompletionContext,
6068 cx: &mut Context<Self>,
6069 ) -> Task<Result<Vec<CompletionResponse>>> {
6070 let language_registry = self.languages.clone();
6071
6072 if let Some((upstream_client, project_id)) = self.upstream_client() {
6073 let snapshot = buffer.read(cx).snapshot();
6074 let offset = position.to_offset(&snapshot);
6075 let scope = snapshot.language_scope_at(offset);
6076 let capable_lsps = self.all_capable_for_proto_request(
6077 buffer,
6078 |server_name, capabilities| {
6079 capabilities.completion_provider.is_some()
6080 && scope
6081 .as_ref()
6082 .map(|scope| scope.language_allowed(server_name))
6083 .unwrap_or(true)
6084 },
6085 cx,
6086 );
6087 if capable_lsps.is_empty() {
6088 return Task::ready(Ok(Vec::new()));
6089 }
6090
6091 let language = buffer.read(cx).language().cloned();
6092
6093 // In the future, we should provide project guests with the names of LSP adapters,
6094 // so that they can use the correct LSP adapter when computing labels. For now,
6095 // guests just use the first LSP adapter associated with the buffer's language.
6096 let lsp_adapter = language.as_ref().and_then(|language| {
6097 language_registry
6098 .lsp_adapters(&language.name())
6099 .first()
6100 .cloned()
6101 });
6102
6103 let buffer = buffer.clone();
6104
6105 cx.spawn(async move |this, cx| {
6106 let requests = join_all(
6107 capable_lsps
6108 .into_iter()
6109 .map(|id| {
6110 let request = GetCompletions {
6111 position,
6112 context: context.clone(),
6113 server_id: Some(id),
6114 };
6115 let buffer = buffer.clone();
6116 let language = language.clone();
6117 let lsp_adapter = lsp_adapter.clone();
6118 let upstream_client = upstream_client.clone();
6119 let response = this
6120 .update(cx, |this, cx| {
6121 this.send_lsp_proto_request(
6122 buffer,
6123 upstream_client,
6124 project_id,
6125 request,
6126 cx,
6127 )
6128 })
6129 .log_err();
6130 async move {
6131 let response = response?.await.log_err()?;
6132
6133 let completions = populate_labels_for_completions(
6134 response.completions,
6135 language,
6136 lsp_adapter,
6137 )
6138 .await;
6139
6140 Some(CompletionResponse {
6141 completions,
6142 display_options: CompletionDisplayOptions::default(),
6143 is_incomplete: response.is_incomplete,
6144 })
6145 }
6146 })
6147 .collect::<Vec<_>>(),
6148 );
6149 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6150 })
6151 } else if let Some(local) = self.as_local() {
6152 let snapshot = buffer.read(cx).snapshot();
6153 let offset = position.to_offset(&snapshot);
6154 let scope = snapshot.language_scope_at(offset);
6155 let language = snapshot.language().cloned();
6156 let completion_settings = language_settings(
6157 language.as_ref().map(|language| language.name()),
6158 buffer.read(cx).file(),
6159 cx,
6160 )
6161 .completions
6162 .clone();
6163 if !completion_settings.lsp {
6164 return Task::ready(Ok(Vec::new()));
6165 }
6166
6167 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6168 local
6169 .language_servers_for_buffer(buffer, cx)
6170 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6171 .filter(|(adapter, _)| {
6172 scope
6173 .as_ref()
6174 .map(|scope| scope.language_allowed(&adapter.name))
6175 .unwrap_or(true)
6176 })
6177 .map(|(_, server)| server.server_id())
6178 .collect()
6179 });
6180
6181 let buffer = buffer.clone();
6182 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6183 let lsp_timeout = if lsp_timeout > 0 {
6184 Some(Duration::from_millis(lsp_timeout))
6185 } else {
6186 None
6187 };
6188 cx.spawn(async move |this, cx| {
6189 let mut tasks = Vec::with_capacity(server_ids.len());
6190 this.update(cx, |lsp_store, cx| {
6191 for server_id in server_ids {
6192 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6193 let lsp_timeout = lsp_timeout
6194 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6195 let mut timeout = cx.background_spawn(async move {
6196 match lsp_timeout {
6197 Some(lsp_timeout) => {
6198 lsp_timeout.await;
6199 true
6200 },
6201 None => false,
6202 }
6203 }).fuse();
6204 let mut lsp_request = lsp_store.request_lsp(
6205 buffer.clone(),
6206 LanguageServerToQuery::Other(server_id),
6207 GetCompletions {
6208 position,
6209 context: context.clone(),
6210 server_id: Some(server_id),
6211 },
6212 cx,
6213 ).fuse();
6214 let new_task = cx.background_spawn(async move {
6215 select_biased! {
6216 response = lsp_request => anyhow::Ok(Some(response?)),
6217 timeout_happened = timeout => {
6218 if timeout_happened {
6219 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6220 Ok(None)
6221 } else {
6222 let completions = lsp_request.await?;
6223 Ok(Some(completions))
6224 }
6225 },
6226 }
6227 });
6228 tasks.push((lsp_adapter, new_task));
6229 }
6230 })?;
6231
6232 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6233 let completion_response = task.await.ok()??;
6234 let completions = populate_labels_for_completions(
6235 completion_response.completions,
6236 language.clone(),
6237 lsp_adapter,
6238 )
6239 .await;
6240 Some(CompletionResponse {
6241 completions,
6242 display_options: CompletionDisplayOptions::default(),
6243 is_incomplete: completion_response.is_incomplete,
6244 })
6245 });
6246
6247 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6248
6249 Ok(responses.into_iter().flatten().collect())
6250 })
6251 } else {
6252 Task::ready(Err(anyhow!("No upstream client or local language server")))
6253 }
6254 }
6255
6256 pub fn resolve_completions(
6257 &self,
6258 buffer: Entity<Buffer>,
6259 completion_indices: Vec<usize>,
6260 completions: Rc<RefCell<Box<[Completion]>>>,
6261 cx: &mut Context<Self>,
6262 ) -> Task<Result<bool>> {
6263 let client = self.upstream_client();
6264 let buffer_id = buffer.read(cx).remote_id();
6265 let buffer_snapshot = buffer.read(cx).snapshot();
6266
6267 if !self.check_if_capable_for_proto_request(
6268 &buffer,
6269 GetCompletions::can_resolve_completions,
6270 cx,
6271 ) {
6272 return Task::ready(Ok(false));
6273 }
6274 cx.spawn(async move |lsp_store, cx| {
6275 let mut did_resolve = false;
6276 if let Some((client, project_id)) = client {
6277 for completion_index in completion_indices {
6278 let server_id = {
6279 let completion = &completions.borrow()[completion_index];
6280 completion.source.server_id()
6281 };
6282 if let Some(server_id) = server_id {
6283 if Self::resolve_completion_remote(
6284 project_id,
6285 server_id,
6286 buffer_id,
6287 completions.clone(),
6288 completion_index,
6289 client.clone(),
6290 )
6291 .await
6292 .log_err()
6293 .is_some()
6294 {
6295 did_resolve = true;
6296 }
6297 } else {
6298 resolve_word_completion(
6299 &buffer_snapshot,
6300 &mut completions.borrow_mut()[completion_index],
6301 );
6302 }
6303 }
6304 } else {
6305 for completion_index in completion_indices {
6306 let server_id = {
6307 let completion = &completions.borrow()[completion_index];
6308 completion.source.server_id()
6309 };
6310 if let Some(server_id) = server_id {
6311 let server_and_adapter = lsp_store
6312 .read_with(cx, |lsp_store, _| {
6313 let server = lsp_store.language_server_for_id(server_id)?;
6314 let adapter =
6315 lsp_store.language_server_adapter_for_id(server.server_id())?;
6316 Some((server, adapter))
6317 })
6318 .ok()
6319 .flatten();
6320 let Some((server, adapter)) = server_and_adapter else {
6321 continue;
6322 };
6323
6324 let resolved = Self::resolve_completion_local(
6325 server,
6326 completions.clone(),
6327 completion_index,
6328 )
6329 .await
6330 .log_err()
6331 .is_some();
6332 if resolved {
6333 Self::regenerate_completion_labels(
6334 adapter,
6335 &buffer_snapshot,
6336 completions.clone(),
6337 completion_index,
6338 )
6339 .await
6340 .log_err();
6341 did_resolve = true;
6342 }
6343 } else {
6344 resolve_word_completion(
6345 &buffer_snapshot,
6346 &mut completions.borrow_mut()[completion_index],
6347 );
6348 }
6349 }
6350 }
6351
6352 Ok(did_resolve)
6353 })
6354 }
6355
6356 async fn resolve_completion_local(
6357 server: Arc<lsp::LanguageServer>,
6358 completions: Rc<RefCell<Box<[Completion]>>>,
6359 completion_index: usize,
6360 ) -> Result<()> {
6361 let server_id = server.server_id();
6362 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6363 return Ok(());
6364 }
6365
6366 let request = {
6367 let completion = &completions.borrow()[completion_index];
6368 match &completion.source {
6369 CompletionSource::Lsp {
6370 lsp_completion,
6371 resolved,
6372 server_id: completion_server_id,
6373 ..
6374 } => {
6375 if *resolved {
6376 return Ok(());
6377 }
6378 anyhow::ensure!(
6379 server_id == *completion_server_id,
6380 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6381 );
6382 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6383 }
6384 CompletionSource::BufferWord { .. }
6385 | CompletionSource::Dap { .. }
6386 | CompletionSource::Custom => {
6387 return Ok(());
6388 }
6389 }
6390 };
6391 let resolved_completion = request
6392 .await
6393 .into_response()
6394 .context("resolve completion")?;
6395
6396 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6397 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6398
6399 let mut completions = completions.borrow_mut();
6400 let completion = &mut completions[completion_index];
6401 if let CompletionSource::Lsp {
6402 lsp_completion,
6403 resolved,
6404 server_id: completion_server_id,
6405 ..
6406 } = &mut completion.source
6407 {
6408 if *resolved {
6409 return Ok(());
6410 }
6411 anyhow::ensure!(
6412 server_id == *completion_server_id,
6413 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6414 );
6415 *lsp_completion = Box::new(resolved_completion);
6416 *resolved = true;
6417 }
6418 Ok(())
6419 }
6420
6421 async fn regenerate_completion_labels(
6422 adapter: Arc<CachedLspAdapter>,
6423 snapshot: &BufferSnapshot,
6424 completions: Rc<RefCell<Box<[Completion]>>>,
6425 completion_index: usize,
6426 ) -> Result<()> {
6427 let completion_item = completions.borrow()[completion_index]
6428 .source
6429 .lsp_completion(true)
6430 .map(Cow::into_owned);
6431 if let Some(lsp_documentation) = completion_item
6432 .as_ref()
6433 .and_then(|completion_item| completion_item.documentation.clone())
6434 {
6435 let mut completions = completions.borrow_mut();
6436 let completion = &mut completions[completion_index];
6437 completion.documentation = Some(lsp_documentation.into());
6438 } else {
6439 let mut completions = completions.borrow_mut();
6440 let completion = &mut completions[completion_index];
6441 completion.documentation = Some(CompletionDocumentation::Undocumented);
6442 }
6443
6444 let mut new_label = match completion_item {
6445 Some(completion_item) => {
6446 // 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
6447 // So we have to update the label here anyway...
6448 let language = snapshot.language();
6449 match language {
6450 Some(language) => {
6451 adapter
6452 .labels_for_completions(
6453 std::slice::from_ref(&completion_item),
6454 language,
6455 )
6456 .await?
6457 }
6458 None => Vec::new(),
6459 }
6460 .pop()
6461 .flatten()
6462 .unwrap_or_else(|| {
6463 CodeLabel::fallback_for_completion(
6464 &completion_item,
6465 language.map(|language| language.as_ref()),
6466 )
6467 })
6468 }
6469 None => CodeLabel::plain(
6470 completions.borrow()[completion_index].new_text.clone(),
6471 None,
6472 ),
6473 };
6474 ensure_uniform_list_compatible_label(&mut new_label);
6475
6476 let mut completions = completions.borrow_mut();
6477 let completion = &mut completions[completion_index];
6478 if completion.label.filter_text() == new_label.filter_text() {
6479 completion.label = new_label;
6480 } else {
6481 log::error!(
6482 "Resolved completion changed display label from {} to {}. \
6483 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6484 completion.label.text(),
6485 new_label.text(),
6486 completion.label.filter_text(),
6487 new_label.filter_text()
6488 );
6489 }
6490
6491 Ok(())
6492 }
6493
6494 async fn resolve_completion_remote(
6495 project_id: u64,
6496 server_id: LanguageServerId,
6497 buffer_id: BufferId,
6498 completions: Rc<RefCell<Box<[Completion]>>>,
6499 completion_index: usize,
6500 client: AnyProtoClient,
6501 ) -> Result<()> {
6502 let lsp_completion = {
6503 let completion = &completions.borrow()[completion_index];
6504 match &completion.source {
6505 CompletionSource::Lsp {
6506 lsp_completion,
6507 resolved,
6508 server_id: completion_server_id,
6509 ..
6510 } => {
6511 anyhow::ensure!(
6512 server_id == *completion_server_id,
6513 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6514 );
6515 if *resolved {
6516 return Ok(());
6517 }
6518 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6519 }
6520 CompletionSource::Custom
6521 | CompletionSource::Dap { .. }
6522 | CompletionSource::BufferWord { .. } => {
6523 return Ok(());
6524 }
6525 }
6526 };
6527 let request = proto::ResolveCompletionDocumentation {
6528 project_id,
6529 language_server_id: server_id.0 as u64,
6530 lsp_completion,
6531 buffer_id: buffer_id.into(),
6532 };
6533
6534 let response = client
6535 .request(request)
6536 .await
6537 .context("completion documentation resolve proto request")?;
6538 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6539
6540 let documentation = if response.documentation.is_empty() {
6541 CompletionDocumentation::Undocumented
6542 } else if response.documentation_is_markdown {
6543 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6544 } else if response.documentation.lines().count() <= 1 {
6545 CompletionDocumentation::SingleLine(response.documentation.into())
6546 } else {
6547 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6548 };
6549
6550 let mut completions = completions.borrow_mut();
6551 let completion = &mut completions[completion_index];
6552 completion.documentation = Some(documentation);
6553 if let CompletionSource::Lsp {
6554 insert_range,
6555 lsp_completion,
6556 resolved,
6557 server_id: completion_server_id,
6558 lsp_defaults: _,
6559 } = &mut completion.source
6560 {
6561 let completion_insert_range = response
6562 .old_insert_start
6563 .and_then(deserialize_anchor)
6564 .zip(response.old_insert_end.and_then(deserialize_anchor));
6565 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6566
6567 if *resolved {
6568 return Ok(());
6569 }
6570 anyhow::ensure!(
6571 server_id == *completion_server_id,
6572 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6573 );
6574 *lsp_completion = Box::new(resolved_lsp_completion);
6575 *resolved = true;
6576 }
6577
6578 let replace_range = response
6579 .old_replace_start
6580 .and_then(deserialize_anchor)
6581 .zip(response.old_replace_end.and_then(deserialize_anchor));
6582 if let Some((old_replace_start, old_replace_end)) = replace_range
6583 && !response.new_text.is_empty()
6584 {
6585 completion.new_text = response.new_text;
6586 completion.replace_range = old_replace_start..old_replace_end;
6587 }
6588
6589 Ok(())
6590 }
6591
6592 pub fn apply_additional_edits_for_completion(
6593 &self,
6594 buffer_handle: Entity<Buffer>,
6595 completions: Rc<RefCell<Box<[Completion]>>>,
6596 completion_index: usize,
6597 push_to_history: bool,
6598 cx: &mut Context<Self>,
6599 ) -> Task<Result<Option<Transaction>>> {
6600 if let Some((client, project_id)) = self.upstream_client() {
6601 let buffer = buffer_handle.read(cx);
6602 let buffer_id = buffer.remote_id();
6603 cx.spawn(async move |_, cx| {
6604 let request = {
6605 let completion = completions.borrow()[completion_index].clone();
6606 proto::ApplyCompletionAdditionalEdits {
6607 project_id,
6608 buffer_id: buffer_id.into(),
6609 completion: Some(Self::serialize_completion(&CoreCompletion {
6610 replace_range: completion.replace_range,
6611 new_text: completion.new_text,
6612 source: completion.source,
6613 })),
6614 }
6615 };
6616
6617 if let Some(transaction) = client.request(request).await?.transaction {
6618 let transaction = language::proto::deserialize_transaction(transaction)?;
6619 buffer_handle
6620 .update(cx, |buffer, _| {
6621 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6622 })?
6623 .await?;
6624 if push_to_history {
6625 buffer_handle.update(cx, |buffer, _| {
6626 buffer.push_transaction(transaction.clone(), Instant::now());
6627 buffer.finalize_last_transaction();
6628 })?;
6629 }
6630 Ok(Some(transaction))
6631 } else {
6632 Ok(None)
6633 }
6634 })
6635 } else {
6636 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6637 let completion = &completions.borrow()[completion_index];
6638 let server_id = completion.source.server_id()?;
6639 Some(
6640 self.language_server_for_local_buffer(buffer, server_id, cx)?
6641 .1
6642 .clone(),
6643 )
6644 }) else {
6645 return Task::ready(Ok(None));
6646 };
6647
6648 cx.spawn(async move |this, cx| {
6649 Self::resolve_completion_local(
6650 server.clone(),
6651 completions.clone(),
6652 completion_index,
6653 )
6654 .await
6655 .context("resolving completion")?;
6656 let completion = completions.borrow()[completion_index].clone();
6657 let additional_text_edits = completion
6658 .source
6659 .lsp_completion(true)
6660 .as_ref()
6661 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6662 if let Some(edits) = additional_text_edits {
6663 let edits = this
6664 .update(cx, |this, cx| {
6665 this.as_local_mut().unwrap().edits_from_lsp(
6666 &buffer_handle,
6667 edits,
6668 server.server_id(),
6669 None,
6670 cx,
6671 )
6672 })?
6673 .await?;
6674
6675 buffer_handle.update(cx, |buffer, cx| {
6676 buffer.finalize_last_transaction();
6677 buffer.start_transaction();
6678
6679 for (range, text) in edits {
6680 let primary = &completion.replace_range;
6681
6682 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6683 // and the primary completion is just an insertion (empty range), then this is likely
6684 // an auto-import scenario and should not be considered overlapping
6685 // https://github.com/zed-industries/zed/issues/26136
6686 let is_file_start_auto_import = {
6687 let snapshot = buffer.snapshot();
6688 let primary_start_point = primary.start.to_point(&snapshot);
6689 let range_start_point = range.start.to_point(&snapshot);
6690
6691 let result = primary_start_point.row == 0
6692 && primary_start_point.column == 0
6693 && range_start_point.row == 0
6694 && range_start_point.column == 0;
6695
6696 result
6697 };
6698
6699 let has_overlap = if is_file_start_auto_import {
6700 false
6701 } else {
6702 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6703 && primary.end.cmp(&range.start, buffer).is_ge();
6704 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6705 && range.end.cmp(&primary.end, buffer).is_ge();
6706 let result = start_within || end_within;
6707 result
6708 };
6709
6710 //Skip additional edits which overlap with the primary completion edit
6711 //https://github.com/zed-industries/zed/pull/1871
6712 if !has_overlap {
6713 buffer.edit([(range, text)], None, cx);
6714 }
6715 }
6716
6717 let transaction = if buffer.end_transaction(cx).is_some() {
6718 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6719 if !push_to_history {
6720 buffer.forget_transaction(transaction.id);
6721 }
6722 Some(transaction)
6723 } else {
6724 None
6725 };
6726 Ok(transaction)
6727 })?
6728 } else {
6729 Ok(None)
6730 }
6731 })
6732 }
6733 }
6734
6735 pub fn pull_diagnostics(
6736 &mut self,
6737 buffer: Entity<Buffer>,
6738 cx: &mut Context<Self>,
6739 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6740 let buffer_id = buffer.read(cx).remote_id();
6741
6742 if let Some((client, upstream_project_id)) = self.upstream_client() {
6743 let mut suitable_capabilities = None;
6744 // Are we capable for proto request?
6745 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6746 &buffer,
6747 |capabilities| {
6748 if let Some(caps) = &capabilities.diagnostic_provider {
6749 suitable_capabilities = Some(caps.clone());
6750 true
6751 } else {
6752 false
6753 }
6754 },
6755 cx,
6756 );
6757 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6758 let Some(dynamic_caps) = suitable_capabilities else {
6759 return Task::ready(Ok(None));
6760 };
6761 assert!(any_server_has_diagnostics_provider);
6762
6763 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6764 let request = GetDocumentDiagnostics {
6765 previous_result_id: None,
6766 identifier,
6767 registration_id: None,
6768 };
6769 let request_task = client.request_lsp(
6770 upstream_project_id,
6771 None,
6772 LSP_REQUEST_TIMEOUT,
6773 cx.background_executor().clone(),
6774 request.to_proto(upstream_project_id, buffer.read(cx)),
6775 );
6776 cx.background_spawn(async move {
6777 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6778 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6779 // Do not attempt to further process the dummy responses here.
6780 let _response = request_task.await?;
6781 Ok(None)
6782 })
6783 } else {
6784 let servers = buffer.update(cx, |buffer, cx| {
6785 self.language_servers_for_local_buffer(buffer, cx)
6786 .map(|(_, server)| server.clone())
6787 .collect::<Vec<_>>()
6788 });
6789
6790 let pull_diagnostics = servers
6791 .into_iter()
6792 .flat_map(|server| {
6793 let result = maybe!({
6794 let local = self.as_local()?;
6795 let server_id = server.server_id();
6796 let providers_with_identifiers = local
6797 .language_server_dynamic_registrations
6798 .get(&server_id)
6799 .into_iter()
6800 .flat_map(|registrations| registrations.diagnostics.clone())
6801 .collect::<Vec<_>>();
6802 Some(
6803 providers_with_identifiers
6804 .into_iter()
6805 .map(|(registration_id, dynamic_caps)| {
6806 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6807 let registration_id = registration_id.map(SharedString::from);
6808 let result_id = self.result_id_for_buffer_pull(
6809 server_id,
6810 buffer_id,
6811 ®istration_id,
6812 cx,
6813 );
6814 self.request_lsp(
6815 buffer.clone(),
6816 LanguageServerToQuery::Other(server_id),
6817 GetDocumentDiagnostics {
6818 previous_result_id: result_id,
6819 registration_id,
6820 identifier,
6821 },
6822 cx,
6823 )
6824 })
6825 .collect::<Vec<_>>(),
6826 )
6827 });
6828
6829 result.unwrap_or_default()
6830 })
6831 .collect::<Vec<_>>();
6832
6833 cx.background_spawn(async move {
6834 let mut responses = Vec::new();
6835 for diagnostics in join_all(pull_diagnostics).await {
6836 responses.extend(diagnostics?);
6837 }
6838 Ok(Some(responses))
6839 })
6840 }
6841 }
6842
6843 pub fn applicable_inlay_chunks(
6844 &mut self,
6845 buffer: &Entity<Buffer>,
6846 ranges: &[Range<text::Anchor>],
6847 cx: &mut Context<Self>,
6848 ) -> Vec<Range<BufferRow>> {
6849 self.latest_lsp_data(buffer, cx)
6850 .inlay_hints
6851 .applicable_chunks(ranges)
6852 .map(|chunk| chunk.row_range())
6853 .collect()
6854 }
6855
6856 pub fn invalidate_inlay_hints<'a>(
6857 &'a mut self,
6858 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6859 ) {
6860 for buffer_id in for_buffers {
6861 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6862 lsp_data.inlay_hints.clear();
6863 }
6864 }
6865 }
6866
6867 pub fn inlay_hints(
6868 &mut self,
6869 invalidate: InvalidationStrategy,
6870 buffer: Entity<Buffer>,
6871 ranges: Vec<Range<text::Anchor>>,
6872 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6873 cx: &mut Context<Self>,
6874 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6875 let next_hint_id = self.next_hint_id.clone();
6876 let lsp_data = self.latest_lsp_data(&buffer, cx);
6877 let query_version = lsp_data.buffer_version.clone();
6878 let mut lsp_refresh_requested = false;
6879 let for_server = if let InvalidationStrategy::RefreshRequested {
6880 server_id,
6881 request_id,
6882 } = invalidate
6883 {
6884 let invalidated = lsp_data
6885 .inlay_hints
6886 .invalidate_for_server_refresh(server_id, request_id);
6887 lsp_refresh_requested = invalidated;
6888 Some(server_id)
6889 } else {
6890 None
6891 };
6892 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6893 let known_chunks = known_chunks
6894 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6895 .map(|(_, known_chunks)| known_chunks)
6896 .unwrap_or_default();
6897
6898 let mut hint_fetch_tasks = Vec::new();
6899 let mut cached_inlay_hints = None;
6900 let mut ranges_to_query = None;
6901 let applicable_chunks = existing_inlay_hints
6902 .applicable_chunks(ranges.as_slice())
6903 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6904 .collect::<Vec<_>>();
6905 if applicable_chunks.is_empty() {
6906 return HashMap::default();
6907 }
6908
6909 for row_chunk in applicable_chunks {
6910 match (
6911 existing_inlay_hints
6912 .cached_hints(&row_chunk)
6913 .filter(|_| !lsp_refresh_requested)
6914 .cloned(),
6915 existing_inlay_hints
6916 .fetched_hints(&row_chunk)
6917 .as_ref()
6918 .filter(|_| !lsp_refresh_requested)
6919 .cloned(),
6920 ) {
6921 (None, None) => {
6922 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6923 continue;
6924 };
6925 ranges_to_query
6926 .get_or_insert_with(Vec::new)
6927 .push((row_chunk, chunk_range));
6928 }
6929 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6930 (Some(cached_hints), None) => {
6931 for (server_id, cached_hints) in cached_hints {
6932 if for_server.is_none_or(|for_server| for_server == server_id) {
6933 cached_inlay_hints
6934 .get_or_insert_with(HashMap::default)
6935 .entry(row_chunk.row_range())
6936 .or_insert_with(HashMap::default)
6937 .entry(server_id)
6938 .or_insert_with(Vec::new)
6939 .extend(cached_hints);
6940 }
6941 }
6942 }
6943 (Some(cached_hints), Some(fetched_hints)) => {
6944 hint_fetch_tasks.push((row_chunk, fetched_hints));
6945 for (server_id, cached_hints) in cached_hints {
6946 if for_server.is_none_or(|for_server| for_server == server_id) {
6947 cached_inlay_hints
6948 .get_or_insert_with(HashMap::default)
6949 .entry(row_chunk.row_range())
6950 .or_insert_with(HashMap::default)
6951 .entry(server_id)
6952 .or_insert_with(Vec::new)
6953 .extend(cached_hints);
6954 }
6955 }
6956 }
6957 }
6958 }
6959
6960 if hint_fetch_tasks.is_empty()
6961 && ranges_to_query
6962 .as_ref()
6963 .is_none_or(|ranges| ranges.is_empty())
6964 && let Some(cached_inlay_hints) = cached_inlay_hints
6965 {
6966 cached_inlay_hints
6967 .into_iter()
6968 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6969 .collect()
6970 } else {
6971 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6972 let next_hint_id = next_hint_id.clone();
6973 let buffer = buffer.clone();
6974 let query_version = query_version.clone();
6975 let new_inlay_hints = cx
6976 .spawn(async move |lsp_store, cx| {
6977 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6978 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6979 })?;
6980 new_fetch_task
6981 .await
6982 .and_then(|new_hints_by_server| {
6983 lsp_store.update(cx, |lsp_store, cx| {
6984 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6985 let update_cache = lsp_data.buffer_version == query_version;
6986 if new_hints_by_server.is_empty() {
6987 if update_cache {
6988 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6989 }
6990 HashMap::default()
6991 } else {
6992 new_hints_by_server
6993 .into_iter()
6994 .map(|(server_id, new_hints)| {
6995 let new_hints = new_hints
6996 .into_iter()
6997 .map(|new_hint| {
6998 (
6999 InlayId::Hint(next_hint_id.fetch_add(
7000 1,
7001 atomic::Ordering::AcqRel,
7002 )),
7003 new_hint,
7004 )
7005 })
7006 .collect::<Vec<_>>();
7007 if update_cache {
7008 lsp_data.inlay_hints.insert_new_hints(
7009 chunk,
7010 server_id,
7011 new_hints.clone(),
7012 );
7013 }
7014 (server_id, new_hints)
7015 })
7016 .collect()
7017 }
7018 })
7019 })
7020 .map_err(Arc::new)
7021 })
7022 .shared();
7023
7024 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7025 *fetch_task = Some(new_inlay_hints.clone());
7026 hint_fetch_tasks.push((chunk, new_inlay_hints));
7027 }
7028
7029 cached_inlay_hints
7030 .unwrap_or_default()
7031 .into_iter()
7032 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7033 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7034 (
7035 chunk.row_range(),
7036 cx.spawn(async move |_, _| {
7037 hints_fetch.await.map_err(|e| {
7038 if e.error_code() != ErrorCode::Internal {
7039 anyhow!(e.error_code())
7040 } else {
7041 anyhow!("{e:#}")
7042 }
7043 })
7044 }),
7045 )
7046 }))
7047 .collect()
7048 }
7049 }
7050
7051 fn fetch_inlay_hints(
7052 &mut self,
7053 for_server: Option<LanguageServerId>,
7054 buffer: &Entity<Buffer>,
7055 range: Range<Anchor>,
7056 cx: &mut Context<Self>,
7057 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7058 let request = InlayHints {
7059 range: range.clone(),
7060 };
7061 if let Some((upstream_client, project_id)) = self.upstream_client() {
7062 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7063 return Task::ready(Ok(HashMap::default()));
7064 }
7065 let request_task = upstream_client.request_lsp(
7066 project_id,
7067 for_server.map(|id| id.to_proto()),
7068 LSP_REQUEST_TIMEOUT,
7069 cx.background_executor().clone(),
7070 request.to_proto(project_id, buffer.read(cx)),
7071 );
7072 let buffer = buffer.clone();
7073 cx.spawn(async move |weak_lsp_store, cx| {
7074 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7075 return Ok(HashMap::default());
7076 };
7077 let Some(responses) = request_task.await? else {
7078 return Ok(HashMap::default());
7079 };
7080
7081 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7082 let lsp_store = lsp_store.clone();
7083 let buffer = buffer.clone();
7084 let cx = cx.clone();
7085 let request = request.clone();
7086 async move {
7087 (
7088 LanguageServerId::from_proto(response.server_id),
7089 request
7090 .response_from_proto(response.response, lsp_store, buffer, cx)
7091 .await,
7092 )
7093 }
7094 }))
7095 .await;
7096
7097 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7098 let mut has_errors = false;
7099 let inlay_hints = inlay_hints
7100 .into_iter()
7101 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7102 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7103 Err(e) => {
7104 has_errors = true;
7105 log::error!("{e:#}");
7106 None
7107 }
7108 })
7109 .map(|(server_id, mut new_hints)| {
7110 new_hints.retain(|hint| {
7111 hint.position.is_valid(&buffer_snapshot)
7112 && range.start.is_valid(&buffer_snapshot)
7113 && range.end.is_valid(&buffer_snapshot)
7114 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7115 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7116 });
7117 (server_id, new_hints)
7118 })
7119 .collect::<HashMap<_, _>>();
7120 anyhow::ensure!(
7121 !has_errors || !inlay_hints.is_empty(),
7122 "Failed to fetch inlay hints"
7123 );
7124 Ok(inlay_hints)
7125 })
7126 } else {
7127 let inlay_hints_task = match for_server {
7128 Some(server_id) => {
7129 let server_task = self.request_lsp(
7130 buffer.clone(),
7131 LanguageServerToQuery::Other(server_id),
7132 request,
7133 cx,
7134 );
7135 cx.background_spawn(async move {
7136 let mut responses = Vec::new();
7137 match server_task.await {
7138 Ok(response) => responses.push((server_id, response)),
7139 // rust-analyzer likes to error with this when its still loading up
7140 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7141 Err(e) => log::error!(
7142 "Error handling response for inlay hints request: {e:#}"
7143 ),
7144 }
7145 responses
7146 })
7147 }
7148 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7149 };
7150 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7151 cx.background_spawn(async move {
7152 Ok(inlay_hints_task
7153 .await
7154 .into_iter()
7155 .map(|(server_id, mut new_hints)| {
7156 new_hints.retain(|hint| {
7157 hint.position.is_valid(&buffer_snapshot)
7158 && range.start.is_valid(&buffer_snapshot)
7159 && range.end.is_valid(&buffer_snapshot)
7160 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7161 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7162 });
7163 (server_id, new_hints)
7164 })
7165 .collect())
7166 })
7167 }
7168 }
7169
7170 pub fn pull_diagnostics_for_buffer(
7171 &mut self,
7172 buffer: Entity<Buffer>,
7173 cx: &mut Context<Self>,
7174 ) -> Task<anyhow::Result<()>> {
7175 let diagnostics = self.pull_diagnostics(buffer, cx);
7176 cx.spawn(async move |lsp_store, cx| {
7177 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7178 return Ok(());
7179 };
7180 lsp_store.update(cx, |lsp_store, cx| {
7181 if lsp_store.as_local().is_none() {
7182 return;
7183 }
7184
7185 let mut unchanged_buffers = HashMap::default();
7186 let server_diagnostics_updates = diagnostics
7187 .into_iter()
7188 .filter_map(|diagnostics_set| match diagnostics_set {
7189 LspPullDiagnostics::Response {
7190 server_id,
7191 uri,
7192 diagnostics,
7193 registration_id,
7194 } => Some((server_id, uri, diagnostics, registration_id)),
7195 LspPullDiagnostics::Default => None,
7196 })
7197 .fold(
7198 HashMap::default(),
7199 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7200 let (result_id, diagnostics) = match diagnostics {
7201 PulledDiagnostics::Unchanged { result_id } => {
7202 unchanged_buffers
7203 .entry(new_registration_id.clone())
7204 .or_insert_with(HashSet::default)
7205 .insert(uri.clone());
7206 (Some(result_id), Vec::new())
7207 }
7208 PulledDiagnostics::Changed {
7209 result_id,
7210 diagnostics,
7211 } => (result_id, diagnostics),
7212 };
7213 let disk_based_sources = Cow::Owned(
7214 lsp_store
7215 .language_server_adapter_for_id(server_id)
7216 .as_ref()
7217 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7218 .unwrap_or(&[])
7219 .to_vec(),
7220 );
7221 acc.entry(server_id)
7222 .or_insert_with(HashMap::default)
7223 .entry(new_registration_id.clone())
7224 .or_insert_with(Vec::new)
7225 .push(DocumentDiagnosticsUpdate {
7226 server_id,
7227 diagnostics: lsp::PublishDiagnosticsParams {
7228 uri,
7229 diagnostics,
7230 version: None,
7231 },
7232 result_id,
7233 disk_based_sources,
7234 registration_id: new_registration_id,
7235 });
7236 acc
7237 },
7238 );
7239
7240 for diagnostic_updates in server_diagnostics_updates.into_values() {
7241 for (registration_id, diagnostic_updates) in diagnostic_updates {
7242 lsp_store
7243 .merge_lsp_diagnostics(
7244 DiagnosticSourceKind::Pulled,
7245 diagnostic_updates,
7246 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7247 DiagnosticSourceKind::Pulled => {
7248 old_diagnostic.registration_id != registration_id
7249 || unchanged_buffers
7250 .get(&old_diagnostic.registration_id)
7251 .is_some_and(|unchanged_buffers| {
7252 unchanged_buffers.contains(&document_uri)
7253 })
7254 }
7255 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7256 true
7257 }
7258 },
7259 cx,
7260 )
7261 .log_err();
7262 }
7263 }
7264 })
7265 })
7266 }
7267
7268 pub fn document_colors(
7269 &mut self,
7270 known_cache_version: Option<usize>,
7271 buffer: Entity<Buffer>,
7272 cx: &mut Context<Self>,
7273 ) -> Option<DocumentColorTask> {
7274 let version_queried_for = buffer.read(cx).version();
7275 let buffer_id = buffer.read(cx).remote_id();
7276
7277 let current_language_servers = self.as_local().map(|local| {
7278 local
7279 .buffers_opened_in_servers
7280 .get(&buffer_id)
7281 .cloned()
7282 .unwrap_or_default()
7283 });
7284
7285 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7286 if let Some(cached_colors) = &lsp_data.document_colors {
7287 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7288 let has_different_servers =
7289 current_language_servers.is_some_and(|current_language_servers| {
7290 current_language_servers
7291 != cached_colors.colors.keys().copied().collect()
7292 });
7293 if !has_different_servers {
7294 let cache_version = cached_colors.cache_version;
7295 if Some(cache_version) == known_cache_version {
7296 return None;
7297 } else {
7298 return Some(
7299 Task::ready(Ok(DocumentColors {
7300 colors: cached_colors
7301 .colors
7302 .values()
7303 .flatten()
7304 .cloned()
7305 .collect(),
7306 cache_version: Some(cache_version),
7307 }))
7308 .shared(),
7309 );
7310 }
7311 }
7312 }
7313 }
7314 }
7315
7316 let color_lsp_data = self
7317 .latest_lsp_data(&buffer, cx)
7318 .document_colors
7319 .get_or_insert_default();
7320 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7321 && !version_queried_for.changed_since(updating_for)
7322 {
7323 return Some(running_update.clone());
7324 }
7325 let buffer_version_queried_for = version_queried_for.clone();
7326 let new_task = cx
7327 .spawn(async move |lsp_store, cx| {
7328 cx.background_executor()
7329 .timer(Duration::from_millis(30))
7330 .await;
7331 let fetched_colors = lsp_store
7332 .update(cx, |lsp_store, cx| {
7333 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7334 })?
7335 .await
7336 .context("fetching document colors")
7337 .map_err(Arc::new);
7338 let fetched_colors = match fetched_colors {
7339 Ok(fetched_colors) => {
7340 if Some(true)
7341 == buffer
7342 .update(cx, |buffer, _| {
7343 buffer.version() != buffer_version_queried_for
7344 })
7345 .ok()
7346 {
7347 return Ok(DocumentColors::default());
7348 }
7349 fetched_colors
7350 }
7351 Err(e) => {
7352 lsp_store
7353 .update(cx, |lsp_store, _| {
7354 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7355 if let Some(document_colors) = &mut lsp_data.document_colors {
7356 document_colors.colors_update = None;
7357 }
7358 }
7359 })
7360 .ok();
7361 return Err(e);
7362 }
7363 };
7364
7365 lsp_store
7366 .update(cx, |lsp_store, cx| {
7367 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7368 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7369
7370 if let Some(fetched_colors) = fetched_colors {
7371 if lsp_data.buffer_version == buffer_version_queried_for {
7372 lsp_colors.colors.extend(fetched_colors);
7373 lsp_colors.cache_version += 1;
7374 } else if !lsp_data
7375 .buffer_version
7376 .changed_since(&buffer_version_queried_for)
7377 {
7378 lsp_data.buffer_version = buffer_version_queried_for;
7379 lsp_colors.colors = fetched_colors;
7380 lsp_colors.cache_version += 1;
7381 }
7382 }
7383 lsp_colors.colors_update = None;
7384 let colors = lsp_colors
7385 .colors
7386 .values()
7387 .flatten()
7388 .cloned()
7389 .collect::<HashSet<_>>();
7390 DocumentColors {
7391 colors,
7392 cache_version: Some(lsp_colors.cache_version),
7393 }
7394 })
7395 .map_err(Arc::new)
7396 })
7397 .shared();
7398 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7399 Some(new_task)
7400 }
7401
7402 fn fetch_document_colors_for_buffer(
7403 &mut self,
7404 buffer: &Entity<Buffer>,
7405 cx: &mut Context<Self>,
7406 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7407 if let Some((client, project_id)) = self.upstream_client() {
7408 let request = GetDocumentColor {};
7409 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7410 return Task::ready(Ok(None));
7411 }
7412
7413 let request_task = client.request_lsp(
7414 project_id,
7415 None,
7416 LSP_REQUEST_TIMEOUT,
7417 cx.background_executor().clone(),
7418 request.to_proto(project_id, buffer.read(cx)),
7419 );
7420 let buffer = buffer.clone();
7421 cx.spawn(async move |lsp_store, cx| {
7422 let Some(lsp_store) = lsp_store.upgrade() else {
7423 return Ok(None);
7424 };
7425 let colors = join_all(
7426 request_task
7427 .await
7428 .log_err()
7429 .flatten()
7430 .map(|response| response.payload)
7431 .unwrap_or_default()
7432 .into_iter()
7433 .map(|color_response| {
7434 let response = request.response_from_proto(
7435 color_response.response,
7436 lsp_store.clone(),
7437 buffer.clone(),
7438 cx.clone(),
7439 );
7440 async move {
7441 (
7442 LanguageServerId::from_proto(color_response.server_id),
7443 response.await.log_err().unwrap_or_default(),
7444 )
7445 }
7446 }),
7447 )
7448 .await
7449 .into_iter()
7450 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7451 acc.entry(server_id)
7452 .or_insert_with(HashSet::default)
7453 .extend(colors);
7454 acc
7455 });
7456 Ok(Some(colors))
7457 })
7458 } else {
7459 let document_colors_task =
7460 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7461 cx.background_spawn(async move {
7462 Ok(Some(
7463 document_colors_task
7464 .await
7465 .into_iter()
7466 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7467 acc.entry(server_id)
7468 .or_insert_with(HashSet::default)
7469 .extend(colors);
7470 acc
7471 })
7472 .into_iter()
7473 .collect(),
7474 ))
7475 })
7476 }
7477 }
7478
7479 pub fn signature_help<T: ToPointUtf16>(
7480 &mut self,
7481 buffer: &Entity<Buffer>,
7482 position: T,
7483 cx: &mut Context<Self>,
7484 ) -> Task<Option<Vec<SignatureHelp>>> {
7485 let position = position.to_point_utf16(buffer.read(cx));
7486
7487 if let Some((client, upstream_project_id)) = self.upstream_client() {
7488 let request = GetSignatureHelp { position };
7489 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7490 return Task::ready(None);
7491 }
7492 let request_task = client.request_lsp(
7493 upstream_project_id,
7494 None,
7495 LSP_REQUEST_TIMEOUT,
7496 cx.background_executor().clone(),
7497 request.to_proto(upstream_project_id, buffer.read(cx)),
7498 );
7499 let buffer = buffer.clone();
7500 cx.spawn(async move |weak_lsp_store, cx| {
7501 let lsp_store = weak_lsp_store.upgrade()?;
7502 let signatures = join_all(
7503 request_task
7504 .await
7505 .log_err()
7506 .flatten()
7507 .map(|response| response.payload)
7508 .unwrap_or_default()
7509 .into_iter()
7510 .map(|response| {
7511 let response = GetSignatureHelp { position }.response_from_proto(
7512 response.response,
7513 lsp_store.clone(),
7514 buffer.clone(),
7515 cx.clone(),
7516 );
7517 async move { response.await.log_err().flatten() }
7518 }),
7519 )
7520 .await
7521 .into_iter()
7522 .flatten()
7523 .collect();
7524 Some(signatures)
7525 })
7526 } else {
7527 let all_actions_task = self.request_multiple_lsp_locally(
7528 buffer,
7529 Some(position),
7530 GetSignatureHelp { position },
7531 cx,
7532 );
7533 cx.background_spawn(async move {
7534 Some(
7535 all_actions_task
7536 .await
7537 .into_iter()
7538 .flat_map(|(_, actions)| actions)
7539 .collect::<Vec<_>>(),
7540 )
7541 })
7542 }
7543 }
7544
7545 pub fn hover(
7546 &mut self,
7547 buffer: &Entity<Buffer>,
7548 position: PointUtf16,
7549 cx: &mut Context<Self>,
7550 ) -> Task<Option<Vec<Hover>>> {
7551 if let Some((client, upstream_project_id)) = self.upstream_client() {
7552 let request = GetHover { position };
7553 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7554 return Task::ready(None);
7555 }
7556 let request_task = client.request_lsp(
7557 upstream_project_id,
7558 None,
7559 LSP_REQUEST_TIMEOUT,
7560 cx.background_executor().clone(),
7561 request.to_proto(upstream_project_id, buffer.read(cx)),
7562 );
7563 let buffer = buffer.clone();
7564 cx.spawn(async move |weak_lsp_store, cx| {
7565 let lsp_store = weak_lsp_store.upgrade()?;
7566 let hovers = join_all(
7567 request_task
7568 .await
7569 .log_err()
7570 .flatten()
7571 .map(|response| response.payload)
7572 .unwrap_or_default()
7573 .into_iter()
7574 .map(|response| {
7575 let response = GetHover { position }.response_from_proto(
7576 response.response,
7577 lsp_store.clone(),
7578 buffer.clone(),
7579 cx.clone(),
7580 );
7581 async move {
7582 response
7583 .await
7584 .log_err()
7585 .flatten()
7586 .and_then(remove_empty_hover_blocks)
7587 }
7588 }),
7589 )
7590 .await
7591 .into_iter()
7592 .flatten()
7593 .collect();
7594 Some(hovers)
7595 })
7596 } else {
7597 let all_actions_task = self.request_multiple_lsp_locally(
7598 buffer,
7599 Some(position),
7600 GetHover { position },
7601 cx,
7602 );
7603 cx.background_spawn(async move {
7604 Some(
7605 all_actions_task
7606 .await
7607 .into_iter()
7608 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7609 .collect::<Vec<Hover>>(),
7610 )
7611 })
7612 }
7613 }
7614
7615 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7616 let language_registry = self.languages.clone();
7617
7618 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7619 let request = upstream_client.request(proto::GetProjectSymbols {
7620 project_id: *project_id,
7621 query: query.to_string(),
7622 });
7623 cx.foreground_executor().spawn(async move {
7624 let response = request.await?;
7625 let mut symbols = Vec::new();
7626 let core_symbols = response
7627 .symbols
7628 .into_iter()
7629 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7630 .collect::<Vec<_>>();
7631 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7632 .await;
7633 Ok(symbols)
7634 })
7635 } else if let Some(local) = self.as_local() {
7636 struct WorkspaceSymbolsResult {
7637 server_id: LanguageServerId,
7638 lsp_adapter: Arc<CachedLspAdapter>,
7639 worktree: WeakEntity<Worktree>,
7640 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7641 }
7642
7643 let mut requests = Vec::new();
7644 let mut requested_servers = BTreeSet::new();
7645 for (seed, state) in local.language_server_ids.iter() {
7646 let Some(worktree_handle) = self
7647 .worktree_store
7648 .read(cx)
7649 .worktree_for_id(seed.worktree_id, cx)
7650 else {
7651 continue;
7652 };
7653 let worktree = worktree_handle.read(cx);
7654 if !worktree.is_visible() {
7655 continue;
7656 }
7657
7658 if !requested_servers.insert(state.id) {
7659 continue;
7660 }
7661
7662 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7663 Some(LanguageServerState::Running {
7664 adapter, server, ..
7665 }) => (adapter.clone(), server),
7666
7667 _ => continue,
7668 };
7669 let supports_workspace_symbol_request =
7670 match server.capabilities().workspace_symbol_provider {
7671 Some(OneOf::Left(supported)) => supported,
7672 Some(OneOf::Right(_)) => true,
7673 None => false,
7674 };
7675 if !supports_workspace_symbol_request {
7676 continue;
7677 }
7678 let worktree_handle = worktree_handle.clone();
7679 let server_id = server.server_id();
7680 requests.push(
7681 server
7682 .request::<lsp::request::WorkspaceSymbolRequest>(
7683 lsp::WorkspaceSymbolParams {
7684 query: query.to_string(),
7685 ..Default::default()
7686 },
7687 )
7688 .map(move |response| {
7689 let lsp_symbols = response.into_response()
7690 .context("workspace symbols request")
7691 .log_err()
7692 .flatten()
7693 .map(|symbol_response| match symbol_response {
7694 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7695 flat_responses.into_iter().map(|lsp_symbol| {
7696 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7697 }).collect::<Vec<_>>()
7698 }
7699 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7700 nested_responses.into_iter().filter_map(|lsp_symbol| {
7701 let location = match lsp_symbol.location {
7702 OneOf::Left(location) => location,
7703 OneOf::Right(_) => {
7704 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7705 return None
7706 }
7707 };
7708 Some((lsp_symbol.name, lsp_symbol.kind, location))
7709 }).collect::<Vec<_>>()
7710 }
7711 }).unwrap_or_default();
7712
7713 WorkspaceSymbolsResult {
7714 server_id,
7715 lsp_adapter,
7716 worktree: worktree_handle.downgrade(),
7717 lsp_symbols,
7718 }
7719 }),
7720 );
7721 }
7722
7723 cx.spawn(async move |this, cx| {
7724 let responses = futures::future::join_all(requests).await;
7725 let this = match this.upgrade() {
7726 Some(this) => this,
7727 None => return Ok(Vec::new()),
7728 };
7729
7730 let mut symbols = Vec::new();
7731 for result in responses {
7732 let core_symbols = this.update(cx, |this, cx| {
7733 result
7734 .lsp_symbols
7735 .into_iter()
7736 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7737 let abs_path = symbol_location.uri.to_file_path().ok()?;
7738 let source_worktree = result.worktree.upgrade()?;
7739 let source_worktree_id = source_worktree.read(cx).id();
7740
7741 let path = if let Some((tree, rel_path)) =
7742 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7743 {
7744 let worktree_id = tree.read(cx).id();
7745 SymbolLocation::InProject(ProjectPath {
7746 worktree_id,
7747 path: rel_path,
7748 })
7749 } else {
7750 SymbolLocation::OutsideProject {
7751 signature: this.symbol_signature(&abs_path),
7752 abs_path: abs_path.into(),
7753 }
7754 };
7755
7756 Some(CoreSymbol {
7757 source_language_server_id: result.server_id,
7758 language_server_name: result.lsp_adapter.name.clone(),
7759 source_worktree_id,
7760 path,
7761 kind: symbol_kind,
7762 name: symbol_name,
7763 range: range_from_lsp(symbol_location.range),
7764 })
7765 })
7766 .collect()
7767 })?;
7768
7769 populate_labels_for_symbols(
7770 core_symbols,
7771 &language_registry,
7772 Some(result.lsp_adapter),
7773 &mut symbols,
7774 )
7775 .await;
7776 }
7777
7778 Ok(symbols)
7779 })
7780 } else {
7781 Task::ready(Err(anyhow!("No upstream client or local language server")))
7782 }
7783 }
7784
7785 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7786 let mut summary = DiagnosticSummary::default();
7787 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7788 summary.error_count += path_summary.error_count;
7789 summary.warning_count += path_summary.warning_count;
7790 }
7791 summary
7792 }
7793
7794 /// Returns the diagnostic summary for a specific project path.
7795 pub fn diagnostic_summary_for_path(
7796 &self,
7797 project_path: &ProjectPath,
7798 _: &App,
7799 ) -> DiagnosticSummary {
7800 if let Some(summaries) = self
7801 .diagnostic_summaries
7802 .get(&project_path.worktree_id)
7803 .and_then(|map| map.get(&project_path.path))
7804 {
7805 let (error_count, warning_count) = summaries.iter().fold(
7806 (0, 0),
7807 |(error_count, warning_count), (_language_server_id, summary)| {
7808 (
7809 error_count + summary.error_count,
7810 warning_count + summary.warning_count,
7811 )
7812 },
7813 );
7814
7815 DiagnosticSummary {
7816 error_count,
7817 warning_count,
7818 }
7819 } else {
7820 DiagnosticSummary::default()
7821 }
7822 }
7823
7824 pub fn diagnostic_summaries<'a>(
7825 &'a self,
7826 include_ignored: bool,
7827 cx: &'a App,
7828 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7829 self.worktree_store
7830 .read(cx)
7831 .visible_worktrees(cx)
7832 .filter_map(|worktree| {
7833 let worktree = worktree.read(cx);
7834 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7835 })
7836 .flat_map(move |(worktree, summaries)| {
7837 let worktree_id = worktree.id();
7838 summaries
7839 .iter()
7840 .filter(move |(path, _)| {
7841 include_ignored
7842 || worktree
7843 .entry_for_path(path.as_ref())
7844 .is_some_and(|entry| !entry.is_ignored)
7845 })
7846 .flat_map(move |(path, summaries)| {
7847 summaries.iter().map(move |(server_id, summary)| {
7848 (
7849 ProjectPath {
7850 worktree_id,
7851 path: path.clone(),
7852 },
7853 *server_id,
7854 *summary,
7855 )
7856 })
7857 })
7858 })
7859 }
7860
7861 pub fn on_buffer_edited(
7862 &mut self,
7863 buffer: Entity<Buffer>,
7864 cx: &mut Context<Self>,
7865 ) -> Option<()> {
7866 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7867 Some(
7868 self.as_local()?
7869 .language_servers_for_buffer(buffer, cx)
7870 .map(|i| i.1.clone())
7871 .collect(),
7872 )
7873 })?;
7874
7875 let buffer = buffer.read(cx);
7876 let file = File::from_dyn(buffer.file())?;
7877 let abs_path = file.as_local()?.abs_path(cx);
7878 let uri = lsp::Uri::from_file_path(&abs_path)
7879 .ok()
7880 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7881 .log_err()?;
7882 let next_snapshot = buffer.text_snapshot();
7883 for language_server in language_servers {
7884 let language_server = language_server.clone();
7885
7886 let buffer_snapshots = self
7887 .as_local_mut()?
7888 .buffer_snapshots
7889 .get_mut(&buffer.remote_id())
7890 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7891 let previous_snapshot = buffer_snapshots.last()?;
7892
7893 let build_incremental_change = || {
7894 buffer
7895 .edits_since::<Dimensions<PointUtf16, usize>>(
7896 previous_snapshot.snapshot.version(),
7897 )
7898 .map(|edit| {
7899 let edit_start = edit.new.start.0;
7900 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7901 let new_text = next_snapshot
7902 .text_for_range(edit.new.start.1..edit.new.end.1)
7903 .collect();
7904 lsp::TextDocumentContentChangeEvent {
7905 range: Some(lsp::Range::new(
7906 point_to_lsp(edit_start),
7907 point_to_lsp(edit_end),
7908 )),
7909 range_length: None,
7910 text: new_text,
7911 }
7912 })
7913 .collect()
7914 };
7915
7916 let document_sync_kind = language_server
7917 .capabilities()
7918 .text_document_sync
7919 .as_ref()
7920 .and_then(|sync| match sync {
7921 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7922 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7923 });
7924
7925 let content_changes: Vec<_> = match document_sync_kind {
7926 Some(lsp::TextDocumentSyncKind::FULL) => {
7927 vec![lsp::TextDocumentContentChangeEvent {
7928 range: None,
7929 range_length: None,
7930 text: next_snapshot.text(),
7931 }]
7932 }
7933 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7934 _ => {
7935 #[cfg(any(test, feature = "test-support"))]
7936 {
7937 build_incremental_change()
7938 }
7939
7940 #[cfg(not(any(test, feature = "test-support")))]
7941 {
7942 continue;
7943 }
7944 }
7945 };
7946
7947 let next_version = previous_snapshot.version + 1;
7948 buffer_snapshots.push(LspBufferSnapshot {
7949 version: next_version,
7950 snapshot: next_snapshot.clone(),
7951 });
7952
7953 language_server
7954 .notify::<lsp::notification::DidChangeTextDocument>(
7955 lsp::DidChangeTextDocumentParams {
7956 text_document: lsp::VersionedTextDocumentIdentifier::new(
7957 uri.clone(),
7958 next_version,
7959 ),
7960 content_changes,
7961 },
7962 )
7963 .ok();
7964 self.pull_workspace_diagnostics(language_server.server_id());
7965 }
7966
7967 None
7968 }
7969
7970 pub fn on_buffer_saved(
7971 &mut self,
7972 buffer: Entity<Buffer>,
7973 cx: &mut Context<Self>,
7974 ) -> Option<()> {
7975 let file = File::from_dyn(buffer.read(cx).file())?;
7976 let worktree_id = file.worktree_id(cx);
7977 let abs_path = file.as_local()?.abs_path(cx);
7978 let text_document = lsp::TextDocumentIdentifier {
7979 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7980 };
7981 let local = self.as_local()?;
7982
7983 for server in local.language_servers_for_worktree(worktree_id) {
7984 if let Some(include_text) = include_text(server.as_ref()) {
7985 let text = if include_text {
7986 Some(buffer.read(cx).text())
7987 } else {
7988 None
7989 };
7990 server
7991 .notify::<lsp::notification::DidSaveTextDocument>(
7992 lsp::DidSaveTextDocumentParams {
7993 text_document: text_document.clone(),
7994 text,
7995 },
7996 )
7997 .ok();
7998 }
7999 }
8000
8001 let language_servers = buffer.update(cx, |buffer, cx| {
8002 local.language_server_ids_for_buffer(buffer, cx)
8003 });
8004 for language_server_id in language_servers {
8005 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8006 }
8007
8008 None
8009 }
8010
8011 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8012 maybe!(async move {
8013 let mut refreshed_servers = HashSet::default();
8014 let servers = lsp_store
8015 .update(cx, |lsp_store, cx| {
8016 let local = lsp_store.as_local()?;
8017
8018 let servers = local
8019 .language_server_ids
8020 .iter()
8021 .filter_map(|(seed, state)| {
8022 let worktree = lsp_store
8023 .worktree_store
8024 .read(cx)
8025 .worktree_for_id(seed.worktree_id, cx);
8026 let delegate: Arc<dyn LspAdapterDelegate> =
8027 worktree.map(|worktree| {
8028 LocalLspAdapterDelegate::new(
8029 local.languages.clone(),
8030 &local.environment,
8031 cx.weak_entity(),
8032 &worktree,
8033 local.http_client.clone(),
8034 local.fs.clone(),
8035 cx,
8036 )
8037 })?;
8038 let server_id = state.id;
8039
8040 let states = local.language_servers.get(&server_id)?;
8041
8042 match states {
8043 LanguageServerState::Starting { .. } => None,
8044 LanguageServerState::Running {
8045 adapter, server, ..
8046 } => {
8047 let adapter = adapter.clone();
8048 let server = server.clone();
8049 refreshed_servers.insert(server.name());
8050 let toolchain = seed.toolchain.clone();
8051 Some(cx.spawn(async move |_, cx| {
8052 let settings =
8053 LocalLspStore::workspace_configuration_for_adapter(
8054 adapter.adapter.clone(),
8055 &delegate,
8056 toolchain,
8057 None,
8058 cx,
8059 )
8060 .await
8061 .ok()?;
8062 server
8063 .notify::<lsp::notification::DidChangeConfiguration>(
8064 lsp::DidChangeConfigurationParams { settings },
8065 )
8066 .ok()?;
8067 Some(())
8068 }))
8069 }
8070 }
8071 })
8072 .collect::<Vec<_>>();
8073
8074 Some(servers)
8075 })
8076 .ok()
8077 .flatten()?;
8078
8079 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8080 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8081 // to stop and unregister its language server wrapper.
8082 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8083 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8084 let _: Vec<Option<()>> = join_all(servers).await;
8085
8086 Some(())
8087 })
8088 .await;
8089 }
8090
8091 fn maintain_workspace_config(
8092 external_refresh_requests: watch::Receiver<()>,
8093 cx: &mut Context<Self>,
8094 ) -> Task<Result<()>> {
8095 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8096 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8097
8098 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8099 *settings_changed_tx.borrow_mut() = ();
8100 });
8101
8102 let mut joint_future =
8103 futures::stream::select(settings_changed_rx, external_refresh_requests);
8104 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8105 // - 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).
8106 // - 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.
8107 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8108 // - 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,
8109 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8110 cx.spawn(async move |this, cx| {
8111 while let Some(()) = joint_future.next().await {
8112 this.update(cx, |this, cx| {
8113 this.refresh_server_tree(cx);
8114 })
8115 .ok();
8116
8117 Self::refresh_workspace_configurations(&this, cx).await;
8118 }
8119
8120 drop(settings_observation);
8121 anyhow::Ok(())
8122 })
8123 }
8124
8125 pub fn language_servers_for_local_buffer<'a>(
8126 &'a self,
8127 buffer: &Buffer,
8128 cx: &mut App,
8129 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8130 let local = self.as_local();
8131 let language_server_ids = local
8132 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8133 .unwrap_or_default();
8134
8135 language_server_ids
8136 .into_iter()
8137 .filter_map(
8138 move |server_id| match local?.language_servers.get(&server_id)? {
8139 LanguageServerState::Running {
8140 adapter, server, ..
8141 } => Some((adapter, server)),
8142 _ => None,
8143 },
8144 )
8145 }
8146
8147 pub fn language_server_for_local_buffer<'a>(
8148 &'a self,
8149 buffer: &'a Buffer,
8150 server_id: LanguageServerId,
8151 cx: &'a mut App,
8152 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8153 self.as_local()?
8154 .language_servers_for_buffer(buffer, cx)
8155 .find(|(_, s)| s.server_id() == server_id)
8156 }
8157
8158 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8159 self.diagnostic_summaries.remove(&id_to_remove);
8160 if let Some(local) = self.as_local_mut() {
8161 let to_remove = local.remove_worktree(id_to_remove, cx);
8162 for server in to_remove {
8163 self.language_server_statuses.remove(&server);
8164 }
8165 }
8166 }
8167
8168 pub fn shared(
8169 &mut self,
8170 project_id: u64,
8171 downstream_client: AnyProtoClient,
8172 _: &mut Context<Self>,
8173 ) {
8174 self.downstream_client = Some((downstream_client.clone(), project_id));
8175
8176 for (server_id, status) in &self.language_server_statuses {
8177 if let Some(server) = self.language_server_for_id(*server_id) {
8178 downstream_client
8179 .send(proto::StartLanguageServer {
8180 project_id,
8181 server: Some(proto::LanguageServer {
8182 id: server_id.to_proto(),
8183 name: status.name.to_string(),
8184 worktree_id: status.worktree.map(|id| id.to_proto()),
8185 }),
8186 capabilities: serde_json::to_string(&server.capabilities())
8187 .expect("serializing server LSP capabilities"),
8188 })
8189 .log_err();
8190 }
8191 }
8192 }
8193
8194 pub fn disconnected_from_host(&mut self) {
8195 self.downstream_client.take();
8196 }
8197
8198 pub fn disconnected_from_ssh_remote(&mut self) {
8199 if let LspStoreMode::Remote(RemoteLspStore {
8200 upstream_client, ..
8201 }) = &mut self.mode
8202 {
8203 upstream_client.take();
8204 }
8205 }
8206
8207 pub(crate) fn set_language_server_statuses_from_proto(
8208 &mut self,
8209 project: WeakEntity<Project>,
8210 language_servers: Vec<proto::LanguageServer>,
8211 server_capabilities: Vec<String>,
8212 cx: &mut Context<Self>,
8213 ) {
8214 let lsp_logs = cx
8215 .try_global::<GlobalLogStore>()
8216 .map(|lsp_store| lsp_store.0.clone());
8217
8218 self.language_server_statuses = language_servers
8219 .into_iter()
8220 .zip(server_capabilities)
8221 .map(|(server, server_capabilities)| {
8222 let server_id = LanguageServerId(server.id as usize);
8223 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8224 self.lsp_server_capabilities
8225 .insert(server_id, server_capabilities);
8226 }
8227
8228 let name = LanguageServerName::from_proto(server.name);
8229 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8230
8231 if let Some(lsp_logs) = &lsp_logs {
8232 lsp_logs.update(cx, |lsp_logs, cx| {
8233 lsp_logs.add_language_server(
8234 // Only remote clients get their language servers set from proto
8235 LanguageServerKind::Remote {
8236 project: project.clone(),
8237 },
8238 server_id,
8239 Some(name.clone()),
8240 worktree,
8241 None,
8242 cx,
8243 );
8244 });
8245 }
8246
8247 (
8248 server_id,
8249 LanguageServerStatus {
8250 name,
8251 pending_work: Default::default(),
8252 has_pending_diagnostic_updates: false,
8253 progress_tokens: Default::default(),
8254 worktree,
8255 binary: None,
8256 configuration: None,
8257 workspace_folders: BTreeSet::new(),
8258 },
8259 )
8260 })
8261 .collect();
8262 }
8263
8264 #[cfg(test)]
8265 pub fn update_diagnostic_entries(
8266 &mut self,
8267 server_id: LanguageServerId,
8268 abs_path: PathBuf,
8269 result_id: Option<SharedString>,
8270 version: Option<i32>,
8271 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8272 cx: &mut Context<Self>,
8273 ) -> anyhow::Result<()> {
8274 self.merge_diagnostic_entries(
8275 vec![DocumentDiagnosticsUpdate {
8276 diagnostics: DocumentDiagnostics {
8277 diagnostics,
8278 document_abs_path: abs_path,
8279 version,
8280 },
8281 result_id,
8282 server_id,
8283 disk_based_sources: Cow::Borrowed(&[]),
8284 registration_id: None,
8285 }],
8286 |_, _, _| false,
8287 cx,
8288 )?;
8289 Ok(())
8290 }
8291
8292 pub fn merge_diagnostic_entries<'a>(
8293 &mut self,
8294 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8295 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8296 cx: &mut Context<Self>,
8297 ) -> anyhow::Result<()> {
8298 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8299 let mut updated_diagnostics_paths = HashMap::default();
8300 for mut update in diagnostic_updates {
8301 let abs_path = &update.diagnostics.document_abs_path;
8302 let server_id = update.server_id;
8303 let Some((worktree, relative_path)) =
8304 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8305 else {
8306 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8307 return Ok(());
8308 };
8309
8310 let worktree_id = worktree.read(cx).id();
8311 let project_path = ProjectPath {
8312 worktree_id,
8313 path: relative_path,
8314 };
8315
8316 let document_uri = lsp::Uri::from_file_path(abs_path)
8317 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8318 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8319 let snapshot = buffer_handle.read(cx).snapshot();
8320 let buffer = buffer_handle.read(cx);
8321 let reused_diagnostics = buffer
8322 .buffer_diagnostics(Some(server_id))
8323 .iter()
8324 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8325 .map(|v| {
8326 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8327 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8328 DiagnosticEntry {
8329 range: start..end,
8330 diagnostic: v.diagnostic.clone(),
8331 }
8332 })
8333 .collect::<Vec<_>>();
8334
8335 self.as_local_mut()
8336 .context("cannot merge diagnostics on a remote LspStore")?
8337 .update_buffer_diagnostics(
8338 &buffer_handle,
8339 server_id,
8340 Some(update.registration_id),
8341 update.result_id,
8342 update.diagnostics.version,
8343 update.diagnostics.diagnostics.clone(),
8344 reused_diagnostics.clone(),
8345 cx,
8346 )?;
8347
8348 update.diagnostics.diagnostics.extend(reused_diagnostics);
8349 } else if let Some(local) = self.as_local() {
8350 let reused_diagnostics = local
8351 .diagnostics
8352 .get(&worktree_id)
8353 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8354 .and_then(|diagnostics_by_server_id| {
8355 diagnostics_by_server_id
8356 .binary_search_by_key(&server_id, |e| e.0)
8357 .ok()
8358 .map(|ix| &diagnostics_by_server_id[ix].1)
8359 })
8360 .into_iter()
8361 .flatten()
8362 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8363
8364 update
8365 .diagnostics
8366 .diagnostics
8367 .extend(reused_diagnostics.cloned());
8368 }
8369
8370 let updated = worktree.update(cx, |worktree, cx| {
8371 self.update_worktree_diagnostics(
8372 worktree.id(),
8373 server_id,
8374 project_path.path.clone(),
8375 update.diagnostics.diagnostics,
8376 cx,
8377 )
8378 })?;
8379 match updated {
8380 ControlFlow::Continue(new_summary) => {
8381 if let Some((project_id, new_summary)) = new_summary {
8382 match &mut diagnostics_summary {
8383 Some(diagnostics_summary) => {
8384 diagnostics_summary
8385 .more_summaries
8386 .push(proto::DiagnosticSummary {
8387 path: project_path.path.as_ref().to_proto(),
8388 language_server_id: server_id.0 as u64,
8389 error_count: new_summary.error_count,
8390 warning_count: new_summary.warning_count,
8391 })
8392 }
8393 None => {
8394 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8395 project_id,
8396 worktree_id: worktree_id.to_proto(),
8397 summary: Some(proto::DiagnosticSummary {
8398 path: project_path.path.as_ref().to_proto(),
8399 language_server_id: server_id.0 as u64,
8400 error_count: new_summary.error_count,
8401 warning_count: new_summary.warning_count,
8402 }),
8403 more_summaries: Vec::new(),
8404 })
8405 }
8406 }
8407 }
8408 updated_diagnostics_paths
8409 .entry(server_id)
8410 .or_insert_with(Vec::new)
8411 .push(project_path);
8412 }
8413 ControlFlow::Break(()) => {}
8414 }
8415 }
8416
8417 if let Some((diagnostics_summary, (downstream_client, _))) =
8418 diagnostics_summary.zip(self.downstream_client.as_ref())
8419 {
8420 downstream_client.send(diagnostics_summary).log_err();
8421 }
8422 for (server_id, paths) in updated_diagnostics_paths {
8423 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8424 }
8425 Ok(())
8426 }
8427
8428 fn update_worktree_diagnostics(
8429 &mut self,
8430 worktree_id: WorktreeId,
8431 server_id: LanguageServerId,
8432 path_in_worktree: Arc<RelPath>,
8433 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8434 _: &mut Context<Worktree>,
8435 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8436 let local = match &mut self.mode {
8437 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8438 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8439 };
8440
8441 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8442 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8443 let summaries_by_server_id = summaries_for_tree
8444 .entry(path_in_worktree.clone())
8445 .or_default();
8446
8447 let old_summary = summaries_by_server_id
8448 .remove(&server_id)
8449 .unwrap_or_default();
8450
8451 let new_summary = DiagnosticSummary::new(&diagnostics);
8452 if diagnostics.is_empty() {
8453 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8454 {
8455 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8456 diagnostics_by_server_id.remove(ix);
8457 }
8458 if diagnostics_by_server_id.is_empty() {
8459 diagnostics_for_tree.remove(&path_in_worktree);
8460 }
8461 }
8462 } else {
8463 summaries_by_server_id.insert(server_id, new_summary);
8464 let diagnostics_by_server_id = diagnostics_for_tree
8465 .entry(path_in_worktree.clone())
8466 .or_default();
8467 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8468 Ok(ix) => {
8469 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8470 }
8471 Err(ix) => {
8472 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8473 }
8474 }
8475 }
8476
8477 if !old_summary.is_empty() || !new_summary.is_empty() {
8478 if let Some((_, project_id)) = &self.downstream_client {
8479 Ok(ControlFlow::Continue(Some((
8480 *project_id,
8481 proto::DiagnosticSummary {
8482 path: path_in_worktree.to_proto(),
8483 language_server_id: server_id.0 as u64,
8484 error_count: new_summary.error_count as u32,
8485 warning_count: new_summary.warning_count as u32,
8486 },
8487 ))))
8488 } else {
8489 Ok(ControlFlow::Continue(None))
8490 }
8491 } else {
8492 Ok(ControlFlow::Break(()))
8493 }
8494 }
8495
8496 pub fn open_buffer_for_symbol(
8497 &mut self,
8498 symbol: &Symbol,
8499 cx: &mut Context<Self>,
8500 ) -> Task<Result<Entity<Buffer>>> {
8501 if let Some((client, project_id)) = self.upstream_client() {
8502 let request = client.request(proto::OpenBufferForSymbol {
8503 project_id,
8504 symbol: Some(Self::serialize_symbol(symbol)),
8505 });
8506 cx.spawn(async move |this, cx| {
8507 let response = request.await?;
8508 let buffer_id = BufferId::new(response.buffer_id)?;
8509 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8510 .await
8511 })
8512 } else if let Some(local) = self.as_local() {
8513 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8514 seed.worktree_id == symbol.source_worktree_id
8515 && state.id == symbol.source_language_server_id
8516 && symbol.language_server_name == seed.name
8517 });
8518 if !is_valid {
8519 return Task::ready(Err(anyhow!(
8520 "language server for worktree and language not found"
8521 )));
8522 };
8523
8524 let symbol_abs_path = match &symbol.path {
8525 SymbolLocation::InProject(project_path) => self
8526 .worktree_store
8527 .read(cx)
8528 .absolutize(&project_path, cx)
8529 .context("no such worktree"),
8530 SymbolLocation::OutsideProject {
8531 abs_path,
8532 signature: _,
8533 } => Ok(abs_path.to_path_buf()),
8534 };
8535 let symbol_abs_path = match symbol_abs_path {
8536 Ok(abs_path) => abs_path,
8537 Err(err) => return Task::ready(Err(err)),
8538 };
8539 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8540 uri
8541 } else {
8542 return Task::ready(Err(anyhow!("invalid symbol path")));
8543 };
8544
8545 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8546 } else {
8547 Task::ready(Err(anyhow!("no upstream client or local store")))
8548 }
8549 }
8550
8551 pub(crate) fn open_local_buffer_via_lsp(
8552 &mut self,
8553 abs_path: lsp::Uri,
8554 language_server_id: LanguageServerId,
8555 cx: &mut Context<Self>,
8556 ) -> Task<Result<Entity<Buffer>>> {
8557 cx.spawn(async move |lsp_store, cx| {
8558 // Escape percent-encoded string.
8559 let current_scheme = abs_path.scheme().to_owned();
8560 // Uri is immutable, so we can't modify the scheme
8561
8562 let abs_path = abs_path
8563 .to_file_path()
8564 .map_err(|()| anyhow!("can't convert URI to path"))?;
8565 let p = abs_path.clone();
8566 let yarn_worktree = lsp_store
8567 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8568 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8569 cx.spawn(async move |this, cx| {
8570 let t = this
8571 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8572 .ok()?;
8573 t.await
8574 })
8575 }),
8576 None => Task::ready(None),
8577 })?
8578 .await;
8579 let (worktree_root_target, known_relative_path) =
8580 if let Some((zip_root, relative_path)) = yarn_worktree {
8581 (zip_root, Some(relative_path))
8582 } else {
8583 (Arc::<Path>::from(abs_path.as_path()), None)
8584 };
8585 let (worktree, relative_path) = if let Some(result) =
8586 lsp_store.update(cx, |lsp_store, cx| {
8587 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8588 worktree_store.find_worktree(&worktree_root_target, cx)
8589 })
8590 })? {
8591 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8592 (result.0, relative_path)
8593 } else {
8594 let worktree = lsp_store
8595 .update(cx, |lsp_store, cx| {
8596 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8597 worktree_store.create_worktree(&worktree_root_target, false, cx)
8598 })
8599 })?
8600 .await?;
8601 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8602 lsp_store
8603 .update(cx, |lsp_store, cx| {
8604 if let Some(local) = lsp_store.as_local_mut() {
8605 local.register_language_server_for_invisible_worktree(
8606 &worktree,
8607 language_server_id,
8608 cx,
8609 )
8610 }
8611 })
8612 .ok();
8613 }
8614 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8615 let relative_path = if let Some(known_path) = known_relative_path {
8616 known_path
8617 } else {
8618 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8619 .into_arc()
8620 };
8621 (worktree, relative_path)
8622 };
8623 let project_path = ProjectPath {
8624 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8625 path: relative_path,
8626 };
8627 lsp_store
8628 .update(cx, |lsp_store, cx| {
8629 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8630 buffer_store.open_buffer(project_path, cx)
8631 })
8632 })?
8633 .await
8634 })
8635 }
8636
8637 fn request_multiple_lsp_locally<P, R>(
8638 &mut self,
8639 buffer: &Entity<Buffer>,
8640 position: Option<P>,
8641 request: R,
8642 cx: &mut Context<Self>,
8643 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8644 where
8645 P: ToOffset,
8646 R: LspCommand + Clone,
8647 <R::LspRequest as lsp::request::Request>::Result: Send,
8648 <R::LspRequest as lsp::request::Request>::Params: Send,
8649 {
8650 let Some(local) = self.as_local() else {
8651 return Task::ready(Vec::new());
8652 };
8653
8654 let snapshot = buffer.read(cx).snapshot();
8655 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8656
8657 let server_ids = buffer.update(cx, |buffer, cx| {
8658 local
8659 .language_servers_for_buffer(buffer, cx)
8660 .filter(|(adapter, _)| {
8661 scope
8662 .as_ref()
8663 .map(|scope| scope.language_allowed(&adapter.name))
8664 .unwrap_or(true)
8665 })
8666 .map(|(_, server)| server.server_id())
8667 .filter(|server_id| {
8668 self.as_local().is_none_or(|local| {
8669 local
8670 .buffers_opened_in_servers
8671 .get(&snapshot.remote_id())
8672 .is_some_and(|servers| servers.contains(server_id))
8673 })
8674 })
8675 .collect::<Vec<_>>()
8676 });
8677
8678 let mut response_results = server_ids
8679 .into_iter()
8680 .map(|server_id| {
8681 let task = self.request_lsp(
8682 buffer.clone(),
8683 LanguageServerToQuery::Other(server_id),
8684 request.clone(),
8685 cx,
8686 );
8687 async move { (server_id, task.await) }
8688 })
8689 .collect::<FuturesUnordered<_>>();
8690
8691 cx.background_spawn(async move {
8692 let mut responses = Vec::with_capacity(response_results.len());
8693 while let Some((server_id, response_result)) = response_results.next().await {
8694 match response_result {
8695 Ok(response) => responses.push((server_id, response)),
8696 // rust-analyzer likes to error with this when its still loading up
8697 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8698 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8699 }
8700 }
8701 responses
8702 })
8703 }
8704
8705 async fn handle_lsp_get_completions(
8706 this: Entity<Self>,
8707 envelope: TypedEnvelope<proto::GetCompletions>,
8708 mut cx: AsyncApp,
8709 ) -> Result<proto::GetCompletionsResponse> {
8710 let sender_id = envelope.original_sender_id().unwrap_or_default();
8711
8712 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8713 let buffer_handle = this.update(&mut cx, |this, cx| {
8714 this.buffer_store.read(cx).get_existing(buffer_id)
8715 })??;
8716 let request = GetCompletions::from_proto(
8717 envelope.payload,
8718 this.clone(),
8719 buffer_handle.clone(),
8720 cx.clone(),
8721 )
8722 .await?;
8723
8724 let server_to_query = match request.server_id {
8725 Some(server_id) => LanguageServerToQuery::Other(server_id),
8726 None => LanguageServerToQuery::FirstCapable,
8727 };
8728
8729 let response = this
8730 .update(&mut cx, |this, cx| {
8731 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8732 })?
8733 .await?;
8734 this.update(&mut cx, |this, cx| {
8735 Ok(GetCompletions::response_to_proto(
8736 response,
8737 this,
8738 sender_id,
8739 &buffer_handle.read(cx).version(),
8740 cx,
8741 ))
8742 })?
8743 }
8744
8745 async fn handle_lsp_command<T: LspCommand>(
8746 this: Entity<Self>,
8747 envelope: TypedEnvelope<T::ProtoRequest>,
8748 mut cx: AsyncApp,
8749 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8750 where
8751 <T::LspRequest as lsp::request::Request>::Params: Send,
8752 <T::LspRequest as lsp::request::Request>::Result: Send,
8753 {
8754 let sender_id = envelope.original_sender_id().unwrap_or_default();
8755 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8756 let buffer_handle = this.update(&mut cx, |this, cx| {
8757 this.buffer_store.read(cx).get_existing(buffer_id)
8758 })??;
8759 let request = T::from_proto(
8760 envelope.payload,
8761 this.clone(),
8762 buffer_handle.clone(),
8763 cx.clone(),
8764 )
8765 .await?;
8766 let response = this
8767 .update(&mut cx, |this, cx| {
8768 this.request_lsp(
8769 buffer_handle.clone(),
8770 LanguageServerToQuery::FirstCapable,
8771 request,
8772 cx,
8773 )
8774 })?
8775 .await?;
8776 this.update(&mut cx, |this, cx| {
8777 Ok(T::response_to_proto(
8778 response,
8779 this,
8780 sender_id,
8781 &buffer_handle.read(cx).version(),
8782 cx,
8783 ))
8784 })?
8785 }
8786
8787 async fn handle_lsp_query(
8788 lsp_store: Entity<Self>,
8789 envelope: TypedEnvelope<proto::LspQuery>,
8790 mut cx: AsyncApp,
8791 ) -> Result<proto::Ack> {
8792 use proto::lsp_query::Request;
8793 let sender_id = envelope.original_sender_id().unwrap_or_default();
8794 let lsp_query = envelope.payload;
8795 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8796 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8797 match lsp_query.request.context("invalid LSP query request")? {
8798 Request::GetReferences(get_references) => {
8799 let position = get_references.position.clone().and_then(deserialize_anchor);
8800 Self::query_lsp_locally::<GetReferences>(
8801 lsp_store,
8802 server_id,
8803 sender_id,
8804 lsp_request_id,
8805 get_references,
8806 position,
8807 &mut cx,
8808 )
8809 .await?;
8810 }
8811 Request::GetDocumentColor(get_document_color) => {
8812 Self::query_lsp_locally::<GetDocumentColor>(
8813 lsp_store,
8814 server_id,
8815 sender_id,
8816 lsp_request_id,
8817 get_document_color,
8818 None,
8819 &mut cx,
8820 )
8821 .await?;
8822 }
8823 Request::GetHover(get_hover) => {
8824 let position = get_hover.position.clone().and_then(deserialize_anchor);
8825 Self::query_lsp_locally::<GetHover>(
8826 lsp_store,
8827 server_id,
8828 sender_id,
8829 lsp_request_id,
8830 get_hover,
8831 position,
8832 &mut cx,
8833 )
8834 .await?;
8835 }
8836 Request::GetCodeActions(get_code_actions) => {
8837 Self::query_lsp_locally::<GetCodeActions>(
8838 lsp_store,
8839 server_id,
8840 sender_id,
8841 lsp_request_id,
8842 get_code_actions,
8843 None,
8844 &mut cx,
8845 )
8846 .await?;
8847 }
8848 Request::GetSignatureHelp(get_signature_help) => {
8849 let position = get_signature_help
8850 .position
8851 .clone()
8852 .and_then(deserialize_anchor);
8853 Self::query_lsp_locally::<GetSignatureHelp>(
8854 lsp_store,
8855 server_id,
8856 sender_id,
8857 lsp_request_id,
8858 get_signature_help,
8859 position,
8860 &mut cx,
8861 )
8862 .await?;
8863 }
8864 Request::GetCodeLens(get_code_lens) => {
8865 Self::query_lsp_locally::<GetCodeLens>(
8866 lsp_store,
8867 server_id,
8868 sender_id,
8869 lsp_request_id,
8870 get_code_lens,
8871 None,
8872 &mut cx,
8873 )
8874 .await?;
8875 }
8876 Request::GetDefinition(get_definition) => {
8877 let position = get_definition.position.clone().and_then(deserialize_anchor);
8878 Self::query_lsp_locally::<GetDefinitions>(
8879 lsp_store,
8880 server_id,
8881 sender_id,
8882 lsp_request_id,
8883 get_definition,
8884 position,
8885 &mut cx,
8886 )
8887 .await?;
8888 }
8889 Request::GetDeclaration(get_declaration) => {
8890 let position = get_declaration
8891 .position
8892 .clone()
8893 .and_then(deserialize_anchor);
8894 Self::query_lsp_locally::<GetDeclarations>(
8895 lsp_store,
8896 server_id,
8897 sender_id,
8898 lsp_request_id,
8899 get_declaration,
8900 position,
8901 &mut cx,
8902 )
8903 .await?;
8904 }
8905 Request::GetTypeDefinition(get_type_definition) => {
8906 let position = get_type_definition
8907 .position
8908 .clone()
8909 .and_then(deserialize_anchor);
8910 Self::query_lsp_locally::<GetTypeDefinitions>(
8911 lsp_store,
8912 server_id,
8913 sender_id,
8914 lsp_request_id,
8915 get_type_definition,
8916 position,
8917 &mut cx,
8918 )
8919 .await?;
8920 }
8921 Request::GetImplementation(get_implementation) => {
8922 let position = get_implementation
8923 .position
8924 .clone()
8925 .and_then(deserialize_anchor);
8926 Self::query_lsp_locally::<GetImplementations>(
8927 lsp_store,
8928 server_id,
8929 sender_id,
8930 lsp_request_id,
8931 get_implementation,
8932 position,
8933 &mut cx,
8934 )
8935 .await?;
8936 }
8937 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8938 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8939 let version = deserialize_version(get_document_diagnostics.buffer_version());
8940 let buffer = lsp_store.update(&mut cx, |this, cx| {
8941 this.buffer_store.read(cx).get_existing(buffer_id)
8942 })??;
8943 buffer
8944 .update(&mut cx, |buffer, _| {
8945 buffer.wait_for_version(version.clone())
8946 })?
8947 .await?;
8948 lsp_store.update(&mut cx, |lsp_store, cx| {
8949 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8950 let key = LspKey {
8951 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8952 server_queried: server_id,
8953 };
8954 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8955 ) {
8956 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8957 lsp_requests.clear();
8958 };
8959 }
8960
8961 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8962 existing_queries.insert(
8963 lsp_request_id,
8964 cx.spawn(async move |lsp_store, cx| {
8965 let diagnostics_pull = lsp_store
8966 .update(cx, |lsp_store, cx| {
8967 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8968 })
8969 .ok();
8970 if let Some(diagnostics_pull) = diagnostics_pull {
8971 match diagnostics_pull.await {
8972 Ok(()) => {}
8973 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8974 };
8975 }
8976 }),
8977 );
8978 })?;
8979 }
8980 Request::InlayHints(inlay_hints) => {
8981 let query_start = inlay_hints
8982 .start
8983 .clone()
8984 .and_then(deserialize_anchor)
8985 .context("invalid inlay hints range start")?;
8986 let query_end = inlay_hints
8987 .end
8988 .clone()
8989 .and_then(deserialize_anchor)
8990 .context("invalid inlay hints range end")?;
8991 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8992 &lsp_store,
8993 server_id,
8994 lsp_request_id,
8995 &inlay_hints,
8996 query_start..query_end,
8997 &mut cx,
8998 )
8999 .await
9000 .context("preparing inlay hints request")?;
9001 Self::query_lsp_locally::<InlayHints>(
9002 lsp_store,
9003 server_id,
9004 sender_id,
9005 lsp_request_id,
9006 inlay_hints,
9007 None,
9008 &mut cx,
9009 )
9010 .await
9011 .context("querying for inlay hints")?
9012 }
9013 }
9014 Ok(proto::Ack {})
9015 }
9016
9017 async fn handle_lsp_query_response(
9018 lsp_store: Entity<Self>,
9019 envelope: TypedEnvelope<proto::LspQueryResponse>,
9020 cx: AsyncApp,
9021 ) -> Result<()> {
9022 lsp_store.read_with(&cx, |lsp_store, _| {
9023 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9024 upstream_client.handle_lsp_response(envelope.clone());
9025 }
9026 })?;
9027 Ok(())
9028 }
9029
9030 async fn handle_apply_code_action(
9031 this: Entity<Self>,
9032 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9033 mut cx: AsyncApp,
9034 ) -> Result<proto::ApplyCodeActionResponse> {
9035 let sender_id = envelope.original_sender_id().unwrap_or_default();
9036 let action =
9037 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9038 let apply_code_action = this.update(&mut cx, |this, cx| {
9039 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9040 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9041 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9042 })??;
9043
9044 let project_transaction = apply_code_action.await?;
9045 let project_transaction = this.update(&mut cx, |this, cx| {
9046 this.buffer_store.update(cx, |buffer_store, cx| {
9047 buffer_store.serialize_project_transaction_for_peer(
9048 project_transaction,
9049 sender_id,
9050 cx,
9051 )
9052 })
9053 })?;
9054 Ok(proto::ApplyCodeActionResponse {
9055 transaction: Some(project_transaction),
9056 })
9057 }
9058
9059 async fn handle_register_buffer_with_language_servers(
9060 this: Entity<Self>,
9061 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9062 mut cx: AsyncApp,
9063 ) -> Result<proto::Ack> {
9064 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9065 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9066 this.update(&mut cx, |this, cx| {
9067 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9068 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9069 project_id: upstream_project_id,
9070 buffer_id: buffer_id.to_proto(),
9071 only_servers: envelope.payload.only_servers,
9072 });
9073 }
9074
9075 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9076 anyhow::bail!("buffer is not open");
9077 };
9078
9079 let handle = this.register_buffer_with_language_servers(
9080 &buffer,
9081 envelope
9082 .payload
9083 .only_servers
9084 .into_iter()
9085 .filter_map(|selector| {
9086 Some(match selector.selector? {
9087 proto::language_server_selector::Selector::ServerId(server_id) => {
9088 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9089 }
9090 proto::language_server_selector::Selector::Name(name) => {
9091 LanguageServerSelector::Name(LanguageServerName(
9092 SharedString::from(name),
9093 ))
9094 }
9095 })
9096 })
9097 .collect(),
9098 false,
9099 cx,
9100 );
9101 this.buffer_store().update(cx, |buffer_store, _| {
9102 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9103 });
9104
9105 Ok(())
9106 })??;
9107 Ok(proto::Ack {})
9108 }
9109
9110 async fn handle_rename_project_entry(
9111 this: Entity<Self>,
9112 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9113 mut cx: AsyncApp,
9114 ) -> Result<proto::ProjectEntryResponse> {
9115 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9116 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9117 let new_path =
9118 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9119
9120 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9121 .update(&mut cx, |this, cx| {
9122 let (worktree, entry) = this
9123 .worktree_store
9124 .read(cx)
9125 .worktree_and_entry_for_id(entry_id, cx)?;
9126 let new_worktree = this
9127 .worktree_store
9128 .read(cx)
9129 .worktree_for_id(new_worktree_id, cx)?;
9130 Some((
9131 this.worktree_store.clone(),
9132 worktree,
9133 new_worktree,
9134 entry.clone(),
9135 ))
9136 })?
9137 .context("worktree not found")?;
9138 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9139 (worktree.absolutize(&old_entry.path), worktree.id())
9140 })?;
9141 let new_abs_path =
9142 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9143
9144 let _transaction = Self::will_rename_entry(
9145 this.downgrade(),
9146 old_worktree_id,
9147 &old_abs_path,
9148 &new_abs_path,
9149 old_entry.is_dir(),
9150 cx.clone(),
9151 )
9152 .await;
9153 let response = WorktreeStore::handle_rename_project_entry(
9154 worktree_store,
9155 envelope.payload,
9156 cx.clone(),
9157 )
9158 .await;
9159 this.read_with(&cx, |this, _| {
9160 this.did_rename_entry(
9161 old_worktree_id,
9162 &old_abs_path,
9163 &new_abs_path,
9164 old_entry.is_dir(),
9165 );
9166 })
9167 .ok();
9168 response
9169 }
9170
9171 async fn handle_update_diagnostic_summary(
9172 this: Entity<Self>,
9173 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9174 mut cx: AsyncApp,
9175 ) -> Result<()> {
9176 this.update(&mut cx, |lsp_store, cx| {
9177 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9178 let mut updated_diagnostics_paths = HashMap::default();
9179 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9180 for message_summary in envelope
9181 .payload
9182 .summary
9183 .into_iter()
9184 .chain(envelope.payload.more_summaries)
9185 {
9186 let project_path = ProjectPath {
9187 worktree_id,
9188 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9189 };
9190 let path = project_path.path.clone();
9191 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9192 let summary = DiagnosticSummary {
9193 error_count: message_summary.error_count as usize,
9194 warning_count: message_summary.warning_count as usize,
9195 };
9196
9197 if summary.is_empty() {
9198 if let Some(worktree_summaries) =
9199 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9200 && let Some(summaries) = worktree_summaries.get_mut(&path)
9201 {
9202 summaries.remove(&server_id);
9203 if summaries.is_empty() {
9204 worktree_summaries.remove(&path);
9205 }
9206 }
9207 } else {
9208 lsp_store
9209 .diagnostic_summaries
9210 .entry(worktree_id)
9211 .or_default()
9212 .entry(path)
9213 .or_default()
9214 .insert(server_id, summary);
9215 }
9216
9217 if let Some((_, project_id)) = &lsp_store.downstream_client {
9218 match &mut diagnostics_summary {
9219 Some(diagnostics_summary) => {
9220 diagnostics_summary
9221 .more_summaries
9222 .push(proto::DiagnosticSummary {
9223 path: project_path.path.as_ref().to_proto(),
9224 language_server_id: server_id.0 as u64,
9225 error_count: summary.error_count as u32,
9226 warning_count: summary.warning_count as u32,
9227 })
9228 }
9229 None => {
9230 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9231 project_id: *project_id,
9232 worktree_id: worktree_id.to_proto(),
9233 summary: Some(proto::DiagnosticSummary {
9234 path: project_path.path.as_ref().to_proto(),
9235 language_server_id: server_id.0 as u64,
9236 error_count: summary.error_count as u32,
9237 warning_count: summary.warning_count as u32,
9238 }),
9239 more_summaries: Vec::new(),
9240 })
9241 }
9242 }
9243 }
9244 updated_diagnostics_paths
9245 .entry(server_id)
9246 .or_insert_with(Vec::new)
9247 .push(project_path);
9248 }
9249
9250 if let Some((diagnostics_summary, (downstream_client, _))) =
9251 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9252 {
9253 downstream_client.send(diagnostics_summary).log_err();
9254 }
9255 for (server_id, paths) in updated_diagnostics_paths {
9256 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9257 }
9258 Ok(())
9259 })?
9260 }
9261
9262 async fn handle_start_language_server(
9263 lsp_store: Entity<Self>,
9264 envelope: TypedEnvelope<proto::StartLanguageServer>,
9265 mut cx: AsyncApp,
9266 ) -> Result<()> {
9267 let server = envelope.payload.server.context("invalid server")?;
9268 let server_capabilities =
9269 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9270 .with_context(|| {
9271 format!(
9272 "incorrect server capabilities {}",
9273 envelope.payload.capabilities
9274 )
9275 })?;
9276 lsp_store.update(&mut cx, |lsp_store, cx| {
9277 let server_id = LanguageServerId(server.id as usize);
9278 let server_name = LanguageServerName::from_proto(server.name.clone());
9279 lsp_store
9280 .lsp_server_capabilities
9281 .insert(server_id, server_capabilities);
9282 lsp_store.language_server_statuses.insert(
9283 server_id,
9284 LanguageServerStatus {
9285 name: server_name.clone(),
9286 pending_work: Default::default(),
9287 has_pending_diagnostic_updates: false,
9288 progress_tokens: Default::default(),
9289 worktree: server.worktree_id.map(WorktreeId::from_proto),
9290 binary: None,
9291 configuration: None,
9292 workspace_folders: BTreeSet::new(),
9293 },
9294 );
9295 cx.emit(LspStoreEvent::LanguageServerAdded(
9296 server_id,
9297 server_name,
9298 server.worktree_id.map(WorktreeId::from_proto),
9299 ));
9300 cx.notify();
9301 })?;
9302 Ok(())
9303 }
9304
9305 async fn handle_update_language_server(
9306 lsp_store: Entity<Self>,
9307 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9308 mut cx: AsyncApp,
9309 ) -> Result<()> {
9310 lsp_store.update(&mut cx, |lsp_store, cx| {
9311 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9312
9313 match envelope.payload.variant.context("invalid variant")? {
9314 proto::update_language_server::Variant::WorkStart(payload) => {
9315 lsp_store.on_lsp_work_start(
9316 language_server_id,
9317 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9318 .context("invalid progress token value")?,
9319 LanguageServerProgress {
9320 title: payload.title,
9321 is_disk_based_diagnostics_progress: false,
9322 is_cancellable: payload.is_cancellable.unwrap_or(false),
9323 message: payload.message,
9324 percentage: payload.percentage.map(|p| p as usize),
9325 last_update_at: cx.background_executor().now(),
9326 },
9327 cx,
9328 );
9329 }
9330 proto::update_language_server::Variant::WorkProgress(payload) => {
9331 lsp_store.on_lsp_work_progress(
9332 language_server_id,
9333 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9334 .context("invalid progress token value")?,
9335 LanguageServerProgress {
9336 title: None,
9337 is_disk_based_diagnostics_progress: false,
9338 is_cancellable: payload.is_cancellable.unwrap_or(false),
9339 message: payload.message,
9340 percentage: payload.percentage.map(|p| p as usize),
9341 last_update_at: cx.background_executor().now(),
9342 },
9343 cx,
9344 );
9345 }
9346
9347 proto::update_language_server::Variant::WorkEnd(payload) => {
9348 lsp_store.on_lsp_work_end(
9349 language_server_id,
9350 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9351 .context("invalid progress token value")?,
9352 cx,
9353 );
9354 }
9355
9356 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9357 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9358 }
9359
9360 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9361 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9362 }
9363
9364 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9365 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9366 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9367 cx.emit(LspStoreEvent::LanguageServerUpdate {
9368 language_server_id,
9369 name: envelope
9370 .payload
9371 .server_name
9372 .map(SharedString::new)
9373 .map(LanguageServerName),
9374 message: non_lsp,
9375 });
9376 }
9377 }
9378
9379 Ok(())
9380 })?
9381 }
9382
9383 async fn handle_language_server_log(
9384 this: Entity<Self>,
9385 envelope: TypedEnvelope<proto::LanguageServerLog>,
9386 mut cx: AsyncApp,
9387 ) -> Result<()> {
9388 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9389 let log_type = envelope
9390 .payload
9391 .log_type
9392 .map(LanguageServerLogType::from_proto)
9393 .context("invalid language server log type")?;
9394
9395 let message = envelope.payload.message;
9396
9397 this.update(&mut cx, |_, cx| {
9398 cx.emit(LspStoreEvent::LanguageServerLog(
9399 language_server_id,
9400 log_type,
9401 message,
9402 ));
9403 })
9404 }
9405
9406 async fn handle_lsp_ext_cancel_flycheck(
9407 lsp_store: Entity<Self>,
9408 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9409 cx: AsyncApp,
9410 ) -> Result<proto::Ack> {
9411 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9412 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9413 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9414 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9415 } else {
9416 None
9417 }
9418 })?;
9419 if let Some(task) = task {
9420 task.context("handling lsp ext cancel flycheck")?;
9421 }
9422
9423 Ok(proto::Ack {})
9424 }
9425
9426 async fn handle_lsp_ext_run_flycheck(
9427 lsp_store: Entity<Self>,
9428 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9429 mut cx: AsyncApp,
9430 ) -> Result<proto::Ack> {
9431 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9432 lsp_store.update(&mut cx, |lsp_store, cx| {
9433 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9434 let text_document = if envelope.payload.current_file_only {
9435 let buffer_id = envelope
9436 .payload
9437 .buffer_id
9438 .map(|id| BufferId::new(id))
9439 .transpose()?;
9440 buffer_id
9441 .and_then(|buffer_id| {
9442 lsp_store
9443 .buffer_store()
9444 .read(cx)
9445 .get(buffer_id)
9446 .and_then(|buffer| {
9447 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9448 })
9449 .map(|path| make_text_document_identifier(&path))
9450 })
9451 .transpose()?
9452 } else {
9453 None
9454 };
9455 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9456 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9457 )?;
9458 }
9459 anyhow::Ok(())
9460 })??;
9461
9462 Ok(proto::Ack {})
9463 }
9464
9465 async fn handle_lsp_ext_clear_flycheck(
9466 lsp_store: Entity<Self>,
9467 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9468 cx: AsyncApp,
9469 ) -> Result<proto::Ack> {
9470 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9471 lsp_store
9472 .read_with(&cx, |lsp_store, _| {
9473 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9474 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9475 } else {
9476 None
9477 }
9478 })
9479 .context("handling lsp ext clear flycheck")?;
9480
9481 Ok(proto::Ack {})
9482 }
9483
9484 pub fn disk_based_diagnostics_started(
9485 &mut self,
9486 language_server_id: LanguageServerId,
9487 cx: &mut Context<Self>,
9488 ) {
9489 if let Some(language_server_status) =
9490 self.language_server_statuses.get_mut(&language_server_id)
9491 {
9492 language_server_status.has_pending_diagnostic_updates = true;
9493 }
9494
9495 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9496 cx.emit(LspStoreEvent::LanguageServerUpdate {
9497 language_server_id,
9498 name: self
9499 .language_server_adapter_for_id(language_server_id)
9500 .map(|adapter| adapter.name()),
9501 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9502 Default::default(),
9503 ),
9504 })
9505 }
9506
9507 pub fn disk_based_diagnostics_finished(
9508 &mut self,
9509 language_server_id: LanguageServerId,
9510 cx: &mut Context<Self>,
9511 ) {
9512 if let Some(language_server_status) =
9513 self.language_server_statuses.get_mut(&language_server_id)
9514 {
9515 language_server_status.has_pending_diagnostic_updates = false;
9516 }
9517
9518 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9519 cx.emit(LspStoreEvent::LanguageServerUpdate {
9520 language_server_id,
9521 name: self
9522 .language_server_adapter_for_id(language_server_id)
9523 .map(|adapter| adapter.name()),
9524 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9525 Default::default(),
9526 ),
9527 })
9528 }
9529
9530 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9531 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9532 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9533 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9534 // the language server might take some time to publish diagnostics.
9535 fn simulate_disk_based_diagnostics_events_if_needed(
9536 &mut self,
9537 language_server_id: LanguageServerId,
9538 cx: &mut Context<Self>,
9539 ) {
9540 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9541
9542 let Some(LanguageServerState::Running {
9543 simulate_disk_based_diagnostics_completion,
9544 adapter,
9545 ..
9546 }) = self
9547 .as_local_mut()
9548 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9549 else {
9550 return;
9551 };
9552
9553 if adapter.disk_based_diagnostics_progress_token.is_some() {
9554 return;
9555 }
9556
9557 let prev_task =
9558 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9559 cx.background_executor()
9560 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9561 .await;
9562
9563 this.update(cx, |this, cx| {
9564 this.disk_based_diagnostics_finished(language_server_id, cx);
9565
9566 if let Some(LanguageServerState::Running {
9567 simulate_disk_based_diagnostics_completion,
9568 ..
9569 }) = this.as_local_mut().and_then(|local_store| {
9570 local_store.language_servers.get_mut(&language_server_id)
9571 }) {
9572 *simulate_disk_based_diagnostics_completion = None;
9573 }
9574 })
9575 .ok();
9576 }));
9577
9578 if prev_task.is_none() {
9579 self.disk_based_diagnostics_started(language_server_id, cx);
9580 }
9581 }
9582
9583 pub fn language_server_statuses(
9584 &self,
9585 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9586 self.language_server_statuses
9587 .iter()
9588 .map(|(key, value)| (*key, value))
9589 }
9590
9591 pub(super) fn did_rename_entry(
9592 &self,
9593 worktree_id: WorktreeId,
9594 old_path: &Path,
9595 new_path: &Path,
9596 is_dir: bool,
9597 ) {
9598 maybe!({
9599 let local_store = self.as_local()?;
9600
9601 let old_uri = lsp::Uri::from_file_path(old_path)
9602 .ok()
9603 .map(|uri| uri.to_string())?;
9604 let new_uri = lsp::Uri::from_file_path(new_path)
9605 .ok()
9606 .map(|uri| uri.to_string())?;
9607
9608 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9609 let Some(filter) = local_store
9610 .language_server_paths_watched_for_rename
9611 .get(&language_server.server_id())
9612 else {
9613 continue;
9614 };
9615
9616 if filter.should_send_did_rename(&old_uri, is_dir) {
9617 language_server
9618 .notify::<DidRenameFiles>(RenameFilesParams {
9619 files: vec![FileRename {
9620 old_uri: old_uri.clone(),
9621 new_uri: new_uri.clone(),
9622 }],
9623 })
9624 .ok();
9625 }
9626 }
9627 Some(())
9628 });
9629 }
9630
9631 pub(super) fn will_rename_entry(
9632 this: WeakEntity<Self>,
9633 worktree_id: WorktreeId,
9634 old_path: &Path,
9635 new_path: &Path,
9636 is_dir: bool,
9637 cx: AsyncApp,
9638 ) -> Task<ProjectTransaction> {
9639 let old_uri = lsp::Uri::from_file_path(old_path)
9640 .ok()
9641 .map(|uri| uri.to_string());
9642 let new_uri = lsp::Uri::from_file_path(new_path)
9643 .ok()
9644 .map(|uri| uri.to_string());
9645 cx.spawn(async move |cx| {
9646 let mut tasks = vec![];
9647 this.update(cx, |this, cx| {
9648 let local_store = this.as_local()?;
9649 let old_uri = old_uri?;
9650 let new_uri = new_uri?;
9651 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9652 let Some(filter) = local_store
9653 .language_server_paths_watched_for_rename
9654 .get(&language_server.server_id())
9655 else {
9656 continue;
9657 };
9658
9659 if filter.should_send_will_rename(&old_uri, is_dir) {
9660 let apply_edit = cx.spawn({
9661 let old_uri = old_uri.clone();
9662 let new_uri = new_uri.clone();
9663 let language_server = language_server.clone();
9664 async move |this, cx| {
9665 let edit = language_server
9666 .request::<WillRenameFiles>(RenameFilesParams {
9667 files: vec![FileRename { old_uri, new_uri }],
9668 })
9669 .await
9670 .into_response()
9671 .context("will rename files")
9672 .log_err()
9673 .flatten()?;
9674
9675 let transaction = LocalLspStore::deserialize_workspace_edit(
9676 this.upgrade()?,
9677 edit,
9678 false,
9679 language_server.clone(),
9680 cx,
9681 )
9682 .await
9683 .ok()?;
9684 Some(transaction)
9685 }
9686 });
9687 tasks.push(apply_edit);
9688 }
9689 }
9690 Some(())
9691 })
9692 .ok()
9693 .flatten();
9694 let mut merged_transaction = ProjectTransaction::default();
9695 for task in tasks {
9696 // Await on tasks sequentially so that the order of application of edits is deterministic
9697 // (at least with regards to the order of registration of language servers)
9698 if let Some(transaction) = task.await {
9699 for (buffer, buffer_transaction) in transaction.0 {
9700 merged_transaction.0.insert(buffer, buffer_transaction);
9701 }
9702 }
9703 }
9704 merged_transaction
9705 })
9706 }
9707
9708 fn lsp_notify_abs_paths_changed(
9709 &mut self,
9710 server_id: LanguageServerId,
9711 changes: Vec<PathEvent>,
9712 ) {
9713 maybe!({
9714 let server = self.language_server_for_id(server_id)?;
9715 let changes = changes
9716 .into_iter()
9717 .filter_map(|event| {
9718 let typ = match event.kind? {
9719 PathEventKind::Created => lsp::FileChangeType::CREATED,
9720 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9721 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9722 };
9723 Some(lsp::FileEvent {
9724 uri: file_path_to_lsp_url(&event.path).log_err()?,
9725 typ,
9726 })
9727 })
9728 .collect::<Vec<_>>();
9729 if !changes.is_empty() {
9730 server
9731 .notify::<lsp::notification::DidChangeWatchedFiles>(
9732 lsp::DidChangeWatchedFilesParams { changes },
9733 )
9734 .ok();
9735 }
9736 Some(())
9737 });
9738 }
9739
9740 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9741 self.as_local()?.language_server_for_id(id)
9742 }
9743
9744 fn on_lsp_progress(
9745 &mut self,
9746 progress_params: lsp::ProgressParams,
9747 language_server_id: LanguageServerId,
9748 disk_based_diagnostics_progress_token: Option<String>,
9749 cx: &mut Context<Self>,
9750 ) {
9751 match progress_params.value {
9752 lsp::ProgressParamsValue::WorkDone(progress) => {
9753 self.handle_work_done_progress(
9754 progress,
9755 language_server_id,
9756 disk_based_diagnostics_progress_token,
9757 ProgressToken::from_lsp(progress_params.token),
9758 cx,
9759 );
9760 }
9761 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9762 let registration_id = match progress_params.token {
9763 lsp::NumberOrString::Number(_) => None,
9764 lsp::NumberOrString::String(token) => token
9765 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9766 .map(|(_, id)| id.to_owned()),
9767 };
9768 if let Some(LanguageServerState::Running {
9769 workspace_diagnostics_refresh_tasks,
9770 ..
9771 }) = self
9772 .as_local_mut()
9773 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9774 && let Some(workspace_diagnostics) =
9775 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9776 {
9777 workspace_diagnostics.progress_tx.try_send(()).ok();
9778 self.apply_workspace_diagnostic_report(
9779 language_server_id,
9780 report,
9781 registration_id.map(SharedString::from),
9782 cx,
9783 )
9784 }
9785 }
9786 }
9787 }
9788
9789 fn handle_work_done_progress(
9790 &mut self,
9791 progress: lsp::WorkDoneProgress,
9792 language_server_id: LanguageServerId,
9793 disk_based_diagnostics_progress_token: Option<String>,
9794 token: ProgressToken,
9795 cx: &mut Context<Self>,
9796 ) {
9797 let language_server_status =
9798 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9799 status
9800 } else {
9801 return;
9802 };
9803
9804 if !language_server_status.progress_tokens.contains(&token) {
9805 return;
9806 }
9807
9808 let is_disk_based_diagnostics_progress =
9809 if let (Some(disk_based_token), ProgressToken::String(token)) =
9810 (&disk_based_diagnostics_progress_token, &token)
9811 {
9812 token.starts_with(disk_based_token)
9813 } else {
9814 false
9815 };
9816
9817 match progress {
9818 lsp::WorkDoneProgress::Begin(report) => {
9819 if is_disk_based_diagnostics_progress {
9820 self.disk_based_diagnostics_started(language_server_id, cx);
9821 }
9822 self.on_lsp_work_start(
9823 language_server_id,
9824 token.clone(),
9825 LanguageServerProgress {
9826 title: Some(report.title),
9827 is_disk_based_diagnostics_progress,
9828 is_cancellable: report.cancellable.unwrap_or(false),
9829 message: report.message.clone(),
9830 percentage: report.percentage.map(|p| p as usize),
9831 last_update_at: cx.background_executor().now(),
9832 },
9833 cx,
9834 );
9835 }
9836 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9837 language_server_id,
9838 token,
9839 LanguageServerProgress {
9840 title: None,
9841 is_disk_based_diagnostics_progress,
9842 is_cancellable: report.cancellable.unwrap_or(false),
9843 message: report.message,
9844 percentage: report.percentage.map(|p| p as usize),
9845 last_update_at: cx.background_executor().now(),
9846 },
9847 cx,
9848 ),
9849 lsp::WorkDoneProgress::End(_) => {
9850 language_server_status.progress_tokens.remove(&token);
9851 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9852 if is_disk_based_diagnostics_progress {
9853 self.disk_based_diagnostics_finished(language_server_id, cx);
9854 }
9855 }
9856 }
9857 }
9858
9859 fn on_lsp_work_start(
9860 &mut self,
9861 language_server_id: LanguageServerId,
9862 token: ProgressToken,
9863 progress: LanguageServerProgress,
9864 cx: &mut Context<Self>,
9865 ) {
9866 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9867 status.pending_work.insert(token.clone(), progress.clone());
9868 cx.notify();
9869 }
9870 cx.emit(LspStoreEvent::LanguageServerUpdate {
9871 language_server_id,
9872 name: self
9873 .language_server_adapter_for_id(language_server_id)
9874 .map(|adapter| adapter.name()),
9875 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9876 token: Some(token.to_proto()),
9877 title: progress.title,
9878 message: progress.message,
9879 percentage: progress.percentage.map(|p| p as u32),
9880 is_cancellable: Some(progress.is_cancellable),
9881 }),
9882 })
9883 }
9884
9885 fn on_lsp_work_progress(
9886 &mut self,
9887 language_server_id: LanguageServerId,
9888 token: ProgressToken,
9889 progress: LanguageServerProgress,
9890 cx: &mut Context<Self>,
9891 ) {
9892 let mut did_update = false;
9893 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9894 match status.pending_work.entry(token.clone()) {
9895 btree_map::Entry::Vacant(entry) => {
9896 entry.insert(progress.clone());
9897 did_update = true;
9898 }
9899 btree_map::Entry::Occupied(mut entry) => {
9900 let entry = entry.get_mut();
9901 if (progress.last_update_at - entry.last_update_at)
9902 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9903 {
9904 entry.last_update_at = progress.last_update_at;
9905 if progress.message.is_some() {
9906 entry.message = progress.message.clone();
9907 }
9908 if progress.percentage.is_some() {
9909 entry.percentage = progress.percentage;
9910 }
9911 if progress.is_cancellable != entry.is_cancellable {
9912 entry.is_cancellable = progress.is_cancellable;
9913 }
9914 did_update = true;
9915 }
9916 }
9917 }
9918 }
9919
9920 if did_update {
9921 cx.emit(LspStoreEvent::LanguageServerUpdate {
9922 language_server_id,
9923 name: self
9924 .language_server_adapter_for_id(language_server_id)
9925 .map(|adapter| adapter.name()),
9926 message: proto::update_language_server::Variant::WorkProgress(
9927 proto::LspWorkProgress {
9928 token: Some(token.to_proto()),
9929 message: progress.message,
9930 percentage: progress.percentage.map(|p| p as u32),
9931 is_cancellable: Some(progress.is_cancellable),
9932 },
9933 ),
9934 })
9935 }
9936 }
9937
9938 fn on_lsp_work_end(
9939 &mut self,
9940 language_server_id: LanguageServerId,
9941 token: ProgressToken,
9942 cx: &mut Context<Self>,
9943 ) {
9944 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9945 if let Some(work) = status.pending_work.remove(&token)
9946 && !work.is_disk_based_diagnostics_progress
9947 {
9948 cx.emit(LspStoreEvent::RefreshInlayHints {
9949 server_id: language_server_id,
9950 request_id: None,
9951 });
9952 }
9953 cx.notify();
9954 }
9955
9956 cx.emit(LspStoreEvent::LanguageServerUpdate {
9957 language_server_id,
9958 name: self
9959 .language_server_adapter_for_id(language_server_id)
9960 .map(|adapter| adapter.name()),
9961 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9962 token: Some(token.to_proto()),
9963 }),
9964 })
9965 }
9966
9967 pub async fn handle_resolve_completion_documentation(
9968 this: Entity<Self>,
9969 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9970 mut cx: AsyncApp,
9971 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9972 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9973
9974 let completion = this
9975 .read_with(&cx, |this, cx| {
9976 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9977 let server = this
9978 .language_server_for_id(id)
9979 .with_context(|| format!("No language server {id}"))?;
9980
9981 anyhow::Ok(cx.background_spawn(async move {
9982 let can_resolve = server
9983 .capabilities()
9984 .completion_provider
9985 .as_ref()
9986 .and_then(|options| options.resolve_provider)
9987 .unwrap_or(false);
9988 if can_resolve {
9989 server
9990 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9991 .await
9992 .into_response()
9993 .context("resolve completion item")
9994 } else {
9995 anyhow::Ok(lsp_completion)
9996 }
9997 }))
9998 })??
9999 .await?;
10000
10001 let mut documentation_is_markdown = false;
10002 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10003 let documentation = match completion.documentation {
10004 Some(lsp::Documentation::String(text)) => text,
10005
10006 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10007 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10008 value
10009 }
10010
10011 _ => String::new(),
10012 };
10013
10014 // If we have a new buffer_id, that means we're talking to a new client
10015 // and want to check for new text_edits in the completion too.
10016 let mut old_replace_start = None;
10017 let mut old_replace_end = None;
10018 let mut old_insert_start = None;
10019 let mut old_insert_end = None;
10020 let mut new_text = String::default();
10021 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10022 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10023 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10024 anyhow::Ok(buffer.read(cx).snapshot())
10025 })??;
10026
10027 if let Some(text_edit) = completion.text_edit.as_ref() {
10028 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10029
10030 if let Some(mut edit) = edit {
10031 LineEnding::normalize(&mut edit.new_text);
10032
10033 new_text = edit.new_text;
10034 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10035 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10036 if let Some(insert_range) = edit.insert_range {
10037 old_insert_start = Some(serialize_anchor(&insert_range.start));
10038 old_insert_end = Some(serialize_anchor(&insert_range.end));
10039 }
10040 }
10041 }
10042 }
10043
10044 Ok(proto::ResolveCompletionDocumentationResponse {
10045 documentation,
10046 documentation_is_markdown,
10047 old_replace_start,
10048 old_replace_end,
10049 new_text,
10050 lsp_completion,
10051 old_insert_start,
10052 old_insert_end,
10053 })
10054 }
10055
10056 async fn handle_on_type_formatting(
10057 this: Entity<Self>,
10058 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10059 mut cx: AsyncApp,
10060 ) -> Result<proto::OnTypeFormattingResponse> {
10061 let on_type_formatting = this.update(&mut cx, |this, cx| {
10062 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10063 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10064 let position = envelope
10065 .payload
10066 .position
10067 .and_then(deserialize_anchor)
10068 .context("invalid position")?;
10069 anyhow::Ok(this.apply_on_type_formatting(
10070 buffer,
10071 position,
10072 envelope.payload.trigger.clone(),
10073 cx,
10074 ))
10075 })??;
10076
10077 let transaction = on_type_formatting
10078 .await?
10079 .as_ref()
10080 .map(language::proto::serialize_transaction);
10081 Ok(proto::OnTypeFormattingResponse { transaction })
10082 }
10083
10084 async fn handle_refresh_inlay_hints(
10085 lsp_store: Entity<Self>,
10086 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10087 mut cx: AsyncApp,
10088 ) -> Result<proto::Ack> {
10089 lsp_store.update(&mut cx, |_, cx| {
10090 cx.emit(LspStoreEvent::RefreshInlayHints {
10091 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10092 request_id: envelope.payload.request_id.map(|id| id as usize),
10093 });
10094 })?;
10095 Ok(proto::Ack {})
10096 }
10097
10098 async fn handle_pull_workspace_diagnostics(
10099 lsp_store: Entity<Self>,
10100 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10101 mut cx: AsyncApp,
10102 ) -> Result<proto::Ack> {
10103 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10104 lsp_store.update(&mut cx, |lsp_store, _| {
10105 lsp_store.pull_workspace_diagnostics(server_id);
10106 })?;
10107 Ok(proto::Ack {})
10108 }
10109
10110 async fn handle_get_color_presentation(
10111 lsp_store: Entity<Self>,
10112 envelope: TypedEnvelope<proto::GetColorPresentation>,
10113 mut cx: AsyncApp,
10114 ) -> Result<proto::GetColorPresentationResponse> {
10115 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10116 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10117 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10118 })??;
10119
10120 let color = envelope
10121 .payload
10122 .color
10123 .context("invalid color resolve request")?;
10124 let start = color
10125 .lsp_range_start
10126 .context("invalid color resolve request")?;
10127 let end = color
10128 .lsp_range_end
10129 .context("invalid color resolve request")?;
10130
10131 let color = DocumentColor {
10132 lsp_range: lsp::Range {
10133 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10134 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10135 },
10136 color: lsp::Color {
10137 red: color.red,
10138 green: color.green,
10139 blue: color.blue,
10140 alpha: color.alpha,
10141 },
10142 resolved: false,
10143 color_presentations: Vec::new(),
10144 };
10145 let resolved_color = lsp_store
10146 .update(&mut cx, |lsp_store, cx| {
10147 lsp_store.resolve_color_presentation(
10148 color,
10149 buffer.clone(),
10150 LanguageServerId(envelope.payload.server_id as usize),
10151 cx,
10152 )
10153 })?
10154 .await
10155 .context("resolving color presentation")?;
10156
10157 Ok(proto::GetColorPresentationResponse {
10158 presentations: resolved_color
10159 .color_presentations
10160 .into_iter()
10161 .map(|presentation| proto::ColorPresentation {
10162 label: presentation.label.to_string(),
10163 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10164 additional_text_edits: presentation
10165 .additional_text_edits
10166 .into_iter()
10167 .map(serialize_lsp_edit)
10168 .collect(),
10169 })
10170 .collect(),
10171 })
10172 }
10173
10174 async fn handle_resolve_inlay_hint(
10175 lsp_store: Entity<Self>,
10176 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10177 mut cx: AsyncApp,
10178 ) -> Result<proto::ResolveInlayHintResponse> {
10179 let proto_hint = envelope
10180 .payload
10181 .hint
10182 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10183 let hint = InlayHints::proto_to_project_hint(proto_hint)
10184 .context("resolved proto inlay hint conversion")?;
10185 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10186 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10187 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10188 })??;
10189 let response_hint = lsp_store
10190 .update(&mut cx, |lsp_store, cx| {
10191 lsp_store.resolve_inlay_hint(
10192 hint,
10193 buffer,
10194 LanguageServerId(envelope.payload.language_server_id as usize),
10195 cx,
10196 )
10197 })?
10198 .await
10199 .context("inlay hints fetch")?;
10200 Ok(proto::ResolveInlayHintResponse {
10201 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10202 })
10203 }
10204
10205 async fn handle_refresh_code_lens(
10206 this: Entity<Self>,
10207 _: TypedEnvelope<proto::RefreshCodeLens>,
10208 mut cx: AsyncApp,
10209 ) -> Result<proto::Ack> {
10210 this.update(&mut cx, |_, cx| {
10211 cx.emit(LspStoreEvent::RefreshCodeLens);
10212 })?;
10213 Ok(proto::Ack {})
10214 }
10215
10216 async fn handle_open_buffer_for_symbol(
10217 this: Entity<Self>,
10218 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10219 mut cx: AsyncApp,
10220 ) -> Result<proto::OpenBufferForSymbolResponse> {
10221 let peer_id = envelope.original_sender_id().unwrap_or_default();
10222 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10223 let symbol = Self::deserialize_symbol(symbol)?;
10224 this.read_with(&cx, |this, _| {
10225 if let SymbolLocation::OutsideProject {
10226 abs_path,
10227 signature,
10228 } = &symbol.path
10229 {
10230 let new_signature = this.symbol_signature(&abs_path);
10231 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10232 }
10233 Ok(())
10234 })??;
10235 let buffer = this
10236 .update(&mut cx, |this, cx| {
10237 this.open_buffer_for_symbol(
10238 &Symbol {
10239 language_server_name: symbol.language_server_name,
10240 source_worktree_id: symbol.source_worktree_id,
10241 source_language_server_id: symbol.source_language_server_id,
10242 path: symbol.path,
10243 name: symbol.name,
10244 kind: symbol.kind,
10245 range: symbol.range,
10246 label: CodeLabel::default(),
10247 },
10248 cx,
10249 )
10250 })?
10251 .await?;
10252
10253 this.update(&mut cx, |this, cx| {
10254 let is_private = buffer
10255 .read(cx)
10256 .file()
10257 .map(|f| f.is_private())
10258 .unwrap_or_default();
10259 if is_private {
10260 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10261 } else {
10262 this.buffer_store
10263 .update(cx, |buffer_store, cx| {
10264 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10265 })
10266 .detach_and_log_err(cx);
10267 let buffer_id = buffer.read(cx).remote_id().to_proto();
10268 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10269 }
10270 })?
10271 }
10272
10273 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10274 let mut hasher = Sha256::new();
10275 hasher.update(abs_path.to_string_lossy().as_bytes());
10276 hasher.update(self.nonce.to_be_bytes());
10277 hasher.finalize().as_slice().try_into().unwrap()
10278 }
10279
10280 pub async fn handle_get_project_symbols(
10281 this: Entity<Self>,
10282 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10283 mut cx: AsyncApp,
10284 ) -> Result<proto::GetProjectSymbolsResponse> {
10285 let symbols = this
10286 .update(&mut cx, |this, cx| {
10287 this.symbols(&envelope.payload.query, cx)
10288 })?
10289 .await?;
10290
10291 Ok(proto::GetProjectSymbolsResponse {
10292 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10293 })
10294 }
10295
10296 pub async fn handle_restart_language_servers(
10297 this: Entity<Self>,
10298 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10299 mut cx: AsyncApp,
10300 ) -> Result<proto::Ack> {
10301 this.update(&mut cx, |lsp_store, cx| {
10302 let buffers =
10303 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10304 lsp_store.restart_language_servers_for_buffers(
10305 buffers,
10306 envelope
10307 .payload
10308 .only_servers
10309 .into_iter()
10310 .filter_map(|selector| {
10311 Some(match selector.selector? {
10312 proto::language_server_selector::Selector::ServerId(server_id) => {
10313 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10314 }
10315 proto::language_server_selector::Selector::Name(name) => {
10316 LanguageServerSelector::Name(LanguageServerName(
10317 SharedString::from(name),
10318 ))
10319 }
10320 })
10321 })
10322 .collect(),
10323 cx,
10324 );
10325 })?;
10326
10327 Ok(proto::Ack {})
10328 }
10329
10330 pub async fn handle_stop_language_servers(
10331 lsp_store: Entity<Self>,
10332 envelope: TypedEnvelope<proto::StopLanguageServers>,
10333 mut cx: AsyncApp,
10334 ) -> Result<proto::Ack> {
10335 lsp_store.update(&mut cx, |lsp_store, cx| {
10336 if envelope.payload.all
10337 && envelope.payload.also_servers.is_empty()
10338 && envelope.payload.buffer_ids.is_empty()
10339 {
10340 lsp_store.stop_all_language_servers(cx);
10341 } else {
10342 let buffers =
10343 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10344 lsp_store
10345 .stop_language_servers_for_buffers(
10346 buffers,
10347 envelope
10348 .payload
10349 .also_servers
10350 .into_iter()
10351 .filter_map(|selector| {
10352 Some(match selector.selector? {
10353 proto::language_server_selector::Selector::ServerId(
10354 server_id,
10355 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10356 server_id,
10357 )),
10358 proto::language_server_selector::Selector::Name(name) => {
10359 LanguageServerSelector::Name(LanguageServerName(
10360 SharedString::from(name),
10361 ))
10362 }
10363 })
10364 })
10365 .collect(),
10366 cx,
10367 )
10368 .detach_and_log_err(cx);
10369 }
10370 })?;
10371
10372 Ok(proto::Ack {})
10373 }
10374
10375 pub async fn handle_cancel_language_server_work(
10376 lsp_store: Entity<Self>,
10377 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10378 mut cx: AsyncApp,
10379 ) -> Result<proto::Ack> {
10380 lsp_store.update(&mut cx, |lsp_store, cx| {
10381 if let Some(work) = envelope.payload.work {
10382 match work {
10383 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10384 let buffers =
10385 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10386 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10387 }
10388 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10389 let server_id = LanguageServerId::from_proto(work.language_server_id);
10390 let token = work
10391 .token
10392 .map(|token| {
10393 ProgressToken::from_proto(token)
10394 .context("invalid work progress token")
10395 })
10396 .transpose()?;
10397 lsp_store.cancel_language_server_work(server_id, token, cx);
10398 }
10399 }
10400 }
10401 anyhow::Ok(())
10402 })??;
10403
10404 Ok(proto::Ack {})
10405 }
10406
10407 fn buffer_ids_to_buffers(
10408 &mut self,
10409 buffer_ids: impl Iterator<Item = u64>,
10410 cx: &mut Context<Self>,
10411 ) -> Vec<Entity<Buffer>> {
10412 buffer_ids
10413 .into_iter()
10414 .flat_map(|buffer_id| {
10415 self.buffer_store
10416 .read(cx)
10417 .get(BufferId::new(buffer_id).log_err()?)
10418 })
10419 .collect::<Vec<_>>()
10420 }
10421
10422 async fn handle_apply_additional_edits_for_completion(
10423 this: Entity<Self>,
10424 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10425 mut cx: AsyncApp,
10426 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10427 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10428 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10429 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10430 let completion = Self::deserialize_completion(
10431 envelope.payload.completion.context("invalid completion")?,
10432 )?;
10433 anyhow::Ok((buffer, completion))
10434 })??;
10435
10436 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10437 this.apply_additional_edits_for_completion(
10438 buffer,
10439 Rc::new(RefCell::new(Box::new([Completion {
10440 replace_range: completion.replace_range,
10441 new_text: completion.new_text,
10442 source: completion.source,
10443 documentation: None,
10444 label: CodeLabel::default(),
10445 match_start: None,
10446 snippet_deduplication_key: None,
10447 insert_text_mode: None,
10448 icon_path: None,
10449 confirm: None,
10450 }]))),
10451 0,
10452 false,
10453 cx,
10454 )
10455 })?;
10456
10457 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10458 transaction: apply_additional_edits
10459 .await?
10460 .as_ref()
10461 .map(language::proto::serialize_transaction),
10462 })
10463 }
10464
10465 pub fn last_formatting_failure(&self) -> Option<&str> {
10466 self.last_formatting_failure.as_deref()
10467 }
10468
10469 pub fn reset_last_formatting_failure(&mut self) {
10470 self.last_formatting_failure = None;
10471 }
10472
10473 pub fn environment_for_buffer(
10474 &self,
10475 buffer: &Entity<Buffer>,
10476 cx: &mut Context<Self>,
10477 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10478 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10479 environment.update(cx, |env, cx| {
10480 env.buffer_environment(buffer, &self.worktree_store, cx)
10481 })
10482 } else {
10483 Task::ready(None).shared()
10484 }
10485 }
10486
10487 pub fn format(
10488 &mut self,
10489 buffers: HashSet<Entity<Buffer>>,
10490 target: LspFormatTarget,
10491 push_to_history: bool,
10492 trigger: FormatTrigger,
10493 cx: &mut Context<Self>,
10494 ) -> Task<anyhow::Result<ProjectTransaction>> {
10495 let logger = zlog::scoped!("format");
10496 if self.as_local().is_some() {
10497 zlog::trace!(logger => "Formatting locally");
10498 let logger = zlog::scoped!(logger => "local");
10499 let buffers = buffers
10500 .into_iter()
10501 .map(|buffer_handle| {
10502 let buffer = buffer_handle.read(cx);
10503 let buffer_abs_path = File::from_dyn(buffer.file())
10504 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10505
10506 (buffer_handle, buffer_abs_path, buffer.remote_id())
10507 })
10508 .collect::<Vec<_>>();
10509
10510 cx.spawn(async move |lsp_store, cx| {
10511 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10512
10513 for (handle, abs_path, id) in buffers {
10514 let env = lsp_store
10515 .update(cx, |lsp_store, cx| {
10516 lsp_store.environment_for_buffer(&handle, cx)
10517 })?
10518 .await;
10519
10520 let ranges = match &target {
10521 LspFormatTarget::Buffers => None,
10522 LspFormatTarget::Ranges(ranges) => {
10523 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10524 }
10525 };
10526
10527 formattable_buffers.push(FormattableBuffer {
10528 handle,
10529 abs_path,
10530 env,
10531 ranges,
10532 });
10533 }
10534 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10535
10536 let format_timer = zlog::time!(logger => "Formatting buffers");
10537 let result = LocalLspStore::format_locally(
10538 lsp_store.clone(),
10539 formattable_buffers,
10540 push_to_history,
10541 trigger,
10542 logger,
10543 cx,
10544 )
10545 .await;
10546 format_timer.end();
10547
10548 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10549
10550 lsp_store.update(cx, |lsp_store, _| {
10551 lsp_store.update_last_formatting_failure(&result);
10552 })?;
10553
10554 result
10555 })
10556 } else if let Some((client, project_id)) = self.upstream_client() {
10557 zlog::trace!(logger => "Formatting remotely");
10558 let logger = zlog::scoped!(logger => "remote");
10559 // Don't support formatting ranges via remote
10560 match target {
10561 LspFormatTarget::Buffers => {}
10562 LspFormatTarget::Ranges(_) => {
10563 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10564 return Task::ready(Ok(ProjectTransaction::default()));
10565 }
10566 }
10567
10568 let buffer_store = self.buffer_store();
10569 cx.spawn(async move |lsp_store, cx| {
10570 zlog::trace!(logger => "Sending remote format request");
10571 let request_timer = zlog::time!(logger => "remote format request");
10572 let result = client
10573 .request(proto::FormatBuffers {
10574 project_id,
10575 trigger: trigger as i32,
10576 buffer_ids: buffers
10577 .iter()
10578 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10579 .collect::<Result<_>>()?,
10580 })
10581 .await
10582 .and_then(|result| result.transaction.context("missing transaction"));
10583 request_timer.end();
10584
10585 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10586
10587 lsp_store.update(cx, |lsp_store, _| {
10588 lsp_store.update_last_formatting_failure(&result);
10589 })?;
10590
10591 let transaction_response = result?;
10592 let _timer = zlog::time!(logger => "deserializing project transaction");
10593 buffer_store
10594 .update(cx, |buffer_store, cx| {
10595 buffer_store.deserialize_project_transaction(
10596 transaction_response,
10597 push_to_history,
10598 cx,
10599 )
10600 })?
10601 .await
10602 })
10603 } else {
10604 zlog::trace!(logger => "Not formatting");
10605 Task::ready(Ok(ProjectTransaction::default()))
10606 }
10607 }
10608
10609 async fn handle_format_buffers(
10610 this: Entity<Self>,
10611 envelope: TypedEnvelope<proto::FormatBuffers>,
10612 mut cx: AsyncApp,
10613 ) -> Result<proto::FormatBuffersResponse> {
10614 let sender_id = envelope.original_sender_id().unwrap_or_default();
10615 let format = this.update(&mut cx, |this, cx| {
10616 let mut buffers = HashSet::default();
10617 for buffer_id in &envelope.payload.buffer_ids {
10618 let buffer_id = BufferId::new(*buffer_id)?;
10619 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10620 }
10621 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10622 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10623 })??;
10624
10625 let project_transaction = format.await?;
10626 let project_transaction = this.update(&mut cx, |this, cx| {
10627 this.buffer_store.update(cx, |buffer_store, cx| {
10628 buffer_store.serialize_project_transaction_for_peer(
10629 project_transaction,
10630 sender_id,
10631 cx,
10632 )
10633 })
10634 })?;
10635 Ok(proto::FormatBuffersResponse {
10636 transaction: Some(project_transaction),
10637 })
10638 }
10639
10640 async fn handle_apply_code_action_kind(
10641 this: Entity<Self>,
10642 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10643 mut cx: AsyncApp,
10644 ) -> Result<proto::ApplyCodeActionKindResponse> {
10645 let sender_id = envelope.original_sender_id().unwrap_or_default();
10646 let format = this.update(&mut cx, |this, cx| {
10647 let mut buffers = HashSet::default();
10648 for buffer_id in &envelope.payload.buffer_ids {
10649 let buffer_id = BufferId::new(*buffer_id)?;
10650 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10651 }
10652 let kind = match envelope.payload.kind.as_str() {
10653 "" => CodeActionKind::EMPTY,
10654 "quickfix" => CodeActionKind::QUICKFIX,
10655 "refactor" => CodeActionKind::REFACTOR,
10656 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10657 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10658 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10659 "source" => CodeActionKind::SOURCE,
10660 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10661 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10662 _ => anyhow::bail!(
10663 "Invalid code action kind {}",
10664 envelope.payload.kind.as_str()
10665 ),
10666 };
10667 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10668 })??;
10669
10670 let project_transaction = format.await?;
10671 let project_transaction = this.update(&mut cx, |this, cx| {
10672 this.buffer_store.update(cx, |buffer_store, cx| {
10673 buffer_store.serialize_project_transaction_for_peer(
10674 project_transaction,
10675 sender_id,
10676 cx,
10677 )
10678 })
10679 })?;
10680 Ok(proto::ApplyCodeActionKindResponse {
10681 transaction: Some(project_transaction),
10682 })
10683 }
10684
10685 async fn shutdown_language_server(
10686 server_state: Option<LanguageServerState>,
10687 name: LanguageServerName,
10688 cx: &mut AsyncApp,
10689 ) {
10690 let server = match server_state {
10691 Some(LanguageServerState::Starting { startup, .. }) => {
10692 let mut timer = cx
10693 .background_executor()
10694 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10695 .fuse();
10696
10697 select! {
10698 server = startup.fuse() => server,
10699 () = timer => {
10700 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10701 None
10702 },
10703 }
10704 }
10705
10706 Some(LanguageServerState::Running { server, .. }) => Some(server),
10707
10708 None => None,
10709 };
10710
10711 if let Some(server) = server
10712 && let Some(shutdown) = server.shutdown()
10713 {
10714 shutdown.await;
10715 }
10716 }
10717
10718 // Returns a list of all of the worktrees which no longer have a language server and the root path
10719 // for the stopped server
10720 fn stop_local_language_server(
10721 &mut self,
10722 server_id: LanguageServerId,
10723 cx: &mut Context<Self>,
10724 ) -> Task<()> {
10725 let local = match &mut self.mode {
10726 LspStoreMode::Local(local) => local,
10727 _ => {
10728 return Task::ready(());
10729 }
10730 };
10731
10732 // Remove this server ID from all entries in the given worktree.
10733 local
10734 .language_server_ids
10735 .retain(|_, state| state.id != server_id);
10736 self.buffer_store.update(cx, |buffer_store, cx| {
10737 for buffer in buffer_store.buffers() {
10738 buffer.update(cx, |buffer, cx| {
10739 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10740 buffer.set_completion_triggers(server_id, Default::default(), cx);
10741 });
10742 }
10743 });
10744
10745 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10746 summaries.retain(|path, summaries_by_server_id| {
10747 if summaries_by_server_id.remove(&server_id).is_some() {
10748 if let Some((client, project_id)) = self.downstream_client.clone() {
10749 client
10750 .send(proto::UpdateDiagnosticSummary {
10751 project_id,
10752 worktree_id: worktree_id.to_proto(),
10753 summary: Some(proto::DiagnosticSummary {
10754 path: path.as_ref().to_proto(),
10755 language_server_id: server_id.0 as u64,
10756 error_count: 0,
10757 warning_count: 0,
10758 }),
10759 more_summaries: Vec::new(),
10760 })
10761 .log_err();
10762 }
10763 !summaries_by_server_id.is_empty()
10764 } else {
10765 true
10766 }
10767 });
10768 }
10769
10770 let local = self.as_local_mut().unwrap();
10771 for diagnostics in local.diagnostics.values_mut() {
10772 diagnostics.retain(|_, diagnostics_by_server_id| {
10773 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10774 diagnostics_by_server_id.remove(ix);
10775 !diagnostics_by_server_id.is_empty()
10776 } else {
10777 true
10778 }
10779 });
10780 }
10781 local.language_server_watched_paths.remove(&server_id);
10782
10783 let server_state = local.language_servers.remove(&server_id);
10784 self.cleanup_lsp_data(server_id);
10785 let name = self
10786 .language_server_statuses
10787 .remove(&server_id)
10788 .map(|status| status.name)
10789 .or_else(|| {
10790 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10791 Some(adapter.name())
10792 } else {
10793 None
10794 }
10795 });
10796
10797 if let Some(name) = name {
10798 log::info!("stopping language server {name}");
10799 self.languages
10800 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10801 cx.notify();
10802
10803 return cx.spawn(async move |lsp_store, cx| {
10804 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10805 lsp_store
10806 .update(cx, |lsp_store, cx| {
10807 lsp_store
10808 .languages
10809 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10810 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10811 cx.notify();
10812 })
10813 .ok();
10814 });
10815 }
10816
10817 if server_state.is_some() {
10818 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10819 }
10820 Task::ready(())
10821 }
10822
10823 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10824 if let Some((client, project_id)) = self.upstream_client() {
10825 let request = client.request(proto::StopLanguageServers {
10826 project_id,
10827 buffer_ids: Vec::new(),
10828 also_servers: Vec::new(),
10829 all: true,
10830 });
10831 cx.background_spawn(request).detach_and_log_err(cx);
10832 } else {
10833 let Some(local) = self.as_local_mut() else {
10834 return;
10835 };
10836 let language_servers_to_stop = local
10837 .language_server_ids
10838 .values()
10839 .map(|state| state.id)
10840 .collect();
10841 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10842 let tasks = language_servers_to_stop
10843 .into_iter()
10844 .map(|server| self.stop_local_language_server(server, cx))
10845 .collect::<Vec<_>>();
10846 cx.background_spawn(async move {
10847 futures::future::join_all(tasks).await;
10848 })
10849 .detach();
10850 }
10851 }
10852
10853 pub fn restart_language_servers_for_buffers(
10854 &mut self,
10855 buffers: Vec<Entity<Buffer>>,
10856 only_restart_servers: HashSet<LanguageServerSelector>,
10857 cx: &mut Context<Self>,
10858 ) {
10859 if let Some((client, project_id)) = self.upstream_client() {
10860 let request = client.request(proto::RestartLanguageServers {
10861 project_id,
10862 buffer_ids: buffers
10863 .into_iter()
10864 .map(|b| b.read(cx).remote_id().to_proto())
10865 .collect(),
10866 only_servers: only_restart_servers
10867 .into_iter()
10868 .map(|selector| {
10869 let selector = match selector {
10870 LanguageServerSelector::Id(language_server_id) => {
10871 proto::language_server_selector::Selector::ServerId(
10872 language_server_id.to_proto(),
10873 )
10874 }
10875 LanguageServerSelector::Name(language_server_name) => {
10876 proto::language_server_selector::Selector::Name(
10877 language_server_name.to_string(),
10878 )
10879 }
10880 };
10881 proto::LanguageServerSelector {
10882 selector: Some(selector),
10883 }
10884 })
10885 .collect(),
10886 all: false,
10887 });
10888 cx.background_spawn(request).detach_and_log_err(cx);
10889 } else {
10890 let stop_task = if only_restart_servers.is_empty() {
10891 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10892 } else {
10893 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10894 };
10895 cx.spawn(async move |lsp_store, cx| {
10896 stop_task.await;
10897 lsp_store
10898 .update(cx, |lsp_store, cx| {
10899 for buffer in buffers {
10900 lsp_store.register_buffer_with_language_servers(
10901 &buffer,
10902 only_restart_servers.clone(),
10903 true,
10904 cx,
10905 );
10906 }
10907 })
10908 .ok()
10909 })
10910 .detach();
10911 }
10912 }
10913
10914 pub fn stop_language_servers_for_buffers(
10915 &mut self,
10916 buffers: Vec<Entity<Buffer>>,
10917 also_stop_servers: HashSet<LanguageServerSelector>,
10918 cx: &mut Context<Self>,
10919 ) -> Task<Result<()>> {
10920 if let Some((client, project_id)) = self.upstream_client() {
10921 let request = client.request(proto::StopLanguageServers {
10922 project_id,
10923 buffer_ids: buffers
10924 .into_iter()
10925 .map(|b| b.read(cx).remote_id().to_proto())
10926 .collect(),
10927 also_servers: also_stop_servers
10928 .into_iter()
10929 .map(|selector| {
10930 let selector = match selector {
10931 LanguageServerSelector::Id(language_server_id) => {
10932 proto::language_server_selector::Selector::ServerId(
10933 language_server_id.to_proto(),
10934 )
10935 }
10936 LanguageServerSelector::Name(language_server_name) => {
10937 proto::language_server_selector::Selector::Name(
10938 language_server_name.to_string(),
10939 )
10940 }
10941 };
10942 proto::LanguageServerSelector {
10943 selector: Some(selector),
10944 }
10945 })
10946 .collect(),
10947 all: false,
10948 });
10949 cx.background_spawn(async move {
10950 let _ = request.await?;
10951 Ok(())
10952 })
10953 } else {
10954 let task =
10955 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10956 cx.background_spawn(async move {
10957 task.await;
10958 Ok(())
10959 })
10960 }
10961 }
10962
10963 fn stop_local_language_servers_for_buffers(
10964 &mut self,
10965 buffers: &[Entity<Buffer>],
10966 also_stop_servers: HashSet<LanguageServerSelector>,
10967 cx: &mut Context<Self>,
10968 ) -> Task<()> {
10969 let Some(local) = self.as_local_mut() else {
10970 return Task::ready(());
10971 };
10972 let mut language_server_names_to_stop = BTreeSet::default();
10973 let mut language_servers_to_stop = also_stop_servers
10974 .into_iter()
10975 .flat_map(|selector| match selector {
10976 LanguageServerSelector::Id(id) => Some(id),
10977 LanguageServerSelector::Name(name) => {
10978 language_server_names_to_stop.insert(name);
10979 None
10980 }
10981 })
10982 .collect::<BTreeSet<_>>();
10983
10984 let mut covered_worktrees = HashSet::default();
10985 for buffer in buffers {
10986 buffer.update(cx, |buffer, cx| {
10987 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10988 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10989 && covered_worktrees.insert(worktree_id)
10990 {
10991 language_server_names_to_stop.retain(|name| {
10992 let old_ids_count = language_servers_to_stop.len();
10993 let all_language_servers_with_this_name = local
10994 .language_server_ids
10995 .iter()
10996 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10997 language_servers_to_stop.extend(all_language_servers_with_this_name);
10998 old_ids_count == language_servers_to_stop.len()
10999 });
11000 }
11001 });
11002 }
11003 for name in language_server_names_to_stop {
11004 language_servers_to_stop.extend(
11005 local
11006 .language_server_ids
11007 .iter()
11008 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11009 );
11010 }
11011
11012 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11013 let tasks = language_servers_to_stop
11014 .into_iter()
11015 .map(|server| self.stop_local_language_server(server, cx))
11016 .collect::<Vec<_>>();
11017
11018 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11019 }
11020
11021 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11022 let (worktree, relative_path) =
11023 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11024
11025 let project_path = ProjectPath {
11026 worktree_id: worktree.read(cx).id(),
11027 path: relative_path,
11028 };
11029
11030 Some(
11031 self.buffer_store()
11032 .read(cx)
11033 .get_by_path(&project_path)?
11034 .read(cx),
11035 )
11036 }
11037
11038 #[cfg(any(test, feature = "test-support"))]
11039 pub fn update_diagnostics(
11040 &mut self,
11041 server_id: LanguageServerId,
11042 diagnostics: lsp::PublishDiagnosticsParams,
11043 result_id: Option<SharedString>,
11044 source_kind: DiagnosticSourceKind,
11045 disk_based_sources: &[String],
11046 cx: &mut Context<Self>,
11047 ) -> Result<()> {
11048 self.merge_lsp_diagnostics(
11049 source_kind,
11050 vec![DocumentDiagnosticsUpdate {
11051 diagnostics,
11052 result_id,
11053 server_id,
11054 disk_based_sources: Cow::Borrowed(disk_based_sources),
11055 registration_id: None,
11056 }],
11057 |_, _, _| false,
11058 cx,
11059 )
11060 }
11061
11062 pub fn merge_lsp_diagnostics(
11063 &mut self,
11064 source_kind: DiagnosticSourceKind,
11065 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11066 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11067 cx: &mut Context<Self>,
11068 ) -> Result<()> {
11069 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11070 let updates = lsp_diagnostics
11071 .into_iter()
11072 .filter_map(|update| {
11073 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11074 Some(DocumentDiagnosticsUpdate {
11075 diagnostics: self.lsp_to_document_diagnostics(
11076 abs_path,
11077 source_kind,
11078 update.server_id,
11079 update.diagnostics,
11080 &update.disk_based_sources,
11081 update.registration_id.clone(),
11082 ),
11083 result_id: update.result_id,
11084 server_id: update.server_id,
11085 disk_based_sources: update.disk_based_sources,
11086 registration_id: update.registration_id,
11087 })
11088 })
11089 .collect();
11090 self.merge_diagnostic_entries(updates, merge, cx)?;
11091 Ok(())
11092 }
11093
11094 fn lsp_to_document_diagnostics(
11095 &mut self,
11096 document_abs_path: PathBuf,
11097 source_kind: DiagnosticSourceKind,
11098 server_id: LanguageServerId,
11099 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11100 disk_based_sources: &[String],
11101 registration_id: Option<SharedString>,
11102 ) -> DocumentDiagnostics {
11103 let mut diagnostics = Vec::default();
11104 let mut primary_diagnostic_group_ids = HashMap::default();
11105 let mut sources_by_group_id = HashMap::default();
11106 let mut supporting_diagnostics = HashMap::default();
11107
11108 let adapter = self.language_server_adapter_for_id(server_id);
11109
11110 // Ensure that primary diagnostics are always the most severe
11111 lsp_diagnostics
11112 .diagnostics
11113 .sort_by_key(|item| item.severity);
11114
11115 for diagnostic in &lsp_diagnostics.diagnostics {
11116 let source = diagnostic.source.as_ref();
11117 let range = range_from_lsp(diagnostic.range);
11118 let is_supporting = diagnostic
11119 .related_information
11120 .as_ref()
11121 .is_some_and(|infos| {
11122 infos.iter().any(|info| {
11123 primary_diagnostic_group_ids.contains_key(&(
11124 source,
11125 diagnostic.code.clone(),
11126 range_from_lsp(info.location.range),
11127 ))
11128 })
11129 });
11130
11131 let is_unnecessary = diagnostic
11132 .tags
11133 .as_ref()
11134 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11135
11136 let underline = self
11137 .language_server_adapter_for_id(server_id)
11138 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11139
11140 if is_supporting {
11141 supporting_diagnostics.insert(
11142 (source, diagnostic.code.clone(), range),
11143 (diagnostic.severity, is_unnecessary),
11144 );
11145 } else {
11146 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11147 let is_disk_based =
11148 source.is_some_and(|source| disk_based_sources.contains(source));
11149
11150 sources_by_group_id.insert(group_id, source);
11151 primary_diagnostic_group_ids
11152 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11153
11154 diagnostics.push(DiagnosticEntry {
11155 range,
11156 diagnostic: Diagnostic {
11157 source: diagnostic.source.clone(),
11158 source_kind,
11159 code: diagnostic.code.clone(),
11160 code_description: diagnostic
11161 .code_description
11162 .as_ref()
11163 .and_then(|d| d.href.clone()),
11164 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11165 markdown: adapter.as_ref().and_then(|adapter| {
11166 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11167 }),
11168 message: diagnostic.message.trim().to_string(),
11169 group_id,
11170 is_primary: true,
11171 is_disk_based,
11172 is_unnecessary,
11173 underline,
11174 data: diagnostic.data.clone(),
11175 registration_id: registration_id.clone(),
11176 },
11177 });
11178 if let Some(infos) = &diagnostic.related_information {
11179 for info in infos {
11180 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11181 let range = range_from_lsp(info.location.range);
11182 diagnostics.push(DiagnosticEntry {
11183 range,
11184 diagnostic: Diagnostic {
11185 source: diagnostic.source.clone(),
11186 source_kind,
11187 code: diagnostic.code.clone(),
11188 code_description: diagnostic
11189 .code_description
11190 .as_ref()
11191 .and_then(|d| d.href.clone()),
11192 severity: DiagnosticSeverity::INFORMATION,
11193 markdown: adapter.as_ref().and_then(|adapter| {
11194 adapter.diagnostic_message_to_markdown(&info.message)
11195 }),
11196 message: info.message.trim().to_string(),
11197 group_id,
11198 is_primary: false,
11199 is_disk_based,
11200 is_unnecessary: false,
11201 underline,
11202 data: diagnostic.data.clone(),
11203 registration_id: registration_id.clone(),
11204 },
11205 });
11206 }
11207 }
11208 }
11209 }
11210 }
11211
11212 for entry in &mut diagnostics {
11213 let diagnostic = &mut entry.diagnostic;
11214 if !diagnostic.is_primary {
11215 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11216 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11217 source,
11218 diagnostic.code.clone(),
11219 entry.range.clone(),
11220 )) {
11221 if let Some(severity) = severity {
11222 diagnostic.severity = severity;
11223 }
11224 diagnostic.is_unnecessary = is_unnecessary;
11225 }
11226 }
11227 }
11228
11229 DocumentDiagnostics {
11230 diagnostics,
11231 document_abs_path,
11232 version: lsp_diagnostics.version,
11233 }
11234 }
11235
11236 fn insert_newly_running_language_server(
11237 &mut self,
11238 adapter: Arc<CachedLspAdapter>,
11239 language_server: Arc<LanguageServer>,
11240 server_id: LanguageServerId,
11241 key: LanguageServerSeed,
11242 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11243 cx: &mut Context<Self>,
11244 ) {
11245 let Some(local) = self.as_local_mut() else {
11246 return;
11247 };
11248 // If the language server for this key doesn't match the server id, don't store the
11249 // server. Which will cause it to be dropped, killing the process
11250 if local
11251 .language_server_ids
11252 .get(&key)
11253 .map(|state| state.id != server_id)
11254 .unwrap_or(false)
11255 {
11256 return;
11257 }
11258
11259 // Update language_servers collection with Running variant of LanguageServerState
11260 // indicating that the server is up and running and ready
11261 let workspace_folders = workspace_folders.lock().clone();
11262 language_server.set_workspace_folders(workspace_folders);
11263
11264 let workspace_diagnostics_refresh_tasks = language_server
11265 .capabilities()
11266 .diagnostic_provider
11267 .and_then(|provider| {
11268 local
11269 .language_server_dynamic_registrations
11270 .entry(server_id)
11271 .or_default()
11272 .diagnostics
11273 .entry(None)
11274 .or_insert(provider.clone());
11275 let workspace_refresher =
11276 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11277
11278 Some((None, workspace_refresher))
11279 })
11280 .into_iter()
11281 .collect();
11282 local.language_servers.insert(
11283 server_id,
11284 LanguageServerState::Running {
11285 workspace_diagnostics_refresh_tasks,
11286 adapter: adapter.clone(),
11287 server: language_server.clone(),
11288 simulate_disk_based_diagnostics_completion: None,
11289 },
11290 );
11291 local
11292 .languages
11293 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11294 if let Some(file_ops_caps) = language_server
11295 .capabilities()
11296 .workspace
11297 .as_ref()
11298 .and_then(|ws| ws.file_operations.as_ref())
11299 {
11300 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11301 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11302 if did_rename_caps.or(will_rename_caps).is_some() {
11303 let watcher = RenamePathsWatchedForServer::default()
11304 .with_did_rename_patterns(did_rename_caps)
11305 .with_will_rename_patterns(will_rename_caps);
11306 local
11307 .language_server_paths_watched_for_rename
11308 .insert(server_id, watcher);
11309 }
11310 }
11311
11312 self.language_server_statuses.insert(
11313 server_id,
11314 LanguageServerStatus {
11315 name: language_server.name(),
11316 pending_work: Default::default(),
11317 has_pending_diagnostic_updates: false,
11318 progress_tokens: Default::default(),
11319 worktree: Some(key.worktree_id),
11320 binary: Some(language_server.binary().clone()),
11321 configuration: Some(language_server.configuration().clone()),
11322 workspace_folders: language_server.workspace_folders(),
11323 },
11324 );
11325
11326 cx.emit(LspStoreEvent::LanguageServerAdded(
11327 server_id,
11328 language_server.name(),
11329 Some(key.worktree_id),
11330 ));
11331
11332 let server_capabilities = language_server.capabilities();
11333 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11334 downstream_client
11335 .send(proto::StartLanguageServer {
11336 project_id: *project_id,
11337 server: Some(proto::LanguageServer {
11338 id: server_id.to_proto(),
11339 name: language_server.name().to_string(),
11340 worktree_id: Some(key.worktree_id.to_proto()),
11341 }),
11342 capabilities: serde_json::to_string(&server_capabilities)
11343 .expect("serializing server LSP capabilities"),
11344 })
11345 .log_err();
11346 }
11347 self.lsp_server_capabilities
11348 .insert(server_id, server_capabilities);
11349
11350 // Tell the language server about every open buffer in the worktree that matches the language.
11351 // Also check for buffers in worktrees that reused this server
11352 let mut worktrees_using_server = vec![key.worktree_id];
11353 if let Some(local) = self.as_local() {
11354 // Find all worktrees that have this server in their language server tree
11355 for (worktree_id, servers) in &local.lsp_tree.instances {
11356 if *worktree_id != key.worktree_id {
11357 for server_map in servers.roots.values() {
11358 if server_map
11359 .values()
11360 .any(|(node, _)| node.id() == Some(server_id))
11361 {
11362 worktrees_using_server.push(*worktree_id);
11363 }
11364 }
11365 }
11366 }
11367 }
11368
11369 let mut buffer_paths_registered = Vec::new();
11370 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11371 let mut lsp_adapters = HashMap::default();
11372 for buffer_handle in buffer_store.buffers() {
11373 let buffer = buffer_handle.read(cx);
11374 let file = match File::from_dyn(buffer.file()) {
11375 Some(file) => file,
11376 None => continue,
11377 };
11378 let language = match buffer.language() {
11379 Some(language) => language,
11380 None => continue,
11381 };
11382
11383 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11384 || !lsp_adapters
11385 .entry(language.name())
11386 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11387 .iter()
11388 .any(|a| a.name == key.name)
11389 {
11390 continue;
11391 }
11392 // didOpen
11393 let file = match file.as_local() {
11394 Some(file) => file,
11395 None => continue,
11396 };
11397
11398 let local = self.as_local_mut().unwrap();
11399
11400 let buffer_id = buffer.remote_id();
11401 if local.registered_buffers.contains_key(&buffer_id) {
11402 let versions = local
11403 .buffer_snapshots
11404 .entry(buffer_id)
11405 .or_default()
11406 .entry(server_id)
11407 .and_modify(|_| {
11408 assert!(
11409 false,
11410 "There should not be an existing snapshot for a newly inserted buffer"
11411 )
11412 })
11413 .or_insert_with(|| {
11414 vec![LspBufferSnapshot {
11415 version: 0,
11416 snapshot: buffer.text_snapshot(),
11417 }]
11418 });
11419
11420 let snapshot = versions.last().unwrap();
11421 let version = snapshot.version;
11422 let initial_snapshot = &snapshot.snapshot;
11423 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11424 language_server.register_buffer(
11425 uri,
11426 adapter.language_id(&language.name()),
11427 version,
11428 initial_snapshot.text(),
11429 );
11430 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11431 local
11432 .buffers_opened_in_servers
11433 .entry(buffer_id)
11434 .or_default()
11435 .insert(server_id);
11436 }
11437 buffer_handle.update(cx, |buffer, cx| {
11438 buffer.set_completion_triggers(
11439 server_id,
11440 language_server
11441 .capabilities()
11442 .completion_provider
11443 .as_ref()
11444 .and_then(|provider| {
11445 provider
11446 .trigger_characters
11447 .as_ref()
11448 .map(|characters| characters.iter().cloned().collect())
11449 })
11450 .unwrap_or_default(),
11451 cx,
11452 )
11453 });
11454 }
11455 });
11456
11457 for (buffer_id, abs_path) in buffer_paths_registered {
11458 cx.emit(LspStoreEvent::LanguageServerUpdate {
11459 language_server_id: server_id,
11460 name: Some(adapter.name()),
11461 message: proto::update_language_server::Variant::RegisteredForBuffer(
11462 proto::RegisteredForBuffer {
11463 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11464 buffer_id: buffer_id.to_proto(),
11465 },
11466 ),
11467 });
11468 }
11469
11470 cx.notify();
11471 }
11472
11473 pub fn language_servers_running_disk_based_diagnostics(
11474 &self,
11475 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11476 self.language_server_statuses
11477 .iter()
11478 .filter_map(|(id, status)| {
11479 if status.has_pending_diagnostic_updates {
11480 Some(*id)
11481 } else {
11482 None
11483 }
11484 })
11485 }
11486
11487 pub(crate) fn cancel_language_server_work_for_buffers(
11488 &mut self,
11489 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11490 cx: &mut Context<Self>,
11491 ) {
11492 if let Some((client, project_id)) = self.upstream_client() {
11493 let request = client.request(proto::CancelLanguageServerWork {
11494 project_id,
11495 work: Some(proto::cancel_language_server_work::Work::Buffers(
11496 proto::cancel_language_server_work::Buffers {
11497 buffer_ids: buffers
11498 .into_iter()
11499 .map(|b| b.read(cx).remote_id().to_proto())
11500 .collect(),
11501 },
11502 )),
11503 });
11504 cx.background_spawn(request).detach_and_log_err(cx);
11505 } else if let Some(local) = self.as_local() {
11506 let servers = buffers
11507 .into_iter()
11508 .flat_map(|buffer| {
11509 buffer.update(cx, |buffer, cx| {
11510 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11511 })
11512 })
11513 .collect::<HashSet<_>>();
11514 for server_id in servers {
11515 self.cancel_language_server_work(server_id, None, cx);
11516 }
11517 }
11518 }
11519
11520 pub(crate) fn cancel_language_server_work(
11521 &mut self,
11522 server_id: LanguageServerId,
11523 token_to_cancel: Option<ProgressToken>,
11524 cx: &mut Context<Self>,
11525 ) {
11526 if let Some(local) = self.as_local() {
11527 let status = self.language_server_statuses.get(&server_id);
11528 let server = local.language_servers.get(&server_id);
11529 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11530 {
11531 for (token, progress) in &status.pending_work {
11532 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11533 && token != token_to_cancel
11534 {
11535 continue;
11536 }
11537 if progress.is_cancellable {
11538 server
11539 .notify::<lsp::notification::WorkDoneProgressCancel>(
11540 WorkDoneProgressCancelParams {
11541 token: token.to_lsp(),
11542 },
11543 )
11544 .ok();
11545 }
11546 }
11547 }
11548 } else if let Some((client, project_id)) = self.upstream_client() {
11549 let request = client.request(proto::CancelLanguageServerWork {
11550 project_id,
11551 work: Some(
11552 proto::cancel_language_server_work::Work::LanguageServerWork(
11553 proto::cancel_language_server_work::LanguageServerWork {
11554 language_server_id: server_id.to_proto(),
11555 token: token_to_cancel.map(|token| token.to_proto()),
11556 },
11557 ),
11558 ),
11559 });
11560 cx.background_spawn(request).detach_and_log_err(cx);
11561 }
11562 }
11563
11564 fn register_supplementary_language_server(
11565 &mut self,
11566 id: LanguageServerId,
11567 name: LanguageServerName,
11568 server: Arc<LanguageServer>,
11569 cx: &mut Context<Self>,
11570 ) {
11571 if let Some(local) = self.as_local_mut() {
11572 local
11573 .supplementary_language_servers
11574 .insert(id, (name.clone(), server));
11575 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11576 }
11577 }
11578
11579 fn unregister_supplementary_language_server(
11580 &mut self,
11581 id: LanguageServerId,
11582 cx: &mut Context<Self>,
11583 ) {
11584 if let Some(local) = self.as_local_mut() {
11585 local.supplementary_language_servers.remove(&id);
11586 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11587 }
11588 }
11589
11590 pub(crate) fn supplementary_language_servers(
11591 &self,
11592 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11593 self.as_local().into_iter().flat_map(|local| {
11594 local
11595 .supplementary_language_servers
11596 .iter()
11597 .map(|(id, (name, _))| (*id, name.clone()))
11598 })
11599 }
11600
11601 pub fn language_server_adapter_for_id(
11602 &self,
11603 id: LanguageServerId,
11604 ) -> Option<Arc<CachedLspAdapter>> {
11605 self.as_local()
11606 .and_then(|local| local.language_servers.get(&id))
11607 .and_then(|language_server_state| match language_server_state {
11608 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11609 _ => None,
11610 })
11611 }
11612
11613 pub(super) fn update_local_worktree_language_servers(
11614 &mut self,
11615 worktree_handle: &Entity<Worktree>,
11616 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11617 cx: &mut Context<Self>,
11618 ) {
11619 if changes.is_empty() {
11620 return;
11621 }
11622
11623 let Some(local) = self.as_local() else { return };
11624
11625 local.prettier_store.update(cx, |prettier_store, cx| {
11626 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11627 });
11628
11629 let worktree_id = worktree_handle.read(cx).id();
11630 let mut language_server_ids = local
11631 .language_server_ids
11632 .iter()
11633 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11634 .collect::<Vec<_>>();
11635 language_server_ids.sort();
11636 language_server_ids.dedup();
11637
11638 // let abs_path = worktree_handle.read(cx).abs_path();
11639 for server_id in &language_server_ids {
11640 if let Some(LanguageServerState::Running { server, .. }) =
11641 local.language_servers.get(server_id)
11642 && let Some(watched_paths) = local
11643 .language_server_watched_paths
11644 .get(server_id)
11645 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11646 {
11647 let params = lsp::DidChangeWatchedFilesParams {
11648 changes: changes
11649 .iter()
11650 .filter_map(|(path, _, change)| {
11651 if !watched_paths.is_match(path.as_std_path()) {
11652 return None;
11653 }
11654 let typ = match change {
11655 PathChange::Loaded => return None,
11656 PathChange::Added => lsp::FileChangeType::CREATED,
11657 PathChange::Removed => lsp::FileChangeType::DELETED,
11658 PathChange::Updated => lsp::FileChangeType::CHANGED,
11659 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11660 };
11661 let uri = lsp::Uri::from_file_path(
11662 worktree_handle.read(cx).absolutize(&path),
11663 )
11664 .ok()?;
11665 Some(lsp::FileEvent { uri, typ })
11666 })
11667 .collect(),
11668 };
11669 if !params.changes.is_empty() {
11670 server
11671 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11672 .ok();
11673 }
11674 }
11675 }
11676 for (path, _, _) in changes {
11677 if let Some(file_name) = path.file_name()
11678 && local.watched_manifest_filenames.contains(file_name)
11679 {
11680 self.request_workspace_config_refresh();
11681 break;
11682 }
11683 }
11684 }
11685
11686 pub fn wait_for_remote_buffer(
11687 &mut self,
11688 id: BufferId,
11689 cx: &mut Context<Self>,
11690 ) -> Task<Result<Entity<Buffer>>> {
11691 self.buffer_store.update(cx, |buffer_store, cx| {
11692 buffer_store.wait_for_remote_buffer(id, cx)
11693 })
11694 }
11695
11696 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11697 let mut result = proto::Symbol {
11698 language_server_name: symbol.language_server_name.0.to_string(),
11699 source_worktree_id: symbol.source_worktree_id.to_proto(),
11700 language_server_id: symbol.source_language_server_id.to_proto(),
11701 name: symbol.name.clone(),
11702 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11703 start: Some(proto::PointUtf16 {
11704 row: symbol.range.start.0.row,
11705 column: symbol.range.start.0.column,
11706 }),
11707 end: Some(proto::PointUtf16 {
11708 row: symbol.range.end.0.row,
11709 column: symbol.range.end.0.column,
11710 }),
11711 worktree_id: Default::default(),
11712 path: Default::default(),
11713 signature: Default::default(),
11714 };
11715 match &symbol.path {
11716 SymbolLocation::InProject(path) => {
11717 result.worktree_id = path.worktree_id.to_proto();
11718 result.path = path.path.to_proto();
11719 }
11720 SymbolLocation::OutsideProject {
11721 abs_path,
11722 signature,
11723 } => {
11724 result.path = abs_path.to_string_lossy().into_owned();
11725 result.signature = signature.to_vec();
11726 }
11727 }
11728 result
11729 }
11730
11731 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11732 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11733 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11734 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11735
11736 let path = if serialized_symbol.signature.is_empty() {
11737 SymbolLocation::InProject(ProjectPath {
11738 worktree_id,
11739 path: RelPath::from_proto(&serialized_symbol.path)
11740 .context("invalid symbol path")?,
11741 })
11742 } else {
11743 SymbolLocation::OutsideProject {
11744 abs_path: Path::new(&serialized_symbol.path).into(),
11745 signature: serialized_symbol
11746 .signature
11747 .try_into()
11748 .map_err(|_| anyhow!("invalid signature"))?,
11749 }
11750 };
11751
11752 let start = serialized_symbol.start.context("invalid start")?;
11753 let end = serialized_symbol.end.context("invalid end")?;
11754 Ok(CoreSymbol {
11755 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11756 source_worktree_id,
11757 source_language_server_id: LanguageServerId::from_proto(
11758 serialized_symbol.language_server_id,
11759 ),
11760 path,
11761 name: serialized_symbol.name,
11762 range: Unclipped(PointUtf16::new(start.row, start.column))
11763 ..Unclipped(PointUtf16::new(end.row, end.column)),
11764 kind,
11765 })
11766 }
11767
11768 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11769 let mut serialized_completion = proto::Completion {
11770 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11771 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11772 new_text: completion.new_text.clone(),
11773 ..proto::Completion::default()
11774 };
11775 match &completion.source {
11776 CompletionSource::Lsp {
11777 insert_range,
11778 server_id,
11779 lsp_completion,
11780 lsp_defaults,
11781 resolved,
11782 } => {
11783 let (old_insert_start, old_insert_end) = insert_range
11784 .as_ref()
11785 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11786 .unzip();
11787
11788 serialized_completion.old_insert_start = old_insert_start;
11789 serialized_completion.old_insert_end = old_insert_end;
11790 serialized_completion.source = proto::completion::Source::Lsp as i32;
11791 serialized_completion.server_id = server_id.0 as u64;
11792 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11793 serialized_completion.lsp_defaults = lsp_defaults
11794 .as_deref()
11795 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11796 serialized_completion.resolved = *resolved;
11797 }
11798 CompletionSource::BufferWord {
11799 word_range,
11800 resolved,
11801 } => {
11802 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11803 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11804 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11805 serialized_completion.resolved = *resolved;
11806 }
11807 CompletionSource::Custom => {
11808 serialized_completion.source = proto::completion::Source::Custom as i32;
11809 serialized_completion.resolved = true;
11810 }
11811 CompletionSource::Dap { sort_text } => {
11812 serialized_completion.source = proto::completion::Source::Dap as i32;
11813 serialized_completion.sort_text = Some(sort_text.clone());
11814 }
11815 }
11816
11817 serialized_completion
11818 }
11819
11820 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11821 let old_replace_start = completion
11822 .old_replace_start
11823 .and_then(deserialize_anchor)
11824 .context("invalid old start")?;
11825 let old_replace_end = completion
11826 .old_replace_end
11827 .and_then(deserialize_anchor)
11828 .context("invalid old end")?;
11829 let insert_range = {
11830 match completion.old_insert_start.zip(completion.old_insert_end) {
11831 Some((start, end)) => {
11832 let start = deserialize_anchor(start).context("invalid insert old start")?;
11833 let end = deserialize_anchor(end).context("invalid insert old end")?;
11834 Some(start..end)
11835 }
11836 None => None,
11837 }
11838 };
11839 Ok(CoreCompletion {
11840 replace_range: old_replace_start..old_replace_end,
11841 new_text: completion.new_text,
11842 source: match proto::completion::Source::from_i32(completion.source) {
11843 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11844 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11845 insert_range,
11846 server_id: LanguageServerId::from_proto(completion.server_id),
11847 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11848 lsp_defaults: completion
11849 .lsp_defaults
11850 .as_deref()
11851 .map(serde_json::from_slice)
11852 .transpose()?,
11853 resolved: completion.resolved,
11854 },
11855 Some(proto::completion::Source::BufferWord) => {
11856 let word_range = completion
11857 .buffer_word_start
11858 .and_then(deserialize_anchor)
11859 .context("invalid buffer word start")?
11860 ..completion
11861 .buffer_word_end
11862 .and_then(deserialize_anchor)
11863 .context("invalid buffer word end")?;
11864 CompletionSource::BufferWord {
11865 word_range,
11866 resolved: completion.resolved,
11867 }
11868 }
11869 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11870 sort_text: completion
11871 .sort_text
11872 .context("expected sort text to exist")?,
11873 },
11874 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11875 },
11876 })
11877 }
11878
11879 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11880 let (kind, lsp_action) = match &action.lsp_action {
11881 LspAction::Action(code_action) => (
11882 proto::code_action::Kind::Action as i32,
11883 serde_json::to_vec(code_action).unwrap(),
11884 ),
11885 LspAction::Command(command) => (
11886 proto::code_action::Kind::Command as i32,
11887 serde_json::to_vec(command).unwrap(),
11888 ),
11889 LspAction::CodeLens(code_lens) => (
11890 proto::code_action::Kind::CodeLens as i32,
11891 serde_json::to_vec(code_lens).unwrap(),
11892 ),
11893 };
11894
11895 proto::CodeAction {
11896 server_id: action.server_id.0 as u64,
11897 start: Some(serialize_anchor(&action.range.start)),
11898 end: Some(serialize_anchor(&action.range.end)),
11899 lsp_action,
11900 kind,
11901 resolved: action.resolved,
11902 }
11903 }
11904
11905 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11906 let start = action
11907 .start
11908 .and_then(deserialize_anchor)
11909 .context("invalid start")?;
11910 let end = action
11911 .end
11912 .and_then(deserialize_anchor)
11913 .context("invalid end")?;
11914 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11915 Some(proto::code_action::Kind::Action) => {
11916 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11917 }
11918 Some(proto::code_action::Kind::Command) => {
11919 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11920 }
11921 Some(proto::code_action::Kind::CodeLens) => {
11922 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11923 }
11924 None => anyhow::bail!("Unknown action kind {}", action.kind),
11925 };
11926 Ok(CodeAction {
11927 server_id: LanguageServerId(action.server_id as usize),
11928 range: start..end,
11929 resolved: action.resolved,
11930 lsp_action,
11931 })
11932 }
11933
11934 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11935 match &formatting_result {
11936 Ok(_) => self.last_formatting_failure = None,
11937 Err(error) => {
11938 let error_string = format!("{error:#}");
11939 log::error!("Formatting failed: {error_string}");
11940 self.last_formatting_failure
11941 .replace(error_string.lines().join(" "));
11942 }
11943 }
11944 }
11945
11946 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11947 self.lsp_server_capabilities.remove(&for_server);
11948 for lsp_data in self.lsp_data.values_mut() {
11949 lsp_data.remove_server_data(for_server);
11950 }
11951 if let Some(local) = self.as_local_mut() {
11952 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11953 local
11954 .workspace_pull_diagnostics_result_ids
11955 .remove(&for_server);
11956 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11957 buffer_servers.remove(&for_server);
11958 }
11959 }
11960 }
11961
11962 pub fn result_id_for_buffer_pull(
11963 &self,
11964 server_id: LanguageServerId,
11965 buffer_id: BufferId,
11966 registration_id: &Option<SharedString>,
11967 cx: &App,
11968 ) -> Option<SharedString> {
11969 let abs_path = self
11970 .buffer_store
11971 .read(cx)
11972 .get(buffer_id)
11973 .and_then(|b| File::from_dyn(b.read(cx).file()))
11974 .map(|f| f.abs_path(cx))?;
11975 self.as_local()?
11976 .buffer_pull_diagnostics_result_ids
11977 .get(&server_id)?
11978 .get(registration_id)?
11979 .get(&abs_path)?
11980 .clone()
11981 }
11982
11983 /// Gets all result_ids for a workspace diagnostics pull request.
11984 /// First, it tries to find buffer's result_id retrieved via the diagnostics pull; if it fails, it falls back to the workspace disagnostics pull result_id.
11985 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
11986 pub fn result_ids_for_workspace_refresh(
11987 &self,
11988 server_id: LanguageServerId,
11989 registration_id: &Option<SharedString>,
11990 ) -> HashMap<PathBuf, SharedString> {
11991 let Some(local) = self.as_local() else {
11992 return HashMap::default();
11993 };
11994 local
11995 .workspace_pull_diagnostics_result_ids
11996 .get(&server_id)
11997 .into_iter()
11998 .filter_map(|diagnostics| diagnostics.get(registration_id))
11999 .flatten()
12000 .filter_map(|(abs_path, result_id)| {
12001 let result_id = local
12002 .buffer_pull_diagnostics_result_ids
12003 .get(&server_id)
12004 .and_then(|buffer_ids_result_ids| {
12005 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12006 })
12007 .cloned()
12008 .flatten()
12009 .or_else(|| result_id.clone())?;
12010 Some((abs_path.clone(), result_id))
12011 })
12012 .collect()
12013 }
12014
12015 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12016 if let Some(LanguageServerState::Running {
12017 workspace_diagnostics_refresh_tasks,
12018 ..
12019 }) = self
12020 .as_local_mut()
12021 .and_then(|local| local.language_servers.get_mut(&server_id))
12022 {
12023 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12024 diagnostics.refresh_tx.try_send(()).ok();
12025 }
12026 }
12027 }
12028
12029 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12030 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12031 return;
12032 };
12033 let Some(local) = self.as_local_mut() else {
12034 return;
12035 };
12036
12037 for server_id in buffer.update(cx, |buffer, cx| {
12038 local.language_server_ids_for_buffer(buffer, cx)
12039 }) {
12040 if let Some(LanguageServerState::Running {
12041 workspace_diagnostics_refresh_tasks,
12042 ..
12043 }) = local.language_servers.get_mut(&server_id)
12044 {
12045 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12046 diagnostics.refresh_tx.try_send(()).ok();
12047 }
12048 }
12049 }
12050 }
12051
12052 fn apply_workspace_diagnostic_report(
12053 &mut self,
12054 server_id: LanguageServerId,
12055 report: lsp::WorkspaceDiagnosticReportResult,
12056 registration_id: Option<SharedString>,
12057 cx: &mut Context<Self>,
12058 ) {
12059 let workspace_diagnostics =
12060 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12061 report,
12062 server_id,
12063 registration_id,
12064 );
12065 let mut unchanged_buffers = HashMap::default();
12066 let workspace_diagnostics_updates = workspace_diagnostics
12067 .into_iter()
12068 .filter_map(
12069 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12070 LspPullDiagnostics::Response {
12071 server_id,
12072 uri,
12073 diagnostics,
12074 registration_id,
12075 } => Some((
12076 server_id,
12077 uri,
12078 diagnostics,
12079 workspace_diagnostics.version,
12080 registration_id,
12081 )),
12082 LspPullDiagnostics::Default => None,
12083 },
12084 )
12085 .fold(
12086 HashMap::default(),
12087 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12088 let (result_id, diagnostics) = match diagnostics {
12089 PulledDiagnostics::Unchanged { result_id } => {
12090 unchanged_buffers
12091 .entry(new_registration_id.clone())
12092 .or_insert_with(HashSet::default)
12093 .insert(uri.clone());
12094 (Some(result_id), Vec::new())
12095 }
12096 PulledDiagnostics::Changed {
12097 result_id,
12098 diagnostics,
12099 } => (result_id, diagnostics),
12100 };
12101 let disk_based_sources = Cow::Owned(
12102 self.language_server_adapter_for_id(server_id)
12103 .as_ref()
12104 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12105 .unwrap_or(&[])
12106 .to_vec(),
12107 );
12108
12109 let Some(abs_path) = uri.to_file_path().ok() else {
12110 return acc;
12111 };
12112 let Some((worktree, relative_path)) =
12113 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12114 else {
12115 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12116 return acc;
12117 };
12118 let worktree_id = worktree.read(cx).id();
12119 let project_path = ProjectPath {
12120 worktree_id,
12121 path: relative_path,
12122 };
12123 if let Some(local_lsp_store) = self.as_local_mut() {
12124 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12125 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12126 }
12127 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12128 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12129 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12130 acc.entry(server_id)
12131 .or_insert_with(HashMap::default)
12132 .entry(new_registration_id.clone())
12133 .or_insert_with(Vec::new)
12134 .push(DocumentDiagnosticsUpdate {
12135 server_id,
12136 diagnostics: lsp::PublishDiagnosticsParams {
12137 uri,
12138 diagnostics,
12139 version,
12140 },
12141 result_id,
12142 disk_based_sources,
12143 registration_id: new_registration_id,
12144 });
12145 }
12146 acc
12147 },
12148 );
12149
12150 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12151 for (registration_id, diagnostic_updates) in diagnostic_updates {
12152 self.merge_lsp_diagnostics(
12153 DiagnosticSourceKind::Pulled,
12154 diagnostic_updates,
12155 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12156 DiagnosticSourceKind::Pulled => {
12157 old_diagnostic.registration_id != registration_id
12158 || unchanged_buffers
12159 .get(&old_diagnostic.registration_id)
12160 .is_some_and(|unchanged_buffers| {
12161 unchanged_buffers.contains(&document_uri)
12162 })
12163 }
12164 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12165 },
12166 cx,
12167 )
12168 .log_err();
12169 }
12170 }
12171 }
12172
12173 fn register_server_capabilities(
12174 &mut self,
12175 server_id: LanguageServerId,
12176 params: lsp::RegistrationParams,
12177 cx: &mut Context<Self>,
12178 ) -> anyhow::Result<()> {
12179 let server = self
12180 .language_server_for_id(server_id)
12181 .with_context(|| format!("no server {server_id} found"))?;
12182 for reg in params.registrations {
12183 match reg.method.as_str() {
12184 "workspace/didChangeWatchedFiles" => {
12185 if let Some(options) = reg.register_options {
12186 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12187 let caps = serde_json::from_value(options)?;
12188 local_lsp_store
12189 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12190 true
12191 } else {
12192 false
12193 };
12194 if notify {
12195 notify_server_capabilities_updated(&server, cx);
12196 }
12197 }
12198 }
12199 "workspace/didChangeConfiguration" => {
12200 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12201 }
12202 "workspace/didChangeWorkspaceFolders" => {
12203 // In this case register options is an empty object, we can ignore it
12204 let caps = lsp::WorkspaceFoldersServerCapabilities {
12205 supported: Some(true),
12206 change_notifications: Some(OneOf::Right(reg.id)),
12207 };
12208 server.update_capabilities(|capabilities| {
12209 capabilities
12210 .workspace
12211 .get_or_insert_default()
12212 .workspace_folders = Some(caps);
12213 });
12214 notify_server_capabilities_updated(&server, cx);
12215 }
12216 "workspace/symbol" => {
12217 let options = parse_register_capabilities(reg)?;
12218 server.update_capabilities(|capabilities| {
12219 capabilities.workspace_symbol_provider = Some(options);
12220 });
12221 notify_server_capabilities_updated(&server, cx);
12222 }
12223 "workspace/fileOperations" => {
12224 if let Some(options) = reg.register_options {
12225 let caps = serde_json::from_value(options)?;
12226 server.update_capabilities(|capabilities| {
12227 capabilities
12228 .workspace
12229 .get_or_insert_default()
12230 .file_operations = Some(caps);
12231 });
12232 notify_server_capabilities_updated(&server, cx);
12233 }
12234 }
12235 "workspace/executeCommand" => {
12236 if let Some(options) = reg.register_options {
12237 let options = serde_json::from_value(options)?;
12238 server.update_capabilities(|capabilities| {
12239 capabilities.execute_command_provider = Some(options);
12240 });
12241 notify_server_capabilities_updated(&server, cx);
12242 }
12243 }
12244 "textDocument/rangeFormatting" => {
12245 let options = parse_register_capabilities(reg)?;
12246 server.update_capabilities(|capabilities| {
12247 capabilities.document_range_formatting_provider = Some(options);
12248 });
12249 notify_server_capabilities_updated(&server, cx);
12250 }
12251 "textDocument/onTypeFormatting" => {
12252 if let Some(options) = reg
12253 .register_options
12254 .map(serde_json::from_value)
12255 .transpose()?
12256 {
12257 server.update_capabilities(|capabilities| {
12258 capabilities.document_on_type_formatting_provider = Some(options);
12259 });
12260 notify_server_capabilities_updated(&server, cx);
12261 }
12262 }
12263 "textDocument/formatting" => {
12264 let options = parse_register_capabilities(reg)?;
12265 server.update_capabilities(|capabilities| {
12266 capabilities.document_formatting_provider = Some(options);
12267 });
12268 notify_server_capabilities_updated(&server, cx);
12269 }
12270 "textDocument/rename" => {
12271 let options = parse_register_capabilities(reg)?;
12272 server.update_capabilities(|capabilities| {
12273 capabilities.rename_provider = Some(options);
12274 });
12275 notify_server_capabilities_updated(&server, cx);
12276 }
12277 "textDocument/inlayHint" => {
12278 let options = parse_register_capabilities(reg)?;
12279 server.update_capabilities(|capabilities| {
12280 capabilities.inlay_hint_provider = Some(options);
12281 });
12282 notify_server_capabilities_updated(&server, cx);
12283 }
12284 "textDocument/documentSymbol" => {
12285 let options = parse_register_capabilities(reg)?;
12286 server.update_capabilities(|capabilities| {
12287 capabilities.document_symbol_provider = Some(options);
12288 });
12289 notify_server_capabilities_updated(&server, cx);
12290 }
12291 "textDocument/codeAction" => {
12292 let options = parse_register_capabilities(reg)?;
12293 let provider = match options {
12294 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12295 OneOf::Right(caps) => caps,
12296 };
12297 server.update_capabilities(|capabilities| {
12298 capabilities.code_action_provider = Some(provider);
12299 });
12300 notify_server_capabilities_updated(&server, cx);
12301 }
12302 "textDocument/definition" => {
12303 let options = parse_register_capabilities(reg)?;
12304 server.update_capabilities(|capabilities| {
12305 capabilities.definition_provider = Some(options);
12306 });
12307 notify_server_capabilities_updated(&server, cx);
12308 }
12309 "textDocument/completion" => {
12310 if let Some(caps) = reg
12311 .register_options
12312 .map(serde_json::from_value::<CompletionOptions>)
12313 .transpose()?
12314 {
12315 server.update_capabilities(|capabilities| {
12316 capabilities.completion_provider = Some(caps.clone());
12317 });
12318
12319 if let Some(local) = self.as_local() {
12320 let mut buffers_with_language_server = Vec::new();
12321 for handle in self.buffer_store.read(cx).buffers() {
12322 let buffer_id = handle.read(cx).remote_id();
12323 if local
12324 .buffers_opened_in_servers
12325 .get(&buffer_id)
12326 .filter(|s| s.contains(&server_id))
12327 .is_some()
12328 {
12329 buffers_with_language_server.push(handle);
12330 }
12331 }
12332 let triggers = caps
12333 .trigger_characters
12334 .unwrap_or_default()
12335 .into_iter()
12336 .collect::<BTreeSet<_>>();
12337 for handle in buffers_with_language_server {
12338 let triggers = triggers.clone();
12339 let _ = handle.update(cx, move |buffer, cx| {
12340 buffer.set_completion_triggers(server_id, triggers, cx);
12341 });
12342 }
12343 }
12344 notify_server_capabilities_updated(&server, cx);
12345 }
12346 }
12347 "textDocument/hover" => {
12348 let options = parse_register_capabilities(reg)?;
12349 let provider = match options {
12350 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12351 OneOf::Right(caps) => caps,
12352 };
12353 server.update_capabilities(|capabilities| {
12354 capabilities.hover_provider = Some(provider);
12355 });
12356 notify_server_capabilities_updated(&server, cx);
12357 }
12358 "textDocument/signatureHelp" => {
12359 if let Some(caps) = reg
12360 .register_options
12361 .map(serde_json::from_value)
12362 .transpose()?
12363 {
12364 server.update_capabilities(|capabilities| {
12365 capabilities.signature_help_provider = Some(caps);
12366 });
12367 notify_server_capabilities_updated(&server, cx);
12368 }
12369 }
12370 "textDocument/didChange" => {
12371 if let Some(sync_kind) = reg
12372 .register_options
12373 .and_then(|opts| opts.get("syncKind").cloned())
12374 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12375 .transpose()?
12376 {
12377 server.update_capabilities(|capabilities| {
12378 let mut sync_options =
12379 Self::take_text_document_sync_options(capabilities);
12380 sync_options.change = Some(sync_kind);
12381 capabilities.text_document_sync =
12382 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12383 });
12384 notify_server_capabilities_updated(&server, cx);
12385 }
12386 }
12387 "textDocument/didSave" => {
12388 if let Some(include_text) = reg
12389 .register_options
12390 .map(|opts| {
12391 let transpose = opts
12392 .get("includeText")
12393 .cloned()
12394 .map(serde_json::from_value::<Option<bool>>)
12395 .transpose();
12396 match transpose {
12397 Ok(value) => Ok(value.flatten()),
12398 Err(e) => Err(e),
12399 }
12400 })
12401 .transpose()?
12402 {
12403 server.update_capabilities(|capabilities| {
12404 let mut sync_options =
12405 Self::take_text_document_sync_options(capabilities);
12406 sync_options.save =
12407 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12408 include_text,
12409 }));
12410 capabilities.text_document_sync =
12411 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12412 });
12413 notify_server_capabilities_updated(&server, cx);
12414 }
12415 }
12416 "textDocument/codeLens" => {
12417 if let Some(caps) = reg
12418 .register_options
12419 .map(serde_json::from_value)
12420 .transpose()?
12421 {
12422 server.update_capabilities(|capabilities| {
12423 capabilities.code_lens_provider = Some(caps);
12424 });
12425 notify_server_capabilities_updated(&server, cx);
12426 }
12427 }
12428 "textDocument/diagnostic" => {
12429 if let Some(caps) = reg
12430 .register_options
12431 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12432 .transpose()?
12433 {
12434 let local = self
12435 .as_local_mut()
12436 .context("Expected LSP Store to be local")?;
12437 let state = local
12438 .language_servers
12439 .get_mut(&server_id)
12440 .context("Could not obtain Language Servers state")?;
12441 local
12442 .language_server_dynamic_registrations
12443 .entry(server_id)
12444 .or_default()
12445 .diagnostics
12446 .insert(Some(reg.id.clone()), caps.clone());
12447
12448 let supports_workspace_diagnostics =
12449 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12450 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12451 diagnostic_options.workspace_diagnostics
12452 }
12453 DiagnosticServerCapabilities::RegistrationOptions(
12454 diagnostic_registration_options,
12455 ) => {
12456 diagnostic_registration_options
12457 .diagnostic_options
12458 .workspace_diagnostics
12459 }
12460 };
12461
12462 if supports_workspace_diagnostics(&caps) {
12463 if let LanguageServerState::Running {
12464 workspace_diagnostics_refresh_tasks,
12465 ..
12466 } = state
12467 && let Some(task) = lsp_workspace_diagnostics_refresh(
12468 Some(reg.id.clone()),
12469 caps.clone(),
12470 server.clone(),
12471 cx,
12472 )
12473 {
12474 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12475 }
12476 }
12477
12478 server.update_capabilities(|capabilities| {
12479 capabilities.diagnostic_provider = Some(caps);
12480 });
12481
12482 notify_server_capabilities_updated(&server, cx);
12483 }
12484 }
12485 "textDocument/documentColor" => {
12486 let options = parse_register_capabilities(reg)?;
12487 let provider = match options {
12488 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12489 OneOf::Right(caps) => caps,
12490 };
12491 server.update_capabilities(|capabilities| {
12492 capabilities.color_provider = Some(provider);
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 _ => log::warn!("unhandled capability registration: {reg:?}"),
12497 }
12498 }
12499
12500 Ok(())
12501 }
12502
12503 fn unregister_server_capabilities(
12504 &mut self,
12505 server_id: LanguageServerId,
12506 params: lsp::UnregistrationParams,
12507 cx: &mut Context<Self>,
12508 ) -> anyhow::Result<()> {
12509 let server = self
12510 .language_server_for_id(server_id)
12511 .with_context(|| format!("no server {server_id} found"))?;
12512 for unreg in params.unregisterations.iter() {
12513 match unreg.method.as_str() {
12514 "workspace/didChangeWatchedFiles" => {
12515 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12516 local_lsp_store
12517 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12518 true
12519 } else {
12520 false
12521 };
12522 if notify {
12523 notify_server_capabilities_updated(&server, cx);
12524 }
12525 }
12526 "workspace/didChangeConfiguration" => {
12527 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12528 }
12529 "workspace/didChangeWorkspaceFolders" => {
12530 server.update_capabilities(|capabilities| {
12531 capabilities
12532 .workspace
12533 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12534 workspace_folders: None,
12535 file_operations: None,
12536 })
12537 .workspace_folders = None;
12538 });
12539 notify_server_capabilities_updated(&server, cx);
12540 }
12541 "workspace/symbol" => {
12542 server.update_capabilities(|capabilities| {
12543 capabilities.workspace_symbol_provider = None
12544 });
12545 notify_server_capabilities_updated(&server, cx);
12546 }
12547 "workspace/fileOperations" => {
12548 server.update_capabilities(|capabilities| {
12549 capabilities
12550 .workspace
12551 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12552 workspace_folders: None,
12553 file_operations: None,
12554 })
12555 .file_operations = None;
12556 });
12557 notify_server_capabilities_updated(&server, cx);
12558 }
12559 "workspace/executeCommand" => {
12560 server.update_capabilities(|capabilities| {
12561 capabilities.execute_command_provider = None;
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 "textDocument/rangeFormatting" => {
12566 server.update_capabilities(|capabilities| {
12567 capabilities.document_range_formatting_provider = None
12568 });
12569 notify_server_capabilities_updated(&server, cx);
12570 }
12571 "textDocument/onTypeFormatting" => {
12572 server.update_capabilities(|capabilities| {
12573 capabilities.document_on_type_formatting_provider = None;
12574 });
12575 notify_server_capabilities_updated(&server, cx);
12576 }
12577 "textDocument/formatting" => {
12578 server.update_capabilities(|capabilities| {
12579 capabilities.document_formatting_provider = None;
12580 });
12581 notify_server_capabilities_updated(&server, cx);
12582 }
12583 "textDocument/rename" => {
12584 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12585 notify_server_capabilities_updated(&server, cx);
12586 }
12587 "textDocument/codeAction" => {
12588 server.update_capabilities(|capabilities| {
12589 capabilities.code_action_provider = None;
12590 });
12591 notify_server_capabilities_updated(&server, cx);
12592 }
12593 "textDocument/definition" => {
12594 server.update_capabilities(|capabilities| {
12595 capabilities.definition_provider = None;
12596 });
12597 notify_server_capabilities_updated(&server, cx);
12598 }
12599 "textDocument/completion" => {
12600 server.update_capabilities(|capabilities| {
12601 capabilities.completion_provider = None;
12602 });
12603 notify_server_capabilities_updated(&server, cx);
12604 }
12605 "textDocument/hover" => {
12606 server.update_capabilities(|capabilities| {
12607 capabilities.hover_provider = None;
12608 });
12609 notify_server_capabilities_updated(&server, cx);
12610 }
12611 "textDocument/signatureHelp" => {
12612 server.update_capabilities(|capabilities| {
12613 capabilities.signature_help_provider = None;
12614 });
12615 notify_server_capabilities_updated(&server, cx);
12616 }
12617 "textDocument/didChange" => {
12618 server.update_capabilities(|capabilities| {
12619 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12620 sync_options.change = None;
12621 capabilities.text_document_sync =
12622 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12623 });
12624 notify_server_capabilities_updated(&server, cx);
12625 }
12626 "textDocument/didSave" => {
12627 server.update_capabilities(|capabilities| {
12628 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12629 sync_options.save = None;
12630 capabilities.text_document_sync =
12631 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12632 });
12633 notify_server_capabilities_updated(&server, cx);
12634 }
12635 "textDocument/codeLens" => {
12636 server.update_capabilities(|capabilities| {
12637 capabilities.code_lens_provider = None;
12638 });
12639 notify_server_capabilities_updated(&server, cx);
12640 }
12641 "textDocument/diagnostic" => {
12642 let local = self
12643 .as_local_mut()
12644 .context("Expected LSP Store to be local")?;
12645
12646 let state = local
12647 .language_servers
12648 .get_mut(&server_id)
12649 .context("Could not obtain Language Servers state")?;
12650 local
12651 .language_server_dynamic_registrations
12652 .get_mut(&server_id)
12653 .with_context(|| {
12654 format!("Expected dynamic registration to exist for server {server_id}")
12655 })?.diagnostics
12656 .remove(&Some(unreg.id.clone()))
12657 .with_context(|| format!(
12658 "Attempted to unregister non-existent diagnostic registration with ID {}",
12659 unreg.id)
12660 )?;
12661
12662 let mut has_any_diagnostic_providers_still = true;
12663 if let LanguageServerState::Running {
12664 workspace_diagnostics_refresh_tasks,
12665 ..
12666 } = state
12667 {
12668 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12669 has_any_diagnostic_providers_still =
12670 !workspace_diagnostics_refresh_tasks.is_empty();
12671 }
12672
12673 if !has_any_diagnostic_providers_still {
12674 server.update_capabilities(|capabilities| {
12675 debug_assert!(capabilities.diagnostic_provider.is_some());
12676 capabilities.diagnostic_provider = None;
12677 });
12678 }
12679
12680 notify_server_capabilities_updated(&server, cx);
12681 }
12682 "textDocument/documentColor" => {
12683 server.update_capabilities(|capabilities| {
12684 capabilities.color_provider = None;
12685 });
12686 notify_server_capabilities_updated(&server, cx);
12687 }
12688 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12689 }
12690 }
12691
12692 Ok(())
12693 }
12694
12695 async fn deduplicate_range_based_lsp_requests<T>(
12696 lsp_store: &Entity<Self>,
12697 server_id: Option<LanguageServerId>,
12698 lsp_request_id: LspRequestId,
12699 proto_request: &T::ProtoRequest,
12700 range: Range<Anchor>,
12701 cx: &mut AsyncApp,
12702 ) -> Result<()>
12703 where
12704 T: LspCommand,
12705 T::ProtoRequest: proto::LspRequestMessage,
12706 {
12707 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12708 let version = deserialize_version(proto_request.buffer_version());
12709 let buffer = lsp_store.update(cx, |this, cx| {
12710 this.buffer_store.read(cx).get_existing(buffer_id)
12711 })??;
12712 buffer
12713 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12714 .await?;
12715 lsp_store.update(cx, |lsp_store, cx| {
12716 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12717 let chunks_queried_for = lsp_data
12718 .inlay_hints
12719 .applicable_chunks(&[range])
12720 .collect::<Vec<_>>();
12721 match chunks_queried_for.as_slice() {
12722 &[chunk] => {
12723 let key = LspKey {
12724 request_type: TypeId::of::<T>(),
12725 server_queried: server_id,
12726 };
12727 let previous_request = lsp_data
12728 .chunk_lsp_requests
12729 .entry(key)
12730 .or_default()
12731 .insert(chunk, lsp_request_id);
12732 if let Some((previous_request, running_requests)) =
12733 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12734 {
12735 running_requests.remove(&previous_request);
12736 }
12737 }
12738 _ambiguous_chunks => {
12739 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12740 // there, a buffer version-based check will be performed and outdated requests discarded.
12741 }
12742 }
12743 anyhow::Ok(())
12744 })??;
12745
12746 Ok(())
12747 }
12748
12749 async fn query_lsp_locally<T>(
12750 lsp_store: Entity<Self>,
12751 for_server_id: Option<LanguageServerId>,
12752 sender_id: proto::PeerId,
12753 lsp_request_id: LspRequestId,
12754 proto_request: T::ProtoRequest,
12755 position: Option<Anchor>,
12756 cx: &mut AsyncApp,
12757 ) -> Result<()>
12758 where
12759 T: LspCommand + Clone,
12760 T::ProtoRequest: proto::LspRequestMessage,
12761 <T::ProtoRequest as proto::RequestMessage>::Response:
12762 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12763 {
12764 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12765 let version = deserialize_version(proto_request.buffer_version());
12766 let buffer = lsp_store.update(cx, |this, cx| {
12767 this.buffer_store.read(cx).get_existing(buffer_id)
12768 })??;
12769 buffer
12770 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12771 .await?;
12772 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12773 let request =
12774 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12775 let key = LspKey {
12776 request_type: TypeId::of::<T>(),
12777 server_queried: for_server_id,
12778 };
12779 lsp_store.update(cx, |lsp_store, cx| {
12780 let request_task = match for_server_id {
12781 Some(server_id) => {
12782 let server_task = lsp_store.request_lsp(
12783 buffer.clone(),
12784 LanguageServerToQuery::Other(server_id),
12785 request.clone(),
12786 cx,
12787 );
12788 cx.background_spawn(async move {
12789 let mut responses = Vec::new();
12790 match server_task.await {
12791 Ok(response) => responses.push((server_id, response)),
12792 // rust-analyzer likes to error with this when its still loading up
12793 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12794 Err(e) => log::error!(
12795 "Error handling response for request {request:?}: {e:#}"
12796 ),
12797 }
12798 responses
12799 })
12800 }
12801 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12802 };
12803 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12804 if T::ProtoRequest::stop_previous_requests() {
12805 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12806 lsp_requests.clear();
12807 }
12808 }
12809 lsp_data.lsp_requests.entry(key).or_default().insert(
12810 lsp_request_id,
12811 cx.spawn(async move |lsp_store, cx| {
12812 let response = request_task.await;
12813 lsp_store
12814 .update(cx, |lsp_store, cx| {
12815 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12816 {
12817 let response = response
12818 .into_iter()
12819 .map(|(server_id, response)| {
12820 (
12821 server_id.to_proto(),
12822 T::response_to_proto(
12823 response,
12824 lsp_store,
12825 sender_id,
12826 &buffer_version,
12827 cx,
12828 )
12829 .into(),
12830 )
12831 })
12832 .collect::<HashMap<_, _>>();
12833 match client.send_lsp_response::<T::ProtoRequest>(
12834 project_id,
12835 lsp_request_id,
12836 response,
12837 ) {
12838 Ok(()) => {}
12839 Err(e) => {
12840 log::error!("Failed to send LSP response: {e:#}",)
12841 }
12842 }
12843 }
12844 })
12845 .ok();
12846 }),
12847 );
12848 })?;
12849 Ok(())
12850 }
12851
12852 fn take_text_document_sync_options(
12853 capabilities: &mut lsp::ServerCapabilities,
12854 ) -> lsp::TextDocumentSyncOptions {
12855 match capabilities.text_document_sync.take() {
12856 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12857 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12858 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12859 sync_options.change = Some(sync_kind);
12860 sync_options
12861 }
12862 None => lsp::TextDocumentSyncOptions::default(),
12863 }
12864 }
12865
12866 #[cfg(any(test, feature = "test-support"))]
12867 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12868 Some(
12869 self.lsp_data
12870 .get_mut(&buffer_id)?
12871 .code_lens
12872 .take()?
12873 .update
12874 .take()?
12875 .1,
12876 )
12877 }
12878
12879 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12880 self.downstream_client.clone()
12881 }
12882
12883 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12884 self.worktree_store.clone()
12885 }
12886
12887 /// Gets what's stored in the LSP data for the given buffer.
12888 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12889 self.lsp_data.get_mut(&buffer_id)
12890 }
12891
12892 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12893 /// new [`BufferLspData`] will be created to replace the previous state.
12894 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12895 let (buffer_id, buffer_version) =
12896 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12897 let lsp_data = self
12898 .lsp_data
12899 .entry(buffer_id)
12900 .or_insert_with(|| BufferLspData::new(buffer, cx));
12901 if buffer_version.changed_since(&lsp_data.buffer_version) {
12902 *lsp_data = BufferLspData::new(buffer, cx);
12903 }
12904 lsp_data
12905 }
12906}
12907
12908// Registration with registerOptions as null, should fallback to true.
12909// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12910fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12911 reg: lsp::Registration,
12912) -> Result<OneOf<bool, T>> {
12913 Ok(match reg.register_options {
12914 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12915 None => OneOf::Left(true),
12916 })
12917}
12918
12919fn subscribe_to_binary_statuses(
12920 languages: &Arc<LanguageRegistry>,
12921 cx: &mut Context<'_, LspStore>,
12922) -> Task<()> {
12923 let mut server_statuses = languages.language_server_binary_statuses();
12924 cx.spawn(async move |lsp_store, cx| {
12925 while let Some((server_name, binary_status)) = server_statuses.next().await {
12926 if lsp_store
12927 .update(cx, |_, cx| {
12928 let mut message = None;
12929 let binary_status = match binary_status {
12930 BinaryStatus::None => proto::ServerBinaryStatus::None,
12931 BinaryStatus::CheckingForUpdate => {
12932 proto::ServerBinaryStatus::CheckingForUpdate
12933 }
12934 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12935 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12936 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12937 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12938 BinaryStatus::Failed { error } => {
12939 message = Some(error);
12940 proto::ServerBinaryStatus::Failed
12941 }
12942 };
12943 cx.emit(LspStoreEvent::LanguageServerUpdate {
12944 // Binary updates are about the binary that might not have any language server id at that point.
12945 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12946 language_server_id: LanguageServerId(0),
12947 name: Some(server_name),
12948 message: proto::update_language_server::Variant::StatusUpdate(
12949 proto::StatusUpdate {
12950 message,
12951 status: Some(proto::status_update::Status::Binary(
12952 binary_status as i32,
12953 )),
12954 },
12955 ),
12956 });
12957 })
12958 .is_err()
12959 {
12960 break;
12961 }
12962 }
12963 })
12964}
12965
12966fn lsp_workspace_diagnostics_refresh(
12967 registration_id: Option<String>,
12968 options: DiagnosticServerCapabilities,
12969 server: Arc<LanguageServer>,
12970 cx: &mut Context<'_, LspStore>,
12971) -> Option<WorkspaceRefreshTask> {
12972 let identifier = workspace_diagnostic_identifier(&options)?;
12973 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
12974
12975 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12976 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12977 refresh_tx.try_send(()).ok();
12978
12979 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12980 let mut attempts = 0;
12981 let max_attempts = 50;
12982 let mut requests = 0;
12983
12984 loop {
12985 let Some(()) = refresh_rx.recv().await else {
12986 return;
12987 };
12988
12989 'request: loop {
12990 requests += 1;
12991 if attempts > max_attempts {
12992 log::error!(
12993 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12994 );
12995 return;
12996 }
12997 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12998 cx.background_executor()
12999 .timer(Duration::from_millis(backoff_millis))
13000 .await;
13001 attempts += 1;
13002
13003 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13004 lsp_store
13005 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13006 .into_iter()
13007 .filter_map(|(abs_path, result_id)| {
13008 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13009 Some(lsp::PreviousResultId {
13010 uri,
13011 value: result_id.to_string(),
13012 })
13013 })
13014 .collect()
13015 }) else {
13016 return;
13017 };
13018
13019 let token = if let Some(registration_id) = ®istration_id {
13020 format!(
13021 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13022 server.server_id(),
13023 )
13024 } else {
13025 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13026 };
13027
13028 progress_rx.try_recv().ok();
13029 let timer =
13030 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13031 let progress = pin!(progress_rx.recv().fuse());
13032 let response_result = server
13033 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13034 lsp::WorkspaceDiagnosticParams {
13035 previous_result_ids,
13036 identifier: identifier.clone(),
13037 work_done_progress_params: Default::default(),
13038 partial_result_params: lsp::PartialResultParams {
13039 partial_result_token: Some(lsp::ProgressToken::String(token)),
13040 },
13041 },
13042 select(timer, progress).then(|either| match either {
13043 Either::Left((message, ..)) => ready(message).left_future(),
13044 Either::Right(..) => pending::<String>().right_future(),
13045 }),
13046 )
13047 .await;
13048
13049 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13050 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13051 match response_result {
13052 ConnectionResult::Timeout => {
13053 log::error!("Timeout during workspace diagnostics pull");
13054 continue 'request;
13055 }
13056 ConnectionResult::ConnectionReset => {
13057 log::error!("Server closed a workspace diagnostics pull request");
13058 continue 'request;
13059 }
13060 ConnectionResult::Result(Err(e)) => {
13061 log::error!("Error during workspace diagnostics pull: {e:#}");
13062 break 'request;
13063 }
13064 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13065 attempts = 0;
13066 if lsp_store
13067 .update(cx, |lsp_store, cx| {
13068 lsp_store.apply_workspace_diagnostic_report(
13069 server.server_id(),
13070 pulled_diagnostics,
13071 registration_id_shared.clone(),
13072 cx,
13073 )
13074 })
13075 .is_err()
13076 {
13077 return;
13078 }
13079 break 'request;
13080 }
13081 }
13082 }
13083 }
13084 });
13085
13086 Some(WorkspaceRefreshTask {
13087 refresh_tx,
13088 progress_tx,
13089 task: workspace_query_language_server,
13090 })
13091}
13092
13093fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13094 match &options {
13095 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13096 diagnostic_options.identifier.clone()
13097 }
13098 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13099 let diagnostic_options = ®istration_options.diagnostic_options;
13100 diagnostic_options.identifier.clone()
13101 }
13102 }
13103}
13104
13105fn workspace_diagnostic_identifier(
13106 options: &DiagnosticServerCapabilities,
13107) -> Option<Option<String>> {
13108 match &options {
13109 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13110 if !diagnostic_options.workspace_diagnostics {
13111 return None;
13112 }
13113 Some(diagnostic_options.identifier.clone())
13114 }
13115 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13116 let diagnostic_options = ®istration_options.diagnostic_options;
13117 if !diagnostic_options.workspace_diagnostics {
13118 return None;
13119 }
13120 Some(diagnostic_options.identifier.clone())
13121 }
13122 }
13123}
13124
13125fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13126 let CompletionSource::BufferWord {
13127 word_range,
13128 resolved,
13129 } = &mut completion.source
13130 else {
13131 return;
13132 };
13133 if *resolved {
13134 return;
13135 }
13136
13137 if completion.new_text
13138 != snapshot
13139 .text_for_range(word_range.clone())
13140 .collect::<String>()
13141 {
13142 return;
13143 }
13144
13145 let mut offset = 0;
13146 for chunk in snapshot.chunks(word_range.clone(), true) {
13147 let end_offset = offset + chunk.text.len();
13148 if let Some(highlight_id) = chunk.syntax_highlight_id {
13149 completion
13150 .label
13151 .runs
13152 .push((offset..end_offset, highlight_id));
13153 }
13154 offset = end_offset;
13155 }
13156 *resolved = true;
13157}
13158
13159impl EventEmitter<LspStoreEvent> for LspStore {}
13160
13161fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13162 hover
13163 .contents
13164 .retain(|hover_block| !hover_block.text.trim().is_empty());
13165 if hover.contents.is_empty() {
13166 None
13167 } else {
13168 Some(hover)
13169 }
13170}
13171
13172async fn populate_labels_for_completions(
13173 new_completions: Vec<CoreCompletion>,
13174 language: Option<Arc<Language>>,
13175 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13176) -> Vec<Completion> {
13177 let lsp_completions = new_completions
13178 .iter()
13179 .filter_map(|new_completion| {
13180 new_completion
13181 .source
13182 .lsp_completion(true)
13183 .map(|lsp_completion| lsp_completion.into_owned())
13184 })
13185 .collect::<Vec<_>>();
13186
13187 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13188 lsp_adapter
13189 .labels_for_completions(&lsp_completions, language)
13190 .await
13191 .log_err()
13192 .unwrap_or_default()
13193 } else {
13194 Vec::new()
13195 }
13196 .into_iter()
13197 .fuse();
13198
13199 let mut completions = Vec::new();
13200 for completion in new_completions {
13201 match completion.source.lsp_completion(true) {
13202 Some(lsp_completion) => {
13203 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13204
13205 let mut label = labels.next().flatten().unwrap_or_else(|| {
13206 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13207 });
13208 ensure_uniform_list_compatible_label(&mut label);
13209 completions.push(Completion {
13210 label,
13211 documentation,
13212 replace_range: completion.replace_range,
13213 new_text: completion.new_text,
13214 insert_text_mode: lsp_completion.insert_text_mode,
13215 source: completion.source,
13216 icon_path: None,
13217 confirm: None,
13218 match_start: None,
13219 snippet_deduplication_key: None,
13220 });
13221 }
13222 None => {
13223 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13224 ensure_uniform_list_compatible_label(&mut label);
13225 completions.push(Completion {
13226 label,
13227 documentation: None,
13228 replace_range: completion.replace_range,
13229 new_text: completion.new_text,
13230 source: completion.source,
13231 insert_text_mode: None,
13232 icon_path: None,
13233 confirm: None,
13234 match_start: None,
13235 snippet_deduplication_key: None,
13236 });
13237 }
13238 }
13239 }
13240 completions
13241}
13242
13243#[derive(Debug)]
13244pub enum LanguageServerToQuery {
13245 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13246 FirstCapable,
13247 /// Query a specific language server.
13248 Other(LanguageServerId),
13249}
13250
13251#[derive(Default)]
13252struct RenamePathsWatchedForServer {
13253 did_rename: Vec<RenameActionPredicate>,
13254 will_rename: Vec<RenameActionPredicate>,
13255}
13256
13257impl RenamePathsWatchedForServer {
13258 fn with_did_rename_patterns(
13259 mut self,
13260 did_rename: Option<&FileOperationRegistrationOptions>,
13261 ) -> Self {
13262 if let Some(did_rename) = did_rename {
13263 self.did_rename = did_rename
13264 .filters
13265 .iter()
13266 .filter_map(|filter| filter.try_into().log_err())
13267 .collect();
13268 }
13269 self
13270 }
13271 fn with_will_rename_patterns(
13272 mut self,
13273 will_rename: Option<&FileOperationRegistrationOptions>,
13274 ) -> Self {
13275 if let Some(will_rename) = will_rename {
13276 self.will_rename = will_rename
13277 .filters
13278 .iter()
13279 .filter_map(|filter| filter.try_into().log_err())
13280 .collect();
13281 }
13282 self
13283 }
13284
13285 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13286 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13287 }
13288 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13289 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13290 }
13291}
13292
13293impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13294 type Error = globset::Error;
13295 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13296 Ok(Self {
13297 kind: ops.pattern.matches.clone(),
13298 glob: GlobBuilder::new(&ops.pattern.glob)
13299 .case_insensitive(
13300 ops.pattern
13301 .options
13302 .as_ref()
13303 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13304 )
13305 .build()?
13306 .compile_matcher(),
13307 })
13308 }
13309}
13310struct RenameActionPredicate {
13311 glob: GlobMatcher,
13312 kind: Option<FileOperationPatternKind>,
13313}
13314
13315impl RenameActionPredicate {
13316 // Returns true if language server should be notified
13317 fn eval(&self, path: &str, is_dir: bool) -> bool {
13318 self.kind.as_ref().is_none_or(|kind| {
13319 let expected_kind = if is_dir {
13320 FileOperationPatternKind::Folder
13321 } else {
13322 FileOperationPatternKind::File
13323 };
13324 kind == &expected_kind
13325 }) && self.glob.is_match(path)
13326 }
13327}
13328
13329#[derive(Default)]
13330struct LanguageServerWatchedPaths {
13331 worktree_paths: HashMap<WorktreeId, GlobSet>,
13332 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13333}
13334
13335#[derive(Default)]
13336struct LanguageServerWatchedPathsBuilder {
13337 worktree_paths: HashMap<WorktreeId, GlobSet>,
13338 abs_paths: HashMap<Arc<Path>, GlobSet>,
13339}
13340
13341impl LanguageServerWatchedPathsBuilder {
13342 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13343 self.worktree_paths.insert(worktree_id, glob_set);
13344 }
13345 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13346 self.abs_paths.insert(path, glob_set);
13347 }
13348 fn build(
13349 self,
13350 fs: Arc<dyn Fs>,
13351 language_server_id: LanguageServerId,
13352 cx: &mut Context<LspStore>,
13353 ) -> LanguageServerWatchedPaths {
13354 let lsp_store = cx.weak_entity();
13355
13356 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13357 let abs_paths = self
13358 .abs_paths
13359 .into_iter()
13360 .map(|(abs_path, globset)| {
13361 let task = cx.spawn({
13362 let abs_path = abs_path.clone();
13363 let fs = fs.clone();
13364
13365 let lsp_store = lsp_store.clone();
13366 async move |_, cx| {
13367 maybe!(async move {
13368 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13369 while let Some(update) = push_updates.0.next().await {
13370 let action = lsp_store
13371 .update(cx, |this, _| {
13372 let Some(local) = this.as_local() else {
13373 return ControlFlow::Break(());
13374 };
13375 let Some(watcher) = local
13376 .language_server_watched_paths
13377 .get(&language_server_id)
13378 else {
13379 return ControlFlow::Break(());
13380 };
13381 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13382 "Watched abs path is not registered with a watcher",
13383 );
13384 let matching_entries = update
13385 .into_iter()
13386 .filter(|event| globs.is_match(&event.path))
13387 .collect::<Vec<_>>();
13388 this.lsp_notify_abs_paths_changed(
13389 language_server_id,
13390 matching_entries,
13391 );
13392 ControlFlow::Continue(())
13393 })
13394 .ok()?;
13395
13396 if action.is_break() {
13397 break;
13398 }
13399 }
13400 Some(())
13401 })
13402 .await;
13403 }
13404 });
13405 (abs_path, (globset, task))
13406 })
13407 .collect();
13408 LanguageServerWatchedPaths {
13409 worktree_paths: self.worktree_paths,
13410 abs_paths,
13411 }
13412 }
13413}
13414
13415struct LspBufferSnapshot {
13416 version: i32,
13417 snapshot: TextBufferSnapshot,
13418}
13419
13420/// A prompt requested by LSP server.
13421#[derive(Clone, Debug)]
13422pub struct LanguageServerPromptRequest {
13423 pub level: PromptLevel,
13424 pub message: String,
13425 pub actions: Vec<MessageActionItem>,
13426 pub lsp_name: String,
13427 pub(crate) response_channel: Sender<MessageActionItem>,
13428}
13429
13430impl LanguageServerPromptRequest {
13431 pub async fn respond(self, index: usize) -> Option<()> {
13432 if let Some(response) = self.actions.into_iter().nth(index) {
13433 self.response_channel.send(response).await.ok()
13434 } else {
13435 None
13436 }
13437 }
13438}
13439impl PartialEq for LanguageServerPromptRequest {
13440 fn eq(&self, other: &Self) -> bool {
13441 self.message == other.message && self.actions == other.actions
13442 }
13443}
13444
13445#[derive(Clone, Debug, PartialEq)]
13446pub enum LanguageServerLogType {
13447 Log(MessageType),
13448 Trace { verbose_info: Option<String> },
13449 Rpc { received: bool },
13450}
13451
13452impl LanguageServerLogType {
13453 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13454 match self {
13455 Self::Log(log_type) => {
13456 use proto::log_message::LogLevel;
13457 let level = match *log_type {
13458 MessageType::ERROR => LogLevel::Error,
13459 MessageType::WARNING => LogLevel::Warning,
13460 MessageType::INFO => LogLevel::Info,
13461 MessageType::LOG => LogLevel::Log,
13462 other => {
13463 log::warn!("Unknown lsp log message type: {other:?}");
13464 LogLevel::Log
13465 }
13466 };
13467 proto::language_server_log::LogType::Log(proto::LogMessage {
13468 level: level as i32,
13469 })
13470 }
13471 Self::Trace { verbose_info } => {
13472 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13473 verbose_info: verbose_info.to_owned(),
13474 })
13475 }
13476 Self::Rpc { received } => {
13477 let kind = if *received {
13478 proto::rpc_message::Kind::Received
13479 } else {
13480 proto::rpc_message::Kind::Sent
13481 };
13482 let kind = kind as i32;
13483 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13484 }
13485 }
13486 }
13487
13488 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13489 use proto::log_message::LogLevel;
13490 use proto::rpc_message;
13491 match log_type {
13492 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13493 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13494 LogLevel::Error => MessageType::ERROR,
13495 LogLevel::Warning => MessageType::WARNING,
13496 LogLevel::Info => MessageType::INFO,
13497 LogLevel::Log => MessageType::LOG,
13498 },
13499 ),
13500 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13501 verbose_info: trace_message.verbose_info,
13502 },
13503 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13504 received: match rpc_message::Kind::from_i32(message.kind)
13505 .unwrap_or(rpc_message::Kind::Received)
13506 {
13507 rpc_message::Kind::Received => true,
13508 rpc_message::Kind::Sent => false,
13509 },
13510 },
13511 }
13512 }
13513}
13514
13515pub struct WorkspaceRefreshTask {
13516 refresh_tx: mpsc::Sender<()>,
13517 progress_tx: mpsc::Sender<()>,
13518 #[allow(dead_code)]
13519 task: Task<()>,
13520}
13521
13522pub enum LanguageServerState {
13523 Starting {
13524 startup: Task<Option<Arc<LanguageServer>>>,
13525 /// List of language servers that will be added to the workspace once it's initialization completes.
13526 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13527 },
13528
13529 Running {
13530 adapter: Arc<CachedLspAdapter>,
13531 server: Arc<LanguageServer>,
13532 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13533 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13534 },
13535}
13536
13537impl LanguageServerState {
13538 fn add_workspace_folder(&self, uri: Uri) {
13539 match self {
13540 LanguageServerState::Starting {
13541 pending_workspace_folders,
13542 ..
13543 } => {
13544 pending_workspace_folders.lock().insert(uri);
13545 }
13546 LanguageServerState::Running { server, .. } => {
13547 server.add_workspace_folder(uri);
13548 }
13549 }
13550 }
13551 fn _remove_workspace_folder(&self, uri: Uri) {
13552 match self {
13553 LanguageServerState::Starting {
13554 pending_workspace_folders,
13555 ..
13556 } => {
13557 pending_workspace_folders.lock().remove(&uri);
13558 }
13559 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13560 }
13561 }
13562}
13563
13564impl std::fmt::Debug for LanguageServerState {
13565 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13566 match self {
13567 LanguageServerState::Starting { .. } => {
13568 f.debug_struct("LanguageServerState::Starting").finish()
13569 }
13570 LanguageServerState::Running { .. } => {
13571 f.debug_struct("LanguageServerState::Running").finish()
13572 }
13573 }
13574 }
13575}
13576
13577#[derive(Clone, Debug, Serialize)]
13578pub struct LanguageServerProgress {
13579 pub is_disk_based_diagnostics_progress: bool,
13580 pub is_cancellable: bool,
13581 pub title: Option<String>,
13582 pub message: Option<String>,
13583 pub percentage: Option<usize>,
13584 #[serde(skip_serializing)]
13585 pub last_update_at: Instant,
13586}
13587
13588#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13589pub struct DiagnosticSummary {
13590 pub error_count: usize,
13591 pub warning_count: usize,
13592}
13593
13594impl DiagnosticSummary {
13595 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13596 let mut this = Self {
13597 error_count: 0,
13598 warning_count: 0,
13599 };
13600
13601 for entry in diagnostics {
13602 if entry.diagnostic.is_primary {
13603 match entry.diagnostic.severity {
13604 DiagnosticSeverity::ERROR => this.error_count += 1,
13605 DiagnosticSeverity::WARNING => this.warning_count += 1,
13606 _ => {}
13607 }
13608 }
13609 }
13610
13611 this
13612 }
13613
13614 pub fn is_empty(&self) -> bool {
13615 self.error_count == 0 && self.warning_count == 0
13616 }
13617
13618 pub fn to_proto(
13619 self,
13620 language_server_id: LanguageServerId,
13621 path: &RelPath,
13622 ) -> proto::DiagnosticSummary {
13623 proto::DiagnosticSummary {
13624 path: path.to_proto(),
13625 language_server_id: language_server_id.0 as u64,
13626 error_count: self.error_count as u32,
13627 warning_count: self.warning_count as u32,
13628 }
13629 }
13630}
13631
13632#[derive(Clone, Debug)]
13633pub enum CompletionDocumentation {
13634 /// There is no documentation for this completion.
13635 Undocumented,
13636 /// A single line of documentation.
13637 SingleLine(SharedString),
13638 /// Multiple lines of plain text documentation.
13639 MultiLinePlainText(SharedString),
13640 /// Markdown documentation.
13641 MultiLineMarkdown(SharedString),
13642 /// Both single line and multiple lines of plain text documentation.
13643 SingleLineAndMultiLinePlainText {
13644 single_line: SharedString,
13645 plain_text: Option<SharedString>,
13646 },
13647}
13648
13649impl CompletionDocumentation {
13650 #[cfg(any(test, feature = "test-support"))]
13651 pub fn text(&self) -> SharedString {
13652 match self {
13653 CompletionDocumentation::Undocumented => "".into(),
13654 CompletionDocumentation::SingleLine(s) => s.clone(),
13655 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13656 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13657 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13658 single_line.clone()
13659 }
13660 }
13661 }
13662}
13663
13664impl From<lsp::Documentation> for CompletionDocumentation {
13665 fn from(docs: lsp::Documentation) -> Self {
13666 match docs {
13667 lsp::Documentation::String(text) => {
13668 if text.lines().count() <= 1 {
13669 CompletionDocumentation::SingleLine(text.into())
13670 } else {
13671 CompletionDocumentation::MultiLinePlainText(text.into())
13672 }
13673 }
13674
13675 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13676 lsp::MarkupKind::PlainText => {
13677 if value.lines().count() <= 1 {
13678 CompletionDocumentation::SingleLine(value.into())
13679 } else {
13680 CompletionDocumentation::MultiLinePlainText(value.into())
13681 }
13682 }
13683
13684 lsp::MarkupKind::Markdown => {
13685 CompletionDocumentation::MultiLineMarkdown(value.into())
13686 }
13687 },
13688 }
13689 }
13690}
13691
13692pub enum ResolvedHint {
13693 Resolved(InlayHint),
13694 Resolving(Shared<Task<()>>),
13695}
13696
13697fn glob_literal_prefix(glob: &Path) -> PathBuf {
13698 glob.components()
13699 .take_while(|component| match component {
13700 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13701 _ => true,
13702 })
13703 .collect()
13704}
13705
13706pub struct SshLspAdapter {
13707 name: LanguageServerName,
13708 binary: LanguageServerBinary,
13709 initialization_options: Option<String>,
13710 code_action_kinds: Option<Vec<CodeActionKind>>,
13711}
13712
13713impl SshLspAdapter {
13714 pub fn new(
13715 name: LanguageServerName,
13716 binary: LanguageServerBinary,
13717 initialization_options: Option<String>,
13718 code_action_kinds: Option<String>,
13719 ) -> Self {
13720 Self {
13721 name,
13722 binary,
13723 initialization_options,
13724 code_action_kinds: code_action_kinds
13725 .as_ref()
13726 .and_then(|c| serde_json::from_str(c).ok()),
13727 }
13728 }
13729}
13730
13731impl LspInstaller for SshLspAdapter {
13732 type BinaryVersion = ();
13733 async fn check_if_user_installed(
13734 &self,
13735 _: &dyn LspAdapterDelegate,
13736 _: Option<Toolchain>,
13737 _: &AsyncApp,
13738 ) -> Option<LanguageServerBinary> {
13739 Some(self.binary.clone())
13740 }
13741
13742 async fn cached_server_binary(
13743 &self,
13744 _: PathBuf,
13745 _: &dyn LspAdapterDelegate,
13746 ) -> Option<LanguageServerBinary> {
13747 None
13748 }
13749
13750 async fn fetch_latest_server_version(
13751 &self,
13752 _: &dyn LspAdapterDelegate,
13753 _: bool,
13754 _: &mut AsyncApp,
13755 ) -> Result<()> {
13756 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13757 }
13758
13759 async fn fetch_server_binary(
13760 &self,
13761 _: (),
13762 _: PathBuf,
13763 _: &dyn LspAdapterDelegate,
13764 ) -> Result<LanguageServerBinary> {
13765 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13766 }
13767}
13768
13769#[async_trait(?Send)]
13770impl LspAdapter for SshLspAdapter {
13771 fn name(&self) -> LanguageServerName {
13772 self.name.clone()
13773 }
13774
13775 async fn initialization_options(
13776 self: Arc<Self>,
13777 _: &Arc<dyn LspAdapterDelegate>,
13778 ) -> Result<Option<serde_json::Value>> {
13779 let Some(options) = &self.initialization_options else {
13780 return Ok(None);
13781 };
13782 let result = serde_json::from_str(options)?;
13783 Ok(result)
13784 }
13785
13786 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13787 self.code_action_kinds.clone()
13788 }
13789}
13790
13791pub fn language_server_settings<'a>(
13792 delegate: &'a dyn LspAdapterDelegate,
13793 language: &LanguageServerName,
13794 cx: &'a App,
13795) -> Option<&'a LspSettings> {
13796 language_server_settings_for(
13797 SettingsLocation {
13798 worktree_id: delegate.worktree_id(),
13799 path: RelPath::empty(),
13800 },
13801 language,
13802 cx,
13803 )
13804}
13805
13806pub fn language_server_settings_for<'a>(
13807 location: SettingsLocation<'a>,
13808 language: &LanguageServerName,
13809 cx: &'a App,
13810) -> Option<&'a LspSettings> {
13811 ProjectSettings::get(Some(location), cx).lsp.get(language)
13812}
13813
13814pub struct LocalLspAdapterDelegate {
13815 lsp_store: WeakEntity<LspStore>,
13816 worktree: worktree::Snapshot,
13817 fs: Arc<dyn Fs>,
13818 http_client: Arc<dyn HttpClient>,
13819 language_registry: Arc<LanguageRegistry>,
13820 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13821}
13822
13823impl LocalLspAdapterDelegate {
13824 pub fn new(
13825 language_registry: Arc<LanguageRegistry>,
13826 environment: &Entity<ProjectEnvironment>,
13827 lsp_store: WeakEntity<LspStore>,
13828 worktree: &Entity<Worktree>,
13829 http_client: Arc<dyn HttpClient>,
13830 fs: Arc<dyn Fs>,
13831 cx: &mut App,
13832 ) -> Arc<Self> {
13833 let load_shell_env_task =
13834 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13835
13836 Arc::new(Self {
13837 lsp_store,
13838 worktree: worktree.read(cx).snapshot(),
13839 fs,
13840 http_client,
13841 language_registry,
13842 load_shell_env_task,
13843 })
13844 }
13845
13846 fn from_local_lsp(
13847 local: &LocalLspStore,
13848 worktree: &Entity<Worktree>,
13849 cx: &mut App,
13850 ) -> Arc<Self> {
13851 Self::new(
13852 local.languages.clone(),
13853 &local.environment,
13854 local.weak.clone(),
13855 worktree,
13856 local.http_client.clone(),
13857 local.fs.clone(),
13858 cx,
13859 )
13860 }
13861}
13862
13863#[async_trait]
13864impl LspAdapterDelegate for LocalLspAdapterDelegate {
13865 fn show_notification(&self, message: &str, cx: &mut App) {
13866 self.lsp_store
13867 .update(cx, |_, cx| {
13868 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13869 })
13870 .ok();
13871 }
13872
13873 fn http_client(&self) -> Arc<dyn HttpClient> {
13874 self.http_client.clone()
13875 }
13876
13877 fn worktree_id(&self) -> WorktreeId {
13878 self.worktree.id()
13879 }
13880
13881 fn worktree_root_path(&self) -> &Path {
13882 self.worktree.abs_path().as_ref()
13883 }
13884
13885 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13886 self.worktree.resolve_executable_path(path)
13887 }
13888
13889 async fn shell_env(&self) -> HashMap<String, String> {
13890 let task = self.load_shell_env_task.clone();
13891 task.await.unwrap_or_default()
13892 }
13893
13894 async fn npm_package_installed_version(
13895 &self,
13896 package_name: &str,
13897 ) -> Result<Option<(PathBuf, String)>> {
13898 let local_package_directory = self.worktree_root_path();
13899 let node_modules_directory = local_package_directory.join("node_modules");
13900
13901 if let Some(version) =
13902 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13903 {
13904 return Ok(Some((node_modules_directory, version)));
13905 }
13906 let Some(npm) = self.which("npm".as_ref()).await else {
13907 log::warn!(
13908 "Failed to find npm executable for {:?}",
13909 local_package_directory
13910 );
13911 return Ok(None);
13912 };
13913
13914 let env = self.shell_env().await;
13915 let output = util::command::new_smol_command(&npm)
13916 .args(["root", "-g"])
13917 .envs(env)
13918 .current_dir(local_package_directory)
13919 .output()
13920 .await?;
13921 let global_node_modules =
13922 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13923
13924 if let Some(version) =
13925 read_package_installed_version(global_node_modules.clone(), package_name).await?
13926 {
13927 return Ok(Some((global_node_modules, version)));
13928 }
13929 return Ok(None);
13930 }
13931
13932 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13933 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13934 if self.fs.is_file(&worktree_abs_path).await {
13935 worktree_abs_path.pop();
13936 }
13937
13938 let env = self.shell_env().await;
13939
13940 let shell_path = env.get("PATH").cloned();
13941
13942 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13943 }
13944
13945 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13946 let mut working_dir = self.worktree_root_path().to_path_buf();
13947 if self.fs.is_file(&working_dir).await {
13948 working_dir.pop();
13949 }
13950 let output = util::command::new_smol_command(&command.path)
13951 .args(command.arguments)
13952 .envs(command.env.clone().unwrap_or_default())
13953 .current_dir(working_dir)
13954 .output()
13955 .await?;
13956
13957 anyhow::ensure!(
13958 output.status.success(),
13959 "{}, stdout: {:?}, stderr: {:?}",
13960 output.status,
13961 String::from_utf8_lossy(&output.stdout),
13962 String::from_utf8_lossy(&output.stderr)
13963 );
13964 Ok(())
13965 }
13966
13967 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13968 self.language_registry
13969 .update_lsp_binary_status(server_name, status);
13970 }
13971
13972 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13973 self.language_registry
13974 .all_lsp_adapters()
13975 .into_iter()
13976 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13977 .collect()
13978 }
13979
13980 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13981 let dir = self.language_registry.language_server_download_dir(name)?;
13982
13983 if !dir.exists() {
13984 smol::fs::create_dir_all(&dir)
13985 .await
13986 .context("failed to create container directory")
13987 .log_err()?;
13988 }
13989
13990 Some(dir)
13991 }
13992
13993 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13994 let entry = self
13995 .worktree
13996 .entry_for_path(path)
13997 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13998 let abs_path = self.worktree.absolutize(&entry.path);
13999 self.fs.load(&abs_path).await
14000 }
14001}
14002
14003async fn populate_labels_for_symbols(
14004 symbols: Vec<CoreSymbol>,
14005 language_registry: &Arc<LanguageRegistry>,
14006 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14007 output: &mut Vec<Symbol>,
14008) {
14009 #[allow(clippy::mutable_key_type)]
14010 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14011
14012 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14013 for symbol in symbols {
14014 let Some(file_name) = symbol.path.file_name() else {
14015 continue;
14016 };
14017 let language = language_registry
14018 .load_language_for_file_path(Path::new(file_name))
14019 .await
14020 .ok()
14021 .or_else(|| {
14022 unknown_paths.insert(file_name.into());
14023 None
14024 });
14025 symbols_by_language
14026 .entry(language)
14027 .or_default()
14028 .push(symbol);
14029 }
14030
14031 for unknown_path in unknown_paths {
14032 log::info!("no language found for symbol in file {unknown_path:?}");
14033 }
14034
14035 let mut label_params = Vec::new();
14036 for (language, mut symbols) in symbols_by_language {
14037 label_params.clear();
14038 label_params.extend(
14039 symbols
14040 .iter_mut()
14041 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14042 );
14043
14044 let mut labels = Vec::new();
14045 if let Some(language) = language {
14046 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14047 language_registry
14048 .lsp_adapters(&language.name())
14049 .first()
14050 .cloned()
14051 });
14052 if let Some(lsp_adapter) = lsp_adapter {
14053 labels = lsp_adapter
14054 .labels_for_symbols(&label_params, &language)
14055 .await
14056 .log_err()
14057 .unwrap_or_default();
14058 }
14059 }
14060
14061 for ((symbol, (name, _)), label) in symbols
14062 .into_iter()
14063 .zip(label_params.drain(..))
14064 .zip(labels.into_iter().chain(iter::repeat(None)))
14065 {
14066 output.push(Symbol {
14067 language_server_name: symbol.language_server_name,
14068 source_worktree_id: symbol.source_worktree_id,
14069 source_language_server_id: symbol.source_language_server_id,
14070 path: symbol.path,
14071 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14072 name,
14073 kind: symbol.kind,
14074 range: symbol.range,
14075 });
14076 }
14077 }
14078}
14079
14080fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14081 match server.capabilities().text_document_sync.as_ref()? {
14082 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14083 // Server wants didSave but didn't specify includeText.
14084 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14085 // Server doesn't want didSave at all.
14086 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14087 // Server provided SaveOptions.
14088 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14089 Some(save_options.include_text.unwrap_or(false))
14090 }
14091 },
14092 // We do not have any save info. Kind affects didChange only.
14093 lsp::TextDocumentSyncCapability::Kind(_) => None,
14094 }
14095}
14096
14097/// Completion items are displayed in a `UniformList`.
14098/// Usually, those items are single-line strings, but in LSP responses,
14099/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14100/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14101/// 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,
14102/// breaking the completions menu presentation.
14103///
14104/// 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.
14105fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14106 let mut new_text = String::with_capacity(label.text.len());
14107 let mut offset_map = vec![0; label.text.len() + 1];
14108 let mut last_char_was_space = false;
14109 let mut new_idx = 0;
14110 let chars = label.text.char_indices().fuse();
14111 let mut newlines_removed = false;
14112
14113 for (idx, c) in chars {
14114 offset_map[idx] = new_idx;
14115
14116 match c {
14117 '\n' if last_char_was_space => {
14118 newlines_removed = true;
14119 }
14120 '\t' | ' ' if last_char_was_space => {}
14121 '\n' if !last_char_was_space => {
14122 new_text.push(' ');
14123 new_idx += 1;
14124 last_char_was_space = true;
14125 newlines_removed = true;
14126 }
14127 ' ' | '\t' => {
14128 new_text.push(' ');
14129 new_idx += 1;
14130 last_char_was_space = true;
14131 }
14132 _ => {
14133 new_text.push(c);
14134 new_idx += c.len_utf8();
14135 last_char_was_space = false;
14136 }
14137 }
14138 }
14139 offset_map[label.text.len()] = new_idx;
14140
14141 // Only modify the label if newlines were removed.
14142 if !newlines_removed {
14143 return;
14144 }
14145
14146 let last_index = new_idx;
14147 let mut run_ranges_errors = Vec::new();
14148 label.runs.retain_mut(|(range, _)| {
14149 match offset_map.get(range.start) {
14150 Some(&start) => range.start = start,
14151 None => {
14152 run_ranges_errors.push(range.clone());
14153 return false;
14154 }
14155 }
14156
14157 match offset_map.get(range.end) {
14158 Some(&end) => range.end = end,
14159 None => {
14160 run_ranges_errors.push(range.clone());
14161 range.end = last_index;
14162 }
14163 }
14164 true
14165 });
14166 if !run_ranges_errors.is_empty() {
14167 log::error!(
14168 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14169 label.text
14170 );
14171 }
14172
14173 let mut wrong_filter_range = None;
14174 if label.filter_range == (0..label.text.len()) {
14175 label.filter_range = 0..new_text.len();
14176 } else {
14177 let mut original_filter_range = Some(label.filter_range.clone());
14178 match offset_map.get(label.filter_range.start) {
14179 Some(&start) => label.filter_range.start = start,
14180 None => {
14181 wrong_filter_range = original_filter_range.take();
14182 label.filter_range.start = last_index;
14183 }
14184 }
14185
14186 match offset_map.get(label.filter_range.end) {
14187 Some(&end) => label.filter_range.end = end,
14188 None => {
14189 wrong_filter_range = original_filter_range.take();
14190 label.filter_range.end = last_index;
14191 }
14192 }
14193 }
14194 if let Some(wrong_filter_range) = wrong_filter_range {
14195 log::error!(
14196 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14197 label.text
14198 );
14199 }
14200
14201 label.text = new_text;
14202}
14203
14204#[cfg(test)]
14205mod tests {
14206 use language::HighlightId;
14207
14208 use super::*;
14209
14210 #[test]
14211 fn test_glob_literal_prefix() {
14212 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14213 assert_eq!(
14214 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14215 Path::new("node_modules")
14216 );
14217 assert_eq!(
14218 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14219 Path::new("foo")
14220 );
14221 assert_eq!(
14222 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14223 Path::new("foo/bar/baz.js")
14224 );
14225
14226 #[cfg(target_os = "windows")]
14227 {
14228 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14229 assert_eq!(
14230 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14231 Path::new("node_modules")
14232 );
14233 assert_eq!(
14234 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14235 Path::new("foo")
14236 );
14237 assert_eq!(
14238 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14239 Path::new("foo/bar/baz.js")
14240 );
14241 }
14242 }
14243
14244 #[test]
14245 fn test_multi_len_chars_normalization() {
14246 let mut label = CodeLabel::new(
14247 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14248 0..6,
14249 vec![(0..6, HighlightId(1))],
14250 );
14251 ensure_uniform_list_compatible_label(&mut label);
14252 assert_eq!(
14253 label,
14254 CodeLabel::new(
14255 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14256 0..6,
14257 vec![(0..6, HighlightId(1))],
14258 )
14259 );
14260 }
14261}