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