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 settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default, Debug)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = &settings.binary
567 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
568 {
569 let settings = settings.clone();
570
571 return cx.background_spawn(async move {
572 let mut env = delegate.shell_env().await;
573 env.extend(settings.env.unwrap_or_default());
574
575 Ok(LanguageServerBinary {
576 // if `path` is absolute, `.join()` will keep it unmodified
577 path: delegate.worktree_root_path().join(path),
578 env: Some(env),
579 arguments: settings
580 .arguments
581 .unwrap_or_default()
582 .iter()
583 .map(Into::into)
584 .collect(),
585 })
586 });
587 }
588 let lsp_binary_options = LanguageServerBinaryOptions {
589 allow_path_lookup: !settings
590 .binary
591 .as_ref()
592 .and_then(|b| b.ignore_system_version)
593 .unwrap_or_default(),
594 allow_binary_download,
595 pre_release: settings
596 .fetch
597 .as_ref()
598 .and_then(|f| f.pre_release)
599 .unwrap_or(false),
600 };
601
602 cx.spawn(async move |cx| {
603 let binary_result = adapter
604 .clone()
605 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
606 .await;
607
608 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
609
610 let mut binary = binary_result?;
611 let mut shell_env = delegate.shell_env().await;
612
613 shell_env.extend(binary.env.unwrap_or_default());
614
615 if let Some(settings) = settings.binary.as_ref() {
616 if let Some(arguments) = &settings.arguments {
617 binary.arguments = arguments.iter().map(Into::into).collect();
618 }
619 if let Some(env) = &settings.env {
620 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
621 }
622 }
623
624 binary.env = Some(shell_env);
625 Ok(binary)
626 })
627 }
628
629 fn setup_lsp_messages(
630 lsp_store: WeakEntity<LspStore>,
631 language_server: &LanguageServer,
632 delegate: Arc<dyn LspAdapterDelegate>,
633 adapter: Arc<CachedLspAdapter>,
634 ) {
635 let name = language_server.name();
636 let server_id = language_server.server_id();
637 language_server
638 .on_notification::<lsp::notification::PublishDiagnostics, _>({
639 let adapter = adapter.clone();
640 let this = lsp_store.clone();
641 move |mut params, cx| {
642 let adapter = adapter.clone();
643 if let Some(this) = this.upgrade() {
644 this.update(cx, |this, cx| {
645 {
646 let buffer = params
647 .uri
648 .to_file_path()
649 .map(|file_path| this.get_buffer(&file_path, cx))
650 .ok()
651 .flatten();
652 adapter.process_diagnostics(&mut params, server_id, buffer);
653 }
654
655 this.merge_lsp_diagnostics(
656 DiagnosticSourceKind::Pushed,
657 vec![DocumentDiagnosticsUpdate {
658 server_id,
659 diagnostics: params,
660 result_id: None,
661 disk_based_sources: Cow::Borrowed(
662 &adapter.disk_based_diagnostic_sources,
663 ),
664 }],
665 |_, diagnostic, cx| match diagnostic.source_kind {
666 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
667 adapter.retain_old_diagnostic(diagnostic, cx)
668 }
669 DiagnosticSourceKind::Pulled => true,
670 },
671 cx,
672 )
673 .log_err();
674 })
675 .ok();
676 }
677 }
678 })
679 .detach();
680 language_server
681 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
682 let adapter = adapter.adapter.clone();
683 let delegate = delegate.clone();
684 let this = lsp_store.clone();
685 move |params, cx| {
686 let adapter = adapter.clone();
687 let delegate = delegate.clone();
688 let this = this.clone();
689 let mut cx = cx.clone();
690 async move {
691 let toolchain_for_id = this
692 .update(&mut cx, |this, _| {
693 this.as_local()?.language_server_ids.iter().find_map(
694 |(seed, value)| {
695 (value.id == server_id).then(|| seed.toolchain.clone())
696 },
697 )
698 })?
699 .context("Expected the LSP store to be in a local mode")?;
700 let workspace_config = Self::workspace_configuration_for_adapter(
701 adapter.clone(),
702 &delegate,
703 toolchain_for_id,
704 &mut cx,
705 )
706 .await?;
707
708 Ok(params
709 .items
710 .into_iter()
711 .map(|item| {
712 if let Some(section) = &item.section {
713 workspace_config
714 .get(section)
715 .cloned()
716 .unwrap_or(serde_json::Value::Null)
717 } else {
718 workspace_config.clone()
719 }
720 })
721 .collect())
722 }
723 }
724 })
725 .detach();
726
727 language_server
728 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
729 let this = lsp_store.clone();
730 move |_, cx| {
731 let this = this.clone();
732 let cx = cx.clone();
733 async move {
734 let Some(server) =
735 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
736 else {
737 return Ok(None);
738 };
739 let root = server.workspace_folders();
740 Ok(Some(
741 root.into_iter()
742 .map(|uri| WorkspaceFolder {
743 uri,
744 name: Default::default(),
745 })
746 .collect(),
747 ))
748 }
749 }
750 })
751 .detach();
752 // Even though we don't have handling for these requests, respond to them to
753 // avoid stalling any language server like `gopls` which waits for a response
754 // to these requests when initializing.
755 language_server
756 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
757 let this = lsp_store.clone();
758 move |params, cx| {
759 let this = this.clone();
760 let mut cx = cx.clone();
761 async move {
762 this.update(&mut cx, |this, _| {
763 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
764 {
765 status
766 .progress_tokens
767 .insert(ProgressToken::from_lsp(params.token));
768 }
769 })?;
770
771 Ok(())
772 }
773 }
774 })
775 .detach();
776
777 language_server
778 .on_request::<lsp::request::RegisterCapability, _, _>({
779 let lsp_store = lsp_store.clone();
780 move |params, cx| {
781 let lsp_store = lsp_store.clone();
782 let mut cx = cx.clone();
783 async move {
784 lsp_store
785 .update(&mut cx, |lsp_store, cx| {
786 if lsp_store.as_local().is_some() {
787 match lsp_store
788 .register_server_capabilities(server_id, params, cx)
789 {
790 Ok(()) => {}
791 Err(e) => {
792 log::error!(
793 "Failed to register server capabilities: {e:#}"
794 );
795 }
796 };
797 }
798 })
799 .ok();
800 Ok(())
801 }
802 }
803 })
804 .detach();
805
806 language_server
807 .on_request::<lsp::request::UnregisterCapability, _, _>({
808 let lsp_store = lsp_store.clone();
809 move |params, cx| {
810 let lsp_store = lsp_store.clone();
811 let mut cx = cx.clone();
812 async move {
813 lsp_store
814 .update(&mut cx, |lsp_store, cx| {
815 if lsp_store.as_local().is_some() {
816 match lsp_store
817 .unregister_server_capabilities(server_id, params, cx)
818 {
819 Ok(()) => {}
820 Err(e) => {
821 log::error!(
822 "Failed to unregister server capabilities: {e:#}"
823 );
824 }
825 }
826 }
827 })
828 .ok();
829 Ok(())
830 }
831 }
832 })
833 .detach();
834
835 language_server
836 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
837 let this = lsp_store.clone();
838 move |params, cx| {
839 let mut cx = cx.clone();
840 let this = this.clone();
841 async move {
842 LocalLspStore::on_lsp_workspace_edit(
843 this.clone(),
844 params,
845 server_id,
846 &mut cx,
847 )
848 .await
849 }
850 }
851 })
852 .detach();
853
854 language_server
855 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
856 let lsp_store = lsp_store.clone();
857 let request_id = Arc::new(AtomicUsize::new(0));
858 move |(), cx| {
859 let lsp_store = lsp_store.clone();
860 let request_id = request_id.clone();
861 let mut cx = cx.clone();
862 async move {
863 lsp_store
864 .update(&mut cx, |lsp_store, cx| {
865 let request_id =
866 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
867 cx.emit(LspStoreEvent::RefreshInlayHints {
868 server_id,
869 request_id,
870 });
871 lsp_store
872 .downstream_client
873 .as_ref()
874 .map(|(client, project_id)| {
875 client.send(proto::RefreshInlayHints {
876 project_id: *project_id,
877 server_id: server_id.to_proto(),
878 request_id: request_id.map(|id| id as u64),
879 })
880 })
881 })?
882 .transpose()?;
883 Ok(())
884 }
885 }
886 })
887 .detach();
888
889 language_server
890 .on_request::<lsp::request::CodeLensRefresh, _, _>({
891 let this = lsp_store.clone();
892 move |(), cx| {
893 let this = this.clone();
894 let mut cx = cx.clone();
895 async move {
896 this.update(&mut cx, |this, cx| {
897 cx.emit(LspStoreEvent::RefreshCodeLens);
898 this.downstream_client.as_ref().map(|(client, project_id)| {
899 client.send(proto::RefreshCodeLens {
900 project_id: *project_id,
901 })
902 })
903 })?
904 .transpose()?;
905 Ok(())
906 }
907 }
908 })
909 .detach();
910
911 language_server
912 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
913 let this = lsp_store.clone();
914 move |(), cx| {
915 let this = this.clone();
916 let mut cx = cx.clone();
917 async move {
918 this.update(&mut cx, |lsp_store, _| {
919 lsp_store.pull_workspace_diagnostics(server_id);
920 lsp_store
921 .downstream_client
922 .as_ref()
923 .map(|(client, project_id)| {
924 client.send(proto::PullWorkspaceDiagnostics {
925 project_id: *project_id,
926 server_id: server_id.to_proto(),
927 })
928 })
929 })?
930 .transpose()?;
931 Ok(())
932 }
933 }
934 })
935 .detach();
936
937 language_server
938 .on_request::<lsp::request::ShowMessageRequest, _, _>({
939 let this = lsp_store.clone();
940 let name = name.to_string();
941 move |params, cx| {
942 let this = this.clone();
943 let name = name.to_string();
944 let mut cx = cx.clone();
945 async move {
946 let actions = params.actions.unwrap_or_default();
947 let (tx, rx) = smol::channel::bounded(1);
948 let request = LanguageServerPromptRequest {
949 level: match params.typ {
950 lsp::MessageType::ERROR => PromptLevel::Critical,
951 lsp::MessageType::WARNING => PromptLevel::Warning,
952 _ => PromptLevel::Info,
953 },
954 message: params.message,
955 actions,
956 response_channel: tx,
957 lsp_name: name.clone(),
958 };
959
960 let did_update = this
961 .update(&mut cx, |_, cx| {
962 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
963 })
964 .is_ok();
965 if did_update {
966 let response = rx.recv().await.ok();
967 Ok(response)
968 } else {
969 Ok(None)
970 }
971 }
972 }
973 })
974 .detach();
975 language_server
976 .on_notification::<lsp::notification::ShowMessage, _>({
977 let this = lsp_store.clone();
978 let name = name.to_string();
979 move |params, cx| {
980 let this = this.clone();
981 let name = name.to_string();
982 let mut cx = cx.clone();
983
984 let (tx, _) = smol::channel::bounded(1);
985 let request = LanguageServerPromptRequest {
986 level: match params.typ {
987 lsp::MessageType::ERROR => PromptLevel::Critical,
988 lsp::MessageType::WARNING => PromptLevel::Warning,
989 _ => PromptLevel::Info,
990 },
991 message: params.message,
992 actions: vec![],
993 response_channel: tx,
994 lsp_name: name,
995 };
996
997 let _ = this.update(&mut cx, |_, cx| {
998 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
999 });
1000 }
1001 })
1002 .detach();
1003
1004 let disk_based_diagnostics_progress_token =
1005 adapter.disk_based_diagnostics_progress_token.clone();
1006
1007 language_server
1008 .on_notification::<lsp::notification::Progress, _>({
1009 let this = lsp_store.clone();
1010 move |params, cx| {
1011 if let Some(this) = this.upgrade() {
1012 this.update(cx, |this, cx| {
1013 this.on_lsp_progress(
1014 params,
1015 server_id,
1016 disk_based_diagnostics_progress_token.clone(),
1017 cx,
1018 );
1019 })
1020 .ok();
1021 }
1022 }
1023 })
1024 .detach();
1025
1026 language_server
1027 .on_notification::<lsp::notification::LogMessage, _>({
1028 let this = lsp_store.clone();
1029 move |params, cx| {
1030 if let Some(this) = this.upgrade() {
1031 this.update(cx, |_, cx| {
1032 cx.emit(LspStoreEvent::LanguageServerLog(
1033 server_id,
1034 LanguageServerLogType::Log(params.typ),
1035 params.message,
1036 ));
1037 })
1038 .ok();
1039 }
1040 }
1041 })
1042 .detach();
1043
1044 language_server
1045 .on_notification::<lsp::notification::LogTrace, _>({
1046 let this = lsp_store.clone();
1047 move |params, cx| {
1048 let mut cx = cx.clone();
1049 if let Some(this) = this.upgrade() {
1050 this.update(&mut cx, |_, cx| {
1051 cx.emit(LspStoreEvent::LanguageServerLog(
1052 server_id,
1053 LanguageServerLogType::Trace {
1054 verbose_info: params.verbose,
1055 },
1056 params.message,
1057 ));
1058 })
1059 .ok();
1060 }
1061 }
1062 })
1063 .detach();
1064
1065 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1066 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1067 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1068 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1069 }
1070
1071 fn shutdown_language_servers_on_quit(
1072 &mut self,
1073 _: &mut Context<LspStore>,
1074 ) -> impl Future<Output = ()> + use<> {
1075 let shutdown_futures = self
1076 .language_servers
1077 .drain()
1078 .map(|(_, server_state)| Self::shutdown_server(server_state))
1079 .collect::<Vec<_>>();
1080
1081 async move {
1082 join_all(shutdown_futures).await;
1083 }
1084 }
1085
1086 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1087 match server_state {
1088 LanguageServerState::Running { server, .. } => {
1089 if let Some(shutdown) = server.shutdown() {
1090 shutdown.await;
1091 }
1092 }
1093 LanguageServerState::Starting { startup, .. } => {
1094 if let Some(server) = startup.await
1095 && let Some(shutdown) = server.shutdown()
1096 {
1097 shutdown.await;
1098 }
1099 }
1100 }
1101 Ok(())
1102 }
1103
1104 fn language_servers_for_worktree(
1105 &self,
1106 worktree_id: WorktreeId,
1107 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1108 self.language_server_ids
1109 .iter()
1110 .filter_map(move |(seed, state)| {
1111 if seed.worktree_id != worktree_id {
1112 return None;
1113 }
1114
1115 if let Some(LanguageServerState::Running { server, .. }) =
1116 self.language_servers.get(&state.id)
1117 {
1118 Some(server)
1119 } else {
1120 None
1121 }
1122 })
1123 }
1124
1125 fn language_server_ids_for_project_path(
1126 &self,
1127 project_path: ProjectPath,
1128 language: &Language,
1129 cx: &mut App,
1130 ) -> Vec<LanguageServerId> {
1131 let Some(worktree) = self
1132 .worktree_store
1133 .read(cx)
1134 .worktree_for_id(project_path.worktree_id, cx)
1135 else {
1136 return Vec::new();
1137 };
1138 let delegate: Arc<dyn ManifestDelegate> =
1139 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1140
1141 self.lsp_tree
1142 .get(
1143 project_path,
1144 language.name(),
1145 language.manifest(),
1146 &delegate,
1147 cx,
1148 )
1149 .collect::<Vec<_>>()
1150 }
1151
1152 fn language_server_ids_for_buffer(
1153 &self,
1154 buffer: &Buffer,
1155 cx: &mut App,
1156 ) -> Vec<LanguageServerId> {
1157 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1158 let worktree_id = file.worktree_id(cx);
1159
1160 let path: Arc<RelPath> = file
1161 .path()
1162 .parent()
1163 .map(Arc::from)
1164 .unwrap_or_else(|| file.path().clone());
1165 let worktree_path = ProjectPath { worktree_id, path };
1166 self.language_server_ids_for_project_path(worktree_path, language, cx)
1167 } else {
1168 Vec::new()
1169 }
1170 }
1171
1172 fn language_servers_for_buffer<'a>(
1173 &'a self,
1174 buffer: &'a Buffer,
1175 cx: &'a mut App,
1176 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1177 self.language_server_ids_for_buffer(buffer, cx)
1178 .into_iter()
1179 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1180 LanguageServerState::Running {
1181 adapter, server, ..
1182 } => Some((adapter, server)),
1183 _ => None,
1184 })
1185 }
1186
1187 async fn execute_code_action_kind_locally(
1188 lsp_store: WeakEntity<LspStore>,
1189 mut buffers: Vec<Entity<Buffer>>,
1190 kind: CodeActionKind,
1191 push_to_history: bool,
1192 cx: &mut AsyncApp,
1193 ) -> anyhow::Result<ProjectTransaction> {
1194 // Do not allow multiple concurrent code actions requests for the
1195 // same buffer.
1196 lsp_store.update(cx, |this, cx| {
1197 let this = this.as_local_mut().unwrap();
1198 buffers.retain(|buffer| {
1199 this.buffers_being_formatted
1200 .insert(buffer.read(cx).remote_id())
1201 });
1202 })?;
1203 let _cleanup = defer({
1204 let this = lsp_store.clone();
1205 let mut cx = cx.clone();
1206 let buffers = &buffers;
1207 move || {
1208 this.update(&mut cx, |this, cx| {
1209 let this = this.as_local_mut().unwrap();
1210 for buffer in buffers {
1211 this.buffers_being_formatted
1212 .remove(&buffer.read(cx).remote_id());
1213 }
1214 })
1215 .ok();
1216 }
1217 });
1218 let mut project_transaction = ProjectTransaction::default();
1219
1220 for buffer in &buffers {
1221 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1222 buffer.update(cx, |buffer, cx| {
1223 lsp_store
1224 .as_local()
1225 .unwrap()
1226 .language_servers_for_buffer(buffer, cx)
1227 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1228 .collect::<Vec<_>>()
1229 })
1230 })?;
1231 for (_, language_server) in adapters_and_servers.iter() {
1232 let actions = Self::get_server_code_actions_from_action_kinds(
1233 &lsp_store,
1234 language_server.server_id(),
1235 vec![kind.clone()],
1236 buffer,
1237 cx,
1238 )
1239 .await?;
1240 Self::execute_code_actions_on_server(
1241 &lsp_store,
1242 language_server,
1243 actions,
1244 push_to_history,
1245 &mut project_transaction,
1246 cx,
1247 )
1248 .await?;
1249 }
1250 }
1251 Ok(project_transaction)
1252 }
1253
1254 async fn format_locally(
1255 lsp_store: WeakEntity<LspStore>,
1256 mut buffers: Vec<FormattableBuffer>,
1257 push_to_history: bool,
1258 trigger: FormatTrigger,
1259 logger: zlog::Logger,
1260 cx: &mut AsyncApp,
1261 ) -> anyhow::Result<ProjectTransaction> {
1262 // Do not allow multiple concurrent formatting requests for the
1263 // same buffer.
1264 lsp_store.update(cx, |this, cx| {
1265 let this = this.as_local_mut().unwrap();
1266 buffers.retain(|buffer| {
1267 this.buffers_being_formatted
1268 .insert(buffer.handle.read(cx).remote_id())
1269 });
1270 })?;
1271
1272 let _cleanup = defer({
1273 let this = lsp_store.clone();
1274 let mut cx = cx.clone();
1275 let buffers = &buffers;
1276 move || {
1277 this.update(&mut cx, |this, cx| {
1278 let this = this.as_local_mut().unwrap();
1279 for buffer in buffers {
1280 this.buffers_being_formatted
1281 .remove(&buffer.handle.read(cx).remote_id());
1282 }
1283 })
1284 .ok();
1285 }
1286 });
1287
1288 let mut project_transaction = ProjectTransaction::default();
1289
1290 for buffer in &buffers {
1291 zlog::debug!(
1292 logger =>
1293 "formatting buffer '{:?}'",
1294 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1295 );
1296 // Create an empty transaction to hold all of the formatting edits.
1297 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1298 // ensure no transactions created while formatting are
1299 // grouped with the previous transaction in the history
1300 // based on the transaction group interval
1301 buffer.finalize_last_transaction();
1302 buffer
1303 .start_transaction()
1304 .context("transaction already open")?;
1305 buffer.end_transaction(cx);
1306 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1307 buffer.finalize_last_transaction();
1308 anyhow::Ok(transaction_id)
1309 })??;
1310
1311 let result = Self::format_buffer_locally(
1312 lsp_store.clone(),
1313 buffer,
1314 formatting_transaction_id,
1315 trigger,
1316 logger,
1317 cx,
1318 )
1319 .await;
1320
1321 buffer.handle.update(cx, |buffer, cx| {
1322 let Some(formatting_transaction) =
1323 buffer.get_transaction(formatting_transaction_id).cloned()
1324 else {
1325 zlog::warn!(logger => "no formatting transaction");
1326 return;
1327 };
1328 if formatting_transaction.edit_ids.is_empty() {
1329 zlog::debug!(logger => "no changes made while formatting");
1330 buffer.forget_transaction(formatting_transaction_id);
1331 return;
1332 }
1333 if !push_to_history {
1334 zlog::trace!(logger => "forgetting format transaction");
1335 buffer.forget_transaction(formatting_transaction.id);
1336 }
1337 project_transaction
1338 .0
1339 .insert(cx.entity(), formatting_transaction);
1340 })?;
1341
1342 result?;
1343 }
1344
1345 Ok(project_transaction)
1346 }
1347
1348 async fn format_buffer_locally(
1349 lsp_store: WeakEntity<LspStore>,
1350 buffer: &FormattableBuffer,
1351 formatting_transaction_id: clock::Lamport,
1352 trigger: FormatTrigger,
1353 logger: zlog::Logger,
1354 cx: &mut AsyncApp,
1355 ) -> Result<()> {
1356 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1357 buffer.handle.update(cx, |buffer, cx| {
1358 let adapters_and_servers = lsp_store
1359 .as_local()
1360 .unwrap()
1361 .language_servers_for_buffer(buffer, cx)
1362 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1363 .collect::<Vec<_>>();
1364 let settings =
1365 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1366 .into_owned();
1367 (adapters_and_servers, settings)
1368 })
1369 })?;
1370
1371 /// Apply edits to the buffer that will become part of the formatting transaction.
1372 /// Fails if the buffer has been edited since the start of that transaction.
1373 fn extend_formatting_transaction(
1374 buffer: &FormattableBuffer,
1375 formatting_transaction_id: text::TransactionId,
1376 cx: &mut AsyncApp,
1377 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1378 ) -> anyhow::Result<()> {
1379 buffer.handle.update(cx, |buffer, cx| {
1380 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1381 if last_transaction_id != Some(formatting_transaction_id) {
1382 anyhow::bail!("Buffer edited while formatting. Aborting")
1383 }
1384 buffer.start_transaction();
1385 operation(buffer, cx);
1386 if let Some(transaction_id) = buffer.end_transaction(cx) {
1387 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1388 }
1389 Ok(())
1390 })?
1391 }
1392
1393 // handle whitespace formatting
1394 if settings.remove_trailing_whitespace_on_save {
1395 zlog::trace!(logger => "removing trailing whitespace");
1396 let diff = buffer
1397 .handle
1398 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1399 .await;
1400 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1401 buffer.apply_diff(diff, cx);
1402 })?;
1403 }
1404
1405 if settings.ensure_final_newline_on_save {
1406 zlog::trace!(logger => "ensuring final newline");
1407 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1408 buffer.ensure_final_newline(cx);
1409 })?;
1410 }
1411
1412 // Formatter for `code_actions_on_format` that runs before
1413 // the rest of the formatters
1414 let mut code_actions_on_format_formatters = None;
1415 let should_run_code_actions_on_format = !matches!(
1416 (trigger, &settings.format_on_save),
1417 (FormatTrigger::Save, &FormatOnSave::Off)
1418 );
1419 if should_run_code_actions_on_format {
1420 let have_code_actions_to_run_on_format = settings
1421 .code_actions_on_format
1422 .values()
1423 .any(|enabled| *enabled);
1424 if have_code_actions_to_run_on_format {
1425 zlog::trace!(logger => "going to run code actions on format");
1426 code_actions_on_format_formatters = Some(
1427 settings
1428 .code_actions_on_format
1429 .iter()
1430 .filter_map(|(action, enabled)| enabled.then_some(action))
1431 .cloned()
1432 .map(Formatter::CodeAction)
1433 .collect::<Vec<_>>(),
1434 );
1435 }
1436 }
1437
1438 let formatters = match (trigger, &settings.format_on_save) {
1439 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1440 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1441 settings.formatter.as_ref()
1442 }
1443 };
1444
1445 let formatters = code_actions_on_format_formatters
1446 .iter()
1447 .flatten()
1448 .chain(formatters);
1449
1450 for formatter in formatters {
1451 let formatter = if formatter == &Formatter::Auto {
1452 if settings.prettier.allowed {
1453 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1454 &Formatter::Prettier
1455 } else {
1456 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1457 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1458 }
1459 } else {
1460 formatter
1461 };
1462 match formatter {
1463 Formatter::Auto => unreachable!("Auto resolved above"),
1464 Formatter::Prettier => {
1465 let logger = zlog::scoped!(logger => "prettier");
1466 zlog::trace!(logger => "formatting");
1467 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1468
1469 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1470 lsp_store.prettier_store().unwrap().downgrade()
1471 })?;
1472 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1473 .await
1474 .transpose()?;
1475 let Some(diff) = diff else {
1476 zlog::trace!(logger => "No changes");
1477 continue;
1478 };
1479
1480 extend_formatting_transaction(
1481 buffer,
1482 formatting_transaction_id,
1483 cx,
1484 |buffer, cx| {
1485 buffer.apply_diff(diff, cx);
1486 },
1487 )?;
1488 }
1489 Formatter::External { command, arguments } => {
1490 let logger = zlog::scoped!(logger => "command");
1491 zlog::trace!(logger => "formatting");
1492 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1493
1494 let diff = Self::format_via_external_command(
1495 buffer,
1496 command.as_ref(),
1497 arguments.as_deref(),
1498 cx,
1499 )
1500 .await
1501 .with_context(|| {
1502 format!("Failed to format buffer via external command: {}", command)
1503 })?;
1504 let Some(diff) = diff else {
1505 zlog::trace!(logger => "No changes");
1506 continue;
1507 };
1508
1509 extend_formatting_transaction(
1510 buffer,
1511 formatting_transaction_id,
1512 cx,
1513 |buffer, cx| {
1514 buffer.apply_diff(diff, cx);
1515 },
1516 )?;
1517 }
1518 Formatter::LanguageServer(specifier) => {
1519 let logger = zlog::scoped!(logger => "language-server");
1520 zlog::trace!(logger => "formatting");
1521 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1522
1523 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1524 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1525 continue;
1526 };
1527
1528 let language_server = match specifier {
1529 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1530 adapters_and_servers.iter().find_map(|(adapter, server)| {
1531 if adapter.name.0.as_ref() == name {
1532 Some(server.clone())
1533 } else {
1534 None
1535 }
1536 })
1537 }
1538 settings::LanguageServerFormatterSpecifier::Current => {
1539 adapters_and_servers.first().map(|e| e.1.clone())
1540 }
1541 };
1542
1543 let Some(language_server) = language_server else {
1544 log::debug!(
1545 "No language server found to format buffer '{:?}'. Skipping",
1546 buffer_path_abs.as_path().to_string_lossy()
1547 );
1548 continue;
1549 };
1550
1551 zlog::trace!(
1552 logger =>
1553 "Formatting buffer '{:?}' using language server '{:?}'",
1554 buffer_path_abs.as_path().to_string_lossy(),
1555 language_server.name()
1556 );
1557
1558 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1559 zlog::trace!(logger => "formatting ranges");
1560 Self::format_ranges_via_lsp(
1561 &lsp_store,
1562 &buffer.handle,
1563 ranges,
1564 buffer_path_abs,
1565 &language_server,
1566 &settings,
1567 cx,
1568 )
1569 .await
1570 .context("Failed to format ranges via language server")?
1571 } else {
1572 zlog::trace!(logger => "formatting full");
1573 Self::format_via_lsp(
1574 &lsp_store,
1575 &buffer.handle,
1576 buffer_path_abs,
1577 &language_server,
1578 &settings,
1579 cx,
1580 )
1581 .await
1582 .context("failed to format via language server")?
1583 };
1584
1585 if edits.is_empty() {
1586 zlog::trace!(logger => "No changes");
1587 continue;
1588 }
1589 extend_formatting_transaction(
1590 buffer,
1591 formatting_transaction_id,
1592 cx,
1593 |buffer, cx| {
1594 buffer.edit(edits, None, cx);
1595 },
1596 )?;
1597 }
1598 Formatter::CodeAction(code_action_name) => {
1599 let logger = zlog::scoped!(logger => "code-actions");
1600 zlog::trace!(logger => "formatting");
1601 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1602
1603 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1604 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1605 continue;
1606 };
1607
1608 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1609 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1610
1611 let mut actions_and_servers = Vec::new();
1612
1613 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1614 let actions_result = Self::get_server_code_actions_from_action_kinds(
1615 &lsp_store,
1616 language_server.server_id(),
1617 vec![code_action_kind.clone()],
1618 &buffer.handle,
1619 cx,
1620 )
1621 .await
1622 .with_context(|| {
1623 format!(
1624 "Failed to resolve code action {:?} with language server {}",
1625 code_action_kind,
1626 language_server.name()
1627 )
1628 });
1629 let Ok(actions) = actions_result else {
1630 // note: it may be better to set result to the error and break formatters here
1631 // but for now we try to execute the actions that we can resolve and skip the rest
1632 zlog::error!(
1633 logger =>
1634 "Failed to resolve code action {:?} with language server {}",
1635 code_action_kind,
1636 language_server.name()
1637 );
1638 continue;
1639 };
1640 for action in actions {
1641 actions_and_servers.push((action, index));
1642 }
1643 }
1644
1645 if actions_and_servers.is_empty() {
1646 zlog::warn!(logger => "No code actions were resolved, continuing");
1647 continue;
1648 }
1649
1650 'actions: for (mut action, server_index) in actions_and_servers {
1651 let server = &adapters_and_servers[server_index].1;
1652
1653 let describe_code_action = |action: &CodeAction| {
1654 format!(
1655 "code action '{}' with title \"{}\" on server {}",
1656 action
1657 .lsp_action
1658 .action_kind()
1659 .unwrap_or("unknown".into())
1660 .as_str(),
1661 action.lsp_action.title(),
1662 server.name(),
1663 )
1664 };
1665
1666 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1667
1668 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1669 zlog::error!(
1670 logger =>
1671 "Failed to resolve {}. Error: {}",
1672 describe_code_action(&action),
1673 err
1674 );
1675 continue;
1676 }
1677
1678 if let Some(edit) = action.lsp_action.edit().cloned() {
1679 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1680 // but filters out and logs warnings for code actions that require unreasonably
1681 // difficult handling on our part, such as:
1682 // - applying edits that call commands
1683 // which can result in arbitrary workspace edits being sent from the server that
1684 // have no way of being tied back to the command that initiated them (i.e. we
1685 // can't know which edits are part of the format request, or if the server is done sending
1686 // actions in response to the command)
1687 // - actions that create/delete/modify/rename files other than the one we are formatting
1688 // as we then would need to handle such changes correctly in the local history as well
1689 // as the remote history through the ProjectTransaction
1690 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1691 // Supporting these actions is not impossible, but not supported as of yet.
1692 if edit.changes.is_none() && edit.document_changes.is_none() {
1693 zlog::trace!(
1694 logger =>
1695 "No changes for code action. Skipping {}",
1696 describe_code_action(&action),
1697 );
1698 continue;
1699 }
1700
1701 let mut operations = Vec::new();
1702 if let Some(document_changes) = edit.document_changes {
1703 match document_changes {
1704 lsp::DocumentChanges::Edits(edits) => operations.extend(
1705 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1706 ),
1707 lsp::DocumentChanges::Operations(ops) => operations = ops,
1708 }
1709 } else if let Some(changes) = edit.changes {
1710 operations.extend(changes.into_iter().map(|(uri, edits)| {
1711 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1712 text_document:
1713 lsp::OptionalVersionedTextDocumentIdentifier {
1714 uri,
1715 version: None,
1716 },
1717 edits: edits.into_iter().map(Edit::Plain).collect(),
1718 })
1719 }));
1720 }
1721
1722 let mut edits = Vec::with_capacity(operations.len());
1723
1724 if operations.is_empty() {
1725 zlog::trace!(
1726 logger =>
1727 "No changes for code action. Skipping {}",
1728 describe_code_action(&action),
1729 );
1730 continue;
1731 }
1732 for operation in operations {
1733 let op = match operation {
1734 lsp::DocumentChangeOperation::Edit(op) => op,
1735 lsp::DocumentChangeOperation::Op(_) => {
1736 zlog::warn!(
1737 logger =>
1738 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1739 describe_code_action(&action),
1740 );
1741 continue 'actions;
1742 }
1743 };
1744 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1745 zlog::warn!(
1746 logger =>
1747 "Failed to convert URI '{:?}' to file path. Skipping {}",
1748 &op.text_document.uri,
1749 describe_code_action(&action),
1750 );
1751 continue 'actions;
1752 };
1753 if &file_path != buffer_path_abs {
1754 zlog::warn!(
1755 logger =>
1756 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1757 file_path,
1758 buffer_path_abs,
1759 describe_code_action(&action),
1760 );
1761 continue 'actions;
1762 }
1763
1764 let mut lsp_edits = Vec::new();
1765 for edit in op.edits {
1766 match edit {
1767 Edit::Plain(edit) => {
1768 if !lsp_edits.contains(&edit) {
1769 lsp_edits.push(edit);
1770 }
1771 }
1772 Edit::Annotated(edit) => {
1773 if !lsp_edits.contains(&edit.text_edit) {
1774 lsp_edits.push(edit.text_edit);
1775 }
1776 }
1777 Edit::Snippet(_) => {
1778 zlog::warn!(
1779 logger =>
1780 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1781 describe_code_action(&action),
1782 );
1783 continue 'actions;
1784 }
1785 }
1786 }
1787 let edits_result = lsp_store
1788 .update(cx, |lsp_store, cx| {
1789 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1790 &buffer.handle,
1791 lsp_edits,
1792 server.server_id(),
1793 op.text_document.version,
1794 cx,
1795 )
1796 })?
1797 .await;
1798 let Ok(resolved_edits) = edits_result else {
1799 zlog::warn!(
1800 logger =>
1801 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1802 buffer_path_abs.as_path(),
1803 describe_code_action(&action),
1804 );
1805 continue 'actions;
1806 };
1807 edits.extend(resolved_edits);
1808 }
1809
1810 if edits.is_empty() {
1811 zlog::warn!(logger => "No edits resolved from LSP");
1812 continue;
1813 }
1814
1815 extend_formatting_transaction(
1816 buffer,
1817 formatting_transaction_id,
1818 cx,
1819 |buffer, cx| {
1820 zlog::info!(
1821 "Applying edits {edits:?}. Content: {:?}",
1822 buffer.text()
1823 );
1824 buffer.edit(edits, None, cx);
1825 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1826 },
1827 )?;
1828 }
1829
1830 if let Some(command) = action.lsp_action.command() {
1831 zlog::warn!(
1832 logger =>
1833 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1834 &command.command,
1835 );
1836
1837 // bail early if command is invalid
1838 let server_capabilities = server.capabilities();
1839 let available_commands = server_capabilities
1840 .execute_command_provider
1841 .as_ref()
1842 .map(|options| options.commands.as_slice())
1843 .unwrap_or_default();
1844 if !available_commands.contains(&command.command) {
1845 zlog::warn!(
1846 logger =>
1847 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1848 command.command,
1849 server.name(),
1850 );
1851 continue;
1852 }
1853
1854 // noop so we just ensure buffer hasn't been edited since resolving code actions
1855 extend_formatting_transaction(
1856 buffer,
1857 formatting_transaction_id,
1858 cx,
1859 |_, _| {},
1860 )?;
1861 zlog::info!(logger => "Executing command {}", &command.command);
1862
1863 lsp_store.update(cx, |this, _| {
1864 this.as_local_mut()
1865 .unwrap()
1866 .last_workspace_edits_by_language_server
1867 .remove(&server.server_id());
1868 })?;
1869
1870 let execute_command_result = server
1871 .request::<lsp::request::ExecuteCommand>(
1872 lsp::ExecuteCommandParams {
1873 command: command.command.clone(),
1874 arguments: command.arguments.clone().unwrap_or_default(),
1875 ..Default::default()
1876 },
1877 )
1878 .await
1879 .into_response();
1880
1881 if execute_command_result.is_err() {
1882 zlog::error!(
1883 logger =>
1884 "Failed to execute command '{}' as part of {}",
1885 &command.command,
1886 describe_code_action(&action),
1887 );
1888 continue 'actions;
1889 }
1890
1891 let mut project_transaction_command =
1892 lsp_store.update(cx, |this, _| {
1893 this.as_local_mut()
1894 .unwrap()
1895 .last_workspace_edits_by_language_server
1896 .remove(&server.server_id())
1897 .unwrap_or_default()
1898 })?;
1899
1900 if let Some(transaction) =
1901 project_transaction_command.0.remove(&buffer.handle)
1902 {
1903 zlog::trace!(
1904 logger =>
1905 "Successfully captured {} edits that resulted from command {}",
1906 transaction.edit_ids.len(),
1907 &command.command,
1908 );
1909 let transaction_id_project_transaction = transaction.id;
1910 buffer.handle.update(cx, |buffer, _| {
1911 // it may have been removed from history if push_to_history was
1912 // false in deserialize_workspace_edit. If so push it so we
1913 // can merge it with the format transaction
1914 // and pop the combined transaction off the history stack
1915 // later if push_to_history is false
1916 if buffer.get_transaction(transaction.id).is_none() {
1917 buffer.push_transaction(transaction, Instant::now());
1918 }
1919 buffer.merge_transactions(
1920 transaction_id_project_transaction,
1921 formatting_transaction_id,
1922 );
1923 })?;
1924 }
1925
1926 if !project_transaction_command.0.is_empty() {
1927 let mut extra_buffers = String::new();
1928 for buffer in project_transaction_command.0.keys() {
1929 buffer
1930 .read_with(cx, |b, cx| {
1931 if let Some(path) = b.project_path(cx) {
1932 if !extra_buffers.is_empty() {
1933 extra_buffers.push_str(", ");
1934 }
1935 extra_buffers.push_str(path.path.as_unix_str());
1936 }
1937 })
1938 .ok();
1939 }
1940 zlog::warn!(
1941 logger =>
1942 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1943 &command.command,
1944 extra_buffers,
1945 );
1946 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1947 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1948 // add it so it's included, and merge it into the format transaction when its created later
1949 }
1950 }
1951 }
1952 }
1953 }
1954 }
1955
1956 Ok(())
1957 }
1958
1959 pub async fn format_ranges_via_lsp(
1960 this: &WeakEntity<LspStore>,
1961 buffer_handle: &Entity<Buffer>,
1962 ranges: &[Range<Anchor>],
1963 abs_path: &Path,
1964 language_server: &Arc<LanguageServer>,
1965 settings: &LanguageSettings,
1966 cx: &mut AsyncApp,
1967 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1968 let capabilities = &language_server.capabilities();
1969 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1970 if range_formatting_provider == Some(&OneOf::Left(false)) {
1971 anyhow::bail!(
1972 "{} language server does not support range formatting",
1973 language_server.name()
1974 );
1975 }
1976
1977 let uri = file_path_to_lsp_url(abs_path)?;
1978 let text_document = lsp::TextDocumentIdentifier::new(uri);
1979
1980 let lsp_edits = {
1981 let mut lsp_ranges = Vec::new();
1982 this.update(cx, |_this, cx| {
1983 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1984 // not have been sent to the language server. This seems like a fairly systemic
1985 // issue, though, the resolution probably is not specific to formatting.
1986 //
1987 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1988 // LSP.
1989 let snapshot = buffer_handle.read(cx).snapshot();
1990 for range in ranges {
1991 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1992 }
1993 anyhow::Ok(())
1994 })??;
1995
1996 let mut edits = None;
1997 for range in lsp_ranges {
1998 if let Some(mut edit) = language_server
1999 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2000 text_document: text_document.clone(),
2001 range,
2002 options: lsp_command::lsp_formatting_options(settings),
2003 work_done_progress_params: Default::default(),
2004 })
2005 .await
2006 .into_response()?
2007 {
2008 edits.get_or_insert_with(Vec::new).append(&mut edit);
2009 }
2010 }
2011 edits
2012 };
2013
2014 if let Some(lsp_edits) = lsp_edits {
2015 this.update(cx, |this, cx| {
2016 this.as_local_mut().unwrap().edits_from_lsp(
2017 buffer_handle,
2018 lsp_edits,
2019 language_server.server_id(),
2020 None,
2021 cx,
2022 )
2023 })?
2024 .await
2025 } else {
2026 Ok(Vec::with_capacity(0))
2027 }
2028 }
2029
2030 async fn format_via_lsp(
2031 this: &WeakEntity<LspStore>,
2032 buffer: &Entity<Buffer>,
2033 abs_path: &Path,
2034 language_server: &Arc<LanguageServer>,
2035 settings: &LanguageSettings,
2036 cx: &mut AsyncApp,
2037 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2038 let logger = zlog::scoped!("lsp_format");
2039 zlog::debug!(logger => "Formatting via LSP");
2040
2041 let uri = file_path_to_lsp_url(abs_path)?;
2042 let text_document = lsp::TextDocumentIdentifier::new(uri);
2043 let capabilities = &language_server.capabilities();
2044
2045 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2046 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2047
2048 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2049 let _timer = zlog::time!(logger => "format-full");
2050 language_server
2051 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2052 text_document,
2053 options: lsp_command::lsp_formatting_options(settings),
2054 work_done_progress_params: Default::default(),
2055 })
2056 .await
2057 .into_response()?
2058 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2059 let _timer = zlog::time!(logger => "format-range");
2060 let buffer_start = lsp::Position::new(0, 0);
2061 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2062 language_server
2063 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2064 text_document: text_document.clone(),
2065 range: lsp::Range::new(buffer_start, buffer_end),
2066 options: lsp_command::lsp_formatting_options(settings),
2067 work_done_progress_params: Default::default(),
2068 })
2069 .await
2070 .into_response()?
2071 } else {
2072 None
2073 };
2074
2075 if let Some(lsp_edits) = lsp_edits {
2076 this.update(cx, |this, cx| {
2077 this.as_local_mut().unwrap().edits_from_lsp(
2078 buffer,
2079 lsp_edits,
2080 language_server.server_id(),
2081 None,
2082 cx,
2083 )
2084 })?
2085 .await
2086 } else {
2087 Ok(Vec::with_capacity(0))
2088 }
2089 }
2090
2091 async fn format_via_external_command(
2092 buffer: &FormattableBuffer,
2093 command: &str,
2094 arguments: Option<&[String]>,
2095 cx: &mut AsyncApp,
2096 ) -> Result<Option<Diff>> {
2097 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2098 let file = File::from_dyn(buffer.file())?;
2099 let worktree = file.worktree.read(cx);
2100 let mut worktree_path = worktree.abs_path().to_path_buf();
2101 if worktree.root_entry()?.is_file() {
2102 worktree_path.pop();
2103 }
2104 Some(worktree_path)
2105 })?;
2106
2107 let mut child = util::command::new_smol_command(command);
2108
2109 if let Some(buffer_env) = buffer.env.as_ref() {
2110 child.envs(buffer_env);
2111 }
2112
2113 if let Some(working_dir_path) = working_dir_path {
2114 child.current_dir(working_dir_path);
2115 }
2116
2117 if let Some(arguments) = arguments {
2118 child.args(arguments.iter().map(|arg| {
2119 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2120 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2121 } else {
2122 arg.replace("{buffer_path}", "Untitled")
2123 }
2124 }));
2125 }
2126
2127 let mut child = child
2128 .stdin(smol::process::Stdio::piped())
2129 .stdout(smol::process::Stdio::piped())
2130 .stderr(smol::process::Stdio::piped())
2131 .spawn()?;
2132
2133 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2134 let text = buffer
2135 .handle
2136 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2137 for chunk in text.chunks() {
2138 stdin.write_all(chunk.as_bytes()).await?;
2139 }
2140 stdin.flush().await?;
2141
2142 let output = child.output().await?;
2143 anyhow::ensure!(
2144 output.status.success(),
2145 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2146 output.status.code(),
2147 String::from_utf8_lossy(&output.stdout),
2148 String::from_utf8_lossy(&output.stderr),
2149 );
2150
2151 let stdout = String::from_utf8(output.stdout)?;
2152 Ok(Some(
2153 buffer
2154 .handle
2155 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2156 .await,
2157 ))
2158 }
2159
2160 async fn try_resolve_code_action(
2161 lang_server: &LanguageServer,
2162 action: &mut CodeAction,
2163 ) -> anyhow::Result<()> {
2164 match &mut action.lsp_action {
2165 LspAction::Action(lsp_action) => {
2166 if !action.resolved
2167 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2168 && lsp_action.data.is_some()
2169 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2170 {
2171 *lsp_action = Box::new(
2172 lang_server
2173 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2174 .await
2175 .into_response()?,
2176 );
2177 }
2178 }
2179 LspAction::CodeLens(lens) => {
2180 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2181 *lens = lang_server
2182 .request::<lsp::request::CodeLensResolve>(lens.clone())
2183 .await
2184 .into_response()?;
2185 }
2186 }
2187 LspAction::Command(_) => {}
2188 }
2189
2190 action.resolved = true;
2191 anyhow::Ok(())
2192 }
2193
2194 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2195 let buffer = buffer_handle.read(cx);
2196
2197 let file = buffer.file().cloned();
2198
2199 let Some(file) = File::from_dyn(file.as_ref()) else {
2200 return;
2201 };
2202 if !file.is_local() {
2203 return;
2204 }
2205 let path = ProjectPath::from_file(file, cx);
2206 let worktree_id = file.worktree_id(cx);
2207 let language = buffer.language().cloned();
2208
2209 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2210 for (server_id, diagnostics) in
2211 diagnostics.get(file.path()).cloned().unwrap_or_default()
2212 {
2213 self.update_buffer_diagnostics(
2214 buffer_handle,
2215 server_id,
2216 None,
2217 None,
2218 diagnostics,
2219 Vec::new(),
2220 cx,
2221 )
2222 .log_err();
2223 }
2224 }
2225 let Some(language) = language else {
2226 return;
2227 };
2228 let Some(snapshot) = self
2229 .worktree_store
2230 .read(cx)
2231 .worktree_for_id(worktree_id, cx)
2232 .map(|worktree| worktree.read(cx).snapshot())
2233 else {
2234 return;
2235 };
2236 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2237
2238 for server_id in
2239 self.lsp_tree
2240 .get(path, language.name(), language.manifest(), &delegate, cx)
2241 {
2242 let server = self
2243 .language_servers
2244 .get(&server_id)
2245 .and_then(|server_state| {
2246 if let LanguageServerState::Running { server, .. } = server_state {
2247 Some(server.clone())
2248 } else {
2249 None
2250 }
2251 });
2252 let server = match server {
2253 Some(server) => server,
2254 None => continue,
2255 };
2256
2257 buffer_handle.update(cx, |buffer, cx| {
2258 buffer.set_completion_triggers(
2259 server.server_id(),
2260 server
2261 .capabilities()
2262 .completion_provider
2263 .as_ref()
2264 .and_then(|provider| {
2265 provider
2266 .trigger_characters
2267 .as_ref()
2268 .map(|characters| characters.iter().cloned().collect())
2269 })
2270 .unwrap_or_default(),
2271 cx,
2272 );
2273 });
2274 }
2275 }
2276
2277 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2278 buffer.update(cx, |buffer, cx| {
2279 let Some(language) = buffer.language() else {
2280 return;
2281 };
2282 let path = ProjectPath {
2283 worktree_id: old_file.worktree_id(cx),
2284 path: old_file.path.clone(),
2285 };
2286 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2287 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2288 buffer.set_completion_triggers(server_id, Default::default(), cx);
2289 }
2290 });
2291 }
2292
2293 fn update_buffer_diagnostics(
2294 &mut self,
2295 buffer: &Entity<Buffer>,
2296 server_id: LanguageServerId,
2297 result_id: Option<String>,
2298 version: Option<i32>,
2299 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2300 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2301 cx: &mut Context<LspStore>,
2302 ) -> Result<()> {
2303 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2304 Ordering::Equal
2305 .then_with(|| b.is_primary.cmp(&a.is_primary))
2306 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2307 .then_with(|| a.severity.cmp(&b.severity))
2308 .then_with(|| a.message.cmp(&b.message))
2309 }
2310
2311 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2312 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2313 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2314
2315 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2316 Ordering::Equal
2317 .then_with(|| a.range.start.cmp(&b.range.start))
2318 .then_with(|| b.range.end.cmp(&a.range.end))
2319 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2320 });
2321
2322 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2323
2324 let edits_since_save = std::cell::LazyCell::new(|| {
2325 let saved_version = buffer.read(cx).saved_version();
2326 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2327 });
2328
2329 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2330
2331 for (new_diagnostic, entry) in diagnostics {
2332 let start;
2333 let end;
2334 if new_diagnostic && entry.diagnostic.is_disk_based {
2335 // Some diagnostics are based on files on disk instead of buffers'
2336 // current contents. Adjust these diagnostics' ranges to reflect
2337 // any unsaved edits.
2338 // Do not alter the reused ones though, as their coordinates were stored as anchors
2339 // and were properly adjusted on reuse.
2340 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2341 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2342 } else {
2343 start = entry.range.start;
2344 end = entry.range.end;
2345 }
2346
2347 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2348 ..snapshot.clip_point_utf16(end, Bias::Right);
2349
2350 // Expand empty ranges by one codepoint
2351 if range.start == range.end {
2352 // This will be go to the next boundary when being clipped
2353 range.end.column += 1;
2354 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2355 if range.start == range.end && range.end.column > 0 {
2356 range.start.column -= 1;
2357 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2358 }
2359 }
2360
2361 sanitized_diagnostics.push(DiagnosticEntry {
2362 range,
2363 diagnostic: entry.diagnostic,
2364 });
2365 }
2366 drop(edits_since_save);
2367
2368 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2369 buffer.update(cx, |buffer, cx| {
2370 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2371 self.buffer_pull_diagnostics_result_ids
2372 .entry(server_id)
2373 .or_default()
2374 .insert(abs_path, result_id);
2375 }
2376
2377 buffer.update_diagnostics(server_id, set, cx)
2378 });
2379
2380 Ok(())
2381 }
2382
2383 fn register_language_server_for_invisible_worktree(
2384 &mut self,
2385 worktree: &Entity<Worktree>,
2386 language_server_id: LanguageServerId,
2387 cx: &mut App,
2388 ) {
2389 let worktree = worktree.read(cx);
2390 let worktree_id = worktree.id();
2391 debug_assert!(!worktree.is_visible());
2392 let Some(mut origin_seed) = self
2393 .language_server_ids
2394 .iter()
2395 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2396 else {
2397 return;
2398 };
2399 origin_seed.worktree_id = worktree_id;
2400 self.language_server_ids
2401 .entry(origin_seed)
2402 .or_insert_with(|| UnifiedLanguageServer {
2403 id: language_server_id,
2404 project_roots: Default::default(),
2405 });
2406 }
2407
2408 fn register_buffer_with_language_servers(
2409 &mut self,
2410 buffer_handle: &Entity<Buffer>,
2411 only_register_servers: HashSet<LanguageServerSelector>,
2412 cx: &mut Context<LspStore>,
2413 ) {
2414 let buffer = buffer_handle.read(cx);
2415 let buffer_id = buffer.remote_id();
2416
2417 let Some(file) = File::from_dyn(buffer.file()) else {
2418 return;
2419 };
2420 if !file.is_local() {
2421 return;
2422 }
2423
2424 let abs_path = file.abs_path(cx);
2425 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2426 return;
2427 };
2428 let initial_snapshot = buffer.text_snapshot();
2429 let worktree_id = file.worktree_id(cx);
2430
2431 let Some(language) = buffer.language().cloned() else {
2432 return;
2433 };
2434 let path: Arc<RelPath> = file
2435 .path()
2436 .parent()
2437 .map(Arc::from)
2438 .unwrap_or_else(|| file.path().clone());
2439 let Some(worktree) = self
2440 .worktree_store
2441 .read(cx)
2442 .worktree_for_id(worktree_id, cx)
2443 else {
2444 return;
2445 };
2446 let language_name = language.name();
2447 let (reused, delegate, servers) = self
2448 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2449 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2450 .unwrap_or_else(|| {
2451 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2452 let delegate: Arc<dyn ManifestDelegate> =
2453 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2454
2455 let servers = self
2456 .lsp_tree
2457 .walk(
2458 ProjectPath { worktree_id, path },
2459 language.name(),
2460 language.manifest(),
2461 &delegate,
2462 cx,
2463 )
2464 .collect::<Vec<_>>();
2465 (false, lsp_delegate, servers)
2466 });
2467 let servers_and_adapters = servers
2468 .into_iter()
2469 .filter_map(|server_node| {
2470 if reused && server_node.server_id().is_none() {
2471 return None;
2472 }
2473 if !only_register_servers.is_empty() {
2474 if let Some(server_id) = server_node.server_id()
2475 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2476 {
2477 return None;
2478 }
2479 if let Some(name) = server_node.name()
2480 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2481 {
2482 return None;
2483 }
2484 }
2485
2486 let server_id = server_node.server_id_or_init(|disposition| {
2487 let path = &disposition.path;
2488
2489 {
2490 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2491
2492 let server_id = self.get_or_insert_language_server(
2493 &worktree,
2494 delegate.clone(),
2495 disposition,
2496 &language_name,
2497 cx,
2498 );
2499
2500 if let Some(state) = self.language_servers.get(&server_id)
2501 && let Ok(uri) = uri
2502 {
2503 state.add_workspace_folder(uri);
2504 };
2505 server_id
2506 }
2507 })?;
2508 let server_state = self.language_servers.get(&server_id)?;
2509 if let LanguageServerState::Running {
2510 server, adapter, ..
2511 } = server_state
2512 {
2513 Some((server.clone(), adapter.clone()))
2514 } else {
2515 None
2516 }
2517 })
2518 .collect::<Vec<_>>();
2519 for (server, adapter) in servers_and_adapters {
2520 buffer_handle.update(cx, |buffer, cx| {
2521 buffer.set_completion_triggers(
2522 server.server_id(),
2523 server
2524 .capabilities()
2525 .completion_provider
2526 .as_ref()
2527 .and_then(|provider| {
2528 provider
2529 .trigger_characters
2530 .as_ref()
2531 .map(|characters| characters.iter().cloned().collect())
2532 })
2533 .unwrap_or_default(),
2534 cx,
2535 );
2536 });
2537
2538 let snapshot = LspBufferSnapshot {
2539 version: 0,
2540 snapshot: initial_snapshot.clone(),
2541 };
2542
2543 let mut registered = false;
2544 self.buffer_snapshots
2545 .entry(buffer_id)
2546 .or_default()
2547 .entry(server.server_id())
2548 .or_insert_with(|| {
2549 registered = true;
2550 server.register_buffer(
2551 uri.clone(),
2552 adapter.language_id(&language.name()),
2553 0,
2554 initial_snapshot.text(),
2555 );
2556
2557 vec![snapshot]
2558 });
2559
2560 self.buffers_opened_in_servers
2561 .entry(buffer_id)
2562 .or_default()
2563 .insert(server.server_id());
2564 if registered {
2565 cx.emit(LspStoreEvent::LanguageServerUpdate {
2566 language_server_id: server.server_id(),
2567 name: None,
2568 message: proto::update_language_server::Variant::RegisteredForBuffer(
2569 proto::RegisteredForBuffer {
2570 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2571 buffer_id: buffer_id.to_proto(),
2572 },
2573 ),
2574 });
2575 }
2576 }
2577 }
2578
2579 fn reuse_existing_language_server<'lang_name>(
2580 &self,
2581 server_tree: &LanguageServerTree,
2582 worktree: &Entity<Worktree>,
2583 language_name: &'lang_name LanguageName,
2584 cx: &mut App,
2585 ) -> Option<(
2586 Arc<LocalLspAdapterDelegate>,
2587 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2588 )> {
2589 if worktree.read(cx).is_visible() {
2590 return None;
2591 }
2592
2593 let worktree_store = self.worktree_store.read(cx);
2594 let servers = server_tree
2595 .instances
2596 .iter()
2597 .filter(|(worktree_id, _)| {
2598 worktree_store
2599 .worktree_for_id(**worktree_id, cx)
2600 .is_some_and(|worktree| worktree.read(cx).is_visible())
2601 })
2602 .flat_map(|(worktree_id, servers)| {
2603 servers
2604 .roots
2605 .iter()
2606 .flat_map(|(_, language_servers)| language_servers)
2607 .map(move |(_, (server_node, server_languages))| {
2608 (worktree_id, server_node, server_languages)
2609 })
2610 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2611 .map(|(worktree_id, server_node, _)| {
2612 (
2613 *worktree_id,
2614 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2615 )
2616 })
2617 })
2618 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2619 acc.entry(worktree_id)
2620 .or_insert_with(Vec::new)
2621 .push(server_node);
2622 acc
2623 })
2624 .into_values()
2625 .max_by_key(|servers| servers.len())?;
2626
2627 let worktree_id = worktree.read(cx).id();
2628 let apply = move |tree: &mut LanguageServerTree| {
2629 for server_node in &servers {
2630 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2631 }
2632 servers
2633 };
2634
2635 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2636 Some((delegate, apply))
2637 }
2638
2639 pub(crate) fn unregister_old_buffer_from_language_servers(
2640 &mut self,
2641 buffer: &Entity<Buffer>,
2642 old_file: &File,
2643 cx: &mut App,
2644 ) {
2645 let old_path = match old_file.as_local() {
2646 Some(local) => local.abs_path(cx),
2647 None => return,
2648 };
2649
2650 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2651 debug_panic!("{old_path:?} is not parseable as an URI");
2652 return;
2653 };
2654 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2655 }
2656
2657 pub(crate) fn unregister_buffer_from_language_servers(
2658 &mut self,
2659 buffer: &Entity<Buffer>,
2660 file_url: &lsp::Uri,
2661 cx: &mut App,
2662 ) {
2663 buffer.update(cx, |buffer, cx| {
2664 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2665
2666 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2667 language_server.unregister_buffer(file_url.clone());
2668 }
2669 });
2670 }
2671
2672 fn buffer_snapshot_for_lsp_version(
2673 &mut self,
2674 buffer: &Entity<Buffer>,
2675 server_id: LanguageServerId,
2676 version: Option<i32>,
2677 cx: &App,
2678 ) -> Result<TextBufferSnapshot> {
2679 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2680
2681 if let Some(version) = version {
2682 let buffer_id = buffer.read(cx).remote_id();
2683 let snapshots = if let Some(snapshots) = self
2684 .buffer_snapshots
2685 .get_mut(&buffer_id)
2686 .and_then(|m| m.get_mut(&server_id))
2687 {
2688 snapshots
2689 } else if version == 0 {
2690 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2691 // We detect this case and treat it as if the version was `None`.
2692 return Ok(buffer.read(cx).text_snapshot());
2693 } else {
2694 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2695 };
2696
2697 let found_snapshot = snapshots
2698 .binary_search_by_key(&version, |e| e.version)
2699 .map(|ix| snapshots[ix].snapshot.clone())
2700 .map_err(|_| {
2701 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2702 })?;
2703
2704 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2705 Ok(found_snapshot)
2706 } else {
2707 Ok((buffer.read(cx)).text_snapshot())
2708 }
2709 }
2710
2711 async fn get_server_code_actions_from_action_kinds(
2712 lsp_store: &WeakEntity<LspStore>,
2713 language_server_id: LanguageServerId,
2714 code_action_kinds: Vec<lsp::CodeActionKind>,
2715 buffer: &Entity<Buffer>,
2716 cx: &mut AsyncApp,
2717 ) -> Result<Vec<CodeAction>> {
2718 let actions = lsp_store
2719 .update(cx, move |this, cx| {
2720 let request = GetCodeActions {
2721 range: text::Anchor::MIN..text::Anchor::MAX,
2722 kinds: Some(code_action_kinds),
2723 };
2724 let server = LanguageServerToQuery::Other(language_server_id);
2725 this.request_lsp(buffer.clone(), server, request, cx)
2726 })?
2727 .await?;
2728 Ok(actions)
2729 }
2730
2731 pub async fn execute_code_actions_on_server(
2732 lsp_store: &WeakEntity<LspStore>,
2733 language_server: &Arc<LanguageServer>,
2734
2735 actions: Vec<CodeAction>,
2736 push_to_history: bool,
2737 project_transaction: &mut ProjectTransaction,
2738 cx: &mut AsyncApp,
2739 ) -> anyhow::Result<()> {
2740 for mut action in actions {
2741 Self::try_resolve_code_action(language_server, &mut action)
2742 .await
2743 .context("resolving a formatting code action")?;
2744
2745 if let Some(edit) = action.lsp_action.edit() {
2746 if edit.changes.is_none() && edit.document_changes.is_none() {
2747 continue;
2748 }
2749
2750 let new = Self::deserialize_workspace_edit(
2751 lsp_store.upgrade().context("project dropped")?,
2752 edit.clone(),
2753 push_to_history,
2754 language_server.clone(),
2755 cx,
2756 )
2757 .await?;
2758 project_transaction.0.extend(new.0);
2759 }
2760
2761 if let Some(command) = action.lsp_action.command() {
2762 let server_capabilities = language_server.capabilities();
2763 let available_commands = server_capabilities
2764 .execute_command_provider
2765 .as_ref()
2766 .map(|options| options.commands.as_slice())
2767 .unwrap_or_default();
2768 if available_commands.contains(&command.command) {
2769 lsp_store.update(cx, |lsp_store, _| {
2770 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2771 mode.last_workspace_edits_by_language_server
2772 .remove(&language_server.server_id());
2773 }
2774 })?;
2775
2776 language_server
2777 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2778 command: command.command.clone(),
2779 arguments: command.arguments.clone().unwrap_or_default(),
2780 ..Default::default()
2781 })
2782 .await
2783 .into_response()
2784 .context("execute command")?;
2785
2786 lsp_store.update(cx, |this, _| {
2787 if let LspStoreMode::Local(mode) = &mut this.mode {
2788 project_transaction.0.extend(
2789 mode.last_workspace_edits_by_language_server
2790 .remove(&language_server.server_id())
2791 .unwrap_or_default()
2792 .0,
2793 )
2794 }
2795 })?;
2796 } else {
2797 log::warn!(
2798 "Cannot execute a command {} not listed in the language server capabilities",
2799 command.command
2800 )
2801 }
2802 }
2803 }
2804 Ok(())
2805 }
2806
2807 pub async fn deserialize_text_edits(
2808 this: Entity<LspStore>,
2809 buffer_to_edit: Entity<Buffer>,
2810 edits: Vec<lsp::TextEdit>,
2811 push_to_history: bool,
2812 _: Arc<CachedLspAdapter>,
2813 language_server: Arc<LanguageServer>,
2814 cx: &mut AsyncApp,
2815 ) -> Result<Option<Transaction>> {
2816 let edits = this
2817 .update(cx, |this, cx| {
2818 this.as_local_mut().unwrap().edits_from_lsp(
2819 &buffer_to_edit,
2820 edits,
2821 language_server.server_id(),
2822 None,
2823 cx,
2824 )
2825 })?
2826 .await?;
2827
2828 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2829 buffer.finalize_last_transaction();
2830 buffer.start_transaction();
2831 for (range, text) in edits {
2832 buffer.edit([(range, text)], None, cx);
2833 }
2834
2835 if buffer.end_transaction(cx).is_some() {
2836 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2837 if !push_to_history {
2838 buffer.forget_transaction(transaction.id);
2839 }
2840 Some(transaction)
2841 } else {
2842 None
2843 }
2844 })?;
2845
2846 Ok(transaction)
2847 }
2848
2849 #[allow(clippy::type_complexity)]
2850 pub(crate) fn edits_from_lsp(
2851 &mut self,
2852 buffer: &Entity<Buffer>,
2853 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2854 server_id: LanguageServerId,
2855 version: Option<i32>,
2856 cx: &mut Context<LspStore>,
2857 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2858 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2859 cx.background_spawn(async move {
2860 let snapshot = snapshot?;
2861 let mut lsp_edits = lsp_edits
2862 .into_iter()
2863 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2864 .collect::<Vec<_>>();
2865
2866 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2867
2868 let mut lsp_edits = lsp_edits.into_iter().peekable();
2869 let mut edits = Vec::new();
2870 while let Some((range, mut new_text)) = lsp_edits.next() {
2871 // Clip invalid ranges provided by the language server.
2872 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2873 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2874
2875 // Combine any LSP edits that are adjacent.
2876 //
2877 // Also, combine LSP edits that are separated from each other by only
2878 // a newline. This is important because for some code actions,
2879 // Rust-analyzer rewrites the entire buffer via a series of edits that
2880 // are separated by unchanged newline characters.
2881 //
2882 // In order for the diffing logic below to work properly, any edits that
2883 // cancel each other out must be combined into one.
2884 while let Some((next_range, next_text)) = lsp_edits.peek() {
2885 if next_range.start.0 > range.end {
2886 if next_range.start.0.row > range.end.row + 1
2887 || next_range.start.0.column > 0
2888 || snapshot.clip_point_utf16(
2889 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2890 Bias::Left,
2891 ) > range.end
2892 {
2893 break;
2894 }
2895 new_text.push('\n');
2896 }
2897 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2898 new_text.push_str(next_text);
2899 lsp_edits.next();
2900 }
2901
2902 // For multiline edits, perform a diff of the old and new text so that
2903 // we can identify the changes more precisely, preserving the locations
2904 // of any anchors positioned in the unchanged regions.
2905 if range.end.row > range.start.row {
2906 let offset = range.start.to_offset(&snapshot);
2907 let old_text = snapshot.text_for_range(range).collect::<String>();
2908 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2909 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2910 (
2911 snapshot.anchor_after(offset + range.start)
2912 ..snapshot.anchor_before(offset + range.end),
2913 replacement,
2914 )
2915 }));
2916 } else if range.end == range.start {
2917 let anchor = snapshot.anchor_after(range.start);
2918 edits.push((anchor..anchor, new_text.into()));
2919 } else {
2920 let edit_start = snapshot.anchor_after(range.start);
2921 let edit_end = snapshot.anchor_before(range.end);
2922 edits.push((edit_start..edit_end, new_text.into()));
2923 }
2924 }
2925
2926 Ok(edits)
2927 })
2928 }
2929
2930 pub(crate) async fn deserialize_workspace_edit(
2931 this: Entity<LspStore>,
2932 edit: lsp::WorkspaceEdit,
2933 push_to_history: bool,
2934 language_server: Arc<LanguageServer>,
2935 cx: &mut AsyncApp,
2936 ) -> Result<ProjectTransaction> {
2937 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2938
2939 let mut operations = Vec::new();
2940 if let Some(document_changes) = edit.document_changes {
2941 match document_changes {
2942 lsp::DocumentChanges::Edits(edits) => {
2943 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2944 }
2945 lsp::DocumentChanges::Operations(ops) => operations = ops,
2946 }
2947 } else if let Some(changes) = edit.changes {
2948 operations.extend(changes.into_iter().map(|(uri, edits)| {
2949 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2950 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2951 uri,
2952 version: None,
2953 },
2954 edits: edits.into_iter().map(Edit::Plain).collect(),
2955 })
2956 }));
2957 }
2958
2959 let mut project_transaction = ProjectTransaction::default();
2960 for operation in operations {
2961 match operation {
2962 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2963 let abs_path = op
2964 .uri
2965 .to_file_path()
2966 .map_err(|()| anyhow!("can't convert URI to path"))?;
2967
2968 if let Some(parent_path) = abs_path.parent() {
2969 fs.create_dir(parent_path).await?;
2970 }
2971 if abs_path.ends_with("/") {
2972 fs.create_dir(&abs_path).await?;
2973 } else {
2974 fs.create_file(
2975 &abs_path,
2976 op.options
2977 .map(|options| fs::CreateOptions {
2978 overwrite: options.overwrite.unwrap_or(false),
2979 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2980 })
2981 .unwrap_or_default(),
2982 )
2983 .await?;
2984 }
2985 }
2986
2987 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2988 let source_abs_path = op
2989 .old_uri
2990 .to_file_path()
2991 .map_err(|()| anyhow!("can't convert URI to path"))?;
2992 let target_abs_path = op
2993 .new_uri
2994 .to_file_path()
2995 .map_err(|()| anyhow!("can't convert URI to path"))?;
2996 fs.rename(
2997 &source_abs_path,
2998 &target_abs_path,
2999 op.options
3000 .map(|options| fs::RenameOptions {
3001 overwrite: options.overwrite.unwrap_or(false),
3002 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3003 })
3004 .unwrap_or_default(),
3005 )
3006 .await?;
3007 }
3008
3009 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3010 let abs_path = op
3011 .uri
3012 .to_file_path()
3013 .map_err(|()| anyhow!("can't convert URI to path"))?;
3014 let options = op
3015 .options
3016 .map(|options| fs::RemoveOptions {
3017 recursive: options.recursive.unwrap_or(false),
3018 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3019 })
3020 .unwrap_or_default();
3021 if abs_path.ends_with("/") {
3022 fs.remove_dir(&abs_path, options).await?;
3023 } else {
3024 fs.remove_file(&abs_path, options).await?;
3025 }
3026 }
3027
3028 lsp::DocumentChangeOperation::Edit(op) => {
3029 let buffer_to_edit = this
3030 .update(cx, |this, cx| {
3031 this.open_local_buffer_via_lsp(
3032 op.text_document.uri.clone(),
3033 language_server.server_id(),
3034 cx,
3035 )
3036 })?
3037 .await?;
3038
3039 let edits = this
3040 .update(cx, |this, cx| {
3041 let path = buffer_to_edit.read(cx).project_path(cx);
3042 let active_entry = this.active_entry;
3043 let is_active_entry = path.is_some_and(|project_path| {
3044 this.worktree_store
3045 .read(cx)
3046 .entry_for_path(&project_path, cx)
3047 .is_some_and(|entry| Some(entry.id) == active_entry)
3048 });
3049 let local = this.as_local_mut().unwrap();
3050
3051 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3052 for edit in op.edits {
3053 match edit {
3054 Edit::Plain(edit) => {
3055 if !edits.contains(&edit) {
3056 edits.push(edit)
3057 }
3058 }
3059 Edit::Annotated(edit) => {
3060 if !edits.contains(&edit.text_edit) {
3061 edits.push(edit.text_edit)
3062 }
3063 }
3064 Edit::Snippet(edit) => {
3065 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3066 else {
3067 continue;
3068 };
3069
3070 if is_active_entry {
3071 snippet_edits.push((edit.range, snippet));
3072 } else {
3073 // Since this buffer is not focused, apply a normal edit.
3074 let new_edit = TextEdit {
3075 range: edit.range,
3076 new_text: snippet.text,
3077 };
3078 if !edits.contains(&new_edit) {
3079 edits.push(new_edit);
3080 }
3081 }
3082 }
3083 }
3084 }
3085 if !snippet_edits.is_empty() {
3086 let buffer_id = buffer_to_edit.read(cx).remote_id();
3087 let version = if let Some(buffer_version) = op.text_document.version
3088 {
3089 local
3090 .buffer_snapshot_for_lsp_version(
3091 &buffer_to_edit,
3092 language_server.server_id(),
3093 Some(buffer_version),
3094 cx,
3095 )
3096 .ok()
3097 .map(|snapshot| snapshot.version)
3098 } else {
3099 Some(buffer_to_edit.read(cx).saved_version().clone())
3100 };
3101
3102 let most_recent_edit =
3103 version.and_then(|version| version.most_recent());
3104 // Check if the edit that triggered that edit has been made by this participant.
3105
3106 if let Some(most_recent_edit) = most_recent_edit {
3107 cx.emit(LspStoreEvent::SnippetEdit {
3108 buffer_id,
3109 edits: snippet_edits,
3110 most_recent_edit,
3111 });
3112 }
3113 }
3114
3115 local.edits_from_lsp(
3116 &buffer_to_edit,
3117 edits,
3118 language_server.server_id(),
3119 op.text_document.version,
3120 cx,
3121 )
3122 })?
3123 .await?;
3124
3125 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3126 buffer.finalize_last_transaction();
3127 buffer.start_transaction();
3128 for (range, text) in edits {
3129 buffer.edit([(range, text)], None, cx);
3130 }
3131
3132 buffer.end_transaction(cx).and_then(|transaction_id| {
3133 if push_to_history {
3134 buffer.finalize_last_transaction();
3135 buffer.get_transaction(transaction_id).cloned()
3136 } else {
3137 buffer.forget_transaction(transaction_id)
3138 }
3139 })
3140 })?;
3141 if let Some(transaction) = transaction {
3142 project_transaction.0.insert(buffer_to_edit, transaction);
3143 }
3144 }
3145 }
3146 }
3147
3148 Ok(project_transaction)
3149 }
3150
3151 async fn on_lsp_workspace_edit(
3152 this: WeakEntity<LspStore>,
3153 params: lsp::ApplyWorkspaceEditParams,
3154 server_id: LanguageServerId,
3155 cx: &mut AsyncApp,
3156 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3157 let this = this.upgrade().context("project project closed")?;
3158 let language_server = this
3159 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3160 .context("language server not found")?;
3161 let transaction = Self::deserialize_workspace_edit(
3162 this.clone(),
3163 params.edit,
3164 true,
3165 language_server.clone(),
3166 cx,
3167 )
3168 .await
3169 .log_err();
3170 this.update(cx, |this, _| {
3171 if let Some(transaction) = transaction {
3172 this.as_local_mut()
3173 .unwrap()
3174 .last_workspace_edits_by_language_server
3175 .insert(server_id, transaction);
3176 }
3177 })?;
3178 Ok(lsp::ApplyWorkspaceEditResponse {
3179 applied: true,
3180 failed_change: None,
3181 failure_reason: None,
3182 })
3183 }
3184
3185 fn remove_worktree(
3186 &mut self,
3187 id_to_remove: WorktreeId,
3188 cx: &mut Context<LspStore>,
3189 ) -> Vec<LanguageServerId> {
3190 self.diagnostics.remove(&id_to_remove);
3191 self.prettier_store.update(cx, |prettier_store, cx| {
3192 prettier_store.remove_worktree(id_to_remove, cx);
3193 });
3194
3195 let mut servers_to_remove = BTreeSet::default();
3196 let mut servers_to_preserve = HashSet::default();
3197 for (seed, state) in &self.language_server_ids {
3198 if seed.worktree_id == id_to_remove {
3199 servers_to_remove.insert(state.id);
3200 } else {
3201 servers_to_preserve.insert(state.id);
3202 }
3203 }
3204 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3205 self.language_server_ids
3206 .retain(|_, state| !servers_to_remove.contains(&state.id));
3207 for server_id_to_remove in &servers_to_remove {
3208 self.language_server_watched_paths
3209 .remove(server_id_to_remove);
3210 self.language_server_paths_watched_for_rename
3211 .remove(server_id_to_remove);
3212 self.last_workspace_edits_by_language_server
3213 .remove(server_id_to_remove);
3214 self.language_servers.remove(server_id_to_remove);
3215 self.buffer_pull_diagnostics_result_ids
3216 .remove(server_id_to_remove);
3217 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3218 buffer_servers.remove(server_id_to_remove);
3219 }
3220 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3221 }
3222 servers_to_remove.into_iter().collect()
3223 }
3224
3225 fn rebuild_watched_paths_inner<'a>(
3226 &'a self,
3227 language_server_id: LanguageServerId,
3228 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3229 cx: &mut Context<LspStore>,
3230 ) -> LanguageServerWatchedPathsBuilder {
3231 let worktrees = self
3232 .worktree_store
3233 .read(cx)
3234 .worktrees()
3235 .filter_map(|worktree| {
3236 self.language_servers_for_worktree(worktree.read(cx).id())
3237 .find(|server| server.server_id() == language_server_id)
3238 .map(|_| worktree)
3239 })
3240 .collect::<Vec<_>>();
3241
3242 let mut worktree_globs = HashMap::default();
3243 let mut abs_globs = HashMap::default();
3244 log::trace!(
3245 "Processing new watcher paths for language server with id {}",
3246 language_server_id
3247 );
3248
3249 for watcher in watchers {
3250 if let Some((worktree, literal_prefix, pattern)) =
3251 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3252 {
3253 worktree.update(cx, |worktree, _| {
3254 if let Some((tree, glob)) =
3255 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3256 {
3257 tree.add_path_prefix_to_scan(literal_prefix);
3258 worktree_globs
3259 .entry(tree.id())
3260 .or_insert_with(GlobSetBuilder::new)
3261 .add(glob);
3262 }
3263 });
3264 } else {
3265 let (path, pattern) = match &watcher.glob_pattern {
3266 lsp::GlobPattern::String(s) => {
3267 let watcher_path = SanitizedPath::new(s);
3268 let path = glob_literal_prefix(watcher_path.as_path());
3269 let pattern = watcher_path
3270 .as_path()
3271 .strip_prefix(&path)
3272 .map(|p| p.to_string_lossy().into_owned())
3273 .unwrap_or_else(|e| {
3274 debug_panic!(
3275 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3276 s,
3277 path.display(),
3278 e
3279 );
3280 watcher_path.as_path().to_string_lossy().into_owned()
3281 });
3282 (path, pattern)
3283 }
3284 lsp::GlobPattern::Relative(rp) => {
3285 let Ok(mut base_uri) = match &rp.base_uri {
3286 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3287 lsp::OneOf::Right(base_uri) => base_uri,
3288 }
3289 .to_file_path() else {
3290 continue;
3291 };
3292
3293 let path = glob_literal_prefix(Path::new(&rp.pattern));
3294 let pattern = Path::new(&rp.pattern)
3295 .strip_prefix(&path)
3296 .map(|p| p.to_string_lossy().into_owned())
3297 .unwrap_or_else(|e| {
3298 debug_panic!(
3299 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3300 rp.pattern,
3301 path.display(),
3302 e
3303 );
3304 rp.pattern.clone()
3305 });
3306 base_uri.push(path);
3307 (base_uri, pattern)
3308 }
3309 };
3310
3311 if let Some(glob) = Glob::new(&pattern).log_err() {
3312 if !path
3313 .components()
3314 .any(|c| matches!(c, path::Component::Normal(_)))
3315 {
3316 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3317 // rather than adding a new watcher for `/`.
3318 for worktree in &worktrees {
3319 worktree_globs
3320 .entry(worktree.read(cx).id())
3321 .or_insert_with(GlobSetBuilder::new)
3322 .add(glob.clone());
3323 }
3324 } else {
3325 abs_globs
3326 .entry(path.into())
3327 .or_insert_with(GlobSetBuilder::new)
3328 .add(glob);
3329 }
3330 }
3331 }
3332 }
3333
3334 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3335 for (worktree_id, builder) in worktree_globs {
3336 if let Ok(globset) = builder.build() {
3337 watch_builder.watch_worktree(worktree_id, globset);
3338 }
3339 }
3340 for (abs_path, builder) in abs_globs {
3341 if let Ok(globset) = builder.build() {
3342 watch_builder.watch_abs_path(abs_path, globset);
3343 }
3344 }
3345 watch_builder
3346 }
3347
3348 fn worktree_and_path_for_file_watcher(
3349 worktrees: &[Entity<Worktree>],
3350 watcher: &FileSystemWatcher,
3351 cx: &App,
3352 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3353 worktrees.iter().find_map(|worktree| {
3354 let tree = worktree.read(cx);
3355 let worktree_root_path = tree.abs_path();
3356 let path_style = tree.path_style();
3357 match &watcher.glob_pattern {
3358 lsp::GlobPattern::String(s) => {
3359 let watcher_path = SanitizedPath::new(s);
3360 let relative = watcher_path
3361 .as_path()
3362 .strip_prefix(&worktree_root_path)
3363 .ok()?;
3364 let literal_prefix = glob_literal_prefix(relative);
3365 Some((
3366 worktree.clone(),
3367 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3368 relative.to_string_lossy().into_owned(),
3369 ))
3370 }
3371 lsp::GlobPattern::Relative(rp) => {
3372 let base_uri = match &rp.base_uri {
3373 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3374 lsp::OneOf::Right(base_uri) => base_uri,
3375 }
3376 .to_file_path()
3377 .ok()?;
3378 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3379 let mut literal_prefix = relative.to_owned();
3380 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3381 Some((
3382 worktree.clone(),
3383 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3384 rp.pattern.clone(),
3385 ))
3386 }
3387 }
3388 })
3389 }
3390
3391 fn rebuild_watched_paths(
3392 &mut self,
3393 language_server_id: LanguageServerId,
3394 cx: &mut Context<LspStore>,
3395 ) {
3396 let Some(registrations) = self
3397 .language_server_dynamic_registrations
3398 .get(&language_server_id)
3399 else {
3400 return;
3401 };
3402
3403 let watch_builder = self.rebuild_watched_paths_inner(
3404 language_server_id,
3405 registrations.did_change_watched_files.values().flatten(),
3406 cx,
3407 );
3408 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3409 self.language_server_watched_paths
3410 .insert(language_server_id, watcher);
3411
3412 cx.notify();
3413 }
3414
3415 fn on_lsp_did_change_watched_files(
3416 &mut self,
3417 language_server_id: LanguageServerId,
3418 registration_id: &str,
3419 params: DidChangeWatchedFilesRegistrationOptions,
3420 cx: &mut Context<LspStore>,
3421 ) {
3422 let registrations = self
3423 .language_server_dynamic_registrations
3424 .entry(language_server_id)
3425 .or_default();
3426
3427 registrations
3428 .did_change_watched_files
3429 .insert(registration_id.to_string(), params.watchers);
3430
3431 self.rebuild_watched_paths(language_server_id, cx);
3432 }
3433
3434 fn on_lsp_unregister_did_change_watched_files(
3435 &mut self,
3436 language_server_id: LanguageServerId,
3437 registration_id: &str,
3438 cx: &mut Context<LspStore>,
3439 ) {
3440 let registrations = self
3441 .language_server_dynamic_registrations
3442 .entry(language_server_id)
3443 .or_default();
3444
3445 if registrations
3446 .did_change_watched_files
3447 .remove(registration_id)
3448 .is_some()
3449 {
3450 log::info!(
3451 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3452 language_server_id,
3453 registration_id
3454 );
3455 } else {
3456 log::warn!(
3457 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3458 language_server_id,
3459 registration_id
3460 );
3461 }
3462
3463 self.rebuild_watched_paths(language_server_id, cx);
3464 }
3465
3466 async fn initialization_options_for_adapter(
3467 adapter: Arc<dyn LspAdapter>,
3468 delegate: &Arc<dyn LspAdapterDelegate>,
3469 ) -> Result<Option<serde_json::Value>> {
3470 let Some(mut initialization_config) =
3471 adapter.clone().initialization_options(delegate).await?
3472 else {
3473 return Ok(None);
3474 };
3475
3476 for other_adapter in delegate.registered_lsp_adapters() {
3477 if other_adapter.name() == adapter.name() {
3478 continue;
3479 }
3480 if let Ok(Some(target_config)) = other_adapter
3481 .clone()
3482 .additional_initialization_options(adapter.name(), delegate)
3483 .await
3484 {
3485 merge_json_value_into(target_config.clone(), &mut initialization_config);
3486 }
3487 }
3488
3489 Ok(Some(initialization_config))
3490 }
3491
3492 async fn workspace_configuration_for_adapter(
3493 adapter: Arc<dyn LspAdapter>,
3494 delegate: &Arc<dyn LspAdapterDelegate>,
3495 toolchain: Option<Toolchain>,
3496 cx: &mut AsyncApp,
3497 ) -> Result<serde_json::Value> {
3498 let mut workspace_config = adapter
3499 .clone()
3500 .workspace_configuration(delegate, toolchain, cx)
3501 .await?;
3502
3503 for other_adapter in delegate.registered_lsp_adapters() {
3504 if other_adapter.name() == adapter.name() {
3505 continue;
3506 }
3507 if let Ok(Some(target_config)) = other_adapter
3508 .clone()
3509 .additional_workspace_configuration(adapter.name(), delegate, cx)
3510 .await
3511 {
3512 merge_json_value_into(target_config.clone(), &mut workspace_config);
3513 }
3514 }
3515
3516 Ok(workspace_config)
3517 }
3518
3519 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3520 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3521 Some(server.clone())
3522 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3523 Some(Arc::clone(server))
3524 } else {
3525 None
3526 }
3527 }
3528}
3529
3530fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3531 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3532 cx.emit(LspStoreEvent::LanguageServerUpdate {
3533 language_server_id: server.server_id(),
3534 name: Some(server.name()),
3535 message: proto::update_language_server::Variant::MetadataUpdated(
3536 proto::ServerMetadataUpdated {
3537 capabilities: Some(capabilities),
3538 },
3539 ),
3540 });
3541 }
3542}
3543
3544#[derive(Debug)]
3545pub struct FormattableBuffer {
3546 handle: Entity<Buffer>,
3547 abs_path: Option<PathBuf>,
3548 env: Option<HashMap<String, String>>,
3549 ranges: Option<Vec<Range<Anchor>>>,
3550}
3551
3552pub struct RemoteLspStore {
3553 upstream_client: Option<AnyProtoClient>,
3554 upstream_project_id: u64,
3555}
3556
3557pub(crate) enum LspStoreMode {
3558 Local(LocalLspStore), // ssh host and collab host
3559 Remote(RemoteLspStore), // collab guest
3560}
3561
3562impl LspStoreMode {
3563 fn is_local(&self) -> bool {
3564 matches!(self, LspStoreMode::Local(_))
3565 }
3566}
3567
3568pub struct LspStore {
3569 mode: LspStoreMode,
3570 last_formatting_failure: Option<String>,
3571 downstream_client: Option<(AnyProtoClient, u64)>,
3572 nonce: u128,
3573 buffer_store: Entity<BufferStore>,
3574 worktree_store: Entity<WorktreeStore>,
3575 pub languages: Arc<LanguageRegistry>,
3576 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3577 active_entry: Option<ProjectEntryId>,
3578 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3579 _maintain_buffer_languages: Task<()>,
3580 diagnostic_summaries:
3581 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3582 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3583 lsp_data: HashMap<BufferId, BufferLspData>,
3584 next_hint_id: Arc<AtomicUsize>,
3585}
3586
3587#[derive(Debug)]
3588pub struct BufferLspData {
3589 buffer_version: Global,
3590 document_colors: Option<DocumentColorData>,
3591 code_lens: Option<CodeLensData>,
3592 inlay_hints: BufferInlayHints,
3593 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3594 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3595}
3596
3597#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3598struct LspKey {
3599 request_type: TypeId,
3600 server_queried: Option<LanguageServerId>,
3601}
3602
3603impl BufferLspData {
3604 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3605 Self {
3606 buffer_version: buffer.read(cx).version(),
3607 document_colors: None,
3608 code_lens: None,
3609 inlay_hints: BufferInlayHints::new(buffer, cx),
3610 lsp_requests: HashMap::default(),
3611 chunk_lsp_requests: HashMap::default(),
3612 }
3613 }
3614
3615 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3616 if let Some(document_colors) = &mut self.document_colors {
3617 document_colors.colors.remove(&for_server);
3618 document_colors.cache_version += 1;
3619 }
3620
3621 if let Some(code_lens) = &mut self.code_lens {
3622 code_lens.lens.remove(&for_server);
3623 }
3624
3625 self.inlay_hints.remove_server_data(for_server);
3626 }
3627
3628 #[cfg(any(test, feature = "test-support"))]
3629 pub fn inlay_hints(&self) -> &BufferInlayHints {
3630 &self.inlay_hints
3631 }
3632}
3633
3634#[derive(Debug, Default, Clone)]
3635pub struct DocumentColors {
3636 pub colors: HashSet<DocumentColor>,
3637 pub cache_version: Option<usize>,
3638}
3639
3640type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3641type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3642
3643#[derive(Debug, Default)]
3644struct DocumentColorData {
3645 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3646 cache_version: usize,
3647 colors_update: Option<(Global, DocumentColorTask)>,
3648}
3649
3650#[derive(Debug, Default)]
3651struct CodeLensData {
3652 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3653 update: Option<(Global, CodeLensTask)>,
3654}
3655
3656#[derive(Debug)]
3657pub enum LspStoreEvent {
3658 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3659 LanguageServerRemoved(LanguageServerId),
3660 LanguageServerUpdate {
3661 language_server_id: LanguageServerId,
3662 name: Option<LanguageServerName>,
3663 message: proto::update_language_server::Variant,
3664 },
3665 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3666 LanguageServerPrompt(LanguageServerPromptRequest),
3667 LanguageDetected {
3668 buffer: Entity<Buffer>,
3669 new_language: Option<Arc<Language>>,
3670 },
3671 Notification(String),
3672 RefreshInlayHints {
3673 server_id: LanguageServerId,
3674 request_id: Option<usize>,
3675 },
3676 RefreshCodeLens,
3677 DiagnosticsUpdated {
3678 server_id: LanguageServerId,
3679 paths: Vec<ProjectPath>,
3680 },
3681 DiskBasedDiagnosticsStarted {
3682 language_server_id: LanguageServerId,
3683 },
3684 DiskBasedDiagnosticsFinished {
3685 language_server_id: LanguageServerId,
3686 },
3687 SnippetEdit {
3688 buffer_id: BufferId,
3689 edits: Vec<(lsp::Range, Snippet)>,
3690 most_recent_edit: clock::Lamport,
3691 },
3692}
3693
3694#[derive(Clone, Debug, Serialize)]
3695pub struct LanguageServerStatus {
3696 pub name: LanguageServerName,
3697 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3698 pub has_pending_diagnostic_updates: bool,
3699 progress_tokens: HashSet<ProgressToken>,
3700 pub worktree: Option<WorktreeId>,
3701}
3702
3703#[derive(Clone, Debug)]
3704struct CoreSymbol {
3705 pub language_server_name: LanguageServerName,
3706 pub source_worktree_id: WorktreeId,
3707 pub source_language_server_id: LanguageServerId,
3708 pub path: SymbolLocation,
3709 pub name: String,
3710 pub kind: lsp::SymbolKind,
3711 pub range: Range<Unclipped<PointUtf16>>,
3712}
3713
3714#[derive(Clone, Debug, PartialEq, Eq)]
3715pub enum SymbolLocation {
3716 InProject(ProjectPath),
3717 OutsideProject {
3718 abs_path: Arc<Path>,
3719 signature: [u8; 32],
3720 },
3721}
3722
3723impl SymbolLocation {
3724 fn file_name(&self) -> Option<&str> {
3725 match self {
3726 Self::InProject(path) => path.path.file_name(),
3727 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3728 }
3729 }
3730}
3731
3732impl LspStore {
3733 pub fn init(client: &AnyProtoClient) {
3734 client.add_entity_request_handler(Self::handle_lsp_query);
3735 client.add_entity_message_handler(Self::handle_lsp_query_response);
3736 client.add_entity_request_handler(Self::handle_restart_language_servers);
3737 client.add_entity_request_handler(Self::handle_stop_language_servers);
3738 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3739 client.add_entity_message_handler(Self::handle_start_language_server);
3740 client.add_entity_message_handler(Self::handle_update_language_server);
3741 client.add_entity_message_handler(Self::handle_language_server_log);
3742 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3743 client.add_entity_request_handler(Self::handle_format_buffers);
3744 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3745 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3746 client.add_entity_request_handler(Self::handle_apply_code_action);
3747 client.add_entity_request_handler(Self::handle_get_project_symbols);
3748 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3749 client.add_entity_request_handler(Self::handle_get_color_presentation);
3750 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3751 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3752 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3753 client.add_entity_request_handler(Self::handle_on_type_formatting);
3754 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3755 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3756 client.add_entity_request_handler(Self::handle_rename_project_entry);
3757 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3758 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3759 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3760 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3761 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3762 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3763 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3764
3765 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3766 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3767 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3768 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3769 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3770 client.add_entity_request_handler(
3771 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3772 );
3773 client.add_entity_request_handler(
3774 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3775 );
3776 client.add_entity_request_handler(
3777 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3778 );
3779 }
3780
3781 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3782 match &self.mode {
3783 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3784 _ => None,
3785 }
3786 }
3787
3788 pub fn as_local(&self) -> Option<&LocalLspStore> {
3789 match &self.mode {
3790 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3791 _ => None,
3792 }
3793 }
3794
3795 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3796 match &mut self.mode {
3797 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3798 _ => None,
3799 }
3800 }
3801
3802 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3803 match &self.mode {
3804 LspStoreMode::Remote(RemoteLspStore {
3805 upstream_client: Some(upstream_client),
3806 upstream_project_id,
3807 ..
3808 }) => Some((upstream_client.clone(), *upstream_project_id)),
3809
3810 LspStoreMode::Remote(RemoteLspStore {
3811 upstream_client: None,
3812 ..
3813 }) => None,
3814 LspStoreMode::Local(_) => None,
3815 }
3816 }
3817
3818 pub fn new_local(
3819 buffer_store: Entity<BufferStore>,
3820 worktree_store: Entity<WorktreeStore>,
3821 prettier_store: Entity<PrettierStore>,
3822 toolchain_store: Entity<LocalToolchainStore>,
3823 environment: Entity<ProjectEnvironment>,
3824 manifest_tree: Entity<ManifestTree>,
3825 languages: Arc<LanguageRegistry>,
3826 http_client: Arc<dyn HttpClient>,
3827 fs: Arc<dyn Fs>,
3828 cx: &mut Context<Self>,
3829 ) -> Self {
3830 let yarn = YarnPathStore::new(fs.clone(), cx);
3831 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3832 .detach();
3833 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3834 .detach();
3835 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3836 .detach();
3837 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3838 .detach();
3839 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3840 .detach();
3841 subscribe_to_binary_statuses(&languages, cx).detach();
3842
3843 let _maintain_workspace_config = {
3844 let (sender, receiver) = watch::channel();
3845 (Self::maintain_workspace_config(receiver, cx), sender)
3846 };
3847
3848 Self {
3849 mode: LspStoreMode::Local(LocalLspStore {
3850 weak: cx.weak_entity(),
3851 worktree_store: worktree_store.clone(),
3852
3853 supplementary_language_servers: Default::default(),
3854 languages: languages.clone(),
3855 language_server_ids: Default::default(),
3856 language_servers: Default::default(),
3857 last_workspace_edits_by_language_server: Default::default(),
3858 language_server_watched_paths: Default::default(),
3859 language_server_paths_watched_for_rename: Default::default(),
3860 language_server_dynamic_registrations: Default::default(),
3861 buffers_being_formatted: Default::default(),
3862 buffer_snapshots: Default::default(),
3863 prettier_store,
3864 environment,
3865 http_client,
3866 fs,
3867 yarn,
3868 next_diagnostic_group_id: Default::default(),
3869 diagnostics: Default::default(),
3870 _subscription: cx.on_app_quit(|this, cx| {
3871 this.as_local_mut()
3872 .unwrap()
3873 .shutdown_language_servers_on_quit(cx)
3874 }),
3875 lsp_tree: LanguageServerTree::new(
3876 manifest_tree,
3877 languages.clone(),
3878 toolchain_store.clone(),
3879 ),
3880 toolchain_store,
3881 registered_buffers: HashMap::default(),
3882 buffers_opened_in_servers: HashMap::default(),
3883 buffer_pull_diagnostics_result_ids: HashMap::default(),
3884 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3885 .manifest_file_names(),
3886 }),
3887 last_formatting_failure: None,
3888 downstream_client: None,
3889 buffer_store,
3890 worktree_store,
3891 languages: languages.clone(),
3892 language_server_statuses: Default::default(),
3893 nonce: StdRng::from_os_rng().random(),
3894 diagnostic_summaries: HashMap::default(),
3895 lsp_server_capabilities: HashMap::default(),
3896 lsp_data: HashMap::default(),
3897 next_hint_id: Arc::default(),
3898 active_entry: None,
3899 _maintain_workspace_config,
3900 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3901 }
3902 }
3903
3904 fn send_lsp_proto_request<R: LspCommand>(
3905 &self,
3906 buffer: Entity<Buffer>,
3907 client: AnyProtoClient,
3908 upstream_project_id: u64,
3909 request: R,
3910 cx: &mut Context<LspStore>,
3911 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3912 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3913 return Task::ready(Ok(R::Response::default()));
3914 }
3915 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3916 cx.spawn(async move |this, cx| {
3917 let response = client.request(message).await?;
3918 let this = this.upgrade().context("project dropped")?;
3919 request
3920 .response_from_proto(response, this, buffer, cx.clone())
3921 .await
3922 })
3923 }
3924
3925 pub(super) fn new_remote(
3926 buffer_store: Entity<BufferStore>,
3927 worktree_store: Entity<WorktreeStore>,
3928 languages: Arc<LanguageRegistry>,
3929 upstream_client: AnyProtoClient,
3930 project_id: u64,
3931 cx: &mut Context<Self>,
3932 ) -> Self {
3933 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3934 .detach();
3935 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3936 .detach();
3937 subscribe_to_binary_statuses(&languages, cx).detach();
3938 let _maintain_workspace_config = {
3939 let (sender, receiver) = watch::channel();
3940 (Self::maintain_workspace_config(receiver, cx), sender)
3941 };
3942 Self {
3943 mode: LspStoreMode::Remote(RemoteLspStore {
3944 upstream_client: Some(upstream_client),
3945 upstream_project_id: project_id,
3946 }),
3947 downstream_client: None,
3948 last_formatting_failure: None,
3949 buffer_store,
3950 worktree_store,
3951 languages: languages.clone(),
3952 language_server_statuses: Default::default(),
3953 nonce: StdRng::from_os_rng().random(),
3954 diagnostic_summaries: HashMap::default(),
3955 lsp_server_capabilities: HashMap::default(),
3956 next_hint_id: Arc::default(),
3957 lsp_data: HashMap::default(),
3958 active_entry: None,
3959
3960 _maintain_workspace_config,
3961 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3962 }
3963 }
3964
3965 fn on_buffer_store_event(
3966 &mut self,
3967 _: Entity<BufferStore>,
3968 event: &BufferStoreEvent,
3969 cx: &mut Context<Self>,
3970 ) {
3971 match event {
3972 BufferStoreEvent::BufferAdded(buffer) => {
3973 self.on_buffer_added(buffer, cx).log_err();
3974 }
3975 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3976 let buffer_id = buffer.read(cx).remote_id();
3977 if let Some(local) = self.as_local_mut()
3978 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3979 {
3980 local.reset_buffer(buffer, old_file, cx);
3981
3982 if local.registered_buffers.contains_key(&buffer_id) {
3983 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3984 }
3985 }
3986
3987 self.detect_language_for_buffer(buffer, cx);
3988 if let Some(local) = self.as_local_mut() {
3989 local.initialize_buffer(buffer, cx);
3990 if local.registered_buffers.contains_key(&buffer_id) {
3991 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3992 }
3993 }
3994 }
3995 _ => {}
3996 }
3997 }
3998
3999 fn on_worktree_store_event(
4000 &mut self,
4001 _: Entity<WorktreeStore>,
4002 event: &WorktreeStoreEvent,
4003 cx: &mut Context<Self>,
4004 ) {
4005 match event {
4006 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4007 if !worktree.read(cx).is_local() {
4008 return;
4009 }
4010 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4011 worktree::Event::UpdatedEntries(changes) => {
4012 this.update_local_worktree_language_servers(&worktree, changes, cx);
4013 }
4014 worktree::Event::UpdatedGitRepositories(_)
4015 | worktree::Event::DeletedEntry(_) => {}
4016 })
4017 .detach()
4018 }
4019 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4020 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4021 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4022 }
4023 WorktreeStoreEvent::WorktreeReleased(..)
4024 | WorktreeStoreEvent::WorktreeOrderChanged
4025 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4026 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4027 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4028 }
4029 }
4030
4031 fn on_prettier_store_event(
4032 &mut self,
4033 _: Entity<PrettierStore>,
4034 event: &PrettierStoreEvent,
4035 cx: &mut Context<Self>,
4036 ) {
4037 match event {
4038 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4039 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4040 }
4041 PrettierStoreEvent::LanguageServerAdded {
4042 new_server_id,
4043 name,
4044 prettier_server,
4045 } => {
4046 self.register_supplementary_language_server(
4047 *new_server_id,
4048 name.clone(),
4049 prettier_server.clone(),
4050 cx,
4051 );
4052 }
4053 }
4054 }
4055
4056 fn on_toolchain_store_event(
4057 &mut self,
4058 _: Entity<LocalToolchainStore>,
4059 event: &ToolchainStoreEvent,
4060 _: &mut Context<Self>,
4061 ) {
4062 if let ToolchainStoreEvent::ToolchainActivated = event {
4063 self.request_workspace_config_refresh()
4064 }
4065 }
4066
4067 fn request_workspace_config_refresh(&mut self) {
4068 *self._maintain_workspace_config.1.borrow_mut() = ();
4069 }
4070
4071 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4072 self.as_local().map(|local| local.prettier_store.clone())
4073 }
4074
4075 fn on_buffer_event(
4076 &mut self,
4077 buffer: Entity<Buffer>,
4078 event: &language::BufferEvent,
4079 cx: &mut Context<Self>,
4080 ) {
4081 match event {
4082 language::BufferEvent::Edited => {
4083 self.on_buffer_edited(buffer, cx);
4084 }
4085
4086 language::BufferEvent::Saved => {
4087 self.on_buffer_saved(buffer, cx);
4088 }
4089
4090 _ => {}
4091 }
4092 }
4093
4094 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4095 buffer
4096 .read(cx)
4097 .set_language_registry(self.languages.clone());
4098
4099 cx.subscribe(buffer, |this, buffer, event, cx| {
4100 this.on_buffer_event(buffer, event, cx);
4101 })
4102 .detach();
4103
4104 self.detect_language_for_buffer(buffer, cx);
4105 if let Some(local) = self.as_local_mut() {
4106 local.initialize_buffer(buffer, cx);
4107 }
4108
4109 Ok(())
4110 }
4111
4112 pub(crate) fn register_buffer_with_language_servers(
4113 &mut self,
4114 buffer: &Entity<Buffer>,
4115 only_register_servers: HashSet<LanguageServerSelector>,
4116 ignore_refcounts: bool,
4117 cx: &mut Context<Self>,
4118 ) -> OpenLspBufferHandle {
4119 let buffer_id = buffer.read(cx).remote_id();
4120 let handle = cx.new(|_| buffer.clone());
4121 if let Some(local) = self.as_local_mut() {
4122 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4123 if !ignore_refcounts {
4124 *refcount += 1;
4125 }
4126
4127 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4128 // 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
4129 // 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
4130 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4131 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4132 return handle;
4133 };
4134 if !file.is_local() {
4135 return handle;
4136 }
4137
4138 if ignore_refcounts || *refcount == 1 {
4139 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4140 }
4141 if !ignore_refcounts {
4142 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4143 let refcount = {
4144 let local = lsp_store.as_local_mut().unwrap();
4145 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4146 debug_panic!("bad refcounting");
4147 return;
4148 };
4149
4150 *refcount -= 1;
4151 *refcount
4152 };
4153 if refcount == 0 {
4154 lsp_store.lsp_data.remove(&buffer_id);
4155 let local = lsp_store.as_local_mut().unwrap();
4156 local.registered_buffers.remove(&buffer_id);
4157 local.buffers_opened_in_servers.remove(&buffer_id);
4158 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4159 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4160 }
4161 }
4162 })
4163 .detach();
4164 }
4165 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4166 let buffer_id = buffer.read(cx).remote_id().to_proto();
4167 cx.background_spawn(async move {
4168 upstream_client
4169 .request(proto::RegisterBufferWithLanguageServers {
4170 project_id: upstream_project_id,
4171 buffer_id,
4172 only_servers: only_register_servers
4173 .into_iter()
4174 .map(|selector| {
4175 let selector = match selector {
4176 LanguageServerSelector::Id(language_server_id) => {
4177 proto::language_server_selector::Selector::ServerId(
4178 language_server_id.to_proto(),
4179 )
4180 }
4181 LanguageServerSelector::Name(language_server_name) => {
4182 proto::language_server_selector::Selector::Name(
4183 language_server_name.to_string(),
4184 )
4185 }
4186 };
4187 proto::LanguageServerSelector {
4188 selector: Some(selector),
4189 }
4190 })
4191 .collect(),
4192 })
4193 .await
4194 })
4195 .detach();
4196 } else {
4197 // Our remote connection got closed
4198 }
4199 handle
4200 }
4201
4202 fn maintain_buffer_languages(
4203 languages: Arc<LanguageRegistry>,
4204 cx: &mut Context<Self>,
4205 ) -> Task<()> {
4206 let mut subscription = languages.subscribe();
4207 let mut prev_reload_count = languages.reload_count();
4208 cx.spawn(async move |this, cx| {
4209 while let Some(()) = subscription.next().await {
4210 if let Some(this) = this.upgrade() {
4211 // If the language registry has been reloaded, then remove and
4212 // re-assign the languages on all open buffers.
4213 let reload_count = languages.reload_count();
4214 if reload_count > prev_reload_count {
4215 prev_reload_count = reload_count;
4216 this.update(cx, |this, cx| {
4217 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4218 for buffer in buffer_store.buffers() {
4219 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4220 {
4221 buffer
4222 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4223 if let Some(local) = this.as_local_mut() {
4224 local.reset_buffer(&buffer, &f, cx);
4225
4226 if local
4227 .registered_buffers
4228 .contains_key(&buffer.read(cx).remote_id())
4229 && let Some(file_url) =
4230 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4231 {
4232 local.unregister_buffer_from_language_servers(
4233 &buffer, &file_url, cx,
4234 );
4235 }
4236 }
4237 }
4238 }
4239 });
4240 })
4241 .ok();
4242 }
4243
4244 this.update(cx, |this, cx| {
4245 let mut plain_text_buffers = Vec::new();
4246 let mut buffers_with_unknown_injections = Vec::new();
4247 for handle in this.buffer_store.read(cx).buffers() {
4248 let buffer = handle.read(cx);
4249 if buffer.language().is_none()
4250 || buffer.language() == Some(&*language::PLAIN_TEXT)
4251 {
4252 plain_text_buffers.push(handle);
4253 } else if buffer.contains_unknown_injections() {
4254 buffers_with_unknown_injections.push(handle);
4255 }
4256 }
4257
4258 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4259 // and reused later in the invisible worktrees.
4260 plain_text_buffers.sort_by_key(|buffer| {
4261 Reverse(
4262 File::from_dyn(buffer.read(cx).file())
4263 .map(|file| file.worktree.read(cx).is_visible()),
4264 )
4265 });
4266
4267 for buffer in plain_text_buffers {
4268 this.detect_language_for_buffer(&buffer, cx);
4269 if let Some(local) = this.as_local_mut() {
4270 local.initialize_buffer(&buffer, cx);
4271 if local
4272 .registered_buffers
4273 .contains_key(&buffer.read(cx).remote_id())
4274 {
4275 local.register_buffer_with_language_servers(
4276 &buffer,
4277 HashSet::default(),
4278 cx,
4279 );
4280 }
4281 }
4282 }
4283
4284 for buffer in buffers_with_unknown_injections {
4285 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4286 }
4287 })
4288 .ok();
4289 }
4290 }
4291 })
4292 }
4293
4294 fn detect_language_for_buffer(
4295 &mut self,
4296 buffer_handle: &Entity<Buffer>,
4297 cx: &mut Context<Self>,
4298 ) -> Option<language::AvailableLanguage> {
4299 // If the buffer has a language, set it and start the language server if we haven't already.
4300 let buffer = buffer_handle.read(cx);
4301 let file = buffer.file()?;
4302
4303 let content = buffer.as_rope();
4304 let available_language = self.languages.language_for_file(file, Some(content), cx);
4305 if let Some(available_language) = &available_language {
4306 if let Some(Ok(Ok(new_language))) = self
4307 .languages
4308 .load_language(available_language)
4309 .now_or_never()
4310 {
4311 self.set_language_for_buffer(buffer_handle, new_language, cx);
4312 }
4313 } else {
4314 cx.emit(LspStoreEvent::LanguageDetected {
4315 buffer: buffer_handle.clone(),
4316 new_language: None,
4317 });
4318 }
4319
4320 available_language
4321 }
4322
4323 pub(crate) fn set_language_for_buffer(
4324 &mut self,
4325 buffer_entity: &Entity<Buffer>,
4326 new_language: Arc<Language>,
4327 cx: &mut Context<Self>,
4328 ) {
4329 let buffer = buffer_entity.read(cx);
4330 let buffer_file = buffer.file().cloned();
4331 let buffer_id = buffer.remote_id();
4332 if let Some(local_store) = self.as_local_mut()
4333 && local_store.registered_buffers.contains_key(&buffer_id)
4334 && let Some(abs_path) =
4335 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4336 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4337 {
4338 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4339 }
4340 buffer_entity.update(cx, |buffer, cx| {
4341 if buffer
4342 .language()
4343 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4344 {
4345 buffer.set_language(Some(new_language.clone()), cx);
4346 }
4347 });
4348
4349 let settings =
4350 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4351 let buffer_file = File::from_dyn(buffer_file.as_ref());
4352
4353 let worktree_id = if let Some(file) = buffer_file {
4354 let worktree = file.worktree.clone();
4355
4356 if let Some(local) = self.as_local_mut()
4357 && local.registered_buffers.contains_key(&buffer_id)
4358 {
4359 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4360 }
4361 Some(worktree.read(cx).id())
4362 } else {
4363 None
4364 };
4365
4366 if settings.prettier.allowed
4367 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4368 {
4369 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4370 if let Some(prettier_store) = prettier_store {
4371 prettier_store.update(cx, |prettier_store, cx| {
4372 prettier_store.install_default_prettier(
4373 worktree_id,
4374 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4375 cx,
4376 )
4377 })
4378 }
4379 }
4380
4381 cx.emit(LspStoreEvent::LanguageDetected {
4382 buffer: buffer_entity.clone(),
4383 new_language: Some(new_language),
4384 })
4385 }
4386
4387 pub fn buffer_store(&self) -> Entity<BufferStore> {
4388 self.buffer_store.clone()
4389 }
4390
4391 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4392 self.active_entry = active_entry;
4393 }
4394
4395 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4396 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4397 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4398 {
4399 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4400 summaries
4401 .iter()
4402 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4403 });
4404 if let Some(summary) = summaries.next() {
4405 client
4406 .send(proto::UpdateDiagnosticSummary {
4407 project_id: downstream_project_id,
4408 worktree_id: worktree.id().to_proto(),
4409 summary: Some(summary),
4410 more_summaries: summaries.collect(),
4411 })
4412 .log_err();
4413 }
4414 }
4415 }
4416
4417 fn is_capable_for_proto_request<R>(
4418 &self,
4419 buffer: &Entity<Buffer>,
4420 request: &R,
4421 cx: &App,
4422 ) -> bool
4423 where
4424 R: LspCommand,
4425 {
4426 self.check_if_capable_for_proto_request(
4427 buffer,
4428 |capabilities| {
4429 request.check_capabilities(AdapterServerCapabilities {
4430 server_capabilities: capabilities.clone(),
4431 code_action_kinds: None,
4432 })
4433 },
4434 cx,
4435 )
4436 }
4437
4438 fn check_if_capable_for_proto_request<F>(
4439 &self,
4440 buffer: &Entity<Buffer>,
4441 check: F,
4442 cx: &App,
4443 ) -> bool
4444 where
4445 F: FnMut(&lsp::ServerCapabilities) -> bool,
4446 {
4447 let Some(language) = buffer.read(cx).language().cloned() else {
4448 return false;
4449 };
4450 let relevant_language_servers = self
4451 .languages
4452 .lsp_adapters(&language.name())
4453 .into_iter()
4454 .map(|lsp_adapter| lsp_adapter.name())
4455 .collect::<HashSet<_>>();
4456 self.language_server_statuses
4457 .iter()
4458 .filter_map(|(server_id, server_status)| {
4459 relevant_language_servers
4460 .contains(&server_status.name)
4461 .then_some(server_id)
4462 })
4463 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4464 .any(check)
4465 }
4466
4467 pub fn request_lsp<R>(
4468 &mut self,
4469 buffer: Entity<Buffer>,
4470 server: LanguageServerToQuery,
4471 request: R,
4472 cx: &mut Context<Self>,
4473 ) -> Task<Result<R::Response>>
4474 where
4475 R: LspCommand,
4476 <R::LspRequest as lsp::request::Request>::Result: Send,
4477 <R::LspRequest as lsp::request::Request>::Params: Send,
4478 {
4479 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4480 return self.send_lsp_proto_request(
4481 buffer,
4482 upstream_client,
4483 upstream_project_id,
4484 request,
4485 cx,
4486 );
4487 }
4488
4489 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4490 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4491 local
4492 .language_servers_for_buffer(buffer, cx)
4493 .find(|(_, server)| {
4494 request.check_capabilities(server.adapter_server_capabilities())
4495 })
4496 .map(|(_, server)| server.clone())
4497 }),
4498 LanguageServerToQuery::Other(id) => self
4499 .language_server_for_local_buffer(buffer, id, cx)
4500 .and_then(|(_, server)| {
4501 request
4502 .check_capabilities(server.adapter_server_capabilities())
4503 .then(|| Arc::clone(server))
4504 }),
4505 }) else {
4506 return Task::ready(Ok(Default::default()));
4507 };
4508
4509 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4510
4511 let Some(file) = file else {
4512 return Task::ready(Ok(Default::default()));
4513 };
4514
4515 let lsp_params = match request.to_lsp_params_or_response(
4516 &file.abs_path(cx),
4517 buffer.read(cx),
4518 &language_server,
4519 cx,
4520 ) {
4521 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4522 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4523 Err(err) => {
4524 let message = format!(
4525 "{} via {} failed: {}",
4526 request.display_name(),
4527 language_server.name(),
4528 err
4529 );
4530 // rust-analyzer likes to error with this when its still loading up
4531 if !message.ends_with("content modified") {
4532 log::warn!("{message}");
4533 }
4534 return Task::ready(Err(anyhow!(message)));
4535 }
4536 };
4537
4538 let status = request.status();
4539 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4540 return Task::ready(Ok(Default::default()));
4541 }
4542 cx.spawn(async move |this, cx| {
4543 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4544
4545 let id = lsp_request.id();
4546 let _cleanup = if status.is_some() {
4547 cx.update(|cx| {
4548 this.update(cx, |this, cx| {
4549 this.on_lsp_work_start(
4550 language_server.server_id(),
4551 ProgressToken::Number(id),
4552 LanguageServerProgress {
4553 is_disk_based_diagnostics_progress: false,
4554 is_cancellable: false,
4555 title: None,
4556 message: status.clone(),
4557 percentage: None,
4558 last_update_at: cx.background_executor().now(),
4559 },
4560 cx,
4561 );
4562 })
4563 })
4564 .log_err();
4565
4566 Some(defer(|| {
4567 cx.update(|cx| {
4568 this.update(cx, |this, cx| {
4569 this.on_lsp_work_end(
4570 language_server.server_id(),
4571 ProgressToken::Number(id),
4572 cx,
4573 );
4574 })
4575 })
4576 .log_err();
4577 }))
4578 } else {
4579 None
4580 };
4581
4582 let result = lsp_request.await.into_response();
4583
4584 let response = result.map_err(|err| {
4585 let message = format!(
4586 "{} via {} failed: {}",
4587 request.display_name(),
4588 language_server.name(),
4589 err
4590 );
4591 // rust-analyzer likes to error with this when its still loading up
4592 if !message.ends_with("content modified") {
4593 log::warn!("{message}");
4594 }
4595 anyhow::anyhow!(message)
4596 })?;
4597
4598 request
4599 .response_from_lsp(
4600 response,
4601 this.upgrade().context("no app context")?,
4602 buffer,
4603 language_server.server_id(),
4604 cx.clone(),
4605 )
4606 .await
4607 })
4608 }
4609
4610 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4611 let mut language_formatters_to_check = Vec::new();
4612 for buffer in self.buffer_store.read(cx).buffers() {
4613 let buffer = buffer.read(cx);
4614 let buffer_file = File::from_dyn(buffer.file());
4615 let buffer_language = buffer.language();
4616 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4617 if buffer_language.is_some() {
4618 language_formatters_to_check.push((
4619 buffer_file.map(|f| f.worktree_id(cx)),
4620 settings.into_owned(),
4621 ));
4622 }
4623 }
4624
4625 self.request_workspace_config_refresh();
4626
4627 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4628 prettier_store.update(cx, |prettier_store, cx| {
4629 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4630 })
4631 }
4632
4633 cx.notify();
4634 }
4635
4636 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4637 let buffer_store = self.buffer_store.clone();
4638 let Some(local) = self.as_local_mut() else {
4639 return;
4640 };
4641 let mut adapters = BTreeMap::default();
4642 let get_adapter = {
4643 let languages = local.languages.clone();
4644 let environment = local.environment.clone();
4645 let weak = local.weak.clone();
4646 let worktree_store = local.worktree_store.clone();
4647 let http_client = local.http_client.clone();
4648 let fs = local.fs.clone();
4649 move |worktree_id, cx: &mut App| {
4650 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4651 Some(LocalLspAdapterDelegate::new(
4652 languages.clone(),
4653 &environment,
4654 weak.clone(),
4655 &worktree,
4656 http_client.clone(),
4657 fs.clone(),
4658 cx,
4659 ))
4660 }
4661 };
4662
4663 let mut messages_to_report = Vec::new();
4664 let (new_tree, to_stop) = {
4665 let mut rebase = local.lsp_tree.rebase();
4666 let buffers = buffer_store
4667 .read(cx)
4668 .buffers()
4669 .filter_map(|buffer| {
4670 let raw_buffer = buffer.read(cx);
4671 if !local
4672 .registered_buffers
4673 .contains_key(&raw_buffer.remote_id())
4674 {
4675 return None;
4676 }
4677 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4678 let language = raw_buffer.language().cloned()?;
4679 Some((file, language, raw_buffer.remote_id()))
4680 })
4681 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4682 for (file, language, buffer_id) in buffers {
4683 let worktree_id = file.worktree_id(cx);
4684 let Some(worktree) = local
4685 .worktree_store
4686 .read(cx)
4687 .worktree_for_id(worktree_id, cx)
4688 else {
4689 continue;
4690 };
4691
4692 if let Some((_, apply)) = local.reuse_existing_language_server(
4693 rebase.server_tree(),
4694 &worktree,
4695 &language.name(),
4696 cx,
4697 ) {
4698 (apply)(rebase.server_tree());
4699 } else if let Some(lsp_delegate) = adapters
4700 .entry(worktree_id)
4701 .or_insert_with(|| get_adapter(worktree_id, cx))
4702 .clone()
4703 {
4704 let delegate =
4705 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4706 let path = file
4707 .path()
4708 .parent()
4709 .map(Arc::from)
4710 .unwrap_or_else(|| file.path().clone());
4711 let worktree_path = ProjectPath { worktree_id, path };
4712 let abs_path = file.abs_path(cx);
4713 let nodes = rebase
4714 .walk(
4715 worktree_path,
4716 language.name(),
4717 language.manifest(),
4718 delegate.clone(),
4719 cx,
4720 )
4721 .collect::<Vec<_>>();
4722 for node in nodes {
4723 let server_id = node.server_id_or_init(|disposition| {
4724 let path = &disposition.path;
4725 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4726 let key = LanguageServerSeed {
4727 worktree_id,
4728 name: disposition.server_name.clone(),
4729 settings: disposition.settings.clone(),
4730 toolchain: local.toolchain_store.read(cx).active_toolchain(
4731 path.worktree_id,
4732 &path.path,
4733 language.name(),
4734 ),
4735 };
4736 local.language_server_ids.remove(&key);
4737
4738 let server_id = local.get_or_insert_language_server(
4739 &worktree,
4740 lsp_delegate.clone(),
4741 disposition,
4742 &language.name(),
4743 cx,
4744 );
4745 if let Some(state) = local.language_servers.get(&server_id)
4746 && let Ok(uri) = uri
4747 {
4748 state.add_workspace_folder(uri);
4749 };
4750 server_id
4751 });
4752
4753 if let Some(language_server_id) = server_id {
4754 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4755 language_server_id,
4756 name: node.name(),
4757 message:
4758 proto::update_language_server::Variant::RegisteredForBuffer(
4759 proto::RegisteredForBuffer {
4760 buffer_abs_path: abs_path
4761 .to_string_lossy()
4762 .into_owned(),
4763 buffer_id: buffer_id.to_proto(),
4764 },
4765 ),
4766 });
4767 }
4768 }
4769 } else {
4770 continue;
4771 }
4772 }
4773 rebase.finish()
4774 };
4775 for message in messages_to_report {
4776 cx.emit(message);
4777 }
4778 local.lsp_tree = new_tree;
4779 for (id, _) in to_stop {
4780 self.stop_local_language_server(id, cx).detach();
4781 }
4782 }
4783
4784 pub fn apply_code_action(
4785 &self,
4786 buffer_handle: Entity<Buffer>,
4787 mut action: CodeAction,
4788 push_to_history: bool,
4789 cx: &mut Context<Self>,
4790 ) -> Task<Result<ProjectTransaction>> {
4791 if let Some((upstream_client, project_id)) = self.upstream_client() {
4792 let request = proto::ApplyCodeAction {
4793 project_id,
4794 buffer_id: buffer_handle.read(cx).remote_id().into(),
4795 action: Some(Self::serialize_code_action(&action)),
4796 };
4797 let buffer_store = self.buffer_store();
4798 cx.spawn(async move |_, cx| {
4799 let response = upstream_client
4800 .request(request)
4801 .await?
4802 .transaction
4803 .context("missing transaction")?;
4804
4805 buffer_store
4806 .update(cx, |buffer_store, cx| {
4807 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4808 })?
4809 .await
4810 })
4811 } else if self.mode.is_local() {
4812 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4813 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4814 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4815 }) else {
4816 return Task::ready(Ok(ProjectTransaction::default()));
4817 };
4818 cx.spawn(async move |this, cx| {
4819 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4820 .await
4821 .context("resolving a code action")?;
4822 if let Some(edit) = action.lsp_action.edit()
4823 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4824 return LocalLspStore::deserialize_workspace_edit(
4825 this.upgrade().context("no app present")?,
4826 edit.clone(),
4827 push_to_history,
4828
4829 lang_server.clone(),
4830 cx,
4831 )
4832 .await;
4833 }
4834
4835 if let Some(command) = action.lsp_action.command() {
4836 let server_capabilities = lang_server.capabilities();
4837 let available_commands = server_capabilities
4838 .execute_command_provider
4839 .as_ref()
4840 .map(|options| options.commands.as_slice())
4841 .unwrap_or_default();
4842 if available_commands.contains(&command.command) {
4843 this.update(cx, |this, _| {
4844 this.as_local_mut()
4845 .unwrap()
4846 .last_workspace_edits_by_language_server
4847 .remove(&lang_server.server_id());
4848 })?;
4849
4850 let _result = lang_server
4851 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4852 command: command.command.clone(),
4853 arguments: command.arguments.clone().unwrap_or_default(),
4854 ..lsp::ExecuteCommandParams::default()
4855 })
4856 .await.into_response()
4857 .context("execute command")?;
4858
4859 return this.update(cx, |this, _| {
4860 this.as_local_mut()
4861 .unwrap()
4862 .last_workspace_edits_by_language_server
4863 .remove(&lang_server.server_id())
4864 .unwrap_or_default()
4865 });
4866 } else {
4867 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4868 }
4869 }
4870
4871 Ok(ProjectTransaction::default())
4872 })
4873 } else {
4874 Task::ready(Err(anyhow!("no upstream client and not local")))
4875 }
4876 }
4877
4878 pub fn apply_code_action_kind(
4879 &mut self,
4880 buffers: HashSet<Entity<Buffer>>,
4881 kind: CodeActionKind,
4882 push_to_history: bool,
4883 cx: &mut Context<Self>,
4884 ) -> Task<anyhow::Result<ProjectTransaction>> {
4885 if self.as_local().is_some() {
4886 cx.spawn(async move |lsp_store, cx| {
4887 let buffers = buffers.into_iter().collect::<Vec<_>>();
4888 let result = LocalLspStore::execute_code_action_kind_locally(
4889 lsp_store.clone(),
4890 buffers,
4891 kind,
4892 push_to_history,
4893 cx,
4894 )
4895 .await;
4896 lsp_store.update(cx, |lsp_store, _| {
4897 lsp_store.update_last_formatting_failure(&result);
4898 })?;
4899 result
4900 })
4901 } else if let Some((client, project_id)) = self.upstream_client() {
4902 let buffer_store = self.buffer_store();
4903 cx.spawn(async move |lsp_store, cx| {
4904 let result = client
4905 .request(proto::ApplyCodeActionKind {
4906 project_id,
4907 kind: kind.as_str().to_owned(),
4908 buffer_ids: buffers
4909 .iter()
4910 .map(|buffer| {
4911 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4912 })
4913 .collect::<Result<_>>()?,
4914 })
4915 .await
4916 .and_then(|result| result.transaction.context("missing transaction"));
4917 lsp_store.update(cx, |lsp_store, _| {
4918 lsp_store.update_last_formatting_failure(&result);
4919 })?;
4920
4921 let transaction_response = result?;
4922 buffer_store
4923 .update(cx, |buffer_store, cx| {
4924 buffer_store.deserialize_project_transaction(
4925 transaction_response,
4926 push_to_history,
4927 cx,
4928 )
4929 })?
4930 .await
4931 })
4932 } else {
4933 Task::ready(Ok(ProjectTransaction::default()))
4934 }
4935 }
4936
4937 pub fn resolved_hint(
4938 &mut self,
4939 buffer_id: BufferId,
4940 id: InlayId,
4941 cx: &mut Context<Self>,
4942 ) -> Option<ResolvedHint> {
4943 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4944
4945 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4946 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4947 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4948 let (server_id, resolve_data) = match &hint.resolve_state {
4949 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4950 ResolveState::Resolving => {
4951 return Some(ResolvedHint::Resolving(
4952 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4953 ));
4954 }
4955 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4956 };
4957
4958 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4959 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4960 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4961 id,
4962 cx.spawn(async move |lsp_store, cx| {
4963 let resolved_hint = resolve_task.await;
4964 lsp_store
4965 .update(cx, |lsp_store, _| {
4966 if let Some(old_inlay_hint) = lsp_store
4967 .lsp_data
4968 .get_mut(&buffer_id)
4969 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4970 {
4971 match resolved_hint {
4972 Ok(resolved_hint) => {
4973 *old_inlay_hint = resolved_hint;
4974 }
4975 Err(e) => {
4976 old_inlay_hint.resolve_state =
4977 ResolveState::CanResolve(server_id, resolve_data);
4978 log::error!("Inlay hint resolve failed: {e:#}");
4979 }
4980 }
4981 }
4982 })
4983 .ok();
4984 })
4985 .shared(),
4986 );
4987 debug_assert!(
4988 previous_task.is_none(),
4989 "Did not change hint's resolve state after spawning its resolve"
4990 );
4991 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4992 None
4993 }
4994
4995 fn resolve_inlay_hint(
4996 &self,
4997 mut hint: InlayHint,
4998 buffer: Entity<Buffer>,
4999 server_id: LanguageServerId,
5000 cx: &mut Context<Self>,
5001 ) -> Task<anyhow::Result<InlayHint>> {
5002 if let Some((upstream_client, project_id)) = self.upstream_client() {
5003 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5004 {
5005 hint.resolve_state = ResolveState::Resolved;
5006 return Task::ready(Ok(hint));
5007 }
5008 let request = proto::ResolveInlayHint {
5009 project_id,
5010 buffer_id: buffer.read(cx).remote_id().into(),
5011 language_server_id: server_id.0 as u64,
5012 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5013 };
5014 cx.background_spawn(async move {
5015 let response = upstream_client
5016 .request(request)
5017 .await
5018 .context("inlay hints proto request")?;
5019 match response.hint {
5020 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5021 .context("inlay hints proto resolve response conversion"),
5022 None => Ok(hint),
5023 }
5024 })
5025 } else {
5026 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5027 self.language_server_for_local_buffer(buffer, server_id, cx)
5028 .map(|(_, server)| server.clone())
5029 }) else {
5030 return Task::ready(Ok(hint));
5031 };
5032 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5033 return Task::ready(Ok(hint));
5034 }
5035 let buffer_snapshot = buffer.read(cx).snapshot();
5036 cx.spawn(async move |_, cx| {
5037 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5038 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5039 );
5040 let resolved_hint = resolve_task
5041 .await
5042 .into_response()
5043 .context("inlay hint resolve LSP request")?;
5044 let resolved_hint = InlayHints::lsp_to_project_hint(
5045 resolved_hint,
5046 &buffer,
5047 server_id,
5048 ResolveState::Resolved,
5049 false,
5050 cx,
5051 )
5052 .await?;
5053 Ok(resolved_hint)
5054 })
5055 }
5056 }
5057
5058 pub fn resolve_color_presentation(
5059 &mut self,
5060 mut color: DocumentColor,
5061 buffer: Entity<Buffer>,
5062 server_id: LanguageServerId,
5063 cx: &mut Context<Self>,
5064 ) -> Task<Result<DocumentColor>> {
5065 if color.resolved {
5066 return Task::ready(Ok(color));
5067 }
5068
5069 if let Some((upstream_client, project_id)) = self.upstream_client() {
5070 let start = color.lsp_range.start;
5071 let end = color.lsp_range.end;
5072 let request = proto::GetColorPresentation {
5073 project_id,
5074 server_id: server_id.to_proto(),
5075 buffer_id: buffer.read(cx).remote_id().into(),
5076 color: Some(proto::ColorInformation {
5077 red: color.color.red,
5078 green: color.color.green,
5079 blue: color.color.blue,
5080 alpha: color.color.alpha,
5081 lsp_range_start: Some(proto::PointUtf16 {
5082 row: start.line,
5083 column: start.character,
5084 }),
5085 lsp_range_end: Some(proto::PointUtf16 {
5086 row: end.line,
5087 column: end.character,
5088 }),
5089 }),
5090 };
5091 cx.background_spawn(async move {
5092 let response = upstream_client
5093 .request(request)
5094 .await
5095 .context("color presentation proto request")?;
5096 color.resolved = true;
5097 color.color_presentations = response
5098 .presentations
5099 .into_iter()
5100 .map(|presentation| ColorPresentation {
5101 label: SharedString::from(presentation.label),
5102 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5103 additional_text_edits: presentation
5104 .additional_text_edits
5105 .into_iter()
5106 .filter_map(deserialize_lsp_edit)
5107 .collect(),
5108 })
5109 .collect();
5110 Ok(color)
5111 })
5112 } else {
5113 let path = match buffer
5114 .update(cx, |buffer, cx| {
5115 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5116 })
5117 .context("buffer with the missing path")
5118 {
5119 Ok(path) => path,
5120 Err(e) => return Task::ready(Err(e)),
5121 };
5122 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5123 self.language_server_for_local_buffer(buffer, server_id, cx)
5124 .map(|(_, server)| server.clone())
5125 }) else {
5126 return Task::ready(Ok(color));
5127 };
5128 cx.background_spawn(async move {
5129 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5130 lsp::ColorPresentationParams {
5131 text_document: make_text_document_identifier(&path)?,
5132 color: color.color,
5133 range: color.lsp_range,
5134 work_done_progress_params: Default::default(),
5135 partial_result_params: Default::default(),
5136 },
5137 );
5138 color.color_presentations = resolve_task
5139 .await
5140 .into_response()
5141 .context("color presentation resolve LSP request")?
5142 .into_iter()
5143 .map(|presentation| ColorPresentation {
5144 label: SharedString::from(presentation.label),
5145 text_edit: presentation.text_edit,
5146 additional_text_edits: presentation
5147 .additional_text_edits
5148 .unwrap_or_default(),
5149 })
5150 .collect();
5151 color.resolved = true;
5152 Ok(color)
5153 })
5154 }
5155 }
5156
5157 pub(crate) fn linked_edits(
5158 &mut self,
5159 buffer: &Entity<Buffer>,
5160 position: Anchor,
5161 cx: &mut Context<Self>,
5162 ) -> Task<Result<Vec<Range<Anchor>>>> {
5163 let snapshot = buffer.read(cx).snapshot();
5164 let scope = snapshot.language_scope_at(position);
5165 let Some(server_id) = self
5166 .as_local()
5167 .and_then(|local| {
5168 buffer.update(cx, |buffer, cx| {
5169 local
5170 .language_servers_for_buffer(buffer, cx)
5171 .filter(|(_, server)| {
5172 LinkedEditingRange::check_server_capabilities(server.capabilities())
5173 })
5174 .filter(|(adapter, _)| {
5175 scope
5176 .as_ref()
5177 .map(|scope| scope.language_allowed(&adapter.name))
5178 .unwrap_or(true)
5179 })
5180 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5181 .next()
5182 })
5183 })
5184 .or_else(|| {
5185 self.upstream_client()
5186 .is_some()
5187 .then_some(LanguageServerToQuery::FirstCapable)
5188 })
5189 .filter(|_| {
5190 maybe!({
5191 let language = buffer.read(cx).language_at(position)?;
5192 Some(
5193 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5194 .linked_edits,
5195 )
5196 }) == Some(true)
5197 })
5198 else {
5199 return Task::ready(Ok(Vec::new()));
5200 };
5201
5202 self.request_lsp(
5203 buffer.clone(),
5204 server_id,
5205 LinkedEditingRange { position },
5206 cx,
5207 )
5208 }
5209
5210 fn apply_on_type_formatting(
5211 &mut self,
5212 buffer: Entity<Buffer>,
5213 position: Anchor,
5214 trigger: String,
5215 cx: &mut Context<Self>,
5216 ) -> Task<Result<Option<Transaction>>> {
5217 if let Some((client, project_id)) = self.upstream_client() {
5218 if !self.check_if_capable_for_proto_request(
5219 &buffer,
5220 |capabilities| {
5221 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5222 },
5223 cx,
5224 ) {
5225 return Task::ready(Ok(None));
5226 }
5227 let request = proto::OnTypeFormatting {
5228 project_id,
5229 buffer_id: buffer.read(cx).remote_id().into(),
5230 position: Some(serialize_anchor(&position)),
5231 trigger,
5232 version: serialize_version(&buffer.read(cx).version()),
5233 };
5234 cx.background_spawn(async move {
5235 client
5236 .request(request)
5237 .await?
5238 .transaction
5239 .map(language::proto::deserialize_transaction)
5240 .transpose()
5241 })
5242 } else if let Some(local) = self.as_local_mut() {
5243 let buffer_id = buffer.read(cx).remote_id();
5244 local.buffers_being_formatted.insert(buffer_id);
5245 cx.spawn(async move |this, cx| {
5246 let _cleanup = defer({
5247 let this = this.clone();
5248 let mut cx = cx.clone();
5249 move || {
5250 this.update(&mut cx, |this, _| {
5251 if let Some(local) = this.as_local_mut() {
5252 local.buffers_being_formatted.remove(&buffer_id);
5253 }
5254 })
5255 .ok();
5256 }
5257 });
5258
5259 buffer
5260 .update(cx, |buffer, _| {
5261 buffer.wait_for_edits(Some(position.timestamp))
5262 })?
5263 .await?;
5264 this.update(cx, |this, cx| {
5265 let position = position.to_point_utf16(buffer.read(cx));
5266 this.on_type_format(buffer, position, trigger, false, cx)
5267 })?
5268 .await
5269 })
5270 } else {
5271 Task::ready(Err(anyhow!("No upstream client or local language server")))
5272 }
5273 }
5274
5275 pub fn on_type_format<T: ToPointUtf16>(
5276 &mut self,
5277 buffer: Entity<Buffer>,
5278 position: T,
5279 trigger: String,
5280 push_to_history: bool,
5281 cx: &mut Context<Self>,
5282 ) -> Task<Result<Option<Transaction>>> {
5283 let position = position.to_point_utf16(buffer.read(cx));
5284 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5285 }
5286
5287 fn on_type_format_impl(
5288 &mut self,
5289 buffer: Entity<Buffer>,
5290 position: PointUtf16,
5291 trigger: String,
5292 push_to_history: bool,
5293 cx: &mut Context<Self>,
5294 ) -> Task<Result<Option<Transaction>>> {
5295 let options = buffer.update(cx, |buffer, cx| {
5296 lsp_command::lsp_formatting_options(
5297 language_settings(
5298 buffer.language_at(position).map(|l| l.name()),
5299 buffer.file(),
5300 cx,
5301 )
5302 .as_ref(),
5303 )
5304 });
5305
5306 cx.spawn(async move |this, cx| {
5307 if let Some(waiter) =
5308 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5309 {
5310 waiter.await?;
5311 }
5312 cx.update(|cx| {
5313 this.update(cx, |this, cx| {
5314 this.request_lsp(
5315 buffer.clone(),
5316 LanguageServerToQuery::FirstCapable,
5317 OnTypeFormatting {
5318 position,
5319 trigger,
5320 options,
5321 push_to_history,
5322 },
5323 cx,
5324 )
5325 })
5326 })??
5327 .await
5328 })
5329 }
5330
5331 pub fn definitions(
5332 &mut self,
5333 buffer: &Entity<Buffer>,
5334 position: PointUtf16,
5335 cx: &mut Context<Self>,
5336 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5337 if let Some((upstream_client, project_id)) = self.upstream_client() {
5338 let request = GetDefinitions { position };
5339 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5340 return Task::ready(Ok(None));
5341 }
5342 let request_task = upstream_client.request_lsp(
5343 project_id,
5344 None,
5345 LSP_REQUEST_TIMEOUT,
5346 cx.background_executor().clone(),
5347 request.to_proto(project_id, buffer.read(cx)),
5348 );
5349 let buffer = buffer.clone();
5350 cx.spawn(async move |weak_lsp_store, cx| {
5351 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5352 return Ok(None);
5353 };
5354 let Some(responses) = request_task.await? else {
5355 return Ok(None);
5356 };
5357 let actions = join_all(responses.payload.into_iter().map(|response| {
5358 GetDefinitions { position }.response_from_proto(
5359 response.response,
5360 lsp_store.clone(),
5361 buffer.clone(),
5362 cx.clone(),
5363 )
5364 }))
5365 .await;
5366
5367 Ok(Some(
5368 actions
5369 .into_iter()
5370 .collect::<Result<Vec<Vec<_>>>>()?
5371 .into_iter()
5372 .flatten()
5373 .dedup()
5374 .collect(),
5375 ))
5376 })
5377 } else {
5378 let definitions_task = self.request_multiple_lsp_locally(
5379 buffer,
5380 Some(position),
5381 GetDefinitions { position },
5382 cx,
5383 );
5384 cx.background_spawn(async move {
5385 Ok(Some(
5386 definitions_task
5387 .await
5388 .into_iter()
5389 .flat_map(|(_, definitions)| definitions)
5390 .dedup()
5391 .collect(),
5392 ))
5393 })
5394 }
5395 }
5396
5397 pub fn declarations(
5398 &mut self,
5399 buffer: &Entity<Buffer>,
5400 position: PointUtf16,
5401 cx: &mut Context<Self>,
5402 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5403 if let Some((upstream_client, project_id)) = self.upstream_client() {
5404 let request = GetDeclarations { position };
5405 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5406 return Task::ready(Ok(None));
5407 }
5408 let request_task = upstream_client.request_lsp(
5409 project_id,
5410 None,
5411 LSP_REQUEST_TIMEOUT,
5412 cx.background_executor().clone(),
5413 request.to_proto(project_id, buffer.read(cx)),
5414 );
5415 let buffer = buffer.clone();
5416 cx.spawn(async move |weak_lsp_store, cx| {
5417 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5418 return Ok(None);
5419 };
5420 let Some(responses) = request_task.await? else {
5421 return Ok(None);
5422 };
5423 let actions = join_all(responses.payload.into_iter().map(|response| {
5424 GetDeclarations { position }.response_from_proto(
5425 response.response,
5426 lsp_store.clone(),
5427 buffer.clone(),
5428 cx.clone(),
5429 )
5430 }))
5431 .await;
5432
5433 Ok(Some(
5434 actions
5435 .into_iter()
5436 .collect::<Result<Vec<Vec<_>>>>()?
5437 .into_iter()
5438 .flatten()
5439 .dedup()
5440 .collect(),
5441 ))
5442 })
5443 } else {
5444 let declarations_task = self.request_multiple_lsp_locally(
5445 buffer,
5446 Some(position),
5447 GetDeclarations { position },
5448 cx,
5449 );
5450 cx.background_spawn(async move {
5451 Ok(Some(
5452 declarations_task
5453 .await
5454 .into_iter()
5455 .flat_map(|(_, declarations)| declarations)
5456 .dedup()
5457 .collect(),
5458 ))
5459 })
5460 }
5461 }
5462
5463 pub fn type_definitions(
5464 &mut self,
5465 buffer: &Entity<Buffer>,
5466 position: PointUtf16,
5467 cx: &mut Context<Self>,
5468 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5469 if let Some((upstream_client, project_id)) = self.upstream_client() {
5470 let request = GetTypeDefinitions { position };
5471 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5472 return Task::ready(Ok(None));
5473 }
5474 let request_task = upstream_client.request_lsp(
5475 project_id,
5476 None,
5477 LSP_REQUEST_TIMEOUT,
5478 cx.background_executor().clone(),
5479 request.to_proto(project_id, buffer.read(cx)),
5480 );
5481 let buffer = buffer.clone();
5482 cx.spawn(async move |weak_lsp_store, cx| {
5483 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5484 return Ok(None);
5485 };
5486 let Some(responses) = request_task.await? else {
5487 return Ok(None);
5488 };
5489 let actions = join_all(responses.payload.into_iter().map(|response| {
5490 GetTypeDefinitions { position }.response_from_proto(
5491 response.response,
5492 lsp_store.clone(),
5493 buffer.clone(),
5494 cx.clone(),
5495 )
5496 }))
5497 .await;
5498
5499 Ok(Some(
5500 actions
5501 .into_iter()
5502 .collect::<Result<Vec<Vec<_>>>>()?
5503 .into_iter()
5504 .flatten()
5505 .dedup()
5506 .collect(),
5507 ))
5508 })
5509 } else {
5510 let type_definitions_task = self.request_multiple_lsp_locally(
5511 buffer,
5512 Some(position),
5513 GetTypeDefinitions { position },
5514 cx,
5515 );
5516 cx.background_spawn(async move {
5517 Ok(Some(
5518 type_definitions_task
5519 .await
5520 .into_iter()
5521 .flat_map(|(_, type_definitions)| type_definitions)
5522 .dedup()
5523 .collect(),
5524 ))
5525 })
5526 }
5527 }
5528
5529 pub fn implementations(
5530 &mut self,
5531 buffer: &Entity<Buffer>,
5532 position: PointUtf16,
5533 cx: &mut Context<Self>,
5534 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5535 if let Some((upstream_client, project_id)) = self.upstream_client() {
5536 let request = GetImplementations { position };
5537 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5538 return Task::ready(Ok(None));
5539 }
5540 let request_task = upstream_client.request_lsp(
5541 project_id,
5542 None,
5543 LSP_REQUEST_TIMEOUT,
5544 cx.background_executor().clone(),
5545 request.to_proto(project_id, buffer.read(cx)),
5546 );
5547 let buffer = buffer.clone();
5548 cx.spawn(async move |weak_lsp_store, cx| {
5549 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5550 return Ok(None);
5551 };
5552 let Some(responses) = request_task.await? else {
5553 return Ok(None);
5554 };
5555 let actions = join_all(responses.payload.into_iter().map(|response| {
5556 GetImplementations { position }.response_from_proto(
5557 response.response,
5558 lsp_store.clone(),
5559 buffer.clone(),
5560 cx.clone(),
5561 )
5562 }))
5563 .await;
5564
5565 Ok(Some(
5566 actions
5567 .into_iter()
5568 .collect::<Result<Vec<Vec<_>>>>()?
5569 .into_iter()
5570 .flatten()
5571 .dedup()
5572 .collect(),
5573 ))
5574 })
5575 } else {
5576 let implementations_task = self.request_multiple_lsp_locally(
5577 buffer,
5578 Some(position),
5579 GetImplementations { position },
5580 cx,
5581 );
5582 cx.background_spawn(async move {
5583 Ok(Some(
5584 implementations_task
5585 .await
5586 .into_iter()
5587 .flat_map(|(_, implementations)| implementations)
5588 .dedup()
5589 .collect(),
5590 ))
5591 })
5592 }
5593 }
5594
5595 pub fn references(
5596 &mut self,
5597 buffer: &Entity<Buffer>,
5598 position: PointUtf16,
5599 cx: &mut Context<Self>,
5600 ) -> Task<Result<Option<Vec<Location>>>> {
5601 if let Some((upstream_client, project_id)) = self.upstream_client() {
5602 let request = GetReferences { position };
5603 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5604 return Task::ready(Ok(None));
5605 }
5606
5607 let request_task = upstream_client.request_lsp(
5608 project_id,
5609 None,
5610 LSP_REQUEST_TIMEOUT,
5611 cx.background_executor().clone(),
5612 request.to_proto(project_id, buffer.read(cx)),
5613 );
5614 let buffer = buffer.clone();
5615 cx.spawn(async move |weak_lsp_store, cx| {
5616 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5617 return Ok(None);
5618 };
5619 let Some(responses) = request_task.await? else {
5620 return Ok(None);
5621 };
5622
5623 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5624 GetReferences { position }.response_from_proto(
5625 lsp_response.response,
5626 lsp_store.clone(),
5627 buffer.clone(),
5628 cx.clone(),
5629 )
5630 }))
5631 .await
5632 .into_iter()
5633 .collect::<Result<Vec<Vec<_>>>>()?
5634 .into_iter()
5635 .flatten()
5636 .dedup()
5637 .collect();
5638 Ok(Some(locations))
5639 })
5640 } else {
5641 let references_task = self.request_multiple_lsp_locally(
5642 buffer,
5643 Some(position),
5644 GetReferences { position },
5645 cx,
5646 );
5647 cx.background_spawn(async move {
5648 Ok(Some(
5649 references_task
5650 .await
5651 .into_iter()
5652 .flat_map(|(_, references)| references)
5653 .dedup()
5654 .collect(),
5655 ))
5656 })
5657 }
5658 }
5659
5660 pub fn code_actions(
5661 &mut self,
5662 buffer: &Entity<Buffer>,
5663 range: Range<Anchor>,
5664 kinds: Option<Vec<CodeActionKind>>,
5665 cx: &mut Context<Self>,
5666 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5667 if let Some((upstream_client, project_id)) = self.upstream_client() {
5668 let request = GetCodeActions {
5669 range: range.clone(),
5670 kinds: kinds.clone(),
5671 };
5672 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5673 return Task::ready(Ok(None));
5674 }
5675 let request_task = upstream_client.request_lsp(
5676 project_id,
5677 None,
5678 LSP_REQUEST_TIMEOUT,
5679 cx.background_executor().clone(),
5680 request.to_proto(project_id, buffer.read(cx)),
5681 );
5682 let buffer = buffer.clone();
5683 cx.spawn(async move |weak_lsp_store, cx| {
5684 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5685 return Ok(None);
5686 };
5687 let Some(responses) = request_task.await? else {
5688 return Ok(None);
5689 };
5690 let actions = join_all(responses.payload.into_iter().map(|response| {
5691 GetCodeActions {
5692 range: range.clone(),
5693 kinds: kinds.clone(),
5694 }
5695 .response_from_proto(
5696 response.response,
5697 lsp_store.clone(),
5698 buffer.clone(),
5699 cx.clone(),
5700 )
5701 }))
5702 .await;
5703
5704 Ok(Some(
5705 actions
5706 .into_iter()
5707 .collect::<Result<Vec<Vec<_>>>>()?
5708 .into_iter()
5709 .flatten()
5710 .collect(),
5711 ))
5712 })
5713 } else {
5714 let all_actions_task = self.request_multiple_lsp_locally(
5715 buffer,
5716 Some(range.start),
5717 GetCodeActions { range, kinds },
5718 cx,
5719 );
5720 cx.background_spawn(async move {
5721 Ok(Some(
5722 all_actions_task
5723 .await
5724 .into_iter()
5725 .flat_map(|(_, actions)| actions)
5726 .collect(),
5727 ))
5728 })
5729 }
5730 }
5731
5732 pub fn code_lens_actions(
5733 &mut self,
5734 buffer: &Entity<Buffer>,
5735 cx: &mut Context<Self>,
5736 ) -> CodeLensTask {
5737 let version_queried_for = buffer.read(cx).version();
5738 let buffer_id = buffer.read(cx).remote_id();
5739 let existing_servers = self.as_local().map(|local| {
5740 local
5741 .buffers_opened_in_servers
5742 .get(&buffer_id)
5743 .cloned()
5744 .unwrap_or_default()
5745 });
5746
5747 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5748 if let Some(cached_lens) = &lsp_data.code_lens {
5749 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5750 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5751 existing_servers != cached_lens.lens.keys().copied().collect()
5752 });
5753 if !has_different_servers {
5754 return Task::ready(Ok(Some(
5755 cached_lens.lens.values().flatten().cloned().collect(),
5756 )))
5757 .shared();
5758 }
5759 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5760 if !version_queried_for.changed_since(updating_for) {
5761 return running_update.clone();
5762 }
5763 }
5764 }
5765 }
5766
5767 let lens_lsp_data = self
5768 .latest_lsp_data(buffer, cx)
5769 .code_lens
5770 .get_or_insert_default();
5771 let buffer = buffer.clone();
5772 let query_version_queried_for = version_queried_for.clone();
5773 let new_task = cx
5774 .spawn(async move |lsp_store, cx| {
5775 cx.background_executor()
5776 .timer(Duration::from_millis(30))
5777 .await;
5778 let fetched_lens = lsp_store
5779 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5780 .map_err(Arc::new)?
5781 .await
5782 .context("fetching code lens")
5783 .map_err(Arc::new);
5784 let fetched_lens = match fetched_lens {
5785 Ok(fetched_lens) => fetched_lens,
5786 Err(e) => {
5787 lsp_store
5788 .update(cx, |lsp_store, _| {
5789 if let Some(lens_lsp_data) = lsp_store
5790 .lsp_data
5791 .get_mut(&buffer_id)
5792 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5793 {
5794 lens_lsp_data.update = None;
5795 }
5796 })
5797 .ok();
5798 return Err(e);
5799 }
5800 };
5801
5802 lsp_store
5803 .update(cx, |lsp_store, _| {
5804 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5805 let code_lens = lsp_data.code_lens.as_mut()?;
5806 if let Some(fetched_lens) = fetched_lens {
5807 if lsp_data.buffer_version == query_version_queried_for {
5808 code_lens.lens.extend(fetched_lens);
5809 } else if !lsp_data
5810 .buffer_version
5811 .changed_since(&query_version_queried_for)
5812 {
5813 lsp_data.buffer_version = query_version_queried_for;
5814 code_lens.lens = fetched_lens;
5815 }
5816 }
5817 code_lens.update = None;
5818 Some(code_lens.lens.values().flatten().cloned().collect())
5819 })
5820 .map_err(Arc::new)
5821 })
5822 .shared();
5823 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5824 new_task
5825 }
5826
5827 fn fetch_code_lens(
5828 &mut self,
5829 buffer: &Entity<Buffer>,
5830 cx: &mut Context<Self>,
5831 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5832 if let Some((upstream_client, project_id)) = self.upstream_client() {
5833 let request = GetCodeLens;
5834 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5835 return Task::ready(Ok(None));
5836 }
5837 let request_task = upstream_client.request_lsp(
5838 project_id,
5839 None,
5840 LSP_REQUEST_TIMEOUT,
5841 cx.background_executor().clone(),
5842 request.to_proto(project_id, buffer.read(cx)),
5843 );
5844 let buffer = buffer.clone();
5845 cx.spawn(async move |weak_lsp_store, cx| {
5846 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5847 return Ok(None);
5848 };
5849 let Some(responses) = request_task.await? else {
5850 return Ok(None);
5851 };
5852
5853 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5854 let lsp_store = lsp_store.clone();
5855 let buffer = buffer.clone();
5856 let cx = cx.clone();
5857 async move {
5858 (
5859 LanguageServerId::from_proto(response.server_id),
5860 GetCodeLens
5861 .response_from_proto(response.response, lsp_store, buffer, cx)
5862 .await,
5863 )
5864 }
5865 }))
5866 .await;
5867
5868 let mut has_errors = false;
5869 let code_lens_actions = code_lens_actions
5870 .into_iter()
5871 .filter_map(|(server_id, code_lens)| match code_lens {
5872 Ok(code_lens) => Some((server_id, code_lens)),
5873 Err(e) => {
5874 has_errors = true;
5875 log::error!("{e:#}");
5876 None
5877 }
5878 })
5879 .collect::<HashMap<_, _>>();
5880 anyhow::ensure!(
5881 !has_errors || !code_lens_actions.is_empty(),
5882 "Failed to fetch code lens"
5883 );
5884 Ok(Some(code_lens_actions))
5885 })
5886 } else {
5887 let code_lens_actions_task =
5888 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5889 cx.background_spawn(async move {
5890 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5891 })
5892 }
5893 }
5894
5895 #[inline(never)]
5896 pub fn completions(
5897 &self,
5898 buffer: &Entity<Buffer>,
5899 position: PointUtf16,
5900 context: CompletionContext,
5901 cx: &mut Context<Self>,
5902 ) -> Task<Result<Vec<CompletionResponse>>> {
5903 let language_registry = self.languages.clone();
5904
5905 if let Some((upstream_client, project_id)) = self.upstream_client() {
5906 let request = GetCompletions { position, context };
5907 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5908 return Task::ready(Ok(Vec::new()));
5909 }
5910 let task = self.send_lsp_proto_request(
5911 buffer.clone(),
5912 upstream_client,
5913 project_id,
5914 request,
5915 cx,
5916 );
5917 let language = buffer.read(cx).language().cloned();
5918
5919 // In the future, we should provide project guests with the names of LSP adapters,
5920 // so that they can use the correct LSP adapter when computing labels. For now,
5921 // guests just use the first LSP adapter associated with the buffer's language.
5922 let lsp_adapter = language.as_ref().and_then(|language| {
5923 language_registry
5924 .lsp_adapters(&language.name())
5925 .first()
5926 .cloned()
5927 });
5928
5929 cx.foreground_executor().spawn(async move {
5930 let completion_response = task.await?;
5931 let completions = populate_labels_for_completions(
5932 completion_response.completions,
5933 language,
5934 lsp_adapter,
5935 )
5936 .await;
5937 Ok(vec![CompletionResponse {
5938 completions,
5939 display_options: CompletionDisplayOptions::default(),
5940 is_incomplete: completion_response.is_incomplete,
5941 }])
5942 })
5943 } else if let Some(local) = self.as_local() {
5944 let snapshot = buffer.read(cx).snapshot();
5945 let offset = position.to_offset(&snapshot);
5946 let scope = snapshot.language_scope_at(offset);
5947 let language = snapshot.language().cloned();
5948 let completion_settings = language_settings(
5949 language.as_ref().map(|language| language.name()),
5950 buffer.read(cx).file(),
5951 cx,
5952 )
5953 .completions
5954 .clone();
5955 if !completion_settings.lsp {
5956 return Task::ready(Ok(Vec::new()));
5957 }
5958
5959 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5960 local
5961 .language_servers_for_buffer(buffer, cx)
5962 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5963 .filter(|(adapter, _)| {
5964 scope
5965 .as_ref()
5966 .map(|scope| scope.language_allowed(&adapter.name))
5967 .unwrap_or(true)
5968 })
5969 .map(|(_, server)| server.server_id())
5970 .collect()
5971 });
5972
5973 let buffer = buffer.clone();
5974 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5975 let lsp_timeout = if lsp_timeout > 0 {
5976 Some(Duration::from_millis(lsp_timeout))
5977 } else {
5978 None
5979 };
5980 cx.spawn(async move |this, cx| {
5981 let mut tasks = Vec::with_capacity(server_ids.len());
5982 this.update(cx, |lsp_store, cx| {
5983 for server_id in server_ids {
5984 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5985 let lsp_timeout = lsp_timeout
5986 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5987 let mut timeout = cx.background_spawn(async move {
5988 match lsp_timeout {
5989 Some(lsp_timeout) => {
5990 lsp_timeout.await;
5991 true
5992 },
5993 None => false,
5994 }
5995 }).fuse();
5996 let mut lsp_request = lsp_store.request_lsp(
5997 buffer.clone(),
5998 LanguageServerToQuery::Other(server_id),
5999 GetCompletions {
6000 position,
6001 context: context.clone(),
6002 },
6003 cx,
6004 ).fuse();
6005 let new_task = cx.background_spawn(async move {
6006 select_biased! {
6007 response = lsp_request => anyhow::Ok(Some(response?)),
6008 timeout_happened = timeout => {
6009 if timeout_happened {
6010 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6011 Ok(None)
6012 } else {
6013 let completions = lsp_request.await?;
6014 Ok(Some(completions))
6015 }
6016 },
6017 }
6018 });
6019 tasks.push((lsp_adapter, new_task));
6020 }
6021 })?;
6022
6023 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6024 let completion_response = task.await.ok()??;
6025 let completions = populate_labels_for_completions(
6026 completion_response.completions,
6027 language.clone(),
6028 lsp_adapter,
6029 )
6030 .await;
6031 Some(CompletionResponse {
6032 completions,
6033 display_options: CompletionDisplayOptions::default(),
6034 is_incomplete: completion_response.is_incomplete,
6035 })
6036 });
6037
6038 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6039
6040 Ok(responses.into_iter().flatten().collect())
6041 })
6042 } else {
6043 Task::ready(Err(anyhow!("No upstream client or local language server")))
6044 }
6045 }
6046
6047 pub fn resolve_completions(
6048 &self,
6049 buffer: Entity<Buffer>,
6050 completion_indices: Vec<usize>,
6051 completions: Rc<RefCell<Box<[Completion]>>>,
6052 cx: &mut Context<Self>,
6053 ) -> Task<Result<bool>> {
6054 let client = self.upstream_client();
6055 let buffer_id = buffer.read(cx).remote_id();
6056 let buffer_snapshot = buffer.read(cx).snapshot();
6057
6058 if !self.check_if_capable_for_proto_request(
6059 &buffer,
6060 GetCompletions::can_resolve_completions,
6061 cx,
6062 ) {
6063 return Task::ready(Ok(false));
6064 }
6065 cx.spawn(async move |lsp_store, cx| {
6066 let mut did_resolve = false;
6067 if let Some((client, project_id)) = client {
6068 for completion_index in completion_indices {
6069 let server_id = {
6070 let completion = &completions.borrow()[completion_index];
6071 completion.source.server_id()
6072 };
6073 if let Some(server_id) = server_id {
6074 if Self::resolve_completion_remote(
6075 project_id,
6076 server_id,
6077 buffer_id,
6078 completions.clone(),
6079 completion_index,
6080 client.clone(),
6081 )
6082 .await
6083 .log_err()
6084 .is_some()
6085 {
6086 did_resolve = true;
6087 }
6088 } else {
6089 resolve_word_completion(
6090 &buffer_snapshot,
6091 &mut completions.borrow_mut()[completion_index],
6092 );
6093 }
6094 }
6095 } else {
6096 for completion_index in completion_indices {
6097 let server_id = {
6098 let completion = &completions.borrow()[completion_index];
6099 completion.source.server_id()
6100 };
6101 if let Some(server_id) = server_id {
6102 let server_and_adapter = lsp_store
6103 .read_with(cx, |lsp_store, _| {
6104 let server = lsp_store.language_server_for_id(server_id)?;
6105 let adapter =
6106 lsp_store.language_server_adapter_for_id(server.server_id())?;
6107 Some((server, adapter))
6108 })
6109 .ok()
6110 .flatten();
6111 let Some((server, adapter)) = server_and_adapter else {
6112 continue;
6113 };
6114
6115 let resolved = Self::resolve_completion_local(
6116 server,
6117 completions.clone(),
6118 completion_index,
6119 )
6120 .await
6121 .log_err()
6122 .is_some();
6123 if resolved {
6124 Self::regenerate_completion_labels(
6125 adapter,
6126 &buffer_snapshot,
6127 completions.clone(),
6128 completion_index,
6129 )
6130 .await
6131 .log_err();
6132 did_resolve = true;
6133 }
6134 } else {
6135 resolve_word_completion(
6136 &buffer_snapshot,
6137 &mut completions.borrow_mut()[completion_index],
6138 );
6139 }
6140 }
6141 }
6142
6143 Ok(did_resolve)
6144 })
6145 }
6146
6147 async fn resolve_completion_local(
6148 server: Arc<lsp::LanguageServer>,
6149 completions: Rc<RefCell<Box<[Completion]>>>,
6150 completion_index: usize,
6151 ) -> Result<()> {
6152 let server_id = server.server_id();
6153 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6154 return Ok(());
6155 }
6156
6157 let request = {
6158 let completion = &completions.borrow()[completion_index];
6159 match &completion.source {
6160 CompletionSource::Lsp {
6161 lsp_completion,
6162 resolved,
6163 server_id: completion_server_id,
6164 ..
6165 } => {
6166 if *resolved {
6167 return Ok(());
6168 }
6169 anyhow::ensure!(
6170 server_id == *completion_server_id,
6171 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6172 );
6173 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6174 }
6175 CompletionSource::BufferWord { .. }
6176 | CompletionSource::Dap { .. }
6177 | CompletionSource::Custom => {
6178 return Ok(());
6179 }
6180 }
6181 };
6182 let resolved_completion = request
6183 .await
6184 .into_response()
6185 .context("resolve completion")?;
6186
6187 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6188 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6189
6190 let mut completions = completions.borrow_mut();
6191 let completion = &mut completions[completion_index];
6192 if let CompletionSource::Lsp {
6193 lsp_completion,
6194 resolved,
6195 server_id: completion_server_id,
6196 ..
6197 } = &mut completion.source
6198 {
6199 if *resolved {
6200 return Ok(());
6201 }
6202 anyhow::ensure!(
6203 server_id == *completion_server_id,
6204 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6205 );
6206 *lsp_completion = Box::new(resolved_completion);
6207 *resolved = true;
6208 }
6209 Ok(())
6210 }
6211
6212 async fn regenerate_completion_labels(
6213 adapter: Arc<CachedLspAdapter>,
6214 snapshot: &BufferSnapshot,
6215 completions: Rc<RefCell<Box<[Completion]>>>,
6216 completion_index: usize,
6217 ) -> Result<()> {
6218 let completion_item = completions.borrow()[completion_index]
6219 .source
6220 .lsp_completion(true)
6221 .map(Cow::into_owned);
6222 if let Some(lsp_documentation) = completion_item
6223 .as_ref()
6224 .and_then(|completion_item| completion_item.documentation.clone())
6225 {
6226 let mut completions = completions.borrow_mut();
6227 let completion = &mut completions[completion_index];
6228 completion.documentation = Some(lsp_documentation.into());
6229 } else {
6230 let mut completions = completions.borrow_mut();
6231 let completion = &mut completions[completion_index];
6232 completion.documentation = Some(CompletionDocumentation::Undocumented);
6233 }
6234
6235 let mut new_label = match completion_item {
6236 Some(completion_item) => {
6237 // 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
6238 // So we have to update the label here anyway...
6239 let language = snapshot.language();
6240 match language {
6241 Some(language) => {
6242 adapter
6243 .labels_for_completions(
6244 std::slice::from_ref(&completion_item),
6245 language,
6246 )
6247 .await?
6248 }
6249 None => Vec::new(),
6250 }
6251 .pop()
6252 .flatten()
6253 .unwrap_or_else(|| {
6254 CodeLabel::fallback_for_completion(
6255 &completion_item,
6256 language.map(|language| language.as_ref()),
6257 )
6258 })
6259 }
6260 None => CodeLabel::plain(
6261 completions.borrow()[completion_index].new_text.clone(),
6262 None,
6263 ),
6264 };
6265 ensure_uniform_list_compatible_label(&mut new_label);
6266
6267 let mut completions = completions.borrow_mut();
6268 let completion = &mut completions[completion_index];
6269 if completion.label.filter_text() == new_label.filter_text() {
6270 completion.label = new_label;
6271 } else {
6272 log::error!(
6273 "Resolved completion changed display label from {} to {}. \
6274 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6275 completion.label.text(),
6276 new_label.text(),
6277 completion.label.filter_text(),
6278 new_label.filter_text()
6279 );
6280 }
6281
6282 Ok(())
6283 }
6284
6285 async fn resolve_completion_remote(
6286 project_id: u64,
6287 server_id: LanguageServerId,
6288 buffer_id: BufferId,
6289 completions: Rc<RefCell<Box<[Completion]>>>,
6290 completion_index: usize,
6291 client: AnyProtoClient,
6292 ) -> Result<()> {
6293 let lsp_completion = {
6294 let completion = &completions.borrow()[completion_index];
6295 match &completion.source {
6296 CompletionSource::Lsp {
6297 lsp_completion,
6298 resolved,
6299 server_id: completion_server_id,
6300 ..
6301 } => {
6302 anyhow::ensure!(
6303 server_id == *completion_server_id,
6304 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6305 );
6306 if *resolved {
6307 return Ok(());
6308 }
6309 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6310 }
6311 CompletionSource::Custom
6312 | CompletionSource::Dap { .. }
6313 | CompletionSource::BufferWord { .. } => {
6314 return Ok(());
6315 }
6316 }
6317 };
6318 let request = proto::ResolveCompletionDocumentation {
6319 project_id,
6320 language_server_id: server_id.0 as u64,
6321 lsp_completion,
6322 buffer_id: buffer_id.into(),
6323 };
6324
6325 let response = client
6326 .request(request)
6327 .await
6328 .context("completion documentation resolve proto request")?;
6329 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6330
6331 let documentation = if response.documentation.is_empty() {
6332 CompletionDocumentation::Undocumented
6333 } else if response.documentation_is_markdown {
6334 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6335 } else if response.documentation.lines().count() <= 1 {
6336 CompletionDocumentation::SingleLine(response.documentation.into())
6337 } else {
6338 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6339 };
6340
6341 let mut completions = completions.borrow_mut();
6342 let completion = &mut completions[completion_index];
6343 completion.documentation = Some(documentation);
6344 if let CompletionSource::Lsp {
6345 insert_range,
6346 lsp_completion,
6347 resolved,
6348 server_id: completion_server_id,
6349 lsp_defaults: _,
6350 } = &mut completion.source
6351 {
6352 let completion_insert_range = response
6353 .old_insert_start
6354 .and_then(deserialize_anchor)
6355 .zip(response.old_insert_end.and_then(deserialize_anchor));
6356 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6357
6358 if *resolved {
6359 return Ok(());
6360 }
6361 anyhow::ensure!(
6362 server_id == *completion_server_id,
6363 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6364 );
6365 *lsp_completion = Box::new(resolved_lsp_completion);
6366 *resolved = true;
6367 }
6368
6369 let replace_range = response
6370 .old_replace_start
6371 .and_then(deserialize_anchor)
6372 .zip(response.old_replace_end.and_then(deserialize_anchor));
6373 if let Some((old_replace_start, old_replace_end)) = replace_range
6374 && !response.new_text.is_empty()
6375 {
6376 completion.new_text = response.new_text;
6377 completion.replace_range = old_replace_start..old_replace_end;
6378 }
6379
6380 Ok(())
6381 }
6382
6383 pub fn apply_additional_edits_for_completion(
6384 &self,
6385 buffer_handle: Entity<Buffer>,
6386 completions: Rc<RefCell<Box<[Completion]>>>,
6387 completion_index: usize,
6388 push_to_history: bool,
6389 cx: &mut Context<Self>,
6390 ) -> Task<Result<Option<Transaction>>> {
6391 if let Some((client, project_id)) = self.upstream_client() {
6392 let buffer = buffer_handle.read(cx);
6393 let buffer_id = buffer.remote_id();
6394 cx.spawn(async move |_, cx| {
6395 let request = {
6396 let completion = completions.borrow()[completion_index].clone();
6397 proto::ApplyCompletionAdditionalEdits {
6398 project_id,
6399 buffer_id: buffer_id.into(),
6400 completion: Some(Self::serialize_completion(&CoreCompletion {
6401 replace_range: completion.replace_range,
6402 new_text: completion.new_text,
6403 source: completion.source,
6404 })),
6405 }
6406 };
6407
6408 if let Some(transaction) = client.request(request).await?.transaction {
6409 let transaction = language::proto::deserialize_transaction(transaction)?;
6410 buffer_handle
6411 .update(cx, |buffer, _| {
6412 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6413 })?
6414 .await?;
6415 if push_to_history {
6416 buffer_handle.update(cx, |buffer, _| {
6417 buffer.push_transaction(transaction.clone(), Instant::now());
6418 buffer.finalize_last_transaction();
6419 })?;
6420 }
6421 Ok(Some(transaction))
6422 } else {
6423 Ok(None)
6424 }
6425 })
6426 } else {
6427 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6428 let completion = &completions.borrow()[completion_index];
6429 let server_id = completion.source.server_id()?;
6430 Some(
6431 self.language_server_for_local_buffer(buffer, server_id, cx)?
6432 .1
6433 .clone(),
6434 )
6435 }) else {
6436 return Task::ready(Ok(None));
6437 };
6438
6439 cx.spawn(async move |this, cx| {
6440 Self::resolve_completion_local(
6441 server.clone(),
6442 completions.clone(),
6443 completion_index,
6444 )
6445 .await
6446 .context("resolving completion")?;
6447 let completion = completions.borrow()[completion_index].clone();
6448 let additional_text_edits = completion
6449 .source
6450 .lsp_completion(true)
6451 .as_ref()
6452 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6453 if let Some(edits) = additional_text_edits {
6454 let edits = this
6455 .update(cx, |this, cx| {
6456 this.as_local_mut().unwrap().edits_from_lsp(
6457 &buffer_handle,
6458 edits,
6459 server.server_id(),
6460 None,
6461 cx,
6462 )
6463 })?
6464 .await?;
6465
6466 buffer_handle.update(cx, |buffer, cx| {
6467 buffer.finalize_last_transaction();
6468 buffer.start_transaction();
6469
6470 for (range, text) in edits {
6471 let primary = &completion.replace_range;
6472
6473 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6474 // and the primary completion is just an insertion (empty range), then this is likely
6475 // an auto-import scenario and should not be considered overlapping
6476 // https://github.com/zed-industries/zed/issues/26136
6477 let is_file_start_auto_import = {
6478 let snapshot = buffer.snapshot();
6479 let primary_start_point = primary.start.to_point(&snapshot);
6480 let range_start_point = range.start.to_point(&snapshot);
6481
6482 let result = primary_start_point.row == 0
6483 && primary_start_point.column == 0
6484 && range_start_point.row == 0
6485 && range_start_point.column == 0;
6486
6487 result
6488 };
6489
6490 let has_overlap = if is_file_start_auto_import {
6491 false
6492 } else {
6493 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6494 && primary.end.cmp(&range.start, buffer).is_ge();
6495 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6496 && range.end.cmp(&primary.end, buffer).is_ge();
6497 let result = start_within || end_within;
6498 result
6499 };
6500
6501 //Skip additional edits which overlap with the primary completion edit
6502 //https://github.com/zed-industries/zed/pull/1871
6503 if !has_overlap {
6504 buffer.edit([(range, text)], None, cx);
6505 }
6506 }
6507
6508 let transaction = if buffer.end_transaction(cx).is_some() {
6509 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6510 if !push_to_history {
6511 buffer.forget_transaction(transaction.id);
6512 }
6513 Some(transaction)
6514 } else {
6515 None
6516 };
6517 Ok(transaction)
6518 })?
6519 } else {
6520 Ok(None)
6521 }
6522 })
6523 }
6524 }
6525
6526 pub fn pull_diagnostics(
6527 &mut self,
6528 buffer: Entity<Buffer>,
6529 cx: &mut Context<Self>,
6530 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6531 let buffer_id = buffer.read(cx).remote_id();
6532
6533 if let Some((client, upstream_project_id)) = self.upstream_client() {
6534 let mut suitable_capabilities = None;
6535 // Are we capable for proto request?
6536 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6537 &buffer,
6538 |capabilities| {
6539 if let Some(caps) = &capabilities.diagnostic_provider {
6540 suitable_capabilities = Some(caps.clone());
6541 true
6542 } else {
6543 false
6544 }
6545 },
6546 cx,
6547 );
6548 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6549 let Some(dynamic_caps) = suitable_capabilities else {
6550 return Task::ready(Ok(None));
6551 };
6552 assert!(any_server_has_diagnostics_provider);
6553
6554 let request = GetDocumentDiagnostics {
6555 previous_result_id: None,
6556 dynamic_caps,
6557 };
6558 let request_task = client.request_lsp(
6559 upstream_project_id,
6560 None,
6561 LSP_REQUEST_TIMEOUT,
6562 cx.background_executor().clone(),
6563 request.to_proto(upstream_project_id, buffer.read(cx)),
6564 );
6565 cx.background_spawn(async move {
6566 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6567 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6568 // Do not attempt to further process the dummy responses here.
6569 let _response = request_task.await?;
6570 Ok(None)
6571 })
6572 } else {
6573 let servers = buffer.update(cx, |buffer, cx| {
6574 self.language_servers_for_local_buffer(buffer, cx)
6575 .map(|(_, server)| server.clone())
6576 .collect::<Vec<_>>()
6577 });
6578
6579 let pull_diagnostics = servers
6580 .into_iter()
6581 .flat_map(|server| {
6582 let result = maybe!({
6583 let local = self.as_local()?;
6584 let server_id = server.server_id();
6585 let providers_with_identifiers = local
6586 .language_server_dynamic_registrations
6587 .get(&server_id)
6588 .into_iter()
6589 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6590 .collect::<Vec<_>>();
6591 Some(
6592 providers_with_identifiers
6593 .into_iter()
6594 .map(|dynamic_caps| {
6595 let result_id = self.result_id(server_id, buffer_id, cx);
6596 self.request_lsp(
6597 buffer.clone(),
6598 LanguageServerToQuery::Other(server_id),
6599 GetDocumentDiagnostics {
6600 previous_result_id: result_id,
6601 dynamic_caps,
6602 },
6603 cx,
6604 )
6605 })
6606 .collect::<Vec<_>>(),
6607 )
6608 });
6609
6610 result.unwrap_or_default()
6611 })
6612 .collect::<Vec<_>>();
6613
6614 cx.background_spawn(async move {
6615 let mut responses = Vec::new();
6616 for diagnostics in join_all(pull_diagnostics).await {
6617 responses.extend(diagnostics?);
6618 }
6619 Ok(Some(responses))
6620 })
6621 }
6622 }
6623
6624 pub fn applicable_inlay_chunks(
6625 &mut self,
6626 buffer: &Entity<Buffer>,
6627 ranges: &[Range<text::Anchor>],
6628 cx: &mut Context<Self>,
6629 ) -> Vec<Range<BufferRow>> {
6630 self.latest_lsp_data(buffer, cx)
6631 .inlay_hints
6632 .applicable_chunks(ranges)
6633 .map(|chunk| chunk.row_range())
6634 .collect()
6635 }
6636
6637 pub fn invalidate_inlay_hints<'a>(
6638 &'a mut self,
6639 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6640 ) {
6641 for buffer_id in for_buffers {
6642 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6643 lsp_data.inlay_hints.clear();
6644 }
6645 }
6646 }
6647
6648 pub fn inlay_hints(
6649 &mut self,
6650 invalidate: InvalidationStrategy,
6651 buffer: Entity<Buffer>,
6652 ranges: Vec<Range<text::Anchor>>,
6653 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6654 cx: &mut Context<Self>,
6655 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6656 let next_hint_id = self.next_hint_id.clone();
6657 let lsp_data = self.latest_lsp_data(&buffer, cx);
6658 let mut lsp_refresh_requested = false;
6659 let for_server = if let InvalidationStrategy::RefreshRequested {
6660 server_id,
6661 request_id,
6662 } = invalidate
6663 {
6664 let invalidated = lsp_data
6665 .inlay_hints
6666 .invalidate_for_server_refresh(server_id, request_id);
6667 lsp_refresh_requested = invalidated;
6668 Some(server_id)
6669 } else {
6670 None
6671 };
6672 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6673 let known_chunks = known_chunks
6674 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6675 .map(|(_, known_chunks)| known_chunks)
6676 .unwrap_or_default();
6677
6678 let mut hint_fetch_tasks = Vec::new();
6679 let mut cached_inlay_hints = None;
6680 let mut ranges_to_query = None;
6681 let applicable_chunks = existing_inlay_hints
6682 .applicable_chunks(ranges.as_slice())
6683 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6684 .collect::<Vec<_>>();
6685 if applicable_chunks.is_empty() {
6686 return HashMap::default();
6687 }
6688
6689 for row_chunk in applicable_chunks {
6690 match (
6691 existing_inlay_hints
6692 .cached_hints(&row_chunk)
6693 .filter(|_| !lsp_refresh_requested)
6694 .cloned(),
6695 existing_inlay_hints
6696 .fetched_hints(&row_chunk)
6697 .as_ref()
6698 .filter(|_| !lsp_refresh_requested)
6699 .cloned(),
6700 ) {
6701 (None, None) => {
6702 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6703 continue;
6704 };
6705 ranges_to_query
6706 .get_or_insert_with(Vec::new)
6707 .push((row_chunk, chunk_range));
6708 }
6709 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6710 (Some(cached_hints), None) => {
6711 for (server_id, cached_hints) in cached_hints {
6712 if for_server.is_none_or(|for_server| for_server == server_id) {
6713 cached_inlay_hints
6714 .get_or_insert_with(HashMap::default)
6715 .entry(row_chunk.row_range())
6716 .or_insert_with(HashMap::default)
6717 .entry(server_id)
6718 .or_insert_with(Vec::new)
6719 .extend(cached_hints);
6720 }
6721 }
6722 }
6723 (Some(cached_hints), Some(fetched_hints)) => {
6724 hint_fetch_tasks.push((row_chunk, fetched_hints));
6725 for (server_id, cached_hints) in cached_hints {
6726 if for_server.is_none_or(|for_server| for_server == server_id) {
6727 cached_inlay_hints
6728 .get_or_insert_with(HashMap::default)
6729 .entry(row_chunk.row_range())
6730 .or_insert_with(HashMap::default)
6731 .entry(server_id)
6732 .or_insert_with(Vec::new)
6733 .extend(cached_hints);
6734 }
6735 }
6736 }
6737 }
6738 }
6739
6740 if hint_fetch_tasks.is_empty()
6741 && ranges_to_query
6742 .as_ref()
6743 .is_none_or(|ranges| ranges.is_empty())
6744 && let Some(cached_inlay_hints) = cached_inlay_hints
6745 {
6746 cached_inlay_hints
6747 .into_iter()
6748 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6749 .collect()
6750 } else {
6751 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6752 let next_hint_id = next_hint_id.clone();
6753 let buffer = buffer.clone();
6754 let new_inlay_hints = cx
6755 .spawn(async move |lsp_store, cx| {
6756 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6757 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6758 })?;
6759 new_fetch_task
6760 .await
6761 .and_then(|new_hints_by_server| {
6762 lsp_store.update(cx, |lsp_store, cx| {
6763 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6764 let update_cache = !lsp_data
6765 .buffer_version
6766 .changed_since(&buffer.read(cx).version());
6767 if new_hints_by_server.is_empty() {
6768 if update_cache {
6769 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6770 }
6771 HashMap::default()
6772 } else {
6773 new_hints_by_server
6774 .into_iter()
6775 .map(|(server_id, new_hints)| {
6776 let new_hints = new_hints
6777 .into_iter()
6778 .map(|new_hint| {
6779 (
6780 InlayId::Hint(next_hint_id.fetch_add(
6781 1,
6782 atomic::Ordering::AcqRel,
6783 )),
6784 new_hint,
6785 )
6786 })
6787 .collect::<Vec<_>>();
6788 if update_cache {
6789 lsp_data.inlay_hints.insert_new_hints(
6790 chunk,
6791 server_id,
6792 new_hints.clone(),
6793 );
6794 }
6795 (server_id, new_hints)
6796 })
6797 .collect()
6798 }
6799 })
6800 })
6801 .map_err(Arc::new)
6802 })
6803 .shared();
6804
6805 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6806 *fetch_task = Some(new_inlay_hints.clone());
6807 hint_fetch_tasks.push((chunk, new_inlay_hints));
6808 }
6809
6810 cached_inlay_hints
6811 .unwrap_or_default()
6812 .into_iter()
6813 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6814 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6815 (
6816 chunk.row_range(),
6817 cx.spawn(async move |_, _| {
6818 hints_fetch.await.map_err(|e| {
6819 if e.error_code() != ErrorCode::Internal {
6820 anyhow!(e.error_code())
6821 } else {
6822 anyhow!("{e:#}")
6823 }
6824 })
6825 }),
6826 )
6827 }))
6828 .collect()
6829 }
6830 }
6831
6832 fn fetch_inlay_hints(
6833 &mut self,
6834 for_server: Option<LanguageServerId>,
6835 buffer: &Entity<Buffer>,
6836 range: Range<Anchor>,
6837 cx: &mut Context<Self>,
6838 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6839 let request = InlayHints {
6840 range: range.clone(),
6841 };
6842 if let Some((upstream_client, project_id)) = self.upstream_client() {
6843 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6844 return Task::ready(Ok(HashMap::default()));
6845 }
6846 let request_task = upstream_client.request_lsp(
6847 project_id,
6848 for_server.map(|id| id.to_proto()),
6849 LSP_REQUEST_TIMEOUT,
6850 cx.background_executor().clone(),
6851 request.to_proto(project_id, buffer.read(cx)),
6852 );
6853 let buffer = buffer.clone();
6854 cx.spawn(async move |weak_lsp_store, cx| {
6855 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6856 return Ok(HashMap::default());
6857 };
6858 let Some(responses) = request_task.await? else {
6859 return Ok(HashMap::default());
6860 };
6861
6862 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6863 let lsp_store = lsp_store.clone();
6864 let buffer = buffer.clone();
6865 let cx = cx.clone();
6866 let request = request.clone();
6867 async move {
6868 (
6869 LanguageServerId::from_proto(response.server_id),
6870 request
6871 .response_from_proto(response.response, lsp_store, buffer, cx)
6872 .await,
6873 )
6874 }
6875 }))
6876 .await;
6877
6878 let mut has_errors = false;
6879 let inlay_hints = inlay_hints
6880 .into_iter()
6881 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6882 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6883 Err(e) => {
6884 has_errors = true;
6885 log::error!("{e:#}");
6886 None
6887 }
6888 })
6889 .collect::<HashMap<_, _>>();
6890 anyhow::ensure!(
6891 !has_errors || !inlay_hints.is_empty(),
6892 "Failed to fetch inlay hints"
6893 );
6894 Ok(inlay_hints)
6895 })
6896 } else {
6897 let inlay_hints_task = match for_server {
6898 Some(server_id) => {
6899 let server_task = self.request_lsp(
6900 buffer.clone(),
6901 LanguageServerToQuery::Other(server_id),
6902 request,
6903 cx,
6904 );
6905 cx.background_spawn(async move {
6906 let mut responses = Vec::new();
6907 match server_task.await {
6908 Ok(response) => responses.push((server_id, response)),
6909 // rust-analyzer likes to error with this when its still loading up
6910 Err(e) if format!("{e:#}").ends_with("content modified") => (),
6911 Err(e) => log::error!(
6912 "Error handling response for inlay hints request: {e:#}"
6913 ),
6914 }
6915 responses
6916 })
6917 }
6918 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6919 };
6920 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6921 cx.background_spawn(async move {
6922 Ok(inlay_hints_task
6923 .await
6924 .into_iter()
6925 .map(|(server_id, mut new_hints)| {
6926 new_hints.retain(|hint| {
6927 hint.position.is_valid(&buffer_snapshot)
6928 && range.start.is_valid(&buffer_snapshot)
6929 && range.end.is_valid(&buffer_snapshot)
6930 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6931 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6932 });
6933 (server_id, new_hints)
6934 })
6935 .collect())
6936 })
6937 }
6938 }
6939
6940 pub fn pull_diagnostics_for_buffer(
6941 &mut self,
6942 buffer: Entity<Buffer>,
6943 cx: &mut Context<Self>,
6944 ) -> Task<anyhow::Result<()>> {
6945 let diagnostics = self.pull_diagnostics(buffer, cx);
6946 cx.spawn(async move |lsp_store, cx| {
6947 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6948 return Ok(());
6949 };
6950 lsp_store.update(cx, |lsp_store, cx| {
6951 if lsp_store.as_local().is_none() {
6952 return;
6953 }
6954
6955 let mut unchanged_buffers = HashSet::default();
6956 let mut changed_buffers = HashSet::default();
6957 let server_diagnostics_updates = diagnostics
6958 .into_iter()
6959 .filter_map(|diagnostics_set| match diagnostics_set {
6960 LspPullDiagnostics::Response {
6961 server_id,
6962 uri,
6963 diagnostics,
6964 } => Some((server_id, uri, diagnostics)),
6965 LspPullDiagnostics::Default => None,
6966 })
6967 .fold(
6968 HashMap::default(),
6969 |mut acc, (server_id, uri, diagnostics)| {
6970 let (result_id, diagnostics) = match diagnostics {
6971 PulledDiagnostics::Unchanged { result_id } => {
6972 unchanged_buffers.insert(uri.clone());
6973 (Some(result_id), Vec::new())
6974 }
6975 PulledDiagnostics::Changed {
6976 result_id,
6977 diagnostics,
6978 } => {
6979 changed_buffers.insert(uri.clone());
6980 (result_id, diagnostics)
6981 }
6982 };
6983 let disk_based_sources = Cow::Owned(
6984 lsp_store
6985 .language_server_adapter_for_id(server_id)
6986 .as_ref()
6987 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6988 .unwrap_or(&[])
6989 .to_vec(),
6990 );
6991 acc.entry(server_id).or_insert_with(Vec::new).push(
6992 DocumentDiagnosticsUpdate {
6993 server_id,
6994 diagnostics: lsp::PublishDiagnosticsParams {
6995 uri,
6996 diagnostics,
6997 version: None,
6998 },
6999 result_id,
7000 disk_based_sources,
7001 },
7002 );
7003 acc
7004 },
7005 );
7006
7007 for diagnostic_updates in server_diagnostics_updates.into_values() {
7008 lsp_store
7009 .merge_lsp_diagnostics(
7010 DiagnosticSourceKind::Pulled,
7011 diagnostic_updates,
7012 |buffer, old_diagnostic, cx| {
7013 File::from_dyn(buffer.file())
7014 .and_then(|file| {
7015 let abs_path = file.as_local()?.abs_path(cx);
7016 lsp::Uri::from_file_path(abs_path).ok()
7017 })
7018 .is_none_or(|buffer_uri| {
7019 unchanged_buffers.contains(&buffer_uri)
7020 || match old_diagnostic.source_kind {
7021 DiagnosticSourceKind::Pulled => {
7022 !changed_buffers.contains(&buffer_uri)
7023 }
7024 DiagnosticSourceKind::Other
7025 | DiagnosticSourceKind::Pushed => true,
7026 }
7027 })
7028 },
7029 cx,
7030 )
7031 .log_err();
7032 }
7033 })
7034 })
7035 }
7036
7037 pub fn document_colors(
7038 &mut self,
7039 known_cache_version: Option<usize>,
7040 buffer: Entity<Buffer>,
7041 cx: &mut Context<Self>,
7042 ) -> Option<DocumentColorTask> {
7043 let version_queried_for = buffer.read(cx).version();
7044 let buffer_id = buffer.read(cx).remote_id();
7045
7046 let current_language_servers = self.as_local().map(|local| {
7047 local
7048 .buffers_opened_in_servers
7049 .get(&buffer_id)
7050 .cloned()
7051 .unwrap_or_default()
7052 });
7053
7054 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7055 if let Some(cached_colors) = &lsp_data.document_colors {
7056 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7057 let has_different_servers =
7058 current_language_servers.is_some_and(|current_language_servers| {
7059 current_language_servers
7060 != cached_colors.colors.keys().copied().collect()
7061 });
7062 if !has_different_servers {
7063 let cache_version = cached_colors.cache_version;
7064 if Some(cache_version) == known_cache_version {
7065 return None;
7066 } else {
7067 return Some(
7068 Task::ready(Ok(DocumentColors {
7069 colors: cached_colors
7070 .colors
7071 .values()
7072 .flatten()
7073 .cloned()
7074 .collect(),
7075 cache_version: Some(cache_version),
7076 }))
7077 .shared(),
7078 );
7079 }
7080 }
7081 }
7082 }
7083 }
7084
7085 let color_lsp_data = self
7086 .latest_lsp_data(&buffer, cx)
7087 .document_colors
7088 .get_or_insert_default();
7089 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7090 && !version_queried_for.changed_since(updating_for)
7091 {
7092 return Some(running_update.clone());
7093 }
7094 let buffer_version_queried_for = version_queried_for.clone();
7095 let new_task = cx
7096 .spawn(async move |lsp_store, cx| {
7097 cx.background_executor()
7098 .timer(Duration::from_millis(30))
7099 .await;
7100 let fetched_colors = lsp_store
7101 .update(cx, |lsp_store, cx| {
7102 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7103 })?
7104 .await
7105 .context("fetching document colors")
7106 .map_err(Arc::new);
7107 let fetched_colors = match fetched_colors {
7108 Ok(fetched_colors) => {
7109 if Some(true)
7110 == buffer
7111 .update(cx, |buffer, _| {
7112 buffer.version() != buffer_version_queried_for
7113 })
7114 .ok()
7115 {
7116 return Ok(DocumentColors::default());
7117 }
7118 fetched_colors
7119 }
7120 Err(e) => {
7121 lsp_store
7122 .update(cx, |lsp_store, _| {
7123 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7124 if let Some(document_colors) = &mut lsp_data.document_colors {
7125 document_colors.colors_update = None;
7126 }
7127 }
7128 })
7129 .ok();
7130 return Err(e);
7131 }
7132 };
7133
7134 lsp_store
7135 .update(cx, |lsp_store, cx| {
7136 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7137 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7138
7139 if let Some(fetched_colors) = fetched_colors {
7140 if lsp_data.buffer_version == buffer_version_queried_for {
7141 lsp_colors.colors.extend(fetched_colors);
7142 lsp_colors.cache_version += 1;
7143 } else if !lsp_data
7144 .buffer_version
7145 .changed_since(&buffer_version_queried_for)
7146 {
7147 lsp_data.buffer_version = buffer_version_queried_for;
7148 lsp_colors.colors = fetched_colors;
7149 lsp_colors.cache_version += 1;
7150 }
7151 }
7152 lsp_colors.colors_update = None;
7153 let colors = lsp_colors
7154 .colors
7155 .values()
7156 .flatten()
7157 .cloned()
7158 .collect::<HashSet<_>>();
7159 DocumentColors {
7160 colors,
7161 cache_version: Some(lsp_colors.cache_version),
7162 }
7163 })
7164 .map_err(Arc::new)
7165 })
7166 .shared();
7167 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7168 Some(new_task)
7169 }
7170
7171 fn fetch_document_colors_for_buffer(
7172 &mut self,
7173 buffer: &Entity<Buffer>,
7174 cx: &mut Context<Self>,
7175 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7176 if let Some((client, project_id)) = self.upstream_client() {
7177 let request = GetDocumentColor {};
7178 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7179 return Task::ready(Ok(None));
7180 }
7181
7182 let request_task = client.request_lsp(
7183 project_id,
7184 None,
7185 LSP_REQUEST_TIMEOUT,
7186 cx.background_executor().clone(),
7187 request.to_proto(project_id, buffer.read(cx)),
7188 );
7189 let buffer = buffer.clone();
7190 cx.spawn(async move |lsp_store, cx| {
7191 let Some(lsp_store) = lsp_store.upgrade() else {
7192 return Ok(None);
7193 };
7194 let colors = join_all(
7195 request_task
7196 .await
7197 .log_err()
7198 .flatten()
7199 .map(|response| response.payload)
7200 .unwrap_or_default()
7201 .into_iter()
7202 .map(|color_response| {
7203 let response = request.response_from_proto(
7204 color_response.response,
7205 lsp_store.clone(),
7206 buffer.clone(),
7207 cx.clone(),
7208 );
7209 async move {
7210 (
7211 LanguageServerId::from_proto(color_response.server_id),
7212 response.await.log_err().unwrap_or_default(),
7213 )
7214 }
7215 }),
7216 )
7217 .await
7218 .into_iter()
7219 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7220 acc.entry(server_id)
7221 .or_insert_with(HashSet::default)
7222 .extend(colors);
7223 acc
7224 });
7225 Ok(Some(colors))
7226 })
7227 } else {
7228 let document_colors_task =
7229 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7230 cx.background_spawn(async move {
7231 Ok(Some(
7232 document_colors_task
7233 .await
7234 .into_iter()
7235 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7236 acc.entry(server_id)
7237 .or_insert_with(HashSet::default)
7238 .extend(colors);
7239 acc
7240 })
7241 .into_iter()
7242 .collect(),
7243 ))
7244 })
7245 }
7246 }
7247
7248 pub fn signature_help<T: ToPointUtf16>(
7249 &mut self,
7250 buffer: &Entity<Buffer>,
7251 position: T,
7252 cx: &mut Context<Self>,
7253 ) -> Task<Option<Vec<SignatureHelp>>> {
7254 let position = position.to_point_utf16(buffer.read(cx));
7255
7256 if let Some((client, upstream_project_id)) = self.upstream_client() {
7257 let request = GetSignatureHelp { position };
7258 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7259 return Task::ready(None);
7260 }
7261 let request_task = client.request_lsp(
7262 upstream_project_id,
7263 None,
7264 LSP_REQUEST_TIMEOUT,
7265 cx.background_executor().clone(),
7266 request.to_proto(upstream_project_id, buffer.read(cx)),
7267 );
7268 let buffer = buffer.clone();
7269 cx.spawn(async move |weak_lsp_store, cx| {
7270 let lsp_store = weak_lsp_store.upgrade()?;
7271 let signatures = join_all(
7272 request_task
7273 .await
7274 .log_err()
7275 .flatten()
7276 .map(|response| response.payload)
7277 .unwrap_or_default()
7278 .into_iter()
7279 .map(|response| {
7280 let response = GetSignatureHelp { position }.response_from_proto(
7281 response.response,
7282 lsp_store.clone(),
7283 buffer.clone(),
7284 cx.clone(),
7285 );
7286 async move { response.await.log_err().flatten() }
7287 }),
7288 )
7289 .await
7290 .into_iter()
7291 .flatten()
7292 .collect();
7293 Some(signatures)
7294 })
7295 } else {
7296 let all_actions_task = self.request_multiple_lsp_locally(
7297 buffer,
7298 Some(position),
7299 GetSignatureHelp { position },
7300 cx,
7301 );
7302 cx.background_spawn(async move {
7303 Some(
7304 all_actions_task
7305 .await
7306 .into_iter()
7307 .flat_map(|(_, actions)| actions)
7308 .collect::<Vec<_>>(),
7309 )
7310 })
7311 }
7312 }
7313
7314 pub fn hover(
7315 &mut self,
7316 buffer: &Entity<Buffer>,
7317 position: PointUtf16,
7318 cx: &mut Context<Self>,
7319 ) -> Task<Option<Vec<Hover>>> {
7320 if let Some((client, upstream_project_id)) = self.upstream_client() {
7321 let request = GetHover { position };
7322 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7323 return Task::ready(None);
7324 }
7325 let request_task = client.request_lsp(
7326 upstream_project_id,
7327 None,
7328 LSP_REQUEST_TIMEOUT,
7329 cx.background_executor().clone(),
7330 request.to_proto(upstream_project_id, buffer.read(cx)),
7331 );
7332 let buffer = buffer.clone();
7333 cx.spawn(async move |weak_lsp_store, cx| {
7334 let lsp_store = weak_lsp_store.upgrade()?;
7335 let hovers = join_all(
7336 request_task
7337 .await
7338 .log_err()
7339 .flatten()
7340 .map(|response| response.payload)
7341 .unwrap_or_default()
7342 .into_iter()
7343 .map(|response| {
7344 let response = GetHover { position }.response_from_proto(
7345 response.response,
7346 lsp_store.clone(),
7347 buffer.clone(),
7348 cx.clone(),
7349 );
7350 async move {
7351 response
7352 .await
7353 .log_err()
7354 .flatten()
7355 .and_then(remove_empty_hover_blocks)
7356 }
7357 }),
7358 )
7359 .await
7360 .into_iter()
7361 .flatten()
7362 .collect();
7363 Some(hovers)
7364 })
7365 } else {
7366 let all_actions_task = self.request_multiple_lsp_locally(
7367 buffer,
7368 Some(position),
7369 GetHover { position },
7370 cx,
7371 );
7372 cx.background_spawn(async move {
7373 Some(
7374 all_actions_task
7375 .await
7376 .into_iter()
7377 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7378 .collect::<Vec<Hover>>(),
7379 )
7380 })
7381 }
7382 }
7383
7384 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7385 let language_registry = self.languages.clone();
7386
7387 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7388 let request = upstream_client.request(proto::GetProjectSymbols {
7389 project_id: *project_id,
7390 query: query.to_string(),
7391 });
7392 cx.foreground_executor().spawn(async move {
7393 let response = request.await?;
7394 let mut symbols = Vec::new();
7395 let core_symbols = response
7396 .symbols
7397 .into_iter()
7398 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7399 .collect::<Vec<_>>();
7400 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7401 .await;
7402 Ok(symbols)
7403 })
7404 } else if let Some(local) = self.as_local() {
7405 struct WorkspaceSymbolsResult {
7406 server_id: LanguageServerId,
7407 lsp_adapter: Arc<CachedLspAdapter>,
7408 worktree: WeakEntity<Worktree>,
7409 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7410 }
7411
7412 let mut requests = Vec::new();
7413 let mut requested_servers = BTreeSet::new();
7414 for (seed, state) in local.language_server_ids.iter() {
7415 let Some(worktree_handle) = self
7416 .worktree_store
7417 .read(cx)
7418 .worktree_for_id(seed.worktree_id, cx)
7419 else {
7420 continue;
7421 };
7422 let worktree = worktree_handle.read(cx);
7423 if !worktree.is_visible() {
7424 continue;
7425 }
7426
7427 if !requested_servers.insert(state.id) {
7428 continue;
7429 }
7430
7431 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7432 Some(LanguageServerState::Running {
7433 adapter, server, ..
7434 }) => (adapter.clone(), server),
7435
7436 _ => continue,
7437 };
7438 let supports_workspace_symbol_request =
7439 match server.capabilities().workspace_symbol_provider {
7440 Some(OneOf::Left(supported)) => supported,
7441 Some(OneOf::Right(_)) => true,
7442 None => false,
7443 };
7444 if !supports_workspace_symbol_request {
7445 continue;
7446 }
7447 let worktree_handle = worktree_handle.clone();
7448 let server_id = server.server_id();
7449 requests.push(
7450 server
7451 .request::<lsp::request::WorkspaceSymbolRequest>(
7452 lsp::WorkspaceSymbolParams {
7453 query: query.to_string(),
7454 ..Default::default()
7455 },
7456 )
7457 .map(move |response| {
7458 let lsp_symbols = response.into_response()
7459 .context("workspace symbols request")
7460 .log_err()
7461 .flatten()
7462 .map(|symbol_response| match symbol_response {
7463 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7464 flat_responses.into_iter().map(|lsp_symbol| {
7465 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7466 }).collect::<Vec<_>>()
7467 }
7468 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7469 nested_responses.into_iter().filter_map(|lsp_symbol| {
7470 let location = match lsp_symbol.location {
7471 OneOf::Left(location) => location,
7472 OneOf::Right(_) => {
7473 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7474 return None
7475 }
7476 };
7477 Some((lsp_symbol.name, lsp_symbol.kind, location))
7478 }).collect::<Vec<_>>()
7479 }
7480 }).unwrap_or_default();
7481
7482 WorkspaceSymbolsResult {
7483 server_id,
7484 lsp_adapter,
7485 worktree: worktree_handle.downgrade(),
7486 lsp_symbols,
7487 }
7488 }),
7489 );
7490 }
7491
7492 cx.spawn(async move |this, cx| {
7493 let responses = futures::future::join_all(requests).await;
7494 let this = match this.upgrade() {
7495 Some(this) => this,
7496 None => return Ok(Vec::new()),
7497 };
7498
7499 let mut symbols = Vec::new();
7500 for result in responses {
7501 let core_symbols = this.update(cx, |this, cx| {
7502 result
7503 .lsp_symbols
7504 .into_iter()
7505 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7506 let abs_path = symbol_location.uri.to_file_path().ok()?;
7507 let source_worktree = result.worktree.upgrade()?;
7508 let source_worktree_id = source_worktree.read(cx).id();
7509
7510 let path = if let Some((tree, rel_path)) =
7511 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7512 {
7513 let worktree_id = tree.read(cx).id();
7514 SymbolLocation::InProject(ProjectPath {
7515 worktree_id,
7516 path: rel_path,
7517 })
7518 } else {
7519 SymbolLocation::OutsideProject {
7520 signature: this.symbol_signature(&abs_path),
7521 abs_path: abs_path.into(),
7522 }
7523 };
7524
7525 Some(CoreSymbol {
7526 source_language_server_id: result.server_id,
7527 language_server_name: result.lsp_adapter.name.clone(),
7528 source_worktree_id,
7529 path,
7530 kind: symbol_kind,
7531 name: symbol_name,
7532 range: range_from_lsp(symbol_location.range),
7533 })
7534 })
7535 .collect()
7536 })?;
7537
7538 populate_labels_for_symbols(
7539 core_symbols,
7540 &language_registry,
7541 Some(result.lsp_adapter),
7542 &mut symbols,
7543 )
7544 .await;
7545 }
7546
7547 Ok(symbols)
7548 })
7549 } else {
7550 Task::ready(Err(anyhow!("No upstream client or local language server")))
7551 }
7552 }
7553
7554 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7555 let mut summary = DiagnosticSummary::default();
7556 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7557 summary.error_count += path_summary.error_count;
7558 summary.warning_count += path_summary.warning_count;
7559 }
7560 summary
7561 }
7562
7563 /// Returns the diagnostic summary for a specific project path.
7564 pub fn diagnostic_summary_for_path(
7565 &self,
7566 project_path: &ProjectPath,
7567 _: &App,
7568 ) -> DiagnosticSummary {
7569 if let Some(summaries) = self
7570 .diagnostic_summaries
7571 .get(&project_path.worktree_id)
7572 .and_then(|map| map.get(&project_path.path))
7573 {
7574 let (error_count, warning_count) = summaries.iter().fold(
7575 (0, 0),
7576 |(error_count, warning_count), (_language_server_id, summary)| {
7577 (
7578 error_count + summary.error_count,
7579 warning_count + summary.warning_count,
7580 )
7581 },
7582 );
7583
7584 DiagnosticSummary {
7585 error_count,
7586 warning_count,
7587 }
7588 } else {
7589 DiagnosticSummary::default()
7590 }
7591 }
7592
7593 pub fn diagnostic_summaries<'a>(
7594 &'a self,
7595 include_ignored: bool,
7596 cx: &'a App,
7597 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7598 self.worktree_store
7599 .read(cx)
7600 .visible_worktrees(cx)
7601 .filter_map(|worktree| {
7602 let worktree = worktree.read(cx);
7603 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7604 })
7605 .flat_map(move |(worktree, summaries)| {
7606 let worktree_id = worktree.id();
7607 summaries
7608 .iter()
7609 .filter(move |(path, _)| {
7610 include_ignored
7611 || worktree
7612 .entry_for_path(path.as_ref())
7613 .is_some_and(|entry| !entry.is_ignored)
7614 })
7615 .flat_map(move |(path, summaries)| {
7616 summaries.iter().map(move |(server_id, summary)| {
7617 (
7618 ProjectPath {
7619 worktree_id,
7620 path: path.clone(),
7621 },
7622 *server_id,
7623 *summary,
7624 )
7625 })
7626 })
7627 })
7628 }
7629
7630 pub fn on_buffer_edited(
7631 &mut self,
7632 buffer: Entity<Buffer>,
7633 cx: &mut Context<Self>,
7634 ) -> Option<()> {
7635 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7636 Some(
7637 self.as_local()?
7638 .language_servers_for_buffer(buffer, cx)
7639 .map(|i| i.1.clone())
7640 .collect(),
7641 )
7642 })?;
7643
7644 let buffer = buffer.read(cx);
7645 let file = File::from_dyn(buffer.file())?;
7646 let abs_path = file.as_local()?.abs_path(cx);
7647 let uri = lsp::Uri::from_file_path(&abs_path)
7648 .ok()
7649 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7650 .log_err()?;
7651 let next_snapshot = buffer.text_snapshot();
7652 for language_server in language_servers {
7653 let language_server = language_server.clone();
7654
7655 let buffer_snapshots = self
7656 .as_local_mut()?
7657 .buffer_snapshots
7658 .get_mut(&buffer.remote_id())
7659 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7660 let previous_snapshot = buffer_snapshots.last()?;
7661
7662 let build_incremental_change = || {
7663 buffer
7664 .edits_since::<Dimensions<PointUtf16, usize>>(
7665 previous_snapshot.snapshot.version(),
7666 )
7667 .map(|edit| {
7668 let edit_start = edit.new.start.0;
7669 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7670 let new_text = next_snapshot
7671 .text_for_range(edit.new.start.1..edit.new.end.1)
7672 .collect();
7673 lsp::TextDocumentContentChangeEvent {
7674 range: Some(lsp::Range::new(
7675 point_to_lsp(edit_start),
7676 point_to_lsp(edit_end),
7677 )),
7678 range_length: None,
7679 text: new_text,
7680 }
7681 })
7682 .collect()
7683 };
7684
7685 let document_sync_kind = language_server
7686 .capabilities()
7687 .text_document_sync
7688 .as_ref()
7689 .and_then(|sync| match sync {
7690 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7691 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7692 });
7693
7694 let content_changes: Vec<_> = match document_sync_kind {
7695 Some(lsp::TextDocumentSyncKind::FULL) => {
7696 vec![lsp::TextDocumentContentChangeEvent {
7697 range: None,
7698 range_length: None,
7699 text: next_snapshot.text(),
7700 }]
7701 }
7702 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7703 _ => {
7704 #[cfg(any(test, feature = "test-support"))]
7705 {
7706 build_incremental_change()
7707 }
7708
7709 #[cfg(not(any(test, feature = "test-support")))]
7710 {
7711 continue;
7712 }
7713 }
7714 };
7715
7716 let next_version = previous_snapshot.version + 1;
7717 buffer_snapshots.push(LspBufferSnapshot {
7718 version: next_version,
7719 snapshot: next_snapshot.clone(),
7720 });
7721
7722 language_server
7723 .notify::<lsp::notification::DidChangeTextDocument>(
7724 lsp::DidChangeTextDocumentParams {
7725 text_document: lsp::VersionedTextDocumentIdentifier::new(
7726 uri.clone(),
7727 next_version,
7728 ),
7729 content_changes,
7730 },
7731 )
7732 .ok();
7733 self.pull_workspace_diagnostics(language_server.server_id());
7734 }
7735
7736 None
7737 }
7738
7739 pub fn on_buffer_saved(
7740 &mut self,
7741 buffer: Entity<Buffer>,
7742 cx: &mut Context<Self>,
7743 ) -> Option<()> {
7744 let file = File::from_dyn(buffer.read(cx).file())?;
7745 let worktree_id = file.worktree_id(cx);
7746 let abs_path = file.as_local()?.abs_path(cx);
7747 let text_document = lsp::TextDocumentIdentifier {
7748 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7749 };
7750 let local = self.as_local()?;
7751
7752 for server in local.language_servers_for_worktree(worktree_id) {
7753 if let Some(include_text) = include_text(server.as_ref()) {
7754 let text = if include_text {
7755 Some(buffer.read(cx).text())
7756 } else {
7757 None
7758 };
7759 server
7760 .notify::<lsp::notification::DidSaveTextDocument>(
7761 lsp::DidSaveTextDocumentParams {
7762 text_document: text_document.clone(),
7763 text,
7764 },
7765 )
7766 .ok();
7767 }
7768 }
7769
7770 let language_servers = buffer.update(cx, |buffer, cx| {
7771 local.language_server_ids_for_buffer(buffer, cx)
7772 });
7773 for language_server_id in language_servers {
7774 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7775 }
7776
7777 None
7778 }
7779
7780 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7781 maybe!(async move {
7782 let mut refreshed_servers = HashSet::default();
7783 let servers = lsp_store
7784 .update(cx, |lsp_store, cx| {
7785 let local = lsp_store.as_local()?;
7786
7787 let servers = local
7788 .language_server_ids
7789 .iter()
7790 .filter_map(|(seed, state)| {
7791 let worktree = lsp_store
7792 .worktree_store
7793 .read(cx)
7794 .worktree_for_id(seed.worktree_id, cx);
7795 let delegate: Arc<dyn LspAdapterDelegate> =
7796 worktree.map(|worktree| {
7797 LocalLspAdapterDelegate::new(
7798 local.languages.clone(),
7799 &local.environment,
7800 cx.weak_entity(),
7801 &worktree,
7802 local.http_client.clone(),
7803 local.fs.clone(),
7804 cx,
7805 )
7806 })?;
7807 let server_id = state.id;
7808
7809 let states = local.language_servers.get(&server_id)?;
7810
7811 match states {
7812 LanguageServerState::Starting { .. } => None,
7813 LanguageServerState::Running {
7814 adapter, server, ..
7815 } => {
7816 let adapter = adapter.clone();
7817 let server = server.clone();
7818 refreshed_servers.insert(server.name());
7819 let toolchain = seed.toolchain.clone();
7820 Some(cx.spawn(async move |_, cx| {
7821 let settings =
7822 LocalLspStore::workspace_configuration_for_adapter(
7823 adapter.adapter.clone(),
7824 &delegate,
7825 toolchain,
7826 cx,
7827 )
7828 .await
7829 .ok()?;
7830 server
7831 .notify::<lsp::notification::DidChangeConfiguration>(
7832 lsp::DidChangeConfigurationParams { settings },
7833 )
7834 .ok()?;
7835 Some(())
7836 }))
7837 }
7838 }
7839 })
7840 .collect::<Vec<_>>();
7841
7842 Some(servers)
7843 })
7844 .ok()
7845 .flatten()?;
7846
7847 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7848 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7849 // to stop and unregister its language server wrapper.
7850 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7851 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7852 let _: Vec<Option<()>> = join_all(servers).await;
7853
7854 Some(())
7855 })
7856 .await;
7857 }
7858
7859 fn maintain_workspace_config(
7860 external_refresh_requests: watch::Receiver<()>,
7861 cx: &mut Context<Self>,
7862 ) -> Task<Result<()>> {
7863 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7864 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7865
7866 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7867 *settings_changed_tx.borrow_mut() = ();
7868 });
7869
7870 let mut joint_future =
7871 futures::stream::select(settings_changed_rx, external_refresh_requests);
7872 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7873 // - 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).
7874 // - 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.
7875 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7876 // - 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,
7877 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7878 cx.spawn(async move |this, cx| {
7879 while let Some(()) = joint_future.next().await {
7880 this.update(cx, |this, cx| {
7881 this.refresh_server_tree(cx);
7882 })
7883 .ok();
7884
7885 Self::refresh_workspace_configurations(&this, cx).await;
7886 }
7887
7888 drop(settings_observation);
7889 anyhow::Ok(())
7890 })
7891 }
7892
7893 pub fn language_servers_for_local_buffer<'a>(
7894 &'a self,
7895 buffer: &Buffer,
7896 cx: &mut App,
7897 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7898 let local = self.as_local();
7899 let language_server_ids = local
7900 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7901 .unwrap_or_default();
7902
7903 language_server_ids
7904 .into_iter()
7905 .filter_map(
7906 move |server_id| match local?.language_servers.get(&server_id)? {
7907 LanguageServerState::Running {
7908 adapter, server, ..
7909 } => Some((adapter, server)),
7910 _ => None,
7911 },
7912 )
7913 }
7914
7915 pub fn language_server_for_local_buffer<'a>(
7916 &'a self,
7917 buffer: &'a Buffer,
7918 server_id: LanguageServerId,
7919 cx: &'a mut App,
7920 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7921 self.as_local()?
7922 .language_servers_for_buffer(buffer, cx)
7923 .find(|(_, s)| s.server_id() == server_id)
7924 }
7925
7926 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7927 self.diagnostic_summaries.remove(&id_to_remove);
7928 if let Some(local) = self.as_local_mut() {
7929 let to_remove = local.remove_worktree(id_to_remove, cx);
7930 for server in to_remove {
7931 self.language_server_statuses.remove(&server);
7932 }
7933 }
7934 }
7935
7936 pub fn shared(
7937 &mut self,
7938 project_id: u64,
7939 downstream_client: AnyProtoClient,
7940 _: &mut Context<Self>,
7941 ) {
7942 self.downstream_client = Some((downstream_client.clone(), project_id));
7943
7944 for (server_id, status) in &self.language_server_statuses {
7945 if let Some(server) = self.language_server_for_id(*server_id) {
7946 downstream_client
7947 .send(proto::StartLanguageServer {
7948 project_id,
7949 server: Some(proto::LanguageServer {
7950 id: server_id.to_proto(),
7951 name: status.name.to_string(),
7952 worktree_id: status.worktree.map(|id| id.to_proto()),
7953 }),
7954 capabilities: serde_json::to_string(&server.capabilities())
7955 .expect("serializing server LSP capabilities"),
7956 })
7957 .log_err();
7958 }
7959 }
7960 }
7961
7962 pub fn disconnected_from_host(&mut self) {
7963 self.downstream_client.take();
7964 }
7965
7966 pub fn disconnected_from_ssh_remote(&mut self) {
7967 if let LspStoreMode::Remote(RemoteLspStore {
7968 upstream_client, ..
7969 }) = &mut self.mode
7970 {
7971 upstream_client.take();
7972 }
7973 }
7974
7975 pub(crate) fn set_language_server_statuses_from_proto(
7976 &mut self,
7977 project: WeakEntity<Project>,
7978 language_servers: Vec<proto::LanguageServer>,
7979 server_capabilities: Vec<String>,
7980 cx: &mut Context<Self>,
7981 ) {
7982 let lsp_logs = cx
7983 .try_global::<GlobalLogStore>()
7984 .map(|lsp_store| lsp_store.0.clone());
7985
7986 self.language_server_statuses = language_servers
7987 .into_iter()
7988 .zip(server_capabilities)
7989 .map(|(server, server_capabilities)| {
7990 let server_id = LanguageServerId(server.id as usize);
7991 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7992 self.lsp_server_capabilities
7993 .insert(server_id, server_capabilities);
7994 }
7995
7996 let name = LanguageServerName::from_proto(server.name);
7997 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7998
7999 if let Some(lsp_logs) = &lsp_logs {
8000 lsp_logs.update(cx, |lsp_logs, cx| {
8001 lsp_logs.add_language_server(
8002 // Only remote clients get their language servers set from proto
8003 LanguageServerKind::Remote {
8004 project: project.clone(),
8005 },
8006 server_id,
8007 Some(name.clone()),
8008 worktree,
8009 None,
8010 cx,
8011 );
8012 });
8013 }
8014
8015 (
8016 server_id,
8017 LanguageServerStatus {
8018 name,
8019 pending_work: Default::default(),
8020 has_pending_diagnostic_updates: false,
8021 progress_tokens: Default::default(),
8022 worktree,
8023 },
8024 )
8025 })
8026 .collect();
8027 }
8028
8029 #[cfg(test)]
8030 pub fn update_diagnostic_entries(
8031 &mut self,
8032 server_id: LanguageServerId,
8033 abs_path: PathBuf,
8034 result_id: Option<String>,
8035 version: Option<i32>,
8036 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8037 cx: &mut Context<Self>,
8038 ) -> anyhow::Result<()> {
8039 self.merge_diagnostic_entries(
8040 vec![DocumentDiagnosticsUpdate {
8041 diagnostics: DocumentDiagnostics {
8042 diagnostics,
8043 document_abs_path: abs_path,
8044 version,
8045 },
8046 result_id,
8047 server_id,
8048 disk_based_sources: Cow::Borrowed(&[]),
8049 }],
8050 |_, _, _| false,
8051 cx,
8052 )?;
8053 Ok(())
8054 }
8055
8056 pub fn merge_diagnostic_entries<'a>(
8057 &mut self,
8058 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8059 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8060 cx: &mut Context<Self>,
8061 ) -> anyhow::Result<()> {
8062 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8063 let mut updated_diagnostics_paths = HashMap::default();
8064 for mut update in diagnostic_updates {
8065 let abs_path = &update.diagnostics.document_abs_path;
8066 let server_id = update.server_id;
8067 let Some((worktree, relative_path)) =
8068 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8069 else {
8070 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8071 return Ok(());
8072 };
8073
8074 let worktree_id = worktree.read(cx).id();
8075 let project_path = ProjectPath {
8076 worktree_id,
8077 path: relative_path,
8078 };
8079
8080 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8081 let snapshot = buffer_handle.read(cx).snapshot();
8082 let buffer = buffer_handle.read(cx);
8083 let reused_diagnostics = buffer
8084 .buffer_diagnostics(Some(server_id))
8085 .iter()
8086 .filter(|v| merge(buffer, &v.diagnostic, cx))
8087 .map(|v| {
8088 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8089 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8090 DiagnosticEntry {
8091 range: start..end,
8092 diagnostic: v.diagnostic.clone(),
8093 }
8094 })
8095 .collect::<Vec<_>>();
8096
8097 self.as_local_mut()
8098 .context("cannot merge diagnostics on a remote LspStore")?
8099 .update_buffer_diagnostics(
8100 &buffer_handle,
8101 server_id,
8102 update.result_id,
8103 update.diagnostics.version,
8104 update.diagnostics.diagnostics.clone(),
8105 reused_diagnostics.clone(),
8106 cx,
8107 )?;
8108
8109 update.diagnostics.diagnostics.extend(reused_diagnostics);
8110 }
8111
8112 let updated = worktree.update(cx, |worktree, cx| {
8113 self.update_worktree_diagnostics(
8114 worktree.id(),
8115 server_id,
8116 project_path.path.clone(),
8117 update.diagnostics.diagnostics,
8118 cx,
8119 )
8120 })?;
8121 match updated {
8122 ControlFlow::Continue(new_summary) => {
8123 if let Some((project_id, new_summary)) = new_summary {
8124 match &mut diagnostics_summary {
8125 Some(diagnostics_summary) => {
8126 diagnostics_summary
8127 .more_summaries
8128 .push(proto::DiagnosticSummary {
8129 path: project_path.path.as_ref().to_proto(),
8130 language_server_id: server_id.0 as u64,
8131 error_count: new_summary.error_count,
8132 warning_count: new_summary.warning_count,
8133 })
8134 }
8135 None => {
8136 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8137 project_id,
8138 worktree_id: worktree_id.to_proto(),
8139 summary: Some(proto::DiagnosticSummary {
8140 path: project_path.path.as_ref().to_proto(),
8141 language_server_id: server_id.0 as u64,
8142 error_count: new_summary.error_count,
8143 warning_count: new_summary.warning_count,
8144 }),
8145 more_summaries: Vec::new(),
8146 })
8147 }
8148 }
8149 }
8150 updated_diagnostics_paths
8151 .entry(server_id)
8152 .or_insert_with(Vec::new)
8153 .push(project_path);
8154 }
8155 ControlFlow::Break(()) => {}
8156 }
8157 }
8158
8159 if let Some((diagnostics_summary, (downstream_client, _))) =
8160 diagnostics_summary.zip(self.downstream_client.as_ref())
8161 {
8162 downstream_client.send(diagnostics_summary).log_err();
8163 }
8164 for (server_id, paths) in updated_diagnostics_paths {
8165 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8166 }
8167 Ok(())
8168 }
8169
8170 fn update_worktree_diagnostics(
8171 &mut self,
8172 worktree_id: WorktreeId,
8173 server_id: LanguageServerId,
8174 path_in_worktree: Arc<RelPath>,
8175 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8176 _: &mut Context<Worktree>,
8177 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8178 let local = match &mut self.mode {
8179 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8180 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8181 };
8182
8183 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8184 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8185 let summaries_by_server_id = summaries_for_tree
8186 .entry(path_in_worktree.clone())
8187 .or_default();
8188
8189 let old_summary = summaries_by_server_id
8190 .remove(&server_id)
8191 .unwrap_or_default();
8192
8193 let new_summary = DiagnosticSummary::new(&diagnostics);
8194 if new_summary.is_empty() {
8195 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8196 {
8197 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8198 diagnostics_by_server_id.remove(ix);
8199 }
8200 if diagnostics_by_server_id.is_empty() {
8201 diagnostics_for_tree.remove(&path_in_worktree);
8202 }
8203 }
8204 } else {
8205 summaries_by_server_id.insert(server_id, new_summary);
8206 let diagnostics_by_server_id = diagnostics_for_tree
8207 .entry(path_in_worktree.clone())
8208 .or_default();
8209 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8210 Ok(ix) => {
8211 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8212 }
8213 Err(ix) => {
8214 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8215 }
8216 }
8217 }
8218
8219 if !old_summary.is_empty() || !new_summary.is_empty() {
8220 if let Some((_, project_id)) = &self.downstream_client {
8221 Ok(ControlFlow::Continue(Some((
8222 *project_id,
8223 proto::DiagnosticSummary {
8224 path: path_in_worktree.to_proto(),
8225 language_server_id: server_id.0 as u64,
8226 error_count: new_summary.error_count as u32,
8227 warning_count: new_summary.warning_count as u32,
8228 },
8229 ))))
8230 } else {
8231 Ok(ControlFlow::Continue(None))
8232 }
8233 } else {
8234 Ok(ControlFlow::Break(()))
8235 }
8236 }
8237
8238 pub fn open_buffer_for_symbol(
8239 &mut self,
8240 symbol: &Symbol,
8241 cx: &mut Context<Self>,
8242 ) -> Task<Result<Entity<Buffer>>> {
8243 if let Some((client, project_id)) = self.upstream_client() {
8244 let request = client.request(proto::OpenBufferForSymbol {
8245 project_id,
8246 symbol: Some(Self::serialize_symbol(symbol)),
8247 });
8248 cx.spawn(async move |this, cx| {
8249 let response = request.await?;
8250 let buffer_id = BufferId::new(response.buffer_id)?;
8251 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8252 .await
8253 })
8254 } else if let Some(local) = self.as_local() {
8255 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8256 seed.worktree_id == symbol.source_worktree_id
8257 && state.id == symbol.source_language_server_id
8258 && symbol.language_server_name == seed.name
8259 });
8260 if !is_valid {
8261 return Task::ready(Err(anyhow!(
8262 "language server for worktree and language not found"
8263 )));
8264 };
8265
8266 let symbol_abs_path = match &symbol.path {
8267 SymbolLocation::InProject(project_path) => self
8268 .worktree_store
8269 .read(cx)
8270 .absolutize(&project_path, cx)
8271 .context("no such worktree"),
8272 SymbolLocation::OutsideProject {
8273 abs_path,
8274 signature: _,
8275 } => Ok(abs_path.to_path_buf()),
8276 };
8277 let symbol_abs_path = match symbol_abs_path {
8278 Ok(abs_path) => abs_path,
8279 Err(err) => return Task::ready(Err(err)),
8280 };
8281 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8282 uri
8283 } else {
8284 return Task::ready(Err(anyhow!("invalid symbol path")));
8285 };
8286
8287 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8288 } else {
8289 Task::ready(Err(anyhow!("no upstream client or local store")))
8290 }
8291 }
8292
8293 pub(crate) fn open_local_buffer_via_lsp(
8294 &mut self,
8295 abs_path: lsp::Uri,
8296 language_server_id: LanguageServerId,
8297 cx: &mut Context<Self>,
8298 ) -> Task<Result<Entity<Buffer>>> {
8299 cx.spawn(async move |lsp_store, cx| {
8300 // Escape percent-encoded string.
8301 let current_scheme = abs_path.scheme().to_owned();
8302 // Uri is immutable, so we can't modify the scheme
8303
8304 let abs_path = abs_path
8305 .to_file_path()
8306 .map_err(|()| anyhow!("can't convert URI to path"))?;
8307 let p = abs_path.clone();
8308 let yarn_worktree = lsp_store
8309 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8310 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8311 cx.spawn(async move |this, cx| {
8312 let t = this
8313 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8314 .ok()?;
8315 t.await
8316 })
8317 }),
8318 None => Task::ready(None),
8319 })?
8320 .await;
8321 let (worktree_root_target, known_relative_path) =
8322 if let Some((zip_root, relative_path)) = yarn_worktree {
8323 (zip_root, Some(relative_path))
8324 } else {
8325 (Arc::<Path>::from(abs_path.as_path()), None)
8326 };
8327 let (worktree, relative_path) = if let Some(result) =
8328 lsp_store.update(cx, |lsp_store, cx| {
8329 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8330 worktree_store.find_worktree(&worktree_root_target, cx)
8331 })
8332 })? {
8333 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8334 (result.0, relative_path)
8335 } else {
8336 let worktree = lsp_store
8337 .update(cx, |lsp_store, cx| {
8338 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8339 worktree_store.create_worktree(&worktree_root_target, false, cx)
8340 })
8341 })?
8342 .await?;
8343 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8344 lsp_store
8345 .update(cx, |lsp_store, cx| {
8346 if let Some(local) = lsp_store.as_local_mut() {
8347 local.register_language_server_for_invisible_worktree(
8348 &worktree,
8349 language_server_id,
8350 cx,
8351 )
8352 }
8353 })
8354 .ok();
8355 }
8356 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8357 let relative_path = if let Some(known_path) = known_relative_path {
8358 known_path
8359 } else {
8360 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8361 .into_arc()
8362 };
8363 (worktree, relative_path)
8364 };
8365 let project_path = ProjectPath {
8366 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8367 path: relative_path,
8368 };
8369 lsp_store
8370 .update(cx, |lsp_store, cx| {
8371 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8372 buffer_store.open_buffer(project_path, cx)
8373 })
8374 })?
8375 .await
8376 })
8377 }
8378
8379 fn request_multiple_lsp_locally<P, R>(
8380 &mut self,
8381 buffer: &Entity<Buffer>,
8382 position: Option<P>,
8383 request: R,
8384 cx: &mut Context<Self>,
8385 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8386 where
8387 P: ToOffset,
8388 R: LspCommand + Clone,
8389 <R::LspRequest as lsp::request::Request>::Result: Send,
8390 <R::LspRequest as lsp::request::Request>::Params: Send,
8391 {
8392 let Some(local) = self.as_local() else {
8393 return Task::ready(Vec::new());
8394 };
8395
8396 let snapshot = buffer.read(cx).snapshot();
8397 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8398
8399 let server_ids = buffer.update(cx, |buffer, cx| {
8400 local
8401 .language_servers_for_buffer(buffer, cx)
8402 .filter(|(adapter, _)| {
8403 scope
8404 .as_ref()
8405 .map(|scope| scope.language_allowed(&adapter.name))
8406 .unwrap_or(true)
8407 })
8408 .map(|(_, server)| server.server_id())
8409 .filter(|server_id| {
8410 self.as_local().is_none_or(|local| {
8411 local
8412 .buffers_opened_in_servers
8413 .get(&snapshot.remote_id())
8414 .is_some_and(|servers| servers.contains(server_id))
8415 })
8416 })
8417 .collect::<Vec<_>>()
8418 });
8419
8420 let mut response_results = server_ids
8421 .into_iter()
8422 .map(|server_id| {
8423 let task = self.request_lsp(
8424 buffer.clone(),
8425 LanguageServerToQuery::Other(server_id),
8426 request.clone(),
8427 cx,
8428 );
8429 async move { (server_id, task.await) }
8430 })
8431 .collect::<FuturesUnordered<_>>();
8432
8433 cx.background_spawn(async move {
8434 let mut responses = Vec::with_capacity(response_results.len());
8435 while let Some((server_id, response_result)) = response_results.next().await {
8436 match response_result {
8437 Ok(response) => responses.push((server_id, response)),
8438 // rust-analyzer likes to error with this when its still loading up
8439 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8440 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8441 }
8442 }
8443 responses
8444 })
8445 }
8446
8447 async fn handle_lsp_command<T: LspCommand>(
8448 this: Entity<Self>,
8449 envelope: TypedEnvelope<T::ProtoRequest>,
8450 mut cx: AsyncApp,
8451 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8452 where
8453 <T::LspRequest as lsp::request::Request>::Params: Send,
8454 <T::LspRequest as lsp::request::Request>::Result: Send,
8455 {
8456 let sender_id = envelope.original_sender_id().unwrap_or_default();
8457 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8458 let buffer_handle = this.update(&mut cx, |this, cx| {
8459 this.buffer_store.read(cx).get_existing(buffer_id)
8460 })??;
8461 let request = T::from_proto(
8462 envelope.payload,
8463 this.clone(),
8464 buffer_handle.clone(),
8465 cx.clone(),
8466 )
8467 .await?;
8468 let response = this
8469 .update(&mut cx, |this, cx| {
8470 this.request_lsp(
8471 buffer_handle.clone(),
8472 LanguageServerToQuery::FirstCapable,
8473 request,
8474 cx,
8475 )
8476 })?
8477 .await?;
8478 this.update(&mut cx, |this, cx| {
8479 Ok(T::response_to_proto(
8480 response,
8481 this,
8482 sender_id,
8483 &buffer_handle.read(cx).version(),
8484 cx,
8485 ))
8486 })?
8487 }
8488
8489 async fn handle_lsp_query(
8490 lsp_store: Entity<Self>,
8491 envelope: TypedEnvelope<proto::LspQuery>,
8492 mut cx: AsyncApp,
8493 ) -> Result<proto::Ack> {
8494 use proto::lsp_query::Request;
8495 let sender_id = envelope.original_sender_id().unwrap_or_default();
8496 let lsp_query = envelope.payload;
8497 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8498 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8499 match lsp_query.request.context("invalid LSP query request")? {
8500 Request::GetReferences(get_references) => {
8501 let position = get_references.position.clone().and_then(deserialize_anchor);
8502 Self::query_lsp_locally::<GetReferences>(
8503 lsp_store,
8504 server_id,
8505 sender_id,
8506 lsp_request_id,
8507 get_references,
8508 position,
8509 &mut cx,
8510 )
8511 .await?;
8512 }
8513 Request::GetDocumentColor(get_document_color) => {
8514 Self::query_lsp_locally::<GetDocumentColor>(
8515 lsp_store,
8516 server_id,
8517 sender_id,
8518 lsp_request_id,
8519 get_document_color,
8520 None,
8521 &mut cx,
8522 )
8523 .await?;
8524 }
8525 Request::GetHover(get_hover) => {
8526 let position = get_hover.position.clone().and_then(deserialize_anchor);
8527 Self::query_lsp_locally::<GetHover>(
8528 lsp_store,
8529 server_id,
8530 sender_id,
8531 lsp_request_id,
8532 get_hover,
8533 position,
8534 &mut cx,
8535 )
8536 .await?;
8537 }
8538 Request::GetCodeActions(get_code_actions) => {
8539 Self::query_lsp_locally::<GetCodeActions>(
8540 lsp_store,
8541 server_id,
8542 sender_id,
8543 lsp_request_id,
8544 get_code_actions,
8545 None,
8546 &mut cx,
8547 )
8548 .await?;
8549 }
8550 Request::GetSignatureHelp(get_signature_help) => {
8551 let position = get_signature_help
8552 .position
8553 .clone()
8554 .and_then(deserialize_anchor);
8555 Self::query_lsp_locally::<GetSignatureHelp>(
8556 lsp_store,
8557 server_id,
8558 sender_id,
8559 lsp_request_id,
8560 get_signature_help,
8561 position,
8562 &mut cx,
8563 )
8564 .await?;
8565 }
8566 Request::GetCodeLens(get_code_lens) => {
8567 Self::query_lsp_locally::<GetCodeLens>(
8568 lsp_store,
8569 server_id,
8570 sender_id,
8571 lsp_request_id,
8572 get_code_lens,
8573 None,
8574 &mut cx,
8575 )
8576 .await?;
8577 }
8578 Request::GetDefinition(get_definition) => {
8579 let position = get_definition.position.clone().and_then(deserialize_anchor);
8580 Self::query_lsp_locally::<GetDefinitions>(
8581 lsp_store,
8582 server_id,
8583 sender_id,
8584 lsp_request_id,
8585 get_definition,
8586 position,
8587 &mut cx,
8588 )
8589 .await?;
8590 }
8591 Request::GetDeclaration(get_declaration) => {
8592 let position = get_declaration
8593 .position
8594 .clone()
8595 .and_then(deserialize_anchor);
8596 Self::query_lsp_locally::<GetDeclarations>(
8597 lsp_store,
8598 server_id,
8599 sender_id,
8600 lsp_request_id,
8601 get_declaration,
8602 position,
8603 &mut cx,
8604 )
8605 .await?;
8606 }
8607 Request::GetTypeDefinition(get_type_definition) => {
8608 let position = get_type_definition
8609 .position
8610 .clone()
8611 .and_then(deserialize_anchor);
8612 Self::query_lsp_locally::<GetTypeDefinitions>(
8613 lsp_store,
8614 server_id,
8615 sender_id,
8616 lsp_request_id,
8617 get_type_definition,
8618 position,
8619 &mut cx,
8620 )
8621 .await?;
8622 }
8623 Request::GetImplementation(get_implementation) => {
8624 let position = get_implementation
8625 .position
8626 .clone()
8627 .and_then(deserialize_anchor);
8628 Self::query_lsp_locally::<GetImplementations>(
8629 lsp_store,
8630 server_id,
8631 sender_id,
8632 lsp_request_id,
8633 get_implementation,
8634 position,
8635 &mut cx,
8636 )
8637 .await?;
8638 }
8639 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8640 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8641 let version = deserialize_version(get_document_diagnostics.buffer_version());
8642 let buffer = lsp_store.update(&mut cx, |this, cx| {
8643 this.buffer_store.read(cx).get_existing(buffer_id)
8644 })??;
8645 buffer
8646 .update(&mut cx, |buffer, _| {
8647 buffer.wait_for_version(version.clone())
8648 })?
8649 .await?;
8650 lsp_store.update(&mut cx, |lsp_store, cx| {
8651 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8652 let key = LspKey {
8653 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8654 server_queried: server_id,
8655 };
8656 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8657 ) {
8658 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8659 lsp_requests.clear();
8660 };
8661 }
8662
8663 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8664 existing_queries.insert(
8665 lsp_request_id,
8666 cx.spawn(async move |lsp_store, cx| {
8667 let diagnostics_pull = lsp_store
8668 .update(cx, |lsp_store, cx| {
8669 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8670 })
8671 .ok();
8672 if let Some(diagnostics_pull) = diagnostics_pull {
8673 match diagnostics_pull.await {
8674 Ok(()) => {}
8675 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8676 };
8677 }
8678 }),
8679 );
8680 })?;
8681 }
8682 Request::InlayHints(inlay_hints) => {
8683 let query_start = inlay_hints
8684 .start
8685 .clone()
8686 .and_then(deserialize_anchor)
8687 .context("invalid inlay hints range start")?;
8688 let query_end = inlay_hints
8689 .end
8690 .clone()
8691 .and_then(deserialize_anchor)
8692 .context("invalid inlay hints range end")?;
8693 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8694 &lsp_store,
8695 server_id,
8696 lsp_request_id,
8697 &inlay_hints,
8698 query_start..query_end,
8699 &mut cx,
8700 )
8701 .await
8702 .context("preparing inlay hints request")?;
8703 Self::query_lsp_locally::<InlayHints>(
8704 lsp_store,
8705 server_id,
8706 sender_id,
8707 lsp_request_id,
8708 inlay_hints,
8709 None,
8710 &mut cx,
8711 )
8712 .await
8713 .context("querying for inlay hints")?
8714 }
8715 }
8716 Ok(proto::Ack {})
8717 }
8718
8719 async fn handle_lsp_query_response(
8720 lsp_store: Entity<Self>,
8721 envelope: TypedEnvelope<proto::LspQueryResponse>,
8722 cx: AsyncApp,
8723 ) -> Result<()> {
8724 lsp_store.read_with(&cx, |lsp_store, _| {
8725 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8726 upstream_client.handle_lsp_response(envelope.clone());
8727 }
8728 })?;
8729 Ok(())
8730 }
8731
8732 async fn handle_apply_code_action(
8733 this: Entity<Self>,
8734 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8735 mut cx: AsyncApp,
8736 ) -> Result<proto::ApplyCodeActionResponse> {
8737 let sender_id = envelope.original_sender_id().unwrap_or_default();
8738 let action =
8739 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8740 let apply_code_action = this.update(&mut cx, |this, cx| {
8741 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8742 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8743 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8744 })??;
8745
8746 let project_transaction = apply_code_action.await?;
8747 let project_transaction = this.update(&mut cx, |this, cx| {
8748 this.buffer_store.update(cx, |buffer_store, cx| {
8749 buffer_store.serialize_project_transaction_for_peer(
8750 project_transaction,
8751 sender_id,
8752 cx,
8753 )
8754 })
8755 })?;
8756 Ok(proto::ApplyCodeActionResponse {
8757 transaction: Some(project_transaction),
8758 })
8759 }
8760
8761 async fn handle_register_buffer_with_language_servers(
8762 this: Entity<Self>,
8763 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8764 mut cx: AsyncApp,
8765 ) -> Result<proto::Ack> {
8766 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8767 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8768 this.update(&mut cx, |this, cx| {
8769 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8770 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8771 project_id: upstream_project_id,
8772 buffer_id: buffer_id.to_proto(),
8773 only_servers: envelope.payload.only_servers,
8774 });
8775 }
8776
8777 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8778 anyhow::bail!("buffer is not open");
8779 };
8780
8781 let handle = this.register_buffer_with_language_servers(
8782 &buffer,
8783 envelope
8784 .payload
8785 .only_servers
8786 .into_iter()
8787 .filter_map(|selector| {
8788 Some(match selector.selector? {
8789 proto::language_server_selector::Selector::ServerId(server_id) => {
8790 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8791 }
8792 proto::language_server_selector::Selector::Name(name) => {
8793 LanguageServerSelector::Name(LanguageServerName(
8794 SharedString::from(name),
8795 ))
8796 }
8797 })
8798 })
8799 .collect(),
8800 false,
8801 cx,
8802 );
8803 this.buffer_store().update(cx, |buffer_store, _| {
8804 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8805 });
8806
8807 Ok(())
8808 })??;
8809 Ok(proto::Ack {})
8810 }
8811
8812 async fn handle_rename_project_entry(
8813 this: Entity<Self>,
8814 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8815 mut cx: AsyncApp,
8816 ) -> Result<proto::ProjectEntryResponse> {
8817 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8818 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8819 let new_path =
8820 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8821
8822 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8823 .update(&mut cx, |this, cx| {
8824 let (worktree, entry) = this
8825 .worktree_store
8826 .read(cx)
8827 .worktree_and_entry_for_id(entry_id, cx)?;
8828 let new_worktree = this
8829 .worktree_store
8830 .read(cx)
8831 .worktree_for_id(new_worktree_id, cx)?;
8832 Some((
8833 this.worktree_store.clone(),
8834 worktree,
8835 new_worktree,
8836 entry.clone(),
8837 ))
8838 })?
8839 .context("worktree not found")?;
8840 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8841 (worktree.absolutize(&old_entry.path), worktree.id())
8842 })?;
8843 let new_abs_path =
8844 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8845
8846 let _transaction = Self::will_rename_entry(
8847 this.downgrade(),
8848 old_worktree_id,
8849 &old_abs_path,
8850 &new_abs_path,
8851 old_entry.is_dir(),
8852 cx.clone(),
8853 )
8854 .await;
8855 let response = WorktreeStore::handle_rename_project_entry(
8856 worktree_store,
8857 envelope.payload,
8858 cx.clone(),
8859 )
8860 .await;
8861 this.read_with(&cx, |this, _| {
8862 this.did_rename_entry(
8863 old_worktree_id,
8864 &old_abs_path,
8865 &new_abs_path,
8866 old_entry.is_dir(),
8867 );
8868 })
8869 .ok();
8870 response
8871 }
8872
8873 async fn handle_update_diagnostic_summary(
8874 this: Entity<Self>,
8875 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8876 mut cx: AsyncApp,
8877 ) -> Result<()> {
8878 this.update(&mut cx, |lsp_store, cx| {
8879 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8880 let mut updated_diagnostics_paths = HashMap::default();
8881 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8882 for message_summary in envelope
8883 .payload
8884 .summary
8885 .into_iter()
8886 .chain(envelope.payload.more_summaries)
8887 {
8888 let project_path = ProjectPath {
8889 worktree_id,
8890 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8891 };
8892 let path = project_path.path.clone();
8893 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8894 let summary = DiagnosticSummary {
8895 error_count: message_summary.error_count as usize,
8896 warning_count: message_summary.warning_count as usize,
8897 };
8898
8899 if summary.is_empty() {
8900 if let Some(worktree_summaries) =
8901 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8902 && let Some(summaries) = worktree_summaries.get_mut(&path)
8903 {
8904 summaries.remove(&server_id);
8905 if summaries.is_empty() {
8906 worktree_summaries.remove(&path);
8907 }
8908 }
8909 } else {
8910 lsp_store
8911 .diagnostic_summaries
8912 .entry(worktree_id)
8913 .or_default()
8914 .entry(path)
8915 .or_default()
8916 .insert(server_id, summary);
8917 }
8918
8919 if let Some((_, project_id)) = &lsp_store.downstream_client {
8920 match &mut diagnostics_summary {
8921 Some(diagnostics_summary) => {
8922 diagnostics_summary
8923 .more_summaries
8924 .push(proto::DiagnosticSummary {
8925 path: project_path.path.as_ref().to_proto(),
8926 language_server_id: server_id.0 as u64,
8927 error_count: summary.error_count as u32,
8928 warning_count: summary.warning_count as u32,
8929 })
8930 }
8931 None => {
8932 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8933 project_id: *project_id,
8934 worktree_id: worktree_id.to_proto(),
8935 summary: Some(proto::DiagnosticSummary {
8936 path: project_path.path.as_ref().to_proto(),
8937 language_server_id: server_id.0 as u64,
8938 error_count: summary.error_count as u32,
8939 warning_count: summary.warning_count as u32,
8940 }),
8941 more_summaries: Vec::new(),
8942 })
8943 }
8944 }
8945 }
8946 updated_diagnostics_paths
8947 .entry(server_id)
8948 .or_insert_with(Vec::new)
8949 .push(project_path);
8950 }
8951
8952 if let Some((diagnostics_summary, (downstream_client, _))) =
8953 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8954 {
8955 downstream_client.send(diagnostics_summary).log_err();
8956 }
8957 for (server_id, paths) in updated_diagnostics_paths {
8958 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8959 }
8960 Ok(())
8961 })?
8962 }
8963
8964 async fn handle_start_language_server(
8965 lsp_store: Entity<Self>,
8966 envelope: TypedEnvelope<proto::StartLanguageServer>,
8967 mut cx: AsyncApp,
8968 ) -> Result<()> {
8969 let server = envelope.payload.server.context("invalid server")?;
8970 let server_capabilities =
8971 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8972 .with_context(|| {
8973 format!(
8974 "incorrect server capabilities {}",
8975 envelope.payload.capabilities
8976 )
8977 })?;
8978 lsp_store.update(&mut cx, |lsp_store, cx| {
8979 let server_id = LanguageServerId(server.id as usize);
8980 let server_name = LanguageServerName::from_proto(server.name.clone());
8981 lsp_store
8982 .lsp_server_capabilities
8983 .insert(server_id, server_capabilities);
8984 lsp_store.language_server_statuses.insert(
8985 server_id,
8986 LanguageServerStatus {
8987 name: server_name.clone(),
8988 pending_work: Default::default(),
8989 has_pending_diagnostic_updates: false,
8990 progress_tokens: Default::default(),
8991 worktree: server.worktree_id.map(WorktreeId::from_proto),
8992 },
8993 );
8994 cx.emit(LspStoreEvent::LanguageServerAdded(
8995 server_id,
8996 server_name,
8997 server.worktree_id.map(WorktreeId::from_proto),
8998 ));
8999 cx.notify();
9000 })?;
9001 Ok(())
9002 }
9003
9004 async fn handle_update_language_server(
9005 lsp_store: Entity<Self>,
9006 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9007 mut cx: AsyncApp,
9008 ) -> Result<()> {
9009 lsp_store.update(&mut cx, |lsp_store, cx| {
9010 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9011
9012 match envelope.payload.variant.context("invalid variant")? {
9013 proto::update_language_server::Variant::WorkStart(payload) => {
9014 lsp_store.on_lsp_work_start(
9015 language_server_id,
9016 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9017 .context("invalid progress token value")?,
9018 LanguageServerProgress {
9019 title: payload.title,
9020 is_disk_based_diagnostics_progress: false,
9021 is_cancellable: payload.is_cancellable.unwrap_or(false),
9022 message: payload.message,
9023 percentage: payload.percentage.map(|p| p as usize),
9024 last_update_at: cx.background_executor().now(),
9025 },
9026 cx,
9027 );
9028 }
9029 proto::update_language_server::Variant::WorkProgress(payload) => {
9030 lsp_store.on_lsp_work_progress(
9031 language_server_id,
9032 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9033 .context("invalid progress token value")?,
9034 LanguageServerProgress {
9035 title: None,
9036 is_disk_based_diagnostics_progress: false,
9037 is_cancellable: payload.is_cancellable.unwrap_or(false),
9038 message: payload.message,
9039 percentage: payload.percentage.map(|p| p as usize),
9040 last_update_at: cx.background_executor().now(),
9041 },
9042 cx,
9043 );
9044 }
9045
9046 proto::update_language_server::Variant::WorkEnd(payload) => {
9047 lsp_store.on_lsp_work_end(
9048 language_server_id,
9049 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9050 .context("invalid progress token value")?,
9051 cx,
9052 );
9053 }
9054
9055 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9056 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9057 }
9058
9059 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9060 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9061 }
9062
9063 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9064 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9065 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9066 cx.emit(LspStoreEvent::LanguageServerUpdate {
9067 language_server_id,
9068 name: envelope
9069 .payload
9070 .server_name
9071 .map(SharedString::new)
9072 .map(LanguageServerName),
9073 message: non_lsp,
9074 });
9075 }
9076 }
9077
9078 Ok(())
9079 })?
9080 }
9081
9082 async fn handle_language_server_log(
9083 this: Entity<Self>,
9084 envelope: TypedEnvelope<proto::LanguageServerLog>,
9085 mut cx: AsyncApp,
9086 ) -> Result<()> {
9087 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9088 let log_type = envelope
9089 .payload
9090 .log_type
9091 .map(LanguageServerLogType::from_proto)
9092 .context("invalid language server log type")?;
9093
9094 let message = envelope.payload.message;
9095
9096 this.update(&mut cx, |_, cx| {
9097 cx.emit(LspStoreEvent::LanguageServerLog(
9098 language_server_id,
9099 log_type,
9100 message,
9101 ));
9102 })
9103 }
9104
9105 async fn handle_lsp_ext_cancel_flycheck(
9106 lsp_store: Entity<Self>,
9107 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9108 cx: AsyncApp,
9109 ) -> Result<proto::Ack> {
9110 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9111 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9112 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9113 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9114 } else {
9115 None
9116 }
9117 })?;
9118 if let Some(task) = task {
9119 task.context("handling lsp ext cancel flycheck")?;
9120 }
9121
9122 Ok(proto::Ack {})
9123 }
9124
9125 async fn handle_lsp_ext_run_flycheck(
9126 lsp_store: Entity<Self>,
9127 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9128 mut cx: AsyncApp,
9129 ) -> Result<proto::Ack> {
9130 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9131 lsp_store.update(&mut cx, |lsp_store, cx| {
9132 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9133 let text_document = if envelope.payload.current_file_only {
9134 let buffer_id = envelope
9135 .payload
9136 .buffer_id
9137 .map(|id| BufferId::new(id))
9138 .transpose()?;
9139 buffer_id
9140 .and_then(|buffer_id| {
9141 lsp_store
9142 .buffer_store()
9143 .read(cx)
9144 .get(buffer_id)
9145 .and_then(|buffer| {
9146 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9147 })
9148 .map(|path| make_text_document_identifier(&path))
9149 })
9150 .transpose()?
9151 } else {
9152 None
9153 };
9154 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9155 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9156 )?;
9157 }
9158 anyhow::Ok(())
9159 })??;
9160
9161 Ok(proto::Ack {})
9162 }
9163
9164 async fn handle_lsp_ext_clear_flycheck(
9165 lsp_store: Entity<Self>,
9166 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9167 cx: AsyncApp,
9168 ) -> Result<proto::Ack> {
9169 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9170 lsp_store
9171 .read_with(&cx, |lsp_store, _| {
9172 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9173 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9174 } else {
9175 None
9176 }
9177 })
9178 .context("handling lsp ext clear flycheck")?;
9179
9180 Ok(proto::Ack {})
9181 }
9182
9183 pub fn disk_based_diagnostics_started(
9184 &mut self,
9185 language_server_id: LanguageServerId,
9186 cx: &mut Context<Self>,
9187 ) {
9188 if let Some(language_server_status) =
9189 self.language_server_statuses.get_mut(&language_server_id)
9190 {
9191 language_server_status.has_pending_diagnostic_updates = true;
9192 }
9193
9194 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9195 cx.emit(LspStoreEvent::LanguageServerUpdate {
9196 language_server_id,
9197 name: self
9198 .language_server_adapter_for_id(language_server_id)
9199 .map(|adapter| adapter.name()),
9200 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9201 Default::default(),
9202 ),
9203 })
9204 }
9205
9206 pub fn disk_based_diagnostics_finished(
9207 &mut self,
9208 language_server_id: LanguageServerId,
9209 cx: &mut Context<Self>,
9210 ) {
9211 if let Some(language_server_status) =
9212 self.language_server_statuses.get_mut(&language_server_id)
9213 {
9214 language_server_status.has_pending_diagnostic_updates = false;
9215 }
9216
9217 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9218 cx.emit(LspStoreEvent::LanguageServerUpdate {
9219 language_server_id,
9220 name: self
9221 .language_server_adapter_for_id(language_server_id)
9222 .map(|adapter| adapter.name()),
9223 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9224 Default::default(),
9225 ),
9226 })
9227 }
9228
9229 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9230 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9231 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9232 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9233 // the language server might take some time to publish diagnostics.
9234 fn simulate_disk_based_diagnostics_events_if_needed(
9235 &mut self,
9236 language_server_id: LanguageServerId,
9237 cx: &mut Context<Self>,
9238 ) {
9239 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9240
9241 let Some(LanguageServerState::Running {
9242 simulate_disk_based_diagnostics_completion,
9243 adapter,
9244 ..
9245 }) = self
9246 .as_local_mut()
9247 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9248 else {
9249 return;
9250 };
9251
9252 if adapter.disk_based_diagnostics_progress_token.is_some() {
9253 return;
9254 }
9255
9256 let prev_task =
9257 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9258 cx.background_executor()
9259 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9260 .await;
9261
9262 this.update(cx, |this, cx| {
9263 this.disk_based_diagnostics_finished(language_server_id, cx);
9264
9265 if let Some(LanguageServerState::Running {
9266 simulate_disk_based_diagnostics_completion,
9267 ..
9268 }) = this.as_local_mut().and_then(|local_store| {
9269 local_store.language_servers.get_mut(&language_server_id)
9270 }) {
9271 *simulate_disk_based_diagnostics_completion = None;
9272 }
9273 })
9274 .ok();
9275 }));
9276
9277 if prev_task.is_none() {
9278 self.disk_based_diagnostics_started(language_server_id, cx);
9279 }
9280 }
9281
9282 pub fn language_server_statuses(
9283 &self,
9284 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9285 self.language_server_statuses
9286 .iter()
9287 .map(|(key, value)| (*key, value))
9288 }
9289
9290 pub(super) fn did_rename_entry(
9291 &self,
9292 worktree_id: WorktreeId,
9293 old_path: &Path,
9294 new_path: &Path,
9295 is_dir: bool,
9296 ) {
9297 maybe!({
9298 let local_store = self.as_local()?;
9299
9300 let old_uri = lsp::Uri::from_file_path(old_path)
9301 .ok()
9302 .map(|uri| uri.to_string())?;
9303 let new_uri = lsp::Uri::from_file_path(new_path)
9304 .ok()
9305 .map(|uri| uri.to_string())?;
9306
9307 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9308 let Some(filter) = local_store
9309 .language_server_paths_watched_for_rename
9310 .get(&language_server.server_id())
9311 else {
9312 continue;
9313 };
9314
9315 if filter.should_send_did_rename(&old_uri, is_dir) {
9316 language_server
9317 .notify::<DidRenameFiles>(RenameFilesParams {
9318 files: vec![FileRename {
9319 old_uri: old_uri.clone(),
9320 new_uri: new_uri.clone(),
9321 }],
9322 })
9323 .ok();
9324 }
9325 }
9326 Some(())
9327 });
9328 }
9329
9330 pub(super) fn will_rename_entry(
9331 this: WeakEntity<Self>,
9332 worktree_id: WorktreeId,
9333 old_path: &Path,
9334 new_path: &Path,
9335 is_dir: bool,
9336 cx: AsyncApp,
9337 ) -> Task<ProjectTransaction> {
9338 let old_uri = lsp::Uri::from_file_path(old_path)
9339 .ok()
9340 .map(|uri| uri.to_string());
9341 let new_uri = lsp::Uri::from_file_path(new_path)
9342 .ok()
9343 .map(|uri| uri.to_string());
9344 cx.spawn(async move |cx| {
9345 let mut tasks = vec![];
9346 this.update(cx, |this, cx| {
9347 let local_store = this.as_local()?;
9348 let old_uri = old_uri?;
9349 let new_uri = new_uri?;
9350 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9351 let Some(filter) = local_store
9352 .language_server_paths_watched_for_rename
9353 .get(&language_server.server_id())
9354 else {
9355 continue;
9356 };
9357
9358 if filter.should_send_will_rename(&old_uri, is_dir) {
9359 let apply_edit = cx.spawn({
9360 let old_uri = old_uri.clone();
9361 let new_uri = new_uri.clone();
9362 let language_server = language_server.clone();
9363 async move |this, cx| {
9364 let edit = language_server
9365 .request::<WillRenameFiles>(RenameFilesParams {
9366 files: vec![FileRename { old_uri, new_uri }],
9367 })
9368 .await
9369 .into_response()
9370 .context("will rename files")
9371 .log_err()
9372 .flatten()?;
9373
9374 let transaction = LocalLspStore::deserialize_workspace_edit(
9375 this.upgrade()?,
9376 edit,
9377 false,
9378 language_server.clone(),
9379 cx,
9380 )
9381 .await
9382 .ok()?;
9383 Some(transaction)
9384 }
9385 });
9386 tasks.push(apply_edit);
9387 }
9388 }
9389 Some(())
9390 })
9391 .ok()
9392 .flatten();
9393 let mut merged_transaction = ProjectTransaction::default();
9394 for task in tasks {
9395 // Await on tasks sequentially so that the order of application of edits is deterministic
9396 // (at least with regards to the order of registration of language servers)
9397 if let Some(transaction) = task.await {
9398 for (buffer, buffer_transaction) in transaction.0 {
9399 merged_transaction.0.insert(buffer, buffer_transaction);
9400 }
9401 }
9402 }
9403 merged_transaction
9404 })
9405 }
9406
9407 fn lsp_notify_abs_paths_changed(
9408 &mut self,
9409 server_id: LanguageServerId,
9410 changes: Vec<PathEvent>,
9411 ) {
9412 maybe!({
9413 let server = self.language_server_for_id(server_id)?;
9414 let changes = changes
9415 .into_iter()
9416 .filter_map(|event| {
9417 let typ = match event.kind? {
9418 PathEventKind::Created => lsp::FileChangeType::CREATED,
9419 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9420 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9421 };
9422 Some(lsp::FileEvent {
9423 uri: file_path_to_lsp_url(&event.path).log_err()?,
9424 typ,
9425 })
9426 })
9427 .collect::<Vec<_>>();
9428 if !changes.is_empty() {
9429 server
9430 .notify::<lsp::notification::DidChangeWatchedFiles>(
9431 lsp::DidChangeWatchedFilesParams { changes },
9432 )
9433 .ok();
9434 }
9435 Some(())
9436 });
9437 }
9438
9439 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9440 self.as_local()?.language_server_for_id(id)
9441 }
9442
9443 fn on_lsp_progress(
9444 &mut self,
9445 progress_params: lsp::ProgressParams,
9446 language_server_id: LanguageServerId,
9447 disk_based_diagnostics_progress_token: Option<String>,
9448 cx: &mut Context<Self>,
9449 ) {
9450 match progress_params.value {
9451 lsp::ProgressParamsValue::WorkDone(progress) => {
9452 self.handle_work_done_progress(
9453 progress,
9454 language_server_id,
9455 disk_based_diagnostics_progress_token,
9456 ProgressToken::from_lsp(progress_params.token),
9457 cx,
9458 );
9459 }
9460 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9461 let identifier = match progress_params.token {
9462 lsp::NumberOrString::Number(_) => None,
9463 lsp::NumberOrString::String(token) => token
9464 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9465 .map(|(_, id)| id.to_owned()),
9466 };
9467 if let Some(LanguageServerState::Running {
9468 workspace_diagnostics_refresh_tasks,
9469 ..
9470 }) = self
9471 .as_local_mut()
9472 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9473 && let Some(workspace_diagnostics) =
9474 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9475 {
9476 workspace_diagnostics.progress_tx.try_send(()).ok();
9477 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9478 }
9479 }
9480 }
9481 }
9482
9483 fn handle_work_done_progress(
9484 &mut self,
9485 progress: lsp::WorkDoneProgress,
9486 language_server_id: LanguageServerId,
9487 disk_based_diagnostics_progress_token: Option<String>,
9488 token: ProgressToken,
9489 cx: &mut Context<Self>,
9490 ) {
9491 let language_server_status =
9492 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9493 status
9494 } else {
9495 return;
9496 };
9497
9498 if !language_server_status.progress_tokens.contains(&token) {
9499 return;
9500 }
9501
9502 let is_disk_based_diagnostics_progress =
9503 if let (Some(disk_based_token), ProgressToken::String(token)) =
9504 (&disk_based_diagnostics_progress_token, &token)
9505 {
9506 token.starts_with(disk_based_token)
9507 } else {
9508 false
9509 };
9510
9511 match progress {
9512 lsp::WorkDoneProgress::Begin(report) => {
9513 if is_disk_based_diagnostics_progress {
9514 self.disk_based_diagnostics_started(language_server_id, cx);
9515 }
9516 self.on_lsp_work_start(
9517 language_server_id,
9518 token.clone(),
9519 LanguageServerProgress {
9520 title: Some(report.title),
9521 is_disk_based_diagnostics_progress,
9522 is_cancellable: report.cancellable.unwrap_or(false),
9523 message: report.message.clone(),
9524 percentage: report.percentage.map(|p| p as usize),
9525 last_update_at: cx.background_executor().now(),
9526 },
9527 cx,
9528 );
9529 }
9530 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9531 language_server_id,
9532 token,
9533 LanguageServerProgress {
9534 title: None,
9535 is_disk_based_diagnostics_progress,
9536 is_cancellable: report.cancellable.unwrap_or(false),
9537 message: report.message,
9538 percentage: report.percentage.map(|p| p as usize),
9539 last_update_at: cx.background_executor().now(),
9540 },
9541 cx,
9542 ),
9543 lsp::WorkDoneProgress::End(_) => {
9544 language_server_status.progress_tokens.remove(&token);
9545 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9546 if is_disk_based_diagnostics_progress {
9547 self.disk_based_diagnostics_finished(language_server_id, cx);
9548 }
9549 }
9550 }
9551 }
9552
9553 fn on_lsp_work_start(
9554 &mut self,
9555 language_server_id: LanguageServerId,
9556 token: ProgressToken,
9557 progress: LanguageServerProgress,
9558 cx: &mut Context<Self>,
9559 ) {
9560 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9561 status.pending_work.insert(token.clone(), progress.clone());
9562 cx.notify();
9563 }
9564 cx.emit(LspStoreEvent::LanguageServerUpdate {
9565 language_server_id,
9566 name: self
9567 .language_server_adapter_for_id(language_server_id)
9568 .map(|adapter| adapter.name()),
9569 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9570 token: Some(token.to_proto()),
9571 title: progress.title,
9572 message: progress.message,
9573 percentage: progress.percentage.map(|p| p as u32),
9574 is_cancellable: Some(progress.is_cancellable),
9575 }),
9576 })
9577 }
9578
9579 fn on_lsp_work_progress(
9580 &mut self,
9581 language_server_id: LanguageServerId,
9582 token: ProgressToken,
9583 progress: LanguageServerProgress,
9584 cx: &mut Context<Self>,
9585 ) {
9586 let mut did_update = false;
9587 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9588 match status.pending_work.entry(token.clone()) {
9589 btree_map::Entry::Vacant(entry) => {
9590 entry.insert(progress.clone());
9591 did_update = true;
9592 }
9593 btree_map::Entry::Occupied(mut entry) => {
9594 let entry = entry.get_mut();
9595 if (progress.last_update_at - entry.last_update_at)
9596 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9597 {
9598 entry.last_update_at = progress.last_update_at;
9599 if progress.message.is_some() {
9600 entry.message = progress.message.clone();
9601 }
9602 if progress.percentage.is_some() {
9603 entry.percentage = progress.percentage;
9604 }
9605 if progress.is_cancellable != entry.is_cancellable {
9606 entry.is_cancellable = progress.is_cancellable;
9607 }
9608 did_update = true;
9609 }
9610 }
9611 }
9612 }
9613
9614 if did_update {
9615 cx.emit(LspStoreEvent::LanguageServerUpdate {
9616 language_server_id,
9617 name: self
9618 .language_server_adapter_for_id(language_server_id)
9619 .map(|adapter| adapter.name()),
9620 message: proto::update_language_server::Variant::WorkProgress(
9621 proto::LspWorkProgress {
9622 token: Some(token.to_proto()),
9623 message: progress.message,
9624 percentage: progress.percentage.map(|p| p as u32),
9625 is_cancellable: Some(progress.is_cancellable),
9626 },
9627 ),
9628 })
9629 }
9630 }
9631
9632 fn on_lsp_work_end(
9633 &mut self,
9634 language_server_id: LanguageServerId,
9635 token: ProgressToken,
9636 cx: &mut Context<Self>,
9637 ) {
9638 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9639 if let Some(work) = status.pending_work.remove(&token)
9640 && !work.is_disk_based_diagnostics_progress
9641 {
9642 cx.emit(LspStoreEvent::RefreshInlayHints {
9643 server_id: language_server_id,
9644 request_id: None,
9645 });
9646 }
9647 cx.notify();
9648 }
9649
9650 cx.emit(LspStoreEvent::LanguageServerUpdate {
9651 language_server_id,
9652 name: self
9653 .language_server_adapter_for_id(language_server_id)
9654 .map(|adapter| adapter.name()),
9655 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9656 token: Some(token.to_proto()),
9657 }),
9658 })
9659 }
9660
9661 pub async fn handle_resolve_completion_documentation(
9662 this: Entity<Self>,
9663 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9664 mut cx: AsyncApp,
9665 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9666 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9667
9668 let completion = this
9669 .read_with(&cx, |this, cx| {
9670 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9671 let server = this
9672 .language_server_for_id(id)
9673 .with_context(|| format!("No language server {id}"))?;
9674
9675 anyhow::Ok(cx.background_spawn(async move {
9676 let can_resolve = server
9677 .capabilities()
9678 .completion_provider
9679 .as_ref()
9680 .and_then(|options| options.resolve_provider)
9681 .unwrap_or(false);
9682 if can_resolve {
9683 server
9684 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9685 .await
9686 .into_response()
9687 .context("resolve completion item")
9688 } else {
9689 anyhow::Ok(lsp_completion)
9690 }
9691 }))
9692 })??
9693 .await?;
9694
9695 let mut documentation_is_markdown = false;
9696 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9697 let documentation = match completion.documentation {
9698 Some(lsp::Documentation::String(text)) => text,
9699
9700 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9701 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9702 value
9703 }
9704
9705 _ => String::new(),
9706 };
9707
9708 // If we have a new buffer_id, that means we're talking to a new client
9709 // and want to check for new text_edits in the completion too.
9710 let mut old_replace_start = None;
9711 let mut old_replace_end = None;
9712 let mut old_insert_start = None;
9713 let mut old_insert_end = None;
9714 let mut new_text = String::default();
9715 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9716 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9717 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9718 anyhow::Ok(buffer.read(cx).snapshot())
9719 })??;
9720
9721 if let Some(text_edit) = completion.text_edit.as_ref() {
9722 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9723
9724 if let Some(mut edit) = edit {
9725 LineEnding::normalize(&mut edit.new_text);
9726
9727 new_text = edit.new_text;
9728 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9729 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9730 if let Some(insert_range) = edit.insert_range {
9731 old_insert_start = Some(serialize_anchor(&insert_range.start));
9732 old_insert_end = Some(serialize_anchor(&insert_range.end));
9733 }
9734 }
9735 }
9736 }
9737
9738 Ok(proto::ResolveCompletionDocumentationResponse {
9739 documentation,
9740 documentation_is_markdown,
9741 old_replace_start,
9742 old_replace_end,
9743 new_text,
9744 lsp_completion,
9745 old_insert_start,
9746 old_insert_end,
9747 })
9748 }
9749
9750 async fn handle_on_type_formatting(
9751 this: Entity<Self>,
9752 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9753 mut cx: AsyncApp,
9754 ) -> Result<proto::OnTypeFormattingResponse> {
9755 let on_type_formatting = this.update(&mut cx, |this, cx| {
9756 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9757 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9758 let position = envelope
9759 .payload
9760 .position
9761 .and_then(deserialize_anchor)
9762 .context("invalid position")?;
9763 anyhow::Ok(this.apply_on_type_formatting(
9764 buffer,
9765 position,
9766 envelope.payload.trigger.clone(),
9767 cx,
9768 ))
9769 })??;
9770
9771 let transaction = on_type_formatting
9772 .await?
9773 .as_ref()
9774 .map(language::proto::serialize_transaction);
9775 Ok(proto::OnTypeFormattingResponse { transaction })
9776 }
9777
9778 async fn handle_refresh_inlay_hints(
9779 lsp_store: Entity<Self>,
9780 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9781 mut cx: AsyncApp,
9782 ) -> Result<proto::Ack> {
9783 lsp_store.update(&mut cx, |_, cx| {
9784 cx.emit(LspStoreEvent::RefreshInlayHints {
9785 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9786 request_id: envelope.payload.request_id.map(|id| id as usize),
9787 });
9788 })?;
9789 Ok(proto::Ack {})
9790 }
9791
9792 async fn handle_pull_workspace_diagnostics(
9793 lsp_store: Entity<Self>,
9794 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9795 mut cx: AsyncApp,
9796 ) -> Result<proto::Ack> {
9797 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9798 lsp_store.update(&mut cx, |lsp_store, _| {
9799 lsp_store.pull_workspace_diagnostics(server_id);
9800 })?;
9801 Ok(proto::Ack {})
9802 }
9803
9804 async fn handle_get_color_presentation(
9805 lsp_store: Entity<Self>,
9806 envelope: TypedEnvelope<proto::GetColorPresentation>,
9807 mut cx: AsyncApp,
9808 ) -> Result<proto::GetColorPresentationResponse> {
9809 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9810 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9811 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9812 })??;
9813
9814 let color = envelope
9815 .payload
9816 .color
9817 .context("invalid color resolve request")?;
9818 let start = color
9819 .lsp_range_start
9820 .context("invalid color resolve request")?;
9821 let end = color
9822 .lsp_range_end
9823 .context("invalid color resolve request")?;
9824
9825 let color = DocumentColor {
9826 lsp_range: lsp::Range {
9827 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9828 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9829 },
9830 color: lsp::Color {
9831 red: color.red,
9832 green: color.green,
9833 blue: color.blue,
9834 alpha: color.alpha,
9835 },
9836 resolved: false,
9837 color_presentations: Vec::new(),
9838 };
9839 let resolved_color = lsp_store
9840 .update(&mut cx, |lsp_store, cx| {
9841 lsp_store.resolve_color_presentation(
9842 color,
9843 buffer.clone(),
9844 LanguageServerId(envelope.payload.server_id as usize),
9845 cx,
9846 )
9847 })?
9848 .await
9849 .context("resolving color presentation")?;
9850
9851 Ok(proto::GetColorPresentationResponse {
9852 presentations: resolved_color
9853 .color_presentations
9854 .into_iter()
9855 .map(|presentation| proto::ColorPresentation {
9856 label: presentation.label.to_string(),
9857 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9858 additional_text_edits: presentation
9859 .additional_text_edits
9860 .into_iter()
9861 .map(serialize_lsp_edit)
9862 .collect(),
9863 })
9864 .collect(),
9865 })
9866 }
9867
9868 async fn handle_resolve_inlay_hint(
9869 lsp_store: Entity<Self>,
9870 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9871 mut cx: AsyncApp,
9872 ) -> Result<proto::ResolveInlayHintResponse> {
9873 let proto_hint = envelope
9874 .payload
9875 .hint
9876 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9877 let hint = InlayHints::proto_to_project_hint(proto_hint)
9878 .context("resolved proto inlay hint conversion")?;
9879 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9880 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9881 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9882 })??;
9883 let response_hint = lsp_store
9884 .update(&mut cx, |lsp_store, cx| {
9885 lsp_store.resolve_inlay_hint(
9886 hint,
9887 buffer,
9888 LanguageServerId(envelope.payload.language_server_id as usize),
9889 cx,
9890 )
9891 })?
9892 .await
9893 .context("inlay hints fetch")?;
9894 Ok(proto::ResolveInlayHintResponse {
9895 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9896 })
9897 }
9898
9899 async fn handle_refresh_code_lens(
9900 this: Entity<Self>,
9901 _: TypedEnvelope<proto::RefreshCodeLens>,
9902 mut cx: AsyncApp,
9903 ) -> Result<proto::Ack> {
9904 this.update(&mut cx, |_, cx| {
9905 cx.emit(LspStoreEvent::RefreshCodeLens);
9906 })?;
9907 Ok(proto::Ack {})
9908 }
9909
9910 async fn handle_open_buffer_for_symbol(
9911 this: Entity<Self>,
9912 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9913 mut cx: AsyncApp,
9914 ) -> Result<proto::OpenBufferForSymbolResponse> {
9915 let peer_id = envelope.original_sender_id().unwrap_or_default();
9916 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9917 let symbol = Self::deserialize_symbol(symbol)?;
9918 this.read_with(&cx, |this, _| {
9919 if let SymbolLocation::OutsideProject {
9920 abs_path,
9921 signature,
9922 } = &symbol.path
9923 {
9924 let new_signature = this.symbol_signature(&abs_path);
9925 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9926 }
9927 Ok(())
9928 })??;
9929 let buffer = this
9930 .update(&mut cx, |this, cx| {
9931 this.open_buffer_for_symbol(
9932 &Symbol {
9933 language_server_name: symbol.language_server_name,
9934 source_worktree_id: symbol.source_worktree_id,
9935 source_language_server_id: symbol.source_language_server_id,
9936 path: symbol.path,
9937 name: symbol.name,
9938 kind: symbol.kind,
9939 range: symbol.range,
9940 label: CodeLabel::default(),
9941 },
9942 cx,
9943 )
9944 })?
9945 .await?;
9946
9947 this.update(&mut cx, |this, cx| {
9948 let is_private = buffer
9949 .read(cx)
9950 .file()
9951 .map(|f| f.is_private())
9952 .unwrap_or_default();
9953 if is_private {
9954 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9955 } else {
9956 this.buffer_store
9957 .update(cx, |buffer_store, cx| {
9958 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9959 })
9960 .detach_and_log_err(cx);
9961 let buffer_id = buffer.read(cx).remote_id().to_proto();
9962 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9963 }
9964 })?
9965 }
9966
9967 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9968 let mut hasher = Sha256::new();
9969 hasher.update(abs_path.to_string_lossy().as_bytes());
9970 hasher.update(self.nonce.to_be_bytes());
9971 hasher.finalize().as_slice().try_into().unwrap()
9972 }
9973
9974 pub async fn handle_get_project_symbols(
9975 this: Entity<Self>,
9976 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9977 mut cx: AsyncApp,
9978 ) -> Result<proto::GetProjectSymbolsResponse> {
9979 let symbols = this
9980 .update(&mut cx, |this, cx| {
9981 this.symbols(&envelope.payload.query, cx)
9982 })?
9983 .await?;
9984
9985 Ok(proto::GetProjectSymbolsResponse {
9986 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9987 })
9988 }
9989
9990 pub async fn handle_restart_language_servers(
9991 this: Entity<Self>,
9992 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9993 mut cx: AsyncApp,
9994 ) -> Result<proto::Ack> {
9995 this.update(&mut cx, |lsp_store, cx| {
9996 let buffers =
9997 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9998 lsp_store.restart_language_servers_for_buffers(
9999 buffers,
10000 envelope
10001 .payload
10002 .only_servers
10003 .into_iter()
10004 .filter_map(|selector| {
10005 Some(match selector.selector? {
10006 proto::language_server_selector::Selector::ServerId(server_id) => {
10007 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10008 }
10009 proto::language_server_selector::Selector::Name(name) => {
10010 LanguageServerSelector::Name(LanguageServerName(
10011 SharedString::from(name),
10012 ))
10013 }
10014 })
10015 })
10016 .collect(),
10017 cx,
10018 );
10019 })?;
10020
10021 Ok(proto::Ack {})
10022 }
10023
10024 pub async fn handle_stop_language_servers(
10025 lsp_store: Entity<Self>,
10026 envelope: TypedEnvelope<proto::StopLanguageServers>,
10027 mut cx: AsyncApp,
10028 ) -> Result<proto::Ack> {
10029 lsp_store.update(&mut cx, |lsp_store, cx| {
10030 if envelope.payload.all
10031 && envelope.payload.also_servers.is_empty()
10032 && envelope.payload.buffer_ids.is_empty()
10033 {
10034 lsp_store.stop_all_language_servers(cx);
10035 } else {
10036 let buffers =
10037 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10038 lsp_store
10039 .stop_language_servers_for_buffers(
10040 buffers,
10041 envelope
10042 .payload
10043 .also_servers
10044 .into_iter()
10045 .filter_map(|selector| {
10046 Some(match selector.selector? {
10047 proto::language_server_selector::Selector::ServerId(
10048 server_id,
10049 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10050 server_id,
10051 )),
10052 proto::language_server_selector::Selector::Name(name) => {
10053 LanguageServerSelector::Name(LanguageServerName(
10054 SharedString::from(name),
10055 ))
10056 }
10057 })
10058 })
10059 .collect(),
10060 cx,
10061 )
10062 .detach_and_log_err(cx);
10063 }
10064 })?;
10065
10066 Ok(proto::Ack {})
10067 }
10068
10069 pub async fn handle_cancel_language_server_work(
10070 lsp_store: Entity<Self>,
10071 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10072 mut cx: AsyncApp,
10073 ) -> Result<proto::Ack> {
10074 lsp_store.update(&mut cx, |lsp_store, cx| {
10075 if let Some(work) = envelope.payload.work {
10076 match work {
10077 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10078 let buffers =
10079 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10080 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10081 }
10082 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10083 let server_id = LanguageServerId::from_proto(work.language_server_id);
10084 let token = work
10085 .token
10086 .map(|token| {
10087 ProgressToken::from_proto(token)
10088 .context("invalid work progress token")
10089 })
10090 .transpose()?;
10091 lsp_store.cancel_language_server_work(server_id, token, cx);
10092 }
10093 }
10094 }
10095 anyhow::Ok(())
10096 })??;
10097
10098 Ok(proto::Ack {})
10099 }
10100
10101 fn buffer_ids_to_buffers(
10102 &mut self,
10103 buffer_ids: impl Iterator<Item = u64>,
10104 cx: &mut Context<Self>,
10105 ) -> Vec<Entity<Buffer>> {
10106 buffer_ids
10107 .into_iter()
10108 .flat_map(|buffer_id| {
10109 self.buffer_store
10110 .read(cx)
10111 .get(BufferId::new(buffer_id).log_err()?)
10112 })
10113 .collect::<Vec<_>>()
10114 }
10115
10116 async fn handle_apply_additional_edits_for_completion(
10117 this: Entity<Self>,
10118 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10119 mut cx: AsyncApp,
10120 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10121 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10122 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10123 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10124 let completion = Self::deserialize_completion(
10125 envelope.payload.completion.context("invalid completion")?,
10126 )?;
10127 anyhow::Ok((buffer, completion))
10128 })??;
10129
10130 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10131 this.apply_additional_edits_for_completion(
10132 buffer,
10133 Rc::new(RefCell::new(Box::new([Completion {
10134 replace_range: completion.replace_range,
10135 new_text: completion.new_text,
10136 source: completion.source,
10137 documentation: None,
10138 label: CodeLabel::default(),
10139 insert_text_mode: None,
10140 icon_path: None,
10141 confirm: None,
10142 }]))),
10143 0,
10144 false,
10145 cx,
10146 )
10147 })?;
10148
10149 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10150 transaction: apply_additional_edits
10151 .await?
10152 .as_ref()
10153 .map(language::proto::serialize_transaction),
10154 })
10155 }
10156
10157 pub fn last_formatting_failure(&self) -> Option<&str> {
10158 self.last_formatting_failure.as_deref()
10159 }
10160
10161 pub fn reset_last_formatting_failure(&mut self) {
10162 self.last_formatting_failure = None;
10163 }
10164
10165 pub fn environment_for_buffer(
10166 &self,
10167 buffer: &Entity<Buffer>,
10168 cx: &mut Context<Self>,
10169 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10170 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10171 environment.update(cx, |env, cx| {
10172 env.buffer_environment(buffer, &self.worktree_store, cx)
10173 })
10174 } else {
10175 Task::ready(None).shared()
10176 }
10177 }
10178
10179 pub fn format(
10180 &mut self,
10181 buffers: HashSet<Entity<Buffer>>,
10182 target: LspFormatTarget,
10183 push_to_history: bool,
10184 trigger: FormatTrigger,
10185 cx: &mut Context<Self>,
10186 ) -> Task<anyhow::Result<ProjectTransaction>> {
10187 let logger = zlog::scoped!("format");
10188 if self.as_local().is_some() {
10189 zlog::trace!(logger => "Formatting locally");
10190 let logger = zlog::scoped!(logger => "local");
10191 let buffers = buffers
10192 .into_iter()
10193 .map(|buffer_handle| {
10194 let buffer = buffer_handle.read(cx);
10195 let buffer_abs_path = File::from_dyn(buffer.file())
10196 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10197
10198 (buffer_handle, buffer_abs_path, buffer.remote_id())
10199 })
10200 .collect::<Vec<_>>();
10201
10202 cx.spawn(async move |lsp_store, cx| {
10203 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10204
10205 for (handle, abs_path, id) in buffers {
10206 let env = lsp_store
10207 .update(cx, |lsp_store, cx| {
10208 lsp_store.environment_for_buffer(&handle, cx)
10209 })?
10210 .await;
10211
10212 let ranges = match &target {
10213 LspFormatTarget::Buffers => None,
10214 LspFormatTarget::Ranges(ranges) => {
10215 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10216 }
10217 };
10218
10219 formattable_buffers.push(FormattableBuffer {
10220 handle,
10221 abs_path,
10222 env,
10223 ranges,
10224 });
10225 }
10226 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10227
10228 let format_timer = zlog::time!(logger => "Formatting buffers");
10229 let result = LocalLspStore::format_locally(
10230 lsp_store.clone(),
10231 formattable_buffers,
10232 push_to_history,
10233 trigger,
10234 logger,
10235 cx,
10236 )
10237 .await;
10238 format_timer.end();
10239
10240 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10241
10242 lsp_store.update(cx, |lsp_store, _| {
10243 lsp_store.update_last_formatting_failure(&result);
10244 })?;
10245
10246 result
10247 })
10248 } else if let Some((client, project_id)) = self.upstream_client() {
10249 zlog::trace!(logger => "Formatting remotely");
10250 let logger = zlog::scoped!(logger => "remote");
10251 // Don't support formatting ranges via remote
10252 match target {
10253 LspFormatTarget::Buffers => {}
10254 LspFormatTarget::Ranges(_) => {
10255 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10256 return Task::ready(Ok(ProjectTransaction::default()));
10257 }
10258 }
10259
10260 let buffer_store = self.buffer_store();
10261 cx.spawn(async move |lsp_store, cx| {
10262 zlog::trace!(logger => "Sending remote format request");
10263 let request_timer = zlog::time!(logger => "remote format request");
10264 let result = client
10265 .request(proto::FormatBuffers {
10266 project_id,
10267 trigger: trigger as i32,
10268 buffer_ids: buffers
10269 .iter()
10270 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10271 .collect::<Result<_>>()?,
10272 })
10273 .await
10274 .and_then(|result| result.transaction.context("missing transaction"));
10275 request_timer.end();
10276
10277 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10278
10279 lsp_store.update(cx, |lsp_store, _| {
10280 lsp_store.update_last_formatting_failure(&result);
10281 })?;
10282
10283 let transaction_response = result?;
10284 let _timer = zlog::time!(logger => "deserializing project transaction");
10285 buffer_store
10286 .update(cx, |buffer_store, cx| {
10287 buffer_store.deserialize_project_transaction(
10288 transaction_response,
10289 push_to_history,
10290 cx,
10291 )
10292 })?
10293 .await
10294 })
10295 } else {
10296 zlog::trace!(logger => "Not formatting");
10297 Task::ready(Ok(ProjectTransaction::default()))
10298 }
10299 }
10300
10301 async fn handle_format_buffers(
10302 this: Entity<Self>,
10303 envelope: TypedEnvelope<proto::FormatBuffers>,
10304 mut cx: AsyncApp,
10305 ) -> Result<proto::FormatBuffersResponse> {
10306 let sender_id = envelope.original_sender_id().unwrap_or_default();
10307 let format = this.update(&mut cx, |this, cx| {
10308 let mut buffers = HashSet::default();
10309 for buffer_id in &envelope.payload.buffer_ids {
10310 let buffer_id = BufferId::new(*buffer_id)?;
10311 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10312 }
10313 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10314 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10315 })??;
10316
10317 let project_transaction = format.await?;
10318 let project_transaction = this.update(&mut cx, |this, cx| {
10319 this.buffer_store.update(cx, |buffer_store, cx| {
10320 buffer_store.serialize_project_transaction_for_peer(
10321 project_transaction,
10322 sender_id,
10323 cx,
10324 )
10325 })
10326 })?;
10327 Ok(proto::FormatBuffersResponse {
10328 transaction: Some(project_transaction),
10329 })
10330 }
10331
10332 async fn handle_apply_code_action_kind(
10333 this: Entity<Self>,
10334 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10335 mut cx: AsyncApp,
10336 ) -> Result<proto::ApplyCodeActionKindResponse> {
10337 let sender_id = envelope.original_sender_id().unwrap_or_default();
10338 let format = this.update(&mut cx, |this, cx| {
10339 let mut buffers = HashSet::default();
10340 for buffer_id in &envelope.payload.buffer_ids {
10341 let buffer_id = BufferId::new(*buffer_id)?;
10342 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10343 }
10344 let kind = match envelope.payload.kind.as_str() {
10345 "" => CodeActionKind::EMPTY,
10346 "quickfix" => CodeActionKind::QUICKFIX,
10347 "refactor" => CodeActionKind::REFACTOR,
10348 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10349 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10350 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10351 "source" => CodeActionKind::SOURCE,
10352 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10353 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10354 _ => anyhow::bail!(
10355 "Invalid code action kind {}",
10356 envelope.payload.kind.as_str()
10357 ),
10358 };
10359 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10360 })??;
10361
10362 let project_transaction = format.await?;
10363 let project_transaction = this.update(&mut cx, |this, cx| {
10364 this.buffer_store.update(cx, |buffer_store, cx| {
10365 buffer_store.serialize_project_transaction_for_peer(
10366 project_transaction,
10367 sender_id,
10368 cx,
10369 )
10370 })
10371 })?;
10372 Ok(proto::ApplyCodeActionKindResponse {
10373 transaction: Some(project_transaction),
10374 })
10375 }
10376
10377 async fn shutdown_language_server(
10378 server_state: Option<LanguageServerState>,
10379 name: LanguageServerName,
10380 cx: &mut AsyncApp,
10381 ) {
10382 let server = match server_state {
10383 Some(LanguageServerState::Starting { startup, .. }) => {
10384 let mut timer = cx
10385 .background_executor()
10386 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10387 .fuse();
10388
10389 select! {
10390 server = startup.fuse() => server,
10391 () = timer => {
10392 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10393 None
10394 },
10395 }
10396 }
10397
10398 Some(LanguageServerState::Running { server, .. }) => Some(server),
10399
10400 None => None,
10401 };
10402
10403 if let Some(server) = server
10404 && let Some(shutdown) = server.shutdown()
10405 {
10406 shutdown.await;
10407 }
10408 }
10409
10410 // Returns a list of all of the worktrees which no longer have a language server and the root path
10411 // for the stopped server
10412 fn stop_local_language_server(
10413 &mut self,
10414 server_id: LanguageServerId,
10415 cx: &mut Context<Self>,
10416 ) -> Task<()> {
10417 let local = match &mut self.mode {
10418 LspStoreMode::Local(local) => local,
10419 _ => {
10420 return Task::ready(());
10421 }
10422 };
10423
10424 // Remove this server ID from all entries in the given worktree.
10425 local
10426 .language_server_ids
10427 .retain(|_, state| state.id != server_id);
10428 self.buffer_store.update(cx, |buffer_store, cx| {
10429 for buffer in buffer_store.buffers() {
10430 buffer.update(cx, |buffer, cx| {
10431 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10432 buffer.set_completion_triggers(server_id, Default::default(), cx);
10433 });
10434 }
10435 });
10436
10437 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10438 summaries.retain(|path, summaries_by_server_id| {
10439 if summaries_by_server_id.remove(&server_id).is_some() {
10440 if let Some((client, project_id)) = self.downstream_client.clone() {
10441 client
10442 .send(proto::UpdateDiagnosticSummary {
10443 project_id,
10444 worktree_id: worktree_id.to_proto(),
10445 summary: Some(proto::DiagnosticSummary {
10446 path: path.as_ref().to_proto(),
10447 language_server_id: server_id.0 as u64,
10448 error_count: 0,
10449 warning_count: 0,
10450 }),
10451 more_summaries: Vec::new(),
10452 })
10453 .log_err();
10454 }
10455 !summaries_by_server_id.is_empty()
10456 } else {
10457 true
10458 }
10459 });
10460 }
10461
10462 let local = self.as_local_mut().unwrap();
10463 for diagnostics in local.diagnostics.values_mut() {
10464 diagnostics.retain(|_, diagnostics_by_server_id| {
10465 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10466 diagnostics_by_server_id.remove(ix);
10467 !diagnostics_by_server_id.is_empty()
10468 } else {
10469 true
10470 }
10471 });
10472 }
10473 local.language_server_watched_paths.remove(&server_id);
10474
10475 let server_state = local.language_servers.remove(&server_id);
10476 self.cleanup_lsp_data(server_id);
10477 let name = self
10478 .language_server_statuses
10479 .remove(&server_id)
10480 .map(|status| status.name)
10481 .or_else(|| {
10482 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10483 Some(adapter.name())
10484 } else {
10485 None
10486 }
10487 });
10488
10489 if let Some(name) = name {
10490 log::info!("stopping language server {name}");
10491 self.languages
10492 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10493 cx.notify();
10494
10495 return cx.spawn(async move |lsp_store, cx| {
10496 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10497 lsp_store
10498 .update(cx, |lsp_store, cx| {
10499 lsp_store
10500 .languages
10501 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10502 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10503 cx.notify();
10504 })
10505 .ok();
10506 });
10507 }
10508
10509 if server_state.is_some() {
10510 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10511 }
10512 Task::ready(())
10513 }
10514
10515 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10516 if let Some((client, project_id)) = self.upstream_client() {
10517 let request = client.request(proto::StopLanguageServers {
10518 project_id,
10519 buffer_ids: Vec::new(),
10520 also_servers: Vec::new(),
10521 all: true,
10522 });
10523 cx.background_spawn(request).detach_and_log_err(cx);
10524 } else {
10525 let Some(local) = self.as_local_mut() else {
10526 return;
10527 };
10528 let language_servers_to_stop = local
10529 .language_server_ids
10530 .values()
10531 .map(|state| state.id)
10532 .collect();
10533 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10534 let tasks = language_servers_to_stop
10535 .into_iter()
10536 .map(|server| self.stop_local_language_server(server, cx))
10537 .collect::<Vec<_>>();
10538 cx.background_spawn(async move {
10539 futures::future::join_all(tasks).await;
10540 })
10541 .detach();
10542 }
10543 }
10544
10545 pub fn restart_language_servers_for_buffers(
10546 &mut self,
10547 buffers: Vec<Entity<Buffer>>,
10548 only_restart_servers: HashSet<LanguageServerSelector>,
10549 cx: &mut Context<Self>,
10550 ) {
10551 if let Some((client, project_id)) = self.upstream_client() {
10552 let request = client.request(proto::RestartLanguageServers {
10553 project_id,
10554 buffer_ids: buffers
10555 .into_iter()
10556 .map(|b| b.read(cx).remote_id().to_proto())
10557 .collect(),
10558 only_servers: only_restart_servers
10559 .into_iter()
10560 .map(|selector| {
10561 let selector = match selector {
10562 LanguageServerSelector::Id(language_server_id) => {
10563 proto::language_server_selector::Selector::ServerId(
10564 language_server_id.to_proto(),
10565 )
10566 }
10567 LanguageServerSelector::Name(language_server_name) => {
10568 proto::language_server_selector::Selector::Name(
10569 language_server_name.to_string(),
10570 )
10571 }
10572 };
10573 proto::LanguageServerSelector {
10574 selector: Some(selector),
10575 }
10576 })
10577 .collect(),
10578 all: false,
10579 });
10580 cx.background_spawn(request).detach_and_log_err(cx);
10581 } else {
10582 let stop_task = if only_restart_servers.is_empty() {
10583 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10584 } else {
10585 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10586 };
10587 cx.spawn(async move |lsp_store, cx| {
10588 stop_task.await;
10589 lsp_store
10590 .update(cx, |lsp_store, cx| {
10591 for buffer in buffers {
10592 lsp_store.register_buffer_with_language_servers(
10593 &buffer,
10594 only_restart_servers.clone(),
10595 true,
10596 cx,
10597 );
10598 }
10599 })
10600 .ok()
10601 })
10602 .detach();
10603 }
10604 }
10605
10606 pub fn stop_language_servers_for_buffers(
10607 &mut self,
10608 buffers: Vec<Entity<Buffer>>,
10609 also_stop_servers: HashSet<LanguageServerSelector>,
10610 cx: &mut Context<Self>,
10611 ) -> Task<Result<()>> {
10612 if let Some((client, project_id)) = self.upstream_client() {
10613 let request = client.request(proto::StopLanguageServers {
10614 project_id,
10615 buffer_ids: buffers
10616 .into_iter()
10617 .map(|b| b.read(cx).remote_id().to_proto())
10618 .collect(),
10619 also_servers: also_stop_servers
10620 .into_iter()
10621 .map(|selector| {
10622 let selector = match selector {
10623 LanguageServerSelector::Id(language_server_id) => {
10624 proto::language_server_selector::Selector::ServerId(
10625 language_server_id.to_proto(),
10626 )
10627 }
10628 LanguageServerSelector::Name(language_server_name) => {
10629 proto::language_server_selector::Selector::Name(
10630 language_server_name.to_string(),
10631 )
10632 }
10633 };
10634 proto::LanguageServerSelector {
10635 selector: Some(selector),
10636 }
10637 })
10638 .collect(),
10639 all: false,
10640 });
10641 cx.background_spawn(async move {
10642 let _ = request.await?;
10643 Ok(())
10644 })
10645 } else {
10646 let task =
10647 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10648 cx.background_spawn(async move {
10649 task.await;
10650 Ok(())
10651 })
10652 }
10653 }
10654
10655 fn stop_local_language_servers_for_buffers(
10656 &mut self,
10657 buffers: &[Entity<Buffer>],
10658 also_stop_servers: HashSet<LanguageServerSelector>,
10659 cx: &mut Context<Self>,
10660 ) -> Task<()> {
10661 let Some(local) = self.as_local_mut() else {
10662 return Task::ready(());
10663 };
10664 let mut language_server_names_to_stop = BTreeSet::default();
10665 let mut language_servers_to_stop = also_stop_servers
10666 .into_iter()
10667 .flat_map(|selector| match selector {
10668 LanguageServerSelector::Id(id) => Some(id),
10669 LanguageServerSelector::Name(name) => {
10670 language_server_names_to_stop.insert(name);
10671 None
10672 }
10673 })
10674 .collect::<BTreeSet<_>>();
10675
10676 let mut covered_worktrees = HashSet::default();
10677 for buffer in buffers {
10678 buffer.update(cx, |buffer, cx| {
10679 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10680 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10681 && covered_worktrees.insert(worktree_id)
10682 {
10683 language_server_names_to_stop.retain(|name| {
10684 let old_ids_count = language_servers_to_stop.len();
10685 let all_language_servers_with_this_name = local
10686 .language_server_ids
10687 .iter()
10688 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10689 language_servers_to_stop.extend(all_language_servers_with_this_name);
10690 old_ids_count == language_servers_to_stop.len()
10691 });
10692 }
10693 });
10694 }
10695 for name in language_server_names_to_stop {
10696 language_servers_to_stop.extend(
10697 local
10698 .language_server_ids
10699 .iter()
10700 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10701 );
10702 }
10703
10704 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10705 let tasks = language_servers_to_stop
10706 .into_iter()
10707 .map(|server| self.stop_local_language_server(server, cx))
10708 .collect::<Vec<_>>();
10709
10710 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10711 }
10712
10713 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10714 let (worktree, relative_path) =
10715 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10716
10717 let project_path = ProjectPath {
10718 worktree_id: worktree.read(cx).id(),
10719 path: relative_path,
10720 };
10721
10722 Some(
10723 self.buffer_store()
10724 .read(cx)
10725 .get_by_path(&project_path)?
10726 .read(cx),
10727 )
10728 }
10729
10730 #[cfg(any(test, feature = "test-support"))]
10731 pub fn update_diagnostics(
10732 &mut self,
10733 server_id: LanguageServerId,
10734 diagnostics: lsp::PublishDiagnosticsParams,
10735 result_id: Option<String>,
10736 source_kind: DiagnosticSourceKind,
10737 disk_based_sources: &[String],
10738 cx: &mut Context<Self>,
10739 ) -> Result<()> {
10740 self.merge_lsp_diagnostics(
10741 source_kind,
10742 vec![DocumentDiagnosticsUpdate {
10743 diagnostics,
10744 result_id,
10745 server_id,
10746 disk_based_sources: Cow::Borrowed(disk_based_sources),
10747 }],
10748 |_, _, _| false,
10749 cx,
10750 )
10751 }
10752
10753 pub fn merge_lsp_diagnostics(
10754 &mut self,
10755 source_kind: DiagnosticSourceKind,
10756 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10757 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10758 cx: &mut Context<Self>,
10759 ) -> Result<()> {
10760 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10761 let updates = lsp_diagnostics
10762 .into_iter()
10763 .filter_map(|update| {
10764 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10765 Some(DocumentDiagnosticsUpdate {
10766 diagnostics: self.lsp_to_document_diagnostics(
10767 abs_path,
10768 source_kind,
10769 update.server_id,
10770 update.diagnostics,
10771 &update.disk_based_sources,
10772 ),
10773 result_id: update.result_id,
10774 server_id: update.server_id,
10775 disk_based_sources: update.disk_based_sources,
10776 })
10777 })
10778 .collect();
10779 self.merge_diagnostic_entries(updates, merge, cx)?;
10780 Ok(())
10781 }
10782
10783 fn lsp_to_document_diagnostics(
10784 &mut self,
10785 document_abs_path: PathBuf,
10786 source_kind: DiagnosticSourceKind,
10787 server_id: LanguageServerId,
10788 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10789 disk_based_sources: &[String],
10790 ) -> DocumentDiagnostics {
10791 let mut diagnostics = Vec::default();
10792 let mut primary_diagnostic_group_ids = HashMap::default();
10793 let mut sources_by_group_id = HashMap::default();
10794 let mut supporting_diagnostics = HashMap::default();
10795
10796 let adapter = self.language_server_adapter_for_id(server_id);
10797
10798 // Ensure that primary diagnostics are always the most severe
10799 lsp_diagnostics
10800 .diagnostics
10801 .sort_by_key(|item| item.severity);
10802
10803 for diagnostic in &lsp_diagnostics.diagnostics {
10804 let source = diagnostic.source.as_ref();
10805 let range = range_from_lsp(diagnostic.range);
10806 let is_supporting = diagnostic
10807 .related_information
10808 .as_ref()
10809 .is_some_and(|infos| {
10810 infos.iter().any(|info| {
10811 primary_diagnostic_group_ids.contains_key(&(
10812 source,
10813 diagnostic.code.clone(),
10814 range_from_lsp(info.location.range),
10815 ))
10816 })
10817 });
10818
10819 let is_unnecessary = diagnostic
10820 .tags
10821 .as_ref()
10822 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10823
10824 let underline = self
10825 .language_server_adapter_for_id(server_id)
10826 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10827
10828 if is_supporting {
10829 supporting_diagnostics.insert(
10830 (source, diagnostic.code.clone(), range),
10831 (diagnostic.severity, is_unnecessary),
10832 );
10833 } else {
10834 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10835 let is_disk_based =
10836 source.is_some_and(|source| disk_based_sources.contains(source));
10837
10838 sources_by_group_id.insert(group_id, source);
10839 primary_diagnostic_group_ids
10840 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10841
10842 diagnostics.push(DiagnosticEntry {
10843 range,
10844 diagnostic: Diagnostic {
10845 source: diagnostic.source.clone(),
10846 source_kind,
10847 code: diagnostic.code.clone(),
10848 code_description: diagnostic
10849 .code_description
10850 .as_ref()
10851 .and_then(|d| d.href.clone()),
10852 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10853 markdown: adapter.as_ref().and_then(|adapter| {
10854 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10855 }),
10856 message: diagnostic.message.trim().to_string(),
10857 group_id,
10858 is_primary: true,
10859 is_disk_based,
10860 is_unnecessary,
10861 underline,
10862 data: diagnostic.data.clone(),
10863 },
10864 });
10865 if let Some(infos) = &diagnostic.related_information {
10866 for info in infos {
10867 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10868 let range = range_from_lsp(info.location.range);
10869 diagnostics.push(DiagnosticEntry {
10870 range,
10871 diagnostic: Diagnostic {
10872 source: diagnostic.source.clone(),
10873 source_kind,
10874 code: diagnostic.code.clone(),
10875 code_description: diagnostic
10876 .code_description
10877 .as_ref()
10878 .and_then(|d| d.href.clone()),
10879 severity: DiagnosticSeverity::INFORMATION,
10880 markdown: adapter.as_ref().and_then(|adapter| {
10881 adapter.diagnostic_message_to_markdown(&info.message)
10882 }),
10883 message: info.message.trim().to_string(),
10884 group_id,
10885 is_primary: false,
10886 is_disk_based,
10887 is_unnecessary: false,
10888 underline,
10889 data: diagnostic.data.clone(),
10890 },
10891 });
10892 }
10893 }
10894 }
10895 }
10896 }
10897
10898 for entry in &mut diagnostics {
10899 let diagnostic = &mut entry.diagnostic;
10900 if !diagnostic.is_primary {
10901 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10902 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10903 source,
10904 diagnostic.code.clone(),
10905 entry.range.clone(),
10906 )) {
10907 if let Some(severity) = severity {
10908 diagnostic.severity = severity;
10909 }
10910 diagnostic.is_unnecessary = is_unnecessary;
10911 }
10912 }
10913 }
10914
10915 DocumentDiagnostics {
10916 diagnostics,
10917 document_abs_path,
10918 version: lsp_diagnostics.version,
10919 }
10920 }
10921
10922 fn insert_newly_running_language_server(
10923 &mut self,
10924 adapter: Arc<CachedLspAdapter>,
10925 language_server: Arc<LanguageServer>,
10926 server_id: LanguageServerId,
10927 key: LanguageServerSeed,
10928 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10929 cx: &mut Context<Self>,
10930 ) {
10931 let Some(local) = self.as_local_mut() else {
10932 return;
10933 };
10934 // If the language server for this key doesn't match the server id, don't store the
10935 // server. Which will cause it to be dropped, killing the process
10936 if local
10937 .language_server_ids
10938 .get(&key)
10939 .map(|state| state.id != server_id)
10940 .unwrap_or(false)
10941 {
10942 return;
10943 }
10944
10945 // Update language_servers collection with Running variant of LanguageServerState
10946 // indicating that the server is up and running and ready
10947 let workspace_folders = workspace_folders.lock().clone();
10948 language_server.set_workspace_folders(workspace_folders);
10949
10950 let workspace_diagnostics_refresh_tasks = language_server
10951 .capabilities()
10952 .diagnostic_provider
10953 .and_then(|provider| {
10954 local
10955 .language_server_dynamic_registrations
10956 .entry(server_id)
10957 .or_default()
10958 .diagnostics
10959 .entry(None)
10960 .or_insert(provider.clone());
10961 let workspace_refresher =
10962 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10963
10964 Some((None, workspace_refresher))
10965 })
10966 .into_iter()
10967 .collect();
10968 local.language_servers.insert(
10969 server_id,
10970 LanguageServerState::Running {
10971 workspace_diagnostics_refresh_tasks,
10972 adapter: adapter.clone(),
10973 server: language_server.clone(),
10974 simulate_disk_based_diagnostics_completion: None,
10975 },
10976 );
10977 local
10978 .languages
10979 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10980 if let Some(file_ops_caps) = language_server
10981 .capabilities()
10982 .workspace
10983 .as_ref()
10984 .and_then(|ws| ws.file_operations.as_ref())
10985 {
10986 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10987 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10988 if did_rename_caps.or(will_rename_caps).is_some() {
10989 let watcher = RenamePathsWatchedForServer::default()
10990 .with_did_rename_patterns(did_rename_caps)
10991 .with_will_rename_patterns(will_rename_caps);
10992 local
10993 .language_server_paths_watched_for_rename
10994 .insert(server_id, watcher);
10995 }
10996 }
10997
10998 self.language_server_statuses.insert(
10999 server_id,
11000 LanguageServerStatus {
11001 name: language_server.name(),
11002 pending_work: Default::default(),
11003 has_pending_diagnostic_updates: false,
11004 progress_tokens: Default::default(),
11005 worktree: Some(key.worktree_id),
11006 },
11007 );
11008
11009 cx.emit(LspStoreEvent::LanguageServerAdded(
11010 server_id,
11011 language_server.name(),
11012 Some(key.worktree_id),
11013 ));
11014
11015 let server_capabilities = language_server.capabilities();
11016 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11017 downstream_client
11018 .send(proto::StartLanguageServer {
11019 project_id: *project_id,
11020 server: Some(proto::LanguageServer {
11021 id: server_id.to_proto(),
11022 name: language_server.name().to_string(),
11023 worktree_id: Some(key.worktree_id.to_proto()),
11024 }),
11025 capabilities: serde_json::to_string(&server_capabilities)
11026 .expect("serializing server LSP capabilities"),
11027 })
11028 .log_err();
11029 }
11030 self.lsp_server_capabilities
11031 .insert(server_id, server_capabilities);
11032
11033 // Tell the language server about every open buffer in the worktree that matches the language.
11034 // Also check for buffers in worktrees that reused this server
11035 let mut worktrees_using_server = vec![key.worktree_id];
11036 if let Some(local) = self.as_local() {
11037 // Find all worktrees that have this server in their language server tree
11038 for (worktree_id, servers) in &local.lsp_tree.instances {
11039 if *worktree_id != key.worktree_id {
11040 for server_map in servers.roots.values() {
11041 if server_map
11042 .values()
11043 .any(|(node, _)| node.id() == Some(server_id))
11044 {
11045 worktrees_using_server.push(*worktree_id);
11046 }
11047 }
11048 }
11049 }
11050 }
11051
11052 let mut buffer_paths_registered = Vec::new();
11053 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11054 let mut lsp_adapters = HashMap::default();
11055 for buffer_handle in buffer_store.buffers() {
11056 let buffer = buffer_handle.read(cx);
11057 let file = match File::from_dyn(buffer.file()) {
11058 Some(file) => file,
11059 None => continue,
11060 };
11061 let language = match buffer.language() {
11062 Some(language) => language,
11063 None => continue,
11064 };
11065
11066 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11067 || !lsp_adapters
11068 .entry(language.name())
11069 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11070 .iter()
11071 .any(|a| a.name == key.name)
11072 {
11073 continue;
11074 }
11075 // didOpen
11076 let file = match file.as_local() {
11077 Some(file) => file,
11078 None => continue,
11079 };
11080
11081 let local = self.as_local_mut().unwrap();
11082
11083 let buffer_id = buffer.remote_id();
11084 if local.registered_buffers.contains_key(&buffer_id) {
11085 let versions = local
11086 .buffer_snapshots
11087 .entry(buffer_id)
11088 .or_default()
11089 .entry(server_id)
11090 .and_modify(|_| {
11091 assert!(
11092 false,
11093 "There should not be an existing snapshot for a newly inserted buffer"
11094 )
11095 })
11096 .or_insert_with(|| {
11097 vec![LspBufferSnapshot {
11098 version: 0,
11099 snapshot: buffer.text_snapshot(),
11100 }]
11101 });
11102
11103 let snapshot = versions.last().unwrap();
11104 let version = snapshot.version;
11105 let initial_snapshot = &snapshot.snapshot;
11106 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11107 language_server.register_buffer(
11108 uri,
11109 adapter.language_id(&language.name()),
11110 version,
11111 initial_snapshot.text(),
11112 );
11113 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11114 local
11115 .buffers_opened_in_servers
11116 .entry(buffer_id)
11117 .or_default()
11118 .insert(server_id);
11119 }
11120 buffer_handle.update(cx, |buffer, cx| {
11121 buffer.set_completion_triggers(
11122 server_id,
11123 language_server
11124 .capabilities()
11125 .completion_provider
11126 .as_ref()
11127 .and_then(|provider| {
11128 provider
11129 .trigger_characters
11130 .as_ref()
11131 .map(|characters| characters.iter().cloned().collect())
11132 })
11133 .unwrap_or_default(),
11134 cx,
11135 )
11136 });
11137 }
11138 });
11139
11140 for (buffer_id, abs_path) in buffer_paths_registered {
11141 cx.emit(LspStoreEvent::LanguageServerUpdate {
11142 language_server_id: server_id,
11143 name: Some(adapter.name()),
11144 message: proto::update_language_server::Variant::RegisteredForBuffer(
11145 proto::RegisteredForBuffer {
11146 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11147 buffer_id: buffer_id.to_proto(),
11148 },
11149 ),
11150 });
11151 }
11152
11153 cx.notify();
11154 }
11155
11156 pub fn language_servers_running_disk_based_diagnostics(
11157 &self,
11158 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11159 self.language_server_statuses
11160 .iter()
11161 .filter_map(|(id, status)| {
11162 if status.has_pending_diagnostic_updates {
11163 Some(*id)
11164 } else {
11165 None
11166 }
11167 })
11168 }
11169
11170 pub(crate) fn cancel_language_server_work_for_buffers(
11171 &mut self,
11172 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11173 cx: &mut Context<Self>,
11174 ) {
11175 if let Some((client, project_id)) = self.upstream_client() {
11176 let request = client.request(proto::CancelLanguageServerWork {
11177 project_id,
11178 work: Some(proto::cancel_language_server_work::Work::Buffers(
11179 proto::cancel_language_server_work::Buffers {
11180 buffer_ids: buffers
11181 .into_iter()
11182 .map(|b| b.read(cx).remote_id().to_proto())
11183 .collect(),
11184 },
11185 )),
11186 });
11187 cx.background_spawn(request).detach_and_log_err(cx);
11188 } else if let Some(local) = self.as_local() {
11189 let servers = buffers
11190 .into_iter()
11191 .flat_map(|buffer| {
11192 buffer.update(cx, |buffer, cx| {
11193 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11194 })
11195 })
11196 .collect::<HashSet<_>>();
11197 for server_id in servers {
11198 self.cancel_language_server_work(server_id, None, cx);
11199 }
11200 }
11201 }
11202
11203 pub(crate) fn cancel_language_server_work(
11204 &mut self,
11205 server_id: LanguageServerId,
11206 token_to_cancel: Option<ProgressToken>,
11207 cx: &mut Context<Self>,
11208 ) {
11209 if let Some(local) = self.as_local() {
11210 let status = self.language_server_statuses.get(&server_id);
11211 let server = local.language_servers.get(&server_id);
11212 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11213 {
11214 for (token, progress) in &status.pending_work {
11215 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11216 && token != token_to_cancel
11217 {
11218 continue;
11219 }
11220 if progress.is_cancellable {
11221 server
11222 .notify::<lsp::notification::WorkDoneProgressCancel>(
11223 WorkDoneProgressCancelParams {
11224 token: token.to_lsp(),
11225 },
11226 )
11227 .ok();
11228 }
11229 }
11230 }
11231 } else if let Some((client, project_id)) = self.upstream_client() {
11232 let request = client.request(proto::CancelLanguageServerWork {
11233 project_id,
11234 work: Some(
11235 proto::cancel_language_server_work::Work::LanguageServerWork(
11236 proto::cancel_language_server_work::LanguageServerWork {
11237 language_server_id: server_id.to_proto(),
11238 token: token_to_cancel.map(|token| token.to_proto()),
11239 },
11240 ),
11241 ),
11242 });
11243 cx.background_spawn(request).detach_and_log_err(cx);
11244 }
11245 }
11246
11247 fn register_supplementary_language_server(
11248 &mut self,
11249 id: LanguageServerId,
11250 name: LanguageServerName,
11251 server: Arc<LanguageServer>,
11252 cx: &mut Context<Self>,
11253 ) {
11254 if let Some(local) = self.as_local_mut() {
11255 local
11256 .supplementary_language_servers
11257 .insert(id, (name.clone(), server));
11258 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11259 }
11260 }
11261
11262 fn unregister_supplementary_language_server(
11263 &mut self,
11264 id: LanguageServerId,
11265 cx: &mut Context<Self>,
11266 ) {
11267 if let Some(local) = self.as_local_mut() {
11268 local.supplementary_language_servers.remove(&id);
11269 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11270 }
11271 }
11272
11273 pub(crate) fn supplementary_language_servers(
11274 &self,
11275 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11276 self.as_local().into_iter().flat_map(|local| {
11277 local
11278 .supplementary_language_servers
11279 .iter()
11280 .map(|(id, (name, _))| (*id, name.clone()))
11281 })
11282 }
11283
11284 pub fn language_server_adapter_for_id(
11285 &self,
11286 id: LanguageServerId,
11287 ) -> Option<Arc<CachedLspAdapter>> {
11288 self.as_local()
11289 .and_then(|local| local.language_servers.get(&id))
11290 .and_then(|language_server_state| match language_server_state {
11291 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11292 _ => None,
11293 })
11294 }
11295
11296 pub(super) fn update_local_worktree_language_servers(
11297 &mut self,
11298 worktree_handle: &Entity<Worktree>,
11299 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11300 cx: &mut Context<Self>,
11301 ) {
11302 if changes.is_empty() {
11303 return;
11304 }
11305
11306 let Some(local) = self.as_local() else { return };
11307
11308 local.prettier_store.update(cx, |prettier_store, cx| {
11309 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11310 });
11311
11312 let worktree_id = worktree_handle.read(cx).id();
11313 let mut language_server_ids = local
11314 .language_server_ids
11315 .iter()
11316 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11317 .collect::<Vec<_>>();
11318 language_server_ids.sort();
11319 language_server_ids.dedup();
11320
11321 // let abs_path = worktree_handle.read(cx).abs_path();
11322 for server_id in &language_server_ids {
11323 if let Some(LanguageServerState::Running { server, .. }) =
11324 local.language_servers.get(server_id)
11325 && let Some(watched_paths) = local
11326 .language_server_watched_paths
11327 .get(server_id)
11328 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11329 {
11330 let params = lsp::DidChangeWatchedFilesParams {
11331 changes: changes
11332 .iter()
11333 .filter_map(|(path, _, change)| {
11334 if !watched_paths.is_match(path.as_std_path()) {
11335 return None;
11336 }
11337 let typ = match change {
11338 PathChange::Loaded => return None,
11339 PathChange::Added => lsp::FileChangeType::CREATED,
11340 PathChange::Removed => lsp::FileChangeType::DELETED,
11341 PathChange::Updated => lsp::FileChangeType::CHANGED,
11342 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11343 };
11344 let uri = lsp::Uri::from_file_path(
11345 worktree_handle.read(cx).absolutize(&path),
11346 )
11347 .ok()?;
11348 Some(lsp::FileEvent { uri, typ })
11349 })
11350 .collect(),
11351 };
11352 if !params.changes.is_empty() {
11353 server
11354 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11355 .ok();
11356 }
11357 }
11358 }
11359 for (path, _, _) in changes {
11360 if let Some(file_name) = path.file_name()
11361 && local.watched_manifest_filenames.contains(file_name)
11362 {
11363 self.request_workspace_config_refresh();
11364 break;
11365 }
11366 }
11367 }
11368
11369 pub fn wait_for_remote_buffer(
11370 &mut self,
11371 id: BufferId,
11372 cx: &mut Context<Self>,
11373 ) -> Task<Result<Entity<Buffer>>> {
11374 self.buffer_store.update(cx, |buffer_store, cx| {
11375 buffer_store.wait_for_remote_buffer(id, cx)
11376 })
11377 }
11378
11379 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11380 let mut result = proto::Symbol {
11381 language_server_name: symbol.language_server_name.0.to_string(),
11382 source_worktree_id: symbol.source_worktree_id.to_proto(),
11383 language_server_id: symbol.source_language_server_id.to_proto(),
11384 name: symbol.name.clone(),
11385 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11386 start: Some(proto::PointUtf16 {
11387 row: symbol.range.start.0.row,
11388 column: symbol.range.start.0.column,
11389 }),
11390 end: Some(proto::PointUtf16 {
11391 row: symbol.range.end.0.row,
11392 column: symbol.range.end.0.column,
11393 }),
11394 worktree_id: Default::default(),
11395 path: Default::default(),
11396 signature: Default::default(),
11397 };
11398 match &symbol.path {
11399 SymbolLocation::InProject(path) => {
11400 result.worktree_id = path.worktree_id.to_proto();
11401 result.path = path.path.to_proto();
11402 }
11403 SymbolLocation::OutsideProject {
11404 abs_path,
11405 signature,
11406 } => {
11407 result.path = abs_path.to_string_lossy().into_owned();
11408 result.signature = signature.to_vec();
11409 }
11410 }
11411 result
11412 }
11413
11414 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11415 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11416 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11417 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11418
11419 let path = if serialized_symbol.signature.is_empty() {
11420 SymbolLocation::InProject(ProjectPath {
11421 worktree_id,
11422 path: RelPath::from_proto(&serialized_symbol.path)
11423 .context("invalid symbol path")?,
11424 })
11425 } else {
11426 SymbolLocation::OutsideProject {
11427 abs_path: Path::new(&serialized_symbol.path).into(),
11428 signature: serialized_symbol
11429 .signature
11430 .try_into()
11431 .map_err(|_| anyhow!("invalid signature"))?,
11432 }
11433 };
11434
11435 let start = serialized_symbol.start.context("invalid start")?;
11436 let end = serialized_symbol.end.context("invalid end")?;
11437 Ok(CoreSymbol {
11438 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11439 source_worktree_id,
11440 source_language_server_id: LanguageServerId::from_proto(
11441 serialized_symbol.language_server_id,
11442 ),
11443 path,
11444 name: serialized_symbol.name,
11445 range: Unclipped(PointUtf16::new(start.row, start.column))
11446 ..Unclipped(PointUtf16::new(end.row, end.column)),
11447 kind,
11448 })
11449 }
11450
11451 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11452 let mut serialized_completion = proto::Completion {
11453 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11454 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11455 new_text: completion.new_text.clone(),
11456 ..proto::Completion::default()
11457 };
11458 match &completion.source {
11459 CompletionSource::Lsp {
11460 insert_range,
11461 server_id,
11462 lsp_completion,
11463 lsp_defaults,
11464 resolved,
11465 } => {
11466 let (old_insert_start, old_insert_end) = insert_range
11467 .as_ref()
11468 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11469 .unzip();
11470
11471 serialized_completion.old_insert_start = old_insert_start;
11472 serialized_completion.old_insert_end = old_insert_end;
11473 serialized_completion.source = proto::completion::Source::Lsp as i32;
11474 serialized_completion.server_id = server_id.0 as u64;
11475 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11476 serialized_completion.lsp_defaults = lsp_defaults
11477 .as_deref()
11478 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11479 serialized_completion.resolved = *resolved;
11480 }
11481 CompletionSource::BufferWord {
11482 word_range,
11483 resolved,
11484 } => {
11485 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11486 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11487 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11488 serialized_completion.resolved = *resolved;
11489 }
11490 CompletionSource::Custom => {
11491 serialized_completion.source = proto::completion::Source::Custom as i32;
11492 serialized_completion.resolved = true;
11493 }
11494 CompletionSource::Dap { sort_text } => {
11495 serialized_completion.source = proto::completion::Source::Dap as i32;
11496 serialized_completion.sort_text = Some(sort_text.clone());
11497 }
11498 }
11499
11500 serialized_completion
11501 }
11502
11503 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11504 let old_replace_start = completion
11505 .old_replace_start
11506 .and_then(deserialize_anchor)
11507 .context("invalid old start")?;
11508 let old_replace_end = completion
11509 .old_replace_end
11510 .and_then(deserialize_anchor)
11511 .context("invalid old end")?;
11512 let insert_range = {
11513 match completion.old_insert_start.zip(completion.old_insert_end) {
11514 Some((start, end)) => {
11515 let start = deserialize_anchor(start).context("invalid insert old start")?;
11516 let end = deserialize_anchor(end).context("invalid insert old end")?;
11517 Some(start..end)
11518 }
11519 None => None,
11520 }
11521 };
11522 Ok(CoreCompletion {
11523 replace_range: old_replace_start..old_replace_end,
11524 new_text: completion.new_text,
11525 source: match proto::completion::Source::from_i32(completion.source) {
11526 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11527 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11528 insert_range,
11529 server_id: LanguageServerId::from_proto(completion.server_id),
11530 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11531 lsp_defaults: completion
11532 .lsp_defaults
11533 .as_deref()
11534 .map(serde_json::from_slice)
11535 .transpose()?,
11536 resolved: completion.resolved,
11537 },
11538 Some(proto::completion::Source::BufferWord) => {
11539 let word_range = completion
11540 .buffer_word_start
11541 .and_then(deserialize_anchor)
11542 .context("invalid buffer word start")?
11543 ..completion
11544 .buffer_word_end
11545 .and_then(deserialize_anchor)
11546 .context("invalid buffer word end")?;
11547 CompletionSource::BufferWord {
11548 word_range,
11549 resolved: completion.resolved,
11550 }
11551 }
11552 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11553 sort_text: completion
11554 .sort_text
11555 .context("expected sort text to exist")?,
11556 },
11557 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11558 },
11559 })
11560 }
11561
11562 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11563 let (kind, lsp_action) = match &action.lsp_action {
11564 LspAction::Action(code_action) => (
11565 proto::code_action::Kind::Action as i32,
11566 serde_json::to_vec(code_action).unwrap(),
11567 ),
11568 LspAction::Command(command) => (
11569 proto::code_action::Kind::Command as i32,
11570 serde_json::to_vec(command).unwrap(),
11571 ),
11572 LspAction::CodeLens(code_lens) => (
11573 proto::code_action::Kind::CodeLens as i32,
11574 serde_json::to_vec(code_lens).unwrap(),
11575 ),
11576 };
11577
11578 proto::CodeAction {
11579 server_id: action.server_id.0 as u64,
11580 start: Some(serialize_anchor(&action.range.start)),
11581 end: Some(serialize_anchor(&action.range.end)),
11582 lsp_action,
11583 kind,
11584 resolved: action.resolved,
11585 }
11586 }
11587
11588 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11589 let start = action
11590 .start
11591 .and_then(deserialize_anchor)
11592 .context("invalid start")?;
11593 let end = action
11594 .end
11595 .and_then(deserialize_anchor)
11596 .context("invalid end")?;
11597 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11598 Some(proto::code_action::Kind::Action) => {
11599 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11600 }
11601 Some(proto::code_action::Kind::Command) => {
11602 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11603 }
11604 Some(proto::code_action::Kind::CodeLens) => {
11605 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11606 }
11607 None => anyhow::bail!("Unknown action kind {}", action.kind),
11608 };
11609 Ok(CodeAction {
11610 server_id: LanguageServerId(action.server_id as usize),
11611 range: start..end,
11612 resolved: action.resolved,
11613 lsp_action,
11614 })
11615 }
11616
11617 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11618 match &formatting_result {
11619 Ok(_) => self.last_formatting_failure = None,
11620 Err(error) => {
11621 let error_string = format!("{error:#}");
11622 log::error!("Formatting failed: {error_string}");
11623 self.last_formatting_failure
11624 .replace(error_string.lines().join(" "));
11625 }
11626 }
11627 }
11628
11629 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11630 self.lsp_server_capabilities.remove(&for_server);
11631 for lsp_data in self.lsp_data.values_mut() {
11632 lsp_data.remove_server_data(for_server);
11633 }
11634 if let Some(local) = self.as_local_mut() {
11635 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11636 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11637 buffer_servers.remove(&for_server);
11638 }
11639 }
11640 }
11641
11642 pub fn result_id(
11643 &self,
11644 server_id: LanguageServerId,
11645 buffer_id: BufferId,
11646 cx: &App,
11647 ) -> Option<String> {
11648 let abs_path = self
11649 .buffer_store
11650 .read(cx)
11651 .get(buffer_id)
11652 .and_then(|b| File::from_dyn(b.read(cx).file()))
11653 .map(|f| f.abs_path(cx))?;
11654 self.as_local()?
11655 .buffer_pull_diagnostics_result_ids
11656 .get(&server_id)?
11657 .get(&abs_path)?
11658 .clone()
11659 }
11660
11661 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11662 let Some(local) = self.as_local() else {
11663 return HashMap::default();
11664 };
11665 local
11666 .buffer_pull_diagnostics_result_ids
11667 .get(&server_id)
11668 .into_iter()
11669 .flatten()
11670 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11671 .collect()
11672 }
11673
11674 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11675 if let Some(LanguageServerState::Running {
11676 workspace_diagnostics_refresh_tasks,
11677 ..
11678 }) = self
11679 .as_local_mut()
11680 .and_then(|local| local.language_servers.get_mut(&server_id))
11681 {
11682 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11683 diagnostics.refresh_tx.try_send(()).ok();
11684 }
11685 }
11686 }
11687
11688 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11689 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11690 return;
11691 };
11692 let Some(local) = self.as_local_mut() else {
11693 return;
11694 };
11695
11696 for server_id in buffer.update(cx, |buffer, cx| {
11697 local.language_server_ids_for_buffer(buffer, cx)
11698 }) {
11699 if let Some(LanguageServerState::Running {
11700 workspace_diagnostics_refresh_tasks,
11701 ..
11702 }) = local.language_servers.get_mut(&server_id)
11703 {
11704 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11705 diagnostics.refresh_tx.try_send(()).ok();
11706 }
11707 }
11708 }
11709 }
11710
11711 fn apply_workspace_diagnostic_report(
11712 &mut self,
11713 server_id: LanguageServerId,
11714 report: lsp::WorkspaceDiagnosticReportResult,
11715 cx: &mut Context<Self>,
11716 ) {
11717 let workspace_diagnostics =
11718 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11719 let mut unchanged_buffers = HashSet::default();
11720 let mut changed_buffers = HashSet::default();
11721 let workspace_diagnostics_updates = workspace_diagnostics
11722 .into_iter()
11723 .filter_map(
11724 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11725 LspPullDiagnostics::Response {
11726 server_id,
11727 uri,
11728 diagnostics,
11729 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11730 LspPullDiagnostics::Default => None,
11731 },
11732 )
11733 .fold(
11734 HashMap::default(),
11735 |mut acc, (server_id, uri, diagnostics, version)| {
11736 let (result_id, diagnostics) = match diagnostics {
11737 PulledDiagnostics::Unchanged { result_id } => {
11738 unchanged_buffers.insert(uri.clone());
11739 (Some(result_id), Vec::new())
11740 }
11741 PulledDiagnostics::Changed {
11742 result_id,
11743 diagnostics,
11744 } => {
11745 changed_buffers.insert(uri.clone());
11746 (result_id, diagnostics)
11747 }
11748 };
11749 let disk_based_sources = Cow::Owned(
11750 self.language_server_adapter_for_id(server_id)
11751 .as_ref()
11752 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11753 .unwrap_or(&[])
11754 .to_vec(),
11755 );
11756 acc.entry(server_id)
11757 .or_insert_with(Vec::new)
11758 .push(DocumentDiagnosticsUpdate {
11759 server_id,
11760 diagnostics: lsp::PublishDiagnosticsParams {
11761 uri,
11762 diagnostics,
11763 version,
11764 },
11765 result_id,
11766 disk_based_sources,
11767 });
11768 acc
11769 },
11770 );
11771
11772 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11773 self.merge_lsp_diagnostics(
11774 DiagnosticSourceKind::Pulled,
11775 diagnostic_updates,
11776 |buffer, old_diagnostic, cx| {
11777 File::from_dyn(buffer.file())
11778 .and_then(|file| {
11779 let abs_path = file.as_local()?.abs_path(cx);
11780 lsp::Uri::from_file_path(abs_path).ok()
11781 })
11782 .is_none_or(|buffer_uri| {
11783 unchanged_buffers.contains(&buffer_uri)
11784 || match old_diagnostic.source_kind {
11785 DiagnosticSourceKind::Pulled => {
11786 !changed_buffers.contains(&buffer_uri)
11787 }
11788 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11789 true
11790 }
11791 }
11792 })
11793 },
11794 cx,
11795 )
11796 .log_err();
11797 }
11798 }
11799
11800 fn register_server_capabilities(
11801 &mut self,
11802 server_id: LanguageServerId,
11803 params: lsp::RegistrationParams,
11804 cx: &mut Context<Self>,
11805 ) -> anyhow::Result<()> {
11806 let server = self
11807 .language_server_for_id(server_id)
11808 .with_context(|| format!("no server {server_id} found"))?;
11809 for reg in params.registrations {
11810 match reg.method.as_str() {
11811 "workspace/didChangeWatchedFiles" => {
11812 if let Some(options) = reg.register_options {
11813 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11814 let caps = serde_json::from_value(options)?;
11815 local_lsp_store
11816 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11817 true
11818 } else {
11819 false
11820 };
11821 if notify {
11822 notify_server_capabilities_updated(&server, cx);
11823 }
11824 }
11825 }
11826 "workspace/didChangeConfiguration" => {
11827 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11828 }
11829 "workspace/didChangeWorkspaceFolders" => {
11830 // In this case register options is an empty object, we can ignore it
11831 let caps = lsp::WorkspaceFoldersServerCapabilities {
11832 supported: Some(true),
11833 change_notifications: Some(OneOf::Right(reg.id)),
11834 };
11835 server.update_capabilities(|capabilities| {
11836 capabilities
11837 .workspace
11838 .get_or_insert_default()
11839 .workspace_folders = Some(caps);
11840 });
11841 notify_server_capabilities_updated(&server, cx);
11842 }
11843 "workspace/symbol" => {
11844 let options = parse_register_capabilities(reg)?;
11845 server.update_capabilities(|capabilities| {
11846 capabilities.workspace_symbol_provider = Some(options);
11847 });
11848 notify_server_capabilities_updated(&server, cx);
11849 }
11850 "workspace/fileOperations" => {
11851 if let Some(options) = reg.register_options {
11852 let caps = serde_json::from_value(options)?;
11853 server.update_capabilities(|capabilities| {
11854 capabilities
11855 .workspace
11856 .get_or_insert_default()
11857 .file_operations = Some(caps);
11858 });
11859 notify_server_capabilities_updated(&server, cx);
11860 }
11861 }
11862 "workspace/executeCommand" => {
11863 if let Some(options) = reg.register_options {
11864 let options = serde_json::from_value(options)?;
11865 server.update_capabilities(|capabilities| {
11866 capabilities.execute_command_provider = Some(options);
11867 });
11868 notify_server_capabilities_updated(&server, cx);
11869 }
11870 }
11871 "textDocument/rangeFormatting" => {
11872 let options = parse_register_capabilities(reg)?;
11873 server.update_capabilities(|capabilities| {
11874 capabilities.document_range_formatting_provider = Some(options);
11875 });
11876 notify_server_capabilities_updated(&server, cx);
11877 }
11878 "textDocument/onTypeFormatting" => {
11879 if let Some(options) = reg
11880 .register_options
11881 .map(serde_json::from_value)
11882 .transpose()?
11883 {
11884 server.update_capabilities(|capabilities| {
11885 capabilities.document_on_type_formatting_provider = Some(options);
11886 });
11887 notify_server_capabilities_updated(&server, cx);
11888 }
11889 }
11890 "textDocument/formatting" => {
11891 let options = parse_register_capabilities(reg)?;
11892 server.update_capabilities(|capabilities| {
11893 capabilities.document_formatting_provider = Some(options);
11894 });
11895 notify_server_capabilities_updated(&server, cx);
11896 }
11897 "textDocument/rename" => {
11898 let options = parse_register_capabilities(reg)?;
11899 server.update_capabilities(|capabilities| {
11900 capabilities.rename_provider = Some(options);
11901 });
11902 notify_server_capabilities_updated(&server, cx);
11903 }
11904 "textDocument/inlayHint" => {
11905 let options = parse_register_capabilities(reg)?;
11906 server.update_capabilities(|capabilities| {
11907 capabilities.inlay_hint_provider = Some(options);
11908 });
11909 notify_server_capabilities_updated(&server, cx);
11910 }
11911 "textDocument/documentSymbol" => {
11912 let options = parse_register_capabilities(reg)?;
11913 server.update_capabilities(|capabilities| {
11914 capabilities.document_symbol_provider = Some(options);
11915 });
11916 notify_server_capabilities_updated(&server, cx);
11917 }
11918 "textDocument/codeAction" => {
11919 let options = parse_register_capabilities(reg)?;
11920 let provider = match options {
11921 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11922 OneOf::Right(caps) => caps,
11923 };
11924 server.update_capabilities(|capabilities| {
11925 capabilities.code_action_provider = Some(provider);
11926 });
11927 notify_server_capabilities_updated(&server, cx);
11928 }
11929 "textDocument/definition" => {
11930 let options = parse_register_capabilities(reg)?;
11931 server.update_capabilities(|capabilities| {
11932 capabilities.definition_provider = Some(options);
11933 });
11934 notify_server_capabilities_updated(&server, cx);
11935 }
11936 "textDocument/completion" => {
11937 if let Some(caps) = reg
11938 .register_options
11939 .map(serde_json::from_value::<CompletionOptions>)
11940 .transpose()?
11941 {
11942 server.update_capabilities(|capabilities| {
11943 capabilities.completion_provider = Some(caps.clone());
11944 });
11945
11946 if let Some(local) = self.as_local() {
11947 let mut buffers_with_language_server = Vec::new();
11948 for handle in self.buffer_store.read(cx).buffers() {
11949 let buffer_id = handle.read(cx).remote_id();
11950 if local
11951 .buffers_opened_in_servers
11952 .get(&buffer_id)
11953 .filter(|s| s.contains(&server_id))
11954 .is_some()
11955 {
11956 buffers_with_language_server.push(handle);
11957 }
11958 }
11959 let triggers = caps
11960 .trigger_characters
11961 .unwrap_or_default()
11962 .into_iter()
11963 .collect::<BTreeSet<_>>();
11964 for handle in buffers_with_language_server {
11965 let triggers = triggers.clone();
11966 let _ = handle.update(cx, move |buffer, cx| {
11967 buffer.set_completion_triggers(server_id, triggers, cx);
11968 });
11969 }
11970 }
11971 notify_server_capabilities_updated(&server, cx);
11972 }
11973 }
11974 "textDocument/hover" => {
11975 let options = parse_register_capabilities(reg)?;
11976 let provider = match options {
11977 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11978 OneOf::Right(caps) => caps,
11979 };
11980 server.update_capabilities(|capabilities| {
11981 capabilities.hover_provider = Some(provider);
11982 });
11983 notify_server_capabilities_updated(&server, cx);
11984 }
11985 "textDocument/signatureHelp" => {
11986 if let Some(caps) = reg
11987 .register_options
11988 .map(serde_json::from_value)
11989 .transpose()?
11990 {
11991 server.update_capabilities(|capabilities| {
11992 capabilities.signature_help_provider = Some(caps);
11993 });
11994 notify_server_capabilities_updated(&server, cx);
11995 }
11996 }
11997 "textDocument/didChange" => {
11998 if let Some(sync_kind) = reg
11999 .register_options
12000 .and_then(|opts| opts.get("syncKind").cloned())
12001 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12002 .transpose()?
12003 {
12004 server.update_capabilities(|capabilities| {
12005 let mut sync_options =
12006 Self::take_text_document_sync_options(capabilities);
12007 sync_options.change = Some(sync_kind);
12008 capabilities.text_document_sync =
12009 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12010 });
12011 notify_server_capabilities_updated(&server, cx);
12012 }
12013 }
12014 "textDocument/didSave" => {
12015 if let Some(include_text) = reg
12016 .register_options
12017 .map(|opts| {
12018 let transpose = opts
12019 .get("includeText")
12020 .cloned()
12021 .map(serde_json::from_value::<Option<bool>>)
12022 .transpose();
12023 match transpose {
12024 Ok(value) => Ok(value.flatten()),
12025 Err(e) => Err(e),
12026 }
12027 })
12028 .transpose()?
12029 {
12030 server.update_capabilities(|capabilities| {
12031 let mut sync_options =
12032 Self::take_text_document_sync_options(capabilities);
12033 sync_options.save =
12034 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12035 include_text,
12036 }));
12037 capabilities.text_document_sync =
12038 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12039 });
12040 notify_server_capabilities_updated(&server, cx);
12041 }
12042 }
12043 "textDocument/codeLens" => {
12044 if let Some(caps) = reg
12045 .register_options
12046 .map(serde_json::from_value)
12047 .transpose()?
12048 {
12049 server.update_capabilities(|capabilities| {
12050 capabilities.code_lens_provider = Some(caps);
12051 });
12052 notify_server_capabilities_updated(&server, cx);
12053 }
12054 }
12055 "textDocument/diagnostic" => {
12056 if let Some(caps) = reg
12057 .register_options
12058 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12059 .transpose()?
12060 {
12061 let local = self
12062 .as_local_mut()
12063 .context("Expected LSP Store to be local")?;
12064 let state = local
12065 .language_servers
12066 .get_mut(&server_id)
12067 .context("Could not obtain Language Servers state")?;
12068 local
12069 .language_server_dynamic_registrations
12070 .entry(server_id)
12071 .or_default()
12072 .diagnostics
12073 .insert(Some(reg.id.clone()), caps.clone());
12074
12075 if let LanguageServerState::Running {
12076 workspace_diagnostics_refresh_tasks,
12077 ..
12078 } = state
12079 && let Some(task) = lsp_workspace_diagnostics_refresh(
12080 Some(reg.id.clone()),
12081 caps.clone(),
12082 server.clone(),
12083 cx,
12084 )
12085 {
12086 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12087 }
12088
12089 let mut did_update_caps = false;
12090 server.update_capabilities(|capabilities| {
12091 if capabilities.diagnostic_provider.as_ref().is_none_or(
12092 |current_caps| {
12093 let supports_workspace_diagnostics =
12094 |capabilities: &DiagnosticServerCapabilities| {
12095 match capabilities {
12096 DiagnosticServerCapabilities::Options(
12097 diagnostic_options,
12098 ) => diagnostic_options.workspace_diagnostics,
12099 DiagnosticServerCapabilities::RegistrationOptions(
12100 diagnostic_registration_options,
12101 ) => {
12102 diagnostic_registration_options
12103 .diagnostic_options
12104 .workspace_diagnostics
12105 }
12106 }
12107 };
12108 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12109 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12110 // as it'll think that they're not supported.
12111 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12112 !supports_workspace_diagnostics(current_caps)
12113 & supports_workspace_diagnostics(&caps)
12114 },
12115 ) {
12116 did_update_caps = true;
12117 capabilities.diagnostic_provider = Some(caps);
12118 }
12119 });
12120 if did_update_caps {
12121 notify_server_capabilities_updated(&server, cx);
12122 }
12123 }
12124 }
12125 "textDocument/documentColor" => {
12126 let options = parse_register_capabilities(reg)?;
12127 let provider = match options {
12128 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12129 OneOf::Right(caps) => caps,
12130 };
12131 server.update_capabilities(|capabilities| {
12132 capabilities.color_provider = Some(provider);
12133 });
12134 notify_server_capabilities_updated(&server, cx);
12135 }
12136 _ => log::warn!("unhandled capability registration: {reg:?}"),
12137 }
12138 }
12139
12140 Ok(())
12141 }
12142
12143 fn unregister_server_capabilities(
12144 &mut self,
12145 server_id: LanguageServerId,
12146 params: lsp::UnregistrationParams,
12147 cx: &mut Context<Self>,
12148 ) -> anyhow::Result<()> {
12149 let server = self
12150 .language_server_for_id(server_id)
12151 .with_context(|| format!("no server {server_id} found"))?;
12152 for unreg in params.unregisterations.iter() {
12153 match unreg.method.as_str() {
12154 "workspace/didChangeWatchedFiles" => {
12155 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12156 local_lsp_store
12157 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12158 true
12159 } else {
12160 false
12161 };
12162 if notify {
12163 notify_server_capabilities_updated(&server, cx);
12164 }
12165 }
12166 "workspace/didChangeConfiguration" => {
12167 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12168 }
12169 "workspace/didChangeWorkspaceFolders" => {
12170 server.update_capabilities(|capabilities| {
12171 capabilities
12172 .workspace
12173 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12174 workspace_folders: None,
12175 file_operations: None,
12176 })
12177 .workspace_folders = None;
12178 });
12179 notify_server_capabilities_updated(&server, cx);
12180 }
12181 "workspace/symbol" => {
12182 server.update_capabilities(|capabilities| {
12183 capabilities.workspace_symbol_provider = None
12184 });
12185 notify_server_capabilities_updated(&server, cx);
12186 }
12187 "workspace/fileOperations" => {
12188 server.update_capabilities(|capabilities| {
12189 capabilities
12190 .workspace
12191 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12192 workspace_folders: None,
12193 file_operations: None,
12194 })
12195 .file_operations = None;
12196 });
12197 notify_server_capabilities_updated(&server, cx);
12198 }
12199 "workspace/executeCommand" => {
12200 server.update_capabilities(|capabilities| {
12201 capabilities.execute_command_provider = None;
12202 });
12203 notify_server_capabilities_updated(&server, cx);
12204 }
12205 "textDocument/rangeFormatting" => {
12206 server.update_capabilities(|capabilities| {
12207 capabilities.document_range_formatting_provider = None
12208 });
12209 notify_server_capabilities_updated(&server, cx);
12210 }
12211 "textDocument/onTypeFormatting" => {
12212 server.update_capabilities(|capabilities| {
12213 capabilities.document_on_type_formatting_provider = None;
12214 });
12215 notify_server_capabilities_updated(&server, cx);
12216 }
12217 "textDocument/formatting" => {
12218 server.update_capabilities(|capabilities| {
12219 capabilities.document_formatting_provider = None;
12220 });
12221 notify_server_capabilities_updated(&server, cx);
12222 }
12223 "textDocument/rename" => {
12224 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12225 notify_server_capabilities_updated(&server, cx);
12226 }
12227 "textDocument/codeAction" => {
12228 server.update_capabilities(|capabilities| {
12229 capabilities.code_action_provider = None;
12230 });
12231 notify_server_capabilities_updated(&server, cx);
12232 }
12233 "textDocument/definition" => {
12234 server.update_capabilities(|capabilities| {
12235 capabilities.definition_provider = None;
12236 });
12237 notify_server_capabilities_updated(&server, cx);
12238 }
12239 "textDocument/completion" => {
12240 server.update_capabilities(|capabilities| {
12241 capabilities.completion_provider = None;
12242 });
12243 notify_server_capabilities_updated(&server, cx);
12244 }
12245 "textDocument/hover" => {
12246 server.update_capabilities(|capabilities| {
12247 capabilities.hover_provider = None;
12248 });
12249 notify_server_capabilities_updated(&server, cx);
12250 }
12251 "textDocument/signatureHelp" => {
12252 server.update_capabilities(|capabilities| {
12253 capabilities.signature_help_provider = None;
12254 });
12255 notify_server_capabilities_updated(&server, cx);
12256 }
12257 "textDocument/didChange" => {
12258 server.update_capabilities(|capabilities| {
12259 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12260 sync_options.change = None;
12261 capabilities.text_document_sync =
12262 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12263 });
12264 notify_server_capabilities_updated(&server, cx);
12265 }
12266 "textDocument/didSave" => {
12267 server.update_capabilities(|capabilities| {
12268 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12269 sync_options.save = None;
12270 capabilities.text_document_sync =
12271 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12272 });
12273 notify_server_capabilities_updated(&server, cx);
12274 }
12275 "textDocument/codeLens" => {
12276 server.update_capabilities(|capabilities| {
12277 capabilities.code_lens_provider = None;
12278 });
12279 notify_server_capabilities_updated(&server, cx);
12280 }
12281 "textDocument/diagnostic" => {
12282 let local = self
12283 .as_local_mut()
12284 .context("Expected LSP Store to be local")?;
12285
12286 let state = local
12287 .language_servers
12288 .get_mut(&server_id)
12289 .context("Could not obtain Language Servers state")?;
12290 let options = local
12291 .language_server_dynamic_registrations
12292 .get_mut(&server_id)
12293 .with_context(|| {
12294 format!("Expected dynamic registration to exist for server {server_id}")
12295 })?.diagnostics
12296 .remove(&Some(unreg.id.clone()))
12297 .with_context(|| format!(
12298 "Attempted to unregister non-existent diagnostic registration with ID {}",
12299 unreg.id)
12300 )?;
12301
12302 let mut has_any_diagnostic_providers_still = true;
12303 if let Some(identifier) = diagnostic_identifier(&options)
12304 && let LanguageServerState::Running {
12305 workspace_diagnostics_refresh_tasks,
12306 ..
12307 } = state
12308 {
12309 workspace_diagnostics_refresh_tasks.remove(&identifier);
12310 has_any_diagnostic_providers_still =
12311 !workspace_diagnostics_refresh_tasks.is_empty();
12312 }
12313
12314 if !has_any_diagnostic_providers_still {
12315 server.update_capabilities(|capabilities| {
12316 debug_assert!(capabilities.diagnostic_provider.is_some());
12317 capabilities.diagnostic_provider = None;
12318 });
12319 }
12320
12321 notify_server_capabilities_updated(&server, cx);
12322 }
12323 "textDocument/documentColor" => {
12324 server.update_capabilities(|capabilities| {
12325 capabilities.color_provider = None;
12326 });
12327 notify_server_capabilities_updated(&server, cx);
12328 }
12329 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12330 }
12331 }
12332
12333 Ok(())
12334 }
12335
12336 async fn deduplicate_range_based_lsp_requests<T>(
12337 lsp_store: &Entity<Self>,
12338 server_id: Option<LanguageServerId>,
12339 lsp_request_id: LspRequestId,
12340 proto_request: &T::ProtoRequest,
12341 range: Range<Anchor>,
12342 cx: &mut AsyncApp,
12343 ) -> Result<()>
12344 where
12345 T: LspCommand,
12346 T::ProtoRequest: proto::LspRequestMessage,
12347 {
12348 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12349 let version = deserialize_version(proto_request.buffer_version());
12350 let buffer = lsp_store.update(cx, |this, cx| {
12351 this.buffer_store.read(cx).get_existing(buffer_id)
12352 })??;
12353 buffer
12354 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12355 .await?;
12356 lsp_store.update(cx, |lsp_store, cx| {
12357 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12358 let chunks_queried_for = lsp_data
12359 .inlay_hints
12360 .applicable_chunks(&[range])
12361 .collect::<Vec<_>>();
12362 match chunks_queried_for.as_slice() {
12363 &[chunk] => {
12364 let key = LspKey {
12365 request_type: TypeId::of::<T>(),
12366 server_queried: server_id,
12367 };
12368 let previous_request = lsp_data
12369 .chunk_lsp_requests
12370 .entry(key)
12371 .or_default()
12372 .insert(chunk, lsp_request_id);
12373 if let Some((previous_request, running_requests)) =
12374 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12375 {
12376 running_requests.remove(&previous_request);
12377 }
12378 }
12379 _ambiguous_chunks => {
12380 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12381 // there, a buffer version-based check will be performed and outdated requests discarded.
12382 }
12383 }
12384 anyhow::Ok(())
12385 })??;
12386
12387 Ok(())
12388 }
12389
12390 async fn query_lsp_locally<T>(
12391 lsp_store: Entity<Self>,
12392 for_server_id: Option<LanguageServerId>,
12393 sender_id: proto::PeerId,
12394 lsp_request_id: LspRequestId,
12395 proto_request: T::ProtoRequest,
12396 position: Option<Anchor>,
12397 cx: &mut AsyncApp,
12398 ) -> Result<()>
12399 where
12400 T: LspCommand + Clone,
12401 T::ProtoRequest: proto::LspRequestMessage,
12402 <T::ProtoRequest as proto::RequestMessage>::Response:
12403 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12404 {
12405 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12406 let version = deserialize_version(proto_request.buffer_version());
12407 let buffer = lsp_store.update(cx, |this, cx| {
12408 this.buffer_store.read(cx).get_existing(buffer_id)
12409 })??;
12410 buffer
12411 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12412 .await?;
12413 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12414 let request =
12415 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12416 let key = LspKey {
12417 request_type: TypeId::of::<T>(),
12418 server_queried: for_server_id,
12419 };
12420 lsp_store.update(cx, |lsp_store, cx| {
12421 let request_task = match for_server_id {
12422 Some(server_id) => {
12423 let server_task = lsp_store.request_lsp(
12424 buffer.clone(),
12425 LanguageServerToQuery::Other(server_id),
12426 request.clone(),
12427 cx,
12428 );
12429 cx.background_spawn(async move {
12430 let mut responses = Vec::new();
12431 match server_task.await {
12432 Ok(response) => responses.push((server_id, response)),
12433 // rust-analyzer likes to error with this when its still loading up
12434 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12435 Err(e) => log::error!(
12436 "Error handling response for request {request:?}: {e:#}"
12437 ),
12438 }
12439 responses
12440 })
12441 }
12442 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12443 };
12444 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12445 if T::ProtoRequest::stop_previous_requests() {
12446 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12447 lsp_requests.clear();
12448 }
12449 }
12450 lsp_data.lsp_requests.entry(key).or_default().insert(
12451 lsp_request_id,
12452 cx.spawn(async move |lsp_store, cx| {
12453 let response = request_task.await;
12454 lsp_store
12455 .update(cx, |lsp_store, cx| {
12456 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12457 {
12458 let response = response
12459 .into_iter()
12460 .map(|(server_id, response)| {
12461 (
12462 server_id.to_proto(),
12463 T::response_to_proto(
12464 response,
12465 lsp_store,
12466 sender_id,
12467 &buffer_version,
12468 cx,
12469 )
12470 .into(),
12471 )
12472 })
12473 .collect::<HashMap<_, _>>();
12474 match client.send_lsp_response::<T::ProtoRequest>(
12475 project_id,
12476 lsp_request_id,
12477 response,
12478 ) {
12479 Ok(()) => {}
12480 Err(e) => {
12481 log::error!("Failed to send LSP response: {e:#}",)
12482 }
12483 }
12484 }
12485 })
12486 .ok();
12487 }),
12488 );
12489 })?;
12490 Ok(())
12491 }
12492
12493 fn take_text_document_sync_options(
12494 capabilities: &mut lsp::ServerCapabilities,
12495 ) -> lsp::TextDocumentSyncOptions {
12496 match capabilities.text_document_sync.take() {
12497 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12498 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12499 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12500 sync_options.change = Some(sync_kind);
12501 sync_options
12502 }
12503 None => lsp::TextDocumentSyncOptions::default(),
12504 }
12505 }
12506
12507 #[cfg(any(test, feature = "test-support"))]
12508 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12509 Some(
12510 self.lsp_data
12511 .get_mut(&buffer_id)?
12512 .code_lens
12513 .take()?
12514 .update
12515 .take()?
12516 .1,
12517 )
12518 }
12519
12520 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12521 self.downstream_client.clone()
12522 }
12523
12524 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12525 self.worktree_store.clone()
12526 }
12527
12528 /// Gets what's stored in the LSP data for the given buffer.
12529 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12530 self.lsp_data.get_mut(&buffer_id)
12531 }
12532
12533 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12534 /// new [`BufferLspData`] will be created to replace the previous state.
12535 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12536 let (buffer_id, buffer_version) =
12537 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12538 let lsp_data = self
12539 .lsp_data
12540 .entry(buffer_id)
12541 .or_insert_with(|| BufferLspData::new(buffer, cx));
12542 if buffer_version.changed_since(&lsp_data.buffer_version) {
12543 *lsp_data = BufferLspData::new(buffer, cx);
12544 }
12545 lsp_data
12546 }
12547}
12548
12549// Registration with registerOptions as null, should fallback to true.
12550// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12551fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12552 reg: lsp::Registration,
12553) -> Result<OneOf<bool, T>> {
12554 Ok(match reg.register_options {
12555 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12556 None => OneOf::Left(true),
12557 })
12558}
12559
12560fn subscribe_to_binary_statuses(
12561 languages: &Arc<LanguageRegistry>,
12562 cx: &mut Context<'_, LspStore>,
12563) -> Task<()> {
12564 let mut server_statuses = languages.language_server_binary_statuses();
12565 cx.spawn(async move |lsp_store, cx| {
12566 while let Some((server_name, binary_status)) = server_statuses.next().await {
12567 if lsp_store
12568 .update(cx, |_, cx| {
12569 let mut message = None;
12570 let binary_status = match binary_status {
12571 BinaryStatus::None => proto::ServerBinaryStatus::None,
12572 BinaryStatus::CheckingForUpdate => {
12573 proto::ServerBinaryStatus::CheckingForUpdate
12574 }
12575 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12576 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12577 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12578 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12579 BinaryStatus::Failed { error } => {
12580 message = Some(error);
12581 proto::ServerBinaryStatus::Failed
12582 }
12583 };
12584 cx.emit(LspStoreEvent::LanguageServerUpdate {
12585 // Binary updates are about the binary that might not have any language server id at that point.
12586 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12587 language_server_id: LanguageServerId(0),
12588 name: Some(server_name),
12589 message: proto::update_language_server::Variant::StatusUpdate(
12590 proto::StatusUpdate {
12591 message,
12592 status: Some(proto::status_update::Status::Binary(
12593 binary_status as i32,
12594 )),
12595 },
12596 ),
12597 });
12598 })
12599 .is_err()
12600 {
12601 break;
12602 }
12603 }
12604 })
12605}
12606
12607fn lsp_workspace_diagnostics_refresh(
12608 registration_id: Option<String>,
12609 options: DiagnosticServerCapabilities,
12610 server: Arc<LanguageServer>,
12611 cx: &mut Context<'_, LspStore>,
12612) -> Option<WorkspaceRefreshTask> {
12613 let identifier = diagnostic_identifier(&options)?;
12614
12615 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12616 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12617 refresh_tx.try_send(()).ok();
12618
12619 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12620 let mut attempts = 0;
12621 let max_attempts = 50;
12622 let mut requests = 0;
12623
12624 loop {
12625 let Some(()) = refresh_rx.recv().await else {
12626 return;
12627 };
12628
12629 'request: loop {
12630 requests += 1;
12631 if attempts > max_attempts {
12632 log::error!(
12633 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12634 );
12635 return;
12636 }
12637 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12638 cx.background_executor()
12639 .timer(Duration::from_millis(backoff_millis))
12640 .await;
12641 attempts += 1;
12642
12643 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12644 lsp_store
12645 .all_result_ids(server.server_id())
12646 .into_iter()
12647 .filter_map(|(abs_path, result_id)| {
12648 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12649 Some(lsp::PreviousResultId {
12650 uri,
12651 value: result_id,
12652 })
12653 })
12654 .collect()
12655 }) else {
12656 return;
12657 };
12658
12659 let token = if let Some(identifier) = ®istration_id {
12660 format!(
12661 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12662 server.server_id(),
12663 )
12664 } else {
12665 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12666 };
12667
12668 progress_rx.try_recv().ok();
12669 let timer =
12670 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12671 let progress = pin!(progress_rx.recv().fuse());
12672 let response_result = server
12673 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12674 lsp::WorkspaceDiagnosticParams {
12675 previous_result_ids,
12676 identifier: identifier.clone(),
12677 work_done_progress_params: Default::default(),
12678 partial_result_params: lsp::PartialResultParams {
12679 partial_result_token: Some(lsp::ProgressToken::String(token)),
12680 },
12681 },
12682 select(timer, progress).then(|either| match either {
12683 Either::Left((message, ..)) => ready(message).left_future(),
12684 Either::Right(..) => pending::<String>().right_future(),
12685 }),
12686 )
12687 .await;
12688
12689 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12690 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12691 match response_result {
12692 ConnectionResult::Timeout => {
12693 log::error!("Timeout during workspace diagnostics pull");
12694 continue 'request;
12695 }
12696 ConnectionResult::ConnectionReset => {
12697 log::error!("Server closed a workspace diagnostics pull request");
12698 continue 'request;
12699 }
12700 ConnectionResult::Result(Err(e)) => {
12701 log::error!("Error during workspace diagnostics pull: {e:#}");
12702 break 'request;
12703 }
12704 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12705 attempts = 0;
12706 if lsp_store
12707 .update(cx, |lsp_store, cx| {
12708 lsp_store.apply_workspace_diagnostic_report(
12709 server.server_id(),
12710 pulled_diagnostics,
12711 cx,
12712 )
12713 })
12714 .is_err()
12715 {
12716 return;
12717 }
12718 break 'request;
12719 }
12720 }
12721 }
12722 }
12723 });
12724
12725 Some(WorkspaceRefreshTask {
12726 refresh_tx,
12727 progress_tx,
12728 task: workspace_query_language_server,
12729 })
12730}
12731
12732fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12733 match &options {
12734 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12735 if !diagnostic_options.workspace_diagnostics {
12736 return None;
12737 }
12738 Some(diagnostic_options.identifier.clone())
12739 }
12740 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12741 let diagnostic_options = ®istration_options.diagnostic_options;
12742 if !diagnostic_options.workspace_diagnostics {
12743 return None;
12744 }
12745 Some(diagnostic_options.identifier.clone())
12746 }
12747 }
12748}
12749
12750fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12751 let CompletionSource::BufferWord {
12752 word_range,
12753 resolved,
12754 } = &mut completion.source
12755 else {
12756 return;
12757 };
12758 if *resolved {
12759 return;
12760 }
12761
12762 if completion.new_text
12763 != snapshot
12764 .text_for_range(word_range.clone())
12765 .collect::<String>()
12766 {
12767 return;
12768 }
12769
12770 let mut offset = 0;
12771 for chunk in snapshot.chunks(word_range.clone(), true) {
12772 let end_offset = offset + chunk.text.len();
12773 if let Some(highlight_id) = chunk.syntax_highlight_id {
12774 completion
12775 .label
12776 .runs
12777 .push((offset..end_offset, highlight_id));
12778 }
12779 offset = end_offset;
12780 }
12781 *resolved = true;
12782}
12783
12784impl EventEmitter<LspStoreEvent> for LspStore {}
12785
12786fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12787 hover
12788 .contents
12789 .retain(|hover_block| !hover_block.text.trim().is_empty());
12790 if hover.contents.is_empty() {
12791 None
12792 } else {
12793 Some(hover)
12794 }
12795}
12796
12797async fn populate_labels_for_completions(
12798 new_completions: Vec<CoreCompletion>,
12799 language: Option<Arc<Language>>,
12800 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12801) -> Vec<Completion> {
12802 let lsp_completions = new_completions
12803 .iter()
12804 .filter_map(|new_completion| {
12805 new_completion
12806 .source
12807 .lsp_completion(true)
12808 .map(|lsp_completion| lsp_completion.into_owned())
12809 })
12810 .collect::<Vec<_>>();
12811
12812 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12813 lsp_adapter
12814 .labels_for_completions(&lsp_completions, language)
12815 .await
12816 .log_err()
12817 .unwrap_or_default()
12818 } else {
12819 Vec::new()
12820 }
12821 .into_iter()
12822 .fuse();
12823
12824 let mut completions = Vec::new();
12825 for completion in new_completions {
12826 match completion.source.lsp_completion(true) {
12827 Some(lsp_completion) => {
12828 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12829
12830 let mut label = labels.next().flatten().unwrap_or_else(|| {
12831 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12832 });
12833 ensure_uniform_list_compatible_label(&mut label);
12834 completions.push(Completion {
12835 label,
12836 documentation,
12837 replace_range: completion.replace_range,
12838 new_text: completion.new_text,
12839 insert_text_mode: lsp_completion.insert_text_mode,
12840 source: completion.source,
12841 icon_path: None,
12842 confirm: None,
12843 });
12844 }
12845 None => {
12846 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12847 ensure_uniform_list_compatible_label(&mut label);
12848 completions.push(Completion {
12849 label,
12850 documentation: None,
12851 replace_range: completion.replace_range,
12852 new_text: completion.new_text,
12853 source: completion.source,
12854 insert_text_mode: None,
12855 icon_path: None,
12856 confirm: None,
12857 });
12858 }
12859 }
12860 }
12861 completions
12862}
12863
12864#[derive(Debug)]
12865pub enum LanguageServerToQuery {
12866 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12867 FirstCapable,
12868 /// Query a specific language server.
12869 Other(LanguageServerId),
12870}
12871
12872#[derive(Default)]
12873struct RenamePathsWatchedForServer {
12874 did_rename: Vec<RenameActionPredicate>,
12875 will_rename: Vec<RenameActionPredicate>,
12876}
12877
12878impl RenamePathsWatchedForServer {
12879 fn with_did_rename_patterns(
12880 mut self,
12881 did_rename: Option<&FileOperationRegistrationOptions>,
12882 ) -> Self {
12883 if let Some(did_rename) = did_rename {
12884 self.did_rename = did_rename
12885 .filters
12886 .iter()
12887 .filter_map(|filter| filter.try_into().log_err())
12888 .collect();
12889 }
12890 self
12891 }
12892 fn with_will_rename_patterns(
12893 mut self,
12894 will_rename: Option<&FileOperationRegistrationOptions>,
12895 ) -> Self {
12896 if let Some(will_rename) = will_rename {
12897 self.will_rename = will_rename
12898 .filters
12899 .iter()
12900 .filter_map(|filter| filter.try_into().log_err())
12901 .collect();
12902 }
12903 self
12904 }
12905
12906 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12907 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12908 }
12909 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12910 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12911 }
12912}
12913
12914impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12915 type Error = globset::Error;
12916 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12917 Ok(Self {
12918 kind: ops.pattern.matches.clone(),
12919 glob: GlobBuilder::new(&ops.pattern.glob)
12920 .case_insensitive(
12921 ops.pattern
12922 .options
12923 .as_ref()
12924 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12925 )
12926 .build()?
12927 .compile_matcher(),
12928 })
12929 }
12930}
12931struct RenameActionPredicate {
12932 glob: GlobMatcher,
12933 kind: Option<FileOperationPatternKind>,
12934}
12935
12936impl RenameActionPredicate {
12937 // Returns true if language server should be notified
12938 fn eval(&self, path: &str, is_dir: bool) -> bool {
12939 self.kind.as_ref().is_none_or(|kind| {
12940 let expected_kind = if is_dir {
12941 FileOperationPatternKind::Folder
12942 } else {
12943 FileOperationPatternKind::File
12944 };
12945 kind == &expected_kind
12946 }) && self.glob.is_match(path)
12947 }
12948}
12949
12950#[derive(Default)]
12951struct LanguageServerWatchedPaths {
12952 worktree_paths: HashMap<WorktreeId, GlobSet>,
12953 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12954}
12955
12956#[derive(Default)]
12957struct LanguageServerWatchedPathsBuilder {
12958 worktree_paths: HashMap<WorktreeId, GlobSet>,
12959 abs_paths: HashMap<Arc<Path>, GlobSet>,
12960}
12961
12962impl LanguageServerWatchedPathsBuilder {
12963 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12964 self.worktree_paths.insert(worktree_id, glob_set);
12965 }
12966 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12967 self.abs_paths.insert(path, glob_set);
12968 }
12969 fn build(
12970 self,
12971 fs: Arc<dyn Fs>,
12972 language_server_id: LanguageServerId,
12973 cx: &mut Context<LspStore>,
12974 ) -> LanguageServerWatchedPaths {
12975 let lsp_store = cx.weak_entity();
12976
12977 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12978 let abs_paths = self
12979 .abs_paths
12980 .into_iter()
12981 .map(|(abs_path, globset)| {
12982 let task = cx.spawn({
12983 let abs_path = abs_path.clone();
12984 let fs = fs.clone();
12985
12986 let lsp_store = lsp_store.clone();
12987 async move |_, cx| {
12988 maybe!(async move {
12989 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12990 while let Some(update) = push_updates.0.next().await {
12991 let action = lsp_store
12992 .update(cx, |this, _| {
12993 let Some(local) = this.as_local() else {
12994 return ControlFlow::Break(());
12995 };
12996 let Some(watcher) = local
12997 .language_server_watched_paths
12998 .get(&language_server_id)
12999 else {
13000 return ControlFlow::Break(());
13001 };
13002 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13003 "Watched abs path is not registered with a watcher",
13004 );
13005 let matching_entries = update
13006 .into_iter()
13007 .filter(|event| globs.is_match(&event.path))
13008 .collect::<Vec<_>>();
13009 this.lsp_notify_abs_paths_changed(
13010 language_server_id,
13011 matching_entries,
13012 );
13013 ControlFlow::Continue(())
13014 })
13015 .ok()?;
13016
13017 if action.is_break() {
13018 break;
13019 }
13020 }
13021 Some(())
13022 })
13023 .await;
13024 }
13025 });
13026 (abs_path, (globset, task))
13027 })
13028 .collect();
13029 LanguageServerWatchedPaths {
13030 worktree_paths: self.worktree_paths,
13031 abs_paths,
13032 }
13033 }
13034}
13035
13036struct LspBufferSnapshot {
13037 version: i32,
13038 snapshot: TextBufferSnapshot,
13039}
13040
13041/// A prompt requested by LSP server.
13042#[derive(Clone, Debug)]
13043pub struct LanguageServerPromptRequest {
13044 pub level: PromptLevel,
13045 pub message: String,
13046 pub actions: Vec<MessageActionItem>,
13047 pub lsp_name: String,
13048 pub(crate) response_channel: Sender<MessageActionItem>,
13049}
13050
13051impl LanguageServerPromptRequest {
13052 pub async fn respond(self, index: usize) -> Option<()> {
13053 if let Some(response) = self.actions.into_iter().nth(index) {
13054 self.response_channel.send(response).await.ok()
13055 } else {
13056 None
13057 }
13058 }
13059}
13060impl PartialEq for LanguageServerPromptRequest {
13061 fn eq(&self, other: &Self) -> bool {
13062 self.message == other.message && self.actions == other.actions
13063 }
13064}
13065
13066#[derive(Clone, Debug, PartialEq)]
13067pub enum LanguageServerLogType {
13068 Log(MessageType),
13069 Trace { verbose_info: Option<String> },
13070 Rpc { received: bool },
13071}
13072
13073impl LanguageServerLogType {
13074 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13075 match self {
13076 Self::Log(log_type) => {
13077 use proto::log_message::LogLevel;
13078 let level = match *log_type {
13079 MessageType::ERROR => LogLevel::Error,
13080 MessageType::WARNING => LogLevel::Warning,
13081 MessageType::INFO => LogLevel::Info,
13082 MessageType::LOG => LogLevel::Log,
13083 other => {
13084 log::warn!("Unknown lsp log message type: {other:?}");
13085 LogLevel::Log
13086 }
13087 };
13088 proto::language_server_log::LogType::Log(proto::LogMessage {
13089 level: level as i32,
13090 })
13091 }
13092 Self::Trace { verbose_info } => {
13093 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13094 verbose_info: verbose_info.to_owned(),
13095 })
13096 }
13097 Self::Rpc { received } => {
13098 let kind = if *received {
13099 proto::rpc_message::Kind::Received
13100 } else {
13101 proto::rpc_message::Kind::Sent
13102 };
13103 let kind = kind as i32;
13104 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13105 }
13106 }
13107 }
13108
13109 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13110 use proto::log_message::LogLevel;
13111 use proto::rpc_message;
13112 match log_type {
13113 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13114 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13115 LogLevel::Error => MessageType::ERROR,
13116 LogLevel::Warning => MessageType::WARNING,
13117 LogLevel::Info => MessageType::INFO,
13118 LogLevel::Log => MessageType::LOG,
13119 },
13120 ),
13121 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13122 verbose_info: trace_message.verbose_info,
13123 },
13124 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13125 received: match rpc_message::Kind::from_i32(message.kind)
13126 .unwrap_or(rpc_message::Kind::Received)
13127 {
13128 rpc_message::Kind::Received => true,
13129 rpc_message::Kind::Sent => false,
13130 },
13131 },
13132 }
13133 }
13134}
13135
13136pub struct WorkspaceRefreshTask {
13137 refresh_tx: mpsc::Sender<()>,
13138 progress_tx: mpsc::Sender<()>,
13139 #[allow(dead_code)]
13140 task: Task<()>,
13141}
13142
13143pub enum LanguageServerState {
13144 Starting {
13145 startup: Task<Option<Arc<LanguageServer>>>,
13146 /// List of language servers that will be added to the workspace once it's initialization completes.
13147 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13148 },
13149
13150 Running {
13151 adapter: Arc<CachedLspAdapter>,
13152 server: Arc<LanguageServer>,
13153 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13154 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13155 },
13156}
13157
13158impl LanguageServerState {
13159 fn add_workspace_folder(&self, uri: Uri) {
13160 match self {
13161 LanguageServerState::Starting {
13162 pending_workspace_folders,
13163 ..
13164 } => {
13165 pending_workspace_folders.lock().insert(uri);
13166 }
13167 LanguageServerState::Running { server, .. } => {
13168 server.add_workspace_folder(uri);
13169 }
13170 }
13171 }
13172 fn _remove_workspace_folder(&self, uri: Uri) {
13173 match self {
13174 LanguageServerState::Starting {
13175 pending_workspace_folders,
13176 ..
13177 } => {
13178 pending_workspace_folders.lock().remove(&uri);
13179 }
13180 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13181 }
13182 }
13183}
13184
13185impl std::fmt::Debug for LanguageServerState {
13186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13187 match self {
13188 LanguageServerState::Starting { .. } => {
13189 f.debug_struct("LanguageServerState::Starting").finish()
13190 }
13191 LanguageServerState::Running { .. } => {
13192 f.debug_struct("LanguageServerState::Running").finish()
13193 }
13194 }
13195 }
13196}
13197
13198#[derive(Clone, Debug, Serialize)]
13199pub struct LanguageServerProgress {
13200 pub is_disk_based_diagnostics_progress: bool,
13201 pub is_cancellable: bool,
13202 pub title: Option<String>,
13203 pub message: Option<String>,
13204 pub percentage: Option<usize>,
13205 #[serde(skip_serializing)]
13206 pub last_update_at: Instant,
13207}
13208
13209#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13210pub struct DiagnosticSummary {
13211 pub error_count: usize,
13212 pub warning_count: usize,
13213}
13214
13215impl DiagnosticSummary {
13216 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13217 let mut this = Self {
13218 error_count: 0,
13219 warning_count: 0,
13220 };
13221
13222 for entry in diagnostics {
13223 if entry.diagnostic.is_primary {
13224 match entry.diagnostic.severity {
13225 DiagnosticSeverity::ERROR => this.error_count += 1,
13226 DiagnosticSeverity::WARNING => this.warning_count += 1,
13227 _ => {}
13228 }
13229 }
13230 }
13231
13232 this
13233 }
13234
13235 pub fn is_empty(&self) -> bool {
13236 self.error_count == 0 && self.warning_count == 0
13237 }
13238
13239 pub fn to_proto(
13240 self,
13241 language_server_id: LanguageServerId,
13242 path: &RelPath,
13243 ) -> proto::DiagnosticSummary {
13244 proto::DiagnosticSummary {
13245 path: path.to_proto(),
13246 language_server_id: language_server_id.0 as u64,
13247 error_count: self.error_count as u32,
13248 warning_count: self.warning_count as u32,
13249 }
13250 }
13251}
13252
13253#[derive(Clone, Debug)]
13254pub enum CompletionDocumentation {
13255 /// There is no documentation for this completion.
13256 Undocumented,
13257 /// A single line of documentation.
13258 SingleLine(SharedString),
13259 /// Multiple lines of plain text documentation.
13260 MultiLinePlainText(SharedString),
13261 /// Markdown documentation.
13262 MultiLineMarkdown(SharedString),
13263 /// Both single line and multiple lines of plain text documentation.
13264 SingleLineAndMultiLinePlainText {
13265 single_line: SharedString,
13266 plain_text: Option<SharedString>,
13267 },
13268}
13269
13270impl CompletionDocumentation {
13271 #[cfg(any(test, feature = "test-support"))]
13272 pub fn text(&self) -> SharedString {
13273 match self {
13274 CompletionDocumentation::Undocumented => "".into(),
13275 CompletionDocumentation::SingleLine(s) => s.clone(),
13276 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13277 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13278 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13279 single_line.clone()
13280 }
13281 }
13282 }
13283}
13284
13285impl From<lsp::Documentation> for CompletionDocumentation {
13286 fn from(docs: lsp::Documentation) -> Self {
13287 match docs {
13288 lsp::Documentation::String(text) => {
13289 if text.lines().count() <= 1 {
13290 CompletionDocumentation::SingleLine(text.into())
13291 } else {
13292 CompletionDocumentation::MultiLinePlainText(text.into())
13293 }
13294 }
13295
13296 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13297 lsp::MarkupKind::PlainText => {
13298 if value.lines().count() <= 1 {
13299 CompletionDocumentation::SingleLine(value.into())
13300 } else {
13301 CompletionDocumentation::MultiLinePlainText(value.into())
13302 }
13303 }
13304
13305 lsp::MarkupKind::Markdown => {
13306 CompletionDocumentation::MultiLineMarkdown(value.into())
13307 }
13308 },
13309 }
13310 }
13311}
13312
13313pub enum ResolvedHint {
13314 Resolved(InlayHint),
13315 Resolving(Shared<Task<()>>),
13316}
13317
13318fn glob_literal_prefix(glob: &Path) -> PathBuf {
13319 glob.components()
13320 .take_while(|component| match component {
13321 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13322 _ => true,
13323 })
13324 .collect()
13325}
13326
13327pub struct SshLspAdapter {
13328 name: LanguageServerName,
13329 binary: LanguageServerBinary,
13330 initialization_options: Option<String>,
13331 code_action_kinds: Option<Vec<CodeActionKind>>,
13332}
13333
13334impl SshLspAdapter {
13335 pub fn new(
13336 name: LanguageServerName,
13337 binary: LanguageServerBinary,
13338 initialization_options: Option<String>,
13339 code_action_kinds: Option<String>,
13340 ) -> Self {
13341 Self {
13342 name,
13343 binary,
13344 initialization_options,
13345 code_action_kinds: code_action_kinds
13346 .as_ref()
13347 .and_then(|c| serde_json::from_str(c).ok()),
13348 }
13349 }
13350}
13351
13352impl LspInstaller for SshLspAdapter {
13353 type BinaryVersion = ();
13354 async fn check_if_user_installed(
13355 &self,
13356 _: &dyn LspAdapterDelegate,
13357 _: Option<Toolchain>,
13358 _: &AsyncApp,
13359 ) -> Option<LanguageServerBinary> {
13360 Some(self.binary.clone())
13361 }
13362
13363 async fn cached_server_binary(
13364 &self,
13365 _: PathBuf,
13366 _: &dyn LspAdapterDelegate,
13367 ) -> Option<LanguageServerBinary> {
13368 None
13369 }
13370
13371 async fn fetch_latest_server_version(
13372 &self,
13373 _: &dyn LspAdapterDelegate,
13374 _: bool,
13375 _: &mut AsyncApp,
13376 ) -> Result<()> {
13377 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13378 }
13379
13380 async fn fetch_server_binary(
13381 &self,
13382 _: (),
13383 _: PathBuf,
13384 _: &dyn LspAdapterDelegate,
13385 ) -> Result<LanguageServerBinary> {
13386 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13387 }
13388}
13389
13390#[async_trait(?Send)]
13391impl LspAdapter for SshLspAdapter {
13392 fn name(&self) -> LanguageServerName {
13393 self.name.clone()
13394 }
13395
13396 async fn initialization_options(
13397 self: Arc<Self>,
13398 _: &Arc<dyn LspAdapterDelegate>,
13399 ) -> Result<Option<serde_json::Value>> {
13400 let Some(options) = &self.initialization_options else {
13401 return Ok(None);
13402 };
13403 let result = serde_json::from_str(options)?;
13404 Ok(result)
13405 }
13406
13407 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13408 self.code_action_kinds.clone()
13409 }
13410}
13411
13412pub fn language_server_settings<'a>(
13413 delegate: &'a dyn LspAdapterDelegate,
13414 language: &LanguageServerName,
13415 cx: &'a App,
13416) -> Option<&'a LspSettings> {
13417 language_server_settings_for(
13418 SettingsLocation {
13419 worktree_id: delegate.worktree_id(),
13420 path: RelPath::empty(),
13421 },
13422 language,
13423 cx,
13424 )
13425}
13426
13427pub(crate) fn language_server_settings_for<'a>(
13428 location: SettingsLocation<'a>,
13429 language: &LanguageServerName,
13430 cx: &'a App,
13431) -> Option<&'a LspSettings> {
13432 ProjectSettings::get(Some(location), cx).lsp.get(language)
13433}
13434
13435pub struct LocalLspAdapterDelegate {
13436 lsp_store: WeakEntity<LspStore>,
13437 worktree: worktree::Snapshot,
13438 fs: Arc<dyn Fs>,
13439 http_client: Arc<dyn HttpClient>,
13440 language_registry: Arc<LanguageRegistry>,
13441 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13442}
13443
13444impl LocalLspAdapterDelegate {
13445 pub fn new(
13446 language_registry: Arc<LanguageRegistry>,
13447 environment: &Entity<ProjectEnvironment>,
13448 lsp_store: WeakEntity<LspStore>,
13449 worktree: &Entity<Worktree>,
13450 http_client: Arc<dyn HttpClient>,
13451 fs: Arc<dyn Fs>,
13452 cx: &mut App,
13453 ) -> Arc<Self> {
13454 let load_shell_env_task =
13455 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13456
13457 Arc::new(Self {
13458 lsp_store,
13459 worktree: worktree.read(cx).snapshot(),
13460 fs,
13461 http_client,
13462 language_registry,
13463 load_shell_env_task,
13464 })
13465 }
13466
13467 fn from_local_lsp(
13468 local: &LocalLspStore,
13469 worktree: &Entity<Worktree>,
13470 cx: &mut App,
13471 ) -> Arc<Self> {
13472 Self::new(
13473 local.languages.clone(),
13474 &local.environment,
13475 local.weak.clone(),
13476 worktree,
13477 local.http_client.clone(),
13478 local.fs.clone(),
13479 cx,
13480 )
13481 }
13482}
13483
13484#[async_trait]
13485impl LspAdapterDelegate for LocalLspAdapterDelegate {
13486 fn show_notification(&self, message: &str, cx: &mut App) {
13487 self.lsp_store
13488 .update(cx, |_, cx| {
13489 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13490 })
13491 .ok();
13492 }
13493
13494 fn http_client(&self) -> Arc<dyn HttpClient> {
13495 self.http_client.clone()
13496 }
13497
13498 fn worktree_id(&self) -> WorktreeId {
13499 self.worktree.id()
13500 }
13501
13502 fn worktree_root_path(&self) -> &Path {
13503 self.worktree.abs_path().as_ref()
13504 }
13505
13506 async fn shell_env(&self) -> HashMap<String, String> {
13507 let task = self.load_shell_env_task.clone();
13508 task.await.unwrap_or_default()
13509 }
13510
13511 async fn npm_package_installed_version(
13512 &self,
13513 package_name: &str,
13514 ) -> Result<Option<(PathBuf, String)>> {
13515 let local_package_directory = self.worktree_root_path();
13516 let node_modules_directory = local_package_directory.join("node_modules");
13517
13518 if let Some(version) =
13519 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13520 {
13521 return Ok(Some((node_modules_directory, version)));
13522 }
13523 let Some(npm) = self.which("npm".as_ref()).await else {
13524 log::warn!(
13525 "Failed to find npm executable for {:?}",
13526 local_package_directory
13527 );
13528 return Ok(None);
13529 };
13530
13531 let env = self.shell_env().await;
13532 let output = util::command::new_smol_command(&npm)
13533 .args(["root", "-g"])
13534 .envs(env)
13535 .current_dir(local_package_directory)
13536 .output()
13537 .await?;
13538 let global_node_modules =
13539 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13540
13541 if let Some(version) =
13542 read_package_installed_version(global_node_modules.clone(), package_name).await?
13543 {
13544 return Ok(Some((global_node_modules, version)));
13545 }
13546 return Ok(None);
13547 }
13548
13549 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13550 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13551 if self.fs.is_file(&worktree_abs_path).await {
13552 worktree_abs_path.pop();
13553 }
13554
13555 let env = self.shell_env().await;
13556
13557 let shell_path = env.get("PATH").cloned();
13558
13559 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13560 }
13561
13562 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13563 let mut working_dir = self.worktree_root_path().to_path_buf();
13564 if self.fs.is_file(&working_dir).await {
13565 working_dir.pop();
13566 }
13567 let output = util::command::new_smol_command(&command.path)
13568 .args(command.arguments)
13569 .envs(command.env.clone().unwrap_or_default())
13570 .current_dir(working_dir)
13571 .output()
13572 .await?;
13573
13574 anyhow::ensure!(
13575 output.status.success(),
13576 "{}, stdout: {:?}, stderr: {:?}",
13577 output.status,
13578 String::from_utf8_lossy(&output.stdout),
13579 String::from_utf8_lossy(&output.stderr)
13580 );
13581 Ok(())
13582 }
13583
13584 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13585 self.language_registry
13586 .update_lsp_binary_status(server_name, status);
13587 }
13588
13589 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13590 self.language_registry
13591 .all_lsp_adapters()
13592 .into_iter()
13593 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13594 .collect()
13595 }
13596
13597 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13598 let dir = self.language_registry.language_server_download_dir(name)?;
13599
13600 if !dir.exists() {
13601 smol::fs::create_dir_all(&dir)
13602 .await
13603 .context("failed to create container directory")
13604 .log_err()?;
13605 }
13606
13607 Some(dir)
13608 }
13609
13610 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13611 let entry = self
13612 .worktree
13613 .entry_for_path(path)
13614 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13615 let abs_path = self.worktree.absolutize(&entry.path);
13616 self.fs.load(&abs_path).await
13617 }
13618}
13619
13620async fn populate_labels_for_symbols(
13621 symbols: Vec<CoreSymbol>,
13622 language_registry: &Arc<LanguageRegistry>,
13623 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13624 output: &mut Vec<Symbol>,
13625) {
13626 #[allow(clippy::mutable_key_type)]
13627 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13628
13629 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13630 for symbol in symbols {
13631 let Some(file_name) = symbol.path.file_name() else {
13632 continue;
13633 };
13634 let language = language_registry
13635 .load_language_for_file_path(Path::new(file_name))
13636 .await
13637 .ok()
13638 .or_else(|| {
13639 unknown_paths.insert(file_name.into());
13640 None
13641 });
13642 symbols_by_language
13643 .entry(language)
13644 .or_default()
13645 .push(symbol);
13646 }
13647
13648 for unknown_path in unknown_paths {
13649 log::info!("no language found for symbol in file {unknown_path:?}");
13650 }
13651
13652 let mut label_params = Vec::new();
13653 for (language, mut symbols) in symbols_by_language {
13654 label_params.clear();
13655 label_params.extend(
13656 symbols
13657 .iter_mut()
13658 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13659 );
13660
13661 let mut labels = Vec::new();
13662 if let Some(language) = language {
13663 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13664 language_registry
13665 .lsp_adapters(&language.name())
13666 .first()
13667 .cloned()
13668 });
13669 if let Some(lsp_adapter) = lsp_adapter {
13670 labels = lsp_adapter
13671 .labels_for_symbols(&label_params, &language)
13672 .await
13673 .log_err()
13674 .unwrap_or_default();
13675 }
13676 }
13677
13678 for ((symbol, (name, _)), label) in symbols
13679 .into_iter()
13680 .zip(label_params.drain(..))
13681 .zip(labels.into_iter().chain(iter::repeat(None)))
13682 {
13683 output.push(Symbol {
13684 language_server_name: symbol.language_server_name,
13685 source_worktree_id: symbol.source_worktree_id,
13686 source_language_server_id: symbol.source_language_server_id,
13687 path: symbol.path,
13688 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13689 name,
13690 kind: symbol.kind,
13691 range: symbol.range,
13692 });
13693 }
13694 }
13695}
13696
13697fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13698 match server.capabilities().text_document_sync.as_ref()? {
13699 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13700 // Server wants didSave but didn't specify includeText.
13701 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13702 // Server doesn't want didSave at all.
13703 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13704 // Server provided SaveOptions.
13705 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13706 Some(save_options.include_text.unwrap_or(false))
13707 }
13708 },
13709 // We do not have any save info. Kind affects didChange only.
13710 lsp::TextDocumentSyncCapability::Kind(_) => None,
13711 }
13712}
13713
13714/// Completion items are displayed in a `UniformList`.
13715/// Usually, those items are single-line strings, but in LSP responses,
13716/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13717/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13718/// 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,
13719/// breaking the completions menu presentation.
13720///
13721/// 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.
13722fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13723 let mut new_text = String::with_capacity(label.text.len());
13724 let mut offset_map = vec![0; label.text.len() + 1];
13725 let mut last_char_was_space = false;
13726 let mut new_idx = 0;
13727 let chars = label.text.char_indices().fuse();
13728 let mut newlines_removed = false;
13729
13730 for (idx, c) in chars {
13731 offset_map[idx] = new_idx;
13732
13733 match c {
13734 '\n' if last_char_was_space => {
13735 newlines_removed = true;
13736 }
13737 '\t' | ' ' if last_char_was_space => {}
13738 '\n' if !last_char_was_space => {
13739 new_text.push(' ');
13740 new_idx += 1;
13741 last_char_was_space = true;
13742 newlines_removed = true;
13743 }
13744 ' ' | '\t' => {
13745 new_text.push(' ');
13746 new_idx += 1;
13747 last_char_was_space = true;
13748 }
13749 _ => {
13750 new_text.push(c);
13751 new_idx += c.len_utf8();
13752 last_char_was_space = false;
13753 }
13754 }
13755 }
13756 offset_map[label.text.len()] = new_idx;
13757
13758 // Only modify the label if newlines were removed.
13759 if !newlines_removed {
13760 return;
13761 }
13762
13763 let last_index = new_idx;
13764 let mut run_ranges_errors = Vec::new();
13765 label.runs.retain_mut(|(range, _)| {
13766 match offset_map.get(range.start) {
13767 Some(&start) => range.start = start,
13768 None => {
13769 run_ranges_errors.push(range.clone());
13770 return false;
13771 }
13772 }
13773
13774 match offset_map.get(range.end) {
13775 Some(&end) => range.end = end,
13776 None => {
13777 run_ranges_errors.push(range.clone());
13778 range.end = last_index;
13779 }
13780 }
13781 true
13782 });
13783 if !run_ranges_errors.is_empty() {
13784 log::error!(
13785 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13786 label.text
13787 );
13788 }
13789
13790 let mut wrong_filter_range = None;
13791 if label.filter_range == (0..label.text.len()) {
13792 label.filter_range = 0..new_text.len();
13793 } else {
13794 let mut original_filter_range = Some(label.filter_range.clone());
13795 match offset_map.get(label.filter_range.start) {
13796 Some(&start) => label.filter_range.start = start,
13797 None => {
13798 wrong_filter_range = original_filter_range.take();
13799 label.filter_range.start = last_index;
13800 }
13801 }
13802
13803 match offset_map.get(label.filter_range.end) {
13804 Some(&end) => label.filter_range.end = end,
13805 None => {
13806 wrong_filter_range = original_filter_range.take();
13807 label.filter_range.end = last_index;
13808 }
13809 }
13810 }
13811 if let Some(wrong_filter_range) = wrong_filter_range {
13812 log::error!(
13813 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13814 label.text
13815 );
13816 }
13817
13818 label.text = new_text;
13819}
13820
13821#[cfg(test)]
13822mod tests {
13823 use language::HighlightId;
13824
13825 use super::*;
13826
13827 #[test]
13828 fn test_glob_literal_prefix() {
13829 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13830 assert_eq!(
13831 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13832 Path::new("node_modules")
13833 );
13834 assert_eq!(
13835 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13836 Path::new("foo")
13837 );
13838 assert_eq!(
13839 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13840 Path::new("foo/bar/baz.js")
13841 );
13842
13843 #[cfg(target_os = "windows")]
13844 {
13845 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13846 assert_eq!(
13847 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13848 Path::new("node_modules")
13849 );
13850 assert_eq!(
13851 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13852 Path::new("foo")
13853 );
13854 assert_eq!(
13855 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13856 Path::new("foo/bar/baz.js")
13857 );
13858 }
13859 }
13860
13861 #[test]
13862 fn test_multi_len_chars_normalization() {
13863 let mut label = CodeLabel::new(
13864 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13865 0..6,
13866 vec![(0..6, HighlightId(1))],
13867 );
13868 ensure_uniform_list_compatible_label(&mut label);
13869 assert_eq!(
13870 label,
13871 CodeLabel::new(
13872 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13873 0..6,
13874 vec![(0..6, HighlightId(1))],
13875 )
13876 );
13877 }
13878}