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