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