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