1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default, Debug)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = &settings.binary
567 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
568 {
569 let settings = settings.clone();
570
571 return cx.background_spawn(async move {
572 let mut env = delegate.shell_env().await;
573 env.extend(settings.env.unwrap_or_default());
574
575 Ok(LanguageServerBinary {
576 path: delegate.resolve_executable_path(path),
577 env: Some(env),
578 arguments: settings
579 .arguments
580 .unwrap_or_default()
581 .iter()
582 .map(Into::into)
583 .collect(),
584 })
585 });
586 }
587 let lsp_binary_options = LanguageServerBinaryOptions {
588 allow_path_lookup: !settings
589 .binary
590 .as_ref()
591 .and_then(|b| b.ignore_system_version)
592 .unwrap_or_default(),
593 allow_binary_download,
594 pre_release: settings
595 .fetch
596 .as_ref()
597 .and_then(|f| f.pre_release)
598 .unwrap_or(false),
599 };
600
601 cx.spawn(async move |cx| {
602 let binary_result = adapter
603 .clone()
604 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
605 .await;
606
607 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
608
609 let mut binary = binary_result?;
610 let mut shell_env = delegate.shell_env().await;
611
612 shell_env.extend(binary.env.unwrap_or_default());
613
614 if let Some(settings) = settings.binary.as_ref() {
615 if let Some(arguments) = &settings.arguments {
616 binary.arguments = arguments.iter().map(Into::into).collect();
617 }
618 if let Some(env) = &settings.env {
619 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
620 }
621 }
622
623 binary.env = Some(shell_env);
624 Ok(binary)
625 })
626 }
627
628 fn setup_lsp_messages(
629 lsp_store: WeakEntity<LspStore>,
630 language_server: &LanguageServer,
631 delegate: Arc<dyn LspAdapterDelegate>,
632 adapter: Arc<CachedLspAdapter>,
633 ) {
634 let name = language_server.name();
635 let server_id = language_server.server_id();
636 language_server
637 .on_notification::<lsp::notification::PublishDiagnostics, _>({
638 let adapter = adapter.clone();
639 let this = lsp_store.clone();
640 move |mut params, cx| {
641 let adapter = adapter.clone();
642 if let Some(this) = this.upgrade() {
643 this.update(cx, |this, cx| {
644 {
645 let buffer = params
646 .uri
647 .to_file_path()
648 .map(|file_path| this.get_buffer(&file_path, cx))
649 .ok()
650 .flatten();
651 adapter.process_diagnostics(&mut params, server_id, buffer);
652 }
653
654 this.merge_lsp_diagnostics(
655 DiagnosticSourceKind::Pushed,
656 vec![DocumentDiagnosticsUpdate {
657 server_id,
658 diagnostics: params,
659 result_id: None,
660 disk_based_sources: Cow::Borrowed(
661 &adapter.disk_based_diagnostic_sources,
662 ),
663 }],
664 |_, diagnostic, cx| match diagnostic.source_kind {
665 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
666 adapter.retain_old_diagnostic(diagnostic, cx)
667 }
668 DiagnosticSourceKind::Pulled => true,
669 },
670 cx,
671 )
672 .log_err();
673 })
674 .ok();
675 }
676 }
677 })
678 .detach();
679 language_server
680 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
681 let adapter = adapter.adapter.clone();
682 let delegate = delegate.clone();
683 let this = lsp_store.clone();
684 move |params, cx| {
685 let adapter = adapter.clone();
686 let delegate = delegate.clone();
687 let this = this.clone();
688 let mut cx = cx.clone();
689 async move {
690 let toolchain_for_id = this
691 .update(&mut cx, |this, _| {
692 this.as_local()?.language_server_ids.iter().find_map(
693 |(seed, value)| {
694 (value.id == server_id).then(|| seed.toolchain.clone())
695 },
696 )
697 })?
698 .context("Expected the LSP store to be in a local mode")?;
699 let workspace_config = Self::workspace_configuration_for_adapter(
700 adapter.clone(),
701 &delegate,
702 toolchain_for_id,
703 &mut cx,
704 )
705 .await?;
706
707 Ok(params
708 .items
709 .into_iter()
710 .map(|item| {
711 if let Some(section) = &item.section {
712 workspace_config
713 .get(section)
714 .cloned()
715 .unwrap_or(serde_json::Value::Null)
716 } else {
717 workspace_config.clone()
718 }
719 })
720 .collect())
721 }
722 }
723 })
724 .detach();
725
726 language_server
727 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
728 let this = lsp_store.clone();
729 move |_, cx| {
730 let this = this.clone();
731 let cx = cx.clone();
732 async move {
733 let Some(server) =
734 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
735 else {
736 return Ok(None);
737 };
738 let root = server.workspace_folders();
739 Ok(Some(
740 root.into_iter()
741 .map(|uri| WorkspaceFolder {
742 uri,
743 name: Default::default(),
744 })
745 .collect(),
746 ))
747 }
748 }
749 })
750 .detach();
751 // Even though we don't have handling for these requests, respond to them to
752 // avoid stalling any language server like `gopls` which waits for a response
753 // to these requests when initializing.
754 language_server
755 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
756 let this = lsp_store.clone();
757 move |params, cx| {
758 let this = this.clone();
759 let mut cx = cx.clone();
760 async move {
761 this.update(&mut cx, |this, _| {
762 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
763 {
764 status
765 .progress_tokens
766 .insert(ProgressToken::from_lsp(params.token));
767 }
768 })?;
769
770 Ok(())
771 }
772 }
773 })
774 .detach();
775
776 language_server
777 .on_request::<lsp::request::RegisterCapability, _, _>({
778 let lsp_store = lsp_store.clone();
779 move |params, cx| {
780 let lsp_store = lsp_store.clone();
781 let mut cx = cx.clone();
782 async move {
783 lsp_store
784 .update(&mut cx, |lsp_store, cx| {
785 if lsp_store.as_local().is_some() {
786 match lsp_store
787 .register_server_capabilities(server_id, params, cx)
788 {
789 Ok(()) => {}
790 Err(e) => {
791 log::error!(
792 "Failed to register server capabilities: {e:#}"
793 );
794 }
795 };
796 }
797 })
798 .ok();
799 Ok(())
800 }
801 }
802 })
803 .detach();
804
805 language_server
806 .on_request::<lsp::request::UnregisterCapability, _, _>({
807 let lsp_store = lsp_store.clone();
808 move |params, cx| {
809 let lsp_store = lsp_store.clone();
810 let mut cx = cx.clone();
811 async move {
812 lsp_store
813 .update(&mut cx, |lsp_store, cx| {
814 if lsp_store.as_local().is_some() {
815 match lsp_store
816 .unregister_server_capabilities(server_id, params, cx)
817 {
818 Ok(()) => {}
819 Err(e) => {
820 log::error!(
821 "Failed to unregister server capabilities: {e:#}"
822 );
823 }
824 }
825 }
826 })
827 .ok();
828 Ok(())
829 }
830 }
831 })
832 .detach();
833
834 language_server
835 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
836 let this = lsp_store.clone();
837 move |params, cx| {
838 let mut cx = cx.clone();
839 let this = this.clone();
840 async move {
841 LocalLspStore::on_lsp_workspace_edit(
842 this.clone(),
843 params,
844 server_id,
845 &mut cx,
846 )
847 .await
848 }
849 }
850 })
851 .detach();
852
853 language_server
854 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
855 let lsp_store = lsp_store.clone();
856 let request_id = Arc::new(AtomicUsize::new(0));
857 move |(), cx| {
858 let lsp_store = lsp_store.clone();
859 let request_id = request_id.clone();
860 let mut cx = cx.clone();
861 async move {
862 lsp_store
863 .update(&mut cx, |lsp_store, cx| {
864 let request_id =
865 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
866 cx.emit(LspStoreEvent::RefreshInlayHints {
867 server_id,
868 request_id,
869 });
870 lsp_store
871 .downstream_client
872 .as_ref()
873 .map(|(client, project_id)| {
874 client.send(proto::RefreshInlayHints {
875 project_id: *project_id,
876 server_id: server_id.to_proto(),
877 request_id: request_id.map(|id| id as u64),
878 })
879 })
880 })?
881 .transpose()?;
882 Ok(())
883 }
884 }
885 })
886 .detach();
887
888 language_server
889 .on_request::<lsp::request::CodeLensRefresh, _, _>({
890 let this = lsp_store.clone();
891 move |(), cx| {
892 let this = this.clone();
893 let mut cx = cx.clone();
894 async move {
895 this.update(&mut cx, |this, cx| {
896 cx.emit(LspStoreEvent::RefreshCodeLens);
897 this.downstream_client.as_ref().map(|(client, project_id)| {
898 client.send(proto::RefreshCodeLens {
899 project_id: *project_id,
900 })
901 })
902 })?
903 .transpose()?;
904 Ok(())
905 }
906 }
907 })
908 .detach();
909
910 language_server
911 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
912 let this = lsp_store.clone();
913 move |(), cx| {
914 let this = this.clone();
915 let mut cx = cx.clone();
916 async move {
917 this.update(&mut cx, |lsp_store, _| {
918 lsp_store.pull_workspace_diagnostics(server_id);
919 lsp_store
920 .downstream_client
921 .as_ref()
922 .map(|(client, project_id)| {
923 client.send(proto::PullWorkspaceDiagnostics {
924 project_id: *project_id,
925 server_id: server_id.to_proto(),
926 })
927 })
928 })?
929 .transpose()?;
930 Ok(())
931 }
932 }
933 })
934 .detach();
935
936 language_server
937 .on_request::<lsp::request::ShowMessageRequest, _, _>({
938 let this = lsp_store.clone();
939 let name = name.to_string();
940 move |params, cx| {
941 let this = this.clone();
942 let name = name.to_string();
943 let mut cx = cx.clone();
944 async move {
945 let actions = params.actions.unwrap_or_default();
946 let (tx, rx) = smol::channel::bounded(1);
947 let request = LanguageServerPromptRequest {
948 level: match params.typ {
949 lsp::MessageType::ERROR => PromptLevel::Critical,
950 lsp::MessageType::WARNING => PromptLevel::Warning,
951 _ => PromptLevel::Info,
952 },
953 message: params.message,
954 actions,
955 response_channel: tx,
956 lsp_name: name.clone(),
957 };
958
959 let did_update = this
960 .update(&mut cx, |_, cx| {
961 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
962 })
963 .is_ok();
964 if did_update {
965 let response = rx.recv().await.ok();
966 Ok(response)
967 } else {
968 Ok(None)
969 }
970 }
971 }
972 })
973 .detach();
974 language_server
975 .on_notification::<lsp::notification::ShowMessage, _>({
976 let this = lsp_store.clone();
977 let name = name.to_string();
978 move |params, cx| {
979 let this = this.clone();
980 let name = name.to_string();
981 let mut cx = cx.clone();
982
983 let (tx, _) = smol::channel::bounded(1);
984 let request = LanguageServerPromptRequest {
985 level: match params.typ {
986 lsp::MessageType::ERROR => PromptLevel::Critical,
987 lsp::MessageType::WARNING => PromptLevel::Warning,
988 _ => PromptLevel::Info,
989 },
990 message: params.message,
991 actions: vec![],
992 response_channel: tx,
993 lsp_name: name,
994 };
995
996 let _ = this.update(&mut cx, |_, cx| {
997 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
998 });
999 }
1000 })
1001 .detach();
1002
1003 let disk_based_diagnostics_progress_token =
1004 adapter.disk_based_diagnostics_progress_token.clone();
1005
1006 language_server
1007 .on_notification::<lsp::notification::Progress, _>({
1008 let this = lsp_store.clone();
1009 move |params, cx| {
1010 if let Some(this) = this.upgrade() {
1011 this.update(cx, |this, cx| {
1012 this.on_lsp_progress(
1013 params,
1014 server_id,
1015 disk_based_diagnostics_progress_token.clone(),
1016 cx,
1017 );
1018 })
1019 .ok();
1020 }
1021 }
1022 })
1023 .detach();
1024
1025 language_server
1026 .on_notification::<lsp::notification::LogMessage, _>({
1027 let this = lsp_store.clone();
1028 move |params, cx| {
1029 if let Some(this) = this.upgrade() {
1030 this.update(cx, |_, cx| {
1031 cx.emit(LspStoreEvent::LanguageServerLog(
1032 server_id,
1033 LanguageServerLogType::Log(params.typ),
1034 params.message,
1035 ));
1036 })
1037 .ok();
1038 }
1039 }
1040 })
1041 .detach();
1042
1043 language_server
1044 .on_notification::<lsp::notification::LogTrace, _>({
1045 let this = lsp_store.clone();
1046 move |params, cx| {
1047 let mut cx = cx.clone();
1048 if let Some(this) = this.upgrade() {
1049 this.update(&mut cx, |_, cx| {
1050 cx.emit(LspStoreEvent::LanguageServerLog(
1051 server_id,
1052 LanguageServerLogType::Trace {
1053 verbose_info: params.verbose,
1054 },
1055 params.message,
1056 ));
1057 })
1058 .ok();
1059 }
1060 }
1061 })
1062 .detach();
1063
1064 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1065 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1066 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1067 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1068 }
1069
1070 fn shutdown_language_servers_on_quit(
1071 &mut self,
1072 _: &mut Context<LspStore>,
1073 ) -> impl Future<Output = ()> + use<> {
1074 let shutdown_futures = self
1075 .language_servers
1076 .drain()
1077 .map(|(_, server_state)| Self::shutdown_server(server_state))
1078 .collect::<Vec<_>>();
1079
1080 async move {
1081 join_all(shutdown_futures).await;
1082 }
1083 }
1084
1085 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1086 match server_state {
1087 LanguageServerState::Running { server, .. } => {
1088 if let Some(shutdown) = server.shutdown() {
1089 shutdown.await;
1090 }
1091 }
1092 LanguageServerState::Starting { startup, .. } => {
1093 if let Some(server) = startup.await
1094 && let Some(shutdown) = server.shutdown()
1095 {
1096 shutdown.await;
1097 }
1098 }
1099 }
1100 Ok(())
1101 }
1102
1103 fn language_servers_for_worktree(
1104 &self,
1105 worktree_id: WorktreeId,
1106 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1107 self.language_server_ids
1108 .iter()
1109 .filter_map(move |(seed, state)| {
1110 if seed.worktree_id != worktree_id {
1111 return None;
1112 }
1113
1114 if let Some(LanguageServerState::Running { server, .. }) =
1115 self.language_servers.get(&state.id)
1116 {
1117 Some(server)
1118 } else {
1119 None
1120 }
1121 })
1122 }
1123
1124 fn language_server_ids_for_project_path(
1125 &self,
1126 project_path: ProjectPath,
1127 language: &Language,
1128 cx: &mut App,
1129 ) -> Vec<LanguageServerId> {
1130 let Some(worktree) = self
1131 .worktree_store
1132 .read(cx)
1133 .worktree_for_id(project_path.worktree_id, cx)
1134 else {
1135 return Vec::new();
1136 };
1137 let delegate: Arc<dyn ManifestDelegate> =
1138 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1139
1140 self.lsp_tree
1141 .get(
1142 project_path,
1143 language.name(),
1144 language.manifest(),
1145 &delegate,
1146 cx,
1147 )
1148 .collect::<Vec<_>>()
1149 }
1150
1151 fn language_server_ids_for_buffer(
1152 &self,
1153 buffer: &Buffer,
1154 cx: &mut App,
1155 ) -> Vec<LanguageServerId> {
1156 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1157 let worktree_id = file.worktree_id(cx);
1158
1159 let path: Arc<RelPath> = file
1160 .path()
1161 .parent()
1162 .map(Arc::from)
1163 .unwrap_or_else(|| file.path().clone());
1164 let worktree_path = ProjectPath { worktree_id, path };
1165 self.language_server_ids_for_project_path(worktree_path, language, cx)
1166 } else {
1167 Vec::new()
1168 }
1169 }
1170
1171 fn language_servers_for_buffer<'a>(
1172 &'a self,
1173 buffer: &'a Buffer,
1174 cx: &'a mut App,
1175 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1176 self.language_server_ids_for_buffer(buffer, cx)
1177 .into_iter()
1178 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1179 LanguageServerState::Running {
1180 adapter, server, ..
1181 } => Some((adapter, server)),
1182 _ => None,
1183 })
1184 }
1185
1186 async fn execute_code_action_kind_locally(
1187 lsp_store: WeakEntity<LspStore>,
1188 mut buffers: Vec<Entity<Buffer>>,
1189 kind: CodeActionKind,
1190 push_to_history: bool,
1191 cx: &mut AsyncApp,
1192 ) -> anyhow::Result<ProjectTransaction> {
1193 // Do not allow multiple concurrent code actions requests for the
1194 // same buffer.
1195 lsp_store.update(cx, |this, cx| {
1196 let this = this.as_local_mut().unwrap();
1197 buffers.retain(|buffer| {
1198 this.buffers_being_formatted
1199 .insert(buffer.read(cx).remote_id())
1200 });
1201 })?;
1202 let _cleanup = defer({
1203 let this = lsp_store.clone();
1204 let mut cx = cx.clone();
1205 let buffers = &buffers;
1206 move || {
1207 this.update(&mut cx, |this, cx| {
1208 let this = this.as_local_mut().unwrap();
1209 for buffer in buffers {
1210 this.buffers_being_formatted
1211 .remove(&buffer.read(cx).remote_id());
1212 }
1213 })
1214 .ok();
1215 }
1216 });
1217 let mut project_transaction = ProjectTransaction::default();
1218
1219 for buffer in &buffers {
1220 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1221 buffer.update(cx, |buffer, cx| {
1222 lsp_store
1223 .as_local()
1224 .unwrap()
1225 .language_servers_for_buffer(buffer, cx)
1226 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1227 .collect::<Vec<_>>()
1228 })
1229 })?;
1230 for (_, language_server) in adapters_and_servers.iter() {
1231 let actions = Self::get_server_code_actions_from_action_kinds(
1232 &lsp_store,
1233 language_server.server_id(),
1234 vec![kind.clone()],
1235 buffer,
1236 cx,
1237 )
1238 .await?;
1239 Self::execute_code_actions_on_server(
1240 &lsp_store,
1241 language_server,
1242 actions,
1243 push_to_history,
1244 &mut project_transaction,
1245 cx,
1246 )
1247 .await?;
1248 }
1249 }
1250 Ok(project_transaction)
1251 }
1252
1253 async fn format_locally(
1254 lsp_store: WeakEntity<LspStore>,
1255 mut buffers: Vec<FormattableBuffer>,
1256 push_to_history: bool,
1257 trigger: FormatTrigger,
1258 logger: zlog::Logger,
1259 cx: &mut AsyncApp,
1260 ) -> anyhow::Result<ProjectTransaction> {
1261 // Do not allow multiple concurrent formatting requests for the
1262 // same buffer.
1263 lsp_store.update(cx, |this, cx| {
1264 let this = this.as_local_mut().unwrap();
1265 buffers.retain(|buffer| {
1266 this.buffers_being_formatted
1267 .insert(buffer.handle.read(cx).remote_id())
1268 });
1269 })?;
1270
1271 let _cleanup = defer({
1272 let this = lsp_store.clone();
1273 let mut cx = cx.clone();
1274 let buffers = &buffers;
1275 move || {
1276 this.update(&mut cx, |this, cx| {
1277 let this = this.as_local_mut().unwrap();
1278 for buffer in buffers {
1279 this.buffers_being_formatted
1280 .remove(&buffer.handle.read(cx).remote_id());
1281 }
1282 })
1283 .ok();
1284 }
1285 });
1286
1287 let mut project_transaction = ProjectTransaction::default();
1288
1289 for buffer in &buffers {
1290 zlog::debug!(
1291 logger =>
1292 "formatting buffer '{:?}'",
1293 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1294 );
1295 // Create an empty transaction to hold all of the formatting edits.
1296 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1297 // ensure no transactions created while formatting are
1298 // grouped with the previous transaction in the history
1299 // based on the transaction group interval
1300 buffer.finalize_last_transaction();
1301 buffer
1302 .start_transaction()
1303 .context("transaction already open")?;
1304 buffer.end_transaction(cx);
1305 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1306 buffer.finalize_last_transaction();
1307 anyhow::Ok(transaction_id)
1308 })??;
1309
1310 let result = Self::format_buffer_locally(
1311 lsp_store.clone(),
1312 buffer,
1313 formatting_transaction_id,
1314 trigger,
1315 logger,
1316 cx,
1317 )
1318 .await;
1319
1320 buffer.handle.update(cx, |buffer, cx| {
1321 let Some(formatting_transaction) =
1322 buffer.get_transaction(formatting_transaction_id).cloned()
1323 else {
1324 zlog::warn!(logger => "no formatting transaction");
1325 return;
1326 };
1327 if formatting_transaction.edit_ids.is_empty() {
1328 zlog::debug!(logger => "no changes made while formatting");
1329 buffer.forget_transaction(formatting_transaction_id);
1330 return;
1331 }
1332 if !push_to_history {
1333 zlog::trace!(logger => "forgetting format transaction");
1334 buffer.forget_transaction(formatting_transaction.id);
1335 }
1336 project_transaction
1337 .0
1338 .insert(cx.entity(), formatting_transaction);
1339 })?;
1340
1341 result?;
1342 }
1343
1344 Ok(project_transaction)
1345 }
1346
1347 async fn format_buffer_locally(
1348 lsp_store: WeakEntity<LspStore>,
1349 buffer: &FormattableBuffer,
1350 formatting_transaction_id: clock::Lamport,
1351 trigger: FormatTrigger,
1352 logger: zlog::Logger,
1353 cx: &mut AsyncApp,
1354 ) -> Result<()> {
1355 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1356 buffer.handle.update(cx, |buffer, cx| {
1357 let adapters_and_servers = lsp_store
1358 .as_local()
1359 .unwrap()
1360 .language_servers_for_buffer(buffer, cx)
1361 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1362 .collect::<Vec<_>>();
1363 let settings =
1364 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1365 .into_owned();
1366 (adapters_and_servers, settings)
1367 })
1368 })?;
1369
1370 /// Apply edits to the buffer that will become part of the formatting transaction.
1371 /// Fails if the buffer has been edited since the start of that transaction.
1372 fn extend_formatting_transaction(
1373 buffer: &FormattableBuffer,
1374 formatting_transaction_id: text::TransactionId,
1375 cx: &mut AsyncApp,
1376 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1377 ) -> anyhow::Result<()> {
1378 buffer.handle.update(cx, |buffer, cx| {
1379 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1380 if last_transaction_id != Some(formatting_transaction_id) {
1381 anyhow::bail!("Buffer edited while formatting. Aborting")
1382 }
1383 buffer.start_transaction();
1384 operation(buffer, cx);
1385 if let Some(transaction_id) = buffer.end_transaction(cx) {
1386 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1387 }
1388 Ok(())
1389 })?
1390 }
1391
1392 // handle whitespace formatting
1393 if settings.remove_trailing_whitespace_on_save {
1394 zlog::trace!(logger => "removing trailing whitespace");
1395 let diff = buffer
1396 .handle
1397 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1398 .await;
1399 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1400 buffer.apply_diff(diff, cx);
1401 })?;
1402 }
1403
1404 if settings.ensure_final_newline_on_save {
1405 zlog::trace!(logger => "ensuring final newline");
1406 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1407 buffer.ensure_final_newline(cx);
1408 })?;
1409 }
1410
1411 // Formatter for `code_actions_on_format` that runs before
1412 // the rest of the formatters
1413 let mut code_actions_on_format_formatters = None;
1414 let should_run_code_actions_on_format = !matches!(
1415 (trigger, &settings.format_on_save),
1416 (FormatTrigger::Save, &FormatOnSave::Off)
1417 );
1418 if should_run_code_actions_on_format {
1419 let have_code_actions_to_run_on_format = settings
1420 .code_actions_on_format
1421 .values()
1422 .any(|enabled| *enabled);
1423 if have_code_actions_to_run_on_format {
1424 zlog::trace!(logger => "going to run code actions on format");
1425 code_actions_on_format_formatters = Some(
1426 settings
1427 .code_actions_on_format
1428 .iter()
1429 .filter_map(|(action, enabled)| enabled.then_some(action))
1430 .cloned()
1431 .map(Formatter::CodeAction)
1432 .collect::<Vec<_>>(),
1433 );
1434 }
1435 }
1436
1437 let formatters = match (trigger, &settings.format_on_save) {
1438 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1439 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1440 settings.formatter.as_ref()
1441 }
1442 };
1443
1444 let formatters = code_actions_on_format_formatters
1445 .iter()
1446 .flatten()
1447 .chain(formatters);
1448
1449 for formatter in formatters {
1450 let formatter = if formatter == &Formatter::Auto {
1451 if settings.prettier.allowed {
1452 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1453 &Formatter::Prettier
1454 } else {
1455 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1456 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1457 }
1458 } else {
1459 formatter
1460 };
1461 match formatter {
1462 Formatter::Auto => unreachable!("Auto resolved above"),
1463 Formatter::Prettier => {
1464 let logger = zlog::scoped!(logger => "prettier");
1465 zlog::trace!(logger => "formatting");
1466 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1467
1468 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1469 lsp_store.prettier_store().unwrap().downgrade()
1470 })?;
1471 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1472 .await
1473 .transpose()?;
1474 let Some(diff) = diff else {
1475 zlog::trace!(logger => "No changes");
1476 continue;
1477 };
1478
1479 extend_formatting_transaction(
1480 buffer,
1481 formatting_transaction_id,
1482 cx,
1483 |buffer, cx| {
1484 buffer.apply_diff(diff, cx);
1485 },
1486 )?;
1487 }
1488 Formatter::External { command, arguments } => {
1489 let logger = zlog::scoped!(logger => "command");
1490 zlog::trace!(logger => "formatting");
1491 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1492
1493 let diff = Self::format_via_external_command(
1494 buffer,
1495 command.as_ref(),
1496 arguments.as_deref(),
1497 cx,
1498 )
1499 .await
1500 .with_context(|| {
1501 format!("Failed to format buffer via external command: {}", command)
1502 })?;
1503 let Some(diff) = diff else {
1504 zlog::trace!(logger => "No changes");
1505 continue;
1506 };
1507
1508 extend_formatting_transaction(
1509 buffer,
1510 formatting_transaction_id,
1511 cx,
1512 |buffer, cx| {
1513 buffer.apply_diff(diff, cx);
1514 },
1515 )?;
1516 }
1517 Formatter::LanguageServer(specifier) => {
1518 let logger = zlog::scoped!(logger => "language-server");
1519 zlog::trace!(logger => "formatting");
1520 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1521
1522 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1523 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1524 continue;
1525 };
1526
1527 let language_server = match specifier {
1528 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1529 adapters_and_servers.iter().find_map(|(adapter, server)| {
1530 if adapter.name.0.as_ref() == name {
1531 Some(server.clone())
1532 } else {
1533 None
1534 }
1535 })
1536 }
1537 settings::LanguageServerFormatterSpecifier::Current => {
1538 adapters_and_servers.first().map(|e| e.1.clone())
1539 }
1540 };
1541
1542 let Some(language_server) = language_server else {
1543 log::debug!(
1544 "No language server found to format buffer '{:?}'. Skipping",
1545 buffer_path_abs.as_path().to_string_lossy()
1546 );
1547 continue;
1548 };
1549
1550 zlog::trace!(
1551 logger =>
1552 "Formatting buffer '{:?}' using language server '{:?}'",
1553 buffer_path_abs.as_path().to_string_lossy(),
1554 language_server.name()
1555 );
1556
1557 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1558 zlog::trace!(logger => "formatting ranges");
1559 Self::format_ranges_via_lsp(
1560 &lsp_store,
1561 &buffer.handle,
1562 ranges,
1563 buffer_path_abs,
1564 &language_server,
1565 &settings,
1566 cx,
1567 )
1568 .await
1569 .context("Failed to format ranges via language server")?
1570 } else {
1571 zlog::trace!(logger => "formatting full");
1572 Self::format_via_lsp(
1573 &lsp_store,
1574 &buffer.handle,
1575 buffer_path_abs,
1576 &language_server,
1577 &settings,
1578 cx,
1579 )
1580 .await
1581 .context("failed to format via language server")?
1582 };
1583
1584 if edits.is_empty() {
1585 zlog::trace!(logger => "No changes");
1586 continue;
1587 }
1588 extend_formatting_transaction(
1589 buffer,
1590 formatting_transaction_id,
1591 cx,
1592 |buffer, cx| {
1593 buffer.edit(edits, None, cx);
1594 },
1595 )?;
1596 }
1597 Formatter::CodeAction(code_action_name) => {
1598 let logger = zlog::scoped!(logger => "code-actions");
1599 zlog::trace!(logger => "formatting");
1600 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1601
1602 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1603 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1604 continue;
1605 };
1606
1607 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1608 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1609
1610 let mut actions_and_servers = Vec::new();
1611
1612 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1613 let actions_result = Self::get_server_code_actions_from_action_kinds(
1614 &lsp_store,
1615 language_server.server_id(),
1616 vec![code_action_kind.clone()],
1617 &buffer.handle,
1618 cx,
1619 )
1620 .await
1621 .with_context(|| {
1622 format!(
1623 "Failed to resolve code action {:?} with language server {}",
1624 code_action_kind,
1625 language_server.name()
1626 )
1627 });
1628 let Ok(actions) = actions_result else {
1629 // note: it may be better to set result to the error and break formatters here
1630 // but for now we try to execute the actions that we can resolve and skip the rest
1631 zlog::error!(
1632 logger =>
1633 "Failed to resolve code action {:?} with language server {}",
1634 code_action_kind,
1635 language_server.name()
1636 );
1637 continue;
1638 };
1639 for action in actions {
1640 actions_and_servers.push((action, index));
1641 }
1642 }
1643
1644 if actions_and_servers.is_empty() {
1645 zlog::warn!(logger => "No code actions were resolved, continuing");
1646 continue;
1647 }
1648
1649 'actions: for (mut action, server_index) in actions_and_servers {
1650 let server = &adapters_and_servers[server_index].1;
1651
1652 let describe_code_action = |action: &CodeAction| {
1653 format!(
1654 "code action '{}' with title \"{}\" on server {}",
1655 action
1656 .lsp_action
1657 .action_kind()
1658 .unwrap_or("unknown".into())
1659 .as_str(),
1660 action.lsp_action.title(),
1661 server.name(),
1662 )
1663 };
1664
1665 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1666
1667 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1668 zlog::error!(
1669 logger =>
1670 "Failed to resolve {}. Error: {}",
1671 describe_code_action(&action),
1672 err
1673 );
1674 continue;
1675 }
1676
1677 if let Some(edit) = action.lsp_action.edit().cloned() {
1678 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1679 // but filters out and logs warnings for code actions that require unreasonably
1680 // difficult handling on our part, such as:
1681 // - applying edits that call commands
1682 // which can result in arbitrary workspace edits being sent from the server that
1683 // have no way of being tied back to the command that initiated them (i.e. we
1684 // can't know which edits are part of the format request, or if the server is done sending
1685 // actions in response to the command)
1686 // - actions that create/delete/modify/rename files other than the one we are formatting
1687 // as we then would need to handle such changes correctly in the local history as well
1688 // as the remote history through the ProjectTransaction
1689 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1690 // Supporting these actions is not impossible, but not supported as of yet.
1691 if edit.changes.is_none() && edit.document_changes.is_none() {
1692 zlog::trace!(
1693 logger =>
1694 "No changes for code action. Skipping {}",
1695 describe_code_action(&action),
1696 );
1697 continue;
1698 }
1699
1700 let mut operations = Vec::new();
1701 if let Some(document_changes) = edit.document_changes {
1702 match document_changes {
1703 lsp::DocumentChanges::Edits(edits) => operations.extend(
1704 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1705 ),
1706 lsp::DocumentChanges::Operations(ops) => operations = ops,
1707 }
1708 } else if let Some(changes) = edit.changes {
1709 operations.extend(changes.into_iter().map(|(uri, edits)| {
1710 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1711 text_document:
1712 lsp::OptionalVersionedTextDocumentIdentifier {
1713 uri,
1714 version: None,
1715 },
1716 edits: edits.into_iter().map(Edit::Plain).collect(),
1717 })
1718 }));
1719 }
1720
1721 let mut edits = Vec::with_capacity(operations.len());
1722
1723 if operations.is_empty() {
1724 zlog::trace!(
1725 logger =>
1726 "No changes for code action. Skipping {}",
1727 describe_code_action(&action),
1728 );
1729 continue;
1730 }
1731 for operation in operations {
1732 let op = match operation {
1733 lsp::DocumentChangeOperation::Edit(op) => op,
1734 lsp::DocumentChangeOperation::Op(_) => {
1735 zlog::warn!(
1736 logger =>
1737 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1738 describe_code_action(&action),
1739 );
1740 continue 'actions;
1741 }
1742 };
1743 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1744 zlog::warn!(
1745 logger =>
1746 "Failed to convert URI '{:?}' to file path. Skipping {}",
1747 &op.text_document.uri,
1748 describe_code_action(&action),
1749 );
1750 continue 'actions;
1751 };
1752 if &file_path != buffer_path_abs {
1753 zlog::warn!(
1754 logger =>
1755 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1756 file_path,
1757 buffer_path_abs,
1758 describe_code_action(&action),
1759 );
1760 continue 'actions;
1761 }
1762
1763 let mut lsp_edits = Vec::new();
1764 for edit in op.edits {
1765 match edit {
1766 Edit::Plain(edit) => {
1767 if !lsp_edits.contains(&edit) {
1768 lsp_edits.push(edit);
1769 }
1770 }
1771 Edit::Annotated(edit) => {
1772 if !lsp_edits.contains(&edit.text_edit) {
1773 lsp_edits.push(edit.text_edit);
1774 }
1775 }
1776 Edit::Snippet(_) => {
1777 zlog::warn!(
1778 logger =>
1779 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1780 describe_code_action(&action),
1781 );
1782 continue 'actions;
1783 }
1784 }
1785 }
1786 let edits_result = lsp_store
1787 .update(cx, |lsp_store, cx| {
1788 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1789 &buffer.handle,
1790 lsp_edits,
1791 server.server_id(),
1792 op.text_document.version,
1793 cx,
1794 )
1795 })?
1796 .await;
1797 let Ok(resolved_edits) = edits_result else {
1798 zlog::warn!(
1799 logger =>
1800 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1801 buffer_path_abs.as_path(),
1802 describe_code_action(&action),
1803 );
1804 continue 'actions;
1805 };
1806 edits.extend(resolved_edits);
1807 }
1808
1809 if edits.is_empty() {
1810 zlog::warn!(logger => "No edits resolved from LSP");
1811 continue;
1812 }
1813
1814 extend_formatting_transaction(
1815 buffer,
1816 formatting_transaction_id,
1817 cx,
1818 |buffer, cx| {
1819 zlog::info!(
1820 "Applying edits {edits:?}. Content: {:?}",
1821 buffer.text()
1822 );
1823 buffer.edit(edits, None, cx);
1824 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1825 },
1826 )?;
1827 }
1828
1829 if let Some(command) = action.lsp_action.command() {
1830 zlog::warn!(
1831 logger =>
1832 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1833 &command.command,
1834 );
1835
1836 // bail early if command is invalid
1837 let server_capabilities = server.capabilities();
1838 let available_commands = server_capabilities
1839 .execute_command_provider
1840 .as_ref()
1841 .map(|options| options.commands.as_slice())
1842 .unwrap_or_default();
1843 if !available_commands.contains(&command.command) {
1844 zlog::warn!(
1845 logger =>
1846 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1847 command.command,
1848 server.name(),
1849 );
1850 continue;
1851 }
1852
1853 // noop so we just ensure buffer hasn't been edited since resolving code actions
1854 extend_formatting_transaction(
1855 buffer,
1856 formatting_transaction_id,
1857 cx,
1858 |_, _| {},
1859 )?;
1860 zlog::info!(logger => "Executing command {}", &command.command);
1861
1862 lsp_store.update(cx, |this, _| {
1863 this.as_local_mut()
1864 .unwrap()
1865 .last_workspace_edits_by_language_server
1866 .remove(&server.server_id());
1867 })?;
1868
1869 let execute_command_result = server
1870 .request::<lsp::request::ExecuteCommand>(
1871 lsp::ExecuteCommandParams {
1872 command: command.command.clone(),
1873 arguments: command.arguments.clone().unwrap_or_default(),
1874 ..Default::default()
1875 },
1876 )
1877 .await
1878 .into_response();
1879
1880 if execute_command_result.is_err() {
1881 zlog::error!(
1882 logger =>
1883 "Failed to execute command '{}' as part of {}",
1884 &command.command,
1885 describe_code_action(&action),
1886 );
1887 continue 'actions;
1888 }
1889
1890 let mut project_transaction_command =
1891 lsp_store.update(cx, |this, _| {
1892 this.as_local_mut()
1893 .unwrap()
1894 .last_workspace_edits_by_language_server
1895 .remove(&server.server_id())
1896 .unwrap_or_default()
1897 })?;
1898
1899 if let Some(transaction) =
1900 project_transaction_command.0.remove(&buffer.handle)
1901 {
1902 zlog::trace!(
1903 logger =>
1904 "Successfully captured {} edits that resulted from command {}",
1905 transaction.edit_ids.len(),
1906 &command.command,
1907 );
1908 let transaction_id_project_transaction = transaction.id;
1909 buffer.handle.update(cx, |buffer, _| {
1910 // it may have been removed from history if push_to_history was
1911 // false in deserialize_workspace_edit. If so push it so we
1912 // can merge it with the format transaction
1913 // and pop the combined transaction off the history stack
1914 // later if push_to_history is false
1915 if buffer.get_transaction(transaction.id).is_none() {
1916 buffer.push_transaction(transaction, Instant::now());
1917 }
1918 buffer.merge_transactions(
1919 transaction_id_project_transaction,
1920 formatting_transaction_id,
1921 );
1922 })?;
1923 }
1924
1925 if !project_transaction_command.0.is_empty() {
1926 let mut extra_buffers = String::new();
1927 for buffer in project_transaction_command.0.keys() {
1928 buffer
1929 .read_with(cx, |b, cx| {
1930 if let Some(path) = b.project_path(cx) {
1931 if !extra_buffers.is_empty() {
1932 extra_buffers.push_str(", ");
1933 }
1934 extra_buffers.push_str(path.path.as_unix_str());
1935 }
1936 })
1937 .ok();
1938 }
1939 zlog::warn!(
1940 logger =>
1941 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1942 &command.command,
1943 extra_buffers,
1944 );
1945 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1946 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1947 // add it so it's included, and merge it into the format transaction when its created later
1948 }
1949 }
1950 }
1951 }
1952 }
1953 }
1954
1955 Ok(())
1956 }
1957
1958 pub async fn format_ranges_via_lsp(
1959 this: &WeakEntity<LspStore>,
1960 buffer_handle: &Entity<Buffer>,
1961 ranges: &[Range<Anchor>],
1962 abs_path: &Path,
1963 language_server: &Arc<LanguageServer>,
1964 settings: &LanguageSettings,
1965 cx: &mut AsyncApp,
1966 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1967 let capabilities = &language_server.capabilities();
1968 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1969 if range_formatting_provider == Some(&OneOf::Left(false)) {
1970 anyhow::bail!(
1971 "{} language server does not support range formatting",
1972 language_server.name()
1973 );
1974 }
1975
1976 let uri = file_path_to_lsp_url(abs_path)?;
1977 let text_document = lsp::TextDocumentIdentifier::new(uri);
1978
1979 let lsp_edits = {
1980 let mut lsp_ranges = Vec::new();
1981 this.update(cx, |_this, cx| {
1982 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1983 // not have been sent to the language server. This seems like a fairly systemic
1984 // issue, though, the resolution probably is not specific to formatting.
1985 //
1986 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1987 // LSP.
1988 let snapshot = buffer_handle.read(cx).snapshot();
1989 for range in ranges {
1990 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1991 }
1992 anyhow::Ok(())
1993 })??;
1994
1995 let mut edits = None;
1996 for range in lsp_ranges {
1997 if let Some(mut edit) = language_server
1998 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1999 text_document: text_document.clone(),
2000 range,
2001 options: lsp_command::lsp_formatting_options(settings),
2002 work_done_progress_params: Default::default(),
2003 })
2004 .await
2005 .into_response()?
2006 {
2007 edits.get_or_insert_with(Vec::new).append(&mut edit);
2008 }
2009 }
2010 edits
2011 };
2012
2013 if let Some(lsp_edits) = lsp_edits {
2014 this.update(cx, |this, cx| {
2015 this.as_local_mut().unwrap().edits_from_lsp(
2016 buffer_handle,
2017 lsp_edits,
2018 language_server.server_id(),
2019 None,
2020 cx,
2021 )
2022 })?
2023 .await
2024 } else {
2025 Ok(Vec::with_capacity(0))
2026 }
2027 }
2028
2029 async fn format_via_lsp(
2030 this: &WeakEntity<LspStore>,
2031 buffer: &Entity<Buffer>,
2032 abs_path: &Path,
2033 language_server: &Arc<LanguageServer>,
2034 settings: &LanguageSettings,
2035 cx: &mut AsyncApp,
2036 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2037 let logger = zlog::scoped!("lsp_format");
2038 zlog::debug!(logger => "Formatting via LSP");
2039
2040 let uri = file_path_to_lsp_url(abs_path)?;
2041 let text_document = lsp::TextDocumentIdentifier::new(uri);
2042 let capabilities = &language_server.capabilities();
2043
2044 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2045 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2046
2047 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2048 let _timer = zlog::time!(logger => "format-full");
2049 language_server
2050 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2051 text_document,
2052 options: lsp_command::lsp_formatting_options(settings),
2053 work_done_progress_params: Default::default(),
2054 })
2055 .await
2056 .into_response()?
2057 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2058 let _timer = zlog::time!(logger => "format-range");
2059 let buffer_start = lsp::Position::new(0, 0);
2060 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2061 language_server
2062 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2063 text_document: text_document.clone(),
2064 range: lsp::Range::new(buffer_start, buffer_end),
2065 options: lsp_command::lsp_formatting_options(settings),
2066 work_done_progress_params: Default::default(),
2067 })
2068 .await
2069 .into_response()?
2070 } else {
2071 None
2072 };
2073
2074 if let Some(lsp_edits) = lsp_edits {
2075 this.update(cx, |this, cx| {
2076 this.as_local_mut().unwrap().edits_from_lsp(
2077 buffer,
2078 lsp_edits,
2079 language_server.server_id(),
2080 None,
2081 cx,
2082 )
2083 })?
2084 .await
2085 } else {
2086 Ok(Vec::with_capacity(0))
2087 }
2088 }
2089
2090 async fn format_via_external_command(
2091 buffer: &FormattableBuffer,
2092 command: &str,
2093 arguments: Option<&[String]>,
2094 cx: &mut AsyncApp,
2095 ) -> Result<Option<Diff>> {
2096 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2097 let file = File::from_dyn(buffer.file())?;
2098 let worktree = file.worktree.read(cx);
2099 let mut worktree_path = worktree.abs_path().to_path_buf();
2100 if worktree.root_entry()?.is_file() {
2101 worktree_path.pop();
2102 }
2103 Some(worktree_path)
2104 })?;
2105
2106 let mut child = util::command::new_smol_command(command);
2107
2108 if let Some(buffer_env) = buffer.env.as_ref() {
2109 child.envs(buffer_env);
2110 }
2111
2112 if let Some(working_dir_path) = working_dir_path {
2113 child.current_dir(working_dir_path);
2114 }
2115
2116 if let Some(arguments) = arguments {
2117 child.args(arguments.iter().map(|arg| {
2118 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2119 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2120 } else {
2121 arg.replace("{buffer_path}", "Untitled")
2122 }
2123 }));
2124 }
2125
2126 let mut child = child
2127 .stdin(smol::process::Stdio::piped())
2128 .stdout(smol::process::Stdio::piped())
2129 .stderr(smol::process::Stdio::piped())
2130 .spawn()?;
2131
2132 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2133 let text = buffer
2134 .handle
2135 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2136 for chunk in text.chunks() {
2137 stdin.write_all(chunk.as_bytes()).await?;
2138 }
2139 stdin.flush().await?;
2140
2141 let output = child.output().await?;
2142 anyhow::ensure!(
2143 output.status.success(),
2144 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2145 output.status.code(),
2146 String::from_utf8_lossy(&output.stdout),
2147 String::from_utf8_lossy(&output.stderr),
2148 );
2149
2150 let stdout = String::from_utf8(output.stdout)?;
2151 Ok(Some(
2152 buffer
2153 .handle
2154 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2155 .await,
2156 ))
2157 }
2158
2159 async fn try_resolve_code_action(
2160 lang_server: &LanguageServer,
2161 action: &mut CodeAction,
2162 ) -> anyhow::Result<()> {
2163 match &mut action.lsp_action {
2164 LspAction::Action(lsp_action) => {
2165 if !action.resolved
2166 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2167 && lsp_action.data.is_some()
2168 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2169 {
2170 *lsp_action = Box::new(
2171 lang_server
2172 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2173 .await
2174 .into_response()?,
2175 );
2176 }
2177 }
2178 LspAction::CodeLens(lens) => {
2179 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2180 *lens = lang_server
2181 .request::<lsp::request::CodeLensResolve>(lens.clone())
2182 .await
2183 .into_response()?;
2184 }
2185 }
2186 LspAction::Command(_) => {}
2187 }
2188
2189 action.resolved = true;
2190 anyhow::Ok(())
2191 }
2192
2193 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2194 let buffer = buffer_handle.read(cx);
2195
2196 let file = buffer.file().cloned();
2197
2198 let Some(file) = File::from_dyn(file.as_ref()) else {
2199 return;
2200 };
2201 if !file.is_local() {
2202 return;
2203 }
2204 let path = ProjectPath::from_file(file, cx);
2205 let worktree_id = file.worktree_id(cx);
2206 let language = buffer.language().cloned();
2207
2208 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2209 for (server_id, diagnostics) in
2210 diagnostics.get(file.path()).cloned().unwrap_or_default()
2211 {
2212 self.update_buffer_diagnostics(
2213 buffer_handle,
2214 server_id,
2215 None,
2216 None,
2217 diagnostics,
2218 Vec::new(),
2219 cx,
2220 )
2221 .log_err();
2222 }
2223 }
2224 let Some(language) = language else {
2225 return;
2226 };
2227 let Some(snapshot) = self
2228 .worktree_store
2229 .read(cx)
2230 .worktree_for_id(worktree_id, cx)
2231 .map(|worktree| worktree.read(cx).snapshot())
2232 else {
2233 return;
2234 };
2235 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2236
2237 for server_id in
2238 self.lsp_tree
2239 .get(path, language.name(), language.manifest(), &delegate, cx)
2240 {
2241 let server = self
2242 .language_servers
2243 .get(&server_id)
2244 .and_then(|server_state| {
2245 if let LanguageServerState::Running { server, .. } = server_state {
2246 Some(server.clone())
2247 } else {
2248 None
2249 }
2250 });
2251 let server = match server {
2252 Some(server) => server,
2253 None => continue,
2254 };
2255
2256 buffer_handle.update(cx, |buffer, cx| {
2257 buffer.set_completion_triggers(
2258 server.server_id(),
2259 server
2260 .capabilities()
2261 .completion_provider
2262 .as_ref()
2263 .and_then(|provider| {
2264 provider
2265 .trigger_characters
2266 .as_ref()
2267 .map(|characters| characters.iter().cloned().collect())
2268 })
2269 .unwrap_or_default(),
2270 cx,
2271 );
2272 });
2273 }
2274 }
2275
2276 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2277 buffer.update(cx, |buffer, cx| {
2278 let Some(language) = buffer.language() else {
2279 return;
2280 };
2281 let path = ProjectPath {
2282 worktree_id: old_file.worktree_id(cx),
2283 path: old_file.path.clone(),
2284 };
2285 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2286 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2287 buffer.set_completion_triggers(server_id, Default::default(), cx);
2288 }
2289 });
2290 }
2291
2292 fn update_buffer_diagnostics(
2293 &mut self,
2294 buffer: &Entity<Buffer>,
2295 server_id: LanguageServerId,
2296 result_id: Option<String>,
2297 version: Option<i32>,
2298 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2299 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2300 cx: &mut Context<LspStore>,
2301 ) -> Result<()> {
2302 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2303 Ordering::Equal
2304 .then_with(|| b.is_primary.cmp(&a.is_primary))
2305 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2306 .then_with(|| a.severity.cmp(&b.severity))
2307 .then_with(|| a.message.cmp(&b.message))
2308 }
2309
2310 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2311 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2312 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2313
2314 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2315 Ordering::Equal
2316 .then_with(|| a.range.start.cmp(&b.range.start))
2317 .then_with(|| b.range.end.cmp(&a.range.end))
2318 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2319 });
2320
2321 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2322
2323 let edits_since_save = std::cell::LazyCell::new(|| {
2324 let saved_version = buffer.read(cx).saved_version();
2325 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2326 });
2327
2328 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2329
2330 for (new_diagnostic, entry) in diagnostics {
2331 let start;
2332 let end;
2333 if new_diagnostic && entry.diagnostic.is_disk_based {
2334 // Some diagnostics are based on files on disk instead of buffers'
2335 // current contents. Adjust these diagnostics' ranges to reflect
2336 // any unsaved edits.
2337 // Do not alter the reused ones though, as their coordinates were stored as anchors
2338 // and were properly adjusted on reuse.
2339 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2340 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2341 } else {
2342 start = entry.range.start;
2343 end = entry.range.end;
2344 }
2345
2346 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2347 ..snapshot.clip_point_utf16(end, Bias::Right);
2348
2349 // Expand empty ranges by one codepoint
2350 if range.start == range.end {
2351 // This will be go to the next boundary when being clipped
2352 range.end.column += 1;
2353 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2354 if range.start == range.end && range.end.column > 0 {
2355 range.start.column -= 1;
2356 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2357 }
2358 }
2359
2360 sanitized_diagnostics.push(DiagnosticEntry {
2361 range,
2362 diagnostic: entry.diagnostic,
2363 });
2364 }
2365 drop(edits_since_save);
2366
2367 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2368 buffer.update(cx, |buffer, cx| {
2369 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2370 self.buffer_pull_diagnostics_result_ids
2371 .entry(server_id)
2372 .or_default()
2373 .insert(abs_path, result_id);
2374 }
2375
2376 buffer.update_diagnostics(server_id, set, cx)
2377 });
2378
2379 Ok(())
2380 }
2381
2382 fn register_language_server_for_invisible_worktree(
2383 &mut self,
2384 worktree: &Entity<Worktree>,
2385 language_server_id: LanguageServerId,
2386 cx: &mut App,
2387 ) {
2388 let worktree = worktree.read(cx);
2389 let worktree_id = worktree.id();
2390 debug_assert!(!worktree.is_visible());
2391 let Some(mut origin_seed) = self
2392 .language_server_ids
2393 .iter()
2394 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2395 else {
2396 return;
2397 };
2398 origin_seed.worktree_id = worktree_id;
2399 self.language_server_ids
2400 .entry(origin_seed)
2401 .or_insert_with(|| UnifiedLanguageServer {
2402 id: language_server_id,
2403 project_roots: Default::default(),
2404 });
2405 }
2406
2407 fn register_buffer_with_language_servers(
2408 &mut self,
2409 buffer_handle: &Entity<Buffer>,
2410 only_register_servers: HashSet<LanguageServerSelector>,
2411 cx: &mut Context<LspStore>,
2412 ) {
2413 let buffer = buffer_handle.read(cx);
2414 let buffer_id = buffer.remote_id();
2415
2416 let Some(file) = File::from_dyn(buffer.file()) else {
2417 return;
2418 };
2419 if !file.is_local() {
2420 return;
2421 }
2422
2423 let abs_path = file.abs_path(cx);
2424 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2425 return;
2426 };
2427 let initial_snapshot = buffer.text_snapshot();
2428 let worktree_id = file.worktree_id(cx);
2429
2430 let Some(language) = buffer.language().cloned() else {
2431 return;
2432 };
2433 let path: Arc<RelPath> = file
2434 .path()
2435 .parent()
2436 .map(Arc::from)
2437 .unwrap_or_else(|| file.path().clone());
2438 let Some(worktree) = self
2439 .worktree_store
2440 .read(cx)
2441 .worktree_for_id(worktree_id, cx)
2442 else {
2443 return;
2444 };
2445 let language_name = language.name();
2446 let (reused, delegate, servers) = self
2447 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2448 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2449 .unwrap_or_else(|| {
2450 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2451 let delegate: Arc<dyn ManifestDelegate> =
2452 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2453
2454 let servers = self
2455 .lsp_tree
2456 .walk(
2457 ProjectPath { worktree_id, path },
2458 language.name(),
2459 language.manifest(),
2460 &delegate,
2461 cx,
2462 )
2463 .collect::<Vec<_>>();
2464 (false, lsp_delegate, servers)
2465 });
2466 let servers_and_adapters = servers
2467 .into_iter()
2468 .filter_map(|server_node| {
2469 if reused && server_node.server_id().is_none() {
2470 return None;
2471 }
2472 if !only_register_servers.is_empty() {
2473 if let Some(server_id) = server_node.server_id()
2474 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2475 {
2476 return None;
2477 }
2478 if let Some(name) = server_node.name()
2479 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2480 {
2481 return None;
2482 }
2483 }
2484
2485 let server_id = server_node.server_id_or_init(|disposition| {
2486 let path = &disposition.path;
2487
2488 {
2489 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2490
2491 let server_id = self.get_or_insert_language_server(
2492 &worktree,
2493 delegate.clone(),
2494 disposition,
2495 &language_name,
2496 cx,
2497 );
2498
2499 if let Some(state) = self.language_servers.get(&server_id)
2500 && let Ok(uri) = uri
2501 {
2502 state.add_workspace_folder(uri);
2503 };
2504 server_id
2505 }
2506 })?;
2507 let server_state = self.language_servers.get(&server_id)?;
2508 if let LanguageServerState::Running {
2509 server, adapter, ..
2510 } = server_state
2511 {
2512 Some((server.clone(), adapter.clone()))
2513 } else {
2514 None
2515 }
2516 })
2517 .collect::<Vec<_>>();
2518 for (server, adapter) in servers_and_adapters {
2519 buffer_handle.update(cx, |buffer, cx| {
2520 buffer.set_completion_triggers(
2521 server.server_id(),
2522 server
2523 .capabilities()
2524 .completion_provider
2525 .as_ref()
2526 .and_then(|provider| {
2527 provider
2528 .trigger_characters
2529 .as_ref()
2530 .map(|characters| characters.iter().cloned().collect())
2531 })
2532 .unwrap_or_default(),
2533 cx,
2534 );
2535 });
2536
2537 let snapshot = LspBufferSnapshot {
2538 version: 0,
2539 snapshot: initial_snapshot.clone(),
2540 };
2541
2542 let mut registered = false;
2543 self.buffer_snapshots
2544 .entry(buffer_id)
2545 .or_default()
2546 .entry(server.server_id())
2547 .or_insert_with(|| {
2548 registered = true;
2549 server.register_buffer(
2550 uri.clone(),
2551 adapter.language_id(&language.name()),
2552 0,
2553 initial_snapshot.text(),
2554 );
2555
2556 vec![snapshot]
2557 });
2558
2559 self.buffers_opened_in_servers
2560 .entry(buffer_id)
2561 .or_default()
2562 .insert(server.server_id());
2563 if registered {
2564 cx.emit(LspStoreEvent::LanguageServerUpdate {
2565 language_server_id: server.server_id(),
2566 name: None,
2567 message: proto::update_language_server::Variant::RegisteredForBuffer(
2568 proto::RegisteredForBuffer {
2569 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2570 buffer_id: buffer_id.to_proto(),
2571 },
2572 ),
2573 });
2574 }
2575 }
2576 }
2577
2578 fn reuse_existing_language_server<'lang_name>(
2579 &self,
2580 server_tree: &LanguageServerTree,
2581 worktree: &Entity<Worktree>,
2582 language_name: &'lang_name LanguageName,
2583 cx: &mut App,
2584 ) -> Option<(
2585 Arc<LocalLspAdapterDelegate>,
2586 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2587 )> {
2588 if worktree.read(cx).is_visible() {
2589 return None;
2590 }
2591
2592 let worktree_store = self.worktree_store.read(cx);
2593 let servers = server_tree
2594 .instances
2595 .iter()
2596 .filter(|(worktree_id, _)| {
2597 worktree_store
2598 .worktree_for_id(**worktree_id, cx)
2599 .is_some_and(|worktree| worktree.read(cx).is_visible())
2600 })
2601 .flat_map(|(worktree_id, servers)| {
2602 servers
2603 .roots
2604 .iter()
2605 .flat_map(|(_, language_servers)| language_servers)
2606 .map(move |(_, (server_node, server_languages))| {
2607 (worktree_id, server_node, server_languages)
2608 })
2609 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2610 .map(|(worktree_id, server_node, _)| {
2611 (
2612 *worktree_id,
2613 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2614 )
2615 })
2616 })
2617 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2618 acc.entry(worktree_id)
2619 .or_insert_with(Vec::new)
2620 .push(server_node);
2621 acc
2622 })
2623 .into_values()
2624 .max_by_key(|servers| servers.len())?;
2625
2626 let worktree_id = worktree.read(cx).id();
2627 let apply = move |tree: &mut LanguageServerTree| {
2628 for server_node in &servers {
2629 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2630 }
2631 servers
2632 };
2633
2634 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2635 Some((delegate, apply))
2636 }
2637
2638 pub(crate) fn unregister_old_buffer_from_language_servers(
2639 &mut self,
2640 buffer: &Entity<Buffer>,
2641 old_file: &File,
2642 cx: &mut App,
2643 ) {
2644 let old_path = match old_file.as_local() {
2645 Some(local) => local.abs_path(cx),
2646 None => return,
2647 };
2648
2649 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2650 debug_panic!("{old_path:?} is not parseable as an URI");
2651 return;
2652 };
2653 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2654 }
2655
2656 pub(crate) fn unregister_buffer_from_language_servers(
2657 &mut self,
2658 buffer: &Entity<Buffer>,
2659 file_url: &lsp::Uri,
2660 cx: &mut App,
2661 ) {
2662 buffer.update(cx, |buffer, cx| {
2663 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2664
2665 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2666 language_server.unregister_buffer(file_url.clone());
2667 }
2668 });
2669 }
2670
2671 fn buffer_snapshot_for_lsp_version(
2672 &mut self,
2673 buffer: &Entity<Buffer>,
2674 server_id: LanguageServerId,
2675 version: Option<i32>,
2676 cx: &App,
2677 ) -> Result<TextBufferSnapshot> {
2678 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2679
2680 if let Some(version) = version {
2681 let buffer_id = buffer.read(cx).remote_id();
2682 let snapshots = if let Some(snapshots) = self
2683 .buffer_snapshots
2684 .get_mut(&buffer_id)
2685 .and_then(|m| m.get_mut(&server_id))
2686 {
2687 snapshots
2688 } else if version == 0 {
2689 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2690 // We detect this case and treat it as if the version was `None`.
2691 return Ok(buffer.read(cx).text_snapshot());
2692 } else {
2693 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2694 };
2695
2696 let found_snapshot = snapshots
2697 .binary_search_by_key(&version, |e| e.version)
2698 .map(|ix| snapshots[ix].snapshot.clone())
2699 .map_err(|_| {
2700 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2701 })?;
2702
2703 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2704 Ok(found_snapshot)
2705 } else {
2706 Ok((buffer.read(cx)).text_snapshot())
2707 }
2708 }
2709
2710 async fn get_server_code_actions_from_action_kinds(
2711 lsp_store: &WeakEntity<LspStore>,
2712 language_server_id: LanguageServerId,
2713 code_action_kinds: Vec<lsp::CodeActionKind>,
2714 buffer: &Entity<Buffer>,
2715 cx: &mut AsyncApp,
2716 ) -> Result<Vec<CodeAction>> {
2717 let actions = lsp_store
2718 .update(cx, move |this, cx| {
2719 let request = GetCodeActions {
2720 range: text::Anchor::MIN..text::Anchor::MAX,
2721 kinds: Some(code_action_kinds),
2722 };
2723 let server = LanguageServerToQuery::Other(language_server_id);
2724 this.request_lsp(buffer.clone(), server, request, cx)
2725 })?
2726 .await?;
2727 Ok(actions)
2728 }
2729
2730 pub async fn execute_code_actions_on_server(
2731 lsp_store: &WeakEntity<LspStore>,
2732 language_server: &Arc<LanguageServer>,
2733
2734 actions: Vec<CodeAction>,
2735 push_to_history: bool,
2736 project_transaction: &mut ProjectTransaction,
2737 cx: &mut AsyncApp,
2738 ) -> anyhow::Result<()> {
2739 for mut action in actions {
2740 Self::try_resolve_code_action(language_server, &mut action)
2741 .await
2742 .context("resolving a formatting code action")?;
2743
2744 if let Some(edit) = action.lsp_action.edit() {
2745 if edit.changes.is_none() && edit.document_changes.is_none() {
2746 continue;
2747 }
2748
2749 let new = Self::deserialize_workspace_edit(
2750 lsp_store.upgrade().context("project dropped")?,
2751 edit.clone(),
2752 push_to_history,
2753 language_server.clone(),
2754 cx,
2755 )
2756 .await?;
2757 project_transaction.0.extend(new.0);
2758 }
2759
2760 if let Some(command) = action.lsp_action.command() {
2761 let server_capabilities = language_server.capabilities();
2762 let available_commands = server_capabilities
2763 .execute_command_provider
2764 .as_ref()
2765 .map(|options| options.commands.as_slice())
2766 .unwrap_or_default();
2767 if available_commands.contains(&command.command) {
2768 lsp_store.update(cx, |lsp_store, _| {
2769 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2770 mode.last_workspace_edits_by_language_server
2771 .remove(&language_server.server_id());
2772 }
2773 })?;
2774
2775 language_server
2776 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2777 command: command.command.clone(),
2778 arguments: command.arguments.clone().unwrap_or_default(),
2779 ..Default::default()
2780 })
2781 .await
2782 .into_response()
2783 .context("execute command")?;
2784
2785 lsp_store.update(cx, |this, _| {
2786 if let LspStoreMode::Local(mode) = &mut this.mode {
2787 project_transaction.0.extend(
2788 mode.last_workspace_edits_by_language_server
2789 .remove(&language_server.server_id())
2790 .unwrap_or_default()
2791 .0,
2792 )
2793 }
2794 })?;
2795 } else {
2796 log::warn!(
2797 "Cannot execute a command {} not listed in the language server capabilities",
2798 command.command
2799 )
2800 }
2801 }
2802 }
2803 Ok(())
2804 }
2805
2806 pub async fn deserialize_text_edits(
2807 this: Entity<LspStore>,
2808 buffer_to_edit: Entity<Buffer>,
2809 edits: Vec<lsp::TextEdit>,
2810 push_to_history: bool,
2811 _: Arc<CachedLspAdapter>,
2812 language_server: Arc<LanguageServer>,
2813 cx: &mut AsyncApp,
2814 ) -> Result<Option<Transaction>> {
2815 let edits = this
2816 .update(cx, |this, cx| {
2817 this.as_local_mut().unwrap().edits_from_lsp(
2818 &buffer_to_edit,
2819 edits,
2820 language_server.server_id(),
2821 None,
2822 cx,
2823 )
2824 })?
2825 .await?;
2826
2827 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2828 buffer.finalize_last_transaction();
2829 buffer.start_transaction();
2830 for (range, text) in edits {
2831 buffer.edit([(range, text)], None, cx);
2832 }
2833
2834 if buffer.end_transaction(cx).is_some() {
2835 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2836 if !push_to_history {
2837 buffer.forget_transaction(transaction.id);
2838 }
2839 Some(transaction)
2840 } else {
2841 None
2842 }
2843 })?;
2844
2845 Ok(transaction)
2846 }
2847
2848 #[allow(clippy::type_complexity)]
2849 pub(crate) fn edits_from_lsp(
2850 &mut self,
2851 buffer: &Entity<Buffer>,
2852 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2853 server_id: LanguageServerId,
2854 version: Option<i32>,
2855 cx: &mut Context<LspStore>,
2856 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2857 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2858 cx.background_spawn(async move {
2859 let snapshot = snapshot?;
2860 let mut lsp_edits = lsp_edits
2861 .into_iter()
2862 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2863 .collect::<Vec<_>>();
2864
2865 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2866
2867 let mut lsp_edits = lsp_edits.into_iter().peekable();
2868 let mut edits = Vec::new();
2869 while let Some((range, mut new_text)) = lsp_edits.next() {
2870 // Clip invalid ranges provided by the language server.
2871 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2872 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2873
2874 // Combine any LSP edits that are adjacent.
2875 //
2876 // Also, combine LSP edits that are separated from each other by only
2877 // a newline. This is important because for some code actions,
2878 // Rust-analyzer rewrites the entire buffer via a series of edits that
2879 // are separated by unchanged newline characters.
2880 //
2881 // In order for the diffing logic below to work properly, any edits that
2882 // cancel each other out must be combined into one.
2883 while let Some((next_range, next_text)) = lsp_edits.peek() {
2884 if next_range.start.0 > range.end {
2885 if next_range.start.0.row > range.end.row + 1
2886 || next_range.start.0.column > 0
2887 || snapshot.clip_point_utf16(
2888 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2889 Bias::Left,
2890 ) > range.end
2891 {
2892 break;
2893 }
2894 new_text.push('\n');
2895 }
2896 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2897 new_text.push_str(next_text);
2898 lsp_edits.next();
2899 }
2900
2901 // For multiline edits, perform a diff of the old and new text so that
2902 // we can identify the changes more precisely, preserving the locations
2903 // of any anchors positioned in the unchanged regions.
2904 if range.end.row > range.start.row {
2905 let offset = range.start.to_offset(&snapshot);
2906 let old_text = snapshot.text_for_range(range).collect::<String>();
2907 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2908 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2909 (
2910 snapshot.anchor_after(offset + range.start)
2911 ..snapshot.anchor_before(offset + range.end),
2912 replacement,
2913 )
2914 }));
2915 } else if range.end == range.start {
2916 let anchor = snapshot.anchor_after(range.start);
2917 edits.push((anchor..anchor, new_text.into()));
2918 } else {
2919 let edit_start = snapshot.anchor_after(range.start);
2920 let edit_end = snapshot.anchor_before(range.end);
2921 edits.push((edit_start..edit_end, new_text.into()));
2922 }
2923 }
2924
2925 Ok(edits)
2926 })
2927 }
2928
2929 pub(crate) async fn deserialize_workspace_edit(
2930 this: Entity<LspStore>,
2931 edit: lsp::WorkspaceEdit,
2932 push_to_history: bool,
2933 language_server: Arc<LanguageServer>,
2934 cx: &mut AsyncApp,
2935 ) -> Result<ProjectTransaction> {
2936 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2937
2938 let mut operations = Vec::new();
2939 if let Some(document_changes) = edit.document_changes {
2940 match document_changes {
2941 lsp::DocumentChanges::Edits(edits) => {
2942 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2943 }
2944 lsp::DocumentChanges::Operations(ops) => operations = ops,
2945 }
2946 } else if let Some(changes) = edit.changes {
2947 operations.extend(changes.into_iter().map(|(uri, edits)| {
2948 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2949 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2950 uri,
2951 version: None,
2952 },
2953 edits: edits.into_iter().map(Edit::Plain).collect(),
2954 })
2955 }));
2956 }
2957
2958 let mut project_transaction = ProjectTransaction::default();
2959 for operation in operations {
2960 match operation {
2961 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2962 let abs_path = op
2963 .uri
2964 .to_file_path()
2965 .map_err(|()| anyhow!("can't convert URI to path"))?;
2966
2967 if let Some(parent_path) = abs_path.parent() {
2968 fs.create_dir(parent_path).await?;
2969 }
2970 if abs_path.ends_with("/") {
2971 fs.create_dir(&abs_path).await?;
2972 } else {
2973 fs.create_file(
2974 &abs_path,
2975 op.options
2976 .map(|options| fs::CreateOptions {
2977 overwrite: options.overwrite.unwrap_or(false),
2978 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2979 })
2980 .unwrap_or_default(),
2981 )
2982 .await?;
2983 }
2984 }
2985
2986 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2987 let source_abs_path = op
2988 .old_uri
2989 .to_file_path()
2990 .map_err(|()| anyhow!("can't convert URI to path"))?;
2991 let target_abs_path = op
2992 .new_uri
2993 .to_file_path()
2994 .map_err(|()| anyhow!("can't convert URI to path"))?;
2995 fs.rename(
2996 &source_abs_path,
2997 &target_abs_path,
2998 op.options
2999 .map(|options| fs::RenameOptions {
3000 overwrite: options.overwrite.unwrap_or(false),
3001 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3002 })
3003 .unwrap_or_default(),
3004 )
3005 .await?;
3006 }
3007
3008 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3009 let abs_path = op
3010 .uri
3011 .to_file_path()
3012 .map_err(|()| anyhow!("can't convert URI to path"))?;
3013 let options = op
3014 .options
3015 .map(|options| fs::RemoveOptions {
3016 recursive: options.recursive.unwrap_or(false),
3017 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3018 })
3019 .unwrap_or_default();
3020 if abs_path.ends_with("/") {
3021 fs.remove_dir(&abs_path, options).await?;
3022 } else {
3023 fs.remove_file(&abs_path, options).await?;
3024 }
3025 }
3026
3027 lsp::DocumentChangeOperation::Edit(op) => {
3028 let buffer_to_edit = this
3029 .update(cx, |this, cx| {
3030 this.open_local_buffer_via_lsp(
3031 op.text_document.uri.clone(),
3032 language_server.server_id(),
3033 cx,
3034 )
3035 })?
3036 .await?;
3037
3038 let edits = this
3039 .update(cx, |this, cx| {
3040 let path = buffer_to_edit.read(cx).project_path(cx);
3041 let active_entry = this.active_entry;
3042 let is_active_entry = path.is_some_and(|project_path| {
3043 this.worktree_store
3044 .read(cx)
3045 .entry_for_path(&project_path, cx)
3046 .is_some_and(|entry| Some(entry.id) == active_entry)
3047 });
3048 let local = this.as_local_mut().unwrap();
3049
3050 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3051 for edit in op.edits {
3052 match edit {
3053 Edit::Plain(edit) => {
3054 if !edits.contains(&edit) {
3055 edits.push(edit)
3056 }
3057 }
3058 Edit::Annotated(edit) => {
3059 if !edits.contains(&edit.text_edit) {
3060 edits.push(edit.text_edit)
3061 }
3062 }
3063 Edit::Snippet(edit) => {
3064 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3065 else {
3066 continue;
3067 };
3068
3069 if is_active_entry {
3070 snippet_edits.push((edit.range, snippet));
3071 } else {
3072 // Since this buffer is not focused, apply a normal edit.
3073 let new_edit = TextEdit {
3074 range: edit.range,
3075 new_text: snippet.text,
3076 };
3077 if !edits.contains(&new_edit) {
3078 edits.push(new_edit);
3079 }
3080 }
3081 }
3082 }
3083 }
3084 if !snippet_edits.is_empty() {
3085 let buffer_id = buffer_to_edit.read(cx).remote_id();
3086 let version = if let Some(buffer_version) = op.text_document.version
3087 {
3088 local
3089 .buffer_snapshot_for_lsp_version(
3090 &buffer_to_edit,
3091 language_server.server_id(),
3092 Some(buffer_version),
3093 cx,
3094 )
3095 .ok()
3096 .map(|snapshot| snapshot.version)
3097 } else {
3098 Some(buffer_to_edit.read(cx).saved_version().clone())
3099 };
3100
3101 let most_recent_edit =
3102 version.and_then(|version| version.most_recent());
3103 // Check if the edit that triggered that edit has been made by this participant.
3104
3105 if let Some(most_recent_edit) = most_recent_edit {
3106 cx.emit(LspStoreEvent::SnippetEdit {
3107 buffer_id,
3108 edits: snippet_edits,
3109 most_recent_edit,
3110 });
3111 }
3112 }
3113
3114 local.edits_from_lsp(
3115 &buffer_to_edit,
3116 edits,
3117 language_server.server_id(),
3118 op.text_document.version,
3119 cx,
3120 )
3121 })?
3122 .await?;
3123
3124 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3125 buffer.finalize_last_transaction();
3126 buffer.start_transaction();
3127 for (range, text) in edits {
3128 buffer.edit([(range, text)], None, cx);
3129 }
3130
3131 buffer.end_transaction(cx).and_then(|transaction_id| {
3132 if push_to_history {
3133 buffer.finalize_last_transaction();
3134 buffer.get_transaction(transaction_id).cloned()
3135 } else {
3136 buffer.forget_transaction(transaction_id)
3137 }
3138 })
3139 })?;
3140 if let Some(transaction) = transaction {
3141 project_transaction.0.insert(buffer_to_edit, transaction);
3142 }
3143 }
3144 }
3145 }
3146
3147 Ok(project_transaction)
3148 }
3149
3150 async fn on_lsp_workspace_edit(
3151 this: WeakEntity<LspStore>,
3152 params: lsp::ApplyWorkspaceEditParams,
3153 server_id: LanguageServerId,
3154 cx: &mut AsyncApp,
3155 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3156 let this = this.upgrade().context("project project closed")?;
3157 let language_server = this
3158 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3159 .context("language server not found")?;
3160 let transaction = Self::deserialize_workspace_edit(
3161 this.clone(),
3162 params.edit,
3163 true,
3164 language_server.clone(),
3165 cx,
3166 )
3167 .await
3168 .log_err();
3169 this.update(cx, |this, _| {
3170 if let Some(transaction) = transaction {
3171 this.as_local_mut()
3172 .unwrap()
3173 .last_workspace_edits_by_language_server
3174 .insert(server_id, transaction);
3175 }
3176 })?;
3177 Ok(lsp::ApplyWorkspaceEditResponse {
3178 applied: true,
3179 failed_change: None,
3180 failure_reason: None,
3181 })
3182 }
3183
3184 fn remove_worktree(
3185 &mut self,
3186 id_to_remove: WorktreeId,
3187 cx: &mut Context<LspStore>,
3188 ) -> Vec<LanguageServerId> {
3189 self.diagnostics.remove(&id_to_remove);
3190 self.prettier_store.update(cx, |prettier_store, cx| {
3191 prettier_store.remove_worktree(id_to_remove, cx);
3192 });
3193
3194 let mut servers_to_remove = BTreeSet::default();
3195 let mut servers_to_preserve = HashSet::default();
3196 for (seed, state) in &self.language_server_ids {
3197 if seed.worktree_id == id_to_remove {
3198 servers_to_remove.insert(state.id);
3199 } else {
3200 servers_to_preserve.insert(state.id);
3201 }
3202 }
3203 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3204 self.language_server_ids
3205 .retain(|_, state| !servers_to_remove.contains(&state.id));
3206 for server_id_to_remove in &servers_to_remove {
3207 self.language_server_watched_paths
3208 .remove(server_id_to_remove);
3209 self.language_server_paths_watched_for_rename
3210 .remove(server_id_to_remove);
3211 self.last_workspace_edits_by_language_server
3212 .remove(server_id_to_remove);
3213 self.language_servers.remove(server_id_to_remove);
3214 self.buffer_pull_diagnostics_result_ids
3215 .remove(server_id_to_remove);
3216 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3217 buffer_servers.remove(server_id_to_remove);
3218 }
3219 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3220 }
3221 servers_to_remove.into_iter().collect()
3222 }
3223
3224 fn rebuild_watched_paths_inner<'a>(
3225 &'a self,
3226 language_server_id: LanguageServerId,
3227 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3228 cx: &mut Context<LspStore>,
3229 ) -> LanguageServerWatchedPathsBuilder {
3230 let worktrees = self
3231 .worktree_store
3232 .read(cx)
3233 .worktrees()
3234 .filter_map(|worktree| {
3235 self.language_servers_for_worktree(worktree.read(cx).id())
3236 .find(|server| server.server_id() == language_server_id)
3237 .map(|_| worktree)
3238 })
3239 .collect::<Vec<_>>();
3240
3241 let mut worktree_globs = HashMap::default();
3242 let mut abs_globs = HashMap::default();
3243 log::trace!(
3244 "Processing new watcher paths for language server with id {}",
3245 language_server_id
3246 );
3247
3248 for watcher in watchers {
3249 if let Some((worktree, literal_prefix, pattern)) =
3250 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3251 {
3252 worktree.update(cx, |worktree, _| {
3253 if let Some((tree, glob)) =
3254 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3255 {
3256 tree.add_path_prefix_to_scan(literal_prefix);
3257 worktree_globs
3258 .entry(tree.id())
3259 .or_insert_with(GlobSetBuilder::new)
3260 .add(glob);
3261 }
3262 });
3263 } else {
3264 let (path, pattern) = match &watcher.glob_pattern {
3265 lsp::GlobPattern::String(s) => {
3266 let watcher_path = SanitizedPath::new(s);
3267 let path = glob_literal_prefix(watcher_path.as_path());
3268 let pattern = watcher_path
3269 .as_path()
3270 .strip_prefix(&path)
3271 .map(|p| p.to_string_lossy().into_owned())
3272 .unwrap_or_else(|e| {
3273 debug_panic!(
3274 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3275 s,
3276 path.display(),
3277 e
3278 );
3279 watcher_path.as_path().to_string_lossy().into_owned()
3280 });
3281 (path, pattern)
3282 }
3283 lsp::GlobPattern::Relative(rp) => {
3284 let Ok(mut base_uri) = match &rp.base_uri {
3285 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3286 lsp::OneOf::Right(base_uri) => base_uri,
3287 }
3288 .to_file_path() else {
3289 continue;
3290 };
3291
3292 let path = glob_literal_prefix(Path::new(&rp.pattern));
3293 let pattern = Path::new(&rp.pattern)
3294 .strip_prefix(&path)
3295 .map(|p| p.to_string_lossy().into_owned())
3296 .unwrap_or_else(|e| {
3297 debug_panic!(
3298 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3299 rp.pattern,
3300 path.display(),
3301 e
3302 );
3303 rp.pattern.clone()
3304 });
3305 base_uri.push(path);
3306 (base_uri, pattern)
3307 }
3308 };
3309
3310 if let Some(glob) = Glob::new(&pattern).log_err() {
3311 if !path
3312 .components()
3313 .any(|c| matches!(c, path::Component::Normal(_)))
3314 {
3315 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3316 // rather than adding a new watcher for `/`.
3317 for worktree in &worktrees {
3318 worktree_globs
3319 .entry(worktree.read(cx).id())
3320 .or_insert_with(GlobSetBuilder::new)
3321 .add(glob.clone());
3322 }
3323 } else {
3324 abs_globs
3325 .entry(path.into())
3326 .or_insert_with(GlobSetBuilder::new)
3327 .add(glob);
3328 }
3329 }
3330 }
3331 }
3332
3333 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3334 for (worktree_id, builder) in worktree_globs {
3335 if let Ok(globset) = builder.build() {
3336 watch_builder.watch_worktree(worktree_id, globset);
3337 }
3338 }
3339 for (abs_path, builder) in abs_globs {
3340 if let Ok(globset) = builder.build() {
3341 watch_builder.watch_abs_path(abs_path, globset);
3342 }
3343 }
3344 watch_builder
3345 }
3346
3347 fn worktree_and_path_for_file_watcher(
3348 worktrees: &[Entity<Worktree>],
3349 watcher: &FileSystemWatcher,
3350 cx: &App,
3351 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3352 worktrees.iter().find_map(|worktree| {
3353 let tree = worktree.read(cx);
3354 let worktree_root_path = tree.abs_path();
3355 let path_style = tree.path_style();
3356 match &watcher.glob_pattern {
3357 lsp::GlobPattern::String(s) => {
3358 let watcher_path = SanitizedPath::new(s);
3359 let relative = watcher_path
3360 .as_path()
3361 .strip_prefix(&worktree_root_path)
3362 .ok()?;
3363 let literal_prefix = glob_literal_prefix(relative);
3364 Some((
3365 worktree.clone(),
3366 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3367 relative.to_string_lossy().into_owned(),
3368 ))
3369 }
3370 lsp::GlobPattern::Relative(rp) => {
3371 let base_uri = match &rp.base_uri {
3372 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3373 lsp::OneOf::Right(base_uri) => base_uri,
3374 }
3375 .to_file_path()
3376 .ok()?;
3377 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3378 let mut literal_prefix = relative.to_owned();
3379 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3380 Some((
3381 worktree.clone(),
3382 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3383 rp.pattern.clone(),
3384 ))
3385 }
3386 }
3387 })
3388 }
3389
3390 fn rebuild_watched_paths(
3391 &mut self,
3392 language_server_id: LanguageServerId,
3393 cx: &mut Context<LspStore>,
3394 ) {
3395 let Some(registrations) = self
3396 .language_server_dynamic_registrations
3397 .get(&language_server_id)
3398 else {
3399 return;
3400 };
3401
3402 let watch_builder = self.rebuild_watched_paths_inner(
3403 language_server_id,
3404 registrations.did_change_watched_files.values().flatten(),
3405 cx,
3406 );
3407 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3408 self.language_server_watched_paths
3409 .insert(language_server_id, watcher);
3410
3411 cx.notify();
3412 }
3413
3414 fn on_lsp_did_change_watched_files(
3415 &mut self,
3416 language_server_id: LanguageServerId,
3417 registration_id: &str,
3418 params: DidChangeWatchedFilesRegistrationOptions,
3419 cx: &mut Context<LspStore>,
3420 ) {
3421 let registrations = self
3422 .language_server_dynamic_registrations
3423 .entry(language_server_id)
3424 .or_default();
3425
3426 registrations
3427 .did_change_watched_files
3428 .insert(registration_id.to_string(), params.watchers);
3429
3430 self.rebuild_watched_paths(language_server_id, cx);
3431 }
3432
3433 fn on_lsp_unregister_did_change_watched_files(
3434 &mut self,
3435 language_server_id: LanguageServerId,
3436 registration_id: &str,
3437 cx: &mut Context<LspStore>,
3438 ) {
3439 let registrations = self
3440 .language_server_dynamic_registrations
3441 .entry(language_server_id)
3442 .or_default();
3443
3444 if registrations
3445 .did_change_watched_files
3446 .remove(registration_id)
3447 .is_some()
3448 {
3449 log::info!(
3450 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3451 language_server_id,
3452 registration_id
3453 );
3454 } else {
3455 log::warn!(
3456 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3457 language_server_id,
3458 registration_id
3459 );
3460 }
3461
3462 self.rebuild_watched_paths(language_server_id, cx);
3463 }
3464
3465 async fn initialization_options_for_adapter(
3466 adapter: Arc<dyn LspAdapter>,
3467 delegate: &Arc<dyn LspAdapterDelegate>,
3468 ) -> Result<Option<serde_json::Value>> {
3469 let Some(mut initialization_config) =
3470 adapter.clone().initialization_options(delegate).await?
3471 else {
3472 return Ok(None);
3473 };
3474
3475 for other_adapter in delegate.registered_lsp_adapters() {
3476 if other_adapter.name() == adapter.name() {
3477 continue;
3478 }
3479 if let Ok(Some(target_config)) = other_adapter
3480 .clone()
3481 .additional_initialization_options(adapter.name(), delegate)
3482 .await
3483 {
3484 merge_json_value_into(target_config.clone(), &mut initialization_config);
3485 }
3486 }
3487
3488 Ok(Some(initialization_config))
3489 }
3490
3491 async fn workspace_configuration_for_adapter(
3492 adapter: Arc<dyn LspAdapter>,
3493 delegate: &Arc<dyn LspAdapterDelegate>,
3494 toolchain: Option<Toolchain>,
3495 cx: &mut AsyncApp,
3496 ) -> Result<serde_json::Value> {
3497 let mut workspace_config = adapter
3498 .clone()
3499 .workspace_configuration(delegate, toolchain, cx)
3500 .await?;
3501
3502 for other_adapter in delegate.registered_lsp_adapters() {
3503 if other_adapter.name() == adapter.name() {
3504 continue;
3505 }
3506 if let Ok(Some(target_config)) = other_adapter
3507 .clone()
3508 .additional_workspace_configuration(adapter.name(), delegate, cx)
3509 .await
3510 {
3511 merge_json_value_into(target_config.clone(), &mut workspace_config);
3512 }
3513 }
3514
3515 Ok(workspace_config)
3516 }
3517
3518 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3519 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3520 Some(server.clone())
3521 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3522 Some(Arc::clone(server))
3523 } else {
3524 None
3525 }
3526 }
3527}
3528
3529fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3530 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3531 cx.emit(LspStoreEvent::LanguageServerUpdate {
3532 language_server_id: server.server_id(),
3533 name: Some(server.name()),
3534 message: proto::update_language_server::Variant::MetadataUpdated(
3535 proto::ServerMetadataUpdated {
3536 capabilities: Some(capabilities),
3537 },
3538 ),
3539 });
3540 }
3541}
3542
3543#[derive(Debug)]
3544pub struct FormattableBuffer {
3545 handle: Entity<Buffer>,
3546 abs_path: Option<PathBuf>,
3547 env: Option<HashMap<String, String>>,
3548 ranges: Option<Vec<Range<Anchor>>>,
3549}
3550
3551pub struct RemoteLspStore {
3552 upstream_client: Option<AnyProtoClient>,
3553 upstream_project_id: u64,
3554}
3555
3556pub(crate) enum LspStoreMode {
3557 Local(LocalLspStore), // ssh host and collab host
3558 Remote(RemoteLspStore), // collab guest
3559}
3560
3561impl LspStoreMode {
3562 fn is_local(&self) -> bool {
3563 matches!(self, LspStoreMode::Local(_))
3564 }
3565}
3566
3567pub struct LspStore {
3568 mode: LspStoreMode,
3569 last_formatting_failure: Option<String>,
3570 downstream_client: Option<(AnyProtoClient, u64)>,
3571 nonce: u128,
3572 buffer_store: Entity<BufferStore>,
3573 worktree_store: Entity<WorktreeStore>,
3574 pub languages: Arc<LanguageRegistry>,
3575 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3576 active_entry: Option<ProjectEntryId>,
3577 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3578 _maintain_buffer_languages: Task<()>,
3579 diagnostic_summaries:
3580 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3581 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3582 lsp_data: HashMap<BufferId, BufferLspData>,
3583 next_hint_id: Arc<AtomicUsize>,
3584}
3585
3586#[derive(Debug)]
3587pub struct BufferLspData {
3588 buffer_version: Global,
3589 document_colors: Option<DocumentColorData>,
3590 code_lens: Option<CodeLensData>,
3591 inlay_hints: BufferInlayHints,
3592 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3593 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3594}
3595
3596#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3597struct LspKey {
3598 request_type: TypeId,
3599 server_queried: Option<LanguageServerId>,
3600}
3601
3602impl BufferLspData {
3603 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3604 Self {
3605 buffer_version: buffer.read(cx).version(),
3606 document_colors: None,
3607 code_lens: None,
3608 inlay_hints: BufferInlayHints::new(buffer, cx),
3609 lsp_requests: HashMap::default(),
3610 chunk_lsp_requests: HashMap::default(),
3611 }
3612 }
3613
3614 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3615 if let Some(document_colors) = &mut self.document_colors {
3616 document_colors.colors.remove(&for_server);
3617 document_colors.cache_version += 1;
3618 }
3619
3620 if let Some(code_lens) = &mut self.code_lens {
3621 code_lens.lens.remove(&for_server);
3622 }
3623
3624 self.inlay_hints.remove_server_data(for_server);
3625 }
3626
3627 #[cfg(any(test, feature = "test-support"))]
3628 pub fn inlay_hints(&self) -> &BufferInlayHints {
3629 &self.inlay_hints
3630 }
3631}
3632
3633#[derive(Debug, Default, Clone)]
3634pub struct DocumentColors {
3635 pub colors: HashSet<DocumentColor>,
3636 pub cache_version: Option<usize>,
3637}
3638
3639type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3640type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3641
3642#[derive(Debug, Default)]
3643struct DocumentColorData {
3644 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3645 cache_version: usize,
3646 colors_update: Option<(Global, DocumentColorTask)>,
3647}
3648
3649#[derive(Debug, Default)]
3650struct CodeLensData {
3651 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3652 update: Option<(Global, CodeLensTask)>,
3653}
3654
3655#[derive(Debug)]
3656pub enum LspStoreEvent {
3657 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3658 LanguageServerRemoved(LanguageServerId),
3659 LanguageServerUpdate {
3660 language_server_id: LanguageServerId,
3661 name: Option<LanguageServerName>,
3662 message: proto::update_language_server::Variant,
3663 },
3664 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3665 LanguageServerPrompt(LanguageServerPromptRequest),
3666 LanguageDetected {
3667 buffer: Entity<Buffer>,
3668 new_language: Option<Arc<Language>>,
3669 },
3670 Notification(String),
3671 RefreshInlayHints {
3672 server_id: LanguageServerId,
3673 request_id: Option<usize>,
3674 },
3675 RefreshCodeLens,
3676 DiagnosticsUpdated {
3677 server_id: LanguageServerId,
3678 paths: Vec<ProjectPath>,
3679 },
3680 DiskBasedDiagnosticsStarted {
3681 language_server_id: LanguageServerId,
3682 },
3683 DiskBasedDiagnosticsFinished {
3684 language_server_id: LanguageServerId,
3685 },
3686 SnippetEdit {
3687 buffer_id: BufferId,
3688 edits: Vec<(lsp::Range, Snippet)>,
3689 most_recent_edit: clock::Lamport,
3690 },
3691}
3692
3693#[derive(Clone, Debug, Serialize)]
3694pub struct LanguageServerStatus {
3695 pub name: LanguageServerName,
3696 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3697 pub has_pending_diagnostic_updates: bool,
3698 progress_tokens: HashSet<ProgressToken>,
3699 pub worktree: Option<WorktreeId>,
3700}
3701
3702#[derive(Clone, Debug)]
3703struct CoreSymbol {
3704 pub language_server_name: LanguageServerName,
3705 pub source_worktree_id: WorktreeId,
3706 pub source_language_server_id: LanguageServerId,
3707 pub path: SymbolLocation,
3708 pub name: String,
3709 pub kind: lsp::SymbolKind,
3710 pub range: Range<Unclipped<PointUtf16>>,
3711}
3712
3713#[derive(Clone, Debug, PartialEq, Eq)]
3714pub enum SymbolLocation {
3715 InProject(ProjectPath),
3716 OutsideProject {
3717 abs_path: Arc<Path>,
3718 signature: [u8; 32],
3719 },
3720}
3721
3722impl SymbolLocation {
3723 fn file_name(&self) -> Option<&str> {
3724 match self {
3725 Self::InProject(path) => path.path.file_name(),
3726 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3727 }
3728 }
3729}
3730
3731impl LspStore {
3732 pub fn init(client: &AnyProtoClient) {
3733 client.add_entity_request_handler(Self::handle_lsp_query);
3734 client.add_entity_message_handler(Self::handle_lsp_query_response);
3735 client.add_entity_request_handler(Self::handle_restart_language_servers);
3736 client.add_entity_request_handler(Self::handle_stop_language_servers);
3737 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3738 client.add_entity_message_handler(Self::handle_start_language_server);
3739 client.add_entity_message_handler(Self::handle_update_language_server);
3740 client.add_entity_message_handler(Self::handle_language_server_log);
3741 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3742 client.add_entity_request_handler(Self::handle_format_buffers);
3743 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3744 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3745 client.add_entity_request_handler(Self::handle_apply_code_action);
3746 client.add_entity_request_handler(Self::handle_get_project_symbols);
3747 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3748 client.add_entity_request_handler(Self::handle_get_color_presentation);
3749 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3750 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3751 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3752 client.add_entity_request_handler(Self::handle_on_type_formatting);
3753 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3754 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3755 client.add_entity_request_handler(Self::handle_rename_project_entry);
3756 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3757 client.add_entity_request_handler(Self::handle_lsp_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.start..chunk.end)
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 buffer_snapshot = buffer.read(cx).snapshot();
6733 let next_hint_id = self.next_hint_id.clone();
6734 let lsp_data = self.latest_lsp_data(&buffer, cx);
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.start..chunk.end)))
6761 .collect::<Vec<_>>();
6762 if applicable_chunks.is_empty() {
6763 return HashMap::default();
6764 }
6765
6766 let last_chunk_number = existing_inlay_hints.buffer_chunks_len() - 1;
6767
6768 for row_chunk in applicable_chunks {
6769 match (
6770 existing_inlay_hints
6771 .cached_hints(&row_chunk)
6772 .filter(|_| !lsp_refresh_requested)
6773 .cloned(),
6774 existing_inlay_hints
6775 .fetched_hints(&row_chunk)
6776 .as_ref()
6777 .filter(|_| !lsp_refresh_requested)
6778 .cloned(),
6779 ) {
6780 (None, None) => {
6781 let end = if last_chunk_number == row_chunk.id {
6782 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6783 } else {
6784 Point::new(row_chunk.end, 0)
6785 };
6786 ranges_to_query.get_or_insert_with(Vec::new).push((
6787 row_chunk,
6788 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6789 ..buffer_snapshot.anchor_after(end),
6790 ));
6791 }
6792 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6793 (Some(cached_hints), None) => {
6794 for (server_id, cached_hints) in cached_hints {
6795 if for_server.is_none_or(|for_server| for_server == server_id) {
6796 cached_inlay_hints
6797 .get_or_insert_with(HashMap::default)
6798 .entry(row_chunk.start..row_chunk.end)
6799 .or_insert_with(HashMap::default)
6800 .entry(server_id)
6801 .or_insert_with(Vec::new)
6802 .extend(cached_hints);
6803 }
6804 }
6805 }
6806 (Some(cached_hints), Some(fetched_hints)) => {
6807 hint_fetch_tasks.push((row_chunk, fetched_hints));
6808 for (server_id, cached_hints) in cached_hints {
6809 if for_server.is_none_or(|for_server| for_server == server_id) {
6810 cached_inlay_hints
6811 .get_or_insert_with(HashMap::default)
6812 .entry(row_chunk.start..row_chunk.end)
6813 .or_insert_with(HashMap::default)
6814 .entry(server_id)
6815 .or_insert_with(Vec::new)
6816 .extend(cached_hints);
6817 }
6818 }
6819 }
6820 }
6821 }
6822
6823 if hint_fetch_tasks.is_empty()
6824 && ranges_to_query
6825 .as_ref()
6826 .is_none_or(|ranges| ranges.is_empty())
6827 && let Some(cached_inlay_hints) = cached_inlay_hints
6828 {
6829 cached_inlay_hints
6830 .into_iter()
6831 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6832 .collect()
6833 } else {
6834 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6835 let next_hint_id = next_hint_id.clone();
6836 let buffer = buffer.clone();
6837 let new_inlay_hints = cx
6838 .spawn(async move |lsp_store, cx| {
6839 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6840 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6841 })?;
6842 new_fetch_task
6843 .await
6844 .and_then(|new_hints_by_server| {
6845 lsp_store.update(cx, |lsp_store, cx| {
6846 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6847 let update_cache = !lsp_data
6848 .buffer_version
6849 .changed_since(&buffer.read(cx).version());
6850 if new_hints_by_server.is_empty() {
6851 if update_cache {
6852 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6853 }
6854 HashMap::default()
6855 } else {
6856 new_hints_by_server
6857 .into_iter()
6858 .map(|(server_id, new_hints)| {
6859 let new_hints = new_hints
6860 .into_iter()
6861 .map(|new_hint| {
6862 (
6863 InlayId::Hint(next_hint_id.fetch_add(
6864 1,
6865 atomic::Ordering::AcqRel,
6866 )),
6867 new_hint,
6868 )
6869 })
6870 .collect::<Vec<_>>();
6871 if update_cache {
6872 lsp_data.inlay_hints.insert_new_hints(
6873 chunk,
6874 server_id,
6875 new_hints.clone(),
6876 );
6877 }
6878 (server_id, new_hints)
6879 })
6880 .collect()
6881 }
6882 })
6883 })
6884 .map_err(Arc::new)
6885 })
6886 .shared();
6887
6888 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6889 *fetch_task = Some(new_inlay_hints.clone());
6890 hint_fetch_tasks.push((chunk, new_inlay_hints));
6891 }
6892
6893 cached_inlay_hints
6894 .unwrap_or_default()
6895 .into_iter()
6896 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6897 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6898 (
6899 chunk.start..chunk.end,
6900 cx.spawn(async move |_, _| {
6901 hints_fetch.await.map_err(|e| {
6902 if e.error_code() != ErrorCode::Internal {
6903 anyhow!(e.error_code())
6904 } else {
6905 anyhow!("{e:#}")
6906 }
6907 })
6908 }),
6909 )
6910 }))
6911 .collect()
6912 }
6913 }
6914
6915 fn fetch_inlay_hints(
6916 &mut self,
6917 for_server: Option<LanguageServerId>,
6918 buffer: &Entity<Buffer>,
6919 range: Range<Anchor>,
6920 cx: &mut Context<Self>,
6921 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6922 let request = InlayHints {
6923 range: range.clone(),
6924 };
6925 if let Some((upstream_client, project_id)) = self.upstream_client() {
6926 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6927 return Task::ready(Ok(HashMap::default()));
6928 }
6929 let request_task = upstream_client.request_lsp(
6930 project_id,
6931 for_server.map(|id| id.to_proto()),
6932 LSP_REQUEST_TIMEOUT,
6933 cx.background_executor().clone(),
6934 request.to_proto(project_id, buffer.read(cx)),
6935 );
6936 let buffer = buffer.clone();
6937 cx.spawn(async move |weak_lsp_store, cx| {
6938 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6939 return Ok(HashMap::default());
6940 };
6941 let Some(responses) = request_task.await? else {
6942 return Ok(HashMap::default());
6943 };
6944
6945 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6946 let lsp_store = lsp_store.clone();
6947 let buffer = buffer.clone();
6948 let cx = cx.clone();
6949 let request = request.clone();
6950 async move {
6951 (
6952 LanguageServerId::from_proto(response.server_id),
6953 request
6954 .response_from_proto(response.response, lsp_store, buffer, cx)
6955 .await,
6956 )
6957 }
6958 }))
6959 .await;
6960
6961 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
6962 let mut has_errors = false;
6963 let inlay_hints = inlay_hints
6964 .into_iter()
6965 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6966 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6967 Err(e) => {
6968 has_errors = true;
6969 log::error!("{e:#}");
6970 None
6971 }
6972 })
6973 .map(|(server_id, mut new_hints)| {
6974 new_hints.retain(|hint| {
6975 hint.position.is_valid(&buffer_snapshot)
6976 && range.start.is_valid(&buffer_snapshot)
6977 && range.end.is_valid(&buffer_snapshot)
6978 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6979 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6980 });
6981 (server_id, new_hints)
6982 })
6983 .collect::<HashMap<_, _>>();
6984 anyhow::ensure!(
6985 !has_errors || !inlay_hints.is_empty(),
6986 "Failed to fetch inlay hints"
6987 );
6988 Ok(inlay_hints)
6989 })
6990 } else {
6991 let inlay_hints_task = match for_server {
6992 Some(server_id) => {
6993 let server_task = self.request_lsp(
6994 buffer.clone(),
6995 LanguageServerToQuery::Other(server_id),
6996 request,
6997 cx,
6998 );
6999 cx.background_spawn(async move {
7000 let mut responses = Vec::new();
7001 match server_task.await {
7002 Ok(response) => responses.push((server_id, response)),
7003 // rust-analyzer likes to error with this when its still loading up
7004 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7005 Err(e) => log::error!(
7006 "Error handling response for inlay hints request: {e:#}"
7007 ),
7008 }
7009 responses
7010 })
7011 }
7012 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7013 };
7014 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7015 cx.background_spawn(async move {
7016 Ok(inlay_hints_task
7017 .await
7018 .into_iter()
7019 .map(|(server_id, mut new_hints)| {
7020 new_hints.retain(|hint| {
7021 hint.position.is_valid(&buffer_snapshot)
7022 && range.start.is_valid(&buffer_snapshot)
7023 && range.end.is_valid(&buffer_snapshot)
7024 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7025 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7026 });
7027 (server_id, new_hints)
7028 })
7029 .collect())
7030 })
7031 }
7032 }
7033
7034 pub fn pull_diagnostics_for_buffer(
7035 &mut self,
7036 buffer: Entity<Buffer>,
7037 cx: &mut Context<Self>,
7038 ) -> Task<anyhow::Result<()>> {
7039 let diagnostics = self.pull_diagnostics(buffer, cx);
7040 cx.spawn(async move |lsp_store, cx| {
7041 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7042 return Ok(());
7043 };
7044 lsp_store.update(cx, |lsp_store, cx| {
7045 if lsp_store.as_local().is_none() {
7046 return;
7047 }
7048
7049 let mut unchanged_buffers = HashSet::default();
7050 let mut changed_buffers = HashSet::default();
7051 let server_diagnostics_updates = diagnostics
7052 .into_iter()
7053 .filter_map(|diagnostics_set| match diagnostics_set {
7054 LspPullDiagnostics::Response {
7055 server_id,
7056 uri,
7057 diagnostics,
7058 } => Some((server_id, uri, diagnostics)),
7059 LspPullDiagnostics::Default => None,
7060 })
7061 .fold(
7062 HashMap::default(),
7063 |mut acc, (server_id, uri, diagnostics)| {
7064 let (result_id, diagnostics) = match diagnostics {
7065 PulledDiagnostics::Unchanged { result_id } => {
7066 unchanged_buffers.insert(uri.clone());
7067 (Some(result_id), Vec::new())
7068 }
7069 PulledDiagnostics::Changed {
7070 result_id,
7071 diagnostics,
7072 } => {
7073 changed_buffers.insert(uri.clone());
7074 (result_id, diagnostics)
7075 }
7076 };
7077 let disk_based_sources = Cow::Owned(
7078 lsp_store
7079 .language_server_adapter_for_id(server_id)
7080 .as_ref()
7081 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7082 .unwrap_or(&[])
7083 .to_vec(),
7084 );
7085 acc.entry(server_id).or_insert_with(Vec::new).push(
7086 DocumentDiagnosticsUpdate {
7087 server_id,
7088 diagnostics: lsp::PublishDiagnosticsParams {
7089 uri,
7090 diagnostics,
7091 version: None,
7092 },
7093 result_id,
7094 disk_based_sources,
7095 },
7096 );
7097 acc
7098 },
7099 );
7100
7101 for diagnostic_updates in server_diagnostics_updates.into_values() {
7102 lsp_store
7103 .merge_lsp_diagnostics(
7104 DiagnosticSourceKind::Pulled,
7105 diagnostic_updates,
7106 |buffer, old_diagnostic, cx| {
7107 File::from_dyn(buffer.file())
7108 .and_then(|file| {
7109 let abs_path = file.as_local()?.abs_path(cx);
7110 lsp::Uri::from_file_path(abs_path).ok()
7111 })
7112 .is_none_or(|buffer_uri| {
7113 unchanged_buffers.contains(&buffer_uri)
7114 || match old_diagnostic.source_kind {
7115 DiagnosticSourceKind::Pulled => {
7116 !changed_buffers.contains(&buffer_uri)
7117 }
7118 DiagnosticSourceKind::Other
7119 | DiagnosticSourceKind::Pushed => true,
7120 }
7121 })
7122 },
7123 cx,
7124 )
7125 .log_err();
7126 }
7127 })
7128 })
7129 }
7130
7131 pub fn document_colors(
7132 &mut self,
7133 known_cache_version: Option<usize>,
7134 buffer: Entity<Buffer>,
7135 cx: &mut Context<Self>,
7136 ) -> Option<DocumentColorTask> {
7137 let version_queried_for = buffer.read(cx).version();
7138 let buffer_id = buffer.read(cx).remote_id();
7139
7140 let current_language_servers = self.as_local().map(|local| {
7141 local
7142 .buffers_opened_in_servers
7143 .get(&buffer_id)
7144 .cloned()
7145 .unwrap_or_default()
7146 });
7147
7148 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7149 if let Some(cached_colors) = &lsp_data.document_colors {
7150 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7151 let has_different_servers =
7152 current_language_servers.is_some_and(|current_language_servers| {
7153 current_language_servers
7154 != cached_colors.colors.keys().copied().collect()
7155 });
7156 if !has_different_servers {
7157 let cache_version = cached_colors.cache_version;
7158 if Some(cache_version) == known_cache_version {
7159 return None;
7160 } else {
7161 return Some(
7162 Task::ready(Ok(DocumentColors {
7163 colors: cached_colors
7164 .colors
7165 .values()
7166 .flatten()
7167 .cloned()
7168 .collect(),
7169 cache_version: Some(cache_version),
7170 }))
7171 .shared(),
7172 );
7173 }
7174 }
7175 }
7176 }
7177 }
7178
7179 let color_lsp_data = self
7180 .latest_lsp_data(&buffer, cx)
7181 .document_colors
7182 .get_or_insert_default();
7183 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7184 && !version_queried_for.changed_since(updating_for)
7185 {
7186 return Some(running_update.clone());
7187 }
7188 let buffer_version_queried_for = version_queried_for.clone();
7189 let new_task = cx
7190 .spawn(async move |lsp_store, cx| {
7191 cx.background_executor()
7192 .timer(Duration::from_millis(30))
7193 .await;
7194 let fetched_colors = lsp_store
7195 .update(cx, |lsp_store, cx| {
7196 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7197 })?
7198 .await
7199 .context("fetching document colors")
7200 .map_err(Arc::new);
7201 let fetched_colors = match fetched_colors {
7202 Ok(fetched_colors) => {
7203 if Some(true)
7204 == buffer
7205 .update(cx, |buffer, _| {
7206 buffer.version() != buffer_version_queried_for
7207 })
7208 .ok()
7209 {
7210 return Ok(DocumentColors::default());
7211 }
7212 fetched_colors
7213 }
7214 Err(e) => {
7215 lsp_store
7216 .update(cx, |lsp_store, _| {
7217 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7218 if let Some(document_colors) = &mut lsp_data.document_colors {
7219 document_colors.colors_update = None;
7220 }
7221 }
7222 })
7223 .ok();
7224 return Err(e);
7225 }
7226 };
7227
7228 lsp_store
7229 .update(cx, |lsp_store, cx| {
7230 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7231 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7232
7233 if let Some(fetched_colors) = fetched_colors {
7234 if lsp_data.buffer_version == buffer_version_queried_for {
7235 lsp_colors.colors.extend(fetched_colors);
7236 lsp_colors.cache_version += 1;
7237 } else if !lsp_data
7238 .buffer_version
7239 .changed_since(&buffer_version_queried_for)
7240 {
7241 lsp_data.buffer_version = buffer_version_queried_for;
7242 lsp_colors.colors = fetched_colors;
7243 lsp_colors.cache_version += 1;
7244 }
7245 }
7246 lsp_colors.colors_update = None;
7247 let colors = lsp_colors
7248 .colors
7249 .values()
7250 .flatten()
7251 .cloned()
7252 .collect::<HashSet<_>>();
7253 DocumentColors {
7254 colors,
7255 cache_version: Some(lsp_colors.cache_version),
7256 }
7257 })
7258 .map_err(Arc::new)
7259 })
7260 .shared();
7261 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7262 Some(new_task)
7263 }
7264
7265 fn fetch_document_colors_for_buffer(
7266 &mut self,
7267 buffer: &Entity<Buffer>,
7268 cx: &mut Context<Self>,
7269 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7270 if let Some((client, project_id)) = self.upstream_client() {
7271 let request = GetDocumentColor {};
7272 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7273 return Task::ready(Ok(None));
7274 }
7275
7276 let request_task = client.request_lsp(
7277 project_id,
7278 None,
7279 LSP_REQUEST_TIMEOUT,
7280 cx.background_executor().clone(),
7281 request.to_proto(project_id, buffer.read(cx)),
7282 );
7283 let buffer = buffer.clone();
7284 cx.spawn(async move |lsp_store, cx| {
7285 let Some(lsp_store) = lsp_store.upgrade() else {
7286 return Ok(None);
7287 };
7288 let colors = join_all(
7289 request_task
7290 .await
7291 .log_err()
7292 .flatten()
7293 .map(|response| response.payload)
7294 .unwrap_or_default()
7295 .into_iter()
7296 .map(|color_response| {
7297 let response = request.response_from_proto(
7298 color_response.response,
7299 lsp_store.clone(),
7300 buffer.clone(),
7301 cx.clone(),
7302 );
7303 async move {
7304 (
7305 LanguageServerId::from_proto(color_response.server_id),
7306 response.await.log_err().unwrap_or_default(),
7307 )
7308 }
7309 }),
7310 )
7311 .await
7312 .into_iter()
7313 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7314 acc.entry(server_id)
7315 .or_insert_with(HashSet::default)
7316 .extend(colors);
7317 acc
7318 });
7319 Ok(Some(colors))
7320 })
7321 } else {
7322 let document_colors_task =
7323 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7324 cx.background_spawn(async move {
7325 Ok(Some(
7326 document_colors_task
7327 .await
7328 .into_iter()
7329 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7330 acc.entry(server_id)
7331 .or_insert_with(HashSet::default)
7332 .extend(colors);
7333 acc
7334 })
7335 .into_iter()
7336 .collect(),
7337 ))
7338 })
7339 }
7340 }
7341
7342 pub fn signature_help<T: ToPointUtf16>(
7343 &mut self,
7344 buffer: &Entity<Buffer>,
7345 position: T,
7346 cx: &mut Context<Self>,
7347 ) -> Task<Option<Vec<SignatureHelp>>> {
7348 let position = position.to_point_utf16(buffer.read(cx));
7349
7350 if let Some((client, upstream_project_id)) = self.upstream_client() {
7351 let request = GetSignatureHelp { position };
7352 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7353 return Task::ready(None);
7354 }
7355 let request_task = client.request_lsp(
7356 upstream_project_id,
7357 None,
7358 LSP_REQUEST_TIMEOUT,
7359 cx.background_executor().clone(),
7360 request.to_proto(upstream_project_id, buffer.read(cx)),
7361 );
7362 let buffer = buffer.clone();
7363 cx.spawn(async move |weak_lsp_store, cx| {
7364 let lsp_store = weak_lsp_store.upgrade()?;
7365 let signatures = join_all(
7366 request_task
7367 .await
7368 .log_err()
7369 .flatten()
7370 .map(|response| response.payload)
7371 .unwrap_or_default()
7372 .into_iter()
7373 .map(|response| {
7374 let response = GetSignatureHelp { position }.response_from_proto(
7375 response.response,
7376 lsp_store.clone(),
7377 buffer.clone(),
7378 cx.clone(),
7379 );
7380 async move { response.await.log_err().flatten() }
7381 }),
7382 )
7383 .await
7384 .into_iter()
7385 .flatten()
7386 .collect();
7387 Some(signatures)
7388 })
7389 } else {
7390 let all_actions_task = self.request_multiple_lsp_locally(
7391 buffer,
7392 Some(position),
7393 GetSignatureHelp { position },
7394 cx,
7395 );
7396 cx.background_spawn(async move {
7397 Some(
7398 all_actions_task
7399 .await
7400 .into_iter()
7401 .flat_map(|(_, actions)| actions)
7402 .collect::<Vec<_>>(),
7403 )
7404 })
7405 }
7406 }
7407
7408 pub fn hover(
7409 &mut self,
7410 buffer: &Entity<Buffer>,
7411 position: PointUtf16,
7412 cx: &mut Context<Self>,
7413 ) -> Task<Option<Vec<Hover>>> {
7414 if let Some((client, upstream_project_id)) = self.upstream_client() {
7415 let request = GetHover { position };
7416 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7417 return Task::ready(None);
7418 }
7419 let request_task = client.request_lsp(
7420 upstream_project_id,
7421 None,
7422 LSP_REQUEST_TIMEOUT,
7423 cx.background_executor().clone(),
7424 request.to_proto(upstream_project_id, buffer.read(cx)),
7425 );
7426 let buffer = buffer.clone();
7427 cx.spawn(async move |weak_lsp_store, cx| {
7428 let lsp_store = weak_lsp_store.upgrade()?;
7429 let hovers = join_all(
7430 request_task
7431 .await
7432 .log_err()
7433 .flatten()
7434 .map(|response| response.payload)
7435 .unwrap_or_default()
7436 .into_iter()
7437 .map(|response| {
7438 let response = GetHover { position }.response_from_proto(
7439 response.response,
7440 lsp_store.clone(),
7441 buffer.clone(),
7442 cx.clone(),
7443 );
7444 async move {
7445 response
7446 .await
7447 .log_err()
7448 .flatten()
7449 .and_then(remove_empty_hover_blocks)
7450 }
7451 }),
7452 )
7453 .await
7454 .into_iter()
7455 .flatten()
7456 .collect();
7457 Some(hovers)
7458 })
7459 } else {
7460 let all_actions_task = self.request_multiple_lsp_locally(
7461 buffer,
7462 Some(position),
7463 GetHover { position },
7464 cx,
7465 );
7466 cx.background_spawn(async move {
7467 Some(
7468 all_actions_task
7469 .await
7470 .into_iter()
7471 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7472 .collect::<Vec<Hover>>(),
7473 )
7474 })
7475 }
7476 }
7477
7478 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7479 let language_registry = self.languages.clone();
7480
7481 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7482 let request = upstream_client.request(proto::GetProjectSymbols {
7483 project_id: *project_id,
7484 query: query.to_string(),
7485 });
7486 cx.foreground_executor().spawn(async move {
7487 let response = request.await?;
7488 let mut symbols = Vec::new();
7489 let core_symbols = response
7490 .symbols
7491 .into_iter()
7492 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7493 .collect::<Vec<_>>();
7494 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7495 .await;
7496 Ok(symbols)
7497 })
7498 } else if let Some(local) = self.as_local() {
7499 struct WorkspaceSymbolsResult {
7500 server_id: LanguageServerId,
7501 lsp_adapter: Arc<CachedLspAdapter>,
7502 worktree: WeakEntity<Worktree>,
7503 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7504 }
7505
7506 let mut requests = Vec::new();
7507 let mut requested_servers = BTreeSet::new();
7508 for (seed, state) in local.language_server_ids.iter() {
7509 let Some(worktree_handle) = self
7510 .worktree_store
7511 .read(cx)
7512 .worktree_for_id(seed.worktree_id, cx)
7513 else {
7514 continue;
7515 };
7516 let worktree = worktree_handle.read(cx);
7517 if !worktree.is_visible() {
7518 continue;
7519 }
7520
7521 if !requested_servers.insert(state.id) {
7522 continue;
7523 }
7524
7525 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7526 Some(LanguageServerState::Running {
7527 adapter, server, ..
7528 }) => (adapter.clone(), server),
7529
7530 _ => continue,
7531 };
7532 let supports_workspace_symbol_request =
7533 match server.capabilities().workspace_symbol_provider {
7534 Some(OneOf::Left(supported)) => supported,
7535 Some(OneOf::Right(_)) => true,
7536 None => false,
7537 };
7538 if !supports_workspace_symbol_request {
7539 continue;
7540 }
7541 let worktree_handle = worktree_handle.clone();
7542 let server_id = server.server_id();
7543 requests.push(
7544 server
7545 .request::<lsp::request::WorkspaceSymbolRequest>(
7546 lsp::WorkspaceSymbolParams {
7547 query: query.to_string(),
7548 ..Default::default()
7549 },
7550 )
7551 .map(move |response| {
7552 let lsp_symbols = response.into_response()
7553 .context("workspace symbols request")
7554 .log_err()
7555 .flatten()
7556 .map(|symbol_response| match symbol_response {
7557 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7558 flat_responses.into_iter().map(|lsp_symbol| {
7559 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7560 }).collect::<Vec<_>>()
7561 }
7562 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7563 nested_responses.into_iter().filter_map(|lsp_symbol| {
7564 let location = match lsp_symbol.location {
7565 OneOf::Left(location) => location,
7566 OneOf::Right(_) => {
7567 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7568 return None
7569 }
7570 };
7571 Some((lsp_symbol.name, lsp_symbol.kind, location))
7572 }).collect::<Vec<_>>()
7573 }
7574 }).unwrap_or_default();
7575
7576 WorkspaceSymbolsResult {
7577 server_id,
7578 lsp_adapter,
7579 worktree: worktree_handle.downgrade(),
7580 lsp_symbols,
7581 }
7582 }),
7583 );
7584 }
7585
7586 cx.spawn(async move |this, cx| {
7587 let responses = futures::future::join_all(requests).await;
7588 let this = match this.upgrade() {
7589 Some(this) => this,
7590 None => return Ok(Vec::new()),
7591 };
7592
7593 let mut symbols = Vec::new();
7594 for result in responses {
7595 let core_symbols = this.update(cx, |this, cx| {
7596 result
7597 .lsp_symbols
7598 .into_iter()
7599 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7600 let abs_path = symbol_location.uri.to_file_path().ok()?;
7601 let source_worktree = result.worktree.upgrade()?;
7602 let source_worktree_id = source_worktree.read(cx).id();
7603
7604 let path = if let Some((tree, rel_path)) =
7605 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7606 {
7607 let worktree_id = tree.read(cx).id();
7608 SymbolLocation::InProject(ProjectPath {
7609 worktree_id,
7610 path: rel_path,
7611 })
7612 } else {
7613 SymbolLocation::OutsideProject {
7614 signature: this.symbol_signature(&abs_path),
7615 abs_path: abs_path.into(),
7616 }
7617 };
7618
7619 Some(CoreSymbol {
7620 source_language_server_id: result.server_id,
7621 language_server_name: result.lsp_adapter.name.clone(),
7622 source_worktree_id,
7623 path,
7624 kind: symbol_kind,
7625 name: symbol_name,
7626 range: range_from_lsp(symbol_location.range),
7627 })
7628 })
7629 .collect()
7630 })?;
7631
7632 populate_labels_for_symbols(
7633 core_symbols,
7634 &language_registry,
7635 Some(result.lsp_adapter),
7636 &mut symbols,
7637 )
7638 .await;
7639 }
7640
7641 Ok(symbols)
7642 })
7643 } else {
7644 Task::ready(Err(anyhow!("No upstream client or local language server")))
7645 }
7646 }
7647
7648 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7649 let mut summary = DiagnosticSummary::default();
7650 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7651 summary.error_count += path_summary.error_count;
7652 summary.warning_count += path_summary.warning_count;
7653 }
7654 summary
7655 }
7656
7657 /// Returns the diagnostic summary for a specific project path.
7658 pub fn diagnostic_summary_for_path(
7659 &self,
7660 project_path: &ProjectPath,
7661 _: &App,
7662 ) -> DiagnosticSummary {
7663 if let Some(summaries) = self
7664 .diagnostic_summaries
7665 .get(&project_path.worktree_id)
7666 .and_then(|map| map.get(&project_path.path))
7667 {
7668 let (error_count, warning_count) = summaries.iter().fold(
7669 (0, 0),
7670 |(error_count, warning_count), (_language_server_id, summary)| {
7671 (
7672 error_count + summary.error_count,
7673 warning_count + summary.warning_count,
7674 )
7675 },
7676 );
7677
7678 DiagnosticSummary {
7679 error_count,
7680 warning_count,
7681 }
7682 } else {
7683 DiagnosticSummary::default()
7684 }
7685 }
7686
7687 pub fn diagnostic_summaries<'a>(
7688 &'a self,
7689 include_ignored: bool,
7690 cx: &'a App,
7691 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7692 self.worktree_store
7693 .read(cx)
7694 .visible_worktrees(cx)
7695 .filter_map(|worktree| {
7696 let worktree = worktree.read(cx);
7697 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7698 })
7699 .flat_map(move |(worktree, summaries)| {
7700 let worktree_id = worktree.id();
7701 summaries
7702 .iter()
7703 .filter(move |(path, _)| {
7704 include_ignored
7705 || worktree
7706 .entry_for_path(path.as_ref())
7707 .is_some_and(|entry| !entry.is_ignored)
7708 })
7709 .flat_map(move |(path, summaries)| {
7710 summaries.iter().map(move |(server_id, summary)| {
7711 (
7712 ProjectPath {
7713 worktree_id,
7714 path: path.clone(),
7715 },
7716 *server_id,
7717 *summary,
7718 )
7719 })
7720 })
7721 })
7722 }
7723
7724 pub fn on_buffer_edited(
7725 &mut self,
7726 buffer: Entity<Buffer>,
7727 cx: &mut Context<Self>,
7728 ) -> Option<()> {
7729 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7730 Some(
7731 self.as_local()?
7732 .language_servers_for_buffer(buffer, cx)
7733 .map(|i| i.1.clone())
7734 .collect(),
7735 )
7736 })?;
7737
7738 let buffer = buffer.read(cx);
7739 let file = File::from_dyn(buffer.file())?;
7740 let abs_path = file.as_local()?.abs_path(cx);
7741 let uri = lsp::Uri::from_file_path(&abs_path)
7742 .ok()
7743 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7744 .log_err()?;
7745 let next_snapshot = buffer.text_snapshot();
7746 for language_server in language_servers {
7747 let language_server = language_server.clone();
7748
7749 let buffer_snapshots = self
7750 .as_local_mut()?
7751 .buffer_snapshots
7752 .get_mut(&buffer.remote_id())
7753 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7754 let previous_snapshot = buffer_snapshots.last()?;
7755
7756 let build_incremental_change = || {
7757 buffer
7758 .edits_since::<Dimensions<PointUtf16, usize>>(
7759 previous_snapshot.snapshot.version(),
7760 )
7761 .map(|edit| {
7762 let edit_start = edit.new.start.0;
7763 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7764 let new_text = next_snapshot
7765 .text_for_range(edit.new.start.1..edit.new.end.1)
7766 .collect();
7767 lsp::TextDocumentContentChangeEvent {
7768 range: Some(lsp::Range::new(
7769 point_to_lsp(edit_start),
7770 point_to_lsp(edit_end),
7771 )),
7772 range_length: None,
7773 text: new_text,
7774 }
7775 })
7776 .collect()
7777 };
7778
7779 let document_sync_kind = language_server
7780 .capabilities()
7781 .text_document_sync
7782 .as_ref()
7783 .and_then(|sync| match sync {
7784 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7785 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7786 });
7787
7788 let content_changes: Vec<_> = match document_sync_kind {
7789 Some(lsp::TextDocumentSyncKind::FULL) => {
7790 vec![lsp::TextDocumentContentChangeEvent {
7791 range: None,
7792 range_length: None,
7793 text: next_snapshot.text(),
7794 }]
7795 }
7796 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7797 _ => {
7798 #[cfg(any(test, feature = "test-support"))]
7799 {
7800 build_incremental_change()
7801 }
7802
7803 #[cfg(not(any(test, feature = "test-support")))]
7804 {
7805 continue;
7806 }
7807 }
7808 };
7809
7810 let next_version = previous_snapshot.version + 1;
7811 buffer_snapshots.push(LspBufferSnapshot {
7812 version: next_version,
7813 snapshot: next_snapshot.clone(),
7814 });
7815
7816 language_server
7817 .notify::<lsp::notification::DidChangeTextDocument>(
7818 lsp::DidChangeTextDocumentParams {
7819 text_document: lsp::VersionedTextDocumentIdentifier::new(
7820 uri.clone(),
7821 next_version,
7822 ),
7823 content_changes,
7824 },
7825 )
7826 .ok();
7827 self.pull_workspace_diagnostics(language_server.server_id());
7828 }
7829
7830 None
7831 }
7832
7833 pub fn on_buffer_saved(
7834 &mut self,
7835 buffer: Entity<Buffer>,
7836 cx: &mut Context<Self>,
7837 ) -> Option<()> {
7838 let file = File::from_dyn(buffer.read(cx).file())?;
7839 let worktree_id = file.worktree_id(cx);
7840 let abs_path = file.as_local()?.abs_path(cx);
7841 let text_document = lsp::TextDocumentIdentifier {
7842 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7843 };
7844 let local = self.as_local()?;
7845
7846 for server in local.language_servers_for_worktree(worktree_id) {
7847 if let Some(include_text) = include_text(server.as_ref()) {
7848 let text = if include_text {
7849 Some(buffer.read(cx).text())
7850 } else {
7851 None
7852 };
7853 server
7854 .notify::<lsp::notification::DidSaveTextDocument>(
7855 lsp::DidSaveTextDocumentParams {
7856 text_document: text_document.clone(),
7857 text,
7858 },
7859 )
7860 .ok();
7861 }
7862 }
7863
7864 let language_servers = buffer.update(cx, |buffer, cx| {
7865 local.language_server_ids_for_buffer(buffer, cx)
7866 });
7867 for language_server_id in language_servers {
7868 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7869 }
7870
7871 None
7872 }
7873
7874 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7875 maybe!(async move {
7876 let mut refreshed_servers = HashSet::default();
7877 let servers = lsp_store
7878 .update(cx, |lsp_store, cx| {
7879 let local = lsp_store.as_local()?;
7880
7881 let servers = local
7882 .language_server_ids
7883 .iter()
7884 .filter_map(|(seed, state)| {
7885 let worktree = lsp_store
7886 .worktree_store
7887 .read(cx)
7888 .worktree_for_id(seed.worktree_id, cx);
7889 let delegate: Arc<dyn LspAdapterDelegate> =
7890 worktree.map(|worktree| {
7891 LocalLspAdapterDelegate::new(
7892 local.languages.clone(),
7893 &local.environment,
7894 cx.weak_entity(),
7895 &worktree,
7896 local.http_client.clone(),
7897 local.fs.clone(),
7898 cx,
7899 )
7900 })?;
7901 let server_id = state.id;
7902
7903 let states = local.language_servers.get(&server_id)?;
7904
7905 match states {
7906 LanguageServerState::Starting { .. } => None,
7907 LanguageServerState::Running {
7908 adapter, server, ..
7909 } => {
7910 let adapter = adapter.clone();
7911 let server = server.clone();
7912 refreshed_servers.insert(server.name());
7913 let toolchain = seed.toolchain.clone();
7914 Some(cx.spawn(async move |_, cx| {
7915 let settings =
7916 LocalLspStore::workspace_configuration_for_adapter(
7917 adapter.adapter.clone(),
7918 &delegate,
7919 toolchain,
7920 cx,
7921 )
7922 .await
7923 .ok()?;
7924 server
7925 .notify::<lsp::notification::DidChangeConfiguration>(
7926 lsp::DidChangeConfigurationParams { settings },
7927 )
7928 .ok()?;
7929 Some(())
7930 }))
7931 }
7932 }
7933 })
7934 .collect::<Vec<_>>();
7935
7936 Some(servers)
7937 })
7938 .ok()
7939 .flatten()?;
7940
7941 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7942 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7943 // to stop and unregister its language server wrapper.
7944 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7945 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7946 let _: Vec<Option<()>> = join_all(servers).await;
7947
7948 Some(())
7949 })
7950 .await;
7951 }
7952
7953 fn maintain_workspace_config(
7954 external_refresh_requests: watch::Receiver<()>,
7955 cx: &mut Context<Self>,
7956 ) -> Task<Result<()>> {
7957 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7958 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7959
7960 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7961 *settings_changed_tx.borrow_mut() = ();
7962 });
7963
7964 let mut joint_future =
7965 futures::stream::select(settings_changed_rx, external_refresh_requests);
7966 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7967 // - 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).
7968 // - 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.
7969 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7970 // - 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,
7971 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7972 cx.spawn(async move |this, cx| {
7973 while let Some(()) = joint_future.next().await {
7974 this.update(cx, |this, cx| {
7975 this.refresh_server_tree(cx);
7976 })
7977 .ok();
7978
7979 Self::refresh_workspace_configurations(&this, cx).await;
7980 }
7981
7982 drop(settings_observation);
7983 anyhow::Ok(())
7984 })
7985 }
7986
7987 pub fn language_servers_for_local_buffer<'a>(
7988 &'a self,
7989 buffer: &Buffer,
7990 cx: &mut App,
7991 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7992 let local = self.as_local();
7993 let language_server_ids = local
7994 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7995 .unwrap_or_default();
7996
7997 language_server_ids
7998 .into_iter()
7999 .filter_map(
8000 move |server_id| match local?.language_servers.get(&server_id)? {
8001 LanguageServerState::Running {
8002 adapter, server, ..
8003 } => Some((adapter, server)),
8004 _ => None,
8005 },
8006 )
8007 }
8008
8009 pub fn language_server_for_local_buffer<'a>(
8010 &'a self,
8011 buffer: &'a Buffer,
8012 server_id: LanguageServerId,
8013 cx: &'a mut App,
8014 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8015 self.as_local()?
8016 .language_servers_for_buffer(buffer, cx)
8017 .find(|(_, s)| s.server_id() == server_id)
8018 }
8019
8020 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8021 self.diagnostic_summaries.remove(&id_to_remove);
8022 if let Some(local) = self.as_local_mut() {
8023 let to_remove = local.remove_worktree(id_to_remove, cx);
8024 for server in to_remove {
8025 self.language_server_statuses.remove(&server);
8026 }
8027 }
8028 }
8029
8030 pub fn shared(
8031 &mut self,
8032 project_id: u64,
8033 downstream_client: AnyProtoClient,
8034 _: &mut Context<Self>,
8035 ) {
8036 self.downstream_client = Some((downstream_client.clone(), project_id));
8037
8038 for (server_id, status) in &self.language_server_statuses {
8039 if let Some(server) = self.language_server_for_id(*server_id) {
8040 downstream_client
8041 .send(proto::StartLanguageServer {
8042 project_id,
8043 server: Some(proto::LanguageServer {
8044 id: server_id.to_proto(),
8045 name: status.name.to_string(),
8046 worktree_id: status.worktree.map(|id| id.to_proto()),
8047 }),
8048 capabilities: serde_json::to_string(&server.capabilities())
8049 .expect("serializing server LSP capabilities"),
8050 })
8051 .log_err();
8052 }
8053 }
8054 }
8055
8056 pub fn disconnected_from_host(&mut self) {
8057 self.downstream_client.take();
8058 }
8059
8060 pub fn disconnected_from_ssh_remote(&mut self) {
8061 if let LspStoreMode::Remote(RemoteLspStore {
8062 upstream_client, ..
8063 }) = &mut self.mode
8064 {
8065 upstream_client.take();
8066 }
8067 }
8068
8069 pub(crate) fn set_language_server_statuses_from_proto(
8070 &mut self,
8071 project: WeakEntity<Project>,
8072 language_servers: Vec<proto::LanguageServer>,
8073 server_capabilities: Vec<String>,
8074 cx: &mut Context<Self>,
8075 ) {
8076 let lsp_logs = cx
8077 .try_global::<GlobalLogStore>()
8078 .map(|lsp_store| lsp_store.0.clone());
8079
8080 self.language_server_statuses = language_servers
8081 .into_iter()
8082 .zip(server_capabilities)
8083 .map(|(server, server_capabilities)| {
8084 let server_id = LanguageServerId(server.id as usize);
8085 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8086 self.lsp_server_capabilities
8087 .insert(server_id, server_capabilities);
8088 }
8089
8090 let name = LanguageServerName::from_proto(server.name);
8091 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8092
8093 if let Some(lsp_logs) = &lsp_logs {
8094 lsp_logs.update(cx, |lsp_logs, cx| {
8095 lsp_logs.add_language_server(
8096 // Only remote clients get their language servers set from proto
8097 LanguageServerKind::Remote {
8098 project: project.clone(),
8099 },
8100 server_id,
8101 Some(name.clone()),
8102 worktree,
8103 None,
8104 cx,
8105 );
8106 });
8107 }
8108
8109 (
8110 server_id,
8111 LanguageServerStatus {
8112 name,
8113 pending_work: Default::default(),
8114 has_pending_diagnostic_updates: false,
8115 progress_tokens: Default::default(),
8116 worktree,
8117 },
8118 )
8119 })
8120 .collect();
8121 }
8122
8123 #[cfg(test)]
8124 pub fn update_diagnostic_entries(
8125 &mut self,
8126 server_id: LanguageServerId,
8127 abs_path: PathBuf,
8128 result_id: Option<String>,
8129 version: Option<i32>,
8130 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8131 cx: &mut Context<Self>,
8132 ) -> anyhow::Result<()> {
8133 self.merge_diagnostic_entries(
8134 vec![DocumentDiagnosticsUpdate {
8135 diagnostics: DocumentDiagnostics {
8136 diagnostics,
8137 document_abs_path: abs_path,
8138 version,
8139 },
8140 result_id,
8141 server_id,
8142 disk_based_sources: Cow::Borrowed(&[]),
8143 }],
8144 |_, _, _| false,
8145 cx,
8146 )?;
8147 Ok(())
8148 }
8149
8150 pub fn merge_diagnostic_entries<'a>(
8151 &mut self,
8152 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8153 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8154 cx: &mut Context<Self>,
8155 ) -> anyhow::Result<()> {
8156 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8157 let mut updated_diagnostics_paths = HashMap::default();
8158 for mut update in diagnostic_updates {
8159 let abs_path = &update.diagnostics.document_abs_path;
8160 let server_id = update.server_id;
8161 let Some((worktree, relative_path)) =
8162 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8163 else {
8164 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8165 return Ok(());
8166 };
8167
8168 let worktree_id = worktree.read(cx).id();
8169 let project_path = ProjectPath {
8170 worktree_id,
8171 path: relative_path,
8172 };
8173
8174 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8175 let snapshot = buffer_handle.read(cx).snapshot();
8176 let buffer = buffer_handle.read(cx);
8177 let reused_diagnostics = buffer
8178 .buffer_diagnostics(Some(server_id))
8179 .iter()
8180 .filter(|v| merge(buffer, &v.diagnostic, cx))
8181 .map(|v| {
8182 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8183 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8184 DiagnosticEntry {
8185 range: start..end,
8186 diagnostic: v.diagnostic.clone(),
8187 }
8188 })
8189 .collect::<Vec<_>>();
8190
8191 self.as_local_mut()
8192 .context("cannot merge diagnostics on a remote LspStore")?
8193 .update_buffer_diagnostics(
8194 &buffer_handle,
8195 server_id,
8196 update.result_id,
8197 update.diagnostics.version,
8198 update.diagnostics.diagnostics.clone(),
8199 reused_diagnostics.clone(),
8200 cx,
8201 )?;
8202
8203 update.diagnostics.diagnostics.extend(reused_diagnostics);
8204 }
8205
8206 let updated = worktree.update(cx, |worktree, cx| {
8207 self.update_worktree_diagnostics(
8208 worktree.id(),
8209 server_id,
8210 project_path.path.clone(),
8211 update.diagnostics.diagnostics,
8212 cx,
8213 )
8214 })?;
8215 match updated {
8216 ControlFlow::Continue(new_summary) => {
8217 if let Some((project_id, new_summary)) = new_summary {
8218 match &mut diagnostics_summary {
8219 Some(diagnostics_summary) => {
8220 diagnostics_summary
8221 .more_summaries
8222 .push(proto::DiagnosticSummary {
8223 path: project_path.path.as_ref().to_proto(),
8224 language_server_id: server_id.0 as u64,
8225 error_count: new_summary.error_count,
8226 warning_count: new_summary.warning_count,
8227 })
8228 }
8229 None => {
8230 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8231 project_id,
8232 worktree_id: worktree_id.to_proto(),
8233 summary: Some(proto::DiagnosticSummary {
8234 path: project_path.path.as_ref().to_proto(),
8235 language_server_id: server_id.0 as u64,
8236 error_count: new_summary.error_count,
8237 warning_count: new_summary.warning_count,
8238 }),
8239 more_summaries: Vec::new(),
8240 })
8241 }
8242 }
8243 }
8244 updated_diagnostics_paths
8245 .entry(server_id)
8246 .or_insert_with(Vec::new)
8247 .push(project_path);
8248 }
8249 ControlFlow::Break(()) => {}
8250 }
8251 }
8252
8253 if let Some((diagnostics_summary, (downstream_client, _))) =
8254 diagnostics_summary.zip(self.downstream_client.as_ref())
8255 {
8256 downstream_client.send(diagnostics_summary).log_err();
8257 }
8258 for (server_id, paths) in updated_diagnostics_paths {
8259 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8260 }
8261 Ok(())
8262 }
8263
8264 fn update_worktree_diagnostics(
8265 &mut self,
8266 worktree_id: WorktreeId,
8267 server_id: LanguageServerId,
8268 path_in_worktree: Arc<RelPath>,
8269 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8270 _: &mut Context<Worktree>,
8271 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8272 let local = match &mut self.mode {
8273 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8274 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8275 };
8276
8277 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8278 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8279 let summaries_by_server_id = summaries_for_tree
8280 .entry(path_in_worktree.clone())
8281 .or_default();
8282
8283 let old_summary = summaries_by_server_id
8284 .remove(&server_id)
8285 .unwrap_or_default();
8286
8287 let new_summary = DiagnosticSummary::new(&diagnostics);
8288 if new_summary.is_empty() {
8289 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8290 {
8291 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8292 diagnostics_by_server_id.remove(ix);
8293 }
8294 if diagnostics_by_server_id.is_empty() {
8295 diagnostics_for_tree.remove(&path_in_worktree);
8296 }
8297 }
8298 } else {
8299 summaries_by_server_id.insert(server_id, new_summary);
8300 let diagnostics_by_server_id = diagnostics_for_tree
8301 .entry(path_in_worktree.clone())
8302 .or_default();
8303 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8304 Ok(ix) => {
8305 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8306 }
8307 Err(ix) => {
8308 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8309 }
8310 }
8311 }
8312
8313 if !old_summary.is_empty() || !new_summary.is_empty() {
8314 if let Some((_, project_id)) = &self.downstream_client {
8315 Ok(ControlFlow::Continue(Some((
8316 *project_id,
8317 proto::DiagnosticSummary {
8318 path: path_in_worktree.to_proto(),
8319 language_server_id: server_id.0 as u64,
8320 error_count: new_summary.error_count as u32,
8321 warning_count: new_summary.warning_count as u32,
8322 },
8323 ))))
8324 } else {
8325 Ok(ControlFlow::Continue(None))
8326 }
8327 } else {
8328 Ok(ControlFlow::Break(()))
8329 }
8330 }
8331
8332 pub fn open_buffer_for_symbol(
8333 &mut self,
8334 symbol: &Symbol,
8335 cx: &mut Context<Self>,
8336 ) -> Task<Result<Entity<Buffer>>> {
8337 if let Some((client, project_id)) = self.upstream_client() {
8338 let request = client.request(proto::OpenBufferForSymbol {
8339 project_id,
8340 symbol: Some(Self::serialize_symbol(symbol)),
8341 });
8342 cx.spawn(async move |this, cx| {
8343 let response = request.await?;
8344 let buffer_id = BufferId::new(response.buffer_id)?;
8345 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8346 .await
8347 })
8348 } else if let Some(local) = self.as_local() {
8349 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8350 seed.worktree_id == symbol.source_worktree_id
8351 && state.id == symbol.source_language_server_id
8352 && symbol.language_server_name == seed.name
8353 });
8354 if !is_valid {
8355 return Task::ready(Err(anyhow!(
8356 "language server for worktree and language not found"
8357 )));
8358 };
8359
8360 let symbol_abs_path = match &symbol.path {
8361 SymbolLocation::InProject(project_path) => self
8362 .worktree_store
8363 .read(cx)
8364 .absolutize(&project_path, cx)
8365 .context("no such worktree"),
8366 SymbolLocation::OutsideProject {
8367 abs_path,
8368 signature: _,
8369 } => Ok(abs_path.to_path_buf()),
8370 };
8371 let symbol_abs_path = match symbol_abs_path {
8372 Ok(abs_path) => abs_path,
8373 Err(err) => return Task::ready(Err(err)),
8374 };
8375 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8376 uri
8377 } else {
8378 return Task::ready(Err(anyhow!("invalid symbol path")));
8379 };
8380
8381 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8382 } else {
8383 Task::ready(Err(anyhow!("no upstream client or local store")))
8384 }
8385 }
8386
8387 pub(crate) fn open_local_buffer_via_lsp(
8388 &mut self,
8389 abs_path: lsp::Uri,
8390 language_server_id: LanguageServerId,
8391 cx: &mut Context<Self>,
8392 ) -> Task<Result<Entity<Buffer>>> {
8393 cx.spawn(async move |lsp_store, cx| {
8394 // Escape percent-encoded string.
8395 let current_scheme = abs_path.scheme().to_owned();
8396 // Uri is immutable, so we can't modify the scheme
8397
8398 let abs_path = abs_path
8399 .to_file_path()
8400 .map_err(|()| anyhow!("can't convert URI to path"))?;
8401 let p = abs_path.clone();
8402 let yarn_worktree = lsp_store
8403 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8404 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8405 cx.spawn(async move |this, cx| {
8406 let t = this
8407 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8408 .ok()?;
8409 t.await
8410 })
8411 }),
8412 None => Task::ready(None),
8413 })?
8414 .await;
8415 let (worktree_root_target, known_relative_path) =
8416 if let Some((zip_root, relative_path)) = yarn_worktree {
8417 (zip_root, Some(relative_path))
8418 } else {
8419 (Arc::<Path>::from(abs_path.as_path()), None)
8420 };
8421 let (worktree, relative_path) = if let Some(result) =
8422 lsp_store.update(cx, |lsp_store, cx| {
8423 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8424 worktree_store.find_worktree(&worktree_root_target, cx)
8425 })
8426 })? {
8427 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8428 (result.0, relative_path)
8429 } else {
8430 let worktree = lsp_store
8431 .update(cx, |lsp_store, cx| {
8432 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8433 worktree_store.create_worktree(&worktree_root_target, false, cx)
8434 })
8435 })?
8436 .await?;
8437 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8438 lsp_store
8439 .update(cx, |lsp_store, cx| {
8440 if let Some(local) = lsp_store.as_local_mut() {
8441 local.register_language_server_for_invisible_worktree(
8442 &worktree,
8443 language_server_id,
8444 cx,
8445 )
8446 }
8447 })
8448 .ok();
8449 }
8450 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8451 let relative_path = if let Some(known_path) = known_relative_path {
8452 known_path
8453 } else {
8454 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8455 .into_arc()
8456 };
8457 (worktree, relative_path)
8458 };
8459 let project_path = ProjectPath {
8460 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8461 path: relative_path,
8462 };
8463 lsp_store
8464 .update(cx, |lsp_store, cx| {
8465 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8466 buffer_store.open_buffer(project_path, cx)
8467 })
8468 })?
8469 .await
8470 })
8471 }
8472
8473 fn request_multiple_lsp_locally<P, R>(
8474 &mut self,
8475 buffer: &Entity<Buffer>,
8476 position: Option<P>,
8477 request: R,
8478 cx: &mut Context<Self>,
8479 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8480 where
8481 P: ToOffset,
8482 R: LspCommand + Clone,
8483 <R::LspRequest as lsp::request::Request>::Result: Send,
8484 <R::LspRequest as lsp::request::Request>::Params: Send,
8485 {
8486 let Some(local) = self.as_local() else {
8487 return Task::ready(Vec::new());
8488 };
8489
8490 let snapshot = buffer.read(cx).snapshot();
8491 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8492
8493 let server_ids = buffer.update(cx, |buffer, cx| {
8494 local
8495 .language_servers_for_buffer(buffer, cx)
8496 .filter(|(adapter, _)| {
8497 scope
8498 .as_ref()
8499 .map(|scope| scope.language_allowed(&adapter.name))
8500 .unwrap_or(true)
8501 })
8502 .map(|(_, server)| server.server_id())
8503 .filter(|server_id| {
8504 self.as_local().is_none_or(|local| {
8505 local
8506 .buffers_opened_in_servers
8507 .get(&snapshot.remote_id())
8508 .is_some_and(|servers| servers.contains(server_id))
8509 })
8510 })
8511 .collect::<Vec<_>>()
8512 });
8513
8514 let mut response_results = server_ids
8515 .into_iter()
8516 .map(|server_id| {
8517 let task = self.request_lsp(
8518 buffer.clone(),
8519 LanguageServerToQuery::Other(server_id),
8520 request.clone(),
8521 cx,
8522 );
8523 async move { (server_id, task.await) }
8524 })
8525 .collect::<FuturesUnordered<_>>();
8526
8527 cx.background_spawn(async move {
8528 let mut responses = Vec::with_capacity(response_results.len());
8529 while let Some((server_id, response_result)) = response_results.next().await {
8530 match response_result {
8531 Ok(response) => responses.push((server_id, response)),
8532 // rust-analyzer likes to error with this when its still loading up
8533 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8534 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8535 }
8536 }
8537 responses
8538 })
8539 }
8540
8541 async fn handle_lsp_get_completions(
8542 this: Entity<Self>,
8543 envelope: TypedEnvelope<proto::GetCompletions>,
8544 mut cx: AsyncApp,
8545 ) -> Result<proto::GetCompletionsResponse> {
8546 let sender_id = envelope.original_sender_id().unwrap_or_default();
8547
8548 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8549 let buffer_handle = this.update(&mut cx, |this, cx| {
8550 this.buffer_store.read(cx).get_existing(buffer_id)
8551 })??;
8552 let request = GetCompletions::from_proto(
8553 envelope.payload,
8554 this.clone(),
8555 buffer_handle.clone(),
8556 cx.clone(),
8557 )
8558 .await?;
8559
8560 let server_to_query = match request.server_id {
8561 Some(server_id) => LanguageServerToQuery::Other(server_id),
8562 None => LanguageServerToQuery::FirstCapable,
8563 };
8564
8565 let response = this
8566 .update(&mut cx, |this, cx| {
8567 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8568 })?
8569 .await?;
8570 this.update(&mut cx, |this, cx| {
8571 Ok(GetCompletions::response_to_proto(
8572 response,
8573 this,
8574 sender_id,
8575 &buffer_handle.read(cx).version(),
8576 cx,
8577 ))
8578 })?
8579 }
8580
8581 async fn handle_lsp_command<T: LspCommand>(
8582 this: Entity<Self>,
8583 envelope: TypedEnvelope<T::ProtoRequest>,
8584 mut cx: AsyncApp,
8585 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8586 where
8587 <T::LspRequest as lsp::request::Request>::Params: Send,
8588 <T::LspRequest as lsp::request::Request>::Result: Send,
8589 {
8590 let sender_id = envelope.original_sender_id().unwrap_or_default();
8591 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8592 let buffer_handle = this.update(&mut cx, |this, cx| {
8593 this.buffer_store.read(cx).get_existing(buffer_id)
8594 })??;
8595 let request = T::from_proto(
8596 envelope.payload,
8597 this.clone(),
8598 buffer_handle.clone(),
8599 cx.clone(),
8600 )
8601 .await?;
8602 let response = this
8603 .update(&mut cx, |this, cx| {
8604 this.request_lsp(
8605 buffer_handle.clone(),
8606 LanguageServerToQuery::FirstCapable,
8607 request,
8608 cx,
8609 )
8610 })?
8611 .await?;
8612 this.update(&mut cx, |this, cx| {
8613 Ok(T::response_to_proto(
8614 response,
8615 this,
8616 sender_id,
8617 &buffer_handle.read(cx).version(),
8618 cx,
8619 ))
8620 })?
8621 }
8622
8623 async fn handle_lsp_query(
8624 lsp_store: Entity<Self>,
8625 envelope: TypedEnvelope<proto::LspQuery>,
8626 mut cx: AsyncApp,
8627 ) -> Result<proto::Ack> {
8628 use proto::lsp_query::Request;
8629 let sender_id = envelope.original_sender_id().unwrap_or_default();
8630 let lsp_query = envelope.payload;
8631 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8632 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8633 match lsp_query.request.context("invalid LSP query request")? {
8634 Request::GetReferences(get_references) => {
8635 let position = get_references.position.clone().and_then(deserialize_anchor);
8636 Self::query_lsp_locally::<GetReferences>(
8637 lsp_store,
8638 server_id,
8639 sender_id,
8640 lsp_request_id,
8641 get_references,
8642 position,
8643 &mut cx,
8644 )
8645 .await?;
8646 }
8647 Request::GetDocumentColor(get_document_color) => {
8648 Self::query_lsp_locally::<GetDocumentColor>(
8649 lsp_store,
8650 server_id,
8651 sender_id,
8652 lsp_request_id,
8653 get_document_color,
8654 None,
8655 &mut cx,
8656 )
8657 .await?;
8658 }
8659 Request::GetHover(get_hover) => {
8660 let position = get_hover.position.clone().and_then(deserialize_anchor);
8661 Self::query_lsp_locally::<GetHover>(
8662 lsp_store,
8663 server_id,
8664 sender_id,
8665 lsp_request_id,
8666 get_hover,
8667 position,
8668 &mut cx,
8669 )
8670 .await?;
8671 }
8672 Request::GetCodeActions(get_code_actions) => {
8673 Self::query_lsp_locally::<GetCodeActions>(
8674 lsp_store,
8675 server_id,
8676 sender_id,
8677 lsp_request_id,
8678 get_code_actions,
8679 None,
8680 &mut cx,
8681 )
8682 .await?;
8683 }
8684 Request::GetSignatureHelp(get_signature_help) => {
8685 let position = get_signature_help
8686 .position
8687 .clone()
8688 .and_then(deserialize_anchor);
8689 Self::query_lsp_locally::<GetSignatureHelp>(
8690 lsp_store,
8691 server_id,
8692 sender_id,
8693 lsp_request_id,
8694 get_signature_help,
8695 position,
8696 &mut cx,
8697 )
8698 .await?;
8699 }
8700 Request::GetCodeLens(get_code_lens) => {
8701 Self::query_lsp_locally::<GetCodeLens>(
8702 lsp_store,
8703 server_id,
8704 sender_id,
8705 lsp_request_id,
8706 get_code_lens,
8707 None,
8708 &mut cx,
8709 )
8710 .await?;
8711 }
8712 Request::GetDefinition(get_definition) => {
8713 let position = get_definition.position.clone().and_then(deserialize_anchor);
8714 Self::query_lsp_locally::<GetDefinitions>(
8715 lsp_store,
8716 server_id,
8717 sender_id,
8718 lsp_request_id,
8719 get_definition,
8720 position,
8721 &mut cx,
8722 )
8723 .await?;
8724 }
8725 Request::GetDeclaration(get_declaration) => {
8726 let position = get_declaration
8727 .position
8728 .clone()
8729 .and_then(deserialize_anchor);
8730 Self::query_lsp_locally::<GetDeclarations>(
8731 lsp_store,
8732 server_id,
8733 sender_id,
8734 lsp_request_id,
8735 get_declaration,
8736 position,
8737 &mut cx,
8738 )
8739 .await?;
8740 }
8741 Request::GetTypeDefinition(get_type_definition) => {
8742 let position = get_type_definition
8743 .position
8744 .clone()
8745 .and_then(deserialize_anchor);
8746 Self::query_lsp_locally::<GetTypeDefinitions>(
8747 lsp_store,
8748 server_id,
8749 sender_id,
8750 lsp_request_id,
8751 get_type_definition,
8752 position,
8753 &mut cx,
8754 )
8755 .await?;
8756 }
8757 Request::GetImplementation(get_implementation) => {
8758 let position = get_implementation
8759 .position
8760 .clone()
8761 .and_then(deserialize_anchor);
8762 Self::query_lsp_locally::<GetImplementations>(
8763 lsp_store,
8764 server_id,
8765 sender_id,
8766 lsp_request_id,
8767 get_implementation,
8768 position,
8769 &mut cx,
8770 )
8771 .await?;
8772 }
8773 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8774 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8775 let version = deserialize_version(get_document_diagnostics.buffer_version());
8776 let buffer = lsp_store.update(&mut cx, |this, cx| {
8777 this.buffer_store.read(cx).get_existing(buffer_id)
8778 })??;
8779 buffer
8780 .update(&mut cx, |buffer, _| {
8781 buffer.wait_for_version(version.clone())
8782 })?
8783 .await?;
8784 lsp_store.update(&mut cx, |lsp_store, cx| {
8785 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8786 let key = LspKey {
8787 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8788 server_queried: server_id,
8789 };
8790 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8791 ) {
8792 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8793 lsp_requests.clear();
8794 };
8795 }
8796
8797 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8798 existing_queries.insert(
8799 lsp_request_id,
8800 cx.spawn(async move |lsp_store, cx| {
8801 let diagnostics_pull = lsp_store
8802 .update(cx, |lsp_store, cx| {
8803 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8804 })
8805 .ok();
8806 if let Some(diagnostics_pull) = diagnostics_pull {
8807 match diagnostics_pull.await {
8808 Ok(()) => {}
8809 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8810 };
8811 }
8812 }),
8813 );
8814 })?;
8815 }
8816 Request::InlayHints(inlay_hints) => {
8817 let query_start = inlay_hints
8818 .start
8819 .clone()
8820 .and_then(deserialize_anchor)
8821 .context("invalid inlay hints range start")?;
8822 let query_end = inlay_hints
8823 .end
8824 .clone()
8825 .and_then(deserialize_anchor)
8826 .context("invalid inlay hints range end")?;
8827 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8828 &lsp_store,
8829 server_id,
8830 lsp_request_id,
8831 &inlay_hints,
8832 query_start..query_end,
8833 &mut cx,
8834 )
8835 .await
8836 .context("preparing inlay hints request")?;
8837 Self::query_lsp_locally::<InlayHints>(
8838 lsp_store,
8839 server_id,
8840 sender_id,
8841 lsp_request_id,
8842 inlay_hints,
8843 None,
8844 &mut cx,
8845 )
8846 .await
8847 .context("querying for inlay hints")?
8848 }
8849 }
8850 Ok(proto::Ack {})
8851 }
8852
8853 async fn handle_lsp_query_response(
8854 lsp_store: Entity<Self>,
8855 envelope: TypedEnvelope<proto::LspQueryResponse>,
8856 cx: AsyncApp,
8857 ) -> Result<()> {
8858 lsp_store.read_with(&cx, |lsp_store, _| {
8859 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8860 upstream_client.handle_lsp_response(envelope.clone());
8861 }
8862 })?;
8863 Ok(())
8864 }
8865
8866 async fn handle_apply_code_action(
8867 this: Entity<Self>,
8868 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8869 mut cx: AsyncApp,
8870 ) -> Result<proto::ApplyCodeActionResponse> {
8871 let sender_id = envelope.original_sender_id().unwrap_or_default();
8872 let action =
8873 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8874 let apply_code_action = this.update(&mut cx, |this, cx| {
8875 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8876 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8877 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8878 })??;
8879
8880 let project_transaction = apply_code_action.await?;
8881 let project_transaction = this.update(&mut cx, |this, cx| {
8882 this.buffer_store.update(cx, |buffer_store, cx| {
8883 buffer_store.serialize_project_transaction_for_peer(
8884 project_transaction,
8885 sender_id,
8886 cx,
8887 )
8888 })
8889 })?;
8890 Ok(proto::ApplyCodeActionResponse {
8891 transaction: Some(project_transaction),
8892 })
8893 }
8894
8895 async fn handle_register_buffer_with_language_servers(
8896 this: Entity<Self>,
8897 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8898 mut cx: AsyncApp,
8899 ) -> Result<proto::Ack> {
8900 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8901 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8902 this.update(&mut cx, |this, cx| {
8903 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8904 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8905 project_id: upstream_project_id,
8906 buffer_id: buffer_id.to_proto(),
8907 only_servers: envelope.payload.only_servers,
8908 });
8909 }
8910
8911 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8912 anyhow::bail!("buffer is not open");
8913 };
8914
8915 let handle = this.register_buffer_with_language_servers(
8916 &buffer,
8917 envelope
8918 .payload
8919 .only_servers
8920 .into_iter()
8921 .filter_map(|selector| {
8922 Some(match selector.selector? {
8923 proto::language_server_selector::Selector::ServerId(server_id) => {
8924 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8925 }
8926 proto::language_server_selector::Selector::Name(name) => {
8927 LanguageServerSelector::Name(LanguageServerName(
8928 SharedString::from(name),
8929 ))
8930 }
8931 })
8932 })
8933 .collect(),
8934 false,
8935 cx,
8936 );
8937 this.buffer_store().update(cx, |buffer_store, _| {
8938 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8939 });
8940
8941 Ok(())
8942 })??;
8943 Ok(proto::Ack {})
8944 }
8945
8946 async fn handle_rename_project_entry(
8947 this: Entity<Self>,
8948 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8949 mut cx: AsyncApp,
8950 ) -> Result<proto::ProjectEntryResponse> {
8951 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8952 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8953 let new_path =
8954 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8955
8956 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8957 .update(&mut cx, |this, cx| {
8958 let (worktree, entry) = this
8959 .worktree_store
8960 .read(cx)
8961 .worktree_and_entry_for_id(entry_id, cx)?;
8962 let new_worktree = this
8963 .worktree_store
8964 .read(cx)
8965 .worktree_for_id(new_worktree_id, cx)?;
8966 Some((
8967 this.worktree_store.clone(),
8968 worktree,
8969 new_worktree,
8970 entry.clone(),
8971 ))
8972 })?
8973 .context("worktree not found")?;
8974 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8975 (worktree.absolutize(&old_entry.path), worktree.id())
8976 })?;
8977 let new_abs_path =
8978 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8979
8980 let _transaction = Self::will_rename_entry(
8981 this.downgrade(),
8982 old_worktree_id,
8983 &old_abs_path,
8984 &new_abs_path,
8985 old_entry.is_dir(),
8986 cx.clone(),
8987 )
8988 .await;
8989 let response = WorktreeStore::handle_rename_project_entry(
8990 worktree_store,
8991 envelope.payload,
8992 cx.clone(),
8993 )
8994 .await;
8995 this.read_with(&cx, |this, _| {
8996 this.did_rename_entry(
8997 old_worktree_id,
8998 &old_abs_path,
8999 &new_abs_path,
9000 old_entry.is_dir(),
9001 );
9002 })
9003 .ok();
9004 response
9005 }
9006
9007 async fn handle_update_diagnostic_summary(
9008 this: Entity<Self>,
9009 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9010 mut cx: AsyncApp,
9011 ) -> Result<()> {
9012 this.update(&mut cx, |lsp_store, cx| {
9013 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9014 let mut updated_diagnostics_paths = HashMap::default();
9015 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9016 for message_summary in envelope
9017 .payload
9018 .summary
9019 .into_iter()
9020 .chain(envelope.payload.more_summaries)
9021 {
9022 let project_path = ProjectPath {
9023 worktree_id,
9024 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9025 };
9026 let path = project_path.path.clone();
9027 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9028 let summary = DiagnosticSummary {
9029 error_count: message_summary.error_count as usize,
9030 warning_count: message_summary.warning_count as usize,
9031 };
9032
9033 if summary.is_empty() {
9034 if let Some(worktree_summaries) =
9035 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9036 && let Some(summaries) = worktree_summaries.get_mut(&path)
9037 {
9038 summaries.remove(&server_id);
9039 if summaries.is_empty() {
9040 worktree_summaries.remove(&path);
9041 }
9042 }
9043 } else {
9044 lsp_store
9045 .diagnostic_summaries
9046 .entry(worktree_id)
9047 .or_default()
9048 .entry(path)
9049 .or_default()
9050 .insert(server_id, summary);
9051 }
9052
9053 if let Some((_, project_id)) = &lsp_store.downstream_client {
9054 match &mut diagnostics_summary {
9055 Some(diagnostics_summary) => {
9056 diagnostics_summary
9057 .more_summaries
9058 .push(proto::DiagnosticSummary {
9059 path: project_path.path.as_ref().to_proto(),
9060 language_server_id: server_id.0 as u64,
9061 error_count: summary.error_count as u32,
9062 warning_count: summary.warning_count as u32,
9063 })
9064 }
9065 None => {
9066 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9067 project_id: *project_id,
9068 worktree_id: worktree_id.to_proto(),
9069 summary: Some(proto::DiagnosticSummary {
9070 path: project_path.path.as_ref().to_proto(),
9071 language_server_id: server_id.0 as u64,
9072 error_count: summary.error_count as u32,
9073 warning_count: summary.warning_count as u32,
9074 }),
9075 more_summaries: Vec::new(),
9076 })
9077 }
9078 }
9079 }
9080 updated_diagnostics_paths
9081 .entry(server_id)
9082 .or_insert_with(Vec::new)
9083 .push(project_path);
9084 }
9085
9086 if let Some((diagnostics_summary, (downstream_client, _))) =
9087 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9088 {
9089 downstream_client.send(diagnostics_summary).log_err();
9090 }
9091 for (server_id, paths) in updated_diagnostics_paths {
9092 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9093 }
9094 Ok(())
9095 })?
9096 }
9097
9098 async fn handle_start_language_server(
9099 lsp_store: Entity<Self>,
9100 envelope: TypedEnvelope<proto::StartLanguageServer>,
9101 mut cx: AsyncApp,
9102 ) -> Result<()> {
9103 let server = envelope.payload.server.context("invalid server")?;
9104 let server_capabilities =
9105 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9106 .with_context(|| {
9107 format!(
9108 "incorrect server capabilities {}",
9109 envelope.payload.capabilities
9110 )
9111 })?;
9112 lsp_store.update(&mut cx, |lsp_store, cx| {
9113 let server_id = LanguageServerId(server.id as usize);
9114 let server_name = LanguageServerName::from_proto(server.name.clone());
9115 lsp_store
9116 .lsp_server_capabilities
9117 .insert(server_id, server_capabilities);
9118 lsp_store.language_server_statuses.insert(
9119 server_id,
9120 LanguageServerStatus {
9121 name: server_name.clone(),
9122 pending_work: Default::default(),
9123 has_pending_diagnostic_updates: false,
9124 progress_tokens: Default::default(),
9125 worktree: server.worktree_id.map(WorktreeId::from_proto),
9126 },
9127 );
9128 cx.emit(LspStoreEvent::LanguageServerAdded(
9129 server_id,
9130 server_name,
9131 server.worktree_id.map(WorktreeId::from_proto),
9132 ));
9133 cx.notify();
9134 })?;
9135 Ok(())
9136 }
9137
9138 async fn handle_update_language_server(
9139 lsp_store: Entity<Self>,
9140 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9141 mut cx: AsyncApp,
9142 ) -> Result<()> {
9143 lsp_store.update(&mut cx, |lsp_store, cx| {
9144 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9145
9146 match envelope.payload.variant.context("invalid variant")? {
9147 proto::update_language_server::Variant::WorkStart(payload) => {
9148 lsp_store.on_lsp_work_start(
9149 language_server_id,
9150 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9151 .context("invalid progress token value")?,
9152 LanguageServerProgress {
9153 title: payload.title,
9154 is_disk_based_diagnostics_progress: false,
9155 is_cancellable: payload.is_cancellable.unwrap_or(false),
9156 message: payload.message,
9157 percentage: payload.percentage.map(|p| p as usize),
9158 last_update_at: cx.background_executor().now(),
9159 },
9160 cx,
9161 );
9162 }
9163 proto::update_language_server::Variant::WorkProgress(payload) => {
9164 lsp_store.on_lsp_work_progress(
9165 language_server_id,
9166 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9167 .context("invalid progress token value")?,
9168 LanguageServerProgress {
9169 title: None,
9170 is_disk_based_diagnostics_progress: false,
9171 is_cancellable: payload.is_cancellable.unwrap_or(false),
9172 message: payload.message,
9173 percentage: payload.percentage.map(|p| p as usize),
9174 last_update_at: cx.background_executor().now(),
9175 },
9176 cx,
9177 );
9178 }
9179
9180 proto::update_language_server::Variant::WorkEnd(payload) => {
9181 lsp_store.on_lsp_work_end(
9182 language_server_id,
9183 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9184 .context("invalid progress token value")?,
9185 cx,
9186 );
9187 }
9188
9189 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9190 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9191 }
9192
9193 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9194 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9195 }
9196
9197 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9198 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9199 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9200 cx.emit(LspStoreEvent::LanguageServerUpdate {
9201 language_server_id,
9202 name: envelope
9203 .payload
9204 .server_name
9205 .map(SharedString::new)
9206 .map(LanguageServerName),
9207 message: non_lsp,
9208 });
9209 }
9210 }
9211
9212 Ok(())
9213 })?
9214 }
9215
9216 async fn handle_language_server_log(
9217 this: Entity<Self>,
9218 envelope: TypedEnvelope<proto::LanguageServerLog>,
9219 mut cx: AsyncApp,
9220 ) -> Result<()> {
9221 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9222 let log_type = envelope
9223 .payload
9224 .log_type
9225 .map(LanguageServerLogType::from_proto)
9226 .context("invalid language server log type")?;
9227
9228 let message = envelope.payload.message;
9229
9230 this.update(&mut cx, |_, cx| {
9231 cx.emit(LspStoreEvent::LanguageServerLog(
9232 language_server_id,
9233 log_type,
9234 message,
9235 ));
9236 })
9237 }
9238
9239 async fn handle_lsp_ext_cancel_flycheck(
9240 lsp_store: Entity<Self>,
9241 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9242 cx: AsyncApp,
9243 ) -> Result<proto::Ack> {
9244 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9245 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9246 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9247 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9248 } else {
9249 None
9250 }
9251 })?;
9252 if let Some(task) = task {
9253 task.context("handling lsp ext cancel flycheck")?;
9254 }
9255
9256 Ok(proto::Ack {})
9257 }
9258
9259 async fn handle_lsp_ext_run_flycheck(
9260 lsp_store: Entity<Self>,
9261 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9262 mut cx: AsyncApp,
9263 ) -> Result<proto::Ack> {
9264 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9265 lsp_store.update(&mut cx, |lsp_store, cx| {
9266 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9267 let text_document = if envelope.payload.current_file_only {
9268 let buffer_id = envelope
9269 .payload
9270 .buffer_id
9271 .map(|id| BufferId::new(id))
9272 .transpose()?;
9273 buffer_id
9274 .and_then(|buffer_id| {
9275 lsp_store
9276 .buffer_store()
9277 .read(cx)
9278 .get(buffer_id)
9279 .and_then(|buffer| {
9280 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9281 })
9282 .map(|path| make_text_document_identifier(&path))
9283 })
9284 .transpose()?
9285 } else {
9286 None
9287 };
9288 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9289 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9290 )?;
9291 }
9292 anyhow::Ok(())
9293 })??;
9294
9295 Ok(proto::Ack {})
9296 }
9297
9298 async fn handle_lsp_ext_clear_flycheck(
9299 lsp_store: Entity<Self>,
9300 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9301 cx: AsyncApp,
9302 ) -> Result<proto::Ack> {
9303 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9304 lsp_store
9305 .read_with(&cx, |lsp_store, _| {
9306 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9307 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9308 } else {
9309 None
9310 }
9311 })
9312 .context("handling lsp ext clear flycheck")?;
9313
9314 Ok(proto::Ack {})
9315 }
9316
9317 pub fn disk_based_diagnostics_started(
9318 &mut self,
9319 language_server_id: LanguageServerId,
9320 cx: &mut Context<Self>,
9321 ) {
9322 if let Some(language_server_status) =
9323 self.language_server_statuses.get_mut(&language_server_id)
9324 {
9325 language_server_status.has_pending_diagnostic_updates = true;
9326 }
9327
9328 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9329 cx.emit(LspStoreEvent::LanguageServerUpdate {
9330 language_server_id,
9331 name: self
9332 .language_server_adapter_for_id(language_server_id)
9333 .map(|adapter| adapter.name()),
9334 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9335 Default::default(),
9336 ),
9337 })
9338 }
9339
9340 pub fn disk_based_diagnostics_finished(
9341 &mut self,
9342 language_server_id: LanguageServerId,
9343 cx: &mut Context<Self>,
9344 ) {
9345 if let Some(language_server_status) =
9346 self.language_server_statuses.get_mut(&language_server_id)
9347 {
9348 language_server_status.has_pending_diagnostic_updates = false;
9349 }
9350
9351 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9352 cx.emit(LspStoreEvent::LanguageServerUpdate {
9353 language_server_id,
9354 name: self
9355 .language_server_adapter_for_id(language_server_id)
9356 .map(|adapter| adapter.name()),
9357 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9358 Default::default(),
9359 ),
9360 })
9361 }
9362
9363 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9364 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9365 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9366 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9367 // the language server might take some time to publish diagnostics.
9368 fn simulate_disk_based_diagnostics_events_if_needed(
9369 &mut self,
9370 language_server_id: LanguageServerId,
9371 cx: &mut Context<Self>,
9372 ) {
9373 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9374
9375 let Some(LanguageServerState::Running {
9376 simulate_disk_based_diagnostics_completion,
9377 adapter,
9378 ..
9379 }) = self
9380 .as_local_mut()
9381 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9382 else {
9383 return;
9384 };
9385
9386 if adapter.disk_based_diagnostics_progress_token.is_some() {
9387 return;
9388 }
9389
9390 let prev_task =
9391 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9392 cx.background_executor()
9393 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9394 .await;
9395
9396 this.update(cx, |this, cx| {
9397 this.disk_based_diagnostics_finished(language_server_id, cx);
9398
9399 if let Some(LanguageServerState::Running {
9400 simulate_disk_based_diagnostics_completion,
9401 ..
9402 }) = this.as_local_mut().and_then(|local_store| {
9403 local_store.language_servers.get_mut(&language_server_id)
9404 }) {
9405 *simulate_disk_based_diagnostics_completion = None;
9406 }
9407 })
9408 .ok();
9409 }));
9410
9411 if prev_task.is_none() {
9412 self.disk_based_diagnostics_started(language_server_id, cx);
9413 }
9414 }
9415
9416 pub fn language_server_statuses(
9417 &self,
9418 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9419 self.language_server_statuses
9420 .iter()
9421 .map(|(key, value)| (*key, value))
9422 }
9423
9424 pub(super) fn did_rename_entry(
9425 &self,
9426 worktree_id: WorktreeId,
9427 old_path: &Path,
9428 new_path: &Path,
9429 is_dir: bool,
9430 ) {
9431 maybe!({
9432 let local_store = self.as_local()?;
9433
9434 let old_uri = lsp::Uri::from_file_path(old_path)
9435 .ok()
9436 .map(|uri| uri.to_string())?;
9437 let new_uri = lsp::Uri::from_file_path(new_path)
9438 .ok()
9439 .map(|uri| uri.to_string())?;
9440
9441 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9442 let Some(filter) = local_store
9443 .language_server_paths_watched_for_rename
9444 .get(&language_server.server_id())
9445 else {
9446 continue;
9447 };
9448
9449 if filter.should_send_did_rename(&old_uri, is_dir) {
9450 language_server
9451 .notify::<DidRenameFiles>(RenameFilesParams {
9452 files: vec![FileRename {
9453 old_uri: old_uri.clone(),
9454 new_uri: new_uri.clone(),
9455 }],
9456 })
9457 .ok();
9458 }
9459 }
9460 Some(())
9461 });
9462 }
9463
9464 pub(super) fn will_rename_entry(
9465 this: WeakEntity<Self>,
9466 worktree_id: WorktreeId,
9467 old_path: &Path,
9468 new_path: &Path,
9469 is_dir: bool,
9470 cx: AsyncApp,
9471 ) -> Task<ProjectTransaction> {
9472 let old_uri = lsp::Uri::from_file_path(old_path)
9473 .ok()
9474 .map(|uri| uri.to_string());
9475 let new_uri = lsp::Uri::from_file_path(new_path)
9476 .ok()
9477 .map(|uri| uri.to_string());
9478 cx.spawn(async move |cx| {
9479 let mut tasks = vec![];
9480 this.update(cx, |this, cx| {
9481 let local_store = this.as_local()?;
9482 let old_uri = old_uri?;
9483 let new_uri = new_uri?;
9484 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9485 let Some(filter) = local_store
9486 .language_server_paths_watched_for_rename
9487 .get(&language_server.server_id())
9488 else {
9489 continue;
9490 };
9491
9492 if filter.should_send_will_rename(&old_uri, is_dir) {
9493 let apply_edit = cx.spawn({
9494 let old_uri = old_uri.clone();
9495 let new_uri = new_uri.clone();
9496 let language_server = language_server.clone();
9497 async move |this, cx| {
9498 let edit = language_server
9499 .request::<WillRenameFiles>(RenameFilesParams {
9500 files: vec![FileRename { old_uri, new_uri }],
9501 })
9502 .await
9503 .into_response()
9504 .context("will rename files")
9505 .log_err()
9506 .flatten()?;
9507
9508 let transaction = LocalLspStore::deserialize_workspace_edit(
9509 this.upgrade()?,
9510 edit,
9511 false,
9512 language_server.clone(),
9513 cx,
9514 )
9515 .await
9516 .ok()?;
9517 Some(transaction)
9518 }
9519 });
9520 tasks.push(apply_edit);
9521 }
9522 }
9523 Some(())
9524 })
9525 .ok()
9526 .flatten();
9527 let mut merged_transaction = ProjectTransaction::default();
9528 for task in tasks {
9529 // Await on tasks sequentially so that the order of application of edits is deterministic
9530 // (at least with regards to the order of registration of language servers)
9531 if let Some(transaction) = task.await {
9532 for (buffer, buffer_transaction) in transaction.0 {
9533 merged_transaction.0.insert(buffer, buffer_transaction);
9534 }
9535 }
9536 }
9537 merged_transaction
9538 })
9539 }
9540
9541 fn lsp_notify_abs_paths_changed(
9542 &mut self,
9543 server_id: LanguageServerId,
9544 changes: Vec<PathEvent>,
9545 ) {
9546 maybe!({
9547 let server = self.language_server_for_id(server_id)?;
9548 let changes = changes
9549 .into_iter()
9550 .filter_map(|event| {
9551 let typ = match event.kind? {
9552 PathEventKind::Created => lsp::FileChangeType::CREATED,
9553 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9554 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9555 };
9556 Some(lsp::FileEvent {
9557 uri: file_path_to_lsp_url(&event.path).log_err()?,
9558 typ,
9559 })
9560 })
9561 .collect::<Vec<_>>();
9562 if !changes.is_empty() {
9563 server
9564 .notify::<lsp::notification::DidChangeWatchedFiles>(
9565 lsp::DidChangeWatchedFilesParams { changes },
9566 )
9567 .ok();
9568 }
9569 Some(())
9570 });
9571 }
9572
9573 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9574 self.as_local()?.language_server_for_id(id)
9575 }
9576
9577 fn on_lsp_progress(
9578 &mut self,
9579 progress_params: lsp::ProgressParams,
9580 language_server_id: LanguageServerId,
9581 disk_based_diagnostics_progress_token: Option<String>,
9582 cx: &mut Context<Self>,
9583 ) {
9584 match progress_params.value {
9585 lsp::ProgressParamsValue::WorkDone(progress) => {
9586 self.handle_work_done_progress(
9587 progress,
9588 language_server_id,
9589 disk_based_diagnostics_progress_token,
9590 ProgressToken::from_lsp(progress_params.token),
9591 cx,
9592 );
9593 }
9594 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9595 let identifier = match progress_params.token {
9596 lsp::NumberOrString::Number(_) => None,
9597 lsp::NumberOrString::String(token) => token
9598 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9599 .map(|(_, id)| id.to_owned()),
9600 };
9601 if let Some(LanguageServerState::Running {
9602 workspace_diagnostics_refresh_tasks,
9603 ..
9604 }) = self
9605 .as_local_mut()
9606 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9607 && let Some(workspace_diagnostics) =
9608 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9609 {
9610 workspace_diagnostics.progress_tx.try_send(()).ok();
9611 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9612 }
9613 }
9614 }
9615 }
9616
9617 fn handle_work_done_progress(
9618 &mut self,
9619 progress: lsp::WorkDoneProgress,
9620 language_server_id: LanguageServerId,
9621 disk_based_diagnostics_progress_token: Option<String>,
9622 token: ProgressToken,
9623 cx: &mut Context<Self>,
9624 ) {
9625 let language_server_status =
9626 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9627 status
9628 } else {
9629 return;
9630 };
9631
9632 if !language_server_status.progress_tokens.contains(&token) {
9633 return;
9634 }
9635
9636 let is_disk_based_diagnostics_progress =
9637 if let (Some(disk_based_token), ProgressToken::String(token)) =
9638 (&disk_based_diagnostics_progress_token, &token)
9639 {
9640 token.starts_with(disk_based_token)
9641 } else {
9642 false
9643 };
9644
9645 match progress {
9646 lsp::WorkDoneProgress::Begin(report) => {
9647 if is_disk_based_diagnostics_progress {
9648 self.disk_based_diagnostics_started(language_server_id, cx);
9649 }
9650 self.on_lsp_work_start(
9651 language_server_id,
9652 token.clone(),
9653 LanguageServerProgress {
9654 title: Some(report.title),
9655 is_disk_based_diagnostics_progress,
9656 is_cancellable: report.cancellable.unwrap_or(false),
9657 message: report.message.clone(),
9658 percentage: report.percentage.map(|p| p as usize),
9659 last_update_at: cx.background_executor().now(),
9660 },
9661 cx,
9662 );
9663 }
9664 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9665 language_server_id,
9666 token,
9667 LanguageServerProgress {
9668 title: None,
9669 is_disk_based_diagnostics_progress,
9670 is_cancellable: report.cancellable.unwrap_or(false),
9671 message: report.message,
9672 percentage: report.percentage.map(|p| p as usize),
9673 last_update_at: cx.background_executor().now(),
9674 },
9675 cx,
9676 ),
9677 lsp::WorkDoneProgress::End(_) => {
9678 language_server_status.progress_tokens.remove(&token);
9679 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9680 if is_disk_based_diagnostics_progress {
9681 self.disk_based_diagnostics_finished(language_server_id, cx);
9682 }
9683 }
9684 }
9685 }
9686
9687 fn on_lsp_work_start(
9688 &mut self,
9689 language_server_id: LanguageServerId,
9690 token: ProgressToken,
9691 progress: LanguageServerProgress,
9692 cx: &mut Context<Self>,
9693 ) {
9694 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9695 status.pending_work.insert(token.clone(), progress.clone());
9696 cx.notify();
9697 }
9698 cx.emit(LspStoreEvent::LanguageServerUpdate {
9699 language_server_id,
9700 name: self
9701 .language_server_adapter_for_id(language_server_id)
9702 .map(|adapter| adapter.name()),
9703 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9704 token: Some(token.to_proto()),
9705 title: progress.title,
9706 message: progress.message,
9707 percentage: progress.percentage.map(|p| p as u32),
9708 is_cancellable: Some(progress.is_cancellable),
9709 }),
9710 })
9711 }
9712
9713 fn on_lsp_work_progress(
9714 &mut self,
9715 language_server_id: LanguageServerId,
9716 token: ProgressToken,
9717 progress: LanguageServerProgress,
9718 cx: &mut Context<Self>,
9719 ) {
9720 let mut did_update = false;
9721 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9722 match status.pending_work.entry(token.clone()) {
9723 btree_map::Entry::Vacant(entry) => {
9724 entry.insert(progress.clone());
9725 did_update = true;
9726 }
9727 btree_map::Entry::Occupied(mut entry) => {
9728 let entry = entry.get_mut();
9729 if (progress.last_update_at - entry.last_update_at)
9730 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9731 {
9732 entry.last_update_at = progress.last_update_at;
9733 if progress.message.is_some() {
9734 entry.message = progress.message.clone();
9735 }
9736 if progress.percentage.is_some() {
9737 entry.percentage = progress.percentage;
9738 }
9739 if progress.is_cancellable != entry.is_cancellable {
9740 entry.is_cancellable = progress.is_cancellable;
9741 }
9742 did_update = true;
9743 }
9744 }
9745 }
9746 }
9747
9748 if did_update {
9749 cx.emit(LspStoreEvent::LanguageServerUpdate {
9750 language_server_id,
9751 name: self
9752 .language_server_adapter_for_id(language_server_id)
9753 .map(|adapter| adapter.name()),
9754 message: proto::update_language_server::Variant::WorkProgress(
9755 proto::LspWorkProgress {
9756 token: Some(token.to_proto()),
9757 message: progress.message,
9758 percentage: progress.percentage.map(|p| p as u32),
9759 is_cancellable: Some(progress.is_cancellable),
9760 },
9761 ),
9762 })
9763 }
9764 }
9765
9766 fn on_lsp_work_end(
9767 &mut self,
9768 language_server_id: LanguageServerId,
9769 token: ProgressToken,
9770 cx: &mut Context<Self>,
9771 ) {
9772 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9773 if let Some(work) = status.pending_work.remove(&token)
9774 && !work.is_disk_based_diagnostics_progress
9775 {
9776 cx.emit(LspStoreEvent::RefreshInlayHints {
9777 server_id: language_server_id,
9778 request_id: None,
9779 });
9780 }
9781 cx.notify();
9782 }
9783
9784 cx.emit(LspStoreEvent::LanguageServerUpdate {
9785 language_server_id,
9786 name: self
9787 .language_server_adapter_for_id(language_server_id)
9788 .map(|adapter| adapter.name()),
9789 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9790 token: Some(token.to_proto()),
9791 }),
9792 })
9793 }
9794
9795 pub async fn handle_resolve_completion_documentation(
9796 this: Entity<Self>,
9797 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9798 mut cx: AsyncApp,
9799 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9800 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9801
9802 let completion = this
9803 .read_with(&cx, |this, cx| {
9804 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9805 let server = this
9806 .language_server_for_id(id)
9807 .with_context(|| format!("No language server {id}"))?;
9808
9809 anyhow::Ok(cx.background_spawn(async move {
9810 let can_resolve = server
9811 .capabilities()
9812 .completion_provider
9813 .as_ref()
9814 .and_then(|options| options.resolve_provider)
9815 .unwrap_or(false);
9816 if can_resolve {
9817 server
9818 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9819 .await
9820 .into_response()
9821 .context("resolve completion item")
9822 } else {
9823 anyhow::Ok(lsp_completion)
9824 }
9825 }))
9826 })??
9827 .await?;
9828
9829 let mut documentation_is_markdown = false;
9830 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9831 let documentation = match completion.documentation {
9832 Some(lsp::Documentation::String(text)) => text,
9833
9834 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9835 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9836 value
9837 }
9838
9839 _ => String::new(),
9840 };
9841
9842 // If we have a new buffer_id, that means we're talking to a new client
9843 // and want to check for new text_edits in the completion too.
9844 let mut old_replace_start = None;
9845 let mut old_replace_end = None;
9846 let mut old_insert_start = None;
9847 let mut old_insert_end = None;
9848 let mut new_text = String::default();
9849 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9850 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9851 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9852 anyhow::Ok(buffer.read(cx).snapshot())
9853 })??;
9854
9855 if let Some(text_edit) = completion.text_edit.as_ref() {
9856 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9857
9858 if let Some(mut edit) = edit {
9859 LineEnding::normalize(&mut edit.new_text);
9860
9861 new_text = edit.new_text;
9862 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9863 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9864 if let Some(insert_range) = edit.insert_range {
9865 old_insert_start = Some(serialize_anchor(&insert_range.start));
9866 old_insert_end = Some(serialize_anchor(&insert_range.end));
9867 }
9868 }
9869 }
9870 }
9871
9872 Ok(proto::ResolveCompletionDocumentationResponse {
9873 documentation,
9874 documentation_is_markdown,
9875 old_replace_start,
9876 old_replace_end,
9877 new_text,
9878 lsp_completion,
9879 old_insert_start,
9880 old_insert_end,
9881 })
9882 }
9883
9884 async fn handle_on_type_formatting(
9885 this: Entity<Self>,
9886 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9887 mut cx: AsyncApp,
9888 ) -> Result<proto::OnTypeFormattingResponse> {
9889 let on_type_formatting = this.update(&mut cx, |this, cx| {
9890 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9891 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9892 let position = envelope
9893 .payload
9894 .position
9895 .and_then(deserialize_anchor)
9896 .context("invalid position")?;
9897 anyhow::Ok(this.apply_on_type_formatting(
9898 buffer,
9899 position,
9900 envelope.payload.trigger.clone(),
9901 cx,
9902 ))
9903 })??;
9904
9905 let transaction = on_type_formatting
9906 .await?
9907 .as_ref()
9908 .map(language::proto::serialize_transaction);
9909 Ok(proto::OnTypeFormattingResponse { transaction })
9910 }
9911
9912 async fn handle_refresh_inlay_hints(
9913 lsp_store: Entity<Self>,
9914 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9915 mut cx: AsyncApp,
9916 ) -> Result<proto::Ack> {
9917 lsp_store.update(&mut cx, |_, cx| {
9918 cx.emit(LspStoreEvent::RefreshInlayHints {
9919 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9920 request_id: envelope.payload.request_id.map(|id| id as usize),
9921 });
9922 })?;
9923 Ok(proto::Ack {})
9924 }
9925
9926 async fn handle_pull_workspace_diagnostics(
9927 lsp_store: Entity<Self>,
9928 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9929 mut cx: AsyncApp,
9930 ) -> Result<proto::Ack> {
9931 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9932 lsp_store.update(&mut cx, |lsp_store, _| {
9933 lsp_store.pull_workspace_diagnostics(server_id);
9934 })?;
9935 Ok(proto::Ack {})
9936 }
9937
9938 async fn handle_get_color_presentation(
9939 lsp_store: Entity<Self>,
9940 envelope: TypedEnvelope<proto::GetColorPresentation>,
9941 mut cx: AsyncApp,
9942 ) -> Result<proto::GetColorPresentationResponse> {
9943 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9944 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9945 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9946 })??;
9947
9948 let color = envelope
9949 .payload
9950 .color
9951 .context("invalid color resolve request")?;
9952 let start = color
9953 .lsp_range_start
9954 .context("invalid color resolve request")?;
9955 let end = color
9956 .lsp_range_end
9957 .context("invalid color resolve request")?;
9958
9959 let color = DocumentColor {
9960 lsp_range: lsp::Range {
9961 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9962 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9963 },
9964 color: lsp::Color {
9965 red: color.red,
9966 green: color.green,
9967 blue: color.blue,
9968 alpha: color.alpha,
9969 },
9970 resolved: false,
9971 color_presentations: Vec::new(),
9972 };
9973 let resolved_color = lsp_store
9974 .update(&mut cx, |lsp_store, cx| {
9975 lsp_store.resolve_color_presentation(
9976 color,
9977 buffer.clone(),
9978 LanguageServerId(envelope.payload.server_id as usize),
9979 cx,
9980 )
9981 })?
9982 .await
9983 .context("resolving color presentation")?;
9984
9985 Ok(proto::GetColorPresentationResponse {
9986 presentations: resolved_color
9987 .color_presentations
9988 .into_iter()
9989 .map(|presentation| proto::ColorPresentation {
9990 label: presentation.label.to_string(),
9991 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9992 additional_text_edits: presentation
9993 .additional_text_edits
9994 .into_iter()
9995 .map(serialize_lsp_edit)
9996 .collect(),
9997 })
9998 .collect(),
9999 })
10000 }
10001
10002 async fn handle_resolve_inlay_hint(
10003 lsp_store: Entity<Self>,
10004 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10005 mut cx: AsyncApp,
10006 ) -> Result<proto::ResolveInlayHintResponse> {
10007 let proto_hint = envelope
10008 .payload
10009 .hint
10010 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10011 let hint = InlayHints::proto_to_project_hint(proto_hint)
10012 .context("resolved proto inlay hint conversion")?;
10013 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10014 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10015 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10016 })??;
10017 let response_hint = lsp_store
10018 .update(&mut cx, |lsp_store, cx| {
10019 lsp_store.resolve_inlay_hint(
10020 hint,
10021 buffer,
10022 LanguageServerId(envelope.payload.language_server_id as usize),
10023 cx,
10024 )
10025 })?
10026 .await
10027 .context("inlay hints fetch")?;
10028 Ok(proto::ResolveInlayHintResponse {
10029 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10030 })
10031 }
10032
10033 async fn handle_refresh_code_lens(
10034 this: Entity<Self>,
10035 _: TypedEnvelope<proto::RefreshCodeLens>,
10036 mut cx: AsyncApp,
10037 ) -> Result<proto::Ack> {
10038 this.update(&mut cx, |_, cx| {
10039 cx.emit(LspStoreEvent::RefreshCodeLens);
10040 })?;
10041 Ok(proto::Ack {})
10042 }
10043
10044 async fn handle_open_buffer_for_symbol(
10045 this: Entity<Self>,
10046 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10047 mut cx: AsyncApp,
10048 ) -> Result<proto::OpenBufferForSymbolResponse> {
10049 let peer_id = envelope.original_sender_id().unwrap_or_default();
10050 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10051 let symbol = Self::deserialize_symbol(symbol)?;
10052 this.read_with(&cx, |this, _| {
10053 if let SymbolLocation::OutsideProject {
10054 abs_path,
10055 signature,
10056 } = &symbol.path
10057 {
10058 let new_signature = this.symbol_signature(&abs_path);
10059 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10060 }
10061 Ok(())
10062 })??;
10063 let buffer = this
10064 .update(&mut cx, |this, cx| {
10065 this.open_buffer_for_symbol(
10066 &Symbol {
10067 language_server_name: symbol.language_server_name,
10068 source_worktree_id: symbol.source_worktree_id,
10069 source_language_server_id: symbol.source_language_server_id,
10070 path: symbol.path,
10071 name: symbol.name,
10072 kind: symbol.kind,
10073 range: symbol.range,
10074 label: CodeLabel::default(),
10075 },
10076 cx,
10077 )
10078 })?
10079 .await?;
10080
10081 this.update(&mut cx, |this, cx| {
10082 let is_private = buffer
10083 .read(cx)
10084 .file()
10085 .map(|f| f.is_private())
10086 .unwrap_or_default();
10087 if is_private {
10088 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10089 } else {
10090 this.buffer_store
10091 .update(cx, |buffer_store, cx| {
10092 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10093 })
10094 .detach_and_log_err(cx);
10095 let buffer_id = buffer.read(cx).remote_id().to_proto();
10096 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10097 }
10098 })?
10099 }
10100
10101 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10102 let mut hasher = Sha256::new();
10103 hasher.update(abs_path.to_string_lossy().as_bytes());
10104 hasher.update(self.nonce.to_be_bytes());
10105 hasher.finalize().as_slice().try_into().unwrap()
10106 }
10107
10108 pub async fn handle_get_project_symbols(
10109 this: Entity<Self>,
10110 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10111 mut cx: AsyncApp,
10112 ) -> Result<proto::GetProjectSymbolsResponse> {
10113 let symbols = this
10114 .update(&mut cx, |this, cx| {
10115 this.symbols(&envelope.payload.query, cx)
10116 })?
10117 .await?;
10118
10119 Ok(proto::GetProjectSymbolsResponse {
10120 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10121 })
10122 }
10123
10124 pub async fn handle_restart_language_servers(
10125 this: Entity<Self>,
10126 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10127 mut cx: AsyncApp,
10128 ) -> Result<proto::Ack> {
10129 this.update(&mut cx, |lsp_store, cx| {
10130 let buffers =
10131 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10132 lsp_store.restart_language_servers_for_buffers(
10133 buffers,
10134 envelope
10135 .payload
10136 .only_servers
10137 .into_iter()
10138 .filter_map(|selector| {
10139 Some(match selector.selector? {
10140 proto::language_server_selector::Selector::ServerId(server_id) => {
10141 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10142 }
10143 proto::language_server_selector::Selector::Name(name) => {
10144 LanguageServerSelector::Name(LanguageServerName(
10145 SharedString::from(name),
10146 ))
10147 }
10148 })
10149 })
10150 .collect(),
10151 cx,
10152 );
10153 })?;
10154
10155 Ok(proto::Ack {})
10156 }
10157
10158 pub async fn handle_stop_language_servers(
10159 lsp_store: Entity<Self>,
10160 envelope: TypedEnvelope<proto::StopLanguageServers>,
10161 mut cx: AsyncApp,
10162 ) -> Result<proto::Ack> {
10163 lsp_store.update(&mut cx, |lsp_store, cx| {
10164 if envelope.payload.all
10165 && envelope.payload.also_servers.is_empty()
10166 && envelope.payload.buffer_ids.is_empty()
10167 {
10168 lsp_store.stop_all_language_servers(cx);
10169 } else {
10170 let buffers =
10171 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10172 lsp_store
10173 .stop_language_servers_for_buffers(
10174 buffers,
10175 envelope
10176 .payload
10177 .also_servers
10178 .into_iter()
10179 .filter_map(|selector| {
10180 Some(match selector.selector? {
10181 proto::language_server_selector::Selector::ServerId(
10182 server_id,
10183 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10184 server_id,
10185 )),
10186 proto::language_server_selector::Selector::Name(name) => {
10187 LanguageServerSelector::Name(LanguageServerName(
10188 SharedString::from(name),
10189 ))
10190 }
10191 })
10192 })
10193 .collect(),
10194 cx,
10195 )
10196 .detach_and_log_err(cx);
10197 }
10198 })?;
10199
10200 Ok(proto::Ack {})
10201 }
10202
10203 pub async fn handle_cancel_language_server_work(
10204 lsp_store: Entity<Self>,
10205 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10206 mut cx: AsyncApp,
10207 ) -> Result<proto::Ack> {
10208 lsp_store.update(&mut cx, |lsp_store, cx| {
10209 if let Some(work) = envelope.payload.work {
10210 match work {
10211 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10212 let buffers =
10213 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10214 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10215 }
10216 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10217 let server_id = LanguageServerId::from_proto(work.language_server_id);
10218 let token = work
10219 .token
10220 .map(|token| {
10221 ProgressToken::from_proto(token)
10222 .context("invalid work progress token")
10223 })
10224 .transpose()?;
10225 lsp_store.cancel_language_server_work(server_id, token, cx);
10226 }
10227 }
10228 }
10229 anyhow::Ok(())
10230 })??;
10231
10232 Ok(proto::Ack {})
10233 }
10234
10235 fn buffer_ids_to_buffers(
10236 &mut self,
10237 buffer_ids: impl Iterator<Item = u64>,
10238 cx: &mut Context<Self>,
10239 ) -> Vec<Entity<Buffer>> {
10240 buffer_ids
10241 .into_iter()
10242 .flat_map(|buffer_id| {
10243 self.buffer_store
10244 .read(cx)
10245 .get(BufferId::new(buffer_id).log_err()?)
10246 })
10247 .collect::<Vec<_>>()
10248 }
10249
10250 async fn handle_apply_additional_edits_for_completion(
10251 this: Entity<Self>,
10252 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10253 mut cx: AsyncApp,
10254 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10255 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10256 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10257 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10258 let completion = Self::deserialize_completion(
10259 envelope.payload.completion.context("invalid completion")?,
10260 )?;
10261 anyhow::Ok((buffer, completion))
10262 })??;
10263
10264 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10265 this.apply_additional_edits_for_completion(
10266 buffer,
10267 Rc::new(RefCell::new(Box::new([Completion {
10268 replace_range: completion.replace_range,
10269 new_text: completion.new_text,
10270 source: completion.source,
10271 documentation: None,
10272 label: CodeLabel::default(),
10273 match_start: None,
10274 snippet_deduplication_key: None,
10275 insert_text_mode: None,
10276 icon_path: None,
10277 confirm: None,
10278 }]))),
10279 0,
10280 false,
10281 cx,
10282 )
10283 })?;
10284
10285 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10286 transaction: apply_additional_edits
10287 .await?
10288 .as_ref()
10289 .map(language::proto::serialize_transaction),
10290 })
10291 }
10292
10293 pub fn last_formatting_failure(&self) -> Option<&str> {
10294 self.last_formatting_failure.as_deref()
10295 }
10296
10297 pub fn reset_last_formatting_failure(&mut self) {
10298 self.last_formatting_failure = None;
10299 }
10300
10301 pub fn environment_for_buffer(
10302 &self,
10303 buffer: &Entity<Buffer>,
10304 cx: &mut Context<Self>,
10305 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10306 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10307 environment.update(cx, |env, cx| {
10308 env.buffer_environment(buffer, &self.worktree_store, cx)
10309 })
10310 } else {
10311 Task::ready(None).shared()
10312 }
10313 }
10314
10315 pub fn format(
10316 &mut self,
10317 buffers: HashSet<Entity<Buffer>>,
10318 target: LspFormatTarget,
10319 push_to_history: bool,
10320 trigger: FormatTrigger,
10321 cx: &mut Context<Self>,
10322 ) -> Task<anyhow::Result<ProjectTransaction>> {
10323 let logger = zlog::scoped!("format");
10324 if self.as_local().is_some() {
10325 zlog::trace!(logger => "Formatting locally");
10326 let logger = zlog::scoped!(logger => "local");
10327 let buffers = buffers
10328 .into_iter()
10329 .map(|buffer_handle| {
10330 let buffer = buffer_handle.read(cx);
10331 let buffer_abs_path = File::from_dyn(buffer.file())
10332 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10333
10334 (buffer_handle, buffer_abs_path, buffer.remote_id())
10335 })
10336 .collect::<Vec<_>>();
10337
10338 cx.spawn(async move |lsp_store, cx| {
10339 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10340
10341 for (handle, abs_path, id) in buffers {
10342 let env = lsp_store
10343 .update(cx, |lsp_store, cx| {
10344 lsp_store.environment_for_buffer(&handle, cx)
10345 })?
10346 .await;
10347
10348 let ranges = match &target {
10349 LspFormatTarget::Buffers => None,
10350 LspFormatTarget::Ranges(ranges) => {
10351 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10352 }
10353 };
10354
10355 formattable_buffers.push(FormattableBuffer {
10356 handle,
10357 abs_path,
10358 env,
10359 ranges,
10360 });
10361 }
10362 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10363
10364 let format_timer = zlog::time!(logger => "Formatting buffers");
10365 let result = LocalLspStore::format_locally(
10366 lsp_store.clone(),
10367 formattable_buffers,
10368 push_to_history,
10369 trigger,
10370 logger,
10371 cx,
10372 )
10373 .await;
10374 format_timer.end();
10375
10376 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10377
10378 lsp_store.update(cx, |lsp_store, _| {
10379 lsp_store.update_last_formatting_failure(&result);
10380 })?;
10381
10382 result
10383 })
10384 } else if let Some((client, project_id)) = self.upstream_client() {
10385 zlog::trace!(logger => "Formatting remotely");
10386 let logger = zlog::scoped!(logger => "remote");
10387 // Don't support formatting ranges via remote
10388 match target {
10389 LspFormatTarget::Buffers => {}
10390 LspFormatTarget::Ranges(_) => {
10391 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10392 return Task::ready(Ok(ProjectTransaction::default()));
10393 }
10394 }
10395
10396 let buffer_store = self.buffer_store();
10397 cx.spawn(async move |lsp_store, cx| {
10398 zlog::trace!(logger => "Sending remote format request");
10399 let request_timer = zlog::time!(logger => "remote format request");
10400 let result = client
10401 .request(proto::FormatBuffers {
10402 project_id,
10403 trigger: trigger as i32,
10404 buffer_ids: buffers
10405 .iter()
10406 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10407 .collect::<Result<_>>()?,
10408 })
10409 .await
10410 .and_then(|result| result.transaction.context("missing transaction"));
10411 request_timer.end();
10412
10413 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10414
10415 lsp_store.update(cx, |lsp_store, _| {
10416 lsp_store.update_last_formatting_failure(&result);
10417 })?;
10418
10419 let transaction_response = result?;
10420 let _timer = zlog::time!(logger => "deserializing project transaction");
10421 buffer_store
10422 .update(cx, |buffer_store, cx| {
10423 buffer_store.deserialize_project_transaction(
10424 transaction_response,
10425 push_to_history,
10426 cx,
10427 )
10428 })?
10429 .await
10430 })
10431 } else {
10432 zlog::trace!(logger => "Not formatting");
10433 Task::ready(Ok(ProjectTransaction::default()))
10434 }
10435 }
10436
10437 async fn handle_format_buffers(
10438 this: Entity<Self>,
10439 envelope: TypedEnvelope<proto::FormatBuffers>,
10440 mut cx: AsyncApp,
10441 ) -> Result<proto::FormatBuffersResponse> {
10442 let sender_id = envelope.original_sender_id().unwrap_or_default();
10443 let format = this.update(&mut cx, |this, cx| {
10444 let mut buffers = HashSet::default();
10445 for buffer_id in &envelope.payload.buffer_ids {
10446 let buffer_id = BufferId::new(*buffer_id)?;
10447 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10448 }
10449 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10450 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10451 })??;
10452
10453 let project_transaction = format.await?;
10454 let project_transaction = this.update(&mut cx, |this, cx| {
10455 this.buffer_store.update(cx, |buffer_store, cx| {
10456 buffer_store.serialize_project_transaction_for_peer(
10457 project_transaction,
10458 sender_id,
10459 cx,
10460 )
10461 })
10462 })?;
10463 Ok(proto::FormatBuffersResponse {
10464 transaction: Some(project_transaction),
10465 })
10466 }
10467
10468 async fn handle_apply_code_action_kind(
10469 this: Entity<Self>,
10470 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10471 mut cx: AsyncApp,
10472 ) -> Result<proto::ApplyCodeActionKindResponse> {
10473 let sender_id = envelope.original_sender_id().unwrap_or_default();
10474 let format = this.update(&mut cx, |this, cx| {
10475 let mut buffers = HashSet::default();
10476 for buffer_id in &envelope.payload.buffer_ids {
10477 let buffer_id = BufferId::new(*buffer_id)?;
10478 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10479 }
10480 let kind = match envelope.payload.kind.as_str() {
10481 "" => CodeActionKind::EMPTY,
10482 "quickfix" => CodeActionKind::QUICKFIX,
10483 "refactor" => CodeActionKind::REFACTOR,
10484 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10485 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10486 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10487 "source" => CodeActionKind::SOURCE,
10488 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10489 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10490 _ => anyhow::bail!(
10491 "Invalid code action kind {}",
10492 envelope.payload.kind.as_str()
10493 ),
10494 };
10495 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10496 })??;
10497
10498 let project_transaction = format.await?;
10499 let project_transaction = this.update(&mut cx, |this, cx| {
10500 this.buffer_store.update(cx, |buffer_store, cx| {
10501 buffer_store.serialize_project_transaction_for_peer(
10502 project_transaction,
10503 sender_id,
10504 cx,
10505 )
10506 })
10507 })?;
10508 Ok(proto::ApplyCodeActionKindResponse {
10509 transaction: Some(project_transaction),
10510 })
10511 }
10512
10513 async fn shutdown_language_server(
10514 server_state: Option<LanguageServerState>,
10515 name: LanguageServerName,
10516 cx: &mut AsyncApp,
10517 ) {
10518 let server = match server_state {
10519 Some(LanguageServerState::Starting { startup, .. }) => {
10520 let mut timer = cx
10521 .background_executor()
10522 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10523 .fuse();
10524
10525 select! {
10526 server = startup.fuse() => server,
10527 () = timer => {
10528 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10529 None
10530 },
10531 }
10532 }
10533
10534 Some(LanguageServerState::Running { server, .. }) => Some(server),
10535
10536 None => None,
10537 };
10538
10539 if let Some(server) = server
10540 && let Some(shutdown) = server.shutdown()
10541 {
10542 shutdown.await;
10543 }
10544 }
10545
10546 // Returns a list of all of the worktrees which no longer have a language server and the root path
10547 // for the stopped server
10548 fn stop_local_language_server(
10549 &mut self,
10550 server_id: LanguageServerId,
10551 cx: &mut Context<Self>,
10552 ) -> Task<()> {
10553 let local = match &mut self.mode {
10554 LspStoreMode::Local(local) => local,
10555 _ => {
10556 return Task::ready(());
10557 }
10558 };
10559
10560 // Remove this server ID from all entries in the given worktree.
10561 local
10562 .language_server_ids
10563 .retain(|_, state| state.id != server_id);
10564 self.buffer_store.update(cx, |buffer_store, cx| {
10565 for buffer in buffer_store.buffers() {
10566 buffer.update(cx, |buffer, cx| {
10567 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10568 buffer.set_completion_triggers(server_id, Default::default(), cx);
10569 });
10570 }
10571 });
10572
10573 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10574 summaries.retain(|path, summaries_by_server_id| {
10575 if summaries_by_server_id.remove(&server_id).is_some() {
10576 if let Some((client, project_id)) = self.downstream_client.clone() {
10577 client
10578 .send(proto::UpdateDiagnosticSummary {
10579 project_id,
10580 worktree_id: worktree_id.to_proto(),
10581 summary: Some(proto::DiagnosticSummary {
10582 path: path.as_ref().to_proto(),
10583 language_server_id: server_id.0 as u64,
10584 error_count: 0,
10585 warning_count: 0,
10586 }),
10587 more_summaries: Vec::new(),
10588 })
10589 .log_err();
10590 }
10591 !summaries_by_server_id.is_empty()
10592 } else {
10593 true
10594 }
10595 });
10596 }
10597
10598 let local = self.as_local_mut().unwrap();
10599 for diagnostics in local.diagnostics.values_mut() {
10600 diagnostics.retain(|_, diagnostics_by_server_id| {
10601 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10602 diagnostics_by_server_id.remove(ix);
10603 !diagnostics_by_server_id.is_empty()
10604 } else {
10605 true
10606 }
10607 });
10608 }
10609 local.language_server_watched_paths.remove(&server_id);
10610
10611 let server_state = local.language_servers.remove(&server_id);
10612 self.cleanup_lsp_data(server_id);
10613 let name = self
10614 .language_server_statuses
10615 .remove(&server_id)
10616 .map(|status| status.name)
10617 .or_else(|| {
10618 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10619 Some(adapter.name())
10620 } else {
10621 None
10622 }
10623 });
10624
10625 if let Some(name) = name {
10626 log::info!("stopping language server {name}");
10627 self.languages
10628 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10629 cx.notify();
10630
10631 return cx.spawn(async move |lsp_store, cx| {
10632 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10633 lsp_store
10634 .update(cx, |lsp_store, cx| {
10635 lsp_store
10636 .languages
10637 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10638 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10639 cx.notify();
10640 })
10641 .ok();
10642 });
10643 }
10644
10645 if server_state.is_some() {
10646 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10647 }
10648 Task::ready(())
10649 }
10650
10651 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10652 if let Some((client, project_id)) = self.upstream_client() {
10653 let request = client.request(proto::StopLanguageServers {
10654 project_id,
10655 buffer_ids: Vec::new(),
10656 also_servers: Vec::new(),
10657 all: true,
10658 });
10659 cx.background_spawn(request).detach_and_log_err(cx);
10660 } else {
10661 let Some(local) = self.as_local_mut() else {
10662 return;
10663 };
10664 let language_servers_to_stop = local
10665 .language_server_ids
10666 .values()
10667 .map(|state| state.id)
10668 .collect();
10669 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10670 let tasks = language_servers_to_stop
10671 .into_iter()
10672 .map(|server| self.stop_local_language_server(server, cx))
10673 .collect::<Vec<_>>();
10674 cx.background_spawn(async move {
10675 futures::future::join_all(tasks).await;
10676 })
10677 .detach();
10678 }
10679 }
10680
10681 pub fn restart_language_servers_for_buffers(
10682 &mut self,
10683 buffers: Vec<Entity<Buffer>>,
10684 only_restart_servers: HashSet<LanguageServerSelector>,
10685 cx: &mut Context<Self>,
10686 ) {
10687 if let Some((client, project_id)) = self.upstream_client() {
10688 let request = client.request(proto::RestartLanguageServers {
10689 project_id,
10690 buffer_ids: buffers
10691 .into_iter()
10692 .map(|b| b.read(cx).remote_id().to_proto())
10693 .collect(),
10694 only_servers: only_restart_servers
10695 .into_iter()
10696 .map(|selector| {
10697 let selector = match selector {
10698 LanguageServerSelector::Id(language_server_id) => {
10699 proto::language_server_selector::Selector::ServerId(
10700 language_server_id.to_proto(),
10701 )
10702 }
10703 LanguageServerSelector::Name(language_server_name) => {
10704 proto::language_server_selector::Selector::Name(
10705 language_server_name.to_string(),
10706 )
10707 }
10708 };
10709 proto::LanguageServerSelector {
10710 selector: Some(selector),
10711 }
10712 })
10713 .collect(),
10714 all: false,
10715 });
10716 cx.background_spawn(request).detach_and_log_err(cx);
10717 } else {
10718 let stop_task = if only_restart_servers.is_empty() {
10719 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10720 } else {
10721 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10722 };
10723 cx.spawn(async move |lsp_store, cx| {
10724 stop_task.await;
10725 lsp_store
10726 .update(cx, |lsp_store, cx| {
10727 for buffer in buffers {
10728 lsp_store.register_buffer_with_language_servers(
10729 &buffer,
10730 only_restart_servers.clone(),
10731 true,
10732 cx,
10733 );
10734 }
10735 })
10736 .ok()
10737 })
10738 .detach();
10739 }
10740 }
10741
10742 pub fn stop_language_servers_for_buffers(
10743 &mut self,
10744 buffers: Vec<Entity<Buffer>>,
10745 also_stop_servers: HashSet<LanguageServerSelector>,
10746 cx: &mut Context<Self>,
10747 ) -> Task<Result<()>> {
10748 if let Some((client, project_id)) = self.upstream_client() {
10749 let request = client.request(proto::StopLanguageServers {
10750 project_id,
10751 buffer_ids: buffers
10752 .into_iter()
10753 .map(|b| b.read(cx).remote_id().to_proto())
10754 .collect(),
10755 also_servers: also_stop_servers
10756 .into_iter()
10757 .map(|selector| {
10758 let selector = match selector {
10759 LanguageServerSelector::Id(language_server_id) => {
10760 proto::language_server_selector::Selector::ServerId(
10761 language_server_id.to_proto(),
10762 )
10763 }
10764 LanguageServerSelector::Name(language_server_name) => {
10765 proto::language_server_selector::Selector::Name(
10766 language_server_name.to_string(),
10767 )
10768 }
10769 };
10770 proto::LanguageServerSelector {
10771 selector: Some(selector),
10772 }
10773 })
10774 .collect(),
10775 all: false,
10776 });
10777 cx.background_spawn(async move {
10778 let _ = request.await?;
10779 Ok(())
10780 })
10781 } else {
10782 let task =
10783 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10784 cx.background_spawn(async move {
10785 task.await;
10786 Ok(())
10787 })
10788 }
10789 }
10790
10791 fn stop_local_language_servers_for_buffers(
10792 &mut self,
10793 buffers: &[Entity<Buffer>],
10794 also_stop_servers: HashSet<LanguageServerSelector>,
10795 cx: &mut Context<Self>,
10796 ) -> Task<()> {
10797 let Some(local) = self.as_local_mut() else {
10798 return Task::ready(());
10799 };
10800 let mut language_server_names_to_stop = BTreeSet::default();
10801 let mut language_servers_to_stop = also_stop_servers
10802 .into_iter()
10803 .flat_map(|selector| match selector {
10804 LanguageServerSelector::Id(id) => Some(id),
10805 LanguageServerSelector::Name(name) => {
10806 language_server_names_to_stop.insert(name);
10807 None
10808 }
10809 })
10810 .collect::<BTreeSet<_>>();
10811
10812 let mut covered_worktrees = HashSet::default();
10813 for buffer in buffers {
10814 buffer.update(cx, |buffer, cx| {
10815 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10816 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10817 && covered_worktrees.insert(worktree_id)
10818 {
10819 language_server_names_to_stop.retain(|name| {
10820 let old_ids_count = language_servers_to_stop.len();
10821 let all_language_servers_with_this_name = local
10822 .language_server_ids
10823 .iter()
10824 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10825 language_servers_to_stop.extend(all_language_servers_with_this_name);
10826 old_ids_count == language_servers_to_stop.len()
10827 });
10828 }
10829 });
10830 }
10831 for name in language_server_names_to_stop {
10832 language_servers_to_stop.extend(
10833 local
10834 .language_server_ids
10835 .iter()
10836 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10837 );
10838 }
10839
10840 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10841 let tasks = language_servers_to_stop
10842 .into_iter()
10843 .map(|server| self.stop_local_language_server(server, cx))
10844 .collect::<Vec<_>>();
10845
10846 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10847 }
10848
10849 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10850 let (worktree, relative_path) =
10851 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10852
10853 let project_path = ProjectPath {
10854 worktree_id: worktree.read(cx).id(),
10855 path: relative_path,
10856 };
10857
10858 Some(
10859 self.buffer_store()
10860 .read(cx)
10861 .get_by_path(&project_path)?
10862 .read(cx),
10863 )
10864 }
10865
10866 #[cfg(any(test, feature = "test-support"))]
10867 pub fn update_diagnostics(
10868 &mut self,
10869 server_id: LanguageServerId,
10870 diagnostics: lsp::PublishDiagnosticsParams,
10871 result_id: Option<String>,
10872 source_kind: DiagnosticSourceKind,
10873 disk_based_sources: &[String],
10874 cx: &mut Context<Self>,
10875 ) -> Result<()> {
10876 self.merge_lsp_diagnostics(
10877 source_kind,
10878 vec![DocumentDiagnosticsUpdate {
10879 diagnostics,
10880 result_id,
10881 server_id,
10882 disk_based_sources: Cow::Borrowed(disk_based_sources),
10883 }],
10884 |_, _, _| false,
10885 cx,
10886 )
10887 }
10888
10889 pub fn merge_lsp_diagnostics(
10890 &mut self,
10891 source_kind: DiagnosticSourceKind,
10892 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10893 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10894 cx: &mut Context<Self>,
10895 ) -> Result<()> {
10896 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10897 let updates = lsp_diagnostics
10898 .into_iter()
10899 .filter_map(|update| {
10900 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10901 Some(DocumentDiagnosticsUpdate {
10902 diagnostics: self.lsp_to_document_diagnostics(
10903 abs_path,
10904 source_kind,
10905 update.server_id,
10906 update.diagnostics,
10907 &update.disk_based_sources,
10908 ),
10909 result_id: update.result_id,
10910 server_id: update.server_id,
10911 disk_based_sources: update.disk_based_sources,
10912 })
10913 })
10914 .collect();
10915 self.merge_diagnostic_entries(updates, merge, cx)?;
10916 Ok(())
10917 }
10918
10919 fn lsp_to_document_diagnostics(
10920 &mut self,
10921 document_abs_path: PathBuf,
10922 source_kind: DiagnosticSourceKind,
10923 server_id: LanguageServerId,
10924 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10925 disk_based_sources: &[String],
10926 ) -> DocumentDiagnostics {
10927 let mut diagnostics = Vec::default();
10928 let mut primary_diagnostic_group_ids = HashMap::default();
10929 let mut sources_by_group_id = HashMap::default();
10930 let mut supporting_diagnostics = HashMap::default();
10931
10932 let adapter = self.language_server_adapter_for_id(server_id);
10933
10934 // Ensure that primary diagnostics are always the most severe
10935 lsp_diagnostics
10936 .diagnostics
10937 .sort_by_key(|item| item.severity);
10938
10939 for diagnostic in &lsp_diagnostics.diagnostics {
10940 let source = diagnostic.source.as_ref();
10941 let range = range_from_lsp(diagnostic.range);
10942 let is_supporting = diagnostic
10943 .related_information
10944 .as_ref()
10945 .is_some_and(|infos| {
10946 infos.iter().any(|info| {
10947 primary_diagnostic_group_ids.contains_key(&(
10948 source,
10949 diagnostic.code.clone(),
10950 range_from_lsp(info.location.range),
10951 ))
10952 })
10953 });
10954
10955 let is_unnecessary = diagnostic
10956 .tags
10957 .as_ref()
10958 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10959
10960 let underline = self
10961 .language_server_adapter_for_id(server_id)
10962 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10963
10964 if is_supporting {
10965 supporting_diagnostics.insert(
10966 (source, diagnostic.code.clone(), range),
10967 (diagnostic.severity, is_unnecessary),
10968 );
10969 } else {
10970 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10971 let is_disk_based =
10972 source.is_some_and(|source| disk_based_sources.contains(source));
10973
10974 sources_by_group_id.insert(group_id, source);
10975 primary_diagnostic_group_ids
10976 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10977
10978 diagnostics.push(DiagnosticEntry {
10979 range,
10980 diagnostic: Diagnostic {
10981 source: diagnostic.source.clone(),
10982 source_kind,
10983 code: diagnostic.code.clone(),
10984 code_description: diagnostic
10985 .code_description
10986 .as_ref()
10987 .and_then(|d| d.href.clone()),
10988 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10989 markdown: adapter.as_ref().and_then(|adapter| {
10990 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10991 }),
10992 message: diagnostic.message.trim().to_string(),
10993 group_id,
10994 is_primary: true,
10995 is_disk_based,
10996 is_unnecessary,
10997 underline,
10998 data: diagnostic.data.clone(),
10999 },
11000 });
11001 if let Some(infos) = &diagnostic.related_information {
11002 for info in infos {
11003 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11004 let range = range_from_lsp(info.location.range);
11005 diagnostics.push(DiagnosticEntry {
11006 range,
11007 diagnostic: Diagnostic {
11008 source: diagnostic.source.clone(),
11009 source_kind,
11010 code: diagnostic.code.clone(),
11011 code_description: diagnostic
11012 .code_description
11013 .as_ref()
11014 .and_then(|d| d.href.clone()),
11015 severity: DiagnosticSeverity::INFORMATION,
11016 markdown: adapter.as_ref().and_then(|adapter| {
11017 adapter.diagnostic_message_to_markdown(&info.message)
11018 }),
11019 message: info.message.trim().to_string(),
11020 group_id,
11021 is_primary: false,
11022 is_disk_based,
11023 is_unnecessary: false,
11024 underline,
11025 data: diagnostic.data.clone(),
11026 },
11027 });
11028 }
11029 }
11030 }
11031 }
11032 }
11033
11034 for entry in &mut diagnostics {
11035 let diagnostic = &mut entry.diagnostic;
11036 if !diagnostic.is_primary {
11037 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11038 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11039 source,
11040 diagnostic.code.clone(),
11041 entry.range.clone(),
11042 )) {
11043 if let Some(severity) = severity {
11044 diagnostic.severity = severity;
11045 }
11046 diagnostic.is_unnecessary = is_unnecessary;
11047 }
11048 }
11049 }
11050
11051 DocumentDiagnostics {
11052 diagnostics,
11053 document_abs_path,
11054 version: lsp_diagnostics.version,
11055 }
11056 }
11057
11058 fn insert_newly_running_language_server(
11059 &mut self,
11060 adapter: Arc<CachedLspAdapter>,
11061 language_server: Arc<LanguageServer>,
11062 server_id: LanguageServerId,
11063 key: LanguageServerSeed,
11064 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11065 cx: &mut Context<Self>,
11066 ) {
11067 let Some(local) = self.as_local_mut() else {
11068 return;
11069 };
11070 // If the language server for this key doesn't match the server id, don't store the
11071 // server. Which will cause it to be dropped, killing the process
11072 if local
11073 .language_server_ids
11074 .get(&key)
11075 .map(|state| state.id != server_id)
11076 .unwrap_or(false)
11077 {
11078 return;
11079 }
11080
11081 // Update language_servers collection with Running variant of LanguageServerState
11082 // indicating that the server is up and running and ready
11083 let workspace_folders = workspace_folders.lock().clone();
11084 language_server.set_workspace_folders(workspace_folders);
11085
11086 let workspace_diagnostics_refresh_tasks = language_server
11087 .capabilities()
11088 .diagnostic_provider
11089 .and_then(|provider| {
11090 local
11091 .language_server_dynamic_registrations
11092 .entry(server_id)
11093 .or_default()
11094 .diagnostics
11095 .entry(None)
11096 .or_insert(provider.clone());
11097 let workspace_refresher =
11098 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11099
11100 Some((None, workspace_refresher))
11101 })
11102 .into_iter()
11103 .collect();
11104 local.language_servers.insert(
11105 server_id,
11106 LanguageServerState::Running {
11107 workspace_diagnostics_refresh_tasks,
11108 adapter: adapter.clone(),
11109 server: language_server.clone(),
11110 simulate_disk_based_diagnostics_completion: None,
11111 },
11112 );
11113 local
11114 .languages
11115 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11116 if let Some(file_ops_caps) = language_server
11117 .capabilities()
11118 .workspace
11119 .as_ref()
11120 .and_then(|ws| ws.file_operations.as_ref())
11121 {
11122 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11123 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11124 if did_rename_caps.or(will_rename_caps).is_some() {
11125 let watcher = RenamePathsWatchedForServer::default()
11126 .with_did_rename_patterns(did_rename_caps)
11127 .with_will_rename_patterns(will_rename_caps);
11128 local
11129 .language_server_paths_watched_for_rename
11130 .insert(server_id, watcher);
11131 }
11132 }
11133
11134 self.language_server_statuses.insert(
11135 server_id,
11136 LanguageServerStatus {
11137 name: language_server.name(),
11138 pending_work: Default::default(),
11139 has_pending_diagnostic_updates: false,
11140 progress_tokens: Default::default(),
11141 worktree: Some(key.worktree_id),
11142 },
11143 );
11144
11145 cx.emit(LspStoreEvent::LanguageServerAdded(
11146 server_id,
11147 language_server.name(),
11148 Some(key.worktree_id),
11149 ));
11150
11151 let server_capabilities = language_server.capabilities();
11152 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11153 downstream_client
11154 .send(proto::StartLanguageServer {
11155 project_id: *project_id,
11156 server: Some(proto::LanguageServer {
11157 id: server_id.to_proto(),
11158 name: language_server.name().to_string(),
11159 worktree_id: Some(key.worktree_id.to_proto()),
11160 }),
11161 capabilities: serde_json::to_string(&server_capabilities)
11162 .expect("serializing server LSP capabilities"),
11163 })
11164 .log_err();
11165 }
11166 self.lsp_server_capabilities
11167 .insert(server_id, server_capabilities);
11168
11169 // Tell the language server about every open buffer in the worktree that matches the language.
11170 // Also check for buffers in worktrees that reused this server
11171 let mut worktrees_using_server = vec![key.worktree_id];
11172 if let Some(local) = self.as_local() {
11173 // Find all worktrees that have this server in their language server tree
11174 for (worktree_id, servers) in &local.lsp_tree.instances {
11175 if *worktree_id != key.worktree_id {
11176 for server_map in servers.roots.values() {
11177 if server_map
11178 .values()
11179 .any(|(node, _)| node.id() == Some(server_id))
11180 {
11181 worktrees_using_server.push(*worktree_id);
11182 }
11183 }
11184 }
11185 }
11186 }
11187
11188 let mut buffer_paths_registered = Vec::new();
11189 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11190 let mut lsp_adapters = HashMap::default();
11191 for buffer_handle in buffer_store.buffers() {
11192 let buffer = buffer_handle.read(cx);
11193 let file = match File::from_dyn(buffer.file()) {
11194 Some(file) => file,
11195 None => continue,
11196 };
11197 let language = match buffer.language() {
11198 Some(language) => language,
11199 None => continue,
11200 };
11201
11202 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11203 || !lsp_adapters
11204 .entry(language.name())
11205 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11206 .iter()
11207 .any(|a| a.name == key.name)
11208 {
11209 continue;
11210 }
11211 // didOpen
11212 let file = match file.as_local() {
11213 Some(file) => file,
11214 None => continue,
11215 };
11216
11217 let local = self.as_local_mut().unwrap();
11218
11219 let buffer_id = buffer.remote_id();
11220 if local.registered_buffers.contains_key(&buffer_id) {
11221 let versions = local
11222 .buffer_snapshots
11223 .entry(buffer_id)
11224 .or_default()
11225 .entry(server_id)
11226 .and_modify(|_| {
11227 assert!(
11228 false,
11229 "There should not be an existing snapshot for a newly inserted buffer"
11230 )
11231 })
11232 .or_insert_with(|| {
11233 vec![LspBufferSnapshot {
11234 version: 0,
11235 snapshot: buffer.text_snapshot(),
11236 }]
11237 });
11238
11239 let snapshot = versions.last().unwrap();
11240 let version = snapshot.version;
11241 let initial_snapshot = &snapshot.snapshot;
11242 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11243 language_server.register_buffer(
11244 uri,
11245 adapter.language_id(&language.name()),
11246 version,
11247 initial_snapshot.text(),
11248 );
11249 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11250 local
11251 .buffers_opened_in_servers
11252 .entry(buffer_id)
11253 .or_default()
11254 .insert(server_id);
11255 }
11256 buffer_handle.update(cx, |buffer, cx| {
11257 buffer.set_completion_triggers(
11258 server_id,
11259 language_server
11260 .capabilities()
11261 .completion_provider
11262 .as_ref()
11263 .and_then(|provider| {
11264 provider
11265 .trigger_characters
11266 .as_ref()
11267 .map(|characters| characters.iter().cloned().collect())
11268 })
11269 .unwrap_or_default(),
11270 cx,
11271 )
11272 });
11273 }
11274 });
11275
11276 for (buffer_id, abs_path) in buffer_paths_registered {
11277 cx.emit(LspStoreEvent::LanguageServerUpdate {
11278 language_server_id: server_id,
11279 name: Some(adapter.name()),
11280 message: proto::update_language_server::Variant::RegisteredForBuffer(
11281 proto::RegisteredForBuffer {
11282 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11283 buffer_id: buffer_id.to_proto(),
11284 },
11285 ),
11286 });
11287 }
11288
11289 cx.notify();
11290 }
11291
11292 pub fn language_servers_running_disk_based_diagnostics(
11293 &self,
11294 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11295 self.language_server_statuses
11296 .iter()
11297 .filter_map(|(id, status)| {
11298 if status.has_pending_diagnostic_updates {
11299 Some(*id)
11300 } else {
11301 None
11302 }
11303 })
11304 }
11305
11306 pub(crate) fn cancel_language_server_work_for_buffers(
11307 &mut self,
11308 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11309 cx: &mut Context<Self>,
11310 ) {
11311 if let Some((client, project_id)) = self.upstream_client() {
11312 let request = client.request(proto::CancelLanguageServerWork {
11313 project_id,
11314 work: Some(proto::cancel_language_server_work::Work::Buffers(
11315 proto::cancel_language_server_work::Buffers {
11316 buffer_ids: buffers
11317 .into_iter()
11318 .map(|b| b.read(cx).remote_id().to_proto())
11319 .collect(),
11320 },
11321 )),
11322 });
11323 cx.background_spawn(request).detach_and_log_err(cx);
11324 } else if let Some(local) = self.as_local() {
11325 let servers = buffers
11326 .into_iter()
11327 .flat_map(|buffer| {
11328 buffer.update(cx, |buffer, cx| {
11329 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11330 })
11331 })
11332 .collect::<HashSet<_>>();
11333 for server_id in servers {
11334 self.cancel_language_server_work(server_id, None, cx);
11335 }
11336 }
11337 }
11338
11339 pub(crate) fn cancel_language_server_work(
11340 &mut self,
11341 server_id: LanguageServerId,
11342 token_to_cancel: Option<ProgressToken>,
11343 cx: &mut Context<Self>,
11344 ) {
11345 if let Some(local) = self.as_local() {
11346 let status = self.language_server_statuses.get(&server_id);
11347 let server = local.language_servers.get(&server_id);
11348 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11349 {
11350 for (token, progress) in &status.pending_work {
11351 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11352 && token != token_to_cancel
11353 {
11354 continue;
11355 }
11356 if progress.is_cancellable {
11357 server
11358 .notify::<lsp::notification::WorkDoneProgressCancel>(
11359 WorkDoneProgressCancelParams {
11360 token: token.to_lsp(),
11361 },
11362 )
11363 .ok();
11364 }
11365 }
11366 }
11367 } else if let Some((client, project_id)) = self.upstream_client() {
11368 let request = client.request(proto::CancelLanguageServerWork {
11369 project_id,
11370 work: Some(
11371 proto::cancel_language_server_work::Work::LanguageServerWork(
11372 proto::cancel_language_server_work::LanguageServerWork {
11373 language_server_id: server_id.to_proto(),
11374 token: token_to_cancel.map(|token| token.to_proto()),
11375 },
11376 ),
11377 ),
11378 });
11379 cx.background_spawn(request).detach_and_log_err(cx);
11380 }
11381 }
11382
11383 fn register_supplementary_language_server(
11384 &mut self,
11385 id: LanguageServerId,
11386 name: LanguageServerName,
11387 server: Arc<LanguageServer>,
11388 cx: &mut Context<Self>,
11389 ) {
11390 if let Some(local) = self.as_local_mut() {
11391 local
11392 .supplementary_language_servers
11393 .insert(id, (name.clone(), server));
11394 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11395 }
11396 }
11397
11398 fn unregister_supplementary_language_server(
11399 &mut self,
11400 id: LanguageServerId,
11401 cx: &mut Context<Self>,
11402 ) {
11403 if let Some(local) = self.as_local_mut() {
11404 local.supplementary_language_servers.remove(&id);
11405 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11406 }
11407 }
11408
11409 pub(crate) fn supplementary_language_servers(
11410 &self,
11411 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11412 self.as_local().into_iter().flat_map(|local| {
11413 local
11414 .supplementary_language_servers
11415 .iter()
11416 .map(|(id, (name, _))| (*id, name.clone()))
11417 })
11418 }
11419
11420 pub fn language_server_adapter_for_id(
11421 &self,
11422 id: LanguageServerId,
11423 ) -> Option<Arc<CachedLspAdapter>> {
11424 self.as_local()
11425 .and_then(|local| local.language_servers.get(&id))
11426 .and_then(|language_server_state| match language_server_state {
11427 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11428 _ => None,
11429 })
11430 }
11431
11432 pub(super) fn update_local_worktree_language_servers(
11433 &mut self,
11434 worktree_handle: &Entity<Worktree>,
11435 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11436 cx: &mut Context<Self>,
11437 ) {
11438 if changes.is_empty() {
11439 return;
11440 }
11441
11442 let Some(local) = self.as_local() else { return };
11443
11444 local.prettier_store.update(cx, |prettier_store, cx| {
11445 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11446 });
11447
11448 let worktree_id = worktree_handle.read(cx).id();
11449 let mut language_server_ids = local
11450 .language_server_ids
11451 .iter()
11452 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11453 .collect::<Vec<_>>();
11454 language_server_ids.sort();
11455 language_server_ids.dedup();
11456
11457 // let abs_path = worktree_handle.read(cx).abs_path();
11458 for server_id in &language_server_ids {
11459 if let Some(LanguageServerState::Running { server, .. }) =
11460 local.language_servers.get(server_id)
11461 && let Some(watched_paths) = local
11462 .language_server_watched_paths
11463 .get(server_id)
11464 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11465 {
11466 let params = lsp::DidChangeWatchedFilesParams {
11467 changes: changes
11468 .iter()
11469 .filter_map(|(path, _, change)| {
11470 if !watched_paths.is_match(path.as_std_path()) {
11471 return None;
11472 }
11473 let typ = match change {
11474 PathChange::Loaded => return None,
11475 PathChange::Added => lsp::FileChangeType::CREATED,
11476 PathChange::Removed => lsp::FileChangeType::DELETED,
11477 PathChange::Updated => lsp::FileChangeType::CHANGED,
11478 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11479 };
11480 let uri = lsp::Uri::from_file_path(
11481 worktree_handle.read(cx).absolutize(&path),
11482 )
11483 .ok()?;
11484 Some(lsp::FileEvent { uri, typ })
11485 })
11486 .collect(),
11487 };
11488 if !params.changes.is_empty() {
11489 server
11490 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11491 .ok();
11492 }
11493 }
11494 }
11495 for (path, _, _) in changes {
11496 if let Some(file_name) = path.file_name()
11497 && local.watched_manifest_filenames.contains(file_name)
11498 {
11499 self.request_workspace_config_refresh();
11500 break;
11501 }
11502 }
11503 }
11504
11505 pub fn wait_for_remote_buffer(
11506 &mut self,
11507 id: BufferId,
11508 cx: &mut Context<Self>,
11509 ) -> Task<Result<Entity<Buffer>>> {
11510 self.buffer_store.update(cx, |buffer_store, cx| {
11511 buffer_store.wait_for_remote_buffer(id, cx)
11512 })
11513 }
11514
11515 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11516 let mut result = proto::Symbol {
11517 language_server_name: symbol.language_server_name.0.to_string(),
11518 source_worktree_id: symbol.source_worktree_id.to_proto(),
11519 language_server_id: symbol.source_language_server_id.to_proto(),
11520 name: symbol.name.clone(),
11521 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11522 start: Some(proto::PointUtf16 {
11523 row: symbol.range.start.0.row,
11524 column: symbol.range.start.0.column,
11525 }),
11526 end: Some(proto::PointUtf16 {
11527 row: symbol.range.end.0.row,
11528 column: symbol.range.end.0.column,
11529 }),
11530 worktree_id: Default::default(),
11531 path: Default::default(),
11532 signature: Default::default(),
11533 };
11534 match &symbol.path {
11535 SymbolLocation::InProject(path) => {
11536 result.worktree_id = path.worktree_id.to_proto();
11537 result.path = path.path.to_proto();
11538 }
11539 SymbolLocation::OutsideProject {
11540 abs_path,
11541 signature,
11542 } => {
11543 result.path = abs_path.to_string_lossy().into_owned();
11544 result.signature = signature.to_vec();
11545 }
11546 }
11547 result
11548 }
11549
11550 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11551 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11552 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11553 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11554
11555 let path = if serialized_symbol.signature.is_empty() {
11556 SymbolLocation::InProject(ProjectPath {
11557 worktree_id,
11558 path: RelPath::from_proto(&serialized_symbol.path)
11559 .context("invalid symbol path")?,
11560 })
11561 } else {
11562 SymbolLocation::OutsideProject {
11563 abs_path: Path::new(&serialized_symbol.path).into(),
11564 signature: serialized_symbol
11565 .signature
11566 .try_into()
11567 .map_err(|_| anyhow!("invalid signature"))?,
11568 }
11569 };
11570
11571 let start = serialized_symbol.start.context("invalid start")?;
11572 let end = serialized_symbol.end.context("invalid end")?;
11573 Ok(CoreSymbol {
11574 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11575 source_worktree_id,
11576 source_language_server_id: LanguageServerId::from_proto(
11577 serialized_symbol.language_server_id,
11578 ),
11579 path,
11580 name: serialized_symbol.name,
11581 range: Unclipped(PointUtf16::new(start.row, start.column))
11582 ..Unclipped(PointUtf16::new(end.row, end.column)),
11583 kind,
11584 })
11585 }
11586
11587 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11588 let mut serialized_completion = proto::Completion {
11589 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11590 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11591 new_text: completion.new_text.clone(),
11592 ..proto::Completion::default()
11593 };
11594 match &completion.source {
11595 CompletionSource::Lsp {
11596 insert_range,
11597 server_id,
11598 lsp_completion,
11599 lsp_defaults,
11600 resolved,
11601 } => {
11602 let (old_insert_start, old_insert_end) = insert_range
11603 .as_ref()
11604 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11605 .unzip();
11606
11607 serialized_completion.old_insert_start = old_insert_start;
11608 serialized_completion.old_insert_end = old_insert_end;
11609 serialized_completion.source = proto::completion::Source::Lsp as i32;
11610 serialized_completion.server_id = server_id.0 as u64;
11611 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11612 serialized_completion.lsp_defaults = lsp_defaults
11613 .as_deref()
11614 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11615 serialized_completion.resolved = *resolved;
11616 }
11617 CompletionSource::BufferWord {
11618 word_range,
11619 resolved,
11620 } => {
11621 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11622 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11623 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11624 serialized_completion.resolved = *resolved;
11625 }
11626 CompletionSource::Custom => {
11627 serialized_completion.source = proto::completion::Source::Custom as i32;
11628 serialized_completion.resolved = true;
11629 }
11630 CompletionSource::Dap { sort_text } => {
11631 serialized_completion.source = proto::completion::Source::Dap as i32;
11632 serialized_completion.sort_text = Some(sort_text.clone());
11633 }
11634 }
11635
11636 serialized_completion
11637 }
11638
11639 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11640 let old_replace_start = completion
11641 .old_replace_start
11642 .and_then(deserialize_anchor)
11643 .context("invalid old start")?;
11644 let old_replace_end = completion
11645 .old_replace_end
11646 .and_then(deserialize_anchor)
11647 .context("invalid old end")?;
11648 let insert_range = {
11649 match completion.old_insert_start.zip(completion.old_insert_end) {
11650 Some((start, end)) => {
11651 let start = deserialize_anchor(start).context("invalid insert old start")?;
11652 let end = deserialize_anchor(end).context("invalid insert old end")?;
11653 Some(start..end)
11654 }
11655 None => None,
11656 }
11657 };
11658 Ok(CoreCompletion {
11659 replace_range: old_replace_start..old_replace_end,
11660 new_text: completion.new_text,
11661 source: match proto::completion::Source::from_i32(completion.source) {
11662 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11663 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11664 insert_range,
11665 server_id: LanguageServerId::from_proto(completion.server_id),
11666 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11667 lsp_defaults: completion
11668 .lsp_defaults
11669 .as_deref()
11670 .map(serde_json::from_slice)
11671 .transpose()?,
11672 resolved: completion.resolved,
11673 },
11674 Some(proto::completion::Source::BufferWord) => {
11675 let word_range = completion
11676 .buffer_word_start
11677 .and_then(deserialize_anchor)
11678 .context("invalid buffer word start")?
11679 ..completion
11680 .buffer_word_end
11681 .and_then(deserialize_anchor)
11682 .context("invalid buffer word end")?;
11683 CompletionSource::BufferWord {
11684 word_range,
11685 resolved: completion.resolved,
11686 }
11687 }
11688 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11689 sort_text: completion
11690 .sort_text
11691 .context("expected sort text to exist")?,
11692 },
11693 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11694 },
11695 })
11696 }
11697
11698 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11699 let (kind, lsp_action) = match &action.lsp_action {
11700 LspAction::Action(code_action) => (
11701 proto::code_action::Kind::Action as i32,
11702 serde_json::to_vec(code_action).unwrap(),
11703 ),
11704 LspAction::Command(command) => (
11705 proto::code_action::Kind::Command as i32,
11706 serde_json::to_vec(command).unwrap(),
11707 ),
11708 LspAction::CodeLens(code_lens) => (
11709 proto::code_action::Kind::CodeLens as i32,
11710 serde_json::to_vec(code_lens).unwrap(),
11711 ),
11712 };
11713
11714 proto::CodeAction {
11715 server_id: action.server_id.0 as u64,
11716 start: Some(serialize_anchor(&action.range.start)),
11717 end: Some(serialize_anchor(&action.range.end)),
11718 lsp_action,
11719 kind,
11720 resolved: action.resolved,
11721 }
11722 }
11723
11724 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11725 let start = action
11726 .start
11727 .and_then(deserialize_anchor)
11728 .context("invalid start")?;
11729 let end = action
11730 .end
11731 .and_then(deserialize_anchor)
11732 .context("invalid end")?;
11733 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11734 Some(proto::code_action::Kind::Action) => {
11735 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11736 }
11737 Some(proto::code_action::Kind::Command) => {
11738 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11739 }
11740 Some(proto::code_action::Kind::CodeLens) => {
11741 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11742 }
11743 None => anyhow::bail!("Unknown action kind {}", action.kind),
11744 };
11745 Ok(CodeAction {
11746 server_id: LanguageServerId(action.server_id as usize),
11747 range: start..end,
11748 resolved: action.resolved,
11749 lsp_action,
11750 })
11751 }
11752
11753 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11754 match &formatting_result {
11755 Ok(_) => self.last_formatting_failure = None,
11756 Err(error) => {
11757 let error_string = format!("{error:#}");
11758 log::error!("Formatting failed: {error_string}");
11759 self.last_formatting_failure
11760 .replace(error_string.lines().join(" "));
11761 }
11762 }
11763 }
11764
11765 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11766 self.lsp_server_capabilities.remove(&for_server);
11767 for lsp_data in self.lsp_data.values_mut() {
11768 lsp_data.remove_server_data(for_server);
11769 }
11770 if let Some(local) = self.as_local_mut() {
11771 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11772 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11773 buffer_servers.remove(&for_server);
11774 }
11775 }
11776 }
11777
11778 pub fn result_id(
11779 &self,
11780 server_id: LanguageServerId,
11781 buffer_id: BufferId,
11782 cx: &App,
11783 ) -> Option<String> {
11784 let abs_path = self
11785 .buffer_store
11786 .read(cx)
11787 .get(buffer_id)
11788 .and_then(|b| File::from_dyn(b.read(cx).file()))
11789 .map(|f| f.abs_path(cx))?;
11790 self.as_local()?
11791 .buffer_pull_diagnostics_result_ids
11792 .get(&server_id)?
11793 .get(&abs_path)?
11794 .clone()
11795 }
11796
11797 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11798 let Some(local) = self.as_local() else {
11799 return HashMap::default();
11800 };
11801 local
11802 .buffer_pull_diagnostics_result_ids
11803 .get(&server_id)
11804 .into_iter()
11805 .flatten()
11806 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11807 .collect()
11808 }
11809
11810 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11811 if let Some(LanguageServerState::Running {
11812 workspace_diagnostics_refresh_tasks,
11813 ..
11814 }) = self
11815 .as_local_mut()
11816 .and_then(|local| local.language_servers.get_mut(&server_id))
11817 {
11818 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11819 diagnostics.refresh_tx.try_send(()).ok();
11820 }
11821 }
11822 }
11823
11824 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11825 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11826 return;
11827 };
11828 let Some(local) = self.as_local_mut() else {
11829 return;
11830 };
11831
11832 for server_id in buffer.update(cx, |buffer, cx| {
11833 local.language_server_ids_for_buffer(buffer, cx)
11834 }) {
11835 if let Some(LanguageServerState::Running {
11836 workspace_diagnostics_refresh_tasks,
11837 ..
11838 }) = local.language_servers.get_mut(&server_id)
11839 {
11840 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11841 diagnostics.refresh_tx.try_send(()).ok();
11842 }
11843 }
11844 }
11845 }
11846
11847 fn apply_workspace_diagnostic_report(
11848 &mut self,
11849 server_id: LanguageServerId,
11850 report: lsp::WorkspaceDiagnosticReportResult,
11851 cx: &mut Context<Self>,
11852 ) {
11853 let workspace_diagnostics =
11854 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11855 let mut unchanged_buffers = HashSet::default();
11856 let mut changed_buffers = HashSet::default();
11857 let workspace_diagnostics_updates = workspace_diagnostics
11858 .into_iter()
11859 .filter_map(
11860 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11861 LspPullDiagnostics::Response {
11862 server_id,
11863 uri,
11864 diagnostics,
11865 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11866 LspPullDiagnostics::Default => None,
11867 },
11868 )
11869 .fold(
11870 HashMap::default(),
11871 |mut acc, (server_id, uri, diagnostics, version)| {
11872 let (result_id, diagnostics) = match diagnostics {
11873 PulledDiagnostics::Unchanged { result_id } => {
11874 unchanged_buffers.insert(uri.clone());
11875 (Some(result_id), Vec::new())
11876 }
11877 PulledDiagnostics::Changed {
11878 result_id,
11879 diagnostics,
11880 } => {
11881 changed_buffers.insert(uri.clone());
11882 (result_id, diagnostics)
11883 }
11884 };
11885 let disk_based_sources = Cow::Owned(
11886 self.language_server_adapter_for_id(server_id)
11887 .as_ref()
11888 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11889 .unwrap_or(&[])
11890 .to_vec(),
11891 );
11892 acc.entry(server_id)
11893 .or_insert_with(Vec::new)
11894 .push(DocumentDiagnosticsUpdate {
11895 server_id,
11896 diagnostics: lsp::PublishDiagnosticsParams {
11897 uri,
11898 diagnostics,
11899 version,
11900 },
11901 result_id,
11902 disk_based_sources,
11903 });
11904 acc
11905 },
11906 );
11907
11908 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11909 self.merge_lsp_diagnostics(
11910 DiagnosticSourceKind::Pulled,
11911 diagnostic_updates,
11912 |buffer, old_diagnostic, cx| {
11913 File::from_dyn(buffer.file())
11914 .and_then(|file| {
11915 let abs_path = file.as_local()?.abs_path(cx);
11916 lsp::Uri::from_file_path(abs_path).ok()
11917 })
11918 .is_none_or(|buffer_uri| {
11919 unchanged_buffers.contains(&buffer_uri)
11920 || match old_diagnostic.source_kind {
11921 DiagnosticSourceKind::Pulled => {
11922 !changed_buffers.contains(&buffer_uri)
11923 }
11924 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11925 true
11926 }
11927 }
11928 })
11929 },
11930 cx,
11931 )
11932 .log_err();
11933 }
11934 }
11935
11936 fn register_server_capabilities(
11937 &mut self,
11938 server_id: LanguageServerId,
11939 params: lsp::RegistrationParams,
11940 cx: &mut Context<Self>,
11941 ) -> anyhow::Result<()> {
11942 let server = self
11943 .language_server_for_id(server_id)
11944 .with_context(|| format!("no server {server_id} found"))?;
11945 for reg in params.registrations {
11946 match reg.method.as_str() {
11947 "workspace/didChangeWatchedFiles" => {
11948 if let Some(options) = reg.register_options {
11949 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11950 let caps = serde_json::from_value(options)?;
11951 local_lsp_store
11952 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11953 true
11954 } else {
11955 false
11956 };
11957 if notify {
11958 notify_server_capabilities_updated(&server, cx);
11959 }
11960 }
11961 }
11962 "workspace/didChangeConfiguration" => {
11963 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11964 }
11965 "workspace/didChangeWorkspaceFolders" => {
11966 // In this case register options is an empty object, we can ignore it
11967 let caps = lsp::WorkspaceFoldersServerCapabilities {
11968 supported: Some(true),
11969 change_notifications: Some(OneOf::Right(reg.id)),
11970 };
11971 server.update_capabilities(|capabilities| {
11972 capabilities
11973 .workspace
11974 .get_or_insert_default()
11975 .workspace_folders = Some(caps);
11976 });
11977 notify_server_capabilities_updated(&server, cx);
11978 }
11979 "workspace/symbol" => {
11980 let options = parse_register_capabilities(reg)?;
11981 server.update_capabilities(|capabilities| {
11982 capabilities.workspace_symbol_provider = Some(options);
11983 });
11984 notify_server_capabilities_updated(&server, cx);
11985 }
11986 "workspace/fileOperations" => {
11987 if let Some(options) = reg.register_options {
11988 let caps = serde_json::from_value(options)?;
11989 server.update_capabilities(|capabilities| {
11990 capabilities
11991 .workspace
11992 .get_or_insert_default()
11993 .file_operations = Some(caps);
11994 });
11995 notify_server_capabilities_updated(&server, cx);
11996 }
11997 }
11998 "workspace/executeCommand" => {
11999 if let Some(options) = reg.register_options {
12000 let options = serde_json::from_value(options)?;
12001 server.update_capabilities(|capabilities| {
12002 capabilities.execute_command_provider = Some(options);
12003 });
12004 notify_server_capabilities_updated(&server, cx);
12005 }
12006 }
12007 "textDocument/rangeFormatting" => {
12008 let options = parse_register_capabilities(reg)?;
12009 server.update_capabilities(|capabilities| {
12010 capabilities.document_range_formatting_provider = Some(options);
12011 });
12012 notify_server_capabilities_updated(&server, cx);
12013 }
12014 "textDocument/onTypeFormatting" => {
12015 if let Some(options) = reg
12016 .register_options
12017 .map(serde_json::from_value)
12018 .transpose()?
12019 {
12020 server.update_capabilities(|capabilities| {
12021 capabilities.document_on_type_formatting_provider = Some(options);
12022 });
12023 notify_server_capabilities_updated(&server, cx);
12024 }
12025 }
12026 "textDocument/formatting" => {
12027 let options = parse_register_capabilities(reg)?;
12028 server.update_capabilities(|capabilities| {
12029 capabilities.document_formatting_provider = Some(options);
12030 });
12031 notify_server_capabilities_updated(&server, cx);
12032 }
12033 "textDocument/rename" => {
12034 let options = parse_register_capabilities(reg)?;
12035 server.update_capabilities(|capabilities| {
12036 capabilities.rename_provider = Some(options);
12037 });
12038 notify_server_capabilities_updated(&server, cx);
12039 }
12040 "textDocument/inlayHint" => {
12041 let options = parse_register_capabilities(reg)?;
12042 server.update_capabilities(|capabilities| {
12043 capabilities.inlay_hint_provider = Some(options);
12044 });
12045 notify_server_capabilities_updated(&server, cx);
12046 }
12047 "textDocument/documentSymbol" => {
12048 let options = parse_register_capabilities(reg)?;
12049 server.update_capabilities(|capabilities| {
12050 capabilities.document_symbol_provider = Some(options);
12051 });
12052 notify_server_capabilities_updated(&server, cx);
12053 }
12054 "textDocument/codeAction" => {
12055 let options = parse_register_capabilities(reg)?;
12056 let provider = match options {
12057 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12058 OneOf::Right(caps) => caps,
12059 };
12060 server.update_capabilities(|capabilities| {
12061 capabilities.code_action_provider = Some(provider);
12062 });
12063 notify_server_capabilities_updated(&server, cx);
12064 }
12065 "textDocument/definition" => {
12066 let options = parse_register_capabilities(reg)?;
12067 server.update_capabilities(|capabilities| {
12068 capabilities.definition_provider = Some(options);
12069 });
12070 notify_server_capabilities_updated(&server, cx);
12071 }
12072 "textDocument/completion" => {
12073 if let Some(caps) = reg
12074 .register_options
12075 .map(serde_json::from_value::<CompletionOptions>)
12076 .transpose()?
12077 {
12078 server.update_capabilities(|capabilities| {
12079 capabilities.completion_provider = Some(caps.clone());
12080 });
12081
12082 if let Some(local) = self.as_local() {
12083 let mut buffers_with_language_server = Vec::new();
12084 for handle in self.buffer_store.read(cx).buffers() {
12085 let buffer_id = handle.read(cx).remote_id();
12086 if local
12087 .buffers_opened_in_servers
12088 .get(&buffer_id)
12089 .filter(|s| s.contains(&server_id))
12090 .is_some()
12091 {
12092 buffers_with_language_server.push(handle);
12093 }
12094 }
12095 let triggers = caps
12096 .trigger_characters
12097 .unwrap_or_default()
12098 .into_iter()
12099 .collect::<BTreeSet<_>>();
12100 for handle in buffers_with_language_server {
12101 let triggers = triggers.clone();
12102 let _ = handle.update(cx, move |buffer, cx| {
12103 buffer.set_completion_triggers(server_id, triggers, cx);
12104 });
12105 }
12106 }
12107 notify_server_capabilities_updated(&server, cx);
12108 }
12109 }
12110 "textDocument/hover" => {
12111 let options = parse_register_capabilities(reg)?;
12112 let provider = match options {
12113 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12114 OneOf::Right(caps) => caps,
12115 };
12116 server.update_capabilities(|capabilities| {
12117 capabilities.hover_provider = Some(provider);
12118 });
12119 notify_server_capabilities_updated(&server, cx);
12120 }
12121 "textDocument/signatureHelp" => {
12122 if let Some(caps) = reg
12123 .register_options
12124 .map(serde_json::from_value)
12125 .transpose()?
12126 {
12127 server.update_capabilities(|capabilities| {
12128 capabilities.signature_help_provider = Some(caps);
12129 });
12130 notify_server_capabilities_updated(&server, cx);
12131 }
12132 }
12133 "textDocument/didChange" => {
12134 if let Some(sync_kind) = reg
12135 .register_options
12136 .and_then(|opts| opts.get("syncKind").cloned())
12137 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12138 .transpose()?
12139 {
12140 server.update_capabilities(|capabilities| {
12141 let mut sync_options =
12142 Self::take_text_document_sync_options(capabilities);
12143 sync_options.change = Some(sync_kind);
12144 capabilities.text_document_sync =
12145 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12146 });
12147 notify_server_capabilities_updated(&server, cx);
12148 }
12149 }
12150 "textDocument/didSave" => {
12151 if let Some(include_text) = reg
12152 .register_options
12153 .map(|opts| {
12154 let transpose = opts
12155 .get("includeText")
12156 .cloned()
12157 .map(serde_json::from_value::<Option<bool>>)
12158 .transpose();
12159 match transpose {
12160 Ok(value) => Ok(value.flatten()),
12161 Err(e) => Err(e),
12162 }
12163 })
12164 .transpose()?
12165 {
12166 server.update_capabilities(|capabilities| {
12167 let mut sync_options =
12168 Self::take_text_document_sync_options(capabilities);
12169 sync_options.save =
12170 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12171 include_text,
12172 }));
12173 capabilities.text_document_sync =
12174 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12175 });
12176 notify_server_capabilities_updated(&server, cx);
12177 }
12178 }
12179 "textDocument/codeLens" => {
12180 if let Some(caps) = reg
12181 .register_options
12182 .map(serde_json::from_value)
12183 .transpose()?
12184 {
12185 server.update_capabilities(|capabilities| {
12186 capabilities.code_lens_provider = Some(caps);
12187 });
12188 notify_server_capabilities_updated(&server, cx);
12189 }
12190 }
12191 "textDocument/diagnostic" => {
12192 if let Some(caps) = reg
12193 .register_options
12194 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12195 .transpose()?
12196 {
12197 let local = self
12198 .as_local_mut()
12199 .context("Expected LSP Store to be local")?;
12200 let state = local
12201 .language_servers
12202 .get_mut(&server_id)
12203 .context("Could not obtain Language Servers state")?;
12204 local
12205 .language_server_dynamic_registrations
12206 .entry(server_id)
12207 .or_default()
12208 .diagnostics
12209 .insert(Some(reg.id.clone()), caps.clone());
12210
12211 if let LanguageServerState::Running {
12212 workspace_diagnostics_refresh_tasks,
12213 ..
12214 } = state
12215 && let Some(task) = lsp_workspace_diagnostics_refresh(
12216 Some(reg.id.clone()),
12217 caps.clone(),
12218 server.clone(),
12219 cx,
12220 )
12221 {
12222 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12223 }
12224
12225 let mut did_update_caps = false;
12226 server.update_capabilities(|capabilities| {
12227 if capabilities.diagnostic_provider.as_ref().is_none_or(
12228 |current_caps| {
12229 let supports_workspace_diagnostics =
12230 |capabilities: &DiagnosticServerCapabilities| {
12231 match capabilities {
12232 DiagnosticServerCapabilities::Options(
12233 diagnostic_options,
12234 ) => diagnostic_options.workspace_diagnostics,
12235 DiagnosticServerCapabilities::RegistrationOptions(
12236 diagnostic_registration_options,
12237 ) => {
12238 diagnostic_registration_options
12239 .diagnostic_options
12240 .workspace_diagnostics
12241 }
12242 }
12243 };
12244 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12245 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12246 // as it'll think that they're not supported.
12247 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12248 !supports_workspace_diagnostics(current_caps)
12249 & supports_workspace_diagnostics(&caps)
12250 },
12251 ) {
12252 did_update_caps = true;
12253 capabilities.diagnostic_provider = Some(caps);
12254 }
12255 });
12256 if did_update_caps {
12257 notify_server_capabilities_updated(&server, cx);
12258 }
12259 }
12260 }
12261 "textDocument/documentColor" => {
12262 let options = parse_register_capabilities(reg)?;
12263 let provider = match options {
12264 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12265 OneOf::Right(caps) => caps,
12266 };
12267 server.update_capabilities(|capabilities| {
12268 capabilities.color_provider = Some(provider);
12269 });
12270 notify_server_capabilities_updated(&server, cx);
12271 }
12272 _ => log::warn!("unhandled capability registration: {reg:?}"),
12273 }
12274 }
12275
12276 Ok(())
12277 }
12278
12279 fn unregister_server_capabilities(
12280 &mut self,
12281 server_id: LanguageServerId,
12282 params: lsp::UnregistrationParams,
12283 cx: &mut Context<Self>,
12284 ) -> anyhow::Result<()> {
12285 let server = self
12286 .language_server_for_id(server_id)
12287 .with_context(|| format!("no server {server_id} found"))?;
12288 for unreg in params.unregisterations.iter() {
12289 match unreg.method.as_str() {
12290 "workspace/didChangeWatchedFiles" => {
12291 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12292 local_lsp_store
12293 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12294 true
12295 } else {
12296 false
12297 };
12298 if notify {
12299 notify_server_capabilities_updated(&server, cx);
12300 }
12301 }
12302 "workspace/didChangeConfiguration" => {
12303 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12304 }
12305 "workspace/didChangeWorkspaceFolders" => {
12306 server.update_capabilities(|capabilities| {
12307 capabilities
12308 .workspace
12309 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12310 workspace_folders: None,
12311 file_operations: None,
12312 })
12313 .workspace_folders = None;
12314 });
12315 notify_server_capabilities_updated(&server, cx);
12316 }
12317 "workspace/symbol" => {
12318 server.update_capabilities(|capabilities| {
12319 capabilities.workspace_symbol_provider = None
12320 });
12321 notify_server_capabilities_updated(&server, cx);
12322 }
12323 "workspace/fileOperations" => {
12324 server.update_capabilities(|capabilities| {
12325 capabilities
12326 .workspace
12327 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12328 workspace_folders: None,
12329 file_operations: None,
12330 })
12331 .file_operations = None;
12332 });
12333 notify_server_capabilities_updated(&server, cx);
12334 }
12335 "workspace/executeCommand" => {
12336 server.update_capabilities(|capabilities| {
12337 capabilities.execute_command_provider = None;
12338 });
12339 notify_server_capabilities_updated(&server, cx);
12340 }
12341 "textDocument/rangeFormatting" => {
12342 server.update_capabilities(|capabilities| {
12343 capabilities.document_range_formatting_provider = None
12344 });
12345 notify_server_capabilities_updated(&server, cx);
12346 }
12347 "textDocument/onTypeFormatting" => {
12348 server.update_capabilities(|capabilities| {
12349 capabilities.document_on_type_formatting_provider = None;
12350 });
12351 notify_server_capabilities_updated(&server, cx);
12352 }
12353 "textDocument/formatting" => {
12354 server.update_capabilities(|capabilities| {
12355 capabilities.document_formatting_provider = None;
12356 });
12357 notify_server_capabilities_updated(&server, cx);
12358 }
12359 "textDocument/rename" => {
12360 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12361 notify_server_capabilities_updated(&server, cx);
12362 }
12363 "textDocument/codeAction" => {
12364 server.update_capabilities(|capabilities| {
12365 capabilities.code_action_provider = None;
12366 });
12367 notify_server_capabilities_updated(&server, cx);
12368 }
12369 "textDocument/definition" => {
12370 server.update_capabilities(|capabilities| {
12371 capabilities.definition_provider = None;
12372 });
12373 notify_server_capabilities_updated(&server, cx);
12374 }
12375 "textDocument/completion" => {
12376 server.update_capabilities(|capabilities| {
12377 capabilities.completion_provider = None;
12378 });
12379 notify_server_capabilities_updated(&server, cx);
12380 }
12381 "textDocument/hover" => {
12382 server.update_capabilities(|capabilities| {
12383 capabilities.hover_provider = None;
12384 });
12385 notify_server_capabilities_updated(&server, cx);
12386 }
12387 "textDocument/signatureHelp" => {
12388 server.update_capabilities(|capabilities| {
12389 capabilities.signature_help_provider = None;
12390 });
12391 notify_server_capabilities_updated(&server, cx);
12392 }
12393 "textDocument/didChange" => {
12394 server.update_capabilities(|capabilities| {
12395 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12396 sync_options.change = None;
12397 capabilities.text_document_sync =
12398 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12399 });
12400 notify_server_capabilities_updated(&server, cx);
12401 }
12402 "textDocument/didSave" => {
12403 server.update_capabilities(|capabilities| {
12404 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12405 sync_options.save = None;
12406 capabilities.text_document_sync =
12407 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12408 });
12409 notify_server_capabilities_updated(&server, cx);
12410 }
12411 "textDocument/codeLens" => {
12412 server.update_capabilities(|capabilities| {
12413 capabilities.code_lens_provider = None;
12414 });
12415 notify_server_capabilities_updated(&server, cx);
12416 }
12417 "textDocument/diagnostic" => {
12418 let local = self
12419 .as_local_mut()
12420 .context("Expected LSP Store to be local")?;
12421
12422 let state = local
12423 .language_servers
12424 .get_mut(&server_id)
12425 .context("Could not obtain Language Servers state")?;
12426 let options = local
12427 .language_server_dynamic_registrations
12428 .get_mut(&server_id)
12429 .with_context(|| {
12430 format!("Expected dynamic registration to exist for server {server_id}")
12431 })?.diagnostics
12432 .remove(&Some(unreg.id.clone()))
12433 .with_context(|| format!(
12434 "Attempted to unregister non-existent diagnostic registration with ID {}",
12435 unreg.id)
12436 )?;
12437
12438 let mut has_any_diagnostic_providers_still = true;
12439 if let Some(identifier) = diagnostic_identifier(&options)
12440 && let LanguageServerState::Running {
12441 workspace_diagnostics_refresh_tasks,
12442 ..
12443 } = state
12444 {
12445 workspace_diagnostics_refresh_tasks.remove(&identifier);
12446 has_any_diagnostic_providers_still =
12447 !workspace_diagnostics_refresh_tasks.is_empty();
12448 }
12449
12450 if !has_any_diagnostic_providers_still {
12451 server.update_capabilities(|capabilities| {
12452 debug_assert!(capabilities.diagnostic_provider.is_some());
12453 capabilities.diagnostic_provider = None;
12454 });
12455 }
12456
12457 notify_server_capabilities_updated(&server, cx);
12458 }
12459 "textDocument/documentColor" => {
12460 server.update_capabilities(|capabilities| {
12461 capabilities.color_provider = None;
12462 });
12463 notify_server_capabilities_updated(&server, cx);
12464 }
12465 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12466 }
12467 }
12468
12469 Ok(())
12470 }
12471
12472 async fn deduplicate_range_based_lsp_requests<T>(
12473 lsp_store: &Entity<Self>,
12474 server_id: Option<LanguageServerId>,
12475 lsp_request_id: LspRequestId,
12476 proto_request: &T::ProtoRequest,
12477 range: Range<Anchor>,
12478 cx: &mut AsyncApp,
12479 ) -> Result<()>
12480 where
12481 T: LspCommand,
12482 T::ProtoRequest: proto::LspRequestMessage,
12483 {
12484 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12485 let version = deserialize_version(proto_request.buffer_version());
12486 let buffer = lsp_store.update(cx, |this, cx| {
12487 this.buffer_store.read(cx).get_existing(buffer_id)
12488 })??;
12489 buffer
12490 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12491 .await?;
12492 lsp_store.update(cx, |lsp_store, cx| {
12493 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12494 let chunks_queried_for = lsp_data
12495 .inlay_hints
12496 .applicable_chunks(&[range])
12497 .collect::<Vec<_>>();
12498 match chunks_queried_for.as_slice() {
12499 &[chunk] => {
12500 let key = LspKey {
12501 request_type: TypeId::of::<T>(),
12502 server_queried: server_id,
12503 };
12504 let previous_request = lsp_data
12505 .chunk_lsp_requests
12506 .entry(key)
12507 .or_default()
12508 .insert(chunk, lsp_request_id);
12509 if let Some((previous_request, running_requests)) =
12510 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12511 {
12512 running_requests.remove(&previous_request);
12513 }
12514 }
12515 _ambiguous_chunks => {
12516 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12517 // there, a buffer version-based check will be performed and outdated requests discarded.
12518 }
12519 }
12520 anyhow::Ok(())
12521 })??;
12522
12523 Ok(())
12524 }
12525
12526 async fn query_lsp_locally<T>(
12527 lsp_store: Entity<Self>,
12528 for_server_id: Option<LanguageServerId>,
12529 sender_id: proto::PeerId,
12530 lsp_request_id: LspRequestId,
12531 proto_request: T::ProtoRequest,
12532 position: Option<Anchor>,
12533 cx: &mut AsyncApp,
12534 ) -> Result<()>
12535 where
12536 T: LspCommand + Clone,
12537 T::ProtoRequest: proto::LspRequestMessage,
12538 <T::ProtoRequest as proto::RequestMessage>::Response:
12539 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12540 {
12541 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12542 let version = deserialize_version(proto_request.buffer_version());
12543 let buffer = lsp_store.update(cx, |this, cx| {
12544 this.buffer_store.read(cx).get_existing(buffer_id)
12545 })??;
12546 buffer
12547 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12548 .await?;
12549 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12550 let request =
12551 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12552 let key = LspKey {
12553 request_type: TypeId::of::<T>(),
12554 server_queried: for_server_id,
12555 };
12556 lsp_store.update(cx, |lsp_store, cx| {
12557 let request_task = match for_server_id {
12558 Some(server_id) => {
12559 let server_task = lsp_store.request_lsp(
12560 buffer.clone(),
12561 LanguageServerToQuery::Other(server_id),
12562 request.clone(),
12563 cx,
12564 );
12565 cx.background_spawn(async move {
12566 let mut responses = Vec::new();
12567 match server_task.await {
12568 Ok(response) => responses.push((server_id, response)),
12569 // rust-analyzer likes to error with this when its still loading up
12570 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12571 Err(e) => log::error!(
12572 "Error handling response for request {request:?}: {e:#}"
12573 ),
12574 }
12575 responses
12576 })
12577 }
12578 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12579 };
12580 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12581 if T::ProtoRequest::stop_previous_requests() {
12582 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12583 lsp_requests.clear();
12584 }
12585 }
12586 lsp_data.lsp_requests.entry(key).or_default().insert(
12587 lsp_request_id,
12588 cx.spawn(async move |lsp_store, cx| {
12589 let response = request_task.await;
12590 lsp_store
12591 .update(cx, |lsp_store, cx| {
12592 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12593 {
12594 let response = response
12595 .into_iter()
12596 .map(|(server_id, response)| {
12597 (
12598 server_id.to_proto(),
12599 T::response_to_proto(
12600 response,
12601 lsp_store,
12602 sender_id,
12603 &buffer_version,
12604 cx,
12605 )
12606 .into(),
12607 )
12608 })
12609 .collect::<HashMap<_, _>>();
12610 match client.send_lsp_response::<T::ProtoRequest>(
12611 project_id,
12612 lsp_request_id,
12613 response,
12614 ) {
12615 Ok(()) => {}
12616 Err(e) => {
12617 log::error!("Failed to send LSP response: {e:#}",)
12618 }
12619 }
12620 }
12621 })
12622 .ok();
12623 }),
12624 );
12625 })?;
12626 Ok(())
12627 }
12628
12629 fn take_text_document_sync_options(
12630 capabilities: &mut lsp::ServerCapabilities,
12631 ) -> lsp::TextDocumentSyncOptions {
12632 match capabilities.text_document_sync.take() {
12633 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12634 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12635 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12636 sync_options.change = Some(sync_kind);
12637 sync_options
12638 }
12639 None => lsp::TextDocumentSyncOptions::default(),
12640 }
12641 }
12642
12643 #[cfg(any(test, feature = "test-support"))]
12644 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12645 Some(
12646 self.lsp_data
12647 .get_mut(&buffer_id)?
12648 .code_lens
12649 .take()?
12650 .update
12651 .take()?
12652 .1,
12653 )
12654 }
12655
12656 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12657 self.downstream_client.clone()
12658 }
12659
12660 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12661 self.worktree_store.clone()
12662 }
12663
12664 /// Gets what's stored in the LSP data for the given buffer.
12665 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12666 self.lsp_data.get_mut(&buffer_id)
12667 }
12668
12669 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12670 /// new [`BufferLspData`] will be created to replace the previous state.
12671 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12672 let (buffer_id, buffer_version) =
12673 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12674 let lsp_data = self
12675 .lsp_data
12676 .entry(buffer_id)
12677 .or_insert_with(|| BufferLspData::new(buffer, cx));
12678 if buffer_version.changed_since(&lsp_data.buffer_version) {
12679 *lsp_data = BufferLspData::new(buffer, cx);
12680 }
12681 lsp_data
12682 }
12683}
12684
12685// Registration with registerOptions as null, should fallback to true.
12686// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12687fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12688 reg: lsp::Registration,
12689) -> Result<OneOf<bool, T>> {
12690 Ok(match reg.register_options {
12691 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12692 None => OneOf::Left(true),
12693 })
12694}
12695
12696fn subscribe_to_binary_statuses(
12697 languages: &Arc<LanguageRegistry>,
12698 cx: &mut Context<'_, LspStore>,
12699) -> Task<()> {
12700 let mut server_statuses = languages.language_server_binary_statuses();
12701 cx.spawn(async move |lsp_store, cx| {
12702 while let Some((server_name, binary_status)) = server_statuses.next().await {
12703 if lsp_store
12704 .update(cx, |_, cx| {
12705 let mut message = None;
12706 let binary_status = match binary_status {
12707 BinaryStatus::None => proto::ServerBinaryStatus::None,
12708 BinaryStatus::CheckingForUpdate => {
12709 proto::ServerBinaryStatus::CheckingForUpdate
12710 }
12711 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12712 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12713 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12714 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12715 BinaryStatus::Failed { error } => {
12716 message = Some(error);
12717 proto::ServerBinaryStatus::Failed
12718 }
12719 };
12720 cx.emit(LspStoreEvent::LanguageServerUpdate {
12721 // Binary updates are about the binary that might not have any language server id at that point.
12722 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12723 language_server_id: LanguageServerId(0),
12724 name: Some(server_name),
12725 message: proto::update_language_server::Variant::StatusUpdate(
12726 proto::StatusUpdate {
12727 message,
12728 status: Some(proto::status_update::Status::Binary(
12729 binary_status as i32,
12730 )),
12731 },
12732 ),
12733 });
12734 })
12735 .is_err()
12736 {
12737 break;
12738 }
12739 }
12740 })
12741}
12742
12743fn lsp_workspace_diagnostics_refresh(
12744 registration_id: Option<String>,
12745 options: DiagnosticServerCapabilities,
12746 server: Arc<LanguageServer>,
12747 cx: &mut Context<'_, LspStore>,
12748) -> Option<WorkspaceRefreshTask> {
12749 let identifier = diagnostic_identifier(&options)?;
12750
12751 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12752 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12753 refresh_tx.try_send(()).ok();
12754
12755 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12756 let mut attempts = 0;
12757 let max_attempts = 50;
12758 let mut requests = 0;
12759
12760 loop {
12761 let Some(()) = refresh_rx.recv().await else {
12762 return;
12763 };
12764
12765 'request: loop {
12766 requests += 1;
12767 if attempts > max_attempts {
12768 log::error!(
12769 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12770 );
12771 return;
12772 }
12773 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12774 cx.background_executor()
12775 .timer(Duration::from_millis(backoff_millis))
12776 .await;
12777 attempts += 1;
12778
12779 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12780 lsp_store
12781 .all_result_ids(server.server_id())
12782 .into_iter()
12783 .filter_map(|(abs_path, result_id)| {
12784 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12785 Some(lsp::PreviousResultId {
12786 uri,
12787 value: result_id,
12788 })
12789 })
12790 .collect()
12791 }) else {
12792 return;
12793 };
12794
12795 let token = if let Some(identifier) = ®istration_id {
12796 format!(
12797 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12798 server.server_id(),
12799 )
12800 } else {
12801 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12802 };
12803
12804 progress_rx.try_recv().ok();
12805 let timer =
12806 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12807 let progress = pin!(progress_rx.recv().fuse());
12808 let response_result = server
12809 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12810 lsp::WorkspaceDiagnosticParams {
12811 previous_result_ids,
12812 identifier: identifier.clone(),
12813 work_done_progress_params: Default::default(),
12814 partial_result_params: lsp::PartialResultParams {
12815 partial_result_token: Some(lsp::ProgressToken::String(token)),
12816 },
12817 },
12818 select(timer, progress).then(|either| match either {
12819 Either::Left((message, ..)) => ready(message).left_future(),
12820 Either::Right(..) => pending::<String>().right_future(),
12821 }),
12822 )
12823 .await;
12824
12825 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12826 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12827 match response_result {
12828 ConnectionResult::Timeout => {
12829 log::error!("Timeout during workspace diagnostics pull");
12830 continue 'request;
12831 }
12832 ConnectionResult::ConnectionReset => {
12833 log::error!("Server closed a workspace diagnostics pull request");
12834 continue 'request;
12835 }
12836 ConnectionResult::Result(Err(e)) => {
12837 log::error!("Error during workspace diagnostics pull: {e:#}");
12838 break 'request;
12839 }
12840 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12841 attempts = 0;
12842 if lsp_store
12843 .update(cx, |lsp_store, cx| {
12844 lsp_store.apply_workspace_diagnostic_report(
12845 server.server_id(),
12846 pulled_diagnostics,
12847 cx,
12848 )
12849 })
12850 .is_err()
12851 {
12852 return;
12853 }
12854 break 'request;
12855 }
12856 }
12857 }
12858 }
12859 });
12860
12861 Some(WorkspaceRefreshTask {
12862 refresh_tx,
12863 progress_tx,
12864 task: workspace_query_language_server,
12865 })
12866}
12867
12868fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12869 match &options {
12870 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12871 if !diagnostic_options.workspace_diagnostics {
12872 return None;
12873 }
12874 Some(diagnostic_options.identifier.clone())
12875 }
12876 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12877 let diagnostic_options = ®istration_options.diagnostic_options;
12878 if !diagnostic_options.workspace_diagnostics {
12879 return None;
12880 }
12881 Some(diagnostic_options.identifier.clone())
12882 }
12883 }
12884}
12885
12886fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12887 let CompletionSource::BufferWord {
12888 word_range,
12889 resolved,
12890 } = &mut completion.source
12891 else {
12892 return;
12893 };
12894 if *resolved {
12895 return;
12896 }
12897
12898 if completion.new_text
12899 != snapshot
12900 .text_for_range(word_range.clone())
12901 .collect::<String>()
12902 {
12903 return;
12904 }
12905
12906 let mut offset = 0;
12907 for chunk in snapshot.chunks(word_range.clone(), true) {
12908 let end_offset = offset + chunk.text.len();
12909 if let Some(highlight_id) = chunk.syntax_highlight_id {
12910 completion
12911 .label
12912 .runs
12913 .push((offset..end_offset, highlight_id));
12914 }
12915 offset = end_offset;
12916 }
12917 *resolved = true;
12918}
12919
12920impl EventEmitter<LspStoreEvent> for LspStore {}
12921
12922fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12923 hover
12924 .contents
12925 .retain(|hover_block| !hover_block.text.trim().is_empty());
12926 if hover.contents.is_empty() {
12927 None
12928 } else {
12929 Some(hover)
12930 }
12931}
12932
12933async fn populate_labels_for_completions(
12934 new_completions: Vec<CoreCompletion>,
12935 language: Option<Arc<Language>>,
12936 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12937) -> Vec<Completion> {
12938 let lsp_completions = new_completions
12939 .iter()
12940 .filter_map(|new_completion| {
12941 new_completion
12942 .source
12943 .lsp_completion(true)
12944 .map(|lsp_completion| lsp_completion.into_owned())
12945 })
12946 .collect::<Vec<_>>();
12947
12948 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12949 lsp_adapter
12950 .labels_for_completions(&lsp_completions, language)
12951 .await
12952 .log_err()
12953 .unwrap_or_default()
12954 } else {
12955 Vec::new()
12956 }
12957 .into_iter()
12958 .fuse();
12959
12960 let mut completions = Vec::new();
12961 for completion in new_completions {
12962 match completion.source.lsp_completion(true) {
12963 Some(lsp_completion) => {
12964 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12965
12966 let mut label = labels.next().flatten().unwrap_or_else(|| {
12967 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12968 });
12969 ensure_uniform_list_compatible_label(&mut label);
12970 completions.push(Completion {
12971 label,
12972 documentation,
12973 replace_range: completion.replace_range,
12974 new_text: completion.new_text,
12975 insert_text_mode: lsp_completion.insert_text_mode,
12976 source: completion.source,
12977 icon_path: None,
12978 confirm: None,
12979 match_start: None,
12980 snippet_deduplication_key: None,
12981 });
12982 }
12983 None => {
12984 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12985 ensure_uniform_list_compatible_label(&mut label);
12986 completions.push(Completion {
12987 label,
12988 documentation: None,
12989 replace_range: completion.replace_range,
12990 new_text: completion.new_text,
12991 source: completion.source,
12992 insert_text_mode: None,
12993 icon_path: None,
12994 confirm: None,
12995 match_start: None,
12996 snippet_deduplication_key: None,
12997 });
12998 }
12999 }
13000 }
13001 completions
13002}
13003
13004#[derive(Debug)]
13005pub enum LanguageServerToQuery {
13006 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13007 FirstCapable,
13008 /// Query a specific language server.
13009 Other(LanguageServerId),
13010}
13011
13012#[derive(Default)]
13013struct RenamePathsWatchedForServer {
13014 did_rename: Vec<RenameActionPredicate>,
13015 will_rename: Vec<RenameActionPredicate>,
13016}
13017
13018impl RenamePathsWatchedForServer {
13019 fn with_did_rename_patterns(
13020 mut self,
13021 did_rename: Option<&FileOperationRegistrationOptions>,
13022 ) -> Self {
13023 if let Some(did_rename) = did_rename {
13024 self.did_rename = did_rename
13025 .filters
13026 .iter()
13027 .filter_map(|filter| filter.try_into().log_err())
13028 .collect();
13029 }
13030 self
13031 }
13032 fn with_will_rename_patterns(
13033 mut self,
13034 will_rename: Option<&FileOperationRegistrationOptions>,
13035 ) -> Self {
13036 if let Some(will_rename) = will_rename {
13037 self.will_rename = will_rename
13038 .filters
13039 .iter()
13040 .filter_map(|filter| filter.try_into().log_err())
13041 .collect();
13042 }
13043 self
13044 }
13045
13046 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13047 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13048 }
13049 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13050 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13051 }
13052}
13053
13054impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13055 type Error = globset::Error;
13056 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13057 Ok(Self {
13058 kind: ops.pattern.matches.clone(),
13059 glob: GlobBuilder::new(&ops.pattern.glob)
13060 .case_insensitive(
13061 ops.pattern
13062 .options
13063 .as_ref()
13064 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13065 )
13066 .build()?
13067 .compile_matcher(),
13068 })
13069 }
13070}
13071struct RenameActionPredicate {
13072 glob: GlobMatcher,
13073 kind: Option<FileOperationPatternKind>,
13074}
13075
13076impl RenameActionPredicate {
13077 // Returns true if language server should be notified
13078 fn eval(&self, path: &str, is_dir: bool) -> bool {
13079 self.kind.as_ref().is_none_or(|kind| {
13080 let expected_kind = if is_dir {
13081 FileOperationPatternKind::Folder
13082 } else {
13083 FileOperationPatternKind::File
13084 };
13085 kind == &expected_kind
13086 }) && self.glob.is_match(path)
13087 }
13088}
13089
13090#[derive(Default)]
13091struct LanguageServerWatchedPaths {
13092 worktree_paths: HashMap<WorktreeId, GlobSet>,
13093 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13094}
13095
13096#[derive(Default)]
13097struct LanguageServerWatchedPathsBuilder {
13098 worktree_paths: HashMap<WorktreeId, GlobSet>,
13099 abs_paths: HashMap<Arc<Path>, GlobSet>,
13100}
13101
13102impl LanguageServerWatchedPathsBuilder {
13103 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13104 self.worktree_paths.insert(worktree_id, glob_set);
13105 }
13106 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13107 self.abs_paths.insert(path, glob_set);
13108 }
13109 fn build(
13110 self,
13111 fs: Arc<dyn Fs>,
13112 language_server_id: LanguageServerId,
13113 cx: &mut Context<LspStore>,
13114 ) -> LanguageServerWatchedPaths {
13115 let lsp_store = cx.weak_entity();
13116
13117 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13118 let abs_paths = self
13119 .abs_paths
13120 .into_iter()
13121 .map(|(abs_path, globset)| {
13122 let task = cx.spawn({
13123 let abs_path = abs_path.clone();
13124 let fs = fs.clone();
13125
13126 let lsp_store = lsp_store.clone();
13127 async move |_, cx| {
13128 maybe!(async move {
13129 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13130 while let Some(update) = push_updates.0.next().await {
13131 let action = lsp_store
13132 .update(cx, |this, _| {
13133 let Some(local) = this.as_local() else {
13134 return ControlFlow::Break(());
13135 };
13136 let Some(watcher) = local
13137 .language_server_watched_paths
13138 .get(&language_server_id)
13139 else {
13140 return ControlFlow::Break(());
13141 };
13142 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13143 "Watched abs path is not registered with a watcher",
13144 );
13145 let matching_entries = update
13146 .into_iter()
13147 .filter(|event| globs.is_match(&event.path))
13148 .collect::<Vec<_>>();
13149 this.lsp_notify_abs_paths_changed(
13150 language_server_id,
13151 matching_entries,
13152 );
13153 ControlFlow::Continue(())
13154 })
13155 .ok()?;
13156
13157 if action.is_break() {
13158 break;
13159 }
13160 }
13161 Some(())
13162 })
13163 .await;
13164 }
13165 });
13166 (abs_path, (globset, task))
13167 })
13168 .collect();
13169 LanguageServerWatchedPaths {
13170 worktree_paths: self.worktree_paths,
13171 abs_paths,
13172 }
13173 }
13174}
13175
13176struct LspBufferSnapshot {
13177 version: i32,
13178 snapshot: TextBufferSnapshot,
13179}
13180
13181/// A prompt requested by LSP server.
13182#[derive(Clone, Debug)]
13183pub struct LanguageServerPromptRequest {
13184 pub level: PromptLevel,
13185 pub message: String,
13186 pub actions: Vec<MessageActionItem>,
13187 pub lsp_name: String,
13188 pub(crate) response_channel: Sender<MessageActionItem>,
13189}
13190
13191impl LanguageServerPromptRequest {
13192 pub async fn respond(self, index: usize) -> Option<()> {
13193 if let Some(response) = self.actions.into_iter().nth(index) {
13194 self.response_channel.send(response).await.ok()
13195 } else {
13196 None
13197 }
13198 }
13199}
13200impl PartialEq for LanguageServerPromptRequest {
13201 fn eq(&self, other: &Self) -> bool {
13202 self.message == other.message && self.actions == other.actions
13203 }
13204}
13205
13206#[derive(Clone, Debug, PartialEq)]
13207pub enum LanguageServerLogType {
13208 Log(MessageType),
13209 Trace { verbose_info: Option<String> },
13210 Rpc { received: bool },
13211}
13212
13213impl LanguageServerLogType {
13214 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13215 match self {
13216 Self::Log(log_type) => {
13217 use proto::log_message::LogLevel;
13218 let level = match *log_type {
13219 MessageType::ERROR => LogLevel::Error,
13220 MessageType::WARNING => LogLevel::Warning,
13221 MessageType::INFO => LogLevel::Info,
13222 MessageType::LOG => LogLevel::Log,
13223 other => {
13224 log::warn!("Unknown lsp log message type: {other:?}");
13225 LogLevel::Log
13226 }
13227 };
13228 proto::language_server_log::LogType::Log(proto::LogMessage {
13229 level: level as i32,
13230 })
13231 }
13232 Self::Trace { verbose_info } => {
13233 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13234 verbose_info: verbose_info.to_owned(),
13235 })
13236 }
13237 Self::Rpc { received } => {
13238 let kind = if *received {
13239 proto::rpc_message::Kind::Received
13240 } else {
13241 proto::rpc_message::Kind::Sent
13242 };
13243 let kind = kind as i32;
13244 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13245 }
13246 }
13247 }
13248
13249 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13250 use proto::log_message::LogLevel;
13251 use proto::rpc_message;
13252 match log_type {
13253 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13254 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13255 LogLevel::Error => MessageType::ERROR,
13256 LogLevel::Warning => MessageType::WARNING,
13257 LogLevel::Info => MessageType::INFO,
13258 LogLevel::Log => MessageType::LOG,
13259 },
13260 ),
13261 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13262 verbose_info: trace_message.verbose_info,
13263 },
13264 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13265 received: match rpc_message::Kind::from_i32(message.kind)
13266 .unwrap_or(rpc_message::Kind::Received)
13267 {
13268 rpc_message::Kind::Received => true,
13269 rpc_message::Kind::Sent => false,
13270 },
13271 },
13272 }
13273 }
13274}
13275
13276pub struct WorkspaceRefreshTask {
13277 refresh_tx: mpsc::Sender<()>,
13278 progress_tx: mpsc::Sender<()>,
13279 #[allow(dead_code)]
13280 task: Task<()>,
13281}
13282
13283pub enum LanguageServerState {
13284 Starting {
13285 startup: Task<Option<Arc<LanguageServer>>>,
13286 /// List of language servers that will be added to the workspace once it's initialization completes.
13287 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13288 },
13289
13290 Running {
13291 adapter: Arc<CachedLspAdapter>,
13292 server: Arc<LanguageServer>,
13293 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13294 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13295 },
13296}
13297
13298impl LanguageServerState {
13299 fn add_workspace_folder(&self, uri: Uri) {
13300 match self {
13301 LanguageServerState::Starting {
13302 pending_workspace_folders,
13303 ..
13304 } => {
13305 pending_workspace_folders.lock().insert(uri);
13306 }
13307 LanguageServerState::Running { server, .. } => {
13308 server.add_workspace_folder(uri);
13309 }
13310 }
13311 }
13312 fn _remove_workspace_folder(&self, uri: Uri) {
13313 match self {
13314 LanguageServerState::Starting {
13315 pending_workspace_folders,
13316 ..
13317 } => {
13318 pending_workspace_folders.lock().remove(&uri);
13319 }
13320 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13321 }
13322 }
13323}
13324
13325impl std::fmt::Debug for LanguageServerState {
13326 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13327 match self {
13328 LanguageServerState::Starting { .. } => {
13329 f.debug_struct("LanguageServerState::Starting").finish()
13330 }
13331 LanguageServerState::Running { .. } => {
13332 f.debug_struct("LanguageServerState::Running").finish()
13333 }
13334 }
13335 }
13336}
13337
13338#[derive(Clone, Debug, Serialize)]
13339pub struct LanguageServerProgress {
13340 pub is_disk_based_diagnostics_progress: bool,
13341 pub is_cancellable: bool,
13342 pub title: Option<String>,
13343 pub message: Option<String>,
13344 pub percentage: Option<usize>,
13345 #[serde(skip_serializing)]
13346 pub last_update_at: Instant,
13347}
13348
13349#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13350pub struct DiagnosticSummary {
13351 pub error_count: usize,
13352 pub warning_count: usize,
13353}
13354
13355impl DiagnosticSummary {
13356 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13357 let mut this = Self {
13358 error_count: 0,
13359 warning_count: 0,
13360 };
13361
13362 for entry in diagnostics {
13363 if entry.diagnostic.is_primary {
13364 match entry.diagnostic.severity {
13365 DiagnosticSeverity::ERROR => this.error_count += 1,
13366 DiagnosticSeverity::WARNING => this.warning_count += 1,
13367 _ => {}
13368 }
13369 }
13370 }
13371
13372 this
13373 }
13374
13375 pub fn is_empty(&self) -> bool {
13376 self.error_count == 0 && self.warning_count == 0
13377 }
13378
13379 pub fn to_proto(
13380 self,
13381 language_server_id: LanguageServerId,
13382 path: &RelPath,
13383 ) -> proto::DiagnosticSummary {
13384 proto::DiagnosticSummary {
13385 path: path.to_proto(),
13386 language_server_id: language_server_id.0 as u64,
13387 error_count: self.error_count as u32,
13388 warning_count: self.warning_count as u32,
13389 }
13390 }
13391}
13392
13393#[derive(Clone, Debug)]
13394pub enum CompletionDocumentation {
13395 /// There is no documentation for this completion.
13396 Undocumented,
13397 /// A single line of documentation.
13398 SingleLine(SharedString),
13399 /// Multiple lines of plain text documentation.
13400 MultiLinePlainText(SharedString),
13401 /// Markdown documentation.
13402 MultiLineMarkdown(SharedString),
13403 /// Both single line and multiple lines of plain text documentation.
13404 SingleLineAndMultiLinePlainText {
13405 single_line: SharedString,
13406 plain_text: Option<SharedString>,
13407 },
13408}
13409
13410impl CompletionDocumentation {
13411 #[cfg(any(test, feature = "test-support"))]
13412 pub fn text(&self) -> SharedString {
13413 match self {
13414 CompletionDocumentation::Undocumented => "".into(),
13415 CompletionDocumentation::SingleLine(s) => s.clone(),
13416 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13417 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13418 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13419 single_line.clone()
13420 }
13421 }
13422 }
13423}
13424
13425impl From<lsp::Documentation> for CompletionDocumentation {
13426 fn from(docs: lsp::Documentation) -> Self {
13427 match docs {
13428 lsp::Documentation::String(text) => {
13429 if text.lines().count() <= 1 {
13430 CompletionDocumentation::SingleLine(text.into())
13431 } else {
13432 CompletionDocumentation::MultiLinePlainText(text.into())
13433 }
13434 }
13435
13436 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13437 lsp::MarkupKind::PlainText => {
13438 if value.lines().count() <= 1 {
13439 CompletionDocumentation::SingleLine(value.into())
13440 } else {
13441 CompletionDocumentation::MultiLinePlainText(value.into())
13442 }
13443 }
13444
13445 lsp::MarkupKind::Markdown => {
13446 CompletionDocumentation::MultiLineMarkdown(value.into())
13447 }
13448 },
13449 }
13450 }
13451}
13452
13453pub enum ResolvedHint {
13454 Resolved(InlayHint),
13455 Resolving(Shared<Task<()>>),
13456}
13457
13458fn glob_literal_prefix(glob: &Path) -> PathBuf {
13459 glob.components()
13460 .take_while(|component| match component {
13461 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13462 _ => true,
13463 })
13464 .collect()
13465}
13466
13467pub struct SshLspAdapter {
13468 name: LanguageServerName,
13469 binary: LanguageServerBinary,
13470 initialization_options: Option<String>,
13471 code_action_kinds: Option<Vec<CodeActionKind>>,
13472}
13473
13474impl SshLspAdapter {
13475 pub fn new(
13476 name: LanguageServerName,
13477 binary: LanguageServerBinary,
13478 initialization_options: Option<String>,
13479 code_action_kinds: Option<String>,
13480 ) -> Self {
13481 Self {
13482 name,
13483 binary,
13484 initialization_options,
13485 code_action_kinds: code_action_kinds
13486 .as_ref()
13487 .and_then(|c| serde_json::from_str(c).ok()),
13488 }
13489 }
13490}
13491
13492impl LspInstaller for SshLspAdapter {
13493 type BinaryVersion = ();
13494 async fn check_if_user_installed(
13495 &self,
13496 _: &dyn LspAdapterDelegate,
13497 _: Option<Toolchain>,
13498 _: &AsyncApp,
13499 ) -> Option<LanguageServerBinary> {
13500 Some(self.binary.clone())
13501 }
13502
13503 async fn cached_server_binary(
13504 &self,
13505 _: PathBuf,
13506 _: &dyn LspAdapterDelegate,
13507 ) -> Option<LanguageServerBinary> {
13508 None
13509 }
13510
13511 async fn fetch_latest_server_version(
13512 &self,
13513 _: &dyn LspAdapterDelegate,
13514 _: bool,
13515 _: &mut AsyncApp,
13516 ) -> Result<()> {
13517 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13518 }
13519
13520 async fn fetch_server_binary(
13521 &self,
13522 _: (),
13523 _: PathBuf,
13524 _: &dyn LspAdapterDelegate,
13525 ) -> Result<LanguageServerBinary> {
13526 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13527 }
13528}
13529
13530#[async_trait(?Send)]
13531impl LspAdapter for SshLspAdapter {
13532 fn name(&self) -> LanguageServerName {
13533 self.name.clone()
13534 }
13535
13536 async fn initialization_options(
13537 self: Arc<Self>,
13538 _: &Arc<dyn LspAdapterDelegate>,
13539 ) -> Result<Option<serde_json::Value>> {
13540 let Some(options) = &self.initialization_options else {
13541 return Ok(None);
13542 };
13543 let result = serde_json::from_str(options)?;
13544 Ok(result)
13545 }
13546
13547 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13548 self.code_action_kinds.clone()
13549 }
13550}
13551
13552pub fn language_server_settings<'a>(
13553 delegate: &'a dyn LspAdapterDelegate,
13554 language: &LanguageServerName,
13555 cx: &'a App,
13556) -> Option<&'a LspSettings> {
13557 language_server_settings_for(
13558 SettingsLocation {
13559 worktree_id: delegate.worktree_id(),
13560 path: RelPath::empty(),
13561 },
13562 language,
13563 cx,
13564 )
13565}
13566
13567pub(crate) fn language_server_settings_for<'a>(
13568 location: SettingsLocation<'a>,
13569 language: &LanguageServerName,
13570 cx: &'a App,
13571) -> Option<&'a LspSettings> {
13572 ProjectSettings::get(Some(location), cx).lsp.get(language)
13573}
13574
13575pub struct LocalLspAdapterDelegate {
13576 lsp_store: WeakEntity<LspStore>,
13577 worktree: worktree::Snapshot,
13578 fs: Arc<dyn Fs>,
13579 http_client: Arc<dyn HttpClient>,
13580 language_registry: Arc<LanguageRegistry>,
13581 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13582}
13583
13584impl LocalLspAdapterDelegate {
13585 pub fn new(
13586 language_registry: Arc<LanguageRegistry>,
13587 environment: &Entity<ProjectEnvironment>,
13588 lsp_store: WeakEntity<LspStore>,
13589 worktree: &Entity<Worktree>,
13590 http_client: Arc<dyn HttpClient>,
13591 fs: Arc<dyn Fs>,
13592 cx: &mut App,
13593 ) -> Arc<Self> {
13594 let load_shell_env_task =
13595 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13596
13597 Arc::new(Self {
13598 lsp_store,
13599 worktree: worktree.read(cx).snapshot(),
13600 fs,
13601 http_client,
13602 language_registry,
13603 load_shell_env_task,
13604 })
13605 }
13606
13607 fn from_local_lsp(
13608 local: &LocalLspStore,
13609 worktree: &Entity<Worktree>,
13610 cx: &mut App,
13611 ) -> Arc<Self> {
13612 Self::new(
13613 local.languages.clone(),
13614 &local.environment,
13615 local.weak.clone(),
13616 worktree,
13617 local.http_client.clone(),
13618 local.fs.clone(),
13619 cx,
13620 )
13621 }
13622}
13623
13624#[async_trait]
13625impl LspAdapterDelegate for LocalLspAdapterDelegate {
13626 fn show_notification(&self, message: &str, cx: &mut App) {
13627 self.lsp_store
13628 .update(cx, |_, cx| {
13629 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13630 })
13631 .ok();
13632 }
13633
13634 fn http_client(&self) -> Arc<dyn HttpClient> {
13635 self.http_client.clone()
13636 }
13637
13638 fn worktree_id(&self) -> WorktreeId {
13639 self.worktree.id()
13640 }
13641
13642 fn worktree_root_path(&self) -> &Path {
13643 self.worktree.abs_path().as_ref()
13644 }
13645
13646 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13647 self.worktree.resolve_executable_path(path)
13648 }
13649
13650 async fn shell_env(&self) -> HashMap<String, String> {
13651 let task = self.load_shell_env_task.clone();
13652 task.await.unwrap_or_default()
13653 }
13654
13655 async fn npm_package_installed_version(
13656 &self,
13657 package_name: &str,
13658 ) -> Result<Option<(PathBuf, String)>> {
13659 let local_package_directory = self.worktree_root_path();
13660 let node_modules_directory = local_package_directory.join("node_modules");
13661
13662 if let Some(version) =
13663 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13664 {
13665 return Ok(Some((node_modules_directory, version)));
13666 }
13667 let Some(npm) = self.which("npm".as_ref()).await else {
13668 log::warn!(
13669 "Failed to find npm executable for {:?}",
13670 local_package_directory
13671 );
13672 return Ok(None);
13673 };
13674
13675 let env = self.shell_env().await;
13676 let output = util::command::new_smol_command(&npm)
13677 .args(["root", "-g"])
13678 .envs(env)
13679 .current_dir(local_package_directory)
13680 .output()
13681 .await?;
13682 let global_node_modules =
13683 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13684
13685 if let Some(version) =
13686 read_package_installed_version(global_node_modules.clone(), package_name).await?
13687 {
13688 return Ok(Some((global_node_modules, version)));
13689 }
13690 return Ok(None);
13691 }
13692
13693 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13694 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13695 if self.fs.is_file(&worktree_abs_path).await {
13696 worktree_abs_path.pop();
13697 }
13698
13699 let env = self.shell_env().await;
13700
13701 let shell_path = env.get("PATH").cloned();
13702
13703 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13704 }
13705
13706 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13707 let mut working_dir = self.worktree_root_path().to_path_buf();
13708 if self.fs.is_file(&working_dir).await {
13709 working_dir.pop();
13710 }
13711 let output = util::command::new_smol_command(&command.path)
13712 .args(command.arguments)
13713 .envs(command.env.clone().unwrap_or_default())
13714 .current_dir(working_dir)
13715 .output()
13716 .await?;
13717
13718 anyhow::ensure!(
13719 output.status.success(),
13720 "{}, stdout: {:?}, stderr: {:?}",
13721 output.status,
13722 String::from_utf8_lossy(&output.stdout),
13723 String::from_utf8_lossy(&output.stderr)
13724 );
13725 Ok(())
13726 }
13727
13728 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13729 self.language_registry
13730 .update_lsp_binary_status(server_name, status);
13731 }
13732
13733 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13734 self.language_registry
13735 .all_lsp_adapters()
13736 .into_iter()
13737 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13738 .collect()
13739 }
13740
13741 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13742 let dir = self.language_registry.language_server_download_dir(name)?;
13743
13744 if !dir.exists() {
13745 smol::fs::create_dir_all(&dir)
13746 .await
13747 .context("failed to create container directory")
13748 .log_err()?;
13749 }
13750
13751 Some(dir)
13752 }
13753
13754 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13755 let entry = self
13756 .worktree
13757 .entry_for_path(path)
13758 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13759 let abs_path = self.worktree.absolutize(&entry.path);
13760 self.fs.load(&abs_path).await
13761 }
13762}
13763
13764async fn populate_labels_for_symbols(
13765 symbols: Vec<CoreSymbol>,
13766 language_registry: &Arc<LanguageRegistry>,
13767 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13768 output: &mut Vec<Symbol>,
13769) {
13770 #[allow(clippy::mutable_key_type)]
13771 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13772
13773 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13774 for symbol in symbols {
13775 let Some(file_name) = symbol.path.file_name() else {
13776 continue;
13777 };
13778 let language = language_registry
13779 .load_language_for_file_path(Path::new(file_name))
13780 .await
13781 .ok()
13782 .or_else(|| {
13783 unknown_paths.insert(file_name.into());
13784 None
13785 });
13786 symbols_by_language
13787 .entry(language)
13788 .or_default()
13789 .push(symbol);
13790 }
13791
13792 for unknown_path in unknown_paths {
13793 log::info!("no language found for symbol in file {unknown_path:?}");
13794 }
13795
13796 let mut label_params = Vec::new();
13797 for (language, mut symbols) in symbols_by_language {
13798 label_params.clear();
13799 label_params.extend(
13800 symbols
13801 .iter_mut()
13802 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13803 );
13804
13805 let mut labels = Vec::new();
13806 if let Some(language) = language {
13807 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13808 language_registry
13809 .lsp_adapters(&language.name())
13810 .first()
13811 .cloned()
13812 });
13813 if let Some(lsp_adapter) = lsp_adapter {
13814 labels = lsp_adapter
13815 .labels_for_symbols(&label_params, &language)
13816 .await
13817 .log_err()
13818 .unwrap_or_default();
13819 }
13820 }
13821
13822 for ((symbol, (name, _)), label) in symbols
13823 .into_iter()
13824 .zip(label_params.drain(..))
13825 .zip(labels.into_iter().chain(iter::repeat(None)))
13826 {
13827 output.push(Symbol {
13828 language_server_name: symbol.language_server_name,
13829 source_worktree_id: symbol.source_worktree_id,
13830 source_language_server_id: symbol.source_language_server_id,
13831 path: symbol.path,
13832 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13833 name,
13834 kind: symbol.kind,
13835 range: symbol.range,
13836 });
13837 }
13838 }
13839}
13840
13841fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13842 match server.capabilities().text_document_sync.as_ref()? {
13843 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13844 // Server wants didSave but didn't specify includeText.
13845 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13846 // Server doesn't want didSave at all.
13847 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13848 // Server provided SaveOptions.
13849 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13850 Some(save_options.include_text.unwrap_or(false))
13851 }
13852 },
13853 // We do not have any save info. Kind affects didChange only.
13854 lsp::TextDocumentSyncCapability::Kind(_) => None,
13855 }
13856}
13857
13858/// Completion items are displayed in a `UniformList`.
13859/// Usually, those items are single-line strings, but in LSP responses,
13860/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13861/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13862/// 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,
13863/// breaking the completions menu presentation.
13864///
13865/// 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.
13866fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13867 let mut new_text = String::with_capacity(label.text.len());
13868 let mut offset_map = vec![0; label.text.len() + 1];
13869 let mut last_char_was_space = false;
13870 let mut new_idx = 0;
13871 let chars = label.text.char_indices().fuse();
13872 let mut newlines_removed = false;
13873
13874 for (idx, c) in chars {
13875 offset_map[idx] = new_idx;
13876
13877 match c {
13878 '\n' if last_char_was_space => {
13879 newlines_removed = true;
13880 }
13881 '\t' | ' ' if last_char_was_space => {}
13882 '\n' if !last_char_was_space => {
13883 new_text.push(' ');
13884 new_idx += 1;
13885 last_char_was_space = true;
13886 newlines_removed = true;
13887 }
13888 ' ' | '\t' => {
13889 new_text.push(' ');
13890 new_idx += 1;
13891 last_char_was_space = true;
13892 }
13893 _ => {
13894 new_text.push(c);
13895 new_idx += c.len_utf8();
13896 last_char_was_space = false;
13897 }
13898 }
13899 }
13900 offset_map[label.text.len()] = new_idx;
13901
13902 // Only modify the label if newlines were removed.
13903 if !newlines_removed {
13904 return;
13905 }
13906
13907 let last_index = new_idx;
13908 let mut run_ranges_errors = Vec::new();
13909 label.runs.retain_mut(|(range, _)| {
13910 match offset_map.get(range.start) {
13911 Some(&start) => range.start = start,
13912 None => {
13913 run_ranges_errors.push(range.clone());
13914 return false;
13915 }
13916 }
13917
13918 match offset_map.get(range.end) {
13919 Some(&end) => range.end = end,
13920 None => {
13921 run_ranges_errors.push(range.clone());
13922 range.end = last_index;
13923 }
13924 }
13925 true
13926 });
13927 if !run_ranges_errors.is_empty() {
13928 log::error!(
13929 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13930 label.text
13931 );
13932 }
13933
13934 let mut wrong_filter_range = None;
13935 if label.filter_range == (0..label.text.len()) {
13936 label.filter_range = 0..new_text.len();
13937 } else {
13938 let mut original_filter_range = Some(label.filter_range.clone());
13939 match offset_map.get(label.filter_range.start) {
13940 Some(&start) => label.filter_range.start = start,
13941 None => {
13942 wrong_filter_range = original_filter_range.take();
13943 label.filter_range.start = last_index;
13944 }
13945 }
13946
13947 match offset_map.get(label.filter_range.end) {
13948 Some(&end) => label.filter_range.end = end,
13949 None => {
13950 wrong_filter_range = original_filter_range.take();
13951 label.filter_range.end = last_index;
13952 }
13953 }
13954 }
13955 if let Some(wrong_filter_range) = wrong_filter_range {
13956 log::error!(
13957 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13958 label.text
13959 );
13960 }
13961
13962 label.text = new_text;
13963}
13964
13965#[cfg(test)]
13966mod tests {
13967 use language::HighlightId;
13968
13969 use super::*;
13970
13971 #[test]
13972 fn test_glob_literal_prefix() {
13973 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13974 assert_eq!(
13975 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13976 Path::new("node_modules")
13977 );
13978 assert_eq!(
13979 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13980 Path::new("foo")
13981 );
13982 assert_eq!(
13983 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13984 Path::new("foo/bar/baz.js")
13985 );
13986
13987 #[cfg(target_os = "windows")]
13988 {
13989 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13990 assert_eq!(
13991 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13992 Path::new("node_modules")
13993 );
13994 assert_eq!(
13995 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13996 Path::new("foo")
13997 );
13998 assert_eq!(
13999 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14000 Path::new("foo/bar/baz.js")
14001 );
14002 }
14003 }
14004
14005 #[test]
14006 fn test_multi_len_chars_normalization() {
14007 let mut label = CodeLabel::new(
14008 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14009 0..6,
14010 vec![(0..6, HighlightId(1))],
14011 );
14012 ensure_uniform_list_compatible_label(&mut label);
14013 assert_eq!(
14014 label,
14015 CodeLabel::new(
14016 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14017 0..6,
14018 vec![(0..6, HighlightId(1))],
14019 )
14020 );
14021 }
14022}