1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default, Debug)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = &settings.binary
567 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
568 {
569 let settings = settings.clone();
570
571 return cx.background_spawn(async move {
572 let mut env = delegate.shell_env().await;
573 env.extend(settings.env.unwrap_or_default());
574
575 Ok(LanguageServerBinary {
576 path: delegate.resolve_executable_path(path),
577 env: Some(env),
578 arguments: settings
579 .arguments
580 .unwrap_or_default()
581 .iter()
582 .map(Into::into)
583 .collect(),
584 })
585 });
586 }
587 let lsp_binary_options = LanguageServerBinaryOptions {
588 allow_path_lookup: !settings
589 .binary
590 .as_ref()
591 .and_then(|b| b.ignore_system_version)
592 .unwrap_or_default(),
593 allow_binary_download,
594 pre_release: settings
595 .fetch
596 .as_ref()
597 .and_then(|f| f.pre_release)
598 .unwrap_or(false),
599 };
600
601 cx.spawn(async move |cx| {
602 let binary_result = adapter
603 .clone()
604 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
605 .await;
606
607 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
608
609 let mut binary = binary_result?;
610 let mut shell_env = delegate.shell_env().await;
611
612 shell_env.extend(binary.env.unwrap_or_default());
613
614 if let Some(settings) = settings.binary.as_ref() {
615 if let Some(arguments) = &settings.arguments {
616 binary.arguments = arguments.iter().map(Into::into).collect();
617 }
618 if let Some(env) = &settings.env {
619 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
620 }
621 }
622
623 binary.env = Some(shell_env);
624 Ok(binary)
625 })
626 }
627
628 fn setup_lsp_messages(
629 lsp_store: WeakEntity<LspStore>,
630 language_server: &LanguageServer,
631 delegate: Arc<dyn LspAdapterDelegate>,
632 adapter: Arc<CachedLspAdapter>,
633 ) {
634 let name = language_server.name();
635 let server_id = language_server.server_id();
636 language_server
637 .on_notification::<lsp::notification::PublishDiagnostics, _>({
638 let adapter = adapter.clone();
639 let this = lsp_store.clone();
640 move |mut params, cx| {
641 let adapter = adapter.clone();
642 if let Some(this) = this.upgrade() {
643 this.update(cx, |this, cx| {
644 {
645 let buffer = params
646 .uri
647 .to_file_path()
648 .map(|file_path| this.get_buffer(&file_path, cx))
649 .ok()
650 .flatten();
651 adapter.process_diagnostics(&mut params, server_id, buffer);
652 }
653
654 this.merge_lsp_diagnostics(
655 DiagnosticSourceKind::Pushed,
656 vec![DocumentDiagnosticsUpdate {
657 server_id,
658 diagnostics: params,
659 result_id: None,
660 disk_based_sources: Cow::Borrowed(
661 &adapter.disk_based_diagnostic_sources,
662 ),
663 }],
664 |_, diagnostic, cx| match diagnostic.source_kind {
665 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
666 adapter.retain_old_diagnostic(diagnostic, cx)
667 }
668 DiagnosticSourceKind::Pulled => true,
669 },
670 cx,
671 )
672 .log_err();
673 })
674 .ok();
675 }
676 }
677 })
678 .detach();
679 language_server
680 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
681 let adapter = adapter.adapter.clone();
682 let delegate = delegate.clone();
683 let this = lsp_store.clone();
684 move |params, cx| {
685 let adapter = adapter.clone();
686 let delegate = delegate.clone();
687 let this = this.clone();
688 let mut cx = cx.clone();
689 async move {
690 let toolchain_for_id = this
691 .update(&mut cx, |this, _| {
692 this.as_local()?.language_server_ids.iter().find_map(
693 |(seed, value)| {
694 (value.id == server_id).then(|| seed.toolchain.clone())
695 },
696 )
697 })?
698 .context("Expected the LSP store to be in a local mode")?;
699 let workspace_config = Self::workspace_configuration_for_adapter(
700 adapter.clone(),
701 &delegate,
702 toolchain_for_id,
703 &mut cx,
704 )
705 .await?;
706
707 Ok(params
708 .items
709 .into_iter()
710 .map(|item| {
711 if let Some(section) = &item.section {
712 workspace_config
713 .get(section)
714 .cloned()
715 .unwrap_or(serde_json::Value::Null)
716 } else {
717 workspace_config.clone()
718 }
719 })
720 .collect())
721 }
722 }
723 })
724 .detach();
725
726 language_server
727 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
728 let this = lsp_store.clone();
729 move |_, cx| {
730 let this = this.clone();
731 let cx = cx.clone();
732 async move {
733 let Some(server) =
734 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
735 else {
736 return Ok(None);
737 };
738 let root = server.workspace_folders();
739 Ok(Some(
740 root.into_iter()
741 .map(|uri| WorkspaceFolder {
742 uri,
743 name: Default::default(),
744 })
745 .collect(),
746 ))
747 }
748 }
749 })
750 .detach();
751 // Even though we don't have handling for these requests, respond to them to
752 // avoid stalling any language server like `gopls` which waits for a response
753 // to these requests when initializing.
754 language_server
755 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
756 let this = lsp_store.clone();
757 move |params, cx| {
758 let this = this.clone();
759 let mut cx = cx.clone();
760 async move {
761 this.update(&mut cx, |this, _| {
762 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
763 {
764 status
765 .progress_tokens
766 .insert(ProgressToken::from_lsp(params.token));
767 }
768 })?;
769
770 Ok(())
771 }
772 }
773 })
774 .detach();
775
776 language_server
777 .on_request::<lsp::request::RegisterCapability, _, _>({
778 let lsp_store = lsp_store.clone();
779 move |params, cx| {
780 let lsp_store = lsp_store.clone();
781 let mut cx = cx.clone();
782 async move {
783 lsp_store
784 .update(&mut cx, |lsp_store, cx| {
785 if lsp_store.as_local().is_some() {
786 match lsp_store
787 .register_server_capabilities(server_id, params, cx)
788 {
789 Ok(()) => {}
790 Err(e) => {
791 log::error!(
792 "Failed to register server capabilities: {e:#}"
793 );
794 }
795 };
796 }
797 })
798 .ok();
799 Ok(())
800 }
801 }
802 })
803 .detach();
804
805 language_server
806 .on_request::<lsp::request::UnregisterCapability, _, _>({
807 let lsp_store = lsp_store.clone();
808 move |params, cx| {
809 let lsp_store = lsp_store.clone();
810 let mut cx = cx.clone();
811 async move {
812 lsp_store
813 .update(&mut cx, |lsp_store, cx| {
814 if lsp_store.as_local().is_some() {
815 match lsp_store
816 .unregister_server_capabilities(server_id, params, cx)
817 {
818 Ok(()) => {}
819 Err(e) => {
820 log::error!(
821 "Failed to unregister server capabilities: {e:#}"
822 );
823 }
824 }
825 }
826 })
827 .ok();
828 Ok(())
829 }
830 }
831 })
832 .detach();
833
834 language_server
835 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
836 let this = lsp_store.clone();
837 move |params, cx| {
838 let mut cx = cx.clone();
839 let this = this.clone();
840 async move {
841 LocalLspStore::on_lsp_workspace_edit(
842 this.clone(),
843 params,
844 server_id,
845 &mut cx,
846 )
847 .await
848 }
849 }
850 })
851 .detach();
852
853 language_server
854 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
855 let lsp_store = lsp_store.clone();
856 let request_id = Arc::new(AtomicUsize::new(0));
857 move |(), cx| {
858 let lsp_store = lsp_store.clone();
859 let request_id = request_id.clone();
860 let mut cx = cx.clone();
861 async move {
862 lsp_store
863 .update(&mut cx, |lsp_store, cx| {
864 let request_id =
865 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
866 cx.emit(LspStoreEvent::RefreshInlayHints {
867 server_id,
868 request_id,
869 });
870 lsp_store
871 .downstream_client
872 .as_ref()
873 .map(|(client, project_id)| {
874 client.send(proto::RefreshInlayHints {
875 project_id: *project_id,
876 server_id: server_id.to_proto(),
877 request_id: request_id.map(|id| id as u64),
878 })
879 })
880 })?
881 .transpose()?;
882 Ok(())
883 }
884 }
885 })
886 .detach();
887
888 language_server
889 .on_request::<lsp::request::CodeLensRefresh, _, _>({
890 let this = lsp_store.clone();
891 move |(), cx| {
892 let this = this.clone();
893 let mut cx = cx.clone();
894 async move {
895 this.update(&mut cx, |this, cx| {
896 cx.emit(LspStoreEvent::RefreshCodeLens);
897 this.downstream_client.as_ref().map(|(client, project_id)| {
898 client.send(proto::RefreshCodeLens {
899 project_id: *project_id,
900 })
901 })
902 })?
903 .transpose()?;
904 Ok(())
905 }
906 }
907 })
908 .detach();
909
910 language_server
911 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
912 let this = lsp_store.clone();
913 move |(), cx| {
914 let this = this.clone();
915 let mut cx = cx.clone();
916 async move {
917 this.update(&mut cx, |lsp_store, _| {
918 lsp_store.pull_workspace_diagnostics(server_id);
919 lsp_store
920 .downstream_client
921 .as_ref()
922 .map(|(client, project_id)| {
923 client.send(proto::PullWorkspaceDiagnostics {
924 project_id: *project_id,
925 server_id: server_id.to_proto(),
926 })
927 })
928 })?
929 .transpose()?;
930 Ok(())
931 }
932 }
933 })
934 .detach();
935
936 language_server
937 .on_request::<lsp::request::ShowMessageRequest, _, _>({
938 let this = lsp_store.clone();
939 let name = name.to_string();
940 move |params, cx| {
941 let this = this.clone();
942 let name = name.to_string();
943 let mut cx = cx.clone();
944 async move {
945 let actions = params.actions.unwrap_or_default();
946 let (tx, rx) = smol::channel::bounded(1);
947 let request = LanguageServerPromptRequest {
948 level: match params.typ {
949 lsp::MessageType::ERROR => PromptLevel::Critical,
950 lsp::MessageType::WARNING => PromptLevel::Warning,
951 _ => PromptLevel::Info,
952 },
953 message: params.message,
954 actions,
955 response_channel: tx,
956 lsp_name: name.clone(),
957 };
958
959 let did_update = this
960 .update(&mut cx, |_, cx| {
961 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
962 })
963 .is_ok();
964 if did_update {
965 let response = rx.recv().await.ok();
966 Ok(response)
967 } else {
968 Ok(None)
969 }
970 }
971 }
972 })
973 .detach();
974 language_server
975 .on_notification::<lsp::notification::ShowMessage, _>({
976 let this = lsp_store.clone();
977 let name = name.to_string();
978 move |params, cx| {
979 let this = this.clone();
980 let name = name.to_string();
981 let mut cx = cx.clone();
982
983 let (tx, _) = smol::channel::bounded(1);
984 let request = LanguageServerPromptRequest {
985 level: match params.typ {
986 lsp::MessageType::ERROR => PromptLevel::Critical,
987 lsp::MessageType::WARNING => PromptLevel::Warning,
988 _ => PromptLevel::Info,
989 },
990 message: params.message,
991 actions: vec![],
992 response_channel: tx,
993 lsp_name: name,
994 };
995
996 let _ = this.update(&mut cx, |_, cx| {
997 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
998 });
999 }
1000 })
1001 .detach();
1002
1003 let disk_based_diagnostics_progress_token =
1004 adapter.disk_based_diagnostics_progress_token.clone();
1005
1006 language_server
1007 .on_notification::<lsp::notification::Progress, _>({
1008 let this = lsp_store.clone();
1009 move |params, cx| {
1010 if let Some(this) = this.upgrade() {
1011 this.update(cx, |this, cx| {
1012 this.on_lsp_progress(
1013 params,
1014 server_id,
1015 disk_based_diagnostics_progress_token.clone(),
1016 cx,
1017 );
1018 })
1019 .ok();
1020 }
1021 }
1022 })
1023 .detach();
1024
1025 language_server
1026 .on_notification::<lsp::notification::LogMessage, _>({
1027 let this = lsp_store.clone();
1028 move |params, cx| {
1029 if let Some(this) = this.upgrade() {
1030 this.update(cx, |_, cx| {
1031 cx.emit(LspStoreEvent::LanguageServerLog(
1032 server_id,
1033 LanguageServerLogType::Log(params.typ),
1034 params.message,
1035 ));
1036 })
1037 .ok();
1038 }
1039 }
1040 })
1041 .detach();
1042
1043 language_server
1044 .on_notification::<lsp::notification::LogTrace, _>({
1045 let this = lsp_store.clone();
1046 move |params, cx| {
1047 let mut cx = cx.clone();
1048 if let Some(this) = this.upgrade() {
1049 this.update(&mut cx, |_, cx| {
1050 cx.emit(LspStoreEvent::LanguageServerLog(
1051 server_id,
1052 LanguageServerLogType::Trace {
1053 verbose_info: params.verbose,
1054 },
1055 params.message,
1056 ));
1057 })
1058 .ok();
1059 }
1060 }
1061 })
1062 .detach();
1063
1064 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1065 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1066 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1067 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1068 }
1069
1070 fn shutdown_language_servers_on_quit(
1071 &mut self,
1072 _: &mut Context<LspStore>,
1073 ) -> impl Future<Output = ()> + use<> {
1074 let shutdown_futures = self
1075 .language_servers
1076 .drain()
1077 .map(|(_, server_state)| Self::shutdown_server(server_state))
1078 .collect::<Vec<_>>();
1079
1080 async move {
1081 join_all(shutdown_futures).await;
1082 }
1083 }
1084
1085 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1086 match server_state {
1087 LanguageServerState::Running { server, .. } => {
1088 if let Some(shutdown) = server.shutdown() {
1089 shutdown.await;
1090 }
1091 }
1092 LanguageServerState::Starting { startup, .. } => {
1093 if let Some(server) = startup.await
1094 && let Some(shutdown) = server.shutdown()
1095 {
1096 shutdown.await;
1097 }
1098 }
1099 }
1100 Ok(())
1101 }
1102
1103 fn language_servers_for_worktree(
1104 &self,
1105 worktree_id: WorktreeId,
1106 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1107 self.language_server_ids
1108 .iter()
1109 .filter_map(move |(seed, state)| {
1110 if seed.worktree_id != worktree_id {
1111 return None;
1112 }
1113
1114 if let Some(LanguageServerState::Running { server, .. }) =
1115 self.language_servers.get(&state.id)
1116 {
1117 Some(server)
1118 } else {
1119 None
1120 }
1121 })
1122 }
1123
1124 fn language_server_ids_for_project_path(
1125 &self,
1126 project_path: ProjectPath,
1127 language: &Language,
1128 cx: &mut App,
1129 ) -> Vec<LanguageServerId> {
1130 let Some(worktree) = self
1131 .worktree_store
1132 .read(cx)
1133 .worktree_for_id(project_path.worktree_id, cx)
1134 else {
1135 return Vec::new();
1136 };
1137 let delegate: Arc<dyn ManifestDelegate> =
1138 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1139
1140 self.lsp_tree
1141 .get(
1142 project_path,
1143 language.name(),
1144 language.manifest(),
1145 &delegate,
1146 cx,
1147 )
1148 .collect::<Vec<_>>()
1149 }
1150
1151 fn language_server_ids_for_buffer(
1152 &self,
1153 buffer: &Buffer,
1154 cx: &mut App,
1155 ) -> Vec<LanguageServerId> {
1156 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1157 let worktree_id = file.worktree_id(cx);
1158
1159 let path: Arc<RelPath> = file
1160 .path()
1161 .parent()
1162 .map(Arc::from)
1163 .unwrap_or_else(|| file.path().clone());
1164 let worktree_path = ProjectPath { worktree_id, path };
1165 self.language_server_ids_for_project_path(worktree_path, language, cx)
1166 } else {
1167 Vec::new()
1168 }
1169 }
1170
1171 fn language_servers_for_buffer<'a>(
1172 &'a self,
1173 buffer: &'a Buffer,
1174 cx: &'a mut App,
1175 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1176 self.language_server_ids_for_buffer(buffer, cx)
1177 .into_iter()
1178 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1179 LanguageServerState::Running {
1180 adapter, server, ..
1181 } => Some((adapter, server)),
1182 _ => None,
1183 })
1184 }
1185
1186 async fn execute_code_action_kind_locally(
1187 lsp_store: WeakEntity<LspStore>,
1188 mut buffers: Vec<Entity<Buffer>>,
1189 kind: CodeActionKind,
1190 push_to_history: bool,
1191 cx: &mut AsyncApp,
1192 ) -> anyhow::Result<ProjectTransaction> {
1193 // Do not allow multiple concurrent code actions requests for the
1194 // same buffer.
1195 lsp_store.update(cx, |this, cx| {
1196 let this = this.as_local_mut().unwrap();
1197 buffers.retain(|buffer| {
1198 this.buffers_being_formatted
1199 .insert(buffer.read(cx).remote_id())
1200 });
1201 })?;
1202 let _cleanup = defer({
1203 let this = lsp_store.clone();
1204 let mut cx = cx.clone();
1205 let buffers = &buffers;
1206 move || {
1207 this.update(&mut cx, |this, cx| {
1208 let this = this.as_local_mut().unwrap();
1209 for buffer in buffers {
1210 this.buffers_being_formatted
1211 .remove(&buffer.read(cx).remote_id());
1212 }
1213 })
1214 .ok();
1215 }
1216 });
1217 let mut project_transaction = ProjectTransaction::default();
1218
1219 for buffer in &buffers {
1220 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1221 buffer.update(cx, |buffer, cx| {
1222 lsp_store
1223 .as_local()
1224 .unwrap()
1225 .language_servers_for_buffer(buffer, cx)
1226 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1227 .collect::<Vec<_>>()
1228 })
1229 })?;
1230 for (_, language_server) in adapters_and_servers.iter() {
1231 let actions = Self::get_server_code_actions_from_action_kinds(
1232 &lsp_store,
1233 language_server.server_id(),
1234 vec![kind.clone()],
1235 buffer,
1236 cx,
1237 )
1238 .await?;
1239 Self::execute_code_actions_on_server(
1240 &lsp_store,
1241 language_server,
1242 actions,
1243 push_to_history,
1244 &mut project_transaction,
1245 cx,
1246 )
1247 .await?;
1248 }
1249 }
1250 Ok(project_transaction)
1251 }
1252
1253 async fn format_locally(
1254 lsp_store: WeakEntity<LspStore>,
1255 mut buffers: Vec<FormattableBuffer>,
1256 push_to_history: bool,
1257 trigger: FormatTrigger,
1258 logger: zlog::Logger,
1259 cx: &mut AsyncApp,
1260 ) -> anyhow::Result<ProjectTransaction> {
1261 // Do not allow multiple concurrent formatting requests for the
1262 // same buffer.
1263 lsp_store.update(cx, |this, cx| {
1264 let this = this.as_local_mut().unwrap();
1265 buffers.retain(|buffer| {
1266 this.buffers_being_formatted
1267 .insert(buffer.handle.read(cx).remote_id())
1268 });
1269 })?;
1270
1271 let _cleanup = defer({
1272 let this = lsp_store.clone();
1273 let mut cx = cx.clone();
1274 let buffers = &buffers;
1275 move || {
1276 this.update(&mut cx, |this, cx| {
1277 let this = this.as_local_mut().unwrap();
1278 for buffer in buffers {
1279 this.buffers_being_formatted
1280 .remove(&buffer.handle.read(cx).remote_id());
1281 }
1282 })
1283 .ok();
1284 }
1285 });
1286
1287 let mut project_transaction = ProjectTransaction::default();
1288
1289 for buffer in &buffers {
1290 zlog::debug!(
1291 logger =>
1292 "formatting buffer '{:?}'",
1293 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1294 );
1295 // Create an empty transaction to hold all of the formatting edits.
1296 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1297 // ensure no transactions created while formatting are
1298 // grouped with the previous transaction in the history
1299 // based on the transaction group interval
1300 buffer.finalize_last_transaction();
1301 buffer
1302 .start_transaction()
1303 .context("transaction already open")?;
1304 buffer.end_transaction(cx);
1305 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1306 buffer.finalize_last_transaction();
1307 anyhow::Ok(transaction_id)
1308 })??;
1309
1310 let result = Self::format_buffer_locally(
1311 lsp_store.clone(),
1312 buffer,
1313 formatting_transaction_id,
1314 trigger,
1315 logger,
1316 cx,
1317 )
1318 .await;
1319
1320 buffer.handle.update(cx, |buffer, cx| {
1321 let Some(formatting_transaction) =
1322 buffer.get_transaction(formatting_transaction_id).cloned()
1323 else {
1324 zlog::warn!(logger => "no formatting transaction");
1325 return;
1326 };
1327 if formatting_transaction.edit_ids.is_empty() {
1328 zlog::debug!(logger => "no changes made while formatting");
1329 buffer.forget_transaction(formatting_transaction_id);
1330 return;
1331 }
1332 if !push_to_history {
1333 zlog::trace!(logger => "forgetting format transaction");
1334 buffer.forget_transaction(formatting_transaction.id);
1335 }
1336 project_transaction
1337 .0
1338 .insert(cx.entity(), formatting_transaction);
1339 })?;
1340
1341 result?;
1342 }
1343
1344 Ok(project_transaction)
1345 }
1346
1347 async fn format_buffer_locally(
1348 lsp_store: WeakEntity<LspStore>,
1349 buffer: &FormattableBuffer,
1350 formatting_transaction_id: clock::Lamport,
1351 trigger: FormatTrigger,
1352 logger: zlog::Logger,
1353 cx: &mut AsyncApp,
1354 ) -> Result<()> {
1355 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1356 buffer.handle.update(cx, |buffer, cx| {
1357 let adapters_and_servers = lsp_store
1358 .as_local()
1359 .unwrap()
1360 .language_servers_for_buffer(buffer, cx)
1361 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1362 .collect::<Vec<_>>();
1363 let settings =
1364 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1365 .into_owned();
1366 (adapters_and_servers, settings)
1367 })
1368 })?;
1369
1370 /// Apply edits to the buffer that will become part of the formatting transaction.
1371 /// Fails if the buffer has been edited since the start of that transaction.
1372 fn extend_formatting_transaction(
1373 buffer: &FormattableBuffer,
1374 formatting_transaction_id: text::TransactionId,
1375 cx: &mut AsyncApp,
1376 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1377 ) -> anyhow::Result<()> {
1378 buffer.handle.update(cx, |buffer, cx| {
1379 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1380 if last_transaction_id != Some(formatting_transaction_id) {
1381 anyhow::bail!("Buffer edited while formatting. Aborting")
1382 }
1383 buffer.start_transaction();
1384 operation(buffer, cx);
1385 if let Some(transaction_id) = buffer.end_transaction(cx) {
1386 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1387 }
1388 Ok(())
1389 })?
1390 }
1391
1392 // handle whitespace formatting
1393 if settings.remove_trailing_whitespace_on_save {
1394 zlog::trace!(logger => "removing trailing whitespace");
1395 let diff = buffer
1396 .handle
1397 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1398 .await;
1399 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1400 buffer.apply_diff(diff, cx);
1401 })?;
1402 }
1403
1404 if settings.ensure_final_newline_on_save {
1405 zlog::trace!(logger => "ensuring final newline");
1406 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1407 buffer.ensure_final_newline(cx);
1408 })?;
1409 }
1410
1411 // Formatter for `code_actions_on_format` that runs before
1412 // the rest of the formatters
1413 let mut code_actions_on_format_formatters = None;
1414 let should_run_code_actions_on_format = !matches!(
1415 (trigger, &settings.format_on_save),
1416 (FormatTrigger::Save, &FormatOnSave::Off)
1417 );
1418 if should_run_code_actions_on_format {
1419 let have_code_actions_to_run_on_format = settings
1420 .code_actions_on_format
1421 .values()
1422 .any(|enabled| *enabled);
1423 if have_code_actions_to_run_on_format {
1424 zlog::trace!(logger => "going to run code actions on format");
1425 code_actions_on_format_formatters = Some(
1426 settings
1427 .code_actions_on_format
1428 .iter()
1429 .filter_map(|(action, enabled)| enabled.then_some(action))
1430 .cloned()
1431 .map(Formatter::CodeAction)
1432 .collect::<Vec<_>>(),
1433 );
1434 }
1435 }
1436
1437 let formatters = match (trigger, &settings.format_on_save) {
1438 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1439 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1440 settings.formatter.as_ref()
1441 }
1442 };
1443
1444 let formatters = code_actions_on_format_formatters
1445 .iter()
1446 .flatten()
1447 .chain(formatters);
1448
1449 for formatter in formatters {
1450 let formatter = if formatter == &Formatter::Auto {
1451 if settings.prettier.allowed {
1452 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1453 &Formatter::Prettier
1454 } else {
1455 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1456 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1457 }
1458 } else {
1459 formatter
1460 };
1461 match formatter {
1462 Formatter::Auto => unreachable!("Auto resolved above"),
1463 Formatter::Prettier => {
1464 let logger = zlog::scoped!(logger => "prettier");
1465 zlog::trace!(logger => "formatting");
1466 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1467
1468 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1469 lsp_store.prettier_store().unwrap().downgrade()
1470 })?;
1471 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1472 .await
1473 .transpose()?;
1474 let Some(diff) = diff else {
1475 zlog::trace!(logger => "No changes");
1476 continue;
1477 };
1478
1479 extend_formatting_transaction(
1480 buffer,
1481 formatting_transaction_id,
1482 cx,
1483 |buffer, cx| {
1484 buffer.apply_diff(diff, cx);
1485 },
1486 )?;
1487 }
1488 Formatter::External { command, arguments } => {
1489 let logger = zlog::scoped!(logger => "command");
1490 zlog::trace!(logger => "formatting");
1491 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1492
1493 let diff = Self::format_via_external_command(
1494 buffer,
1495 command.as_ref(),
1496 arguments.as_deref(),
1497 cx,
1498 )
1499 .await
1500 .with_context(|| {
1501 format!("Failed to format buffer via external command: {}", command)
1502 })?;
1503 let Some(diff) = diff else {
1504 zlog::trace!(logger => "No changes");
1505 continue;
1506 };
1507
1508 extend_formatting_transaction(
1509 buffer,
1510 formatting_transaction_id,
1511 cx,
1512 |buffer, cx| {
1513 buffer.apply_diff(diff, cx);
1514 },
1515 )?;
1516 }
1517 Formatter::LanguageServer(specifier) => {
1518 let logger = zlog::scoped!(logger => "language-server");
1519 zlog::trace!(logger => "formatting");
1520 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1521
1522 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1523 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1524 continue;
1525 };
1526
1527 let language_server = match specifier {
1528 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1529 adapters_and_servers.iter().find_map(|(adapter, server)| {
1530 if adapter.name.0.as_ref() == name {
1531 Some(server.clone())
1532 } else {
1533 None
1534 }
1535 })
1536 }
1537 settings::LanguageServerFormatterSpecifier::Current => {
1538 adapters_and_servers.first().map(|e| e.1.clone())
1539 }
1540 };
1541
1542 let Some(language_server) = language_server else {
1543 log::debug!(
1544 "No language server found to format buffer '{:?}'. Skipping",
1545 buffer_path_abs.as_path().to_string_lossy()
1546 );
1547 continue;
1548 };
1549
1550 zlog::trace!(
1551 logger =>
1552 "Formatting buffer '{:?}' using language server '{:?}'",
1553 buffer_path_abs.as_path().to_string_lossy(),
1554 language_server.name()
1555 );
1556
1557 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1558 zlog::trace!(logger => "formatting ranges");
1559 Self::format_ranges_via_lsp(
1560 &lsp_store,
1561 &buffer.handle,
1562 ranges,
1563 buffer_path_abs,
1564 &language_server,
1565 &settings,
1566 cx,
1567 )
1568 .await
1569 .context("Failed to format ranges via language server")?
1570 } else {
1571 zlog::trace!(logger => "formatting full");
1572 Self::format_via_lsp(
1573 &lsp_store,
1574 &buffer.handle,
1575 buffer_path_abs,
1576 &language_server,
1577 &settings,
1578 cx,
1579 )
1580 .await
1581 .context("failed to format via language server")?
1582 };
1583
1584 if edits.is_empty() {
1585 zlog::trace!(logger => "No changes");
1586 continue;
1587 }
1588 extend_formatting_transaction(
1589 buffer,
1590 formatting_transaction_id,
1591 cx,
1592 |buffer, cx| {
1593 buffer.edit(edits, None, cx);
1594 },
1595 )?;
1596 }
1597 Formatter::CodeAction(code_action_name) => {
1598 let logger = zlog::scoped!(logger => "code-actions");
1599 zlog::trace!(logger => "formatting");
1600 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1601
1602 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1603 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1604 continue;
1605 };
1606
1607 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1608 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1609
1610 let mut actions_and_servers = Vec::new();
1611
1612 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1613 let actions_result = Self::get_server_code_actions_from_action_kinds(
1614 &lsp_store,
1615 language_server.server_id(),
1616 vec![code_action_kind.clone()],
1617 &buffer.handle,
1618 cx,
1619 )
1620 .await
1621 .with_context(|| {
1622 format!(
1623 "Failed to resolve code action {:?} with language server {}",
1624 code_action_kind,
1625 language_server.name()
1626 )
1627 });
1628 let Ok(actions) = actions_result else {
1629 // note: it may be better to set result to the error and break formatters here
1630 // but for now we try to execute the actions that we can resolve and skip the rest
1631 zlog::error!(
1632 logger =>
1633 "Failed to resolve code action {:?} with language server {}",
1634 code_action_kind,
1635 language_server.name()
1636 );
1637 continue;
1638 };
1639 for action in actions {
1640 actions_and_servers.push((action, index));
1641 }
1642 }
1643
1644 if actions_and_servers.is_empty() {
1645 zlog::warn!(logger => "No code actions were resolved, continuing");
1646 continue;
1647 }
1648
1649 'actions: for (mut action, server_index) in actions_and_servers {
1650 let server = &adapters_and_servers[server_index].1;
1651
1652 let describe_code_action = |action: &CodeAction| {
1653 format!(
1654 "code action '{}' with title \"{}\" on server {}",
1655 action
1656 .lsp_action
1657 .action_kind()
1658 .unwrap_or("unknown".into())
1659 .as_str(),
1660 action.lsp_action.title(),
1661 server.name(),
1662 )
1663 };
1664
1665 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1666
1667 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1668 zlog::error!(
1669 logger =>
1670 "Failed to resolve {}. Error: {}",
1671 describe_code_action(&action),
1672 err
1673 );
1674 continue;
1675 }
1676
1677 if let Some(edit) = action.lsp_action.edit().cloned() {
1678 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1679 // but filters out and logs warnings for code actions that require unreasonably
1680 // difficult handling on our part, such as:
1681 // - applying edits that call commands
1682 // which can result in arbitrary workspace edits being sent from the server that
1683 // have no way of being tied back to the command that initiated them (i.e. we
1684 // can't know which edits are part of the format request, or if the server is done sending
1685 // actions in response to the command)
1686 // - actions that create/delete/modify/rename files other than the one we are formatting
1687 // as we then would need to handle such changes correctly in the local history as well
1688 // as the remote history through the ProjectTransaction
1689 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1690 // Supporting these actions is not impossible, but not supported as of yet.
1691 if edit.changes.is_none() && edit.document_changes.is_none() {
1692 zlog::trace!(
1693 logger =>
1694 "No changes for code action. Skipping {}",
1695 describe_code_action(&action),
1696 );
1697 continue;
1698 }
1699
1700 let mut operations = Vec::new();
1701 if let Some(document_changes) = edit.document_changes {
1702 match document_changes {
1703 lsp::DocumentChanges::Edits(edits) => operations.extend(
1704 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1705 ),
1706 lsp::DocumentChanges::Operations(ops) => operations = ops,
1707 }
1708 } else if let Some(changes) = edit.changes {
1709 operations.extend(changes.into_iter().map(|(uri, edits)| {
1710 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1711 text_document:
1712 lsp::OptionalVersionedTextDocumentIdentifier {
1713 uri,
1714 version: None,
1715 },
1716 edits: edits.into_iter().map(Edit::Plain).collect(),
1717 })
1718 }));
1719 }
1720
1721 let mut edits = Vec::with_capacity(operations.len());
1722
1723 if operations.is_empty() {
1724 zlog::trace!(
1725 logger =>
1726 "No changes for code action. Skipping {}",
1727 describe_code_action(&action),
1728 );
1729 continue;
1730 }
1731 for operation in operations {
1732 let op = match operation {
1733 lsp::DocumentChangeOperation::Edit(op) => op,
1734 lsp::DocumentChangeOperation::Op(_) => {
1735 zlog::warn!(
1736 logger =>
1737 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1738 describe_code_action(&action),
1739 );
1740 continue 'actions;
1741 }
1742 };
1743 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1744 zlog::warn!(
1745 logger =>
1746 "Failed to convert URI '{:?}' to file path. Skipping {}",
1747 &op.text_document.uri,
1748 describe_code_action(&action),
1749 );
1750 continue 'actions;
1751 };
1752 if &file_path != buffer_path_abs {
1753 zlog::warn!(
1754 logger =>
1755 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1756 file_path,
1757 buffer_path_abs,
1758 describe_code_action(&action),
1759 );
1760 continue 'actions;
1761 }
1762
1763 let mut lsp_edits = Vec::new();
1764 for edit in op.edits {
1765 match edit {
1766 Edit::Plain(edit) => {
1767 if !lsp_edits.contains(&edit) {
1768 lsp_edits.push(edit);
1769 }
1770 }
1771 Edit::Annotated(edit) => {
1772 if !lsp_edits.contains(&edit.text_edit) {
1773 lsp_edits.push(edit.text_edit);
1774 }
1775 }
1776 Edit::Snippet(_) => {
1777 zlog::warn!(
1778 logger =>
1779 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1780 describe_code_action(&action),
1781 );
1782 continue 'actions;
1783 }
1784 }
1785 }
1786 let edits_result = lsp_store
1787 .update(cx, |lsp_store, cx| {
1788 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1789 &buffer.handle,
1790 lsp_edits,
1791 server.server_id(),
1792 op.text_document.version,
1793 cx,
1794 )
1795 })?
1796 .await;
1797 let Ok(resolved_edits) = edits_result else {
1798 zlog::warn!(
1799 logger =>
1800 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1801 buffer_path_abs.as_path(),
1802 describe_code_action(&action),
1803 );
1804 continue 'actions;
1805 };
1806 edits.extend(resolved_edits);
1807 }
1808
1809 if edits.is_empty() {
1810 zlog::warn!(logger => "No edits resolved from LSP");
1811 continue;
1812 }
1813
1814 extend_formatting_transaction(
1815 buffer,
1816 formatting_transaction_id,
1817 cx,
1818 |buffer, cx| {
1819 zlog::info!(
1820 "Applying edits {edits:?}. Content: {:?}",
1821 buffer.text()
1822 );
1823 buffer.edit(edits, None, cx);
1824 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1825 },
1826 )?;
1827 }
1828
1829 if let Some(command) = action.lsp_action.command() {
1830 zlog::warn!(
1831 logger =>
1832 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1833 &command.command,
1834 );
1835
1836 // bail early if command is invalid
1837 let server_capabilities = server.capabilities();
1838 let available_commands = server_capabilities
1839 .execute_command_provider
1840 .as_ref()
1841 .map(|options| options.commands.as_slice())
1842 .unwrap_or_default();
1843 if !available_commands.contains(&command.command) {
1844 zlog::warn!(
1845 logger =>
1846 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1847 command.command,
1848 server.name(),
1849 );
1850 continue;
1851 }
1852
1853 // noop so we just ensure buffer hasn't been edited since resolving code actions
1854 extend_formatting_transaction(
1855 buffer,
1856 formatting_transaction_id,
1857 cx,
1858 |_, _| {},
1859 )?;
1860 zlog::info!(logger => "Executing command {}", &command.command);
1861
1862 lsp_store.update(cx, |this, _| {
1863 this.as_local_mut()
1864 .unwrap()
1865 .last_workspace_edits_by_language_server
1866 .remove(&server.server_id());
1867 })?;
1868
1869 let execute_command_result = server
1870 .request::<lsp::request::ExecuteCommand>(
1871 lsp::ExecuteCommandParams {
1872 command: command.command.clone(),
1873 arguments: command.arguments.clone().unwrap_or_default(),
1874 ..Default::default()
1875 },
1876 )
1877 .await
1878 .into_response();
1879
1880 if execute_command_result.is_err() {
1881 zlog::error!(
1882 logger =>
1883 "Failed to execute command '{}' as part of {}",
1884 &command.command,
1885 describe_code_action(&action),
1886 );
1887 continue 'actions;
1888 }
1889
1890 let mut project_transaction_command =
1891 lsp_store.update(cx, |this, _| {
1892 this.as_local_mut()
1893 .unwrap()
1894 .last_workspace_edits_by_language_server
1895 .remove(&server.server_id())
1896 .unwrap_or_default()
1897 })?;
1898
1899 if let Some(transaction) =
1900 project_transaction_command.0.remove(&buffer.handle)
1901 {
1902 zlog::trace!(
1903 logger =>
1904 "Successfully captured {} edits that resulted from command {}",
1905 transaction.edit_ids.len(),
1906 &command.command,
1907 );
1908 let transaction_id_project_transaction = transaction.id;
1909 buffer.handle.update(cx, |buffer, _| {
1910 // it may have been removed from history if push_to_history was
1911 // false in deserialize_workspace_edit. If so push it so we
1912 // can merge it with the format transaction
1913 // and pop the combined transaction off the history stack
1914 // later if push_to_history is false
1915 if buffer.get_transaction(transaction.id).is_none() {
1916 buffer.push_transaction(transaction, Instant::now());
1917 }
1918 buffer.merge_transactions(
1919 transaction_id_project_transaction,
1920 formatting_transaction_id,
1921 );
1922 })?;
1923 }
1924
1925 if !project_transaction_command.0.is_empty() {
1926 let mut extra_buffers = String::new();
1927 for buffer in project_transaction_command.0.keys() {
1928 buffer
1929 .read_with(cx, |b, cx| {
1930 if let Some(path) = b.project_path(cx) {
1931 if !extra_buffers.is_empty() {
1932 extra_buffers.push_str(", ");
1933 }
1934 extra_buffers.push_str(path.path.as_unix_str());
1935 }
1936 })
1937 .ok();
1938 }
1939 zlog::warn!(
1940 logger =>
1941 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1942 &command.command,
1943 extra_buffers,
1944 );
1945 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1946 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1947 // add it so it's included, and merge it into the format transaction when its created later
1948 }
1949 }
1950 }
1951 }
1952 }
1953 }
1954
1955 Ok(())
1956 }
1957
1958 pub async fn format_ranges_via_lsp(
1959 this: &WeakEntity<LspStore>,
1960 buffer_handle: &Entity<Buffer>,
1961 ranges: &[Range<Anchor>],
1962 abs_path: &Path,
1963 language_server: &Arc<LanguageServer>,
1964 settings: &LanguageSettings,
1965 cx: &mut AsyncApp,
1966 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1967 let capabilities = &language_server.capabilities();
1968 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1969 if range_formatting_provider == Some(&OneOf::Left(false)) {
1970 anyhow::bail!(
1971 "{} language server does not support range formatting",
1972 language_server.name()
1973 );
1974 }
1975
1976 let uri = file_path_to_lsp_url(abs_path)?;
1977 let text_document = lsp::TextDocumentIdentifier::new(uri);
1978
1979 let lsp_edits = {
1980 let mut lsp_ranges = Vec::new();
1981 this.update(cx, |_this, cx| {
1982 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1983 // not have been sent to the language server. This seems like a fairly systemic
1984 // issue, though, the resolution probably is not specific to formatting.
1985 //
1986 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1987 // LSP.
1988 let snapshot = buffer_handle.read(cx).snapshot();
1989 for range in ranges {
1990 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1991 }
1992 anyhow::Ok(())
1993 })??;
1994
1995 let mut edits = None;
1996 for range in lsp_ranges {
1997 if let Some(mut edit) = language_server
1998 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1999 text_document: text_document.clone(),
2000 range,
2001 options: lsp_command::lsp_formatting_options(settings),
2002 work_done_progress_params: Default::default(),
2003 })
2004 .await
2005 .into_response()?
2006 {
2007 edits.get_or_insert_with(Vec::new).append(&mut edit);
2008 }
2009 }
2010 edits
2011 };
2012
2013 if let Some(lsp_edits) = lsp_edits {
2014 this.update(cx, |this, cx| {
2015 this.as_local_mut().unwrap().edits_from_lsp(
2016 buffer_handle,
2017 lsp_edits,
2018 language_server.server_id(),
2019 None,
2020 cx,
2021 )
2022 })?
2023 .await
2024 } else {
2025 Ok(Vec::with_capacity(0))
2026 }
2027 }
2028
2029 async fn format_via_lsp(
2030 this: &WeakEntity<LspStore>,
2031 buffer: &Entity<Buffer>,
2032 abs_path: &Path,
2033 language_server: &Arc<LanguageServer>,
2034 settings: &LanguageSettings,
2035 cx: &mut AsyncApp,
2036 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2037 let logger = zlog::scoped!("lsp_format");
2038 zlog::debug!(logger => "Formatting via LSP");
2039
2040 let uri = file_path_to_lsp_url(abs_path)?;
2041 let text_document = lsp::TextDocumentIdentifier::new(uri);
2042 let capabilities = &language_server.capabilities();
2043
2044 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2045 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2046
2047 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2048 let _timer = zlog::time!(logger => "format-full");
2049 language_server
2050 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2051 text_document,
2052 options: lsp_command::lsp_formatting_options(settings),
2053 work_done_progress_params: Default::default(),
2054 })
2055 .await
2056 .into_response()?
2057 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2058 let _timer = zlog::time!(logger => "format-range");
2059 let buffer_start = lsp::Position::new(0, 0);
2060 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2061 language_server
2062 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2063 text_document: text_document.clone(),
2064 range: lsp::Range::new(buffer_start, buffer_end),
2065 options: lsp_command::lsp_formatting_options(settings),
2066 work_done_progress_params: Default::default(),
2067 })
2068 .await
2069 .into_response()?
2070 } else {
2071 None
2072 };
2073
2074 if let Some(lsp_edits) = lsp_edits {
2075 this.update(cx, |this, cx| {
2076 this.as_local_mut().unwrap().edits_from_lsp(
2077 buffer,
2078 lsp_edits,
2079 language_server.server_id(),
2080 None,
2081 cx,
2082 )
2083 })?
2084 .await
2085 } else {
2086 Ok(Vec::with_capacity(0))
2087 }
2088 }
2089
2090 async fn format_via_external_command(
2091 buffer: &FormattableBuffer,
2092 command: &str,
2093 arguments: Option<&[String]>,
2094 cx: &mut AsyncApp,
2095 ) -> Result<Option<Diff>> {
2096 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2097 let file = File::from_dyn(buffer.file())?;
2098 let worktree = file.worktree.read(cx);
2099 let mut worktree_path = worktree.abs_path().to_path_buf();
2100 if worktree.root_entry()?.is_file() {
2101 worktree_path.pop();
2102 }
2103 Some(worktree_path)
2104 })?;
2105
2106 let mut child = util::command::new_smol_command(command);
2107
2108 if let Some(buffer_env) = buffer.env.as_ref() {
2109 child.envs(buffer_env);
2110 }
2111
2112 if let Some(working_dir_path) = working_dir_path {
2113 child.current_dir(working_dir_path);
2114 }
2115
2116 if let Some(arguments) = arguments {
2117 child.args(arguments.iter().map(|arg| {
2118 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2119 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2120 } else {
2121 arg.replace("{buffer_path}", "Untitled")
2122 }
2123 }));
2124 }
2125
2126 let mut child = child
2127 .stdin(smol::process::Stdio::piped())
2128 .stdout(smol::process::Stdio::piped())
2129 .stderr(smol::process::Stdio::piped())
2130 .spawn()?;
2131
2132 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2133 let text = buffer
2134 .handle
2135 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2136 for chunk in text.chunks() {
2137 stdin.write_all(chunk.as_bytes()).await?;
2138 }
2139 stdin.flush().await?;
2140
2141 let output = child.output().await?;
2142 anyhow::ensure!(
2143 output.status.success(),
2144 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2145 output.status.code(),
2146 String::from_utf8_lossy(&output.stdout),
2147 String::from_utf8_lossy(&output.stderr),
2148 );
2149
2150 let stdout = String::from_utf8(output.stdout)?;
2151 Ok(Some(
2152 buffer
2153 .handle
2154 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2155 .await,
2156 ))
2157 }
2158
2159 async fn try_resolve_code_action(
2160 lang_server: &LanguageServer,
2161 action: &mut CodeAction,
2162 ) -> anyhow::Result<()> {
2163 match &mut action.lsp_action {
2164 LspAction::Action(lsp_action) => {
2165 if !action.resolved
2166 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2167 && lsp_action.data.is_some()
2168 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2169 {
2170 *lsp_action = Box::new(
2171 lang_server
2172 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2173 .await
2174 .into_response()?,
2175 );
2176 }
2177 }
2178 LspAction::CodeLens(lens) => {
2179 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2180 *lens = lang_server
2181 .request::<lsp::request::CodeLensResolve>(lens.clone())
2182 .await
2183 .into_response()?;
2184 }
2185 }
2186 LspAction::Command(_) => {}
2187 }
2188
2189 action.resolved = true;
2190 anyhow::Ok(())
2191 }
2192
2193 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2194 let buffer = buffer_handle.read(cx);
2195
2196 let file = buffer.file().cloned();
2197
2198 let Some(file) = File::from_dyn(file.as_ref()) else {
2199 return;
2200 };
2201 if !file.is_local() {
2202 return;
2203 }
2204 let path = ProjectPath::from_file(file, cx);
2205 let worktree_id = file.worktree_id(cx);
2206 let language = buffer.language().cloned();
2207
2208 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2209 for (server_id, diagnostics) in
2210 diagnostics.get(file.path()).cloned().unwrap_or_default()
2211 {
2212 self.update_buffer_diagnostics(
2213 buffer_handle,
2214 server_id,
2215 None,
2216 None,
2217 diagnostics,
2218 Vec::new(),
2219 cx,
2220 )
2221 .log_err();
2222 }
2223 }
2224 let Some(language) = language else {
2225 return;
2226 };
2227 let Some(snapshot) = self
2228 .worktree_store
2229 .read(cx)
2230 .worktree_for_id(worktree_id, cx)
2231 .map(|worktree| worktree.read(cx).snapshot())
2232 else {
2233 return;
2234 };
2235 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2236
2237 for server_id in
2238 self.lsp_tree
2239 .get(path, language.name(), language.manifest(), &delegate, cx)
2240 {
2241 let server = self
2242 .language_servers
2243 .get(&server_id)
2244 .and_then(|server_state| {
2245 if let LanguageServerState::Running { server, .. } = server_state {
2246 Some(server.clone())
2247 } else {
2248 None
2249 }
2250 });
2251 let server = match server {
2252 Some(server) => server,
2253 None => continue,
2254 };
2255
2256 buffer_handle.update(cx, |buffer, cx| {
2257 buffer.set_completion_triggers(
2258 server.server_id(),
2259 server
2260 .capabilities()
2261 .completion_provider
2262 .as_ref()
2263 .and_then(|provider| {
2264 provider
2265 .trigger_characters
2266 .as_ref()
2267 .map(|characters| characters.iter().cloned().collect())
2268 })
2269 .unwrap_or_default(),
2270 cx,
2271 );
2272 });
2273 }
2274 }
2275
2276 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2277 buffer.update(cx, |buffer, cx| {
2278 let Some(language) = buffer.language() else {
2279 return;
2280 };
2281 let path = ProjectPath {
2282 worktree_id: old_file.worktree_id(cx),
2283 path: old_file.path.clone(),
2284 };
2285 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2286 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2287 buffer.set_completion_triggers(server_id, Default::default(), cx);
2288 }
2289 });
2290 }
2291
2292 fn update_buffer_diagnostics(
2293 &mut self,
2294 buffer: &Entity<Buffer>,
2295 server_id: LanguageServerId,
2296 result_id: Option<String>,
2297 version: Option<i32>,
2298 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2299 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2300 cx: &mut Context<LspStore>,
2301 ) -> Result<()> {
2302 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2303 Ordering::Equal
2304 .then_with(|| b.is_primary.cmp(&a.is_primary))
2305 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2306 .then_with(|| a.severity.cmp(&b.severity))
2307 .then_with(|| a.message.cmp(&b.message))
2308 }
2309
2310 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2311 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2312 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2313
2314 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2315 Ordering::Equal
2316 .then_with(|| a.range.start.cmp(&b.range.start))
2317 .then_with(|| b.range.end.cmp(&a.range.end))
2318 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2319 });
2320
2321 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2322
2323 let edits_since_save = std::cell::LazyCell::new(|| {
2324 let saved_version = buffer.read(cx).saved_version();
2325 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2326 });
2327
2328 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2329
2330 for (new_diagnostic, entry) in diagnostics {
2331 let start;
2332 let end;
2333 if new_diagnostic && entry.diagnostic.is_disk_based {
2334 // Some diagnostics are based on files on disk instead of buffers'
2335 // current contents. Adjust these diagnostics' ranges to reflect
2336 // any unsaved edits.
2337 // Do not alter the reused ones though, as their coordinates were stored as anchors
2338 // and were properly adjusted on reuse.
2339 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2340 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2341 } else {
2342 start = entry.range.start;
2343 end = entry.range.end;
2344 }
2345
2346 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2347 ..snapshot.clip_point_utf16(end, Bias::Right);
2348
2349 // Expand empty ranges by one codepoint
2350 if range.start == range.end {
2351 // This will be go to the next boundary when being clipped
2352 range.end.column += 1;
2353 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2354 if range.start == range.end && range.end.column > 0 {
2355 range.start.column -= 1;
2356 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2357 }
2358 }
2359
2360 sanitized_diagnostics.push(DiagnosticEntry {
2361 range,
2362 diagnostic: entry.diagnostic,
2363 });
2364 }
2365 drop(edits_since_save);
2366
2367 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2368 buffer.update(cx, |buffer, cx| {
2369 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2370 self.buffer_pull_diagnostics_result_ids
2371 .entry(server_id)
2372 .or_default()
2373 .insert(abs_path, result_id);
2374 }
2375
2376 buffer.update_diagnostics(server_id, set, cx)
2377 });
2378
2379 Ok(())
2380 }
2381
2382 fn register_language_server_for_invisible_worktree(
2383 &mut self,
2384 worktree: &Entity<Worktree>,
2385 language_server_id: LanguageServerId,
2386 cx: &mut App,
2387 ) {
2388 let worktree = worktree.read(cx);
2389 let worktree_id = worktree.id();
2390 debug_assert!(!worktree.is_visible());
2391 let Some(mut origin_seed) = self
2392 .language_server_ids
2393 .iter()
2394 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2395 else {
2396 return;
2397 };
2398 origin_seed.worktree_id = worktree_id;
2399 self.language_server_ids
2400 .entry(origin_seed)
2401 .or_insert_with(|| UnifiedLanguageServer {
2402 id: language_server_id,
2403 project_roots: Default::default(),
2404 });
2405 }
2406
2407 fn register_buffer_with_language_servers(
2408 &mut self,
2409 buffer_handle: &Entity<Buffer>,
2410 only_register_servers: HashSet<LanguageServerSelector>,
2411 cx: &mut Context<LspStore>,
2412 ) {
2413 let buffer = buffer_handle.read(cx);
2414 let buffer_id = buffer.remote_id();
2415
2416 let Some(file) = File::from_dyn(buffer.file()) else {
2417 return;
2418 };
2419 if !file.is_local() {
2420 return;
2421 }
2422
2423 let abs_path = file.abs_path(cx);
2424 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2425 return;
2426 };
2427 let initial_snapshot = buffer.text_snapshot();
2428 let worktree_id = file.worktree_id(cx);
2429
2430 let Some(language) = buffer.language().cloned() else {
2431 return;
2432 };
2433 let path: Arc<RelPath> = file
2434 .path()
2435 .parent()
2436 .map(Arc::from)
2437 .unwrap_or_else(|| file.path().clone());
2438 let Some(worktree) = self
2439 .worktree_store
2440 .read(cx)
2441 .worktree_for_id(worktree_id, cx)
2442 else {
2443 return;
2444 };
2445 let language_name = language.name();
2446 let (reused, delegate, servers) = self
2447 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2448 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2449 .unwrap_or_else(|| {
2450 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2451 let delegate: Arc<dyn ManifestDelegate> =
2452 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2453
2454 let servers = self
2455 .lsp_tree
2456 .walk(
2457 ProjectPath { worktree_id, path },
2458 language.name(),
2459 language.manifest(),
2460 &delegate,
2461 cx,
2462 )
2463 .collect::<Vec<_>>();
2464 (false, lsp_delegate, servers)
2465 });
2466 let servers_and_adapters = servers
2467 .into_iter()
2468 .filter_map(|server_node| {
2469 if reused && server_node.server_id().is_none() {
2470 return None;
2471 }
2472 if !only_register_servers.is_empty() {
2473 if let Some(server_id) = server_node.server_id()
2474 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2475 {
2476 return None;
2477 }
2478 if let Some(name) = server_node.name()
2479 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2480 {
2481 return None;
2482 }
2483 }
2484
2485 let server_id = server_node.server_id_or_init(|disposition| {
2486 let path = &disposition.path;
2487
2488 {
2489 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2490
2491 let server_id = self.get_or_insert_language_server(
2492 &worktree,
2493 delegate.clone(),
2494 disposition,
2495 &language_name,
2496 cx,
2497 );
2498
2499 if let Some(state) = self.language_servers.get(&server_id)
2500 && let Ok(uri) = uri
2501 {
2502 state.add_workspace_folder(uri);
2503 };
2504 server_id
2505 }
2506 })?;
2507 let server_state = self.language_servers.get(&server_id)?;
2508 if let LanguageServerState::Running {
2509 server, adapter, ..
2510 } = server_state
2511 {
2512 Some((server.clone(), adapter.clone()))
2513 } else {
2514 None
2515 }
2516 })
2517 .collect::<Vec<_>>();
2518 for (server, adapter) in servers_and_adapters {
2519 buffer_handle.update(cx, |buffer, cx| {
2520 buffer.set_completion_triggers(
2521 server.server_id(),
2522 server
2523 .capabilities()
2524 .completion_provider
2525 .as_ref()
2526 .and_then(|provider| {
2527 provider
2528 .trigger_characters
2529 .as_ref()
2530 .map(|characters| characters.iter().cloned().collect())
2531 })
2532 .unwrap_or_default(),
2533 cx,
2534 );
2535 });
2536
2537 let snapshot = LspBufferSnapshot {
2538 version: 0,
2539 snapshot: initial_snapshot.clone(),
2540 };
2541
2542 let mut registered = false;
2543 self.buffer_snapshots
2544 .entry(buffer_id)
2545 .or_default()
2546 .entry(server.server_id())
2547 .or_insert_with(|| {
2548 registered = true;
2549 server.register_buffer(
2550 uri.clone(),
2551 adapter.language_id(&language.name()),
2552 0,
2553 initial_snapshot.text(),
2554 );
2555
2556 vec![snapshot]
2557 });
2558
2559 self.buffers_opened_in_servers
2560 .entry(buffer_id)
2561 .or_default()
2562 .insert(server.server_id());
2563 if registered {
2564 cx.emit(LspStoreEvent::LanguageServerUpdate {
2565 language_server_id: server.server_id(),
2566 name: None,
2567 message: proto::update_language_server::Variant::RegisteredForBuffer(
2568 proto::RegisteredForBuffer {
2569 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2570 buffer_id: buffer_id.to_proto(),
2571 },
2572 ),
2573 });
2574 }
2575 }
2576 }
2577
2578 fn reuse_existing_language_server<'lang_name>(
2579 &self,
2580 server_tree: &LanguageServerTree,
2581 worktree: &Entity<Worktree>,
2582 language_name: &'lang_name LanguageName,
2583 cx: &mut App,
2584 ) -> Option<(
2585 Arc<LocalLspAdapterDelegate>,
2586 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2587 )> {
2588 if worktree.read(cx).is_visible() {
2589 return None;
2590 }
2591
2592 let worktree_store = self.worktree_store.read(cx);
2593 let servers = server_tree
2594 .instances
2595 .iter()
2596 .filter(|(worktree_id, _)| {
2597 worktree_store
2598 .worktree_for_id(**worktree_id, cx)
2599 .is_some_and(|worktree| worktree.read(cx).is_visible())
2600 })
2601 .flat_map(|(worktree_id, servers)| {
2602 servers
2603 .roots
2604 .iter()
2605 .flat_map(|(_, language_servers)| language_servers)
2606 .map(move |(_, (server_node, server_languages))| {
2607 (worktree_id, server_node, server_languages)
2608 })
2609 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2610 .map(|(worktree_id, server_node, _)| {
2611 (
2612 *worktree_id,
2613 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2614 )
2615 })
2616 })
2617 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2618 acc.entry(worktree_id)
2619 .or_insert_with(Vec::new)
2620 .push(server_node);
2621 acc
2622 })
2623 .into_values()
2624 .max_by_key(|servers| servers.len())?;
2625
2626 let worktree_id = worktree.read(cx).id();
2627 let apply = move |tree: &mut LanguageServerTree| {
2628 for server_node in &servers {
2629 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2630 }
2631 servers
2632 };
2633
2634 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2635 Some((delegate, apply))
2636 }
2637
2638 pub(crate) fn unregister_old_buffer_from_language_servers(
2639 &mut self,
2640 buffer: &Entity<Buffer>,
2641 old_file: &File,
2642 cx: &mut App,
2643 ) {
2644 let old_path = match old_file.as_local() {
2645 Some(local) => local.abs_path(cx),
2646 None => return,
2647 };
2648
2649 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2650 debug_panic!("{old_path:?} is not parseable as an URI");
2651 return;
2652 };
2653 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2654 }
2655
2656 pub(crate) fn unregister_buffer_from_language_servers(
2657 &mut self,
2658 buffer: &Entity<Buffer>,
2659 file_url: &lsp::Uri,
2660 cx: &mut App,
2661 ) {
2662 buffer.update(cx, |buffer, cx| {
2663 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2664
2665 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2666 language_server.unregister_buffer(file_url.clone());
2667 }
2668 });
2669 }
2670
2671 fn buffer_snapshot_for_lsp_version(
2672 &mut self,
2673 buffer: &Entity<Buffer>,
2674 server_id: LanguageServerId,
2675 version: Option<i32>,
2676 cx: &App,
2677 ) -> Result<TextBufferSnapshot> {
2678 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2679
2680 if let Some(version) = version {
2681 let buffer_id = buffer.read(cx).remote_id();
2682 let snapshots = if let Some(snapshots) = self
2683 .buffer_snapshots
2684 .get_mut(&buffer_id)
2685 .and_then(|m| m.get_mut(&server_id))
2686 {
2687 snapshots
2688 } else if version == 0 {
2689 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2690 // We detect this case and treat it as if the version was `None`.
2691 return Ok(buffer.read(cx).text_snapshot());
2692 } else {
2693 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2694 };
2695
2696 let found_snapshot = snapshots
2697 .binary_search_by_key(&version, |e| e.version)
2698 .map(|ix| snapshots[ix].snapshot.clone())
2699 .map_err(|_| {
2700 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2701 })?;
2702
2703 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2704 Ok(found_snapshot)
2705 } else {
2706 Ok((buffer.read(cx)).text_snapshot())
2707 }
2708 }
2709
2710 async fn get_server_code_actions_from_action_kinds(
2711 lsp_store: &WeakEntity<LspStore>,
2712 language_server_id: LanguageServerId,
2713 code_action_kinds: Vec<lsp::CodeActionKind>,
2714 buffer: &Entity<Buffer>,
2715 cx: &mut AsyncApp,
2716 ) -> Result<Vec<CodeAction>> {
2717 let actions = lsp_store
2718 .update(cx, move |this, cx| {
2719 let request = GetCodeActions {
2720 range: text::Anchor::MIN..text::Anchor::MAX,
2721 kinds: Some(code_action_kinds),
2722 };
2723 let server = LanguageServerToQuery::Other(language_server_id);
2724 this.request_lsp(buffer.clone(), server, request, cx)
2725 })?
2726 .await?;
2727 Ok(actions)
2728 }
2729
2730 pub async fn execute_code_actions_on_server(
2731 lsp_store: &WeakEntity<LspStore>,
2732 language_server: &Arc<LanguageServer>,
2733
2734 actions: Vec<CodeAction>,
2735 push_to_history: bool,
2736 project_transaction: &mut ProjectTransaction,
2737 cx: &mut AsyncApp,
2738 ) -> anyhow::Result<()> {
2739 for mut action in actions {
2740 Self::try_resolve_code_action(language_server, &mut action)
2741 .await
2742 .context("resolving a formatting code action")?;
2743
2744 if let Some(edit) = action.lsp_action.edit() {
2745 if edit.changes.is_none() && edit.document_changes.is_none() {
2746 continue;
2747 }
2748
2749 let new = Self::deserialize_workspace_edit(
2750 lsp_store.upgrade().context("project dropped")?,
2751 edit.clone(),
2752 push_to_history,
2753 language_server.clone(),
2754 cx,
2755 )
2756 .await?;
2757 project_transaction.0.extend(new.0);
2758 }
2759
2760 if let Some(command) = action.lsp_action.command() {
2761 let server_capabilities = language_server.capabilities();
2762 let available_commands = server_capabilities
2763 .execute_command_provider
2764 .as_ref()
2765 .map(|options| options.commands.as_slice())
2766 .unwrap_or_default();
2767 if available_commands.contains(&command.command) {
2768 lsp_store.update(cx, |lsp_store, _| {
2769 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2770 mode.last_workspace_edits_by_language_server
2771 .remove(&language_server.server_id());
2772 }
2773 })?;
2774
2775 language_server
2776 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2777 command: command.command.clone(),
2778 arguments: command.arguments.clone().unwrap_or_default(),
2779 ..Default::default()
2780 })
2781 .await
2782 .into_response()
2783 .context("execute command")?;
2784
2785 lsp_store.update(cx, |this, _| {
2786 if let LspStoreMode::Local(mode) = &mut this.mode {
2787 project_transaction.0.extend(
2788 mode.last_workspace_edits_by_language_server
2789 .remove(&language_server.server_id())
2790 .unwrap_or_default()
2791 .0,
2792 )
2793 }
2794 })?;
2795 } else {
2796 log::warn!(
2797 "Cannot execute a command {} not listed in the language server capabilities",
2798 command.command
2799 )
2800 }
2801 }
2802 }
2803 Ok(())
2804 }
2805
2806 pub async fn deserialize_text_edits(
2807 this: Entity<LspStore>,
2808 buffer_to_edit: Entity<Buffer>,
2809 edits: Vec<lsp::TextEdit>,
2810 push_to_history: bool,
2811 _: Arc<CachedLspAdapter>,
2812 language_server: Arc<LanguageServer>,
2813 cx: &mut AsyncApp,
2814 ) -> Result<Option<Transaction>> {
2815 let edits = this
2816 .update(cx, |this, cx| {
2817 this.as_local_mut().unwrap().edits_from_lsp(
2818 &buffer_to_edit,
2819 edits,
2820 language_server.server_id(),
2821 None,
2822 cx,
2823 )
2824 })?
2825 .await?;
2826
2827 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2828 buffer.finalize_last_transaction();
2829 buffer.start_transaction();
2830 for (range, text) in edits {
2831 buffer.edit([(range, text)], None, cx);
2832 }
2833
2834 if buffer.end_transaction(cx).is_some() {
2835 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2836 if !push_to_history {
2837 buffer.forget_transaction(transaction.id);
2838 }
2839 Some(transaction)
2840 } else {
2841 None
2842 }
2843 })?;
2844
2845 Ok(transaction)
2846 }
2847
2848 #[allow(clippy::type_complexity)]
2849 pub(crate) fn edits_from_lsp(
2850 &mut self,
2851 buffer: &Entity<Buffer>,
2852 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2853 server_id: LanguageServerId,
2854 version: Option<i32>,
2855 cx: &mut Context<LspStore>,
2856 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2857 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2858 cx.background_spawn(async move {
2859 let snapshot = snapshot?;
2860 let mut lsp_edits = lsp_edits
2861 .into_iter()
2862 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2863 .collect::<Vec<_>>();
2864
2865 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2866
2867 let mut lsp_edits = lsp_edits.into_iter().peekable();
2868 let mut edits = Vec::new();
2869 while let Some((range, mut new_text)) = lsp_edits.next() {
2870 // Clip invalid ranges provided by the language server.
2871 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2872 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2873
2874 // Combine any LSP edits that are adjacent.
2875 //
2876 // Also, combine LSP edits that are separated from each other by only
2877 // a newline. This is important because for some code actions,
2878 // Rust-analyzer rewrites the entire buffer via a series of edits that
2879 // are separated by unchanged newline characters.
2880 //
2881 // In order for the diffing logic below to work properly, any edits that
2882 // cancel each other out must be combined into one.
2883 while let Some((next_range, next_text)) = lsp_edits.peek() {
2884 if next_range.start.0 > range.end {
2885 if next_range.start.0.row > range.end.row + 1
2886 || next_range.start.0.column > 0
2887 || snapshot.clip_point_utf16(
2888 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2889 Bias::Left,
2890 ) > range.end
2891 {
2892 break;
2893 }
2894 new_text.push('\n');
2895 }
2896 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2897 new_text.push_str(next_text);
2898 lsp_edits.next();
2899 }
2900
2901 // For multiline edits, perform a diff of the old and new text so that
2902 // we can identify the changes more precisely, preserving the locations
2903 // of any anchors positioned in the unchanged regions.
2904 if range.end.row > range.start.row {
2905 let offset = range.start.to_offset(&snapshot);
2906 let old_text = snapshot.text_for_range(range).collect::<String>();
2907 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2908 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2909 (
2910 snapshot.anchor_after(offset + range.start)
2911 ..snapshot.anchor_before(offset + range.end),
2912 replacement,
2913 )
2914 }));
2915 } else if range.end == range.start {
2916 let anchor = snapshot.anchor_after(range.start);
2917 edits.push((anchor..anchor, new_text.into()));
2918 } else {
2919 let edit_start = snapshot.anchor_after(range.start);
2920 let edit_end = snapshot.anchor_before(range.end);
2921 edits.push((edit_start..edit_end, new_text.into()));
2922 }
2923 }
2924
2925 Ok(edits)
2926 })
2927 }
2928
2929 pub(crate) async fn deserialize_workspace_edit(
2930 this: Entity<LspStore>,
2931 edit: lsp::WorkspaceEdit,
2932 push_to_history: bool,
2933 language_server: Arc<LanguageServer>,
2934 cx: &mut AsyncApp,
2935 ) -> Result<ProjectTransaction> {
2936 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2937
2938 let mut operations = Vec::new();
2939 if let Some(document_changes) = edit.document_changes {
2940 match document_changes {
2941 lsp::DocumentChanges::Edits(edits) => {
2942 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2943 }
2944 lsp::DocumentChanges::Operations(ops) => operations = ops,
2945 }
2946 } else if let Some(changes) = edit.changes {
2947 operations.extend(changes.into_iter().map(|(uri, edits)| {
2948 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2949 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2950 uri,
2951 version: None,
2952 },
2953 edits: edits.into_iter().map(Edit::Plain).collect(),
2954 })
2955 }));
2956 }
2957
2958 let mut project_transaction = ProjectTransaction::default();
2959 for operation in operations {
2960 match operation {
2961 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2962 let abs_path = op
2963 .uri
2964 .to_file_path()
2965 .map_err(|()| anyhow!("can't convert URI to path"))?;
2966
2967 if let Some(parent_path) = abs_path.parent() {
2968 fs.create_dir(parent_path).await?;
2969 }
2970 if abs_path.ends_with("/") {
2971 fs.create_dir(&abs_path).await?;
2972 } else {
2973 fs.create_file(
2974 &abs_path,
2975 op.options
2976 .map(|options| fs::CreateOptions {
2977 overwrite: options.overwrite.unwrap_or(false),
2978 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2979 })
2980 .unwrap_or_default(),
2981 )
2982 .await?;
2983 }
2984 }
2985
2986 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2987 let source_abs_path = op
2988 .old_uri
2989 .to_file_path()
2990 .map_err(|()| anyhow!("can't convert URI to path"))?;
2991 let target_abs_path = op
2992 .new_uri
2993 .to_file_path()
2994 .map_err(|()| anyhow!("can't convert URI to path"))?;
2995 fs.rename(
2996 &source_abs_path,
2997 &target_abs_path,
2998 op.options
2999 .map(|options| fs::RenameOptions {
3000 overwrite: options.overwrite.unwrap_or(false),
3001 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3002 })
3003 .unwrap_or_default(),
3004 )
3005 .await?;
3006 }
3007
3008 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3009 let abs_path = op
3010 .uri
3011 .to_file_path()
3012 .map_err(|()| anyhow!("can't convert URI to path"))?;
3013 let options = op
3014 .options
3015 .map(|options| fs::RemoveOptions {
3016 recursive: options.recursive.unwrap_or(false),
3017 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3018 })
3019 .unwrap_or_default();
3020 if abs_path.ends_with("/") {
3021 fs.remove_dir(&abs_path, options).await?;
3022 } else {
3023 fs.remove_file(&abs_path, options).await?;
3024 }
3025 }
3026
3027 lsp::DocumentChangeOperation::Edit(op) => {
3028 let buffer_to_edit = this
3029 .update(cx, |this, cx| {
3030 this.open_local_buffer_via_lsp(
3031 op.text_document.uri.clone(),
3032 language_server.server_id(),
3033 cx,
3034 )
3035 })?
3036 .await?;
3037
3038 let edits = this
3039 .update(cx, |this, cx| {
3040 let path = buffer_to_edit.read(cx).project_path(cx);
3041 let active_entry = this.active_entry;
3042 let is_active_entry = path.is_some_and(|project_path| {
3043 this.worktree_store
3044 .read(cx)
3045 .entry_for_path(&project_path, cx)
3046 .is_some_and(|entry| Some(entry.id) == active_entry)
3047 });
3048 let local = this.as_local_mut().unwrap();
3049
3050 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3051 for edit in op.edits {
3052 match edit {
3053 Edit::Plain(edit) => {
3054 if !edits.contains(&edit) {
3055 edits.push(edit)
3056 }
3057 }
3058 Edit::Annotated(edit) => {
3059 if !edits.contains(&edit.text_edit) {
3060 edits.push(edit.text_edit)
3061 }
3062 }
3063 Edit::Snippet(edit) => {
3064 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3065 else {
3066 continue;
3067 };
3068
3069 if is_active_entry {
3070 snippet_edits.push((edit.range, snippet));
3071 } else {
3072 // Since this buffer is not focused, apply a normal edit.
3073 let new_edit = TextEdit {
3074 range: edit.range,
3075 new_text: snippet.text,
3076 };
3077 if !edits.contains(&new_edit) {
3078 edits.push(new_edit);
3079 }
3080 }
3081 }
3082 }
3083 }
3084 if !snippet_edits.is_empty() {
3085 let buffer_id = buffer_to_edit.read(cx).remote_id();
3086 let version = if let Some(buffer_version) = op.text_document.version
3087 {
3088 local
3089 .buffer_snapshot_for_lsp_version(
3090 &buffer_to_edit,
3091 language_server.server_id(),
3092 Some(buffer_version),
3093 cx,
3094 )
3095 .ok()
3096 .map(|snapshot| snapshot.version)
3097 } else {
3098 Some(buffer_to_edit.read(cx).saved_version().clone())
3099 };
3100
3101 let most_recent_edit =
3102 version.and_then(|version| version.most_recent());
3103 // Check if the edit that triggered that edit has been made by this participant.
3104
3105 if let Some(most_recent_edit) = most_recent_edit {
3106 cx.emit(LspStoreEvent::SnippetEdit {
3107 buffer_id,
3108 edits: snippet_edits,
3109 most_recent_edit,
3110 });
3111 }
3112 }
3113
3114 local.edits_from_lsp(
3115 &buffer_to_edit,
3116 edits,
3117 language_server.server_id(),
3118 op.text_document.version,
3119 cx,
3120 )
3121 })?
3122 .await?;
3123
3124 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3125 buffer.finalize_last_transaction();
3126 buffer.start_transaction();
3127 for (range, text) in edits {
3128 buffer.edit([(range, text)], None, cx);
3129 }
3130
3131 buffer.end_transaction(cx).and_then(|transaction_id| {
3132 if push_to_history {
3133 buffer.finalize_last_transaction();
3134 buffer.get_transaction(transaction_id).cloned()
3135 } else {
3136 buffer.forget_transaction(transaction_id)
3137 }
3138 })
3139 })?;
3140 if let Some(transaction) = transaction {
3141 project_transaction.0.insert(buffer_to_edit, transaction);
3142 }
3143 }
3144 }
3145 }
3146
3147 Ok(project_transaction)
3148 }
3149
3150 async fn on_lsp_workspace_edit(
3151 this: WeakEntity<LspStore>,
3152 params: lsp::ApplyWorkspaceEditParams,
3153 server_id: LanguageServerId,
3154 cx: &mut AsyncApp,
3155 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3156 let this = this.upgrade().context("project project closed")?;
3157 let language_server = this
3158 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3159 .context("language server not found")?;
3160 let transaction = Self::deserialize_workspace_edit(
3161 this.clone(),
3162 params.edit,
3163 true,
3164 language_server.clone(),
3165 cx,
3166 )
3167 .await
3168 .log_err();
3169 this.update(cx, |this, _| {
3170 if let Some(transaction) = transaction {
3171 this.as_local_mut()
3172 .unwrap()
3173 .last_workspace_edits_by_language_server
3174 .insert(server_id, transaction);
3175 }
3176 })?;
3177 Ok(lsp::ApplyWorkspaceEditResponse {
3178 applied: true,
3179 failed_change: None,
3180 failure_reason: None,
3181 })
3182 }
3183
3184 fn remove_worktree(
3185 &mut self,
3186 id_to_remove: WorktreeId,
3187 cx: &mut Context<LspStore>,
3188 ) -> Vec<LanguageServerId> {
3189 self.diagnostics.remove(&id_to_remove);
3190 self.prettier_store.update(cx, |prettier_store, cx| {
3191 prettier_store.remove_worktree(id_to_remove, cx);
3192 });
3193
3194 let mut servers_to_remove = BTreeSet::default();
3195 let mut servers_to_preserve = HashSet::default();
3196 for (seed, state) in &self.language_server_ids {
3197 if seed.worktree_id == id_to_remove {
3198 servers_to_remove.insert(state.id);
3199 } else {
3200 servers_to_preserve.insert(state.id);
3201 }
3202 }
3203 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3204 self.language_server_ids
3205 .retain(|_, state| !servers_to_remove.contains(&state.id));
3206 for server_id_to_remove in &servers_to_remove {
3207 self.language_server_watched_paths
3208 .remove(server_id_to_remove);
3209 self.language_server_paths_watched_for_rename
3210 .remove(server_id_to_remove);
3211 self.last_workspace_edits_by_language_server
3212 .remove(server_id_to_remove);
3213 self.language_servers.remove(server_id_to_remove);
3214 self.buffer_pull_diagnostics_result_ids
3215 .remove(server_id_to_remove);
3216 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3217 buffer_servers.remove(server_id_to_remove);
3218 }
3219 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3220 }
3221 servers_to_remove.into_iter().collect()
3222 }
3223
3224 fn rebuild_watched_paths_inner<'a>(
3225 &'a self,
3226 language_server_id: LanguageServerId,
3227 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3228 cx: &mut Context<LspStore>,
3229 ) -> LanguageServerWatchedPathsBuilder {
3230 let worktrees = self
3231 .worktree_store
3232 .read(cx)
3233 .worktrees()
3234 .filter_map(|worktree| {
3235 self.language_servers_for_worktree(worktree.read(cx).id())
3236 .find(|server| server.server_id() == language_server_id)
3237 .map(|_| worktree)
3238 })
3239 .collect::<Vec<_>>();
3240
3241 let mut worktree_globs = HashMap::default();
3242 let mut abs_globs = HashMap::default();
3243 log::trace!(
3244 "Processing new watcher paths for language server with id {}",
3245 language_server_id
3246 );
3247
3248 for watcher in watchers {
3249 if let Some((worktree, literal_prefix, pattern)) =
3250 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3251 {
3252 worktree.update(cx, |worktree, _| {
3253 if let Some((tree, glob)) =
3254 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3255 {
3256 tree.add_path_prefix_to_scan(literal_prefix);
3257 worktree_globs
3258 .entry(tree.id())
3259 .or_insert_with(GlobSetBuilder::new)
3260 .add(glob);
3261 }
3262 });
3263 } else {
3264 let (path, pattern) = match &watcher.glob_pattern {
3265 lsp::GlobPattern::String(s) => {
3266 let watcher_path = SanitizedPath::new(s);
3267 let path = glob_literal_prefix(watcher_path.as_path());
3268 let pattern = watcher_path
3269 .as_path()
3270 .strip_prefix(&path)
3271 .map(|p| p.to_string_lossy().into_owned())
3272 .unwrap_or_else(|e| {
3273 debug_panic!(
3274 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3275 s,
3276 path.display(),
3277 e
3278 );
3279 watcher_path.as_path().to_string_lossy().into_owned()
3280 });
3281 (path, pattern)
3282 }
3283 lsp::GlobPattern::Relative(rp) => {
3284 let Ok(mut base_uri) = match &rp.base_uri {
3285 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3286 lsp::OneOf::Right(base_uri) => base_uri,
3287 }
3288 .to_file_path() else {
3289 continue;
3290 };
3291
3292 let path = glob_literal_prefix(Path::new(&rp.pattern));
3293 let pattern = Path::new(&rp.pattern)
3294 .strip_prefix(&path)
3295 .map(|p| p.to_string_lossy().into_owned())
3296 .unwrap_or_else(|e| {
3297 debug_panic!(
3298 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3299 rp.pattern,
3300 path.display(),
3301 e
3302 );
3303 rp.pattern.clone()
3304 });
3305 base_uri.push(path);
3306 (base_uri, pattern)
3307 }
3308 };
3309
3310 if let Some(glob) = Glob::new(&pattern).log_err() {
3311 if !path
3312 .components()
3313 .any(|c| matches!(c, path::Component::Normal(_)))
3314 {
3315 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3316 // rather than adding a new watcher for `/`.
3317 for worktree in &worktrees {
3318 worktree_globs
3319 .entry(worktree.read(cx).id())
3320 .or_insert_with(GlobSetBuilder::new)
3321 .add(glob.clone());
3322 }
3323 } else {
3324 abs_globs
3325 .entry(path.into())
3326 .or_insert_with(GlobSetBuilder::new)
3327 .add(glob);
3328 }
3329 }
3330 }
3331 }
3332
3333 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3334 for (worktree_id, builder) in worktree_globs {
3335 if let Ok(globset) = builder.build() {
3336 watch_builder.watch_worktree(worktree_id, globset);
3337 }
3338 }
3339 for (abs_path, builder) in abs_globs {
3340 if let Ok(globset) = builder.build() {
3341 watch_builder.watch_abs_path(abs_path, globset);
3342 }
3343 }
3344 watch_builder
3345 }
3346
3347 fn worktree_and_path_for_file_watcher(
3348 worktrees: &[Entity<Worktree>],
3349 watcher: &FileSystemWatcher,
3350 cx: &App,
3351 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3352 worktrees.iter().find_map(|worktree| {
3353 let tree = worktree.read(cx);
3354 let worktree_root_path = tree.abs_path();
3355 let path_style = tree.path_style();
3356 match &watcher.glob_pattern {
3357 lsp::GlobPattern::String(s) => {
3358 let watcher_path = SanitizedPath::new(s);
3359 let relative = watcher_path
3360 .as_path()
3361 .strip_prefix(&worktree_root_path)
3362 .ok()?;
3363 let literal_prefix = glob_literal_prefix(relative);
3364 Some((
3365 worktree.clone(),
3366 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3367 relative.to_string_lossy().into_owned(),
3368 ))
3369 }
3370 lsp::GlobPattern::Relative(rp) => {
3371 let base_uri = match &rp.base_uri {
3372 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3373 lsp::OneOf::Right(base_uri) => base_uri,
3374 }
3375 .to_file_path()
3376 .ok()?;
3377 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3378 let mut literal_prefix = relative.to_owned();
3379 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3380 Some((
3381 worktree.clone(),
3382 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3383 rp.pattern.clone(),
3384 ))
3385 }
3386 }
3387 })
3388 }
3389
3390 fn rebuild_watched_paths(
3391 &mut self,
3392 language_server_id: LanguageServerId,
3393 cx: &mut Context<LspStore>,
3394 ) {
3395 let Some(registrations) = self
3396 .language_server_dynamic_registrations
3397 .get(&language_server_id)
3398 else {
3399 return;
3400 };
3401
3402 let watch_builder = self.rebuild_watched_paths_inner(
3403 language_server_id,
3404 registrations.did_change_watched_files.values().flatten(),
3405 cx,
3406 );
3407 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3408 self.language_server_watched_paths
3409 .insert(language_server_id, watcher);
3410
3411 cx.notify();
3412 }
3413
3414 fn on_lsp_did_change_watched_files(
3415 &mut self,
3416 language_server_id: LanguageServerId,
3417 registration_id: &str,
3418 params: DidChangeWatchedFilesRegistrationOptions,
3419 cx: &mut Context<LspStore>,
3420 ) {
3421 let registrations = self
3422 .language_server_dynamic_registrations
3423 .entry(language_server_id)
3424 .or_default();
3425
3426 registrations
3427 .did_change_watched_files
3428 .insert(registration_id.to_string(), params.watchers);
3429
3430 self.rebuild_watched_paths(language_server_id, cx);
3431 }
3432
3433 fn on_lsp_unregister_did_change_watched_files(
3434 &mut self,
3435 language_server_id: LanguageServerId,
3436 registration_id: &str,
3437 cx: &mut Context<LspStore>,
3438 ) {
3439 let registrations = self
3440 .language_server_dynamic_registrations
3441 .entry(language_server_id)
3442 .or_default();
3443
3444 if registrations
3445 .did_change_watched_files
3446 .remove(registration_id)
3447 .is_some()
3448 {
3449 log::info!(
3450 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3451 language_server_id,
3452 registration_id
3453 );
3454 } else {
3455 log::warn!(
3456 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3457 language_server_id,
3458 registration_id
3459 );
3460 }
3461
3462 self.rebuild_watched_paths(language_server_id, cx);
3463 }
3464
3465 async fn initialization_options_for_adapter(
3466 adapter: Arc<dyn LspAdapter>,
3467 delegate: &Arc<dyn LspAdapterDelegate>,
3468 ) -> Result<Option<serde_json::Value>> {
3469 let Some(mut initialization_config) =
3470 adapter.clone().initialization_options(delegate).await?
3471 else {
3472 return Ok(None);
3473 };
3474
3475 for other_adapter in delegate.registered_lsp_adapters() {
3476 if other_adapter.name() == adapter.name() {
3477 continue;
3478 }
3479 if let Ok(Some(target_config)) = other_adapter
3480 .clone()
3481 .additional_initialization_options(adapter.name(), delegate)
3482 .await
3483 {
3484 merge_json_value_into(target_config.clone(), &mut initialization_config);
3485 }
3486 }
3487
3488 Ok(Some(initialization_config))
3489 }
3490
3491 async fn workspace_configuration_for_adapter(
3492 adapter: Arc<dyn LspAdapter>,
3493 delegate: &Arc<dyn LspAdapterDelegate>,
3494 toolchain: Option<Toolchain>,
3495 cx: &mut AsyncApp,
3496 ) -> Result<serde_json::Value> {
3497 let mut workspace_config = adapter
3498 .clone()
3499 .workspace_configuration(delegate, toolchain, cx)
3500 .await?;
3501
3502 for other_adapter in delegate.registered_lsp_adapters() {
3503 if other_adapter.name() == adapter.name() {
3504 continue;
3505 }
3506 if let Ok(Some(target_config)) = other_adapter
3507 .clone()
3508 .additional_workspace_configuration(adapter.name(), delegate, cx)
3509 .await
3510 {
3511 merge_json_value_into(target_config.clone(), &mut workspace_config);
3512 }
3513 }
3514
3515 Ok(workspace_config)
3516 }
3517
3518 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3519 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3520 Some(server.clone())
3521 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3522 Some(Arc::clone(server))
3523 } else {
3524 None
3525 }
3526 }
3527}
3528
3529fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3530 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3531 cx.emit(LspStoreEvent::LanguageServerUpdate {
3532 language_server_id: server.server_id(),
3533 name: Some(server.name()),
3534 message: proto::update_language_server::Variant::MetadataUpdated(
3535 proto::ServerMetadataUpdated {
3536 capabilities: Some(capabilities),
3537 },
3538 ),
3539 });
3540 }
3541}
3542
3543#[derive(Debug)]
3544pub struct FormattableBuffer {
3545 handle: Entity<Buffer>,
3546 abs_path: Option<PathBuf>,
3547 env: Option<HashMap<String, String>>,
3548 ranges: Option<Vec<Range<Anchor>>>,
3549}
3550
3551pub struct RemoteLspStore {
3552 upstream_client: Option<AnyProtoClient>,
3553 upstream_project_id: u64,
3554}
3555
3556pub(crate) enum LspStoreMode {
3557 Local(LocalLspStore), // ssh host and collab host
3558 Remote(RemoteLspStore), // collab guest
3559}
3560
3561impl LspStoreMode {
3562 fn is_local(&self) -> bool {
3563 matches!(self, LspStoreMode::Local(_))
3564 }
3565}
3566
3567pub struct LspStore {
3568 mode: LspStoreMode,
3569 last_formatting_failure: Option<String>,
3570 downstream_client: Option<(AnyProtoClient, u64)>,
3571 nonce: u128,
3572 buffer_store: Entity<BufferStore>,
3573 worktree_store: Entity<WorktreeStore>,
3574 pub languages: Arc<LanguageRegistry>,
3575 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3576 active_entry: Option<ProjectEntryId>,
3577 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3578 _maintain_buffer_languages: Task<()>,
3579 diagnostic_summaries:
3580 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3581 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3582 lsp_data: HashMap<BufferId, BufferLspData>,
3583 next_hint_id: Arc<AtomicUsize>,
3584}
3585
3586#[derive(Debug)]
3587pub struct BufferLspData {
3588 buffer_version: Global,
3589 document_colors: Option<DocumentColorData>,
3590 code_lens: Option<CodeLensData>,
3591 inlay_hints: BufferInlayHints,
3592 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3593 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3594}
3595
3596#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3597struct LspKey {
3598 request_type: TypeId,
3599 server_queried: Option<LanguageServerId>,
3600}
3601
3602impl BufferLspData {
3603 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3604 Self {
3605 buffer_version: buffer.read(cx).version(),
3606 document_colors: None,
3607 code_lens: None,
3608 inlay_hints: BufferInlayHints::new(buffer, cx),
3609 lsp_requests: HashMap::default(),
3610 chunk_lsp_requests: HashMap::default(),
3611 }
3612 }
3613
3614 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3615 if let Some(document_colors) = &mut self.document_colors {
3616 document_colors.colors.remove(&for_server);
3617 document_colors.cache_version += 1;
3618 }
3619
3620 if let Some(code_lens) = &mut self.code_lens {
3621 code_lens.lens.remove(&for_server);
3622 }
3623
3624 self.inlay_hints.remove_server_data(for_server);
3625 }
3626
3627 #[cfg(any(test, feature = "test-support"))]
3628 pub fn inlay_hints(&self) -> &BufferInlayHints {
3629 &self.inlay_hints
3630 }
3631}
3632
3633#[derive(Debug, Default, Clone)]
3634pub struct DocumentColors {
3635 pub colors: HashSet<DocumentColor>,
3636 pub cache_version: Option<usize>,
3637}
3638
3639type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3640type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3641
3642#[derive(Debug, Default)]
3643struct DocumentColorData {
3644 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3645 cache_version: usize,
3646 colors_update: Option<(Global, DocumentColorTask)>,
3647}
3648
3649#[derive(Debug, Default)]
3650struct CodeLensData {
3651 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3652 update: Option<(Global, CodeLensTask)>,
3653}
3654
3655#[derive(Debug)]
3656pub enum LspStoreEvent {
3657 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3658 LanguageServerRemoved(LanguageServerId),
3659 LanguageServerUpdate {
3660 language_server_id: LanguageServerId,
3661 name: Option<LanguageServerName>,
3662 message: proto::update_language_server::Variant,
3663 },
3664 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3665 LanguageServerPrompt(LanguageServerPromptRequest),
3666 LanguageDetected {
3667 buffer: Entity<Buffer>,
3668 new_language: Option<Arc<Language>>,
3669 },
3670 Notification(String),
3671 RefreshInlayHints {
3672 server_id: LanguageServerId,
3673 request_id: Option<usize>,
3674 },
3675 RefreshCodeLens,
3676 DiagnosticsUpdated {
3677 server_id: LanguageServerId,
3678 paths: Vec<ProjectPath>,
3679 },
3680 DiskBasedDiagnosticsStarted {
3681 language_server_id: LanguageServerId,
3682 },
3683 DiskBasedDiagnosticsFinished {
3684 language_server_id: LanguageServerId,
3685 },
3686 SnippetEdit {
3687 buffer_id: BufferId,
3688 edits: Vec<(lsp::Range, Snippet)>,
3689 most_recent_edit: clock::Lamport,
3690 },
3691}
3692
3693#[derive(Clone, Debug, Serialize)]
3694pub struct LanguageServerStatus {
3695 pub name: LanguageServerName,
3696 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3697 pub has_pending_diagnostic_updates: bool,
3698 progress_tokens: HashSet<ProgressToken>,
3699 pub worktree: Option<WorktreeId>,
3700}
3701
3702#[derive(Clone, Debug)]
3703struct CoreSymbol {
3704 pub language_server_name: LanguageServerName,
3705 pub source_worktree_id: WorktreeId,
3706 pub source_language_server_id: LanguageServerId,
3707 pub path: SymbolLocation,
3708 pub name: String,
3709 pub kind: lsp::SymbolKind,
3710 pub range: Range<Unclipped<PointUtf16>>,
3711}
3712
3713#[derive(Clone, Debug, PartialEq, Eq)]
3714pub enum SymbolLocation {
3715 InProject(ProjectPath),
3716 OutsideProject {
3717 abs_path: Arc<Path>,
3718 signature: [u8; 32],
3719 },
3720}
3721
3722impl SymbolLocation {
3723 fn file_name(&self) -> Option<&str> {
3724 match self {
3725 Self::InProject(path) => path.path.file_name(),
3726 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3727 }
3728 }
3729}
3730
3731impl LspStore {
3732 pub fn init(client: &AnyProtoClient) {
3733 client.add_entity_request_handler(Self::handle_lsp_query);
3734 client.add_entity_message_handler(Self::handle_lsp_query_response);
3735 client.add_entity_request_handler(Self::handle_restart_language_servers);
3736 client.add_entity_request_handler(Self::handle_stop_language_servers);
3737 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3738 client.add_entity_message_handler(Self::handle_start_language_server);
3739 client.add_entity_message_handler(Self::handle_update_language_server);
3740 client.add_entity_message_handler(Self::handle_language_server_log);
3741 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3742 client.add_entity_request_handler(Self::handle_format_buffers);
3743 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3744 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3745 client.add_entity_request_handler(Self::handle_apply_code_action);
3746 client.add_entity_request_handler(Self::handle_get_project_symbols);
3747 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3748 client.add_entity_request_handler(Self::handle_get_color_presentation);
3749 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3750 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3751 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3752 client.add_entity_request_handler(Self::handle_on_type_formatting);
3753 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3754 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3755 client.add_entity_request_handler(Self::handle_rename_project_entry);
3756 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3757 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3758 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3759 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3760 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3761 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3762 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3763
3764 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3765 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3766 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3767 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3768 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3769 client.add_entity_request_handler(
3770 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3771 );
3772 client.add_entity_request_handler(
3773 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3774 );
3775 client.add_entity_request_handler(
3776 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3777 );
3778 }
3779
3780 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3781 match &self.mode {
3782 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3783 _ => None,
3784 }
3785 }
3786
3787 pub fn as_local(&self) -> Option<&LocalLspStore> {
3788 match &self.mode {
3789 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3790 _ => None,
3791 }
3792 }
3793
3794 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3795 match &mut self.mode {
3796 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3797 _ => None,
3798 }
3799 }
3800
3801 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3802 match &self.mode {
3803 LspStoreMode::Remote(RemoteLspStore {
3804 upstream_client: Some(upstream_client),
3805 upstream_project_id,
3806 ..
3807 }) => Some((upstream_client.clone(), *upstream_project_id)),
3808
3809 LspStoreMode::Remote(RemoteLspStore {
3810 upstream_client: None,
3811 ..
3812 }) => None,
3813 LspStoreMode::Local(_) => None,
3814 }
3815 }
3816
3817 pub fn new_local(
3818 buffer_store: Entity<BufferStore>,
3819 worktree_store: Entity<WorktreeStore>,
3820 prettier_store: Entity<PrettierStore>,
3821 toolchain_store: Entity<LocalToolchainStore>,
3822 environment: Entity<ProjectEnvironment>,
3823 manifest_tree: Entity<ManifestTree>,
3824 languages: Arc<LanguageRegistry>,
3825 http_client: Arc<dyn HttpClient>,
3826 fs: Arc<dyn Fs>,
3827 cx: &mut Context<Self>,
3828 ) -> Self {
3829 let yarn = YarnPathStore::new(fs.clone(), cx);
3830 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3831 .detach();
3832 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3833 .detach();
3834 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3835 .detach();
3836 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3837 .detach();
3838 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3839 .detach();
3840 subscribe_to_binary_statuses(&languages, cx).detach();
3841
3842 let _maintain_workspace_config = {
3843 let (sender, receiver) = watch::channel();
3844 (Self::maintain_workspace_config(receiver, cx), sender)
3845 };
3846
3847 Self {
3848 mode: LspStoreMode::Local(LocalLspStore {
3849 weak: cx.weak_entity(),
3850 worktree_store: worktree_store.clone(),
3851
3852 supplementary_language_servers: Default::default(),
3853 languages: languages.clone(),
3854 language_server_ids: Default::default(),
3855 language_servers: Default::default(),
3856 last_workspace_edits_by_language_server: Default::default(),
3857 language_server_watched_paths: Default::default(),
3858 language_server_paths_watched_for_rename: Default::default(),
3859 language_server_dynamic_registrations: Default::default(),
3860 buffers_being_formatted: Default::default(),
3861 buffer_snapshots: Default::default(),
3862 prettier_store,
3863 environment,
3864 http_client,
3865 fs,
3866 yarn,
3867 next_diagnostic_group_id: Default::default(),
3868 diagnostics: Default::default(),
3869 _subscription: cx.on_app_quit(|this, cx| {
3870 this.as_local_mut()
3871 .unwrap()
3872 .shutdown_language_servers_on_quit(cx)
3873 }),
3874 lsp_tree: LanguageServerTree::new(
3875 manifest_tree,
3876 languages.clone(),
3877 toolchain_store.clone(),
3878 ),
3879 toolchain_store,
3880 registered_buffers: HashMap::default(),
3881 buffers_opened_in_servers: HashMap::default(),
3882 buffer_pull_diagnostics_result_ids: HashMap::default(),
3883 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3884 .manifest_file_names(),
3885 }),
3886 last_formatting_failure: None,
3887 downstream_client: None,
3888 buffer_store,
3889 worktree_store,
3890 languages: languages.clone(),
3891 language_server_statuses: Default::default(),
3892 nonce: StdRng::from_os_rng().random(),
3893 diagnostic_summaries: HashMap::default(),
3894 lsp_server_capabilities: HashMap::default(),
3895 lsp_data: HashMap::default(),
3896 next_hint_id: Arc::default(),
3897 active_entry: None,
3898 _maintain_workspace_config,
3899 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3900 }
3901 }
3902
3903 fn send_lsp_proto_request<R: LspCommand>(
3904 &self,
3905 buffer: Entity<Buffer>,
3906 client: AnyProtoClient,
3907 upstream_project_id: u64,
3908 request: R,
3909 cx: &mut Context<LspStore>,
3910 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3911 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3912 return Task::ready(Ok(R::Response::default()));
3913 }
3914 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3915 cx.spawn(async move |this, cx| {
3916 let response = client.request(message).await?;
3917 let this = this.upgrade().context("project dropped")?;
3918 request
3919 .response_from_proto(response, this, buffer, cx.clone())
3920 .await
3921 })
3922 }
3923
3924 pub(super) fn new_remote(
3925 buffer_store: Entity<BufferStore>,
3926 worktree_store: Entity<WorktreeStore>,
3927 languages: Arc<LanguageRegistry>,
3928 upstream_client: AnyProtoClient,
3929 project_id: u64,
3930 cx: &mut Context<Self>,
3931 ) -> Self {
3932 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3933 .detach();
3934 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3935 .detach();
3936 subscribe_to_binary_statuses(&languages, cx).detach();
3937 let _maintain_workspace_config = {
3938 let (sender, receiver) = watch::channel();
3939 (Self::maintain_workspace_config(receiver, cx), sender)
3940 };
3941 Self {
3942 mode: LspStoreMode::Remote(RemoteLspStore {
3943 upstream_client: Some(upstream_client),
3944 upstream_project_id: project_id,
3945 }),
3946 downstream_client: None,
3947 last_formatting_failure: None,
3948 buffer_store,
3949 worktree_store,
3950 languages: languages.clone(),
3951 language_server_statuses: Default::default(),
3952 nonce: StdRng::from_os_rng().random(),
3953 diagnostic_summaries: HashMap::default(),
3954 lsp_server_capabilities: HashMap::default(),
3955 next_hint_id: Arc::default(),
3956 lsp_data: HashMap::default(),
3957 active_entry: None,
3958
3959 _maintain_workspace_config,
3960 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3961 }
3962 }
3963
3964 fn on_buffer_store_event(
3965 &mut self,
3966 _: Entity<BufferStore>,
3967 event: &BufferStoreEvent,
3968 cx: &mut Context<Self>,
3969 ) {
3970 match event {
3971 BufferStoreEvent::BufferAdded(buffer) => {
3972 self.on_buffer_added(buffer, cx).log_err();
3973 }
3974 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3975 let buffer_id = buffer.read(cx).remote_id();
3976 if let Some(local) = self.as_local_mut()
3977 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3978 {
3979 local.reset_buffer(buffer, old_file, cx);
3980
3981 if local.registered_buffers.contains_key(&buffer_id) {
3982 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3983 }
3984 }
3985
3986 self.detect_language_for_buffer(buffer, cx);
3987 if let Some(local) = self.as_local_mut() {
3988 local.initialize_buffer(buffer, cx);
3989 if local.registered_buffers.contains_key(&buffer_id) {
3990 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3991 }
3992 }
3993 }
3994 _ => {}
3995 }
3996 }
3997
3998 fn on_worktree_store_event(
3999 &mut self,
4000 _: Entity<WorktreeStore>,
4001 event: &WorktreeStoreEvent,
4002 cx: &mut Context<Self>,
4003 ) {
4004 match event {
4005 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4006 if !worktree.read(cx).is_local() {
4007 return;
4008 }
4009 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4010 worktree::Event::UpdatedEntries(changes) => {
4011 this.update_local_worktree_language_servers(&worktree, changes, cx);
4012 }
4013 worktree::Event::UpdatedGitRepositories(_)
4014 | worktree::Event::DeletedEntry(_) => {}
4015 })
4016 .detach()
4017 }
4018 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4019 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4020 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4021 }
4022 WorktreeStoreEvent::WorktreeReleased(..)
4023 | WorktreeStoreEvent::WorktreeOrderChanged
4024 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4025 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4026 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4027 }
4028 }
4029
4030 fn on_prettier_store_event(
4031 &mut self,
4032 _: Entity<PrettierStore>,
4033 event: &PrettierStoreEvent,
4034 cx: &mut Context<Self>,
4035 ) {
4036 match event {
4037 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4038 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4039 }
4040 PrettierStoreEvent::LanguageServerAdded {
4041 new_server_id,
4042 name,
4043 prettier_server,
4044 } => {
4045 self.register_supplementary_language_server(
4046 *new_server_id,
4047 name.clone(),
4048 prettier_server.clone(),
4049 cx,
4050 );
4051 }
4052 }
4053 }
4054
4055 fn on_toolchain_store_event(
4056 &mut self,
4057 _: Entity<LocalToolchainStore>,
4058 event: &ToolchainStoreEvent,
4059 _: &mut Context<Self>,
4060 ) {
4061 if let ToolchainStoreEvent::ToolchainActivated = event {
4062 self.request_workspace_config_refresh()
4063 }
4064 }
4065
4066 fn request_workspace_config_refresh(&mut self) {
4067 *self._maintain_workspace_config.1.borrow_mut() = ();
4068 }
4069
4070 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4071 self.as_local().map(|local| local.prettier_store.clone())
4072 }
4073
4074 fn on_buffer_event(
4075 &mut self,
4076 buffer: Entity<Buffer>,
4077 event: &language::BufferEvent,
4078 cx: &mut Context<Self>,
4079 ) {
4080 match event {
4081 language::BufferEvent::Edited => {
4082 self.on_buffer_edited(buffer, cx);
4083 }
4084
4085 language::BufferEvent::Saved => {
4086 self.on_buffer_saved(buffer, cx);
4087 }
4088
4089 _ => {}
4090 }
4091 }
4092
4093 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4094 buffer
4095 .read(cx)
4096 .set_language_registry(self.languages.clone());
4097
4098 cx.subscribe(buffer, |this, buffer, event, cx| {
4099 this.on_buffer_event(buffer, event, cx);
4100 })
4101 .detach();
4102
4103 self.detect_language_for_buffer(buffer, cx);
4104 if let Some(local) = self.as_local_mut() {
4105 local.initialize_buffer(buffer, cx);
4106 }
4107
4108 Ok(())
4109 }
4110
4111 pub(crate) fn register_buffer_with_language_servers(
4112 &mut self,
4113 buffer: &Entity<Buffer>,
4114 only_register_servers: HashSet<LanguageServerSelector>,
4115 ignore_refcounts: bool,
4116 cx: &mut Context<Self>,
4117 ) -> OpenLspBufferHandle {
4118 let buffer_id = buffer.read(cx).remote_id();
4119 let handle = cx.new(|_| buffer.clone());
4120 if let Some(local) = self.as_local_mut() {
4121 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4122 if !ignore_refcounts {
4123 *refcount += 1;
4124 }
4125
4126 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4127 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4128 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4129 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4130 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4131 return handle;
4132 };
4133 if !file.is_local() {
4134 return handle;
4135 }
4136
4137 if ignore_refcounts || *refcount == 1 {
4138 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4139 }
4140 if !ignore_refcounts {
4141 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4142 let refcount = {
4143 let local = lsp_store.as_local_mut().unwrap();
4144 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4145 debug_panic!("bad refcounting");
4146 return;
4147 };
4148
4149 *refcount -= 1;
4150 *refcount
4151 };
4152 if refcount == 0 {
4153 lsp_store.lsp_data.remove(&buffer_id);
4154 let local = lsp_store.as_local_mut().unwrap();
4155 local.registered_buffers.remove(&buffer_id);
4156 local.buffers_opened_in_servers.remove(&buffer_id);
4157 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4158 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4159 }
4160 }
4161 })
4162 .detach();
4163 }
4164 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4165 let buffer_id = buffer.read(cx).remote_id().to_proto();
4166 cx.background_spawn(async move {
4167 upstream_client
4168 .request(proto::RegisterBufferWithLanguageServers {
4169 project_id: upstream_project_id,
4170 buffer_id,
4171 only_servers: only_register_servers
4172 .into_iter()
4173 .map(|selector| {
4174 let selector = match selector {
4175 LanguageServerSelector::Id(language_server_id) => {
4176 proto::language_server_selector::Selector::ServerId(
4177 language_server_id.to_proto(),
4178 )
4179 }
4180 LanguageServerSelector::Name(language_server_name) => {
4181 proto::language_server_selector::Selector::Name(
4182 language_server_name.to_string(),
4183 )
4184 }
4185 };
4186 proto::LanguageServerSelector {
4187 selector: Some(selector),
4188 }
4189 })
4190 .collect(),
4191 })
4192 .await
4193 })
4194 .detach();
4195 } else {
4196 // Our remote connection got closed
4197 }
4198 handle
4199 }
4200
4201 fn maintain_buffer_languages(
4202 languages: Arc<LanguageRegistry>,
4203 cx: &mut Context<Self>,
4204 ) -> Task<()> {
4205 let mut subscription = languages.subscribe();
4206 let mut prev_reload_count = languages.reload_count();
4207 cx.spawn(async move |this, cx| {
4208 while let Some(()) = subscription.next().await {
4209 if let Some(this) = this.upgrade() {
4210 // If the language registry has been reloaded, then remove and
4211 // re-assign the languages on all open buffers.
4212 let reload_count = languages.reload_count();
4213 if reload_count > prev_reload_count {
4214 prev_reload_count = reload_count;
4215 this.update(cx, |this, cx| {
4216 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4217 for buffer in buffer_store.buffers() {
4218 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4219 {
4220 buffer
4221 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4222 if let Some(local) = this.as_local_mut() {
4223 local.reset_buffer(&buffer, &f, cx);
4224
4225 if local
4226 .registered_buffers
4227 .contains_key(&buffer.read(cx).remote_id())
4228 && let Some(file_url) =
4229 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4230 {
4231 local.unregister_buffer_from_language_servers(
4232 &buffer, &file_url, cx,
4233 );
4234 }
4235 }
4236 }
4237 }
4238 });
4239 })
4240 .ok();
4241 }
4242
4243 this.update(cx, |this, cx| {
4244 let mut plain_text_buffers = Vec::new();
4245 let mut buffers_with_unknown_injections = Vec::new();
4246 for handle in this.buffer_store.read(cx).buffers() {
4247 let buffer = handle.read(cx);
4248 if buffer.language().is_none()
4249 || buffer.language() == Some(&*language::PLAIN_TEXT)
4250 {
4251 plain_text_buffers.push(handle);
4252 } else if buffer.contains_unknown_injections() {
4253 buffers_with_unknown_injections.push(handle);
4254 }
4255 }
4256
4257 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4258 // and reused later in the invisible worktrees.
4259 plain_text_buffers.sort_by_key(|buffer| {
4260 Reverse(
4261 File::from_dyn(buffer.read(cx).file())
4262 .map(|file| file.worktree.read(cx).is_visible()),
4263 )
4264 });
4265
4266 for buffer in plain_text_buffers {
4267 this.detect_language_for_buffer(&buffer, cx);
4268 if let Some(local) = this.as_local_mut() {
4269 local.initialize_buffer(&buffer, cx);
4270 if local
4271 .registered_buffers
4272 .contains_key(&buffer.read(cx).remote_id())
4273 {
4274 local.register_buffer_with_language_servers(
4275 &buffer,
4276 HashSet::default(),
4277 cx,
4278 );
4279 }
4280 }
4281 }
4282
4283 for buffer in buffers_with_unknown_injections {
4284 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4285 }
4286 })
4287 .ok();
4288 }
4289 }
4290 })
4291 }
4292
4293 fn detect_language_for_buffer(
4294 &mut self,
4295 buffer_handle: &Entity<Buffer>,
4296 cx: &mut Context<Self>,
4297 ) -> Option<language::AvailableLanguage> {
4298 // If the buffer has a language, set it and start the language server if we haven't already.
4299 let buffer = buffer_handle.read(cx);
4300 let file = buffer.file()?;
4301
4302 let content = buffer.as_rope();
4303 let available_language = self.languages.language_for_file(file, Some(content), cx);
4304 if let Some(available_language) = &available_language {
4305 if let Some(Ok(Ok(new_language))) = self
4306 .languages
4307 .load_language(available_language)
4308 .now_or_never()
4309 {
4310 self.set_language_for_buffer(buffer_handle, new_language, cx);
4311 }
4312 } else {
4313 cx.emit(LspStoreEvent::LanguageDetected {
4314 buffer: buffer_handle.clone(),
4315 new_language: None,
4316 });
4317 }
4318
4319 available_language
4320 }
4321
4322 pub(crate) fn set_language_for_buffer(
4323 &mut self,
4324 buffer_entity: &Entity<Buffer>,
4325 new_language: Arc<Language>,
4326 cx: &mut Context<Self>,
4327 ) {
4328 let buffer = buffer_entity.read(cx);
4329 let buffer_file = buffer.file().cloned();
4330 let buffer_id = buffer.remote_id();
4331 if let Some(local_store) = self.as_local_mut()
4332 && local_store.registered_buffers.contains_key(&buffer_id)
4333 && let Some(abs_path) =
4334 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4335 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4336 {
4337 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4338 }
4339 buffer_entity.update(cx, |buffer, cx| {
4340 if buffer
4341 .language()
4342 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4343 {
4344 buffer.set_language(Some(new_language.clone()), cx);
4345 }
4346 });
4347
4348 let settings =
4349 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4350 let buffer_file = File::from_dyn(buffer_file.as_ref());
4351
4352 let worktree_id = if let Some(file) = buffer_file {
4353 let worktree = file.worktree.clone();
4354
4355 if let Some(local) = self.as_local_mut()
4356 && local.registered_buffers.contains_key(&buffer_id)
4357 {
4358 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4359 }
4360 Some(worktree.read(cx).id())
4361 } else {
4362 None
4363 };
4364
4365 if settings.prettier.allowed
4366 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4367 {
4368 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4369 if let Some(prettier_store) = prettier_store {
4370 prettier_store.update(cx, |prettier_store, cx| {
4371 prettier_store.install_default_prettier(
4372 worktree_id,
4373 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4374 cx,
4375 )
4376 })
4377 }
4378 }
4379
4380 cx.emit(LspStoreEvent::LanguageDetected {
4381 buffer: buffer_entity.clone(),
4382 new_language: Some(new_language),
4383 })
4384 }
4385
4386 pub fn buffer_store(&self) -> Entity<BufferStore> {
4387 self.buffer_store.clone()
4388 }
4389
4390 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4391 self.active_entry = active_entry;
4392 }
4393
4394 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4395 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4396 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4397 {
4398 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4399 summaries
4400 .iter()
4401 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4402 });
4403 if let Some(summary) = summaries.next() {
4404 client
4405 .send(proto::UpdateDiagnosticSummary {
4406 project_id: downstream_project_id,
4407 worktree_id: worktree.id().to_proto(),
4408 summary: Some(summary),
4409 more_summaries: summaries.collect(),
4410 })
4411 .log_err();
4412 }
4413 }
4414 }
4415
4416 fn is_capable_for_proto_request<R>(
4417 &self,
4418 buffer: &Entity<Buffer>,
4419 request: &R,
4420 cx: &App,
4421 ) -> bool
4422 where
4423 R: LspCommand,
4424 {
4425 self.check_if_capable_for_proto_request(
4426 buffer,
4427 |capabilities| {
4428 request.check_capabilities(AdapterServerCapabilities {
4429 server_capabilities: capabilities.clone(),
4430 code_action_kinds: None,
4431 })
4432 },
4433 cx,
4434 )
4435 }
4436
4437 fn check_if_capable_for_proto_request<F>(
4438 &self,
4439 buffer: &Entity<Buffer>,
4440 check: F,
4441 cx: &App,
4442 ) -> bool
4443 where
4444 F: FnMut(&lsp::ServerCapabilities) -> bool,
4445 {
4446 let Some(language) = buffer.read(cx).language().cloned() else {
4447 return false;
4448 };
4449 let relevant_language_servers = self
4450 .languages
4451 .lsp_adapters(&language.name())
4452 .into_iter()
4453 .map(|lsp_adapter| lsp_adapter.name())
4454 .collect::<HashSet<_>>();
4455 self.language_server_statuses
4456 .iter()
4457 .filter_map(|(server_id, server_status)| {
4458 relevant_language_servers
4459 .contains(&server_status.name)
4460 .then_some(server_id)
4461 })
4462 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4463 .any(check)
4464 }
4465
4466 pub fn request_lsp<R>(
4467 &mut self,
4468 buffer: Entity<Buffer>,
4469 server: LanguageServerToQuery,
4470 request: R,
4471 cx: &mut Context<Self>,
4472 ) -> Task<Result<R::Response>>
4473 where
4474 R: LspCommand,
4475 <R::LspRequest as lsp::request::Request>::Result: Send,
4476 <R::LspRequest as lsp::request::Request>::Params: Send,
4477 {
4478 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4479 return self.send_lsp_proto_request(
4480 buffer,
4481 upstream_client,
4482 upstream_project_id,
4483 request,
4484 cx,
4485 );
4486 }
4487
4488 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4489 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4490 local
4491 .language_servers_for_buffer(buffer, cx)
4492 .find(|(_, server)| {
4493 request.check_capabilities(server.adapter_server_capabilities())
4494 })
4495 .map(|(_, server)| server.clone())
4496 }),
4497 LanguageServerToQuery::Other(id) => self
4498 .language_server_for_local_buffer(buffer, id, cx)
4499 .and_then(|(_, server)| {
4500 request
4501 .check_capabilities(server.adapter_server_capabilities())
4502 .then(|| Arc::clone(server))
4503 }),
4504 }) else {
4505 return Task::ready(Ok(Default::default()));
4506 };
4507
4508 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4509
4510 let Some(file) = file else {
4511 return Task::ready(Ok(Default::default()));
4512 };
4513
4514 let lsp_params = match request.to_lsp_params_or_response(
4515 &file.abs_path(cx),
4516 buffer.read(cx),
4517 &language_server,
4518 cx,
4519 ) {
4520 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4521 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4522 Err(err) => {
4523 let message = format!(
4524 "{} via {} failed: {}",
4525 request.display_name(),
4526 language_server.name(),
4527 err
4528 );
4529 // rust-analyzer likes to error with this when its still loading up
4530 if !message.ends_with("content modified") {
4531 log::warn!("{message}");
4532 }
4533 return Task::ready(Err(anyhow!(message)));
4534 }
4535 };
4536
4537 let status = request.status();
4538 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4539 return Task::ready(Ok(Default::default()));
4540 }
4541 cx.spawn(async move |this, cx| {
4542 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4543
4544 let id = lsp_request.id();
4545 let _cleanup = if status.is_some() {
4546 cx.update(|cx| {
4547 this.update(cx, |this, cx| {
4548 this.on_lsp_work_start(
4549 language_server.server_id(),
4550 ProgressToken::Number(id),
4551 LanguageServerProgress {
4552 is_disk_based_diagnostics_progress: false,
4553 is_cancellable: false,
4554 title: None,
4555 message: status.clone(),
4556 percentage: None,
4557 last_update_at: cx.background_executor().now(),
4558 },
4559 cx,
4560 );
4561 })
4562 })
4563 .log_err();
4564
4565 Some(defer(|| {
4566 cx.update(|cx| {
4567 this.update(cx, |this, cx| {
4568 this.on_lsp_work_end(
4569 language_server.server_id(),
4570 ProgressToken::Number(id),
4571 cx,
4572 );
4573 })
4574 })
4575 .log_err();
4576 }))
4577 } else {
4578 None
4579 };
4580
4581 let result = lsp_request.await.into_response();
4582
4583 let response = result.map_err(|err| {
4584 let message = format!(
4585 "{} via {} failed: {}",
4586 request.display_name(),
4587 language_server.name(),
4588 err
4589 );
4590 // rust-analyzer likes to error with this when its still loading up
4591 if !message.ends_with("content modified") {
4592 log::warn!("{message}");
4593 }
4594 anyhow::anyhow!(message)
4595 })?;
4596
4597 request
4598 .response_from_lsp(
4599 response,
4600 this.upgrade().context("no app context")?,
4601 buffer,
4602 language_server.server_id(),
4603 cx.clone(),
4604 )
4605 .await
4606 })
4607 }
4608
4609 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4610 let mut language_formatters_to_check = Vec::new();
4611 for buffer in self.buffer_store.read(cx).buffers() {
4612 let buffer = buffer.read(cx);
4613 let buffer_file = File::from_dyn(buffer.file());
4614 let buffer_language = buffer.language();
4615 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4616 if buffer_language.is_some() {
4617 language_formatters_to_check.push((
4618 buffer_file.map(|f| f.worktree_id(cx)),
4619 settings.into_owned(),
4620 ));
4621 }
4622 }
4623
4624 self.request_workspace_config_refresh();
4625
4626 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4627 prettier_store.update(cx, |prettier_store, cx| {
4628 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4629 })
4630 }
4631
4632 cx.notify();
4633 }
4634
4635 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4636 let buffer_store = self.buffer_store.clone();
4637 let Some(local) = self.as_local_mut() else {
4638 return;
4639 };
4640 let mut adapters = BTreeMap::default();
4641 let get_adapter = {
4642 let languages = local.languages.clone();
4643 let environment = local.environment.clone();
4644 let weak = local.weak.clone();
4645 let worktree_store = local.worktree_store.clone();
4646 let http_client = local.http_client.clone();
4647 let fs = local.fs.clone();
4648 move |worktree_id, cx: &mut App| {
4649 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4650 Some(LocalLspAdapterDelegate::new(
4651 languages.clone(),
4652 &environment,
4653 weak.clone(),
4654 &worktree,
4655 http_client.clone(),
4656 fs.clone(),
4657 cx,
4658 ))
4659 }
4660 };
4661
4662 let mut messages_to_report = Vec::new();
4663 let (new_tree, to_stop) = {
4664 let mut rebase = local.lsp_tree.rebase();
4665 let buffers = buffer_store
4666 .read(cx)
4667 .buffers()
4668 .filter_map(|buffer| {
4669 let raw_buffer = buffer.read(cx);
4670 if !local
4671 .registered_buffers
4672 .contains_key(&raw_buffer.remote_id())
4673 {
4674 return None;
4675 }
4676 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4677 let language = raw_buffer.language().cloned()?;
4678 Some((file, language, raw_buffer.remote_id()))
4679 })
4680 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4681 for (file, language, buffer_id) in buffers {
4682 let worktree_id = file.worktree_id(cx);
4683 let Some(worktree) = local
4684 .worktree_store
4685 .read(cx)
4686 .worktree_for_id(worktree_id, cx)
4687 else {
4688 continue;
4689 };
4690
4691 if let Some((_, apply)) = local.reuse_existing_language_server(
4692 rebase.server_tree(),
4693 &worktree,
4694 &language.name(),
4695 cx,
4696 ) {
4697 (apply)(rebase.server_tree());
4698 } else if let Some(lsp_delegate) = adapters
4699 .entry(worktree_id)
4700 .or_insert_with(|| get_adapter(worktree_id, cx))
4701 .clone()
4702 {
4703 let delegate =
4704 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4705 let path = file
4706 .path()
4707 .parent()
4708 .map(Arc::from)
4709 .unwrap_or_else(|| file.path().clone());
4710 let worktree_path = ProjectPath { worktree_id, path };
4711 let abs_path = file.abs_path(cx);
4712 let nodes = rebase
4713 .walk(
4714 worktree_path,
4715 language.name(),
4716 language.manifest(),
4717 delegate.clone(),
4718 cx,
4719 )
4720 .collect::<Vec<_>>();
4721 for node in nodes {
4722 let server_id = node.server_id_or_init(|disposition| {
4723 let path = &disposition.path;
4724 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4725 let key = LanguageServerSeed {
4726 worktree_id,
4727 name: disposition.server_name.clone(),
4728 settings: disposition.settings.clone(),
4729 toolchain: local.toolchain_store.read(cx).active_toolchain(
4730 path.worktree_id,
4731 &path.path,
4732 language.name(),
4733 ),
4734 };
4735 local.language_server_ids.remove(&key);
4736
4737 let server_id = local.get_or_insert_language_server(
4738 &worktree,
4739 lsp_delegate.clone(),
4740 disposition,
4741 &language.name(),
4742 cx,
4743 );
4744 if let Some(state) = local.language_servers.get(&server_id)
4745 && let Ok(uri) = uri
4746 {
4747 state.add_workspace_folder(uri);
4748 };
4749 server_id
4750 });
4751
4752 if let Some(language_server_id) = server_id {
4753 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4754 language_server_id,
4755 name: node.name(),
4756 message:
4757 proto::update_language_server::Variant::RegisteredForBuffer(
4758 proto::RegisteredForBuffer {
4759 buffer_abs_path: abs_path
4760 .to_string_lossy()
4761 .into_owned(),
4762 buffer_id: buffer_id.to_proto(),
4763 },
4764 ),
4765 });
4766 }
4767 }
4768 } else {
4769 continue;
4770 }
4771 }
4772 rebase.finish()
4773 };
4774 for message in messages_to_report {
4775 cx.emit(message);
4776 }
4777 local.lsp_tree = new_tree;
4778 for (id, _) in to_stop {
4779 self.stop_local_language_server(id, cx).detach();
4780 }
4781 }
4782
4783 pub fn apply_code_action(
4784 &self,
4785 buffer_handle: Entity<Buffer>,
4786 mut action: CodeAction,
4787 push_to_history: bool,
4788 cx: &mut Context<Self>,
4789 ) -> Task<Result<ProjectTransaction>> {
4790 if let Some((upstream_client, project_id)) = self.upstream_client() {
4791 let request = proto::ApplyCodeAction {
4792 project_id,
4793 buffer_id: buffer_handle.read(cx).remote_id().into(),
4794 action: Some(Self::serialize_code_action(&action)),
4795 };
4796 let buffer_store = self.buffer_store();
4797 cx.spawn(async move |_, cx| {
4798 let response = upstream_client
4799 .request(request)
4800 .await?
4801 .transaction
4802 .context("missing transaction")?;
4803
4804 buffer_store
4805 .update(cx, |buffer_store, cx| {
4806 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4807 })?
4808 .await
4809 })
4810 } else if self.mode.is_local() {
4811 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4812 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4813 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4814 }) else {
4815 return Task::ready(Ok(ProjectTransaction::default()));
4816 };
4817 cx.spawn(async move |this, cx| {
4818 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4819 .await
4820 .context("resolving a code action")?;
4821 if let Some(edit) = action.lsp_action.edit()
4822 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4823 return LocalLspStore::deserialize_workspace_edit(
4824 this.upgrade().context("no app present")?,
4825 edit.clone(),
4826 push_to_history,
4827
4828 lang_server.clone(),
4829 cx,
4830 )
4831 .await;
4832 }
4833
4834 if let Some(command) = action.lsp_action.command() {
4835 let server_capabilities = lang_server.capabilities();
4836 let available_commands = server_capabilities
4837 .execute_command_provider
4838 .as_ref()
4839 .map(|options| options.commands.as_slice())
4840 .unwrap_or_default();
4841 if available_commands.contains(&command.command) {
4842 this.update(cx, |this, _| {
4843 this.as_local_mut()
4844 .unwrap()
4845 .last_workspace_edits_by_language_server
4846 .remove(&lang_server.server_id());
4847 })?;
4848
4849 let _result = lang_server
4850 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4851 command: command.command.clone(),
4852 arguments: command.arguments.clone().unwrap_or_default(),
4853 ..lsp::ExecuteCommandParams::default()
4854 })
4855 .await.into_response()
4856 .context("execute command")?;
4857
4858 return this.update(cx, |this, _| {
4859 this.as_local_mut()
4860 .unwrap()
4861 .last_workspace_edits_by_language_server
4862 .remove(&lang_server.server_id())
4863 .unwrap_or_default()
4864 });
4865 } else {
4866 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4867 }
4868 }
4869
4870 Ok(ProjectTransaction::default())
4871 })
4872 } else {
4873 Task::ready(Err(anyhow!("no upstream client and not local")))
4874 }
4875 }
4876
4877 pub fn apply_code_action_kind(
4878 &mut self,
4879 buffers: HashSet<Entity<Buffer>>,
4880 kind: CodeActionKind,
4881 push_to_history: bool,
4882 cx: &mut Context<Self>,
4883 ) -> Task<anyhow::Result<ProjectTransaction>> {
4884 if self.as_local().is_some() {
4885 cx.spawn(async move |lsp_store, cx| {
4886 let buffers = buffers.into_iter().collect::<Vec<_>>();
4887 let result = LocalLspStore::execute_code_action_kind_locally(
4888 lsp_store.clone(),
4889 buffers,
4890 kind,
4891 push_to_history,
4892 cx,
4893 )
4894 .await;
4895 lsp_store.update(cx, |lsp_store, _| {
4896 lsp_store.update_last_formatting_failure(&result);
4897 })?;
4898 result
4899 })
4900 } else if let Some((client, project_id)) = self.upstream_client() {
4901 let buffer_store = self.buffer_store();
4902 cx.spawn(async move |lsp_store, cx| {
4903 let result = client
4904 .request(proto::ApplyCodeActionKind {
4905 project_id,
4906 kind: kind.as_str().to_owned(),
4907 buffer_ids: buffers
4908 .iter()
4909 .map(|buffer| {
4910 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4911 })
4912 .collect::<Result<_>>()?,
4913 })
4914 .await
4915 .and_then(|result| result.transaction.context("missing transaction"));
4916 lsp_store.update(cx, |lsp_store, _| {
4917 lsp_store.update_last_formatting_failure(&result);
4918 })?;
4919
4920 let transaction_response = result?;
4921 buffer_store
4922 .update(cx, |buffer_store, cx| {
4923 buffer_store.deserialize_project_transaction(
4924 transaction_response,
4925 push_to_history,
4926 cx,
4927 )
4928 })?
4929 .await
4930 })
4931 } else {
4932 Task::ready(Ok(ProjectTransaction::default()))
4933 }
4934 }
4935
4936 pub fn resolved_hint(
4937 &mut self,
4938 buffer_id: BufferId,
4939 id: InlayId,
4940 cx: &mut Context<Self>,
4941 ) -> Option<ResolvedHint> {
4942 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4943
4944 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4945 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4946 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4947 let (server_id, resolve_data) = match &hint.resolve_state {
4948 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4949 ResolveState::Resolving => {
4950 return Some(ResolvedHint::Resolving(
4951 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4952 ));
4953 }
4954 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4955 };
4956
4957 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4958 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4959 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4960 id,
4961 cx.spawn(async move |lsp_store, cx| {
4962 let resolved_hint = resolve_task.await;
4963 lsp_store
4964 .update(cx, |lsp_store, _| {
4965 if let Some(old_inlay_hint) = lsp_store
4966 .lsp_data
4967 .get_mut(&buffer_id)
4968 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4969 {
4970 match resolved_hint {
4971 Ok(resolved_hint) => {
4972 *old_inlay_hint = resolved_hint;
4973 }
4974 Err(e) => {
4975 old_inlay_hint.resolve_state =
4976 ResolveState::CanResolve(server_id, resolve_data);
4977 log::error!("Inlay hint resolve failed: {e:#}");
4978 }
4979 }
4980 }
4981 })
4982 .ok();
4983 })
4984 .shared(),
4985 );
4986 debug_assert!(
4987 previous_task.is_none(),
4988 "Did not change hint's resolve state after spawning its resolve"
4989 );
4990 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4991 None
4992 }
4993
4994 fn resolve_inlay_hint(
4995 &self,
4996 mut hint: InlayHint,
4997 buffer: Entity<Buffer>,
4998 server_id: LanguageServerId,
4999 cx: &mut Context<Self>,
5000 ) -> Task<anyhow::Result<InlayHint>> {
5001 if let Some((upstream_client, project_id)) = self.upstream_client() {
5002 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5003 {
5004 hint.resolve_state = ResolveState::Resolved;
5005 return Task::ready(Ok(hint));
5006 }
5007 let request = proto::ResolveInlayHint {
5008 project_id,
5009 buffer_id: buffer.read(cx).remote_id().into(),
5010 language_server_id: server_id.0 as u64,
5011 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5012 };
5013 cx.background_spawn(async move {
5014 let response = upstream_client
5015 .request(request)
5016 .await
5017 .context("inlay hints proto request")?;
5018 match response.hint {
5019 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5020 .context("inlay hints proto resolve response conversion"),
5021 None => Ok(hint),
5022 }
5023 })
5024 } else {
5025 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5026 self.language_server_for_local_buffer(buffer, server_id, cx)
5027 .map(|(_, server)| server.clone())
5028 }) else {
5029 return Task::ready(Ok(hint));
5030 };
5031 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5032 return Task::ready(Ok(hint));
5033 }
5034 let buffer_snapshot = buffer.read(cx).snapshot();
5035 cx.spawn(async move |_, cx| {
5036 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5037 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5038 );
5039 let resolved_hint = resolve_task
5040 .await
5041 .into_response()
5042 .context("inlay hint resolve LSP request")?;
5043 let resolved_hint = InlayHints::lsp_to_project_hint(
5044 resolved_hint,
5045 &buffer,
5046 server_id,
5047 ResolveState::Resolved,
5048 false,
5049 cx,
5050 )
5051 .await?;
5052 Ok(resolved_hint)
5053 })
5054 }
5055 }
5056
5057 pub fn resolve_color_presentation(
5058 &mut self,
5059 mut color: DocumentColor,
5060 buffer: Entity<Buffer>,
5061 server_id: LanguageServerId,
5062 cx: &mut Context<Self>,
5063 ) -> Task<Result<DocumentColor>> {
5064 if color.resolved {
5065 return Task::ready(Ok(color));
5066 }
5067
5068 if let Some((upstream_client, project_id)) = self.upstream_client() {
5069 let start = color.lsp_range.start;
5070 let end = color.lsp_range.end;
5071 let request = proto::GetColorPresentation {
5072 project_id,
5073 server_id: server_id.to_proto(),
5074 buffer_id: buffer.read(cx).remote_id().into(),
5075 color: Some(proto::ColorInformation {
5076 red: color.color.red,
5077 green: color.color.green,
5078 blue: color.color.blue,
5079 alpha: color.color.alpha,
5080 lsp_range_start: Some(proto::PointUtf16 {
5081 row: start.line,
5082 column: start.character,
5083 }),
5084 lsp_range_end: Some(proto::PointUtf16 {
5085 row: end.line,
5086 column: end.character,
5087 }),
5088 }),
5089 };
5090 cx.background_spawn(async move {
5091 let response = upstream_client
5092 .request(request)
5093 .await
5094 .context("color presentation proto request")?;
5095 color.resolved = true;
5096 color.color_presentations = response
5097 .presentations
5098 .into_iter()
5099 .map(|presentation| ColorPresentation {
5100 label: SharedString::from(presentation.label),
5101 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5102 additional_text_edits: presentation
5103 .additional_text_edits
5104 .into_iter()
5105 .filter_map(deserialize_lsp_edit)
5106 .collect(),
5107 })
5108 .collect();
5109 Ok(color)
5110 })
5111 } else {
5112 let path = match buffer
5113 .update(cx, |buffer, cx| {
5114 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5115 })
5116 .context("buffer with the missing path")
5117 {
5118 Ok(path) => path,
5119 Err(e) => return Task::ready(Err(e)),
5120 };
5121 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5122 self.language_server_for_local_buffer(buffer, server_id, cx)
5123 .map(|(_, server)| server.clone())
5124 }) else {
5125 return Task::ready(Ok(color));
5126 };
5127 cx.background_spawn(async move {
5128 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5129 lsp::ColorPresentationParams {
5130 text_document: make_text_document_identifier(&path)?,
5131 color: color.color,
5132 range: color.lsp_range,
5133 work_done_progress_params: Default::default(),
5134 partial_result_params: Default::default(),
5135 },
5136 );
5137 color.color_presentations = resolve_task
5138 .await
5139 .into_response()
5140 .context("color presentation resolve LSP request")?
5141 .into_iter()
5142 .map(|presentation| ColorPresentation {
5143 label: SharedString::from(presentation.label),
5144 text_edit: presentation.text_edit,
5145 additional_text_edits: presentation
5146 .additional_text_edits
5147 .unwrap_or_default(),
5148 })
5149 .collect();
5150 color.resolved = true;
5151 Ok(color)
5152 })
5153 }
5154 }
5155
5156 pub(crate) fn linked_edits(
5157 &mut self,
5158 buffer: &Entity<Buffer>,
5159 position: Anchor,
5160 cx: &mut Context<Self>,
5161 ) -> Task<Result<Vec<Range<Anchor>>>> {
5162 let snapshot = buffer.read(cx).snapshot();
5163 let scope = snapshot.language_scope_at(position);
5164 let Some(server_id) = self
5165 .as_local()
5166 .and_then(|local| {
5167 buffer.update(cx, |buffer, cx| {
5168 local
5169 .language_servers_for_buffer(buffer, cx)
5170 .filter(|(_, server)| {
5171 LinkedEditingRange::check_server_capabilities(server.capabilities())
5172 })
5173 .filter(|(adapter, _)| {
5174 scope
5175 .as_ref()
5176 .map(|scope| scope.language_allowed(&adapter.name))
5177 .unwrap_or(true)
5178 })
5179 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5180 .next()
5181 })
5182 })
5183 .or_else(|| {
5184 self.upstream_client()
5185 .is_some()
5186 .then_some(LanguageServerToQuery::FirstCapable)
5187 })
5188 .filter(|_| {
5189 maybe!({
5190 let language = buffer.read(cx).language_at(position)?;
5191 Some(
5192 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5193 .linked_edits,
5194 )
5195 }) == Some(true)
5196 })
5197 else {
5198 return Task::ready(Ok(Vec::new()));
5199 };
5200
5201 self.request_lsp(
5202 buffer.clone(),
5203 server_id,
5204 LinkedEditingRange { position },
5205 cx,
5206 )
5207 }
5208
5209 fn apply_on_type_formatting(
5210 &mut self,
5211 buffer: Entity<Buffer>,
5212 position: Anchor,
5213 trigger: String,
5214 cx: &mut Context<Self>,
5215 ) -> Task<Result<Option<Transaction>>> {
5216 if let Some((client, project_id)) = self.upstream_client() {
5217 if !self.check_if_capable_for_proto_request(
5218 &buffer,
5219 |capabilities| {
5220 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5221 },
5222 cx,
5223 ) {
5224 return Task::ready(Ok(None));
5225 }
5226 let request = proto::OnTypeFormatting {
5227 project_id,
5228 buffer_id: buffer.read(cx).remote_id().into(),
5229 position: Some(serialize_anchor(&position)),
5230 trigger,
5231 version: serialize_version(&buffer.read(cx).version()),
5232 };
5233 cx.background_spawn(async move {
5234 client
5235 .request(request)
5236 .await?
5237 .transaction
5238 .map(language::proto::deserialize_transaction)
5239 .transpose()
5240 })
5241 } else if let Some(local) = self.as_local_mut() {
5242 let buffer_id = buffer.read(cx).remote_id();
5243 local.buffers_being_formatted.insert(buffer_id);
5244 cx.spawn(async move |this, cx| {
5245 let _cleanup = defer({
5246 let this = this.clone();
5247 let mut cx = cx.clone();
5248 move || {
5249 this.update(&mut cx, |this, _| {
5250 if let Some(local) = this.as_local_mut() {
5251 local.buffers_being_formatted.remove(&buffer_id);
5252 }
5253 })
5254 .ok();
5255 }
5256 });
5257
5258 buffer
5259 .update(cx, |buffer, _| {
5260 buffer.wait_for_edits(Some(position.timestamp))
5261 })?
5262 .await?;
5263 this.update(cx, |this, cx| {
5264 let position = position.to_point_utf16(buffer.read(cx));
5265 this.on_type_format(buffer, position, trigger, false, cx)
5266 })?
5267 .await
5268 })
5269 } else {
5270 Task::ready(Err(anyhow!("No upstream client or local language server")))
5271 }
5272 }
5273
5274 pub fn on_type_format<T: ToPointUtf16>(
5275 &mut self,
5276 buffer: Entity<Buffer>,
5277 position: T,
5278 trigger: String,
5279 push_to_history: bool,
5280 cx: &mut Context<Self>,
5281 ) -> Task<Result<Option<Transaction>>> {
5282 let position = position.to_point_utf16(buffer.read(cx));
5283 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5284 }
5285
5286 fn on_type_format_impl(
5287 &mut self,
5288 buffer: Entity<Buffer>,
5289 position: PointUtf16,
5290 trigger: String,
5291 push_to_history: bool,
5292 cx: &mut Context<Self>,
5293 ) -> Task<Result<Option<Transaction>>> {
5294 let options = buffer.update(cx, |buffer, cx| {
5295 lsp_command::lsp_formatting_options(
5296 language_settings(
5297 buffer.language_at(position).map(|l| l.name()),
5298 buffer.file(),
5299 cx,
5300 )
5301 .as_ref(),
5302 )
5303 });
5304
5305 cx.spawn(async move |this, cx| {
5306 if let Some(waiter) =
5307 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5308 {
5309 waiter.await?;
5310 }
5311 cx.update(|cx| {
5312 this.update(cx, |this, cx| {
5313 this.request_lsp(
5314 buffer.clone(),
5315 LanguageServerToQuery::FirstCapable,
5316 OnTypeFormatting {
5317 position,
5318 trigger,
5319 options,
5320 push_to_history,
5321 },
5322 cx,
5323 )
5324 })
5325 })??
5326 .await
5327 })
5328 }
5329
5330 pub fn definitions(
5331 &mut self,
5332 buffer: &Entity<Buffer>,
5333 position: PointUtf16,
5334 cx: &mut Context<Self>,
5335 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5336 if let Some((upstream_client, project_id)) = self.upstream_client() {
5337 let request = GetDefinitions { position };
5338 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5339 return Task::ready(Ok(None));
5340 }
5341 let request_task = upstream_client.request_lsp(
5342 project_id,
5343 None,
5344 LSP_REQUEST_TIMEOUT,
5345 cx.background_executor().clone(),
5346 request.to_proto(project_id, buffer.read(cx)),
5347 );
5348 let buffer = buffer.clone();
5349 cx.spawn(async move |weak_lsp_store, cx| {
5350 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5351 return Ok(None);
5352 };
5353 let Some(responses) = request_task.await? else {
5354 return Ok(None);
5355 };
5356 let actions = join_all(responses.payload.into_iter().map(|response| {
5357 GetDefinitions { position }.response_from_proto(
5358 response.response,
5359 lsp_store.clone(),
5360 buffer.clone(),
5361 cx.clone(),
5362 )
5363 }))
5364 .await;
5365
5366 Ok(Some(
5367 actions
5368 .into_iter()
5369 .collect::<Result<Vec<Vec<_>>>>()?
5370 .into_iter()
5371 .flatten()
5372 .dedup()
5373 .collect(),
5374 ))
5375 })
5376 } else {
5377 let definitions_task = self.request_multiple_lsp_locally(
5378 buffer,
5379 Some(position),
5380 GetDefinitions { position },
5381 cx,
5382 );
5383 cx.background_spawn(async move {
5384 Ok(Some(
5385 definitions_task
5386 .await
5387 .into_iter()
5388 .flat_map(|(_, definitions)| definitions)
5389 .dedup()
5390 .collect(),
5391 ))
5392 })
5393 }
5394 }
5395
5396 pub fn declarations(
5397 &mut self,
5398 buffer: &Entity<Buffer>,
5399 position: PointUtf16,
5400 cx: &mut Context<Self>,
5401 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5402 if let Some((upstream_client, project_id)) = self.upstream_client() {
5403 let request = GetDeclarations { position };
5404 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5405 return Task::ready(Ok(None));
5406 }
5407 let request_task = upstream_client.request_lsp(
5408 project_id,
5409 None,
5410 LSP_REQUEST_TIMEOUT,
5411 cx.background_executor().clone(),
5412 request.to_proto(project_id, buffer.read(cx)),
5413 );
5414 let buffer = buffer.clone();
5415 cx.spawn(async move |weak_lsp_store, cx| {
5416 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5417 return Ok(None);
5418 };
5419 let Some(responses) = request_task.await? else {
5420 return Ok(None);
5421 };
5422 let actions = join_all(responses.payload.into_iter().map(|response| {
5423 GetDeclarations { position }.response_from_proto(
5424 response.response,
5425 lsp_store.clone(),
5426 buffer.clone(),
5427 cx.clone(),
5428 )
5429 }))
5430 .await;
5431
5432 Ok(Some(
5433 actions
5434 .into_iter()
5435 .collect::<Result<Vec<Vec<_>>>>()?
5436 .into_iter()
5437 .flatten()
5438 .dedup()
5439 .collect(),
5440 ))
5441 })
5442 } else {
5443 let declarations_task = self.request_multiple_lsp_locally(
5444 buffer,
5445 Some(position),
5446 GetDeclarations { position },
5447 cx,
5448 );
5449 cx.background_spawn(async move {
5450 Ok(Some(
5451 declarations_task
5452 .await
5453 .into_iter()
5454 .flat_map(|(_, declarations)| declarations)
5455 .dedup()
5456 .collect(),
5457 ))
5458 })
5459 }
5460 }
5461
5462 pub fn type_definitions(
5463 &mut self,
5464 buffer: &Entity<Buffer>,
5465 position: PointUtf16,
5466 cx: &mut Context<Self>,
5467 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5468 if let Some((upstream_client, project_id)) = self.upstream_client() {
5469 let request = GetTypeDefinitions { position };
5470 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5471 return Task::ready(Ok(None));
5472 }
5473 let request_task = upstream_client.request_lsp(
5474 project_id,
5475 None,
5476 LSP_REQUEST_TIMEOUT,
5477 cx.background_executor().clone(),
5478 request.to_proto(project_id, buffer.read(cx)),
5479 );
5480 let buffer = buffer.clone();
5481 cx.spawn(async move |weak_lsp_store, cx| {
5482 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5483 return Ok(None);
5484 };
5485 let Some(responses) = request_task.await? else {
5486 return Ok(None);
5487 };
5488 let actions = join_all(responses.payload.into_iter().map(|response| {
5489 GetTypeDefinitions { position }.response_from_proto(
5490 response.response,
5491 lsp_store.clone(),
5492 buffer.clone(),
5493 cx.clone(),
5494 )
5495 }))
5496 .await;
5497
5498 Ok(Some(
5499 actions
5500 .into_iter()
5501 .collect::<Result<Vec<Vec<_>>>>()?
5502 .into_iter()
5503 .flatten()
5504 .dedup()
5505 .collect(),
5506 ))
5507 })
5508 } else {
5509 let type_definitions_task = self.request_multiple_lsp_locally(
5510 buffer,
5511 Some(position),
5512 GetTypeDefinitions { position },
5513 cx,
5514 );
5515 cx.background_spawn(async move {
5516 Ok(Some(
5517 type_definitions_task
5518 .await
5519 .into_iter()
5520 .flat_map(|(_, type_definitions)| type_definitions)
5521 .dedup()
5522 .collect(),
5523 ))
5524 })
5525 }
5526 }
5527
5528 pub fn implementations(
5529 &mut self,
5530 buffer: &Entity<Buffer>,
5531 position: PointUtf16,
5532 cx: &mut Context<Self>,
5533 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5534 if let Some((upstream_client, project_id)) = self.upstream_client() {
5535 let request = GetImplementations { position };
5536 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5537 return Task::ready(Ok(None));
5538 }
5539 let request_task = upstream_client.request_lsp(
5540 project_id,
5541 None,
5542 LSP_REQUEST_TIMEOUT,
5543 cx.background_executor().clone(),
5544 request.to_proto(project_id, buffer.read(cx)),
5545 );
5546 let buffer = buffer.clone();
5547 cx.spawn(async move |weak_lsp_store, cx| {
5548 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5549 return Ok(None);
5550 };
5551 let Some(responses) = request_task.await? else {
5552 return Ok(None);
5553 };
5554 let actions = join_all(responses.payload.into_iter().map(|response| {
5555 GetImplementations { position }.response_from_proto(
5556 response.response,
5557 lsp_store.clone(),
5558 buffer.clone(),
5559 cx.clone(),
5560 )
5561 }))
5562 .await;
5563
5564 Ok(Some(
5565 actions
5566 .into_iter()
5567 .collect::<Result<Vec<Vec<_>>>>()?
5568 .into_iter()
5569 .flatten()
5570 .dedup()
5571 .collect(),
5572 ))
5573 })
5574 } else {
5575 let implementations_task = self.request_multiple_lsp_locally(
5576 buffer,
5577 Some(position),
5578 GetImplementations { position },
5579 cx,
5580 );
5581 cx.background_spawn(async move {
5582 Ok(Some(
5583 implementations_task
5584 .await
5585 .into_iter()
5586 .flat_map(|(_, implementations)| implementations)
5587 .dedup()
5588 .collect(),
5589 ))
5590 })
5591 }
5592 }
5593
5594 pub fn references(
5595 &mut self,
5596 buffer: &Entity<Buffer>,
5597 position: PointUtf16,
5598 cx: &mut Context<Self>,
5599 ) -> Task<Result<Option<Vec<Location>>>> {
5600 if let Some((upstream_client, project_id)) = self.upstream_client() {
5601 let request = GetReferences { position };
5602 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5603 return Task::ready(Ok(None));
5604 }
5605
5606 let request_task = upstream_client.request_lsp(
5607 project_id,
5608 None,
5609 LSP_REQUEST_TIMEOUT,
5610 cx.background_executor().clone(),
5611 request.to_proto(project_id, buffer.read(cx)),
5612 );
5613 let buffer = buffer.clone();
5614 cx.spawn(async move |weak_lsp_store, cx| {
5615 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5616 return Ok(None);
5617 };
5618 let Some(responses) = request_task.await? else {
5619 return Ok(None);
5620 };
5621
5622 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5623 GetReferences { position }.response_from_proto(
5624 lsp_response.response,
5625 lsp_store.clone(),
5626 buffer.clone(),
5627 cx.clone(),
5628 )
5629 }))
5630 .await
5631 .into_iter()
5632 .collect::<Result<Vec<Vec<_>>>>()?
5633 .into_iter()
5634 .flatten()
5635 .dedup()
5636 .collect();
5637 Ok(Some(locations))
5638 })
5639 } else {
5640 let references_task = self.request_multiple_lsp_locally(
5641 buffer,
5642 Some(position),
5643 GetReferences { position },
5644 cx,
5645 );
5646 cx.background_spawn(async move {
5647 Ok(Some(
5648 references_task
5649 .await
5650 .into_iter()
5651 .flat_map(|(_, references)| references)
5652 .dedup()
5653 .collect(),
5654 ))
5655 })
5656 }
5657 }
5658
5659 pub fn code_actions(
5660 &mut self,
5661 buffer: &Entity<Buffer>,
5662 range: Range<Anchor>,
5663 kinds: Option<Vec<CodeActionKind>>,
5664 cx: &mut Context<Self>,
5665 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5666 if let Some((upstream_client, project_id)) = self.upstream_client() {
5667 let request = GetCodeActions {
5668 range: range.clone(),
5669 kinds: kinds.clone(),
5670 };
5671 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5672 return Task::ready(Ok(None));
5673 }
5674 let request_task = upstream_client.request_lsp(
5675 project_id,
5676 None,
5677 LSP_REQUEST_TIMEOUT,
5678 cx.background_executor().clone(),
5679 request.to_proto(project_id, buffer.read(cx)),
5680 );
5681 let buffer = buffer.clone();
5682 cx.spawn(async move |weak_lsp_store, cx| {
5683 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5684 return Ok(None);
5685 };
5686 let Some(responses) = request_task.await? else {
5687 return Ok(None);
5688 };
5689 let actions = join_all(responses.payload.into_iter().map(|response| {
5690 GetCodeActions {
5691 range: range.clone(),
5692 kinds: kinds.clone(),
5693 }
5694 .response_from_proto(
5695 response.response,
5696 lsp_store.clone(),
5697 buffer.clone(),
5698 cx.clone(),
5699 )
5700 }))
5701 .await;
5702
5703 Ok(Some(
5704 actions
5705 .into_iter()
5706 .collect::<Result<Vec<Vec<_>>>>()?
5707 .into_iter()
5708 .flatten()
5709 .collect(),
5710 ))
5711 })
5712 } else {
5713 let all_actions_task = self.request_multiple_lsp_locally(
5714 buffer,
5715 Some(range.start),
5716 GetCodeActions { range, kinds },
5717 cx,
5718 );
5719 cx.background_spawn(async move {
5720 Ok(Some(
5721 all_actions_task
5722 .await
5723 .into_iter()
5724 .flat_map(|(_, actions)| actions)
5725 .collect(),
5726 ))
5727 })
5728 }
5729 }
5730
5731 pub fn code_lens_actions(
5732 &mut self,
5733 buffer: &Entity<Buffer>,
5734 cx: &mut Context<Self>,
5735 ) -> CodeLensTask {
5736 let version_queried_for = buffer.read(cx).version();
5737 let buffer_id = buffer.read(cx).remote_id();
5738 let existing_servers = self.as_local().map(|local| {
5739 local
5740 .buffers_opened_in_servers
5741 .get(&buffer_id)
5742 .cloned()
5743 .unwrap_or_default()
5744 });
5745
5746 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5747 if let Some(cached_lens) = &lsp_data.code_lens {
5748 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5749 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5750 existing_servers != cached_lens.lens.keys().copied().collect()
5751 });
5752 if !has_different_servers {
5753 return Task::ready(Ok(Some(
5754 cached_lens.lens.values().flatten().cloned().collect(),
5755 )))
5756 .shared();
5757 }
5758 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5759 if !version_queried_for.changed_since(updating_for) {
5760 return running_update.clone();
5761 }
5762 }
5763 }
5764 }
5765
5766 let lens_lsp_data = self
5767 .latest_lsp_data(buffer, cx)
5768 .code_lens
5769 .get_or_insert_default();
5770 let buffer = buffer.clone();
5771 let query_version_queried_for = version_queried_for.clone();
5772 let new_task = cx
5773 .spawn(async move |lsp_store, cx| {
5774 cx.background_executor()
5775 .timer(Duration::from_millis(30))
5776 .await;
5777 let fetched_lens = lsp_store
5778 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5779 .map_err(Arc::new)?
5780 .await
5781 .context("fetching code lens")
5782 .map_err(Arc::new);
5783 let fetched_lens = match fetched_lens {
5784 Ok(fetched_lens) => fetched_lens,
5785 Err(e) => {
5786 lsp_store
5787 .update(cx, |lsp_store, _| {
5788 if let Some(lens_lsp_data) = lsp_store
5789 .lsp_data
5790 .get_mut(&buffer_id)
5791 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5792 {
5793 lens_lsp_data.update = None;
5794 }
5795 })
5796 .ok();
5797 return Err(e);
5798 }
5799 };
5800
5801 lsp_store
5802 .update(cx, |lsp_store, _| {
5803 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5804 let code_lens = lsp_data.code_lens.as_mut()?;
5805 if let Some(fetched_lens) = fetched_lens {
5806 if lsp_data.buffer_version == query_version_queried_for {
5807 code_lens.lens.extend(fetched_lens);
5808 } else if !lsp_data
5809 .buffer_version
5810 .changed_since(&query_version_queried_for)
5811 {
5812 lsp_data.buffer_version = query_version_queried_for;
5813 code_lens.lens = fetched_lens;
5814 }
5815 }
5816 code_lens.update = None;
5817 Some(code_lens.lens.values().flatten().cloned().collect())
5818 })
5819 .map_err(Arc::new)
5820 })
5821 .shared();
5822 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5823 new_task
5824 }
5825
5826 fn fetch_code_lens(
5827 &mut self,
5828 buffer: &Entity<Buffer>,
5829 cx: &mut Context<Self>,
5830 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5831 if let Some((upstream_client, project_id)) = self.upstream_client() {
5832 let request = GetCodeLens;
5833 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5834 return Task::ready(Ok(None));
5835 }
5836 let request_task = upstream_client.request_lsp(
5837 project_id,
5838 None,
5839 LSP_REQUEST_TIMEOUT,
5840 cx.background_executor().clone(),
5841 request.to_proto(project_id, buffer.read(cx)),
5842 );
5843 let buffer = buffer.clone();
5844 cx.spawn(async move |weak_lsp_store, cx| {
5845 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5846 return Ok(None);
5847 };
5848 let Some(responses) = request_task.await? else {
5849 return Ok(None);
5850 };
5851
5852 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5853 let lsp_store = lsp_store.clone();
5854 let buffer = buffer.clone();
5855 let cx = cx.clone();
5856 async move {
5857 (
5858 LanguageServerId::from_proto(response.server_id),
5859 GetCodeLens
5860 .response_from_proto(response.response, lsp_store, buffer, cx)
5861 .await,
5862 )
5863 }
5864 }))
5865 .await;
5866
5867 let mut has_errors = false;
5868 let code_lens_actions = code_lens_actions
5869 .into_iter()
5870 .filter_map(|(server_id, code_lens)| match code_lens {
5871 Ok(code_lens) => Some((server_id, code_lens)),
5872 Err(e) => {
5873 has_errors = true;
5874 log::error!("{e:#}");
5875 None
5876 }
5877 })
5878 .collect::<HashMap<_, _>>();
5879 anyhow::ensure!(
5880 !has_errors || !code_lens_actions.is_empty(),
5881 "Failed to fetch code lens"
5882 );
5883 Ok(Some(code_lens_actions))
5884 })
5885 } else {
5886 let code_lens_actions_task =
5887 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5888 cx.background_spawn(async move {
5889 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5890 })
5891 }
5892 }
5893
5894 #[inline(never)]
5895 pub fn completions(
5896 &self,
5897 buffer: &Entity<Buffer>,
5898 position: PointUtf16,
5899 context: CompletionContext,
5900 cx: &mut Context<Self>,
5901 ) -> Task<Result<Vec<CompletionResponse>>> {
5902 let language_registry = self.languages.clone();
5903
5904 if let Some((upstream_client, project_id)) = self.upstream_client() {
5905 let request = GetCompletions { position, context };
5906 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5907 return Task::ready(Ok(Vec::new()));
5908 }
5909 let task = self.send_lsp_proto_request(
5910 buffer.clone(),
5911 upstream_client,
5912 project_id,
5913 request,
5914 cx,
5915 );
5916 let language = buffer.read(cx).language().cloned();
5917
5918 // In the future, we should provide project guests with the names of LSP adapters,
5919 // so that they can use the correct LSP adapter when computing labels. For now,
5920 // guests just use the first LSP adapter associated with the buffer's language.
5921 let lsp_adapter = language.as_ref().and_then(|language| {
5922 language_registry
5923 .lsp_adapters(&language.name())
5924 .first()
5925 .cloned()
5926 });
5927
5928 cx.foreground_executor().spawn(async move {
5929 let completion_response = task.await?;
5930 let completions = populate_labels_for_completions(
5931 completion_response.completions,
5932 language,
5933 lsp_adapter,
5934 )
5935 .await;
5936 Ok(vec![CompletionResponse {
5937 completions,
5938 display_options: CompletionDisplayOptions::default(),
5939 is_incomplete: completion_response.is_incomplete,
5940 }])
5941 })
5942 } else if let Some(local) = self.as_local() {
5943 let snapshot = buffer.read(cx).snapshot();
5944 let offset = position.to_offset(&snapshot);
5945 let scope = snapshot.language_scope_at(offset);
5946 let language = snapshot.language().cloned();
5947 let completion_settings = language_settings(
5948 language.as_ref().map(|language| language.name()),
5949 buffer.read(cx).file(),
5950 cx,
5951 )
5952 .completions
5953 .clone();
5954 if !completion_settings.lsp {
5955 return Task::ready(Ok(Vec::new()));
5956 }
5957
5958 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5959 local
5960 .language_servers_for_buffer(buffer, cx)
5961 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5962 .filter(|(adapter, _)| {
5963 scope
5964 .as_ref()
5965 .map(|scope| scope.language_allowed(&adapter.name))
5966 .unwrap_or(true)
5967 })
5968 .map(|(_, server)| server.server_id())
5969 .collect()
5970 });
5971
5972 let buffer = buffer.clone();
5973 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5974 let lsp_timeout = if lsp_timeout > 0 {
5975 Some(Duration::from_millis(lsp_timeout))
5976 } else {
5977 None
5978 };
5979 cx.spawn(async move |this, cx| {
5980 let mut tasks = Vec::with_capacity(server_ids.len());
5981 this.update(cx, |lsp_store, cx| {
5982 for server_id in server_ids {
5983 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5984 let lsp_timeout = lsp_timeout
5985 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5986 let mut timeout = cx.background_spawn(async move {
5987 match lsp_timeout {
5988 Some(lsp_timeout) => {
5989 lsp_timeout.await;
5990 true
5991 },
5992 None => false,
5993 }
5994 }).fuse();
5995 let mut lsp_request = lsp_store.request_lsp(
5996 buffer.clone(),
5997 LanguageServerToQuery::Other(server_id),
5998 GetCompletions {
5999 position,
6000 context: context.clone(),
6001 },
6002 cx,
6003 ).fuse();
6004 let new_task = cx.background_spawn(async move {
6005 select_biased! {
6006 response = lsp_request => anyhow::Ok(Some(response?)),
6007 timeout_happened = timeout => {
6008 if timeout_happened {
6009 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6010 Ok(None)
6011 } else {
6012 let completions = lsp_request.await?;
6013 Ok(Some(completions))
6014 }
6015 },
6016 }
6017 });
6018 tasks.push((lsp_adapter, new_task));
6019 }
6020 })?;
6021
6022 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6023 let completion_response = task.await.ok()??;
6024 let completions = populate_labels_for_completions(
6025 completion_response.completions,
6026 language.clone(),
6027 lsp_adapter,
6028 )
6029 .await;
6030 Some(CompletionResponse {
6031 completions,
6032 display_options: CompletionDisplayOptions::default(),
6033 is_incomplete: completion_response.is_incomplete,
6034 })
6035 });
6036
6037 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6038
6039 Ok(responses.into_iter().flatten().collect())
6040 })
6041 } else {
6042 Task::ready(Err(anyhow!("No upstream client or local language server")))
6043 }
6044 }
6045
6046 pub fn resolve_completions(
6047 &self,
6048 buffer: Entity<Buffer>,
6049 completion_indices: Vec<usize>,
6050 completions: Rc<RefCell<Box<[Completion]>>>,
6051 cx: &mut Context<Self>,
6052 ) -> Task<Result<bool>> {
6053 let client = self.upstream_client();
6054 let buffer_id = buffer.read(cx).remote_id();
6055 let buffer_snapshot = buffer.read(cx).snapshot();
6056
6057 if !self.check_if_capable_for_proto_request(
6058 &buffer,
6059 GetCompletions::can_resolve_completions,
6060 cx,
6061 ) {
6062 return Task::ready(Ok(false));
6063 }
6064 cx.spawn(async move |lsp_store, cx| {
6065 let mut did_resolve = false;
6066 if let Some((client, project_id)) = client {
6067 for completion_index in completion_indices {
6068 let server_id = {
6069 let completion = &completions.borrow()[completion_index];
6070 completion.source.server_id()
6071 };
6072 if let Some(server_id) = server_id {
6073 if Self::resolve_completion_remote(
6074 project_id,
6075 server_id,
6076 buffer_id,
6077 completions.clone(),
6078 completion_index,
6079 client.clone(),
6080 )
6081 .await
6082 .log_err()
6083 .is_some()
6084 {
6085 did_resolve = true;
6086 }
6087 } else {
6088 resolve_word_completion(
6089 &buffer_snapshot,
6090 &mut completions.borrow_mut()[completion_index],
6091 );
6092 }
6093 }
6094 } else {
6095 for completion_index in completion_indices {
6096 let server_id = {
6097 let completion = &completions.borrow()[completion_index];
6098 completion.source.server_id()
6099 };
6100 if let Some(server_id) = server_id {
6101 let server_and_adapter = lsp_store
6102 .read_with(cx, |lsp_store, _| {
6103 let server = lsp_store.language_server_for_id(server_id)?;
6104 let adapter =
6105 lsp_store.language_server_adapter_for_id(server.server_id())?;
6106 Some((server, adapter))
6107 })
6108 .ok()
6109 .flatten();
6110 let Some((server, adapter)) = server_and_adapter else {
6111 continue;
6112 };
6113
6114 let resolved = Self::resolve_completion_local(
6115 server,
6116 completions.clone(),
6117 completion_index,
6118 )
6119 .await
6120 .log_err()
6121 .is_some();
6122 if resolved {
6123 Self::regenerate_completion_labels(
6124 adapter,
6125 &buffer_snapshot,
6126 completions.clone(),
6127 completion_index,
6128 )
6129 .await
6130 .log_err();
6131 did_resolve = true;
6132 }
6133 } else {
6134 resolve_word_completion(
6135 &buffer_snapshot,
6136 &mut completions.borrow_mut()[completion_index],
6137 );
6138 }
6139 }
6140 }
6141
6142 Ok(did_resolve)
6143 })
6144 }
6145
6146 async fn resolve_completion_local(
6147 server: Arc<lsp::LanguageServer>,
6148 completions: Rc<RefCell<Box<[Completion]>>>,
6149 completion_index: usize,
6150 ) -> Result<()> {
6151 let server_id = server.server_id();
6152 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6153 return Ok(());
6154 }
6155
6156 let request = {
6157 let completion = &completions.borrow()[completion_index];
6158 match &completion.source {
6159 CompletionSource::Lsp {
6160 lsp_completion,
6161 resolved,
6162 server_id: completion_server_id,
6163 ..
6164 } => {
6165 if *resolved {
6166 return Ok(());
6167 }
6168 anyhow::ensure!(
6169 server_id == *completion_server_id,
6170 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6171 );
6172 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6173 }
6174 CompletionSource::BufferWord { .. }
6175 | CompletionSource::Dap { .. }
6176 | CompletionSource::Custom => {
6177 return Ok(());
6178 }
6179 }
6180 };
6181 let resolved_completion = request
6182 .await
6183 .into_response()
6184 .context("resolve completion")?;
6185
6186 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6187 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6188
6189 let mut completions = completions.borrow_mut();
6190 let completion = &mut completions[completion_index];
6191 if let CompletionSource::Lsp {
6192 lsp_completion,
6193 resolved,
6194 server_id: completion_server_id,
6195 ..
6196 } = &mut completion.source
6197 {
6198 if *resolved {
6199 return Ok(());
6200 }
6201 anyhow::ensure!(
6202 server_id == *completion_server_id,
6203 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6204 );
6205 *lsp_completion = Box::new(resolved_completion);
6206 *resolved = true;
6207 }
6208 Ok(())
6209 }
6210
6211 async fn regenerate_completion_labels(
6212 adapter: Arc<CachedLspAdapter>,
6213 snapshot: &BufferSnapshot,
6214 completions: Rc<RefCell<Box<[Completion]>>>,
6215 completion_index: usize,
6216 ) -> Result<()> {
6217 let completion_item = completions.borrow()[completion_index]
6218 .source
6219 .lsp_completion(true)
6220 .map(Cow::into_owned);
6221 if let Some(lsp_documentation) = completion_item
6222 .as_ref()
6223 .and_then(|completion_item| completion_item.documentation.clone())
6224 {
6225 let mut completions = completions.borrow_mut();
6226 let completion = &mut completions[completion_index];
6227 completion.documentation = Some(lsp_documentation.into());
6228 } else {
6229 let mut completions = completions.borrow_mut();
6230 let completion = &mut completions[completion_index];
6231 completion.documentation = Some(CompletionDocumentation::Undocumented);
6232 }
6233
6234 let mut new_label = match completion_item {
6235 Some(completion_item) => {
6236 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6237 // So we have to update the label here anyway...
6238 let language = snapshot.language();
6239 match language {
6240 Some(language) => {
6241 adapter
6242 .labels_for_completions(
6243 std::slice::from_ref(&completion_item),
6244 language,
6245 )
6246 .await?
6247 }
6248 None => Vec::new(),
6249 }
6250 .pop()
6251 .flatten()
6252 .unwrap_or_else(|| {
6253 CodeLabel::fallback_for_completion(
6254 &completion_item,
6255 language.map(|language| language.as_ref()),
6256 )
6257 })
6258 }
6259 None => CodeLabel::plain(
6260 completions.borrow()[completion_index].new_text.clone(),
6261 None,
6262 ),
6263 };
6264 ensure_uniform_list_compatible_label(&mut new_label);
6265
6266 let mut completions = completions.borrow_mut();
6267 let completion = &mut completions[completion_index];
6268 if completion.label.filter_text() == new_label.filter_text() {
6269 completion.label = new_label;
6270 } else {
6271 log::error!(
6272 "Resolved completion changed display label from {} to {}. \
6273 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6274 completion.label.text(),
6275 new_label.text(),
6276 completion.label.filter_text(),
6277 new_label.filter_text()
6278 );
6279 }
6280
6281 Ok(())
6282 }
6283
6284 async fn resolve_completion_remote(
6285 project_id: u64,
6286 server_id: LanguageServerId,
6287 buffer_id: BufferId,
6288 completions: Rc<RefCell<Box<[Completion]>>>,
6289 completion_index: usize,
6290 client: AnyProtoClient,
6291 ) -> Result<()> {
6292 let lsp_completion = {
6293 let completion = &completions.borrow()[completion_index];
6294 match &completion.source {
6295 CompletionSource::Lsp {
6296 lsp_completion,
6297 resolved,
6298 server_id: completion_server_id,
6299 ..
6300 } => {
6301 anyhow::ensure!(
6302 server_id == *completion_server_id,
6303 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6304 );
6305 if *resolved {
6306 return Ok(());
6307 }
6308 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6309 }
6310 CompletionSource::Custom
6311 | CompletionSource::Dap { .. }
6312 | CompletionSource::BufferWord { .. } => {
6313 return Ok(());
6314 }
6315 }
6316 };
6317 let request = proto::ResolveCompletionDocumentation {
6318 project_id,
6319 language_server_id: server_id.0 as u64,
6320 lsp_completion,
6321 buffer_id: buffer_id.into(),
6322 };
6323
6324 let response = client
6325 .request(request)
6326 .await
6327 .context("completion documentation resolve proto request")?;
6328 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6329
6330 let documentation = if response.documentation.is_empty() {
6331 CompletionDocumentation::Undocumented
6332 } else if response.documentation_is_markdown {
6333 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6334 } else if response.documentation.lines().count() <= 1 {
6335 CompletionDocumentation::SingleLine(response.documentation.into())
6336 } else {
6337 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6338 };
6339
6340 let mut completions = completions.borrow_mut();
6341 let completion = &mut completions[completion_index];
6342 completion.documentation = Some(documentation);
6343 if let CompletionSource::Lsp {
6344 insert_range,
6345 lsp_completion,
6346 resolved,
6347 server_id: completion_server_id,
6348 lsp_defaults: _,
6349 } = &mut completion.source
6350 {
6351 let completion_insert_range = response
6352 .old_insert_start
6353 .and_then(deserialize_anchor)
6354 .zip(response.old_insert_end.and_then(deserialize_anchor));
6355 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6356
6357 if *resolved {
6358 return Ok(());
6359 }
6360 anyhow::ensure!(
6361 server_id == *completion_server_id,
6362 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6363 );
6364 *lsp_completion = Box::new(resolved_lsp_completion);
6365 *resolved = true;
6366 }
6367
6368 let replace_range = response
6369 .old_replace_start
6370 .and_then(deserialize_anchor)
6371 .zip(response.old_replace_end.and_then(deserialize_anchor));
6372 if let Some((old_replace_start, old_replace_end)) = replace_range
6373 && !response.new_text.is_empty()
6374 {
6375 completion.new_text = response.new_text;
6376 completion.replace_range = old_replace_start..old_replace_end;
6377 }
6378
6379 Ok(())
6380 }
6381
6382 pub fn apply_additional_edits_for_completion(
6383 &self,
6384 buffer_handle: Entity<Buffer>,
6385 completions: Rc<RefCell<Box<[Completion]>>>,
6386 completion_index: usize,
6387 push_to_history: bool,
6388 cx: &mut Context<Self>,
6389 ) -> Task<Result<Option<Transaction>>> {
6390 if let Some((client, project_id)) = self.upstream_client() {
6391 let buffer = buffer_handle.read(cx);
6392 let buffer_id = buffer.remote_id();
6393 cx.spawn(async move |_, cx| {
6394 let request = {
6395 let completion = completions.borrow()[completion_index].clone();
6396 proto::ApplyCompletionAdditionalEdits {
6397 project_id,
6398 buffer_id: buffer_id.into(),
6399 completion: Some(Self::serialize_completion(&CoreCompletion {
6400 replace_range: completion.replace_range,
6401 new_text: completion.new_text,
6402 source: completion.source,
6403 })),
6404 }
6405 };
6406
6407 if let Some(transaction) = client.request(request).await?.transaction {
6408 let transaction = language::proto::deserialize_transaction(transaction)?;
6409 buffer_handle
6410 .update(cx, |buffer, _| {
6411 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6412 })?
6413 .await?;
6414 if push_to_history {
6415 buffer_handle.update(cx, |buffer, _| {
6416 buffer.push_transaction(transaction.clone(), Instant::now());
6417 buffer.finalize_last_transaction();
6418 })?;
6419 }
6420 Ok(Some(transaction))
6421 } else {
6422 Ok(None)
6423 }
6424 })
6425 } else {
6426 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6427 let completion = &completions.borrow()[completion_index];
6428 let server_id = completion.source.server_id()?;
6429 Some(
6430 self.language_server_for_local_buffer(buffer, server_id, cx)?
6431 .1
6432 .clone(),
6433 )
6434 }) else {
6435 return Task::ready(Ok(None));
6436 };
6437
6438 cx.spawn(async move |this, cx| {
6439 Self::resolve_completion_local(
6440 server.clone(),
6441 completions.clone(),
6442 completion_index,
6443 )
6444 .await
6445 .context("resolving completion")?;
6446 let completion = completions.borrow()[completion_index].clone();
6447 let additional_text_edits = completion
6448 .source
6449 .lsp_completion(true)
6450 .as_ref()
6451 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6452 if let Some(edits) = additional_text_edits {
6453 let edits = this
6454 .update(cx, |this, cx| {
6455 this.as_local_mut().unwrap().edits_from_lsp(
6456 &buffer_handle,
6457 edits,
6458 server.server_id(),
6459 None,
6460 cx,
6461 )
6462 })?
6463 .await?;
6464
6465 buffer_handle.update(cx, |buffer, cx| {
6466 buffer.finalize_last_transaction();
6467 buffer.start_transaction();
6468
6469 for (range, text) in edits {
6470 let primary = &completion.replace_range;
6471
6472 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6473 // and the primary completion is just an insertion (empty range), then this is likely
6474 // an auto-import scenario and should not be considered overlapping
6475 // https://github.com/zed-industries/zed/issues/26136
6476 let is_file_start_auto_import = {
6477 let snapshot = buffer.snapshot();
6478 let primary_start_point = primary.start.to_point(&snapshot);
6479 let range_start_point = range.start.to_point(&snapshot);
6480
6481 let result = primary_start_point.row == 0
6482 && primary_start_point.column == 0
6483 && range_start_point.row == 0
6484 && range_start_point.column == 0;
6485
6486 result
6487 };
6488
6489 let has_overlap = if is_file_start_auto_import {
6490 false
6491 } else {
6492 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6493 && primary.end.cmp(&range.start, buffer).is_ge();
6494 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6495 && range.end.cmp(&primary.end, buffer).is_ge();
6496 let result = start_within || end_within;
6497 result
6498 };
6499
6500 //Skip additional edits which overlap with the primary completion edit
6501 //https://github.com/zed-industries/zed/pull/1871
6502 if !has_overlap {
6503 buffer.edit([(range, text)], None, cx);
6504 }
6505 }
6506
6507 let transaction = if buffer.end_transaction(cx).is_some() {
6508 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6509 if !push_to_history {
6510 buffer.forget_transaction(transaction.id);
6511 }
6512 Some(transaction)
6513 } else {
6514 None
6515 };
6516 Ok(transaction)
6517 })?
6518 } else {
6519 Ok(None)
6520 }
6521 })
6522 }
6523 }
6524
6525 pub fn pull_diagnostics(
6526 &mut self,
6527 buffer: Entity<Buffer>,
6528 cx: &mut Context<Self>,
6529 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6530 let buffer_id = buffer.read(cx).remote_id();
6531
6532 if let Some((client, upstream_project_id)) = self.upstream_client() {
6533 let mut suitable_capabilities = None;
6534 // Are we capable for proto request?
6535 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6536 &buffer,
6537 |capabilities| {
6538 if let Some(caps) = &capabilities.diagnostic_provider {
6539 suitable_capabilities = Some(caps.clone());
6540 true
6541 } else {
6542 false
6543 }
6544 },
6545 cx,
6546 );
6547 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6548 let Some(dynamic_caps) = suitable_capabilities else {
6549 return Task::ready(Ok(None));
6550 };
6551 assert!(any_server_has_diagnostics_provider);
6552
6553 let request = GetDocumentDiagnostics {
6554 previous_result_id: None,
6555 dynamic_caps,
6556 };
6557 let request_task = client.request_lsp(
6558 upstream_project_id,
6559 None,
6560 LSP_REQUEST_TIMEOUT,
6561 cx.background_executor().clone(),
6562 request.to_proto(upstream_project_id, buffer.read(cx)),
6563 );
6564 cx.background_spawn(async move {
6565 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6566 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6567 // Do not attempt to further process the dummy responses here.
6568 let _response = request_task.await?;
6569 Ok(None)
6570 })
6571 } else {
6572 let servers = buffer.update(cx, |buffer, cx| {
6573 self.language_servers_for_local_buffer(buffer, cx)
6574 .map(|(_, server)| server.clone())
6575 .collect::<Vec<_>>()
6576 });
6577
6578 let pull_diagnostics = servers
6579 .into_iter()
6580 .flat_map(|server| {
6581 let result = maybe!({
6582 let local = self.as_local()?;
6583 let server_id = server.server_id();
6584 let providers_with_identifiers = local
6585 .language_server_dynamic_registrations
6586 .get(&server_id)
6587 .into_iter()
6588 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6589 .collect::<Vec<_>>();
6590 Some(
6591 providers_with_identifiers
6592 .into_iter()
6593 .map(|dynamic_caps| {
6594 let result_id = self.result_id(server_id, buffer_id, cx);
6595 self.request_lsp(
6596 buffer.clone(),
6597 LanguageServerToQuery::Other(server_id),
6598 GetDocumentDiagnostics {
6599 previous_result_id: result_id,
6600 dynamic_caps,
6601 },
6602 cx,
6603 )
6604 })
6605 .collect::<Vec<_>>(),
6606 )
6607 });
6608
6609 result.unwrap_or_default()
6610 })
6611 .collect::<Vec<_>>();
6612
6613 cx.background_spawn(async move {
6614 let mut responses = Vec::new();
6615 for diagnostics in join_all(pull_diagnostics).await {
6616 responses.extend(diagnostics?);
6617 }
6618 Ok(Some(responses))
6619 })
6620 }
6621 }
6622
6623 pub fn applicable_inlay_chunks(
6624 &mut self,
6625 buffer: &Entity<Buffer>,
6626 ranges: &[Range<text::Anchor>],
6627 cx: &mut Context<Self>,
6628 ) -> Vec<Range<BufferRow>> {
6629 self.latest_lsp_data(buffer, cx)
6630 .inlay_hints
6631 .applicable_chunks(ranges)
6632 .map(|chunk| chunk.start..chunk.end)
6633 .collect()
6634 }
6635
6636 pub fn invalidate_inlay_hints<'a>(
6637 &'a mut self,
6638 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6639 ) {
6640 for buffer_id in for_buffers {
6641 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6642 lsp_data.inlay_hints.clear();
6643 }
6644 }
6645 }
6646
6647 pub fn inlay_hints(
6648 &mut self,
6649 invalidate: InvalidationStrategy,
6650 buffer: Entity<Buffer>,
6651 ranges: Vec<Range<text::Anchor>>,
6652 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6653 cx: &mut Context<Self>,
6654 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6655 let buffer_snapshot = buffer.read(cx).snapshot();
6656 let next_hint_id = self.next_hint_id.clone();
6657 let lsp_data = self.latest_lsp_data(&buffer, cx);
6658 let mut lsp_refresh_requested = false;
6659 let for_server = if let InvalidationStrategy::RefreshRequested {
6660 server_id,
6661 request_id,
6662 } = invalidate
6663 {
6664 let invalidated = lsp_data
6665 .inlay_hints
6666 .invalidate_for_server_refresh(server_id, request_id);
6667 lsp_refresh_requested = invalidated;
6668 Some(server_id)
6669 } else {
6670 None
6671 };
6672 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6673 let known_chunks = known_chunks
6674 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6675 .map(|(_, known_chunks)| known_chunks)
6676 .unwrap_or_default();
6677
6678 let mut hint_fetch_tasks = Vec::new();
6679 let mut cached_inlay_hints = None;
6680 let mut ranges_to_query = None;
6681 let applicable_chunks = existing_inlay_hints
6682 .applicable_chunks(ranges.as_slice())
6683 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6684 .collect::<Vec<_>>();
6685 if applicable_chunks.is_empty() {
6686 return HashMap::default();
6687 }
6688
6689 let last_chunk_number = existing_inlay_hints.buffer_chunks_len() - 1;
6690
6691 for row_chunk in applicable_chunks {
6692 match (
6693 existing_inlay_hints
6694 .cached_hints(&row_chunk)
6695 .filter(|_| !lsp_refresh_requested)
6696 .cloned(),
6697 existing_inlay_hints
6698 .fetched_hints(&row_chunk)
6699 .as_ref()
6700 .filter(|_| !lsp_refresh_requested)
6701 .cloned(),
6702 ) {
6703 (None, None) => {
6704 let end = if last_chunk_number == row_chunk.id {
6705 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6706 } else {
6707 Point::new(row_chunk.end, 0)
6708 };
6709 ranges_to_query.get_or_insert_with(Vec::new).push((
6710 row_chunk,
6711 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6712 ..buffer_snapshot.anchor_after(end),
6713 ));
6714 }
6715 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6716 (Some(cached_hints), None) => {
6717 for (server_id, cached_hints) in cached_hints {
6718 if for_server.is_none_or(|for_server| for_server == server_id) {
6719 cached_inlay_hints
6720 .get_or_insert_with(HashMap::default)
6721 .entry(row_chunk.start..row_chunk.end)
6722 .or_insert_with(HashMap::default)
6723 .entry(server_id)
6724 .or_insert_with(Vec::new)
6725 .extend(cached_hints);
6726 }
6727 }
6728 }
6729 (Some(cached_hints), Some(fetched_hints)) => {
6730 hint_fetch_tasks.push((row_chunk, fetched_hints));
6731 for (server_id, cached_hints) in cached_hints {
6732 if for_server.is_none_or(|for_server| for_server == server_id) {
6733 cached_inlay_hints
6734 .get_or_insert_with(HashMap::default)
6735 .entry(row_chunk.start..row_chunk.end)
6736 .or_insert_with(HashMap::default)
6737 .entry(server_id)
6738 .or_insert_with(Vec::new)
6739 .extend(cached_hints);
6740 }
6741 }
6742 }
6743 }
6744 }
6745
6746 if hint_fetch_tasks.is_empty()
6747 && ranges_to_query
6748 .as_ref()
6749 .is_none_or(|ranges| ranges.is_empty())
6750 && let Some(cached_inlay_hints) = cached_inlay_hints
6751 {
6752 cached_inlay_hints
6753 .into_iter()
6754 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6755 .collect()
6756 } else {
6757 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6758 let next_hint_id = next_hint_id.clone();
6759 let buffer = buffer.clone();
6760 let new_inlay_hints = cx
6761 .spawn(async move |lsp_store, cx| {
6762 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6763 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6764 })?;
6765 new_fetch_task
6766 .await
6767 .and_then(|new_hints_by_server| {
6768 lsp_store.update(cx, |lsp_store, cx| {
6769 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6770 let update_cache = !lsp_data
6771 .buffer_version
6772 .changed_since(&buffer.read(cx).version());
6773 if new_hints_by_server.is_empty() {
6774 if update_cache {
6775 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6776 }
6777 HashMap::default()
6778 } else {
6779 new_hints_by_server
6780 .into_iter()
6781 .map(|(server_id, new_hints)| {
6782 let new_hints = new_hints
6783 .into_iter()
6784 .map(|new_hint| {
6785 (
6786 InlayId::Hint(next_hint_id.fetch_add(
6787 1,
6788 atomic::Ordering::AcqRel,
6789 )),
6790 new_hint,
6791 )
6792 })
6793 .collect::<Vec<_>>();
6794 if update_cache {
6795 lsp_data.inlay_hints.insert_new_hints(
6796 chunk,
6797 server_id,
6798 new_hints.clone(),
6799 );
6800 }
6801 (server_id, new_hints)
6802 })
6803 .collect()
6804 }
6805 })
6806 })
6807 .map_err(Arc::new)
6808 })
6809 .shared();
6810
6811 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6812 *fetch_task = Some(new_inlay_hints.clone());
6813 hint_fetch_tasks.push((chunk, new_inlay_hints));
6814 }
6815
6816 cached_inlay_hints
6817 .unwrap_or_default()
6818 .into_iter()
6819 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6820 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6821 (
6822 chunk.start..chunk.end,
6823 cx.spawn(async move |_, _| {
6824 hints_fetch.await.map_err(|e| {
6825 if e.error_code() != ErrorCode::Internal {
6826 anyhow!(e.error_code())
6827 } else {
6828 anyhow!("{e:#}")
6829 }
6830 })
6831 }),
6832 )
6833 }))
6834 .collect()
6835 }
6836 }
6837
6838 fn fetch_inlay_hints(
6839 &mut self,
6840 for_server: Option<LanguageServerId>,
6841 buffer: &Entity<Buffer>,
6842 range: Range<Anchor>,
6843 cx: &mut Context<Self>,
6844 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6845 let request = InlayHints {
6846 range: range.clone(),
6847 };
6848 if let Some((upstream_client, project_id)) = self.upstream_client() {
6849 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6850 return Task::ready(Ok(HashMap::default()));
6851 }
6852 let request_task = upstream_client.request_lsp(
6853 project_id,
6854 for_server.map(|id| id.to_proto()),
6855 LSP_REQUEST_TIMEOUT,
6856 cx.background_executor().clone(),
6857 request.to_proto(project_id, buffer.read(cx)),
6858 );
6859 let buffer = buffer.clone();
6860 cx.spawn(async move |weak_lsp_store, cx| {
6861 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6862 return Ok(HashMap::default());
6863 };
6864 let Some(responses) = request_task.await? else {
6865 return Ok(HashMap::default());
6866 };
6867
6868 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6869 let lsp_store = lsp_store.clone();
6870 let buffer = buffer.clone();
6871 let cx = cx.clone();
6872 let request = request.clone();
6873 async move {
6874 (
6875 LanguageServerId::from_proto(response.server_id),
6876 request
6877 .response_from_proto(response.response, lsp_store, buffer, cx)
6878 .await,
6879 )
6880 }
6881 }))
6882 .await;
6883
6884 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
6885 let mut has_errors = false;
6886 let inlay_hints = inlay_hints
6887 .into_iter()
6888 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6889 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6890 Err(e) => {
6891 has_errors = true;
6892 log::error!("{e:#}");
6893 None
6894 }
6895 })
6896 .map(|(server_id, mut new_hints)| {
6897 new_hints.retain(|hint| {
6898 hint.position.is_valid(&buffer_snapshot)
6899 && range.start.is_valid(&buffer_snapshot)
6900 && range.end.is_valid(&buffer_snapshot)
6901 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6902 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6903 });
6904 (server_id, new_hints)
6905 })
6906 .collect::<HashMap<_, _>>();
6907 anyhow::ensure!(
6908 !has_errors || !inlay_hints.is_empty(),
6909 "Failed to fetch inlay hints"
6910 );
6911 Ok(inlay_hints)
6912 })
6913 } else {
6914 let inlay_hints_task = match for_server {
6915 Some(server_id) => {
6916 let server_task = self.request_lsp(
6917 buffer.clone(),
6918 LanguageServerToQuery::Other(server_id),
6919 request,
6920 cx,
6921 );
6922 cx.background_spawn(async move {
6923 let mut responses = Vec::new();
6924 match server_task.await {
6925 Ok(response) => responses.push((server_id, response)),
6926 // rust-analyzer likes to error with this when its still loading up
6927 Err(e) if format!("{e:#}").ends_with("content modified") => (),
6928 Err(e) => log::error!(
6929 "Error handling response for inlay hints request: {e:#}"
6930 ),
6931 }
6932 responses
6933 })
6934 }
6935 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6936 };
6937 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6938 cx.background_spawn(async move {
6939 Ok(inlay_hints_task
6940 .await
6941 .into_iter()
6942 .map(|(server_id, mut new_hints)| {
6943 new_hints.retain(|hint| {
6944 hint.position.is_valid(&buffer_snapshot)
6945 && range.start.is_valid(&buffer_snapshot)
6946 && range.end.is_valid(&buffer_snapshot)
6947 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6948 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6949 });
6950 (server_id, new_hints)
6951 })
6952 .collect())
6953 })
6954 }
6955 }
6956
6957 pub fn pull_diagnostics_for_buffer(
6958 &mut self,
6959 buffer: Entity<Buffer>,
6960 cx: &mut Context<Self>,
6961 ) -> Task<anyhow::Result<()>> {
6962 let diagnostics = self.pull_diagnostics(buffer, cx);
6963 cx.spawn(async move |lsp_store, cx| {
6964 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6965 return Ok(());
6966 };
6967 lsp_store.update(cx, |lsp_store, cx| {
6968 if lsp_store.as_local().is_none() {
6969 return;
6970 }
6971
6972 let mut unchanged_buffers = HashSet::default();
6973 let mut changed_buffers = HashSet::default();
6974 let server_diagnostics_updates = diagnostics
6975 .into_iter()
6976 .filter_map(|diagnostics_set| match diagnostics_set {
6977 LspPullDiagnostics::Response {
6978 server_id,
6979 uri,
6980 diagnostics,
6981 } => Some((server_id, uri, diagnostics)),
6982 LspPullDiagnostics::Default => None,
6983 })
6984 .fold(
6985 HashMap::default(),
6986 |mut acc, (server_id, uri, diagnostics)| {
6987 let (result_id, diagnostics) = match diagnostics {
6988 PulledDiagnostics::Unchanged { result_id } => {
6989 unchanged_buffers.insert(uri.clone());
6990 (Some(result_id), Vec::new())
6991 }
6992 PulledDiagnostics::Changed {
6993 result_id,
6994 diagnostics,
6995 } => {
6996 changed_buffers.insert(uri.clone());
6997 (result_id, diagnostics)
6998 }
6999 };
7000 let disk_based_sources = Cow::Owned(
7001 lsp_store
7002 .language_server_adapter_for_id(server_id)
7003 .as_ref()
7004 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7005 .unwrap_or(&[])
7006 .to_vec(),
7007 );
7008 acc.entry(server_id).or_insert_with(Vec::new).push(
7009 DocumentDiagnosticsUpdate {
7010 server_id,
7011 diagnostics: lsp::PublishDiagnosticsParams {
7012 uri,
7013 diagnostics,
7014 version: None,
7015 },
7016 result_id,
7017 disk_based_sources,
7018 },
7019 );
7020 acc
7021 },
7022 );
7023
7024 for diagnostic_updates in server_diagnostics_updates.into_values() {
7025 lsp_store
7026 .merge_lsp_diagnostics(
7027 DiagnosticSourceKind::Pulled,
7028 diagnostic_updates,
7029 |buffer, old_diagnostic, cx| {
7030 File::from_dyn(buffer.file())
7031 .and_then(|file| {
7032 let abs_path = file.as_local()?.abs_path(cx);
7033 lsp::Uri::from_file_path(abs_path).ok()
7034 })
7035 .is_none_or(|buffer_uri| {
7036 unchanged_buffers.contains(&buffer_uri)
7037 || match old_diagnostic.source_kind {
7038 DiagnosticSourceKind::Pulled => {
7039 !changed_buffers.contains(&buffer_uri)
7040 }
7041 DiagnosticSourceKind::Other
7042 | DiagnosticSourceKind::Pushed => true,
7043 }
7044 })
7045 },
7046 cx,
7047 )
7048 .log_err();
7049 }
7050 })
7051 })
7052 }
7053
7054 pub fn document_colors(
7055 &mut self,
7056 known_cache_version: Option<usize>,
7057 buffer: Entity<Buffer>,
7058 cx: &mut Context<Self>,
7059 ) -> Option<DocumentColorTask> {
7060 let version_queried_for = buffer.read(cx).version();
7061 let buffer_id = buffer.read(cx).remote_id();
7062
7063 let current_language_servers = self.as_local().map(|local| {
7064 local
7065 .buffers_opened_in_servers
7066 .get(&buffer_id)
7067 .cloned()
7068 .unwrap_or_default()
7069 });
7070
7071 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7072 if let Some(cached_colors) = &lsp_data.document_colors {
7073 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7074 let has_different_servers =
7075 current_language_servers.is_some_and(|current_language_servers| {
7076 current_language_servers
7077 != cached_colors.colors.keys().copied().collect()
7078 });
7079 if !has_different_servers {
7080 let cache_version = cached_colors.cache_version;
7081 if Some(cache_version) == known_cache_version {
7082 return None;
7083 } else {
7084 return Some(
7085 Task::ready(Ok(DocumentColors {
7086 colors: cached_colors
7087 .colors
7088 .values()
7089 .flatten()
7090 .cloned()
7091 .collect(),
7092 cache_version: Some(cache_version),
7093 }))
7094 .shared(),
7095 );
7096 }
7097 }
7098 }
7099 }
7100 }
7101
7102 let color_lsp_data = self
7103 .latest_lsp_data(&buffer, cx)
7104 .document_colors
7105 .get_or_insert_default();
7106 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7107 && !version_queried_for.changed_since(updating_for)
7108 {
7109 return Some(running_update.clone());
7110 }
7111 let buffer_version_queried_for = version_queried_for.clone();
7112 let new_task = cx
7113 .spawn(async move |lsp_store, cx| {
7114 cx.background_executor()
7115 .timer(Duration::from_millis(30))
7116 .await;
7117 let fetched_colors = lsp_store
7118 .update(cx, |lsp_store, cx| {
7119 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7120 })?
7121 .await
7122 .context("fetching document colors")
7123 .map_err(Arc::new);
7124 let fetched_colors = match fetched_colors {
7125 Ok(fetched_colors) => {
7126 if Some(true)
7127 == buffer
7128 .update(cx, |buffer, _| {
7129 buffer.version() != buffer_version_queried_for
7130 })
7131 .ok()
7132 {
7133 return Ok(DocumentColors::default());
7134 }
7135 fetched_colors
7136 }
7137 Err(e) => {
7138 lsp_store
7139 .update(cx, |lsp_store, _| {
7140 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7141 if let Some(document_colors) = &mut lsp_data.document_colors {
7142 document_colors.colors_update = None;
7143 }
7144 }
7145 })
7146 .ok();
7147 return Err(e);
7148 }
7149 };
7150
7151 lsp_store
7152 .update(cx, |lsp_store, cx| {
7153 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7154 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7155
7156 if let Some(fetched_colors) = fetched_colors {
7157 if lsp_data.buffer_version == buffer_version_queried_for {
7158 lsp_colors.colors.extend(fetched_colors);
7159 lsp_colors.cache_version += 1;
7160 } else if !lsp_data
7161 .buffer_version
7162 .changed_since(&buffer_version_queried_for)
7163 {
7164 lsp_data.buffer_version = buffer_version_queried_for;
7165 lsp_colors.colors = fetched_colors;
7166 lsp_colors.cache_version += 1;
7167 }
7168 }
7169 lsp_colors.colors_update = None;
7170 let colors = lsp_colors
7171 .colors
7172 .values()
7173 .flatten()
7174 .cloned()
7175 .collect::<HashSet<_>>();
7176 DocumentColors {
7177 colors,
7178 cache_version: Some(lsp_colors.cache_version),
7179 }
7180 })
7181 .map_err(Arc::new)
7182 })
7183 .shared();
7184 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7185 Some(new_task)
7186 }
7187
7188 fn fetch_document_colors_for_buffer(
7189 &mut self,
7190 buffer: &Entity<Buffer>,
7191 cx: &mut Context<Self>,
7192 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7193 if let Some((client, project_id)) = self.upstream_client() {
7194 let request = GetDocumentColor {};
7195 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7196 return Task::ready(Ok(None));
7197 }
7198
7199 let request_task = client.request_lsp(
7200 project_id,
7201 None,
7202 LSP_REQUEST_TIMEOUT,
7203 cx.background_executor().clone(),
7204 request.to_proto(project_id, buffer.read(cx)),
7205 );
7206 let buffer = buffer.clone();
7207 cx.spawn(async move |lsp_store, cx| {
7208 let Some(lsp_store) = lsp_store.upgrade() else {
7209 return Ok(None);
7210 };
7211 let colors = join_all(
7212 request_task
7213 .await
7214 .log_err()
7215 .flatten()
7216 .map(|response| response.payload)
7217 .unwrap_or_default()
7218 .into_iter()
7219 .map(|color_response| {
7220 let response = request.response_from_proto(
7221 color_response.response,
7222 lsp_store.clone(),
7223 buffer.clone(),
7224 cx.clone(),
7225 );
7226 async move {
7227 (
7228 LanguageServerId::from_proto(color_response.server_id),
7229 response.await.log_err().unwrap_or_default(),
7230 )
7231 }
7232 }),
7233 )
7234 .await
7235 .into_iter()
7236 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7237 acc.entry(server_id)
7238 .or_insert_with(HashSet::default)
7239 .extend(colors);
7240 acc
7241 });
7242 Ok(Some(colors))
7243 })
7244 } else {
7245 let document_colors_task =
7246 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7247 cx.background_spawn(async move {
7248 Ok(Some(
7249 document_colors_task
7250 .await
7251 .into_iter()
7252 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7253 acc.entry(server_id)
7254 .or_insert_with(HashSet::default)
7255 .extend(colors);
7256 acc
7257 })
7258 .into_iter()
7259 .collect(),
7260 ))
7261 })
7262 }
7263 }
7264
7265 pub fn signature_help<T: ToPointUtf16>(
7266 &mut self,
7267 buffer: &Entity<Buffer>,
7268 position: T,
7269 cx: &mut Context<Self>,
7270 ) -> Task<Option<Vec<SignatureHelp>>> {
7271 let position = position.to_point_utf16(buffer.read(cx));
7272
7273 if let Some((client, upstream_project_id)) = self.upstream_client() {
7274 let request = GetSignatureHelp { position };
7275 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7276 return Task::ready(None);
7277 }
7278 let request_task = client.request_lsp(
7279 upstream_project_id,
7280 None,
7281 LSP_REQUEST_TIMEOUT,
7282 cx.background_executor().clone(),
7283 request.to_proto(upstream_project_id, buffer.read(cx)),
7284 );
7285 let buffer = buffer.clone();
7286 cx.spawn(async move |weak_lsp_store, cx| {
7287 let lsp_store = weak_lsp_store.upgrade()?;
7288 let signatures = 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(|response| {
7297 let response = GetSignatureHelp { position }.response_from_proto(
7298 response.response,
7299 lsp_store.clone(),
7300 buffer.clone(),
7301 cx.clone(),
7302 );
7303 async move { response.await.log_err().flatten() }
7304 }),
7305 )
7306 .await
7307 .into_iter()
7308 .flatten()
7309 .collect();
7310 Some(signatures)
7311 })
7312 } else {
7313 let all_actions_task = self.request_multiple_lsp_locally(
7314 buffer,
7315 Some(position),
7316 GetSignatureHelp { position },
7317 cx,
7318 );
7319 cx.background_spawn(async move {
7320 Some(
7321 all_actions_task
7322 .await
7323 .into_iter()
7324 .flat_map(|(_, actions)| actions)
7325 .collect::<Vec<_>>(),
7326 )
7327 })
7328 }
7329 }
7330
7331 pub fn hover(
7332 &mut self,
7333 buffer: &Entity<Buffer>,
7334 position: PointUtf16,
7335 cx: &mut Context<Self>,
7336 ) -> Task<Option<Vec<Hover>>> {
7337 if let Some((client, upstream_project_id)) = self.upstream_client() {
7338 let request = GetHover { position };
7339 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7340 return Task::ready(None);
7341 }
7342 let request_task = client.request_lsp(
7343 upstream_project_id,
7344 None,
7345 LSP_REQUEST_TIMEOUT,
7346 cx.background_executor().clone(),
7347 request.to_proto(upstream_project_id, buffer.read(cx)),
7348 );
7349 let buffer = buffer.clone();
7350 cx.spawn(async move |weak_lsp_store, cx| {
7351 let lsp_store = weak_lsp_store.upgrade()?;
7352 let hovers = join_all(
7353 request_task
7354 .await
7355 .log_err()
7356 .flatten()
7357 .map(|response| response.payload)
7358 .unwrap_or_default()
7359 .into_iter()
7360 .map(|response| {
7361 let response = GetHover { position }.response_from_proto(
7362 response.response,
7363 lsp_store.clone(),
7364 buffer.clone(),
7365 cx.clone(),
7366 );
7367 async move {
7368 response
7369 .await
7370 .log_err()
7371 .flatten()
7372 .and_then(remove_empty_hover_blocks)
7373 }
7374 }),
7375 )
7376 .await
7377 .into_iter()
7378 .flatten()
7379 .collect();
7380 Some(hovers)
7381 })
7382 } else {
7383 let all_actions_task = self.request_multiple_lsp_locally(
7384 buffer,
7385 Some(position),
7386 GetHover { position },
7387 cx,
7388 );
7389 cx.background_spawn(async move {
7390 Some(
7391 all_actions_task
7392 .await
7393 .into_iter()
7394 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7395 .collect::<Vec<Hover>>(),
7396 )
7397 })
7398 }
7399 }
7400
7401 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7402 let language_registry = self.languages.clone();
7403
7404 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7405 let request = upstream_client.request(proto::GetProjectSymbols {
7406 project_id: *project_id,
7407 query: query.to_string(),
7408 });
7409 cx.foreground_executor().spawn(async move {
7410 let response = request.await?;
7411 let mut symbols = Vec::new();
7412 let core_symbols = response
7413 .symbols
7414 .into_iter()
7415 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7416 .collect::<Vec<_>>();
7417 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7418 .await;
7419 Ok(symbols)
7420 })
7421 } else if let Some(local) = self.as_local() {
7422 struct WorkspaceSymbolsResult {
7423 server_id: LanguageServerId,
7424 lsp_adapter: Arc<CachedLspAdapter>,
7425 worktree: WeakEntity<Worktree>,
7426 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7427 }
7428
7429 let mut requests = Vec::new();
7430 let mut requested_servers = BTreeSet::new();
7431 for (seed, state) in local.language_server_ids.iter() {
7432 let Some(worktree_handle) = self
7433 .worktree_store
7434 .read(cx)
7435 .worktree_for_id(seed.worktree_id, cx)
7436 else {
7437 continue;
7438 };
7439 let worktree = worktree_handle.read(cx);
7440 if !worktree.is_visible() {
7441 continue;
7442 }
7443
7444 if !requested_servers.insert(state.id) {
7445 continue;
7446 }
7447
7448 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7449 Some(LanguageServerState::Running {
7450 adapter, server, ..
7451 }) => (adapter.clone(), server),
7452
7453 _ => continue,
7454 };
7455 let supports_workspace_symbol_request =
7456 match server.capabilities().workspace_symbol_provider {
7457 Some(OneOf::Left(supported)) => supported,
7458 Some(OneOf::Right(_)) => true,
7459 None => false,
7460 };
7461 if !supports_workspace_symbol_request {
7462 continue;
7463 }
7464 let worktree_handle = worktree_handle.clone();
7465 let server_id = server.server_id();
7466 requests.push(
7467 server
7468 .request::<lsp::request::WorkspaceSymbolRequest>(
7469 lsp::WorkspaceSymbolParams {
7470 query: query.to_string(),
7471 ..Default::default()
7472 },
7473 )
7474 .map(move |response| {
7475 let lsp_symbols = response.into_response()
7476 .context("workspace symbols request")
7477 .log_err()
7478 .flatten()
7479 .map(|symbol_response| match symbol_response {
7480 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7481 flat_responses.into_iter().map(|lsp_symbol| {
7482 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7483 }).collect::<Vec<_>>()
7484 }
7485 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7486 nested_responses.into_iter().filter_map(|lsp_symbol| {
7487 let location = match lsp_symbol.location {
7488 OneOf::Left(location) => location,
7489 OneOf::Right(_) => {
7490 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7491 return None
7492 }
7493 };
7494 Some((lsp_symbol.name, lsp_symbol.kind, location))
7495 }).collect::<Vec<_>>()
7496 }
7497 }).unwrap_or_default();
7498
7499 WorkspaceSymbolsResult {
7500 server_id,
7501 lsp_adapter,
7502 worktree: worktree_handle.downgrade(),
7503 lsp_symbols,
7504 }
7505 }),
7506 );
7507 }
7508
7509 cx.spawn(async move |this, cx| {
7510 let responses = futures::future::join_all(requests).await;
7511 let this = match this.upgrade() {
7512 Some(this) => this,
7513 None => return Ok(Vec::new()),
7514 };
7515
7516 let mut symbols = Vec::new();
7517 for result in responses {
7518 let core_symbols = this.update(cx, |this, cx| {
7519 result
7520 .lsp_symbols
7521 .into_iter()
7522 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7523 let abs_path = symbol_location.uri.to_file_path().ok()?;
7524 let source_worktree = result.worktree.upgrade()?;
7525 let source_worktree_id = source_worktree.read(cx).id();
7526
7527 let path = if let Some((tree, rel_path)) =
7528 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7529 {
7530 let worktree_id = tree.read(cx).id();
7531 SymbolLocation::InProject(ProjectPath {
7532 worktree_id,
7533 path: rel_path,
7534 })
7535 } else {
7536 SymbolLocation::OutsideProject {
7537 signature: this.symbol_signature(&abs_path),
7538 abs_path: abs_path.into(),
7539 }
7540 };
7541
7542 Some(CoreSymbol {
7543 source_language_server_id: result.server_id,
7544 language_server_name: result.lsp_adapter.name.clone(),
7545 source_worktree_id,
7546 path,
7547 kind: symbol_kind,
7548 name: symbol_name,
7549 range: range_from_lsp(symbol_location.range),
7550 })
7551 })
7552 .collect()
7553 })?;
7554
7555 populate_labels_for_symbols(
7556 core_symbols,
7557 &language_registry,
7558 Some(result.lsp_adapter),
7559 &mut symbols,
7560 )
7561 .await;
7562 }
7563
7564 Ok(symbols)
7565 })
7566 } else {
7567 Task::ready(Err(anyhow!("No upstream client or local language server")))
7568 }
7569 }
7570
7571 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7572 let mut summary = DiagnosticSummary::default();
7573 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7574 summary.error_count += path_summary.error_count;
7575 summary.warning_count += path_summary.warning_count;
7576 }
7577 summary
7578 }
7579
7580 /// Returns the diagnostic summary for a specific project path.
7581 pub fn diagnostic_summary_for_path(
7582 &self,
7583 project_path: &ProjectPath,
7584 _: &App,
7585 ) -> DiagnosticSummary {
7586 if let Some(summaries) = self
7587 .diagnostic_summaries
7588 .get(&project_path.worktree_id)
7589 .and_then(|map| map.get(&project_path.path))
7590 {
7591 let (error_count, warning_count) = summaries.iter().fold(
7592 (0, 0),
7593 |(error_count, warning_count), (_language_server_id, summary)| {
7594 (
7595 error_count + summary.error_count,
7596 warning_count + summary.warning_count,
7597 )
7598 },
7599 );
7600
7601 DiagnosticSummary {
7602 error_count,
7603 warning_count,
7604 }
7605 } else {
7606 DiagnosticSummary::default()
7607 }
7608 }
7609
7610 pub fn diagnostic_summaries<'a>(
7611 &'a self,
7612 include_ignored: bool,
7613 cx: &'a App,
7614 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7615 self.worktree_store
7616 .read(cx)
7617 .visible_worktrees(cx)
7618 .filter_map(|worktree| {
7619 let worktree = worktree.read(cx);
7620 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7621 })
7622 .flat_map(move |(worktree, summaries)| {
7623 let worktree_id = worktree.id();
7624 summaries
7625 .iter()
7626 .filter(move |(path, _)| {
7627 include_ignored
7628 || worktree
7629 .entry_for_path(path.as_ref())
7630 .is_some_and(|entry| !entry.is_ignored)
7631 })
7632 .flat_map(move |(path, summaries)| {
7633 summaries.iter().map(move |(server_id, summary)| {
7634 (
7635 ProjectPath {
7636 worktree_id,
7637 path: path.clone(),
7638 },
7639 *server_id,
7640 *summary,
7641 )
7642 })
7643 })
7644 })
7645 }
7646
7647 pub fn on_buffer_edited(
7648 &mut self,
7649 buffer: Entity<Buffer>,
7650 cx: &mut Context<Self>,
7651 ) -> Option<()> {
7652 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7653 Some(
7654 self.as_local()?
7655 .language_servers_for_buffer(buffer, cx)
7656 .map(|i| i.1.clone())
7657 .collect(),
7658 )
7659 })?;
7660
7661 let buffer = buffer.read(cx);
7662 let file = File::from_dyn(buffer.file())?;
7663 let abs_path = file.as_local()?.abs_path(cx);
7664 let uri = lsp::Uri::from_file_path(&abs_path)
7665 .ok()
7666 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7667 .log_err()?;
7668 let next_snapshot = buffer.text_snapshot();
7669 for language_server in language_servers {
7670 let language_server = language_server.clone();
7671
7672 let buffer_snapshots = self
7673 .as_local_mut()?
7674 .buffer_snapshots
7675 .get_mut(&buffer.remote_id())
7676 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7677 let previous_snapshot = buffer_snapshots.last()?;
7678
7679 let build_incremental_change = || {
7680 buffer
7681 .edits_since::<Dimensions<PointUtf16, usize>>(
7682 previous_snapshot.snapshot.version(),
7683 )
7684 .map(|edit| {
7685 let edit_start = edit.new.start.0;
7686 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7687 let new_text = next_snapshot
7688 .text_for_range(edit.new.start.1..edit.new.end.1)
7689 .collect();
7690 lsp::TextDocumentContentChangeEvent {
7691 range: Some(lsp::Range::new(
7692 point_to_lsp(edit_start),
7693 point_to_lsp(edit_end),
7694 )),
7695 range_length: None,
7696 text: new_text,
7697 }
7698 })
7699 .collect()
7700 };
7701
7702 let document_sync_kind = language_server
7703 .capabilities()
7704 .text_document_sync
7705 .as_ref()
7706 .and_then(|sync| match sync {
7707 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7708 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7709 });
7710
7711 let content_changes: Vec<_> = match document_sync_kind {
7712 Some(lsp::TextDocumentSyncKind::FULL) => {
7713 vec![lsp::TextDocumentContentChangeEvent {
7714 range: None,
7715 range_length: None,
7716 text: next_snapshot.text(),
7717 }]
7718 }
7719 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7720 _ => {
7721 #[cfg(any(test, feature = "test-support"))]
7722 {
7723 build_incremental_change()
7724 }
7725
7726 #[cfg(not(any(test, feature = "test-support")))]
7727 {
7728 continue;
7729 }
7730 }
7731 };
7732
7733 let next_version = previous_snapshot.version + 1;
7734 buffer_snapshots.push(LspBufferSnapshot {
7735 version: next_version,
7736 snapshot: next_snapshot.clone(),
7737 });
7738
7739 language_server
7740 .notify::<lsp::notification::DidChangeTextDocument>(
7741 lsp::DidChangeTextDocumentParams {
7742 text_document: lsp::VersionedTextDocumentIdentifier::new(
7743 uri.clone(),
7744 next_version,
7745 ),
7746 content_changes,
7747 },
7748 )
7749 .ok();
7750 self.pull_workspace_diagnostics(language_server.server_id());
7751 }
7752
7753 None
7754 }
7755
7756 pub fn on_buffer_saved(
7757 &mut self,
7758 buffer: Entity<Buffer>,
7759 cx: &mut Context<Self>,
7760 ) -> Option<()> {
7761 let file = File::from_dyn(buffer.read(cx).file())?;
7762 let worktree_id = file.worktree_id(cx);
7763 let abs_path = file.as_local()?.abs_path(cx);
7764 let text_document = lsp::TextDocumentIdentifier {
7765 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7766 };
7767 let local = self.as_local()?;
7768
7769 for server in local.language_servers_for_worktree(worktree_id) {
7770 if let Some(include_text) = include_text(server.as_ref()) {
7771 let text = if include_text {
7772 Some(buffer.read(cx).text())
7773 } else {
7774 None
7775 };
7776 server
7777 .notify::<lsp::notification::DidSaveTextDocument>(
7778 lsp::DidSaveTextDocumentParams {
7779 text_document: text_document.clone(),
7780 text,
7781 },
7782 )
7783 .ok();
7784 }
7785 }
7786
7787 let language_servers = buffer.update(cx, |buffer, cx| {
7788 local.language_server_ids_for_buffer(buffer, cx)
7789 });
7790 for language_server_id in language_servers {
7791 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7792 }
7793
7794 None
7795 }
7796
7797 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7798 maybe!(async move {
7799 let mut refreshed_servers = HashSet::default();
7800 let servers = lsp_store
7801 .update(cx, |lsp_store, cx| {
7802 let local = lsp_store.as_local()?;
7803
7804 let servers = local
7805 .language_server_ids
7806 .iter()
7807 .filter_map(|(seed, state)| {
7808 let worktree = lsp_store
7809 .worktree_store
7810 .read(cx)
7811 .worktree_for_id(seed.worktree_id, cx);
7812 let delegate: Arc<dyn LspAdapterDelegate> =
7813 worktree.map(|worktree| {
7814 LocalLspAdapterDelegate::new(
7815 local.languages.clone(),
7816 &local.environment,
7817 cx.weak_entity(),
7818 &worktree,
7819 local.http_client.clone(),
7820 local.fs.clone(),
7821 cx,
7822 )
7823 })?;
7824 let server_id = state.id;
7825
7826 let states = local.language_servers.get(&server_id)?;
7827
7828 match states {
7829 LanguageServerState::Starting { .. } => None,
7830 LanguageServerState::Running {
7831 adapter, server, ..
7832 } => {
7833 let adapter = adapter.clone();
7834 let server = server.clone();
7835 refreshed_servers.insert(server.name());
7836 let toolchain = seed.toolchain.clone();
7837 Some(cx.spawn(async move |_, cx| {
7838 let settings =
7839 LocalLspStore::workspace_configuration_for_adapter(
7840 adapter.adapter.clone(),
7841 &delegate,
7842 toolchain,
7843 cx,
7844 )
7845 .await
7846 .ok()?;
7847 server
7848 .notify::<lsp::notification::DidChangeConfiguration>(
7849 lsp::DidChangeConfigurationParams { settings },
7850 )
7851 .ok()?;
7852 Some(())
7853 }))
7854 }
7855 }
7856 })
7857 .collect::<Vec<_>>();
7858
7859 Some(servers)
7860 })
7861 .ok()
7862 .flatten()?;
7863
7864 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7865 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7866 // to stop and unregister its language server wrapper.
7867 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7868 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7869 let _: Vec<Option<()>> = join_all(servers).await;
7870
7871 Some(())
7872 })
7873 .await;
7874 }
7875
7876 fn maintain_workspace_config(
7877 external_refresh_requests: watch::Receiver<()>,
7878 cx: &mut Context<Self>,
7879 ) -> Task<Result<()>> {
7880 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7881 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7882
7883 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7884 *settings_changed_tx.borrow_mut() = ();
7885 });
7886
7887 let mut joint_future =
7888 futures::stream::select(settings_changed_rx, external_refresh_requests);
7889 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7890 // - 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).
7891 // - 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.
7892 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7893 // - 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,
7894 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7895 cx.spawn(async move |this, cx| {
7896 while let Some(()) = joint_future.next().await {
7897 this.update(cx, |this, cx| {
7898 this.refresh_server_tree(cx);
7899 })
7900 .ok();
7901
7902 Self::refresh_workspace_configurations(&this, cx).await;
7903 }
7904
7905 drop(settings_observation);
7906 anyhow::Ok(())
7907 })
7908 }
7909
7910 pub fn language_servers_for_local_buffer<'a>(
7911 &'a self,
7912 buffer: &Buffer,
7913 cx: &mut App,
7914 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7915 let local = self.as_local();
7916 let language_server_ids = local
7917 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7918 .unwrap_or_default();
7919
7920 language_server_ids
7921 .into_iter()
7922 .filter_map(
7923 move |server_id| match local?.language_servers.get(&server_id)? {
7924 LanguageServerState::Running {
7925 adapter, server, ..
7926 } => Some((adapter, server)),
7927 _ => None,
7928 },
7929 )
7930 }
7931
7932 pub fn language_server_for_local_buffer<'a>(
7933 &'a self,
7934 buffer: &'a Buffer,
7935 server_id: LanguageServerId,
7936 cx: &'a mut App,
7937 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7938 self.as_local()?
7939 .language_servers_for_buffer(buffer, cx)
7940 .find(|(_, s)| s.server_id() == server_id)
7941 }
7942
7943 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7944 self.diagnostic_summaries.remove(&id_to_remove);
7945 if let Some(local) = self.as_local_mut() {
7946 let to_remove = local.remove_worktree(id_to_remove, cx);
7947 for server in to_remove {
7948 self.language_server_statuses.remove(&server);
7949 }
7950 }
7951 }
7952
7953 pub fn shared(
7954 &mut self,
7955 project_id: u64,
7956 downstream_client: AnyProtoClient,
7957 _: &mut Context<Self>,
7958 ) {
7959 self.downstream_client = Some((downstream_client.clone(), project_id));
7960
7961 for (server_id, status) in &self.language_server_statuses {
7962 if let Some(server) = self.language_server_for_id(*server_id) {
7963 downstream_client
7964 .send(proto::StartLanguageServer {
7965 project_id,
7966 server: Some(proto::LanguageServer {
7967 id: server_id.to_proto(),
7968 name: status.name.to_string(),
7969 worktree_id: status.worktree.map(|id| id.to_proto()),
7970 }),
7971 capabilities: serde_json::to_string(&server.capabilities())
7972 .expect("serializing server LSP capabilities"),
7973 })
7974 .log_err();
7975 }
7976 }
7977 }
7978
7979 pub fn disconnected_from_host(&mut self) {
7980 self.downstream_client.take();
7981 }
7982
7983 pub fn disconnected_from_ssh_remote(&mut self) {
7984 if let LspStoreMode::Remote(RemoteLspStore {
7985 upstream_client, ..
7986 }) = &mut self.mode
7987 {
7988 upstream_client.take();
7989 }
7990 }
7991
7992 pub(crate) fn set_language_server_statuses_from_proto(
7993 &mut self,
7994 project: WeakEntity<Project>,
7995 language_servers: Vec<proto::LanguageServer>,
7996 server_capabilities: Vec<String>,
7997 cx: &mut Context<Self>,
7998 ) {
7999 let lsp_logs = cx
8000 .try_global::<GlobalLogStore>()
8001 .map(|lsp_store| lsp_store.0.clone());
8002
8003 self.language_server_statuses = language_servers
8004 .into_iter()
8005 .zip(server_capabilities)
8006 .map(|(server, server_capabilities)| {
8007 let server_id = LanguageServerId(server.id as usize);
8008 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8009 self.lsp_server_capabilities
8010 .insert(server_id, server_capabilities);
8011 }
8012
8013 let name = LanguageServerName::from_proto(server.name);
8014 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8015
8016 if let Some(lsp_logs) = &lsp_logs {
8017 lsp_logs.update(cx, |lsp_logs, cx| {
8018 lsp_logs.add_language_server(
8019 // Only remote clients get their language servers set from proto
8020 LanguageServerKind::Remote {
8021 project: project.clone(),
8022 },
8023 server_id,
8024 Some(name.clone()),
8025 worktree,
8026 None,
8027 cx,
8028 );
8029 });
8030 }
8031
8032 (
8033 server_id,
8034 LanguageServerStatus {
8035 name,
8036 pending_work: Default::default(),
8037 has_pending_diagnostic_updates: false,
8038 progress_tokens: Default::default(),
8039 worktree,
8040 },
8041 )
8042 })
8043 .collect();
8044 }
8045
8046 #[cfg(test)]
8047 pub fn update_diagnostic_entries(
8048 &mut self,
8049 server_id: LanguageServerId,
8050 abs_path: PathBuf,
8051 result_id: Option<String>,
8052 version: Option<i32>,
8053 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8054 cx: &mut Context<Self>,
8055 ) -> anyhow::Result<()> {
8056 self.merge_diagnostic_entries(
8057 vec![DocumentDiagnosticsUpdate {
8058 diagnostics: DocumentDiagnostics {
8059 diagnostics,
8060 document_abs_path: abs_path,
8061 version,
8062 },
8063 result_id,
8064 server_id,
8065 disk_based_sources: Cow::Borrowed(&[]),
8066 }],
8067 |_, _, _| false,
8068 cx,
8069 )?;
8070 Ok(())
8071 }
8072
8073 pub fn merge_diagnostic_entries<'a>(
8074 &mut self,
8075 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8076 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8077 cx: &mut Context<Self>,
8078 ) -> anyhow::Result<()> {
8079 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8080 let mut updated_diagnostics_paths = HashMap::default();
8081 for mut update in diagnostic_updates {
8082 let abs_path = &update.diagnostics.document_abs_path;
8083 let server_id = update.server_id;
8084 let Some((worktree, relative_path)) =
8085 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8086 else {
8087 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8088 return Ok(());
8089 };
8090
8091 let worktree_id = worktree.read(cx).id();
8092 let project_path = ProjectPath {
8093 worktree_id,
8094 path: relative_path,
8095 };
8096
8097 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8098 let snapshot = buffer_handle.read(cx).snapshot();
8099 let buffer = buffer_handle.read(cx);
8100 let reused_diagnostics = buffer
8101 .buffer_diagnostics(Some(server_id))
8102 .iter()
8103 .filter(|v| merge(buffer, &v.diagnostic, cx))
8104 .map(|v| {
8105 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8106 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8107 DiagnosticEntry {
8108 range: start..end,
8109 diagnostic: v.diagnostic.clone(),
8110 }
8111 })
8112 .collect::<Vec<_>>();
8113
8114 self.as_local_mut()
8115 .context("cannot merge diagnostics on a remote LspStore")?
8116 .update_buffer_diagnostics(
8117 &buffer_handle,
8118 server_id,
8119 update.result_id,
8120 update.diagnostics.version,
8121 update.diagnostics.diagnostics.clone(),
8122 reused_diagnostics.clone(),
8123 cx,
8124 )?;
8125
8126 update.diagnostics.diagnostics.extend(reused_diagnostics);
8127 }
8128
8129 let updated = worktree.update(cx, |worktree, cx| {
8130 self.update_worktree_diagnostics(
8131 worktree.id(),
8132 server_id,
8133 project_path.path.clone(),
8134 update.diagnostics.diagnostics,
8135 cx,
8136 )
8137 })?;
8138 match updated {
8139 ControlFlow::Continue(new_summary) => {
8140 if let Some((project_id, new_summary)) = new_summary {
8141 match &mut diagnostics_summary {
8142 Some(diagnostics_summary) => {
8143 diagnostics_summary
8144 .more_summaries
8145 .push(proto::DiagnosticSummary {
8146 path: project_path.path.as_ref().to_proto(),
8147 language_server_id: server_id.0 as u64,
8148 error_count: new_summary.error_count,
8149 warning_count: new_summary.warning_count,
8150 })
8151 }
8152 None => {
8153 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8154 project_id,
8155 worktree_id: worktree_id.to_proto(),
8156 summary: Some(proto::DiagnosticSummary {
8157 path: project_path.path.as_ref().to_proto(),
8158 language_server_id: server_id.0 as u64,
8159 error_count: new_summary.error_count,
8160 warning_count: new_summary.warning_count,
8161 }),
8162 more_summaries: Vec::new(),
8163 })
8164 }
8165 }
8166 }
8167 updated_diagnostics_paths
8168 .entry(server_id)
8169 .or_insert_with(Vec::new)
8170 .push(project_path);
8171 }
8172 ControlFlow::Break(()) => {}
8173 }
8174 }
8175
8176 if let Some((diagnostics_summary, (downstream_client, _))) =
8177 diagnostics_summary.zip(self.downstream_client.as_ref())
8178 {
8179 downstream_client.send(diagnostics_summary).log_err();
8180 }
8181 for (server_id, paths) in updated_diagnostics_paths {
8182 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8183 }
8184 Ok(())
8185 }
8186
8187 fn update_worktree_diagnostics(
8188 &mut self,
8189 worktree_id: WorktreeId,
8190 server_id: LanguageServerId,
8191 path_in_worktree: Arc<RelPath>,
8192 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8193 _: &mut Context<Worktree>,
8194 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8195 let local = match &mut self.mode {
8196 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8197 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8198 };
8199
8200 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8201 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8202 let summaries_by_server_id = summaries_for_tree
8203 .entry(path_in_worktree.clone())
8204 .or_default();
8205
8206 let old_summary = summaries_by_server_id
8207 .remove(&server_id)
8208 .unwrap_or_default();
8209
8210 let new_summary = DiagnosticSummary::new(&diagnostics);
8211 if new_summary.is_empty() {
8212 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8213 {
8214 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8215 diagnostics_by_server_id.remove(ix);
8216 }
8217 if diagnostics_by_server_id.is_empty() {
8218 diagnostics_for_tree.remove(&path_in_worktree);
8219 }
8220 }
8221 } else {
8222 summaries_by_server_id.insert(server_id, new_summary);
8223 let diagnostics_by_server_id = diagnostics_for_tree
8224 .entry(path_in_worktree.clone())
8225 .or_default();
8226 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8227 Ok(ix) => {
8228 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8229 }
8230 Err(ix) => {
8231 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8232 }
8233 }
8234 }
8235
8236 if !old_summary.is_empty() || !new_summary.is_empty() {
8237 if let Some((_, project_id)) = &self.downstream_client {
8238 Ok(ControlFlow::Continue(Some((
8239 *project_id,
8240 proto::DiagnosticSummary {
8241 path: path_in_worktree.to_proto(),
8242 language_server_id: server_id.0 as u64,
8243 error_count: new_summary.error_count as u32,
8244 warning_count: new_summary.warning_count as u32,
8245 },
8246 ))))
8247 } else {
8248 Ok(ControlFlow::Continue(None))
8249 }
8250 } else {
8251 Ok(ControlFlow::Break(()))
8252 }
8253 }
8254
8255 pub fn open_buffer_for_symbol(
8256 &mut self,
8257 symbol: &Symbol,
8258 cx: &mut Context<Self>,
8259 ) -> Task<Result<Entity<Buffer>>> {
8260 if let Some((client, project_id)) = self.upstream_client() {
8261 let request = client.request(proto::OpenBufferForSymbol {
8262 project_id,
8263 symbol: Some(Self::serialize_symbol(symbol)),
8264 });
8265 cx.spawn(async move |this, cx| {
8266 let response = request.await?;
8267 let buffer_id = BufferId::new(response.buffer_id)?;
8268 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8269 .await
8270 })
8271 } else if let Some(local) = self.as_local() {
8272 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8273 seed.worktree_id == symbol.source_worktree_id
8274 && state.id == symbol.source_language_server_id
8275 && symbol.language_server_name == seed.name
8276 });
8277 if !is_valid {
8278 return Task::ready(Err(anyhow!(
8279 "language server for worktree and language not found"
8280 )));
8281 };
8282
8283 let symbol_abs_path = match &symbol.path {
8284 SymbolLocation::InProject(project_path) => self
8285 .worktree_store
8286 .read(cx)
8287 .absolutize(&project_path, cx)
8288 .context("no such worktree"),
8289 SymbolLocation::OutsideProject {
8290 abs_path,
8291 signature: _,
8292 } => Ok(abs_path.to_path_buf()),
8293 };
8294 let symbol_abs_path = match symbol_abs_path {
8295 Ok(abs_path) => abs_path,
8296 Err(err) => return Task::ready(Err(err)),
8297 };
8298 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8299 uri
8300 } else {
8301 return Task::ready(Err(anyhow!("invalid symbol path")));
8302 };
8303
8304 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8305 } else {
8306 Task::ready(Err(anyhow!("no upstream client or local store")))
8307 }
8308 }
8309
8310 pub(crate) fn open_local_buffer_via_lsp(
8311 &mut self,
8312 abs_path: lsp::Uri,
8313 language_server_id: LanguageServerId,
8314 cx: &mut Context<Self>,
8315 ) -> Task<Result<Entity<Buffer>>> {
8316 cx.spawn(async move |lsp_store, cx| {
8317 // Escape percent-encoded string.
8318 let current_scheme = abs_path.scheme().to_owned();
8319 // Uri is immutable, so we can't modify the scheme
8320
8321 let abs_path = abs_path
8322 .to_file_path()
8323 .map_err(|()| anyhow!("can't convert URI to path"))?;
8324 let p = abs_path.clone();
8325 let yarn_worktree = lsp_store
8326 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8327 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8328 cx.spawn(async move |this, cx| {
8329 let t = this
8330 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8331 .ok()?;
8332 t.await
8333 })
8334 }),
8335 None => Task::ready(None),
8336 })?
8337 .await;
8338 let (worktree_root_target, known_relative_path) =
8339 if let Some((zip_root, relative_path)) = yarn_worktree {
8340 (zip_root, Some(relative_path))
8341 } else {
8342 (Arc::<Path>::from(abs_path.as_path()), None)
8343 };
8344 let (worktree, relative_path) = if let Some(result) =
8345 lsp_store.update(cx, |lsp_store, cx| {
8346 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8347 worktree_store.find_worktree(&worktree_root_target, cx)
8348 })
8349 })? {
8350 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8351 (result.0, relative_path)
8352 } else {
8353 let worktree = lsp_store
8354 .update(cx, |lsp_store, cx| {
8355 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8356 worktree_store.create_worktree(&worktree_root_target, false, cx)
8357 })
8358 })?
8359 .await?;
8360 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8361 lsp_store
8362 .update(cx, |lsp_store, cx| {
8363 if let Some(local) = lsp_store.as_local_mut() {
8364 local.register_language_server_for_invisible_worktree(
8365 &worktree,
8366 language_server_id,
8367 cx,
8368 )
8369 }
8370 })
8371 .ok();
8372 }
8373 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8374 let relative_path = if let Some(known_path) = known_relative_path {
8375 known_path
8376 } else {
8377 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8378 .into_arc()
8379 };
8380 (worktree, relative_path)
8381 };
8382 let project_path = ProjectPath {
8383 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8384 path: relative_path,
8385 };
8386 lsp_store
8387 .update(cx, |lsp_store, cx| {
8388 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8389 buffer_store.open_buffer(project_path, cx)
8390 })
8391 })?
8392 .await
8393 })
8394 }
8395
8396 fn request_multiple_lsp_locally<P, R>(
8397 &mut self,
8398 buffer: &Entity<Buffer>,
8399 position: Option<P>,
8400 request: R,
8401 cx: &mut Context<Self>,
8402 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8403 where
8404 P: ToOffset,
8405 R: LspCommand + Clone,
8406 <R::LspRequest as lsp::request::Request>::Result: Send,
8407 <R::LspRequest as lsp::request::Request>::Params: Send,
8408 {
8409 let Some(local) = self.as_local() else {
8410 return Task::ready(Vec::new());
8411 };
8412
8413 let snapshot = buffer.read(cx).snapshot();
8414 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8415
8416 let server_ids = buffer.update(cx, |buffer, cx| {
8417 local
8418 .language_servers_for_buffer(buffer, cx)
8419 .filter(|(adapter, _)| {
8420 scope
8421 .as_ref()
8422 .map(|scope| scope.language_allowed(&adapter.name))
8423 .unwrap_or(true)
8424 })
8425 .map(|(_, server)| server.server_id())
8426 .filter(|server_id| {
8427 self.as_local().is_none_or(|local| {
8428 local
8429 .buffers_opened_in_servers
8430 .get(&snapshot.remote_id())
8431 .is_some_and(|servers| servers.contains(server_id))
8432 })
8433 })
8434 .collect::<Vec<_>>()
8435 });
8436
8437 let mut response_results = server_ids
8438 .into_iter()
8439 .map(|server_id| {
8440 let task = self.request_lsp(
8441 buffer.clone(),
8442 LanguageServerToQuery::Other(server_id),
8443 request.clone(),
8444 cx,
8445 );
8446 async move { (server_id, task.await) }
8447 })
8448 .collect::<FuturesUnordered<_>>();
8449
8450 cx.background_spawn(async move {
8451 let mut responses = Vec::with_capacity(response_results.len());
8452 while let Some((server_id, response_result)) = response_results.next().await {
8453 match response_result {
8454 Ok(response) => responses.push((server_id, response)),
8455 // rust-analyzer likes to error with this when its still loading up
8456 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8457 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8458 }
8459 }
8460 responses
8461 })
8462 }
8463
8464 async fn handle_lsp_command<T: LspCommand>(
8465 this: Entity<Self>,
8466 envelope: TypedEnvelope<T::ProtoRequest>,
8467 mut cx: AsyncApp,
8468 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8469 where
8470 <T::LspRequest as lsp::request::Request>::Params: Send,
8471 <T::LspRequest as lsp::request::Request>::Result: Send,
8472 {
8473 let sender_id = envelope.original_sender_id().unwrap_or_default();
8474 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8475 let buffer_handle = this.update(&mut cx, |this, cx| {
8476 this.buffer_store.read(cx).get_existing(buffer_id)
8477 })??;
8478 let request = T::from_proto(
8479 envelope.payload,
8480 this.clone(),
8481 buffer_handle.clone(),
8482 cx.clone(),
8483 )
8484 .await?;
8485 let response = this
8486 .update(&mut cx, |this, cx| {
8487 this.request_lsp(
8488 buffer_handle.clone(),
8489 LanguageServerToQuery::FirstCapable,
8490 request,
8491 cx,
8492 )
8493 })?
8494 .await?;
8495 this.update(&mut cx, |this, cx| {
8496 Ok(T::response_to_proto(
8497 response,
8498 this,
8499 sender_id,
8500 &buffer_handle.read(cx).version(),
8501 cx,
8502 ))
8503 })?
8504 }
8505
8506 async fn handle_lsp_query(
8507 lsp_store: Entity<Self>,
8508 envelope: TypedEnvelope<proto::LspQuery>,
8509 mut cx: AsyncApp,
8510 ) -> Result<proto::Ack> {
8511 use proto::lsp_query::Request;
8512 let sender_id = envelope.original_sender_id().unwrap_or_default();
8513 let lsp_query = envelope.payload;
8514 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8515 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8516 match lsp_query.request.context("invalid LSP query request")? {
8517 Request::GetReferences(get_references) => {
8518 let position = get_references.position.clone().and_then(deserialize_anchor);
8519 Self::query_lsp_locally::<GetReferences>(
8520 lsp_store,
8521 server_id,
8522 sender_id,
8523 lsp_request_id,
8524 get_references,
8525 position,
8526 &mut cx,
8527 )
8528 .await?;
8529 }
8530 Request::GetDocumentColor(get_document_color) => {
8531 Self::query_lsp_locally::<GetDocumentColor>(
8532 lsp_store,
8533 server_id,
8534 sender_id,
8535 lsp_request_id,
8536 get_document_color,
8537 None,
8538 &mut cx,
8539 )
8540 .await?;
8541 }
8542 Request::GetHover(get_hover) => {
8543 let position = get_hover.position.clone().and_then(deserialize_anchor);
8544 Self::query_lsp_locally::<GetHover>(
8545 lsp_store,
8546 server_id,
8547 sender_id,
8548 lsp_request_id,
8549 get_hover,
8550 position,
8551 &mut cx,
8552 )
8553 .await?;
8554 }
8555 Request::GetCodeActions(get_code_actions) => {
8556 Self::query_lsp_locally::<GetCodeActions>(
8557 lsp_store,
8558 server_id,
8559 sender_id,
8560 lsp_request_id,
8561 get_code_actions,
8562 None,
8563 &mut cx,
8564 )
8565 .await?;
8566 }
8567 Request::GetSignatureHelp(get_signature_help) => {
8568 let position = get_signature_help
8569 .position
8570 .clone()
8571 .and_then(deserialize_anchor);
8572 Self::query_lsp_locally::<GetSignatureHelp>(
8573 lsp_store,
8574 server_id,
8575 sender_id,
8576 lsp_request_id,
8577 get_signature_help,
8578 position,
8579 &mut cx,
8580 )
8581 .await?;
8582 }
8583 Request::GetCodeLens(get_code_lens) => {
8584 Self::query_lsp_locally::<GetCodeLens>(
8585 lsp_store,
8586 server_id,
8587 sender_id,
8588 lsp_request_id,
8589 get_code_lens,
8590 None,
8591 &mut cx,
8592 )
8593 .await?;
8594 }
8595 Request::GetDefinition(get_definition) => {
8596 let position = get_definition.position.clone().and_then(deserialize_anchor);
8597 Self::query_lsp_locally::<GetDefinitions>(
8598 lsp_store,
8599 server_id,
8600 sender_id,
8601 lsp_request_id,
8602 get_definition,
8603 position,
8604 &mut cx,
8605 )
8606 .await?;
8607 }
8608 Request::GetDeclaration(get_declaration) => {
8609 let position = get_declaration
8610 .position
8611 .clone()
8612 .and_then(deserialize_anchor);
8613 Self::query_lsp_locally::<GetDeclarations>(
8614 lsp_store,
8615 server_id,
8616 sender_id,
8617 lsp_request_id,
8618 get_declaration,
8619 position,
8620 &mut cx,
8621 )
8622 .await?;
8623 }
8624 Request::GetTypeDefinition(get_type_definition) => {
8625 let position = get_type_definition
8626 .position
8627 .clone()
8628 .and_then(deserialize_anchor);
8629 Self::query_lsp_locally::<GetTypeDefinitions>(
8630 lsp_store,
8631 server_id,
8632 sender_id,
8633 lsp_request_id,
8634 get_type_definition,
8635 position,
8636 &mut cx,
8637 )
8638 .await?;
8639 }
8640 Request::GetImplementation(get_implementation) => {
8641 let position = get_implementation
8642 .position
8643 .clone()
8644 .and_then(deserialize_anchor);
8645 Self::query_lsp_locally::<GetImplementations>(
8646 lsp_store,
8647 server_id,
8648 sender_id,
8649 lsp_request_id,
8650 get_implementation,
8651 position,
8652 &mut cx,
8653 )
8654 .await?;
8655 }
8656 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8657 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8658 let version = deserialize_version(get_document_diagnostics.buffer_version());
8659 let buffer = lsp_store.update(&mut cx, |this, cx| {
8660 this.buffer_store.read(cx).get_existing(buffer_id)
8661 })??;
8662 buffer
8663 .update(&mut cx, |buffer, _| {
8664 buffer.wait_for_version(version.clone())
8665 })?
8666 .await?;
8667 lsp_store.update(&mut cx, |lsp_store, cx| {
8668 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8669 let key = LspKey {
8670 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8671 server_queried: server_id,
8672 };
8673 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8674 ) {
8675 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8676 lsp_requests.clear();
8677 };
8678 }
8679
8680 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8681 existing_queries.insert(
8682 lsp_request_id,
8683 cx.spawn(async move |lsp_store, cx| {
8684 let diagnostics_pull = lsp_store
8685 .update(cx, |lsp_store, cx| {
8686 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8687 })
8688 .ok();
8689 if let Some(diagnostics_pull) = diagnostics_pull {
8690 match diagnostics_pull.await {
8691 Ok(()) => {}
8692 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8693 };
8694 }
8695 }),
8696 );
8697 })?;
8698 }
8699 Request::InlayHints(inlay_hints) => {
8700 let query_start = inlay_hints
8701 .start
8702 .clone()
8703 .and_then(deserialize_anchor)
8704 .context("invalid inlay hints range start")?;
8705 let query_end = inlay_hints
8706 .end
8707 .clone()
8708 .and_then(deserialize_anchor)
8709 .context("invalid inlay hints range end")?;
8710 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8711 &lsp_store,
8712 server_id,
8713 lsp_request_id,
8714 &inlay_hints,
8715 query_start..query_end,
8716 &mut cx,
8717 )
8718 .await
8719 .context("preparing inlay hints request")?;
8720 Self::query_lsp_locally::<InlayHints>(
8721 lsp_store,
8722 server_id,
8723 sender_id,
8724 lsp_request_id,
8725 inlay_hints,
8726 None,
8727 &mut cx,
8728 )
8729 .await
8730 .context("querying for inlay hints")?
8731 }
8732 }
8733 Ok(proto::Ack {})
8734 }
8735
8736 async fn handle_lsp_query_response(
8737 lsp_store: Entity<Self>,
8738 envelope: TypedEnvelope<proto::LspQueryResponse>,
8739 cx: AsyncApp,
8740 ) -> Result<()> {
8741 lsp_store.read_with(&cx, |lsp_store, _| {
8742 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8743 upstream_client.handle_lsp_response(envelope.clone());
8744 }
8745 })?;
8746 Ok(())
8747 }
8748
8749 async fn handle_apply_code_action(
8750 this: Entity<Self>,
8751 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8752 mut cx: AsyncApp,
8753 ) -> Result<proto::ApplyCodeActionResponse> {
8754 let sender_id = envelope.original_sender_id().unwrap_or_default();
8755 let action =
8756 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8757 let apply_code_action = this.update(&mut cx, |this, cx| {
8758 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8759 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8760 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8761 })??;
8762
8763 let project_transaction = apply_code_action.await?;
8764 let project_transaction = this.update(&mut cx, |this, cx| {
8765 this.buffer_store.update(cx, |buffer_store, cx| {
8766 buffer_store.serialize_project_transaction_for_peer(
8767 project_transaction,
8768 sender_id,
8769 cx,
8770 )
8771 })
8772 })?;
8773 Ok(proto::ApplyCodeActionResponse {
8774 transaction: Some(project_transaction),
8775 })
8776 }
8777
8778 async fn handle_register_buffer_with_language_servers(
8779 this: Entity<Self>,
8780 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8781 mut cx: AsyncApp,
8782 ) -> Result<proto::Ack> {
8783 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8784 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8785 this.update(&mut cx, |this, cx| {
8786 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8787 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8788 project_id: upstream_project_id,
8789 buffer_id: buffer_id.to_proto(),
8790 only_servers: envelope.payload.only_servers,
8791 });
8792 }
8793
8794 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8795 anyhow::bail!("buffer is not open");
8796 };
8797
8798 let handle = this.register_buffer_with_language_servers(
8799 &buffer,
8800 envelope
8801 .payload
8802 .only_servers
8803 .into_iter()
8804 .filter_map(|selector| {
8805 Some(match selector.selector? {
8806 proto::language_server_selector::Selector::ServerId(server_id) => {
8807 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8808 }
8809 proto::language_server_selector::Selector::Name(name) => {
8810 LanguageServerSelector::Name(LanguageServerName(
8811 SharedString::from(name),
8812 ))
8813 }
8814 })
8815 })
8816 .collect(),
8817 false,
8818 cx,
8819 );
8820 this.buffer_store().update(cx, |buffer_store, _| {
8821 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8822 });
8823
8824 Ok(())
8825 })??;
8826 Ok(proto::Ack {})
8827 }
8828
8829 async fn handle_rename_project_entry(
8830 this: Entity<Self>,
8831 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8832 mut cx: AsyncApp,
8833 ) -> Result<proto::ProjectEntryResponse> {
8834 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8835 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8836 let new_path =
8837 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8838
8839 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8840 .update(&mut cx, |this, cx| {
8841 let (worktree, entry) = this
8842 .worktree_store
8843 .read(cx)
8844 .worktree_and_entry_for_id(entry_id, cx)?;
8845 let new_worktree = this
8846 .worktree_store
8847 .read(cx)
8848 .worktree_for_id(new_worktree_id, cx)?;
8849 Some((
8850 this.worktree_store.clone(),
8851 worktree,
8852 new_worktree,
8853 entry.clone(),
8854 ))
8855 })?
8856 .context("worktree not found")?;
8857 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8858 (worktree.absolutize(&old_entry.path), worktree.id())
8859 })?;
8860 let new_abs_path =
8861 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8862
8863 let _transaction = Self::will_rename_entry(
8864 this.downgrade(),
8865 old_worktree_id,
8866 &old_abs_path,
8867 &new_abs_path,
8868 old_entry.is_dir(),
8869 cx.clone(),
8870 )
8871 .await;
8872 let response = WorktreeStore::handle_rename_project_entry(
8873 worktree_store,
8874 envelope.payload,
8875 cx.clone(),
8876 )
8877 .await;
8878 this.read_with(&cx, |this, _| {
8879 this.did_rename_entry(
8880 old_worktree_id,
8881 &old_abs_path,
8882 &new_abs_path,
8883 old_entry.is_dir(),
8884 );
8885 })
8886 .ok();
8887 response
8888 }
8889
8890 async fn handle_update_diagnostic_summary(
8891 this: Entity<Self>,
8892 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8893 mut cx: AsyncApp,
8894 ) -> Result<()> {
8895 this.update(&mut cx, |lsp_store, cx| {
8896 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8897 let mut updated_diagnostics_paths = HashMap::default();
8898 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8899 for message_summary in envelope
8900 .payload
8901 .summary
8902 .into_iter()
8903 .chain(envelope.payload.more_summaries)
8904 {
8905 let project_path = ProjectPath {
8906 worktree_id,
8907 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8908 };
8909 let path = project_path.path.clone();
8910 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8911 let summary = DiagnosticSummary {
8912 error_count: message_summary.error_count as usize,
8913 warning_count: message_summary.warning_count as usize,
8914 };
8915
8916 if summary.is_empty() {
8917 if let Some(worktree_summaries) =
8918 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8919 && let Some(summaries) = worktree_summaries.get_mut(&path)
8920 {
8921 summaries.remove(&server_id);
8922 if summaries.is_empty() {
8923 worktree_summaries.remove(&path);
8924 }
8925 }
8926 } else {
8927 lsp_store
8928 .diagnostic_summaries
8929 .entry(worktree_id)
8930 .or_default()
8931 .entry(path)
8932 .or_default()
8933 .insert(server_id, summary);
8934 }
8935
8936 if let Some((_, project_id)) = &lsp_store.downstream_client {
8937 match &mut diagnostics_summary {
8938 Some(diagnostics_summary) => {
8939 diagnostics_summary
8940 .more_summaries
8941 .push(proto::DiagnosticSummary {
8942 path: project_path.path.as_ref().to_proto(),
8943 language_server_id: server_id.0 as u64,
8944 error_count: summary.error_count as u32,
8945 warning_count: summary.warning_count as u32,
8946 })
8947 }
8948 None => {
8949 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8950 project_id: *project_id,
8951 worktree_id: worktree_id.to_proto(),
8952 summary: Some(proto::DiagnosticSummary {
8953 path: project_path.path.as_ref().to_proto(),
8954 language_server_id: server_id.0 as u64,
8955 error_count: summary.error_count as u32,
8956 warning_count: summary.warning_count as u32,
8957 }),
8958 more_summaries: Vec::new(),
8959 })
8960 }
8961 }
8962 }
8963 updated_diagnostics_paths
8964 .entry(server_id)
8965 .or_insert_with(Vec::new)
8966 .push(project_path);
8967 }
8968
8969 if let Some((diagnostics_summary, (downstream_client, _))) =
8970 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8971 {
8972 downstream_client.send(diagnostics_summary).log_err();
8973 }
8974 for (server_id, paths) in updated_diagnostics_paths {
8975 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8976 }
8977 Ok(())
8978 })?
8979 }
8980
8981 async fn handle_start_language_server(
8982 lsp_store: Entity<Self>,
8983 envelope: TypedEnvelope<proto::StartLanguageServer>,
8984 mut cx: AsyncApp,
8985 ) -> Result<()> {
8986 let server = envelope.payload.server.context("invalid server")?;
8987 let server_capabilities =
8988 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8989 .with_context(|| {
8990 format!(
8991 "incorrect server capabilities {}",
8992 envelope.payload.capabilities
8993 )
8994 })?;
8995 lsp_store.update(&mut cx, |lsp_store, cx| {
8996 let server_id = LanguageServerId(server.id as usize);
8997 let server_name = LanguageServerName::from_proto(server.name.clone());
8998 lsp_store
8999 .lsp_server_capabilities
9000 .insert(server_id, server_capabilities);
9001 lsp_store.language_server_statuses.insert(
9002 server_id,
9003 LanguageServerStatus {
9004 name: server_name.clone(),
9005 pending_work: Default::default(),
9006 has_pending_diagnostic_updates: false,
9007 progress_tokens: Default::default(),
9008 worktree: server.worktree_id.map(WorktreeId::from_proto),
9009 },
9010 );
9011 cx.emit(LspStoreEvent::LanguageServerAdded(
9012 server_id,
9013 server_name,
9014 server.worktree_id.map(WorktreeId::from_proto),
9015 ));
9016 cx.notify();
9017 })?;
9018 Ok(())
9019 }
9020
9021 async fn handle_update_language_server(
9022 lsp_store: Entity<Self>,
9023 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9024 mut cx: AsyncApp,
9025 ) -> Result<()> {
9026 lsp_store.update(&mut cx, |lsp_store, cx| {
9027 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9028
9029 match envelope.payload.variant.context("invalid variant")? {
9030 proto::update_language_server::Variant::WorkStart(payload) => {
9031 lsp_store.on_lsp_work_start(
9032 language_server_id,
9033 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9034 .context("invalid progress token value")?,
9035 LanguageServerProgress {
9036 title: payload.title,
9037 is_disk_based_diagnostics_progress: false,
9038 is_cancellable: payload.is_cancellable.unwrap_or(false),
9039 message: payload.message,
9040 percentage: payload.percentage.map(|p| p as usize),
9041 last_update_at: cx.background_executor().now(),
9042 },
9043 cx,
9044 );
9045 }
9046 proto::update_language_server::Variant::WorkProgress(payload) => {
9047 lsp_store.on_lsp_work_progress(
9048 language_server_id,
9049 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9050 .context("invalid progress token value")?,
9051 LanguageServerProgress {
9052 title: None,
9053 is_disk_based_diagnostics_progress: false,
9054 is_cancellable: payload.is_cancellable.unwrap_or(false),
9055 message: payload.message,
9056 percentage: payload.percentage.map(|p| p as usize),
9057 last_update_at: cx.background_executor().now(),
9058 },
9059 cx,
9060 );
9061 }
9062
9063 proto::update_language_server::Variant::WorkEnd(payload) => {
9064 lsp_store.on_lsp_work_end(
9065 language_server_id,
9066 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9067 .context("invalid progress token value")?,
9068 cx,
9069 );
9070 }
9071
9072 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9073 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9074 }
9075
9076 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9077 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9078 }
9079
9080 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9081 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9082 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9083 cx.emit(LspStoreEvent::LanguageServerUpdate {
9084 language_server_id,
9085 name: envelope
9086 .payload
9087 .server_name
9088 .map(SharedString::new)
9089 .map(LanguageServerName),
9090 message: non_lsp,
9091 });
9092 }
9093 }
9094
9095 Ok(())
9096 })?
9097 }
9098
9099 async fn handle_language_server_log(
9100 this: Entity<Self>,
9101 envelope: TypedEnvelope<proto::LanguageServerLog>,
9102 mut cx: AsyncApp,
9103 ) -> Result<()> {
9104 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9105 let log_type = envelope
9106 .payload
9107 .log_type
9108 .map(LanguageServerLogType::from_proto)
9109 .context("invalid language server log type")?;
9110
9111 let message = envelope.payload.message;
9112
9113 this.update(&mut cx, |_, cx| {
9114 cx.emit(LspStoreEvent::LanguageServerLog(
9115 language_server_id,
9116 log_type,
9117 message,
9118 ));
9119 })
9120 }
9121
9122 async fn handle_lsp_ext_cancel_flycheck(
9123 lsp_store: Entity<Self>,
9124 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9125 cx: AsyncApp,
9126 ) -> Result<proto::Ack> {
9127 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9128 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9129 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9130 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9131 } else {
9132 None
9133 }
9134 })?;
9135 if let Some(task) = task {
9136 task.context("handling lsp ext cancel flycheck")?;
9137 }
9138
9139 Ok(proto::Ack {})
9140 }
9141
9142 async fn handle_lsp_ext_run_flycheck(
9143 lsp_store: Entity<Self>,
9144 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9145 mut cx: AsyncApp,
9146 ) -> Result<proto::Ack> {
9147 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9148 lsp_store.update(&mut cx, |lsp_store, cx| {
9149 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9150 let text_document = if envelope.payload.current_file_only {
9151 let buffer_id = envelope
9152 .payload
9153 .buffer_id
9154 .map(|id| BufferId::new(id))
9155 .transpose()?;
9156 buffer_id
9157 .and_then(|buffer_id| {
9158 lsp_store
9159 .buffer_store()
9160 .read(cx)
9161 .get(buffer_id)
9162 .and_then(|buffer| {
9163 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9164 })
9165 .map(|path| make_text_document_identifier(&path))
9166 })
9167 .transpose()?
9168 } else {
9169 None
9170 };
9171 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9172 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9173 )?;
9174 }
9175 anyhow::Ok(())
9176 })??;
9177
9178 Ok(proto::Ack {})
9179 }
9180
9181 async fn handle_lsp_ext_clear_flycheck(
9182 lsp_store: Entity<Self>,
9183 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9184 cx: AsyncApp,
9185 ) -> Result<proto::Ack> {
9186 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9187 lsp_store
9188 .read_with(&cx, |lsp_store, _| {
9189 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9190 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9191 } else {
9192 None
9193 }
9194 })
9195 .context("handling lsp ext clear flycheck")?;
9196
9197 Ok(proto::Ack {})
9198 }
9199
9200 pub fn disk_based_diagnostics_started(
9201 &mut self,
9202 language_server_id: LanguageServerId,
9203 cx: &mut Context<Self>,
9204 ) {
9205 if let Some(language_server_status) =
9206 self.language_server_statuses.get_mut(&language_server_id)
9207 {
9208 language_server_status.has_pending_diagnostic_updates = true;
9209 }
9210
9211 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9212 cx.emit(LspStoreEvent::LanguageServerUpdate {
9213 language_server_id,
9214 name: self
9215 .language_server_adapter_for_id(language_server_id)
9216 .map(|adapter| adapter.name()),
9217 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9218 Default::default(),
9219 ),
9220 })
9221 }
9222
9223 pub fn disk_based_diagnostics_finished(
9224 &mut self,
9225 language_server_id: LanguageServerId,
9226 cx: &mut Context<Self>,
9227 ) {
9228 if let Some(language_server_status) =
9229 self.language_server_statuses.get_mut(&language_server_id)
9230 {
9231 language_server_status.has_pending_diagnostic_updates = false;
9232 }
9233
9234 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9235 cx.emit(LspStoreEvent::LanguageServerUpdate {
9236 language_server_id,
9237 name: self
9238 .language_server_adapter_for_id(language_server_id)
9239 .map(|adapter| adapter.name()),
9240 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9241 Default::default(),
9242 ),
9243 })
9244 }
9245
9246 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9247 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9248 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9249 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9250 // the language server might take some time to publish diagnostics.
9251 fn simulate_disk_based_diagnostics_events_if_needed(
9252 &mut self,
9253 language_server_id: LanguageServerId,
9254 cx: &mut Context<Self>,
9255 ) {
9256 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9257
9258 let Some(LanguageServerState::Running {
9259 simulate_disk_based_diagnostics_completion,
9260 adapter,
9261 ..
9262 }) = self
9263 .as_local_mut()
9264 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9265 else {
9266 return;
9267 };
9268
9269 if adapter.disk_based_diagnostics_progress_token.is_some() {
9270 return;
9271 }
9272
9273 let prev_task =
9274 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9275 cx.background_executor()
9276 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9277 .await;
9278
9279 this.update(cx, |this, cx| {
9280 this.disk_based_diagnostics_finished(language_server_id, cx);
9281
9282 if let Some(LanguageServerState::Running {
9283 simulate_disk_based_diagnostics_completion,
9284 ..
9285 }) = this.as_local_mut().and_then(|local_store| {
9286 local_store.language_servers.get_mut(&language_server_id)
9287 }) {
9288 *simulate_disk_based_diagnostics_completion = None;
9289 }
9290 })
9291 .ok();
9292 }));
9293
9294 if prev_task.is_none() {
9295 self.disk_based_diagnostics_started(language_server_id, cx);
9296 }
9297 }
9298
9299 pub fn language_server_statuses(
9300 &self,
9301 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9302 self.language_server_statuses
9303 .iter()
9304 .map(|(key, value)| (*key, value))
9305 }
9306
9307 pub(super) fn did_rename_entry(
9308 &self,
9309 worktree_id: WorktreeId,
9310 old_path: &Path,
9311 new_path: &Path,
9312 is_dir: bool,
9313 ) {
9314 maybe!({
9315 let local_store = self.as_local()?;
9316
9317 let old_uri = lsp::Uri::from_file_path(old_path)
9318 .ok()
9319 .map(|uri| uri.to_string())?;
9320 let new_uri = lsp::Uri::from_file_path(new_path)
9321 .ok()
9322 .map(|uri| uri.to_string())?;
9323
9324 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9325 let Some(filter) = local_store
9326 .language_server_paths_watched_for_rename
9327 .get(&language_server.server_id())
9328 else {
9329 continue;
9330 };
9331
9332 if filter.should_send_did_rename(&old_uri, is_dir) {
9333 language_server
9334 .notify::<DidRenameFiles>(RenameFilesParams {
9335 files: vec![FileRename {
9336 old_uri: old_uri.clone(),
9337 new_uri: new_uri.clone(),
9338 }],
9339 })
9340 .ok();
9341 }
9342 }
9343 Some(())
9344 });
9345 }
9346
9347 pub(super) fn will_rename_entry(
9348 this: WeakEntity<Self>,
9349 worktree_id: WorktreeId,
9350 old_path: &Path,
9351 new_path: &Path,
9352 is_dir: bool,
9353 cx: AsyncApp,
9354 ) -> Task<ProjectTransaction> {
9355 let old_uri = lsp::Uri::from_file_path(old_path)
9356 .ok()
9357 .map(|uri| uri.to_string());
9358 let new_uri = lsp::Uri::from_file_path(new_path)
9359 .ok()
9360 .map(|uri| uri.to_string());
9361 cx.spawn(async move |cx| {
9362 let mut tasks = vec![];
9363 this.update(cx, |this, cx| {
9364 let local_store = this.as_local()?;
9365 let old_uri = old_uri?;
9366 let new_uri = new_uri?;
9367 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9368 let Some(filter) = local_store
9369 .language_server_paths_watched_for_rename
9370 .get(&language_server.server_id())
9371 else {
9372 continue;
9373 };
9374
9375 if filter.should_send_will_rename(&old_uri, is_dir) {
9376 let apply_edit = cx.spawn({
9377 let old_uri = old_uri.clone();
9378 let new_uri = new_uri.clone();
9379 let language_server = language_server.clone();
9380 async move |this, cx| {
9381 let edit = language_server
9382 .request::<WillRenameFiles>(RenameFilesParams {
9383 files: vec![FileRename { old_uri, new_uri }],
9384 })
9385 .await
9386 .into_response()
9387 .context("will rename files")
9388 .log_err()
9389 .flatten()?;
9390
9391 let transaction = LocalLspStore::deserialize_workspace_edit(
9392 this.upgrade()?,
9393 edit,
9394 false,
9395 language_server.clone(),
9396 cx,
9397 )
9398 .await
9399 .ok()?;
9400 Some(transaction)
9401 }
9402 });
9403 tasks.push(apply_edit);
9404 }
9405 }
9406 Some(())
9407 })
9408 .ok()
9409 .flatten();
9410 let mut merged_transaction = ProjectTransaction::default();
9411 for task in tasks {
9412 // Await on tasks sequentially so that the order of application of edits is deterministic
9413 // (at least with regards to the order of registration of language servers)
9414 if let Some(transaction) = task.await {
9415 for (buffer, buffer_transaction) in transaction.0 {
9416 merged_transaction.0.insert(buffer, buffer_transaction);
9417 }
9418 }
9419 }
9420 merged_transaction
9421 })
9422 }
9423
9424 fn lsp_notify_abs_paths_changed(
9425 &mut self,
9426 server_id: LanguageServerId,
9427 changes: Vec<PathEvent>,
9428 ) {
9429 maybe!({
9430 let server = self.language_server_for_id(server_id)?;
9431 let changes = changes
9432 .into_iter()
9433 .filter_map(|event| {
9434 let typ = match event.kind? {
9435 PathEventKind::Created => lsp::FileChangeType::CREATED,
9436 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9437 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9438 };
9439 Some(lsp::FileEvent {
9440 uri: file_path_to_lsp_url(&event.path).log_err()?,
9441 typ,
9442 })
9443 })
9444 .collect::<Vec<_>>();
9445 if !changes.is_empty() {
9446 server
9447 .notify::<lsp::notification::DidChangeWatchedFiles>(
9448 lsp::DidChangeWatchedFilesParams { changes },
9449 )
9450 .ok();
9451 }
9452 Some(())
9453 });
9454 }
9455
9456 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9457 self.as_local()?.language_server_for_id(id)
9458 }
9459
9460 fn on_lsp_progress(
9461 &mut self,
9462 progress_params: lsp::ProgressParams,
9463 language_server_id: LanguageServerId,
9464 disk_based_diagnostics_progress_token: Option<String>,
9465 cx: &mut Context<Self>,
9466 ) {
9467 match progress_params.value {
9468 lsp::ProgressParamsValue::WorkDone(progress) => {
9469 self.handle_work_done_progress(
9470 progress,
9471 language_server_id,
9472 disk_based_diagnostics_progress_token,
9473 ProgressToken::from_lsp(progress_params.token),
9474 cx,
9475 );
9476 }
9477 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9478 let identifier = match progress_params.token {
9479 lsp::NumberOrString::Number(_) => None,
9480 lsp::NumberOrString::String(token) => token
9481 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9482 .map(|(_, id)| id.to_owned()),
9483 };
9484 if let Some(LanguageServerState::Running {
9485 workspace_diagnostics_refresh_tasks,
9486 ..
9487 }) = self
9488 .as_local_mut()
9489 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9490 && let Some(workspace_diagnostics) =
9491 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9492 {
9493 workspace_diagnostics.progress_tx.try_send(()).ok();
9494 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9495 }
9496 }
9497 }
9498 }
9499
9500 fn handle_work_done_progress(
9501 &mut self,
9502 progress: lsp::WorkDoneProgress,
9503 language_server_id: LanguageServerId,
9504 disk_based_diagnostics_progress_token: Option<String>,
9505 token: ProgressToken,
9506 cx: &mut Context<Self>,
9507 ) {
9508 let language_server_status =
9509 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9510 status
9511 } else {
9512 return;
9513 };
9514
9515 if !language_server_status.progress_tokens.contains(&token) {
9516 return;
9517 }
9518
9519 let is_disk_based_diagnostics_progress =
9520 if let (Some(disk_based_token), ProgressToken::String(token)) =
9521 (&disk_based_diagnostics_progress_token, &token)
9522 {
9523 token.starts_with(disk_based_token)
9524 } else {
9525 false
9526 };
9527
9528 match progress {
9529 lsp::WorkDoneProgress::Begin(report) => {
9530 if is_disk_based_diagnostics_progress {
9531 self.disk_based_diagnostics_started(language_server_id, cx);
9532 }
9533 self.on_lsp_work_start(
9534 language_server_id,
9535 token.clone(),
9536 LanguageServerProgress {
9537 title: Some(report.title),
9538 is_disk_based_diagnostics_progress,
9539 is_cancellable: report.cancellable.unwrap_or(false),
9540 message: report.message.clone(),
9541 percentage: report.percentage.map(|p| p as usize),
9542 last_update_at: cx.background_executor().now(),
9543 },
9544 cx,
9545 );
9546 }
9547 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9548 language_server_id,
9549 token,
9550 LanguageServerProgress {
9551 title: None,
9552 is_disk_based_diagnostics_progress,
9553 is_cancellable: report.cancellable.unwrap_or(false),
9554 message: report.message,
9555 percentage: report.percentage.map(|p| p as usize),
9556 last_update_at: cx.background_executor().now(),
9557 },
9558 cx,
9559 ),
9560 lsp::WorkDoneProgress::End(_) => {
9561 language_server_status.progress_tokens.remove(&token);
9562 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9563 if is_disk_based_diagnostics_progress {
9564 self.disk_based_diagnostics_finished(language_server_id, cx);
9565 }
9566 }
9567 }
9568 }
9569
9570 fn on_lsp_work_start(
9571 &mut self,
9572 language_server_id: LanguageServerId,
9573 token: ProgressToken,
9574 progress: LanguageServerProgress,
9575 cx: &mut Context<Self>,
9576 ) {
9577 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9578 status.pending_work.insert(token.clone(), progress.clone());
9579 cx.notify();
9580 }
9581 cx.emit(LspStoreEvent::LanguageServerUpdate {
9582 language_server_id,
9583 name: self
9584 .language_server_adapter_for_id(language_server_id)
9585 .map(|adapter| adapter.name()),
9586 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9587 token: Some(token.to_proto()),
9588 title: progress.title,
9589 message: progress.message,
9590 percentage: progress.percentage.map(|p| p as u32),
9591 is_cancellable: Some(progress.is_cancellable),
9592 }),
9593 })
9594 }
9595
9596 fn on_lsp_work_progress(
9597 &mut self,
9598 language_server_id: LanguageServerId,
9599 token: ProgressToken,
9600 progress: LanguageServerProgress,
9601 cx: &mut Context<Self>,
9602 ) {
9603 let mut did_update = false;
9604 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9605 match status.pending_work.entry(token.clone()) {
9606 btree_map::Entry::Vacant(entry) => {
9607 entry.insert(progress.clone());
9608 did_update = true;
9609 }
9610 btree_map::Entry::Occupied(mut entry) => {
9611 let entry = entry.get_mut();
9612 if (progress.last_update_at - entry.last_update_at)
9613 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9614 {
9615 entry.last_update_at = progress.last_update_at;
9616 if progress.message.is_some() {
9617 entry.message = progress.message.clone();
9618 }
9619 if progress.percentage.is_some() {
9620 entry.percentage = progress.percentage;
9621 }
9622 if progress.is_cancellable != entry.is_cancellable {
9623 entry.is_cancellable = progress.is_cancellable;
9624 }
9625 did_update = true;
9626 }
9627 }
9628 }
9629 }
9630
9631 if did_update {
9632 cx.emit(LspStoreEvent::LanguageServerUpdate {
9633 language_server_id,
9634 name: self
9635 .language_server_adapter_for_id(language_server_id)
9636 .map(|adapter| adapter.name()),
9637 message: proto::update_language_server::Variant::WorkProgress(
9638 proto::LspWorkProgress {
9639 token: Some(token.to_proto()),
9640 message: progress.message,
9641 percentage: progress.percentage.map(|p| p as u32),
9642 is_cancellable: Some(progress.is_cancellable),
9643 },
9644 ),
9645 })
9646 }
9647 }
9648
9649 fn on_lsp_work_end(
9650 &mut self,
9651 language_server_id: LanguageServerId,
9652 token: ProgressToken,
9653 cx: &mut Context<Self>,
9654 ) {
9655 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9656 if let Some(work) = status.pending_work.remove(&token)
9657 && !work.is_disk_based_diagnostics_progress
9658 {
9659 cx.emit(LspStoreEvent::RefreshInlayHints {
9660 server_id: language_server_id,
9661 request_id: None,
9662 });
9663 }
9664 cx.notify();
9665 }
9666
9667 cx.emit(LspStoreEvent::LanguageServerUpdate {
9668 language_server_id,
9669 name: self
9670 .language_server_adapter_for_id(language_server_id)
9671 .map(|adapter| adapter.name()),
9672 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9673 token: Some(token.to_proto()),
9674 }),
9675 })
9676 }
9677
9678 pub async fn handle_resolve_completion_documentation(
9679 this: Entity<Self>,
9680 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9681 mut cx: AsyncApp,
9682 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9683 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9684
9685 let completion = this
9686 .read_with(&cx, |this, cx| {
9687 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9688 let server = this
9689 .language_server_for_id(id)
9690 .with_context(|| format!("No language server {id}"))?;
9691
9692 anyhow::Ok(cx.background_spawn(async move {
9693 let can_resolve = server
9694 .capabilities()
9695 .completion_provider
9696 .as_ref()
9697 .and_then(|options| options.resolve_provider)
9698 .unwrap_or(false);
9699 if can_resolve {
9700 server
9701 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9702 .await
9703 .into_response()
9704 .context("resolve completion item")
9705 } else {
9706 anyhow::Ok(lsp_completion)
9707 }
9708 }))
9709 })??
9710 .await?;
9711
9712 let mut documentation_is_markdown = false;
9713 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9714 let documentation = match completion.documentation {
9715 Some(lsp::Documentation::String(text)) => text,
9716
9717 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9718 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9719 value
9720 }
9721
9722 _ => String::new(),
9723 };
9724
9725 // If we have a new buffer_id, that means we're talking to a new client
9726 // and want to check for new text_edits in the completion too.
9727 let mut old_replace_start = None;
9728 let mut old_replace_end = None;
9729 let mut old_insert_start = None;
9730 let mut old_insert_end = None;
9731 let mut new_text = String::default();
9732 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9733 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9734 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9735 anyhow::Ok(buffer.read(cx).snapshot())
9736 })??;
9737
9738 if let Some(text_edit) = completion.text_edit.as_ref() {
9739 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9740
9741 if let Some(mut edit) = edit {
9742 LineEnding::normalize(&mut edit.new_text);
9743
9744 new_text = edit.new_text;
9745 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9746 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9747 if let Some(insert_range) = edit.insert_range {
9748 old_insert_start = Some(serialize_anchor(&insert_range.start));
9749 old_insert_end = Some(serialize_anchor(&insert_range.end));
9750 }
9751 }
9752 }
9753 }
9754
9755 Ok(proto::ResolveCompletionDocumentationResponse {
9756 documentation,
9757 documentation_is_markdown,
9758 old_replace_start,
9759 old_replace_end,
9760 new_text,
9761 lsp_completion,
9762 old_insert_start,
9763 old_insert_end,
9764 })
9765 }
9766
9767 async fn handle_on_type_formatting(
9768 this: Entity<Self>,
9769 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9770 mut cx: AsyncApp,
9771 ) -> Result<proto::OnTypeFormattingResponse> {
9772 let on_type_formatting = this.update(&mut cx, |this, cx| {
9773 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9774 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9775 let position = envelope
9776 .payload
9777 .position
9778 .and_then(deserialize_anchor)
9779 .context("invalid position")?;
9780 anyhow::Ok(this.apply_on_type_formatting(
9781 buffer,
9782 position,
9783 envelope.payload.trigger.clone(),
9784 cx,
9785 ))
9786 })??;
9787
9788 let transaction = on_type_formatting
9789 .await?
9790 .as_ref()
9791 .map(language::proto::serialize_transaction);
9792 Ok(proto::OnTypeFormattingResponse { transaction })
9793 }
9794
9795 async fn handle_refresh_inlay_hints(
9796 lsp_store: Entity<Self>,
9797 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9798 mut cx: AsyncApp,
9799 ) -> Result<proto::Ack> {
9800 lsp_store.update(&mut cx, |_, cx| {
9801 cx.emit(LspStoreEvent::RefreshInlayHints {
9802 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9803 request_id: envelope.payload.request_id.map(|id| id as usize),
9804 });
9805 })?;
9806 Ok(proto::Ack {})
9807 }
9808
9809 async fn handle_pull_workspace_diagnostics(
9810 lsp_store: Entity<Self>,
9811 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9812 mut cx: AsyncApp,
9813 ) -> Result<proto::Ack> {
9814 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9815 lsp_store.update(&mut cx, |lsp_store, _| {
9816 lsp_store.pull_workspace_diagnostics(server_id);
9817 })?;
9818 Ok(proto::Ack {})
9819 }
9820
9821 async fn handle_get_color_presentation(
9822 lsp_store: Entity<Self>,
9823 envelope: TypedEnvelope<proto::GetColorPresentation>,
9824 mut cx: AsyncApp,
9825 ) -> Result<proto::GetColorPresentationResponse> {
9826 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9827 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9828 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9829 })??;
9830
9831 let color = envelope
9832 .payload
9833 .color
9834 .context("invalid color resolve request")?;
9835 let start = color
9836 .lsp_range_start
9837 .context("invalid color resolve request")?;
9838 let end = color
9839 .lsp_range_end
9840 .context("invalid color resolve request")?;
9841
9842 let color = DocumentColor {
9843 lsp_range: lsp::Range {
9844 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9845 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9846 },
9847 color: lsp::Color {
9848 red: color.red,
9849 green: color.green,
9850 blue: color.blue,
9851 alpha: color.alpha,
9852 },
9853 resolved: false,
9854 color_presentations: Vec::new(),
9855 };
9856 let resolved_color = lsp_store
9857 .update(&mut cx, |lsp_store, cx| {
9858 lsp_store.resolve_color_presentation(
9859 color,
9860 buffer.clone(),
9861 LanguageServerId(envelope.payload.server_id as usize),
9862 cx,
9863 )
9864 })?
9865 .await
9866 .context("resolving color presentation")?;
9867
9868 Ok(proto::GetColorPresentationResponse {
9869 presentations: resolved_color
9870 .color_presentations
9871 .into_iter()
9872 .map(|presentation| proto::ColorPresentation {
9873 label: presentation.label.to_string(),
9874 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9875 additional_text_edits: presentation
9876 .additional_text_edits
9877 .into_iter()
9878 .map(serialize_lsp_edit)
9879 .collect(),
9880 })
9881 .collect(),
9882 })
9883 }
9884
9885 async fn handle_resolve_inlay_hint(
9886 lsp_store: Entity<Self>,
9887 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9888 mut cx: AsyncApp,
9889 ) -> Result<proto::ResolveInlayHintResponse> {
9890 let proto_hint = envelope
9891 .payload
9892 .hint
9893 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9894 let hint = InlayHints::proto_to_project_hint(proto_hint)
9895 .context("resolved proto inlay hint conversion")?;
9896 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9897 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9898 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9899 })??;
9900 let response_hint = lsp_store
9901 .update(&mut cx, |lsp_store, cx| {
9902 lsp_store.resolve_inlay_hint(
9903 hint,
9904 buffer,
9905 LanguageServerId(envelope.payload.language_server_id as usize),
9906 cx,
9907 )
9908 })?
9909 .await
9910 .context("inlay hints fetch")?;
9911 Ok(proto::ResolveInlayHintResponse {
9912 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9913 })
9914 }
9915
9916 async fn handle_refresh_code_lens(
9917 this: Entity<Self>,
9918 _: TypedEnvelope<proto::RefreshCodeLens>,
9919 mut cx: AsyncApp,
9920 ) -> Result<proto::Ack> {
9921 this.update(&mut cx, |_, cx| {
9922 cx.emit(LspStoreEvent::RefreshCodeLens);
9923 })?;
9924 Ok(proto::Ack {})
9925 }
9926
9927 async fn handle_open_buffer_for_symbol(
9928 this: Entity<Self>,
9929 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9930 mut cx: AsyncApp,
9931 ) -> Result<proto::OpenBufferForSymbolResponse> {
9932 let peer_id = envelope.original_sender_id().unwrap_or_default();
9933 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9934 let symbol = Self::deserialize_symbol(symbol)?;
9935 this.read_with(&cx, |this, _| {
9936 if let SymbolLocation::OutsideProject {
9937 abs_path,
9938 signature,
9939 } = &symbol.path
9940 {
9941 let new_signature = this.symbol_signature(&abs_path);
9942 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9943 }
9944 Ok(())
9945 })??;
9946 let buffer = this
9947 .update(&mut cx, |this, cx| {
9948 this.open_buffer_for_symbol(
9949 &Symbol {
9950 language_server_name: symbol.language_server_name,
9951 source_worktree_id: symbol.source_worktree_id,
9952 source_language_server_id: symbol.source_language_server_id,
9953 path: symbol.path,
9954 name: symbol.name,
9955 kind: symbol.kind,
9956 range: symbol.range,
9957 label: CodeLabel::default(),
9958 },
9959 cx,
9960 )
9961 })?
9962 .await?;
9963
9964 this.update(&mut cx, |this, cx| {
9965 let is_private = buffer
9966 .read(cx)
9967 .file()
9968 .map(|f| f.is_private())
9969 .unwrap_or_default();
9970 if is_private {
9971 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9972 } else {
9973 this.buffer_store
9974 .update(cx, |buffer_store, cx| {
9975 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9976 })
9977 .detach_and_log_err(cx);
9978 let buffer_id = buffer.read(cx).remote_id().to_proto();
9979 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9980 }
9981 })?
9982 }
9983
9984 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9985 let mut hasher = Sha256::new();
9986 hasher.update(abs_path.to_string_lossy().as_bytes());
9987 hasher.update(self.nonce.to_be_bytes());
9988 hasher.finalize().as_slice().try_into().unwrap()
9989 }
9990
9991 pub async fn handle_get_project_symbols(
9992 this: Entity<Self>,
9993 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9994 mut cx: AsyncApp,
9995 ) -> Result<proto::GetProjectSymbolsResponse> {
9996 let symbols = this
9997 .update(&mut cx, |this, cx| {
9998 this.symbols(&envelope.payload.query, cx)
9999 })?
10000 .await?;
10001
10002 Ok(proto::GetProjectSymbolsResponse {
10003 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10004 })
10005 }
10006
10007 pub async fn handle_restart_language_servers(
10008 this: Entity<Self>,
10009 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10010 mut cx: AsyncApp,
10011 ) -> Result<proto::Ack> {
10012 this.update(&mut cx, |lsp_store, cx| {
10013 let buffers =
10014 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10015 lsp_store.restart_language_servers_for_buffers(
10016 buffers,
10017 envelope
10018 .payload
10019 .only_servers
10020 .into_iter()
10021 .filter_map(|selector| {
10022 Some(match selector.selector? {
10023 proto::language_server_selector::Selector::ServerId(server_id) => {
10024 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10025 }
10026 proto::language_server_selector::Selector::Name(name) => {
10027 LanguageServerSelector::Name(LanguageServerName(
10028 SharedString::from(name),
10029 ))
10030 }
10031 })
10032 })
10033 .collect(),
10034 cx,
10035 );
10036 })?;
10037
10038 Ok(proto::Ack {})
10039 }
10040
10041 pub async fn handle_stop_language_servers(
10042 lsp_store: Entity<Self>,
10043 envelope: TypedEnvelope<proto::StopLanguageServers>,
10044 mut cx: AsyncApp,
10045 ) -> Result<proto::Ack> {
10046 lsp_store.update(&mut cx, |lsp_store, cx| {
10047 if envelope.payload.all
10048 && envelope.payload.also_servers.is_empty()
10049 && envelope.payload.buffer_ids.is_empty()
10050 {
10051 lsp_store.stop_all_language_servers(cx);
10052 } else {
10053 let buffers =
10054 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10055 lsp_store
10056 .stop_language_servers_for_buffers(
10057 buffers,
10058 envelope
10059 .payload
10060 .also_servers
10061 .into_iter()
10062 .filter_map(|selector| {
10063 Some(match selector.selector? {
10064 proto::language_server_selector::Selector::ServerId(
10065 server_id,
10066 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10067 server_id,
10068 )),
10069 proto::language_server_selector::Selector::Name(name) => {
10070 LanguageServerSelector::Name(LanguageServerName(
10071 SharedString::from(name),
10072 ))
10073 }
10074 })
10075 })
10076 .collect(),
10077 cx,
10078 )
10079 .detach_and_log_err(cx);
10080 }
10081 })?;
10082
10083 Ok(proto::Ack {})
10084 }
10085
10086 pub async fn handle_cancel_language_server_work(
10087 lsp_store: Entity<Self>,
10088 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10089 mut cx: AsyncApp,
10090 ) -> Result<proto::Ack> {
10091 lsp_store.update(&mut cx, |lsp_store, cx| {
10092 if let Some(work) = envelope.payload.work {
10093 match work {
10094 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10095 let buffers =
10096 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10097 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10098 }
10099 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10100 let server_id = LanguageServerId::from_proto(work.language_server_id);
10101 let token = work
10102 .token
10103 .map(|token| {
10104 ProgressToken::from_proto(token)
10105 .context("invalid work progress token")
10106 })
10107 .transpose()?;
10108 lsp_store.cancel_language_server_work(server_id, token, cx);
10109 }
10110 }
10111 }
10112 anyhow::Ok(())
10113 })??;
10114
10115 Ok(proto::Ack {})
10116 }
10117
10118 fn buffer_ids_to_buffers(
10119 &mut self,
10120 buffer_ids: impl Iterator<Item = u64>,
10121 cx: &mut Context<Self>,
10122 ) -> Vec<Entity<Buffer>> {
10123 buffer_ids
10124 .into_iter()
10125 .flat_map(|buffer_id| {
10126 self.buffer_store
10127 .read(cx)
10128 .get(BufferId::new(buffer_id).log_err()?)
10129 })
10130 .collect::<Vec<_>>()
10131 }
10132
10133 async fn handle_apply_additional_edits_for_completion(
10134 this: Entity<Self>,
10135 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10136 mut cx: AsyncApp,
10137 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10138 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10139 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10140 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10141 let completion = Self::deserialize_completion(
10142 envelope.payload.completion.context("invalid completion")?,
10143 )?;
10144 anyhow::Ok((buffer, completion))
10145 })??;
10146
10147 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10148 this.apply_additional_edits_for_completion(
10149 buffer,
10150 Rc::new(RefCell::new(Box::new([Completion {
10151 replace_range: completion.replace_range,
10152 new_text: completion.new_text,
10153 source: completion.source,
10154 documentation: None,
10155 label: CodeLabel::default(),
10156 match_start: None,
10157 snippet_deduplication_key: None,
10158 insert_text_mode: None,
10159 icon_path: None,
10160 confirm: None,
10161 }]))),
10162 0,
10163 false,
10164 cx,
10165 )
10166 })?;
10167
10168 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10169 transaction: apply_additional_edits
10170 .await?
10171 .as_ref()
10172 .map(language::proto::serialize_transaction),
10173 })
10174 }
10175
10176 pub fn last_formatting_failure(&self) -> Option<&str> {
10177 self.last_formatting_failure.as_deref()
10178 }
10179
10180 pub fn reset_last_formatting_failure(&mut self) {
10181 self.last_formatting_failure = None;
10182 }
10183
10184 pub fn environment_for_buffer(
10185 &self,
10186 buffer: &Entity<Buffer>,
10187 cx: &mut Context<Self>,
10188 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10189 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10190 environment.update(cx, |env, cx| {
10191 env.buffer_environment(buffer, &self.worktree_store, cx)
10192 })
10193 } else {
10194 Task::ready(None).shared()
10195 }
10196 }
10197
10198 pub fn format(
10199 &mut self,
10200 buffers: HashSet<Entity<Buffer>>,
10201 target: LspFormatTarget,
10202 push_to_history: bool,
10203 trigger: FormatTrigger,
10204 cx: &mut Context<Self>,
10205 ) -> Task<anyhow::Result<ProjectTransaction>> {
10206 let logger = zlog::scoped!("format");
10207 if self.as_local().is_some() {
10208 zlog::trace!(logger => "Formatting locally");
10209 let logger = zlog::scoped!(logger => "local");
10210 let buffers = buffers
10211 .into_iter()
10212 .map(|buffer_handle| {
10213 let buffer = buffer_handle.read(cx);
10214 let buffer_abs_path = File::from_dyn(buffer.file())
10215 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10216
10217 (buffer_handle, buffer_abs_path, buffer.remote_id())
10218 })
10219 .collect::<Vec<_>>();
10220
10221 cx.spawn(async move |lsp_store, cx| {
10222 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10223
10224 for (handle, abs_path, id) in buffers {
10225 let env = lsp_store
10226 .update(cx, |lsp_store, cx| {
10227 lsp_store.environment_for_buffer(&handle, cx)
10228 })?
10229 .await;
10230
10231 let ranges = match &target {
10232 LspFormatTarget::Buffers => None,
10233 LspFormatTarget::Ranges(ranges) => {
10234 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10235 }
10236 };
10237
10238 formattable_buffers.push(FormattableBuffer {
10239 handle,
10240 abs_path,
10241 env,
10242 ranges,
10243 });
10244 }
10245 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10246
10247 let format_timer = zlog::time!(logger => "Formatting buffers");
10248 let result = LocalLspStore::format_locally(
10249 lsp_store.clone(),
10250 formattable_buffers,
10251 push_to_history,
10252 trigger,
10253 logger,
10254 cx,
10255 )
10256 .await;
10257 format_timer.end();
10258
10259 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10260
10261 lsp_store.update(cx, |lsp_store, _| {
10262 lsp_store.update_last_formatting_failure(&result);
10263 })?;
10264
10265 result
10266 })
10267 } else if let Some((client, project_id)) = self.upstream_client() {
10268 zlog::trace!(logger => "Formatting remotely");
10269 let logger = zlog::scoped!(logger => "remote");
10270 // Don't support formatting ranges via remote
10271 match target {
10272 LspFormatTarget::Buffers => {}
10273 LspFormatTarget::Ranges(_) => {
10274 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10275 return Task::ready(Ok(ProjectTransaction::default()));
10276 }
10277 }
10278
10279 let buffer_store = self.buffer_store();
10280 cx.spawn(async move |lsp_store, cx| {
10281 zlog::trace!(logger => "Sending remote format request");
10282 let request_timer = zlog::time!(logger => "remote format request");
10283 let result = client
10284 .request(proto::FormatBuffers {
10285 project_id,
10286 trigger: trigger as i32,
10287 buffer_ids: buffers
10288 .iter()
10289 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10290 .collect::<Result<_>>()?,
10291 })
10292 .await
10293 .and_then(|result| result.transaction.context("missing transaction"));
10294 request_timer.end();
10295
10296 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10297
10298 lsp_store.update(cx, |lsp_store, _| {
10299 lsp_store.update_last_formatting_failure(&result);
10300 })?;
10301
10302 let transaction_response = result?;
10303 let _timer = zlog::time!(logger => "deserializing project transaction");
10304 buffer_store
10305 .update(cx, |buffer_store, cx| {
10306 buffer_store.deserialize_project_transaction(
10307 transaction_response,
10308 push_to_history,
10309 cx,
10310 )
10311 })?
10312 .await
10313 })
10314 } else {
10315 zlog::trace!(logger => "Not formatting");
10316 Task::ready(Ok(ProjectTransaction::default()))
10317 }
10318 }
10319
10320 async fn handle_format_buffers(
10321 this: Entity<Self>,
10322 envelope: TypedEnvelope<proto::FormatBuffers>,
10323 mut cx: AsyncApp,
10324 ) -> Result<proto::FormatBuffersResponse> {
10325 let sender_id = envelope.original_sender_id().unwrap_or_default();
10326 let format = this.update(&mut cx, |this, cx| {
10327 let mut buffers = HashSet::default();
10328 for buffer_id in &envelope.payload.buffer_ids {
10329 let buffer_id = BufferId::new(*buffer_id)?;
10330 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10331 }
10332 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10333 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10334 })??;
10335
10336 let project_transaction = format.await?;
10337 let project_transaction = this.update(&mut cx, |this, cx| {
10338 this.buffer_store.update(cx, |buffer_store, cx| {
10339 buffer_store.serialize_project_transaction_for_peer(
10340 project_transaction,
10341 sender_id,
10342 cx,
10343 )
10344 })
10345 })?;
10346 Ok(proto::FormatBuffersResponse {
10347 transaction: Some(project_transaction),
10348 })
10349 }
10350
10351 async fn handle_apply_code_action_kind(
10352 this: Entity<Self>,
10353 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10354 mut cx: AsyncApp,
10355 ) -> Result<proto::ApplyCodeActionKindResponse> {
10356 let sender_id = envelope.original_sender_id().unwrap_or_default();
10357 let format = this.update(&mut cx, |this, cx| {
10358 let mut buffers = HashSet::default();
10359 for buffer_id in &envelope.payload.buffer_ids {
10360 let buffer_id = BufferId::new(*buffer_id)?;
10361 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10362 }
10363 let kind = match envelope.payload.kind.as_str() {
10364 "" => CodeActionKind::EMPTY,
10365 "quickfix" => CodeActionKind::QUICKFIX,
10366 "refactor" => CodeActionKind::REFACTOR,
10367 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10368 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10369 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10370 "source" => CodeActionKind::SOURCE,
10371 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10372 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10373 _ => anyhow::bail!(
10374 "Invalid code action kind {}",
10375 envelope.payload.kind.as_str()
10376 ),
10377 };
10378 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10379 })??;
10380
10381 let project_transaction = format.await?;
10382 let project_transaction = this.update(&mut cx, |this, cx| {
10383 this.buffer_store.update(cx, |buffer_store, cx| {
10384 buffer_store.serialize_project_transaction_for_peer(
10385 project_transaction,
10386 sender_id,
10387 cx,
10388 )
10389 })
10390 })?;
10391 Ok(proto::ApplyCodeActionKindResponse {
10392 transaction: Some(project_transaction),
10393 })
10394 }
10395
10396 async fn shutdown_language_server(
10397 server_state: Option<LanguageServerState>,
10398 name: LanguageServerName,
10399 cx: &mut AsyncApp,
10400 ) {
10401 let server = match server_state {
10402 Some(LanguageServerState::Starting { startup, .. }) => {
10403 let mut timer = cx
10404 .background_executor()
10405 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10406 .fuse();
10407
10408 select! {
10409 server = startup.fuse() => server,
10410 () = timer => {
10411 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10412 None
10413 },
10414 }
10415 }
10416
10417 Some(LanguageServerState::Running { server, .. }) => Some(server),
10418
10419 None => None,
10420 };
10421
10422 if let Some(server) = server
10423 && let Some(shutdown) = server.shutdown()
10424 {
10425 shutdown.await;
10426 }
10427 }
10428
10429 // Returns a list of all of the worktrees which no longer have a language server and the root path
10430 // for the stopped server
10431 fn stop_local_language_server(
10432 &mut self,
10433 server_id: LanguageServerId,
10434 cx: &mut Context<Self>,
10435 ) -> Task<()> {
10436 let local = match &mut self.mode {
10437 LspStoreMode::Local(local) => local,
10438 _ => {
10439 return Task::ready(());
10440 }
10441 };
10442
10443 // Remove this server ID from all entries in the given worktree.
10444 local
10445 .language_server_ids
10446 .retain(|_, state| state.id != server_id);
10447 self.buffer_store.update(cx, |buffer_store, cx| {
10448 for buffer in buffer_store.buffers() {
10449 buffer.update(cx, |buffer, cx| {
10450 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10451 buffer.set_completion_triggers(server_id, Default::default(), cx);
10452 });
10453 }
10454 });
10455
10456 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10457 summaries.retain(|path, summaries_by_server_id| {
10458 if summaries_by_server_id.remove(&server_id).is_some() {
10459 if let Some((client, project_id)) = self.downstream_client.clone() {
10460 client
10461 .send(proto::UpdateDiagnosticSummary {
10462 project_id,
10463 worktree_id: worktree_id.to_proto(),
10464 summary: Some(proto::DiagnosticSummary {
10465 path: path.as_ref().to_proto(),
10466 language_server_id: server_id.0 as u64,
10467 error_count: 0,
10468 warning_count: 0,
10469 }),
10470 more_summaries: Vec::new(),
10471 })
10472 .log_err();
10473 }
10474 !summaries_by_server_id.is_empty()
10475 } else {
10476 true
10477 }
10478 });
10479 }
10480
10481 let local = self.as_local_mut().unwrap();
10482 for diagnostics in local.diagnostics.values_mut() {
10483 diagnostics.retain(|_, diagnostics_by_server_id| {
10484 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10485 diagnostics_by_server_id.remove(ix);
10486 !diagnostics_by_server_id.is_empty()
10487 } else {
10488 true
10489 }
10490 });
10491 }
10492 local.language_server_watched_paths.remove(&server_id);
10493
10494 let server_state = local.language_servers.remove(&server_id);
10495 self.cleanup_lsp_data(server_id);
10496 let name = self
10497 .language_server_statuses
10498 .remove(&server_id)
10499 .map(|status| status.name)
10500 .or_else(|| {
10501 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10502 Some(adapter.name())
10503 } else {
10504 None
10505 }
10506 });
10507
10508 if let Some(name) = name {
10509 log::info!("stopping language server {name}");
10510 self.languages
10511 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10512 cx.notify();
10513
10514 return cx.spawn(async move |lsp_store, cx| {
10515 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10516 lsp_store
10517 .update(cx, |lsp_store, cx| {
10518 lsp_store
10519 .languages
10520 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10521 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10522 cx.notify();
10523 })
10524 .ok();
10525 });
10526 }
10527
10528 if server_state.is_some() {
10529 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10530 }
10531 Task::ready(())
10532 }
10533
10534 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10535 if let Some((client, project_id)) = self.upstream_client() {
10536 let request = client.request(proto::StopLanguageServers {
10537 project_id,
10538 buffer_ids: Vec::new(),
10539 also_servers: Vec::new(),
10540 all: true,
10541 });
10542 cx.background_spawn(request).detach_and_log_err(cx);
10543 } else {
10544 let Some(local) = self.as_local_mut() else {
10545 return;
10546 };
10547 let language_servers_to_stop = local
10548 .language_server_ids
10549 .values()
10550 .map(|state| state.id)
10551 .collect();
10552 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10553 let tasks = language_servers_to_stop
10554 .into_iter()
10555 .map(|server| self.stop_local_language_server(server, cx))
10556 .collect::<Vec<_>>();
10557 cx.background_spawn(async move {
10558 futures::future::join_all(tasks).await;
10559 })
10560 .detach();
10561 }
10562 }
10563
10564 pub fn restart_language_servers_for_buffers(
10565 &mut self,
10566 buffers: Vec<Entity<Buffer>>,
10567 only_restart_servers: HashSet<LanguageServerSelector>,
10568 cx: &mut Context<Self>,
10569 ) {
10570 if let Some((client, project_id)) = self.upstream_client() {
10571 let request = client.request(proto::RestartLanguageServers {
10572 project_id,
10573 buffer_ids: buffers
10574 .into_iter()
10575 .map(|b| b.read(cx).remote_id().to_proto())
10576 .collect(),
10577 only_servers: only_restart_servers
10578 .into_iter()
10579 .map(|selector| {
10580 let selector = match selector {
10581 LanguageServerSelector::Id(language_server_id) => {
10582 proto::language_server_selector::Selector::ServerId(
10583 language_server_id.to_proto(),
10584 )
10585 }
10586 LanguageServerSelector::Name(language_server_name) => {
10587 proto::language_server_selector::Selector::Name(
10588 language_server_name.to_string(),
10589 )
10590 }
10591 };
10592 proto::LanguageServerSelector {
10593 selector: Some(selector),
10594 }
10595 })
10596 .collect(),
10597 all: false,
10598 });
10599 cx.background_spawn(request).detach_and_log_err(cx);
10600 } else {
10601 let stop_task = if only_restart_servers.is_empty() {
10602 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10603 } else {
10604 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10605 };
10606 cx.spawn(async move |lsp_store, cx| {
10607 stop_task.await;
10608 lsp_store
10609 .update(cx, |lsp_store, cx| {
10610 for buffer in buffers {
10611 lsp_store.register_buffer_with_language_servers(
10612 &buffer,
10613 only_restart_servers.clone(),
10614 true,
10615 cx,
10616 );
10617 }
10618 })
10619 .ok()
10620 })
10621 .detach();
10622 }
10623 }
10624
10625 pub fn stop_language_servers_for_buffers(
10626 &mut self,
10627 buffers: Vec<Entity<Buffer>>,
10628 also_stop_servers: HashSet<LanguageServerSelector>,
10629 cx: &mut Context<Self>,
10630 ) -> Task<Result<()>> {
10631 if let Some((client, project_id)) = self.upstream_client() {
10632 let request = client.request(proto::StopLanguageServers {
10633 project_id,
10634 buffer_ids: buffers
10635 .into_iter()
10636 .map(|b| b.read(cx).remote_id().to_proto())
10637 .collect(),
10638 also_servers: also_stop_servers
10639 .into_iter()
10640 .map(|selector| {
10641 let selector = match selector {
10642 LanguageServerSelector::Id(language_server_id) => {
10643 proto::language_server_selector::Selector::ServerId(
10644 language_server_id.to_proto(),
10645 )
10646 }
10647 LanguageServerSelector::Name(language_server_name) => {
10648 proto::language_server_selector::Selector::Name(
10649 language_server_name.to_string(),
10650 )
10651 }
10652 };
10653 proto::LanguageServerSelector {
10654 selector: Some(selector),
10655 }
10656 })
10657 .collect(),
10658 all: false,
10659 });
10660 cx.background_spawn(async move {
10661 let _ = request.await?;
10662 Ok(())
10663 })
10664 } else {
10665 let task =
10666 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10667 cx.background_spawn(async move {
10668 task.await;
10669 Ok(())
10670 })
10671 }
10672 }
10673
10674 fn stop_local_language_servers_for_buffers(
10675 &mut self,
10676 buffers: &[Entity<Buffer>],
10677 also_stop_servers: HashSet<LanguageServerSelector>,
10678 cx: &mut Context<Self>,
10679 ) -> Task<()> {
10680 let Some(local) = self.as_local_mut() else {
10681 return Task::ready(());
10682 };
10683 let mut language_server_names_to_stop = BTreeSet::default();
10684 let mut language_servers_to_stop = also_stop_servers
10685 .into_iter()
10686 .flat_map(|selector| match selector {
10687 LanguageServerSelector::Id(id) => Some(id),
10688 LanguageServerSelector::Name(name) => {
10689 language_server_names_to_stop.insert(name);
10690 None
10691 }
10692 })
10693 .collect::<BTreeSet<_>>();
10694
10695 let mut covered_worktrees = HashSet::default();
10696 for buffer in buffers {
10697 buffer.update(cx, |buffer, cx| {
10698 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10699 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10700 && covered_worktrees.insert(worktree_id)
10701 {
10702 language_server_names_to_stop.retain(|name| {
10703 let old_ids_count = language_servers_to_stop.len();
10704 let all_language_servers_with_this_name = local
10705 .language_server_ids
10706 .iter()
10707 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10708 language_servers_to_stop.extend(all_language_servers_with_this_name);
10709 old_ids_count == language_servers_to_stop.len()
10710 });
10711 }
10712 });
10713 }
10714 for name in language_server_names_to_stop {
10715 language_servers_to_stop.extend(
10716 local
10717 .language_server_ids
10718 .iter()
10719 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10720 );
10721 }
10722
10723 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10724 let tasks = language_servers_to_stop
10725 .into_iter()
10726 .map(|server| self.stop_local_language_server(server, cx))
10727 .collect::<Vec<_>>();
10728
10729 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10730 }
10731
10732 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10733 let (worktree, relative_path) =
10734 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10735
10736 let project_path = ProjectPath {
10737 worktree_id: worktree.read(cx).id(),
10738 path: relative_path,
10739 };
10740
10741 Some(
10742 self.buffer_store()
10743 .read(cx)
10744 .get_by_path(&project_path)?
10745 .read(cx),
10746 )
10747 }
10748
10749 #[cfg(any(test, feature = "test-support"))]
10750 pub fn update_diagnostics(
10751 &mut self,
10752 server_id: LanguageServerId,
10753 diagnostics: lsp::PublishDiagnosticsParams,
10754 result_id: Option<String>,
10755 source_kind: DiagnosticSourceKind,
10756 disk_based_sources: &[String],
10757 cx: &mut Context<Self>,
10758 ) -> Result<()> {
10759 self.merge_lsp_diagnostics(
10760 source_kind,
10761 vec![DocumentDiagnosticsUpdate {
10762 diagnostics,
10763 result_id,
10764 server_id,
10765 disk_based_sources: Cow::Borrowed(disk_based_sources),
10766 }],
10767 |_, _, _| false,
10768 cx,
10769 )
10770 }
10771
10772 pub fn merge_lsp_diagnostics(
10773 &mut self,
10774 source_kind: DiagnosticSourceKind,
10775 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10776 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10777 cx: &mut Context<Self>,
10778 ) -> Result<()> {
10779 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10780 let updates = lsp_diagnostics
10781 .into_iter()
10782 .filter_map(|update| {
10783 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10784 Some(DocumentDiagnosticsUpdate {
10785 diagnostics: self.lsp_to_document_diagnostics(
10786 abs_path,
10787 source_kind,
10788 update.server_id,
10789 update.diagnostics,
10790 &update.disk_based_sources,
10791 ),
10792 result_id: update.result_id,
10793 server_id: update.server_id,
10794 disk_based_sources: update.disk_based_sources,
10795 })
10796 })
10797 .collect();
10798 self.merge_diagnostic_entries(updates, merge, cx)?;
10799 Ok(())
10800 }
10801
10802 fn lsp_to_document_diagnostics(
10803 &mut self,
10804 document_abs_path: PathBuf,
10805 source_kind: DiagnosticSourceKind,
10806 server_id: LanguageServerId,
10807 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10808 disk_based_sources: &[String],
10809 ) -> DocumentDiagnostics {
10810 let mut diagnostics = Vec::default();
10811 let mut primary_diagnostic_group_ids = HashMap::default();
10812 let mut sources_by_group_id = HashMap::default();
10813 let mut supporting_diagnostics = HashMap::default();
10814
10815 let adapter = self.language_server_adapter_for_id(server_id);
10816
10817 // Ensure that primary diagnostics are always the most severe
10818 lsp_diagnostics
10819 .diagnostics
10820 .sort_by_key(|item| item.severity);
10821
10822 for diagnostic in &lsp_diagnostics.diagnostics {
10823 let source = diagnostic.source.as_ref();
10824 let range = range_from_lsp(diagnostic.range);
10825 let is_supporting = diagnostic
10826 .related_information
10827 .as_ref()
10828 .is_some_and(|infos| {
10829 infos.iter().any(|info| {
10830 primary_diagnostic_group_ids.contains_key(&(
10831 source,
10832 diagnostic.code.clone(),
10833 range_from_lsp(info.location.range),
10834 ))
10835 })
10836 });
10837
10838 let is_unnecessary = diagnostic
10839 .tags
10840 .as_ref()
10841 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10842
10843 let underline = self
10844 .language_server_adapter_for_id(server_id)
10845 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10846
10847 if is_supporting {
10848 supporting_diagnostics.insert(
10849 (source, diagnostic.code.clone(), range),
10850 (diagnostic.severity, is_unnecessary),
10851 );
10852 } else {
10853 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10854 let is_disk_based =
10855 source.is_some_and(|source| disk_based_sources.contains(source));
10856
10857 sources_by_group_id.insert(group_id, source);
10858 primary_diagnostic_group_ids
10859 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10860
10861 diagnostics.push(DiagnosticEntry {
10862 range,
10863 diagnostic: Diagnostic {
10864 source: diagnostic.source.clone(),
10865 source_kind,
10866 code: diagnostic.code.clone(),
10867 code_description: diagnostic
10868 .code_description
10869 .as_ref()
10870 .and_then(|d| d.href.clone()),
10871 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10872 markdown: adapter.as_ref().and_then(|adapter| {
10873 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10874 }),
10875 message: diagnostic.message.trim().to_string(),
10876 group_id,
10877 is_primary: true,
10878 is_disk_based,
10879 is_unnecessary,
10880 underline,
10881 data: diagnostic.data.clone(),
10882 },
10883 });
10884 if let Some(infos) = &diagnostic.related_information {
10885 for info in infos {
10886 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10887 let range = range_from_lsp(info.location.range);
10888 diagnostics.push(DiagnosticEntry {
10889 range,
10890 diagnostic: Diagnostic {
10891 source: diagnostic.source.clone(),
10892 source_kind,
10893 code: diagnostic.code.clone(),
10894 code_description: diagnostic
10895 .code_description
10896 .as_ref()
10897 .and_then(|d| d.href.clone()),
10898 severity: DiagnosticSeverity::INFORMATION,
10899 markdown: adapter.as_ref().and_then(|adapter| {
10900 adapter.diagnostic_message_to_markdown(&info.message)
10901 }),
10902 message: info.message.trim().to_string(),
10903 group_id,
10904 is_primary: false,
10905 is_disk_based,
10906 is_unnecessary: false,
10907 underline,
10908 data: diagnostic.data.clone(),
10909 },
10910 });
10911 }
10912 }
10913 }
10914 }
10915 }
10916
10917 for entry in &mut diagnostics {
10918 let diagnostic = &mut entry.diagnostic;
10919 if !diagnostic.is_primary {
10920 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10921 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10922 source,
10923 diagnostic.code.clone(),
10924 entry.range.clone(),
10925 )) {
10926 if let Some(severity) = severity {
10927 diagnostic.severity = severity;
10928 }
10929 diagnostic.is_unnecessary = is_unnecessary;
10930 }
10931 }
10932 }
10933
10934 DocumentDiagnostics {
10935 diagnostics,
10936 document_abs_path,
10937 version: lsp_diagnostics.version,
10938 }
10939 }
10940
10941 fn insert_newly_running_language_server(
10942 &mut self,
10943 adapter: Arc<CachedLspAdapter>,
10944 language_server: Arc<LanguageServer>,
10945 server_id: LanguageServerId,
10946 key: LanguageServerSeed,
10947 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10948 cx: &mut Context<Self>,
10949 ) {
10950 let Some(local) = self.as_local_mut() else {
10951 return;
10952 };
10953 // If the language server for this key doesn't match the server id, don't store the
10954 // server. Which will cause it to be dropped, killing the process
10955 if local
10956 .language_server_ids
10957 .get(&key)
10958 .map(|state| state.id != server_id)
10959 .unwrap_or(false)
10960 {
10961 return;
10962 }
10963
10964 // Update language_servers collection with Running variant of LanguageServerState
10965 // indicating that the server is up and running and ready
10966 let workspace_folders = workspace_folders.lock().clone();
10967 language_server.set_workspace_folders(workspace_folders);
10968
10969 let workspace_diagnostics_refresh_tasks = language_server
10970 .capabilities()
10971 .diagnostic_provider
10972 .and_then(|provider| {
10973 local
10974 .language_server_dynamic_registrations
10975 .entry(server_id)
10976 .or_default()
10977 .diagnostics
10978 .entry(None)
10979 .or_insert(provider.clone());
10980 let workspace_refresher =
10981 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10982
10983 Some((None, workspace_refresher))
10984 })
10985 .into_iter()
10986 .collect();
10987 local.language_servers.insert(
10988 server_id,
10989 LanguageServerState::Running {
10990 workspace_diagnostics_refresh_tasks,
10991 adapter: adapter.clone(),
10992 server: language_server.clone(),
10993 simulate_disk_based_diagnostics_completion: None,
10994 },
10995 );
10996 local
10997 .languages
10998 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10999 if let Some(file_ops_caps) = language_server
11000 .capabilities()
11001 .workspace
11002 .as_ref()
11003 .and_then(|ws| ws.file_operations.as_ref())
11004 {
11005 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11006 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11007 if did_rename_caps.or(will_rename_caps).is_some() {
11008 let watcher = RenamePathsWatchedForServer::default()
11009 .with_did_rename_patterns(did_rename_caps)
11010 .with_will_rename_patterns(will_rename_caps);
11011 local
11012 .language_server_paths_watched_for_rename
11013 .insert(server_id, watcher);
11014 }
11015 }
11016
11017 self.language_server_statuses.insert(
11018 server_id,
11019 LanguageServerStatus {
11020 name: language_server.name(),
11021 pending_work: Default::default(),
11022 has_pending_diagnostic_updates: false,
11023 progress_tokens: Default::default(),
11024 worktree: Some(key.worktree_id),
11025 },
11026 );
11027
11028 cx.emit(LspStoreEvent::LanguageServerAdded(
11029 server_id,
11030 language_server.name(),
11031 Some(key.worktree_id),
11032 ));
11033
11034 let server_capabilities = language_server.capabilities();
11035 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11036 downstream_client
11037 .send(proto::StartLanguageServer {
11038 project_id: *project_id,
11039 server: Some(proto::LanguageServer {
11040 id: server_id.to_proto(),
11041 name: language_server.name().to_string(),
11042 worktree_id: Some(key.worktree_id.to_proto()),
11043 }),
11044 capabilities: serde_json::to_string(&server_capabilities)
11045 .expect("serializing server LSP capabilities"),
11046 })
11047 .log_err();
11048 }
11049 self.lsp_server_capabilities
11050 .insert(server_id, server_capabilities);
11051
11052 // Tell the language server about every open buffer in the worktree that matches the language.
11053 // Also check for buffers in worktrees that reused this server
11054 let mut worktrees_using_server = vec![key.worktree_id];
11055 if let Some(local) = self.as_local() {
11056 // Find all worktrees that have this server in their language server tree
11057 for (worktree_id, servers) in &local.lsp_tree.instances {
11058 if *worktree_id != key.worktree_id {
11059 for server_map in servers.roots.values() {
11060 if server_map
11061 .values()
11062 .any(|(node, _)| node.id() == Some(server_id))
11063 {
11064 worktrees_using_server.push(*worktree_id);
11065 }
11066 }
11067 }
11068 }
11069 }
11070
11071 let mut buffer_paths_registered = Vec::new();
11072 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11073 let mut lsp_adapters = HashMap::default();
11074 for buffer_handle in buffer_store.buffers() {
11075 let buffer = buffer_handle.read(cx);
11076 let file = match File::from_dyn(buffer.file()) {
11077 Some(file) => file,
11078 None => continue,
11079 };
11080 let language = match buffer.language() {
11081 Some(language) => language,
11082 None => continue,
11083 };
11084
11085 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11086 || !lsp_adapters
11087 .entry(language.name())
11088 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11089 .iter()
11090 .any(|a| a.name == key.name)
11091 {
11092 continue;
11093 }
11094 // didOpen
11095 let file = match file.as_local() {
11096 Some(file) => file,
11097 None => continue,
11098 };
11099
11100 let local = self.as_local_mut().unwrap();
11101
11102 let buffer_id = buffer.remote_id();
11103 if local.registered_buffers.contains_key(&buffer_id) {
11104 let versions = local
11105 .buffer_snapshots
11106 .entry(buffer_id)
11107 .or_default()
11108 .entry(server_id)
11109 .and_modify(|_| {
11110 assert!(
11111 false,
11112 "There should not be an existing snapshot for a newly inserted buffer"
11113 )
11114 })
11115 .or_insert_with(|| {
11116 vec![LspBufferSnapshot {
11117 version: 0,
11118 snapshot: buffer.text_snapshot(),
11119 }]
11120 });
11121
11122 let snapshot = versions.last().unwrap();
11123 let version = snapshot.version;
11124 let initial_snapshot = &snapshot.snapshot;
11125 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11126 language_server.register_buffer(
11127 uri,
11128 adapter.language_id(&language.name()),
11129 version,
11130 initial_snapshot.text(),
11131 );
11132 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11133 local
11134 .buffers_opened_in_servers
11135 .entry(buffer_id)
11136 .or_default()
11137 .insert(server_id);
11138 }
11139 buffer_handle.update(cx, |buffer, cx| {
11140 buffer.set_completion_triggers(
11141 server_id,
11142 language_server
11143 .capabilities()
11144 .completion_provider
11145 .as_ref()
11146 .and_then(|provider| {
11147 provider
11148 .trigger_characters
11149 .as_ref()
11150 .map(|characters| characters.iter().cloned().collect())
11151 })
11152 .unwrap_or_default(),
11153 cx,
11154 )
11155 });
11156 }
11157 });
11158
11159 for (buffer_id, abs_path) in buffer_paths_registered {
11160 cx.emit(LspStoreEvent::LanguageServerUpdate {
11161 language_server_id: server_id,
11162 name: Some(adapter.name()),
11163 message: proto::update_language_server::Variant::RegisteredForBuffer(
11164 proto::RegisteredForBuffer {
11165 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11166 buffer_id: buffer_id.to_proto(),
11167 },
11168 ),
11169 });
11170 }
11171
11172 cx.notify();
11173 }
11174
11175 pub fn language_servers_running_disk_based_diagnostics(
11176 &self,
11177 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11178 self.language_server_statuses
11179 .iter()
11180 .filter_map(|(id, status)| {
11181 if status.has_pending_diagnostic_updates {
11182 Some(*id)
11183 } else {
11184 None
11185 }
11186 })
11187 }
11188
11189 pub(crate) fn cancel_language_server_work_for_buffers(
11190 &mut self,
11191 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11192 cx: &mut Context<Self>,
11193 ) {
11194 if let Some((client, project_id)) = self.upstream_client() {
11195 let request = client.request(proto::CancelLanguageServerWork {
11196 project_id,
11197 work: Some(proto::cancel_language_server_work::Work::Buffers(
11198 proto::cancel_language_server_work::Buffers {
11199 buffer_ids: buffers
11200 .into_iter()
11201 .map(|b| b.read(cx).remote_id().to_proto())
11202 .collect(),
11203 },
11204 )),
11205 });
11206 cx.background_spawn(request).detach_and_log_err(cx);
11207 } else if let Some(local) = self.as_local() {
11208 let servers = buffers
11209 .into_iter()
11210 .flat_map(|buffer| {
11211 buffer.update(cx, |buffer, cx| {
11212 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11213 })
11214 })
11215 .collect::<HashSet<_>>();
11216 for server_id in servers {
11217 self.cancel_language_server_work(server_id, None, cx);
11218 }
11219 }
11220 }
11221
11222 pub(crate) fn cancel_language_server_work(
11223 &mut self,
11224 server_id: LanguageServerId,
11225 token_to_cancel: Option<ProgressToken>,
11226 cx: &mut Context<Self>,
11227 ) {
11228 if let Some(local) = self.as_local() {
11229 let status = self.language_server_statuses.get(&server_id);
11230 let server = local.language_servers.get(&server_id);
11231 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11232 {
11233 for (token, progress) in &status.pending_work {
11234 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11235 && token != token_to_cancel
11236 {
11237 continue;
11238 }
11239 if progress.is_cancellable {
11240 server
11241 .notify::<lsp::notification::WorkDoneProgressCancel>(
11242 WorkDoneProgressCancelParams {
11243 token: token.to_lsp(),
11244 },
11245 )
11246 .ok();
11247 }
11248 }
11249 }
11250 } else if let Some((client, project_id)) = self.upstream_client() {
11251 let request = client.request(proto::CancelLanguageServerWork {
11252 project_id,
11253 work: Some(
11254 proto::cancel_language_server_work::Work::LanguageServerWork(
11255 proto::cancel_language_server_work::LanguageServerWork {
11256 language_server_id: server_id.to_proto(),
11257 token: token_to_cancel.map(|token| token.to_proto()),
11258 },
11259 ),
11260 ),
11261 });
11262 cx.background_spawn(request).detach_and_log_err(cx);
11263 }
11264 }
11265
11266 fn register_supplementary_language_server(
11267 &mut self,
11268 id: LanguageServerId,
11269 name: LanguageServerName,
11270 server: Arc<LanguageServer>,
11271 cx: &mut Context<Self>,
11272 ) {
11273 if let Some(local) = self.as_local_mut() {
11274 local
11275 .supplementary_language_servers
11276 .insert(id, (name.clone(), server));
11277 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11278 }
11279 }
11280
11281 fn unregister_supplementary_language_server(
11282 &mut self,
11283 id: LanguageServerId,
11284 cx: &mut Context<Self>,
11285 ) {
11286 if let Some(local) = self.as_local_mut() {
11287 local.supplementary_language_servers.remove(&id);
11288 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11289 }
11290 }
11291
11292 pub(crate) fn supplementary_language_servers(
11293 &self,
11294 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11295 self.as_local().into_iter().flat_map(|local| {
11296 local
11297 .supplementary_language_servers
11298 .iter()
11299 .map(|(id, (name, _))| (*id, name.clone()))
11300 })
11301 }
11302
11303 pub fn language_server_adapter_for_id(
11304 &self,
11305 id: LanguageServerId,
11306 ) -> Option<Arc<CachedLspAdapter>> {
11307 self.as_local()
11308 .and_then(|local| local.language_servers.get(&id))
11309 .and_then(|language_server_state| match language_server_state {
11310 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11311 _ => None,
11312 })
11313 }
11314
11315 pub(super) fn update_local_worktree_language_servers(
11316 &mut self,
11317 worktree_handle: &Entity<Worktree>,
11318 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11319 cx: &mut Context<Self>,
11320 ) {
11321 if changes.is_empty() {
11322 return;
11323 }
11324
11325 let Some(local) = self.as_local() else { return };
11326
11327 local.prettier_store.update(cx, |prettier_store, cx| {
11328 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11329 });
11330
11331 let worktree_id = worktree_handle.read(cx).id();
11332 let mut language_server_ids = local
11333 .language_server_ids
11334 .iter()
11335 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11336 .collect::<Vec<_>>();
11337 language_server_ids.sort();
11338 language_server_ids.dedup();
11339
11340 // let abs_path = worktree_handle.read(cx).abs_path();
11341 for server_id in &language_server_ids {
11342 if let Some(LanguageServerState::Running { server, .. }) =
11343 local.language_servers.get(server_id)
11344 && let Some(watched_paths) = local
11345 .language_server_watched_paths
11346 .get(server_id)
11347 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11348 {
11349 let params = lsp::DidChangeWatchedFilesParams {
11350 changes: changes
11351 .iter()
11352 .filter_map(|(path, _, change)| {
11353 if !watched_paths.is_match(path.as_std_path()) {
11354 return None;
11355 }
11356 let typ = match change {
11357 PathChange::Loaded => return None,
11358 PathChange::Added => lsp::FileChangeType::CREATED,
11359 PathChange::Removed => lsp::FileChangeType::DELETED,
11360 PathChange::Updated => lsp::FileChangeType::CHANGED,
11361 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11362 };
11363 let uri = lsp::Uri::from_file_path(
11364 worktree_handle.read(cx).absolutize(&path),
11365 )
11366 .ok()?;
11367 Some(lsp::FileEvent { uri, typ })
11368 })
11369 .collect(),
11370 };
11371 if !params.changes.is_empty() {
11372 server
11373 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11374 .ok();
11375 }
11376 }
11377 }
11378 for (path, _, _) in changes {
11379 if let Some(file_name) = path.file_name()
11380 && local.watched_manifest_filenames.contains(file_name)
11381 {
11382 self.request_workspace_config_refresh();
11383 break;
11384 }
11385 }
11386 }
11387
11388 pub fn wait_for_remote_buffer(
11389 &mut self,
11390 id: BufferId,
11391 cx: &mut Context<Self>,
11392 ) -> Task<Result<Entity<Buffer>>> {
11393 self.buffer_store.update(cx, |buffer_store, cx| {
11394 buffer_store.wait_for_remote_buffer(id, cx)
11395 })
11396 }
11397
11398 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11399 let mut result = proto::Symbol {
11400 language_server_name: symbol.language_server_name.0.to_string(),
11401 source_worktree_id: symbol.source_worktree_id.to_proto(),
11402 language_server_id: symbol.source_language_server_id.to_proto(),
11403 name: symbol.name.clone(),
11404 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11405 start: Some(proto::PointUtf16 {
11406 row: symbol.range.start.0.row,
11407 column: symbol.range.start.0.column,
11408 }),
11409 end: Some(proto::PointUtf16 {
11410 row: symbol.range.end.0.row,
11411 column: symbol.range.end.0.column,
11412 }),
11413 worktree_id: Default::default(),
11414 path: Default::default(),
11415 signature: Default::default(),
11416 };
11417 match &symbol.path {
11418 SymbolLocation::InProject(path) => {
11419 result.worktree_id = path.worktree_id.to_proto();
11420 result.path = path.path.to_proto();
11421 }
11422 SymbolLocation::OutsideProject {
11423 abs_path,
11424 signature,
11425 } => {
11426 result.path = abs_path.to_string_lossy().into_owned();
11427 result.signature = signature.to_vec();
11428 }
11429 }
11430 result
11431 }
11432
11433 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11434 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11435 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11436 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11437
11438 let path = if serialized_symbol.signature.is_empty() {
11439 SymbolLocation::InProject(ProjectPath {
11440 worktree_id,
11441 path: RelPath::from_proto(&serialized_symbol.path)
11442 .context("invalid symbol path")?,
11443 })
11444 } else {
11445 SymbolLocation::OutsideProject {
11446 abs_path: Path::new(&serialized_symbol.path).into(),
11447 signature: serialized_symbol
11448 .signature
11449 .try_into()
11450 .map_err(|_| anyhow!("invalid signature"))?,
11451 }
11452 };
11453
11454 let start = serialized_symbol.start.context("invalid start")?;
11455 let end = serialized_symbol.end.context("invalid end")?;
11456 Ok(CoreSymbol {
11457 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11458 source_worktree_id,
11459 source_language_server_id: LanguageServerId::from_proto(
11460 serialized_symbol.language_server_id,
11461 ),
11462 path,
11463 name: serialized_symbol.name,
11464 range: Unclipped(PointUtf16::new(start.row, start.column))
11465 ..Unclipped(PointUtf16::new(end.row, end.column)),
11466 kind,
11467 })
11468 }
11469
11470 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11471 let mut serialized_completion = proto::Completion {
11472 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11473 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11474 new_text: completion.new_text.clone(),
11475 ..proto::Completion::default()
11476 };
11477 match &completion.source {
11478 CompletionSource::Lsp {
11479 insert_range,
11480 server_id,
11481 lsp_completion,
11482 lsp_defaults,
11483 resolved,
11484 } => {
11485 let (old_insert_start, old_insert_end) = insert_range
11486 .as_ref()
11487 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11488 .unzip();
11489
11490 serialized_completion.old_insert_start = old_insert_start;
11491 serialized_completion.old_insert_end = old_insert_end;
11492 serialized_completion.source = proto::completion::Source::Lsp as i32;
11493 serialized_completion.server_id = server_id.0 as u64;
11494 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11495 serialized_completion.lsp_defaults = lsp_defaults
11496 .as_deref()
11497 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11498 serialized_completion.resolved = *resolved;
11499 }
11500 CompletionSource::BufferWord {
11501 word_range,
11502 resolved,
11503 } => {
11504 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11505 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11506 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11507 serialized_completion.resolved = *resolved;
11508 }
11509 CompletionSource::Custom => {
11510 serialized_completion.source = proto::completion::Source::Custom as i32;
11511 serialized_completion.resolved = true;
11512 }
11513 CompletionSource::Dap { sort_text } => {
11514 serialized_completion.source = proto::completion::Source::Dap as i32;
11515 serialized_completion.sort_text = Some(sort_text.clone());
11516 }
11517 }
11518
11519 serialized_completion
11520 }
11521
11522 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11523 let old_replace_start = completion
11524 .old_replace_start
11525 .and_then(deserialize_anchor)
11526 .context("invalid old start")?;
11527 let old_replace_end = completion
11528 .old_replace_end
11529 .and_then(deserialize_anchor)
11530 .context("invalid old end")?;
11531 let insert_range = {
11532 match completion.old_insert_start.zip(completion.old_insert_end) {
11533 Some((start, end)) => {
11534 let start = deserialize_anchor(start).context("invalid insert old start")?;
11535 let end = deserialize_anchor(end).context("invalid insert old end")?;
11536 Some(start..end)
11537 }
11538 None => None,
11539 }
11540 };
11541 Ok(CoreCompletion {
11542 replace_range: old_replace_start..old_replace_end,
11543 new_text: completion.new_text,
11544 source: match proto::completion::Source::from_i32(completion.source) {
11545 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11546 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11547 insert_range,
11548 server_id: LanguageServerId::from_proto(completion.server_id),
11549 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11550 lsp_defaults: completion
11551 .lsp_defaults
11552 .as_deref()
11553 .map(serde_json::from_slice)
11554 .transpose()?,
11555 resolved: completion.resolved,
11556 },
11557 Some(proto::completion::Source::BufferWord) => {
11558 let word_range = completion
11559 .buffer_word_start
11560 .and_then(deserialize_anchor)
11561 .context("invalid buffer word start")?
11562 ..completion
11563 .buffer_word_end
11564 .and_then(deserialize_anchor)
11565 .context("invalid buffer word end")?;
11566 CompletionSource::BufferWord {
11567 word_range,
11568 resolved: completion.resolved,
11569 }
11570 }
11571 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11572 sort_text: completion
11573 .sort_text
11574 .context("expected sort text to exist")?,
11575 },
11576 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11577 },
11578 })
11579 }
11580
11581 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11582 let (kind, lsp_action) = match &action.lsp_action {
11583 LspAction::Action(code_action) => (
11584 proto::code_action::Kind::Action as i32,
11585 serde_json::to_vec(code_action).unwrap(),
11586 ),
11587 LspAction::Command(command) => (
11588 proto::code_action::Kind::Command as i32,
11589 serde_json::to_vec(command).unwrap(),
11590 ),
11591 LspAction::CodeLens(code_lens) => (
11592 proto::code_action::Kind::CodeLens as i32,
11593 serde_json::to_vec(code_lens).unwrap(),
11594 ),
11595 };
11596
11597 proto::CodeAction {
11598 server_id: action.server_id.0 as u64,
11599 start: Some(serialize_anchor(&action.range.start)),
11600 end: Some(serialize_anchor(&action.range.end)),
11601 lsp_action,
11602 kind,
11603 resolved: action.resolved,
11604 }
11605 }
11606
11607 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11608 let start = action
11609 .start
11610 .and_then(deserialize_anchor)
11611 .context("invalid start")?;
11612 let end = action
11613 .end
11614 .and_then(deserialize_anchor)
11615 .context("invalid end")?;
11616 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11617 Some(proto::code_action::Kind::Action) => {
11618 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11619 }
11620 Some(proto::code_action::Kind::Command) => {
11621 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11622 }
11623 Some(proto::code_action::Kind::CodeLens) => {
11624 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11625 }
11626 None => anyhow::bail!("Unknown action kind {}", action.kind),
11627 };
11628 Ok(CodeAction {
11629 server_id: LanguageServerId(action.server_id as usize),
11630 range: start..end,
11631 resolved: action.resolved,
11632 lsp_action,
11633 })
11634 }
11635
11636 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11637 match &formatting_result {
11638 Ok(_) => self.last_formatting_failure = None,
11639 Err(error) => {
11640 let error_string = format!("{error:#}");
11641 log::error!("Formatting failed: {error_string}");
11642 self.last_formatting_failure
11643 .replace(error_string.lines().join(" "));
11644 }
11645 }
11646 }
11647
11648 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11649 self.lsp_server_capabilities.remove(&for_server);
11650 for lsp_data in self.lsp_data.values_mut() {
11651 lsp_data.remove_server_data(for_server);
11652 }
11653 if let Some(local) = self.as_local_mut() {
11654 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11655 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11656 buffer_servers.remove(&for_server);
11657 }
11658 }
11659 }
11660
11661 pub fn result_id(
11662 &self,
11663 server_id: LanguageServerId,
11664 buffer_id: BufferId,
11665 cx: &App,
11666 ) -> Option<String> {
11667 let abs_path = self
11668 .buffer_store
11669 .read(cx)
11670 .get(buffer_id)
11671 .and_then(|b| File::from_dyn(b.read(cx).file()))
11672 .map(|f| f.abs_path(cx))?;
11673 self.as_local()?
11674 .buffer_pull_diagnostics_result_ids
11675 .get(&server_id)?
11676 .get(&abs_path)?
11677 .clone()
11678 }
11679
11680 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11681 let Some(local) = self.as_local() else {
11682 return HashMap::default();
11683 };
11684 local
11685 .buffer_pull_diagnostics_result_ids
11686 .get(&server_id)
11687 .into_iter()
11688 .flatten()
11689 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11690 .collect()
11691 }
11692
11693 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11694 if let Some(LanguageServerState::Running {
11695 workspace_diagnostics_refresh_tasks,
11696 ..
11697 }) = self
11698 .as_local_mut()
11699 .and_then(|local| local.language_servers.get_mut(&server_id))
11700 {
11701 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11702 diagnostics.refresh_tx.try_send(()).ok();
11703 }
11704 }
11705 }
11706
11707 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11708 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11709 return;
11710 };
11711 let Some(local) = self.as_local_mut() else {
11712 return;
11713 };
11714
11715 for server_id in buffer.update(cx, |buffer, cx| {
11716 local.language_server_ids_for_buffer(buffer, cx)
11717 }) {
11718 if let Some(LanguageServerState::Running {
11719 workspace_diagnostics_refresh_tasks,
11720 ..
11721 }) = local.language_servers.get_mut(&server_id)
11722 {
11723 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11724 diagnostics.refresh_tx.try_send(()).ok();
11725 }
11726 }
11727 }
11728 }
11729
11730 fn apply_workspace_diagnostic_report(
11731 &mut self,
11732 server_id: LanguageServerId,
11733 report: lsp::WorkspaceDiagnosticReportResult,
11734 cx: &mut Context<Self>,
11735 ) {
11736 let workspace_diagnostics =
11737 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11738 let mut unchanged_buffers = HashSet::default();
11739 let mut changed_buffers = HashSet::default();
11740 let workspace_diagnostics_updates = workspace_diagnostics
11741 .into_iter()
11742 .filter_map(
11743 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11744 LspPullDiagnostics::Response {
11745 server_id,
11746 uri,
11747 diagnostics,
11748 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11749 LspPullDiagnostics::Default => None,
11750 },
11751 )
11752 .fold(
11753 HashMap::default(),
11754 |mut acc, (server_id, uri, diagnostics, version)| {
11755 let (result_id, diagnostics) = match diagnostics {
11756 PulledDiagnostics::Unchanged { result_id } => {
11757 unchanged_buffers.insert(uri.clone());
11758 (Some(result_id), Vec::new())
11759 }
11760 PulledDiagnostics::Changed {
11761 result_id,
11762 diagnostics,
11763 } => {
11764 changed_buffers.insert(uri.clone());
11765 (result_id, diagnostics)
11766 }
11767 };
11768 let disk_based_sources = Cow::Owned(
11769 self.language_server_adapter_for_id(server_id)
11770 .as_ref()
11771 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11772 .unwrap_or(&[])
11773 .to_vec(),
11774 );
11775 acc.entry(server_id)
11776 .or_insert_with(Vec::new)
11777 .push(DocumentDiagnosticsUpdate {
11778 server_id,
11779 diagnostics: lsp::PublishDiagnosticsParams {
11780 uri,
11781 diagnostics,
11782 version,
11783 },
11784 result_id,
11785 disk_based_sources,
11786 });
11787 acc
11788 },
11789 );
11790
11791 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11792 self.merge_lsp_diagnostics(
11793 DiagnosticSourceKind::Pulled,
11794 diagnostic_updates,
11795 |buffer, old_diagnostic, cx| {
11796 File::from_dyn(buffer.file())
11797 .and_then(|file| {
11798 let abs_path = file.as_local()?.abs_path(cx);
11799 lsp::Uri::from_file_path(abs_path).ok()
11800 })
11801 .is_none_or(|buffer_uri| {
11802 unchanged_buffers.contains(&buffer_uri)
11803 || match old_diagnostic.source_kind {
11804 DiagnosticSourceKind::Pulled => {
11805 !changed_buffers.contains(&buffer_uri)
11806 }
11807 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11808 true
11809 }
11810 }
11811 })
11812 },
11813 cx,
11814 )
11815 .log_err();
11816 }
11817 }
11818
11819 fn register_server_capabilities(
11820 &mut self,
11821 server_id: LanguageServerId,
11822 params: lsp::RegistrationParams,
11823 cx: &mut Context<Self>,
11824 ) -> anyhow::Result<()> {
11825 let server = self
11826 .language_server_for_id(server_id)
11827 .with_context(|| format!("no server {server_id} found"))?;
11828 for reg in params.registrations {
11829 match reg.method.as_str() {
11830 "workspace/didChangeWatchedFiles" => {
11831 if let Some(options) = reg.register_options {
11832 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11833 let caps = serde_json::from_value(options)?;
11834 local_lsp_store
11835 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11836 true
11837 } else {
11838 false
11839 };
11840 if notify {
11841 notify_server_capabilities_updated(&server, cx);
11842 }
11843 }
11844 }
11845 "workspace/didChangeConfiguration" => {
11846 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11847 }
11848 "workspace/didChangeWorkspaceFolders" => {
11849 // In this case register options is an empty object, we can ignore it
11850 let caps = lsp::WorkspaceFoldersServerCapabilities {
11851 supported: Some(true),
11852 change_notifications: Some(OneOf::Right(reg.id)),
11853 };
11854 server.update_capabilities(|capabilities| {
11855 capabilities
11856 .workspace
11857 .get_or_insert_default()
11858 .workspace_folders = Some(caps);
11859 });
11860 notify_server_capabilities_updated(&server, cx);
11861 }
11862 "workspace/symbol" => {
11863 let options = parse_register_capabilities(reg)?;
11864 server.update_capabilities(|capabilities| {
11865 capabilities.workspace_symbol_provider = Some(options);
11866 });
11867 notify_server_capabilities_updated(&server, cx);
11868 }
11869 "workspace/fileOperations" => {
11870 if let Some(options) = reg.register_options {
11871 let caps = serde_json::from_value(options)?;
11872 server.update_capabilities(|capabilities| {
11873 capabilities
11874 .workspace
11875 .get_or_insert_default()
11876 .file_operations = Some(caps);
11877 });
11878 notify_server_capabilities_updated(&server, cx);
11879 }
11880 }
11881 "workspace/executeCommand" => {
11882 if let Some(options) = reg.register_options {
11883 let options = serde_json::from_value(options)?;
11884 server.update_capabilities(|capabilities| {
11885 capabilities.execute_command_provider = Some(options);
11886 });
11887 notify_server_capabilities_updated(&server, cx);
11888 }
11889 }
11890 "textDocument/rangeFormatting" => {
11891 let options = parse_register_capabilities(reg)?;
11892 server.update_capabilities(|capabilities| {
11893 capabilities.document_range_formatting_provider = Some(options);
11894 });
11895 notify_server_capabilities_updated(&server, cx);
11896 }
11897 "textDocument/onTypeFormatting" => {
11898 if let Some(options) = reg
11899 .register_options
11900 .map(serde_json::from_value)
11901 .transpose()?
11902 {
11903 server.update_capabilities(|capabilities| {
11904 capabilities.document_on_type_formatting_provider = Some(options);
11905 });
11906 notify_server_capabilities_updated(&server, cx);
11907 }
11908 }
11909 "textDocument/formatting" => {
11910 let options = parse_register_capabilities(reg)?;
11911 server.update_capabilities(|capabilities| {
11912 capabilities.document_formatting_provider = Some(options);
11913 });
11914 notify_server_capabilities_updated(&server, cx);
11915 }
11916 "textDocument/rename" => {
11917 let options = parse_register_capabilities(reg)?;
11918 server.update_capabilities(|capabilities| {
11919 capabilities.rename_provider = Some(options);
11920 });
11921 notify_server_capabilities_updated(&server, cx);
11922 }
11923 "textDocument/inlayHint" => {
11924 let options = parse_register_capabilities(reg)?;
11925 server.update_capabilities(|capabilities| {
11926 capabilities.inlay_hint_provider = Some(options);
11927 });
11928 notify_server_capabilities_updated(&server, cx);
11929 }
11930 "textDocument/documentSymbol" => {
11931 let options = parse_register_capabilities(reg)?;
11932 server.update_capabilities(|capabilities| {
11933 capabilities.document_symbol_provider = Some(options);
11934 });
11935 notify_server_capabilities_updated(&server, cx);
11936 }
11937 "textDocument/codeAction" => {
11938 let options = parse_register_capabilities(reg)?;
11939 let provider = match options {
11940 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11941 OneOf::Right(caps) => caps,
11942 };
11943 server.update_capabilities(|capabilities| {
11944 capabilities.code_action_provider = Some(provider);
11945 });
11946 notify_server_capabilities_updated(&server, cx);
11947 }
11948 "textDocument/definition" => {
11949 let options = parse_register_capabilities(reg)?;
11950 server.update_capabilities(|capabilities| {
11951 capabilities.definition_provider = Some(options);
11952 });
11953 notify_server_capabilities_updated(&server, cx);
11954 }
11955 "textDocument/completion" => {
11956 if let Some(caps) = reg
11957 .register_options
11958 .map(serde_json::from_value::<CompletionOptions>)
11959 .transpose()?
11960 {
11961 server.update_capabilities(|capabilities| {
11962 capabilities.completion_provider = Some(caps.clone());
11963 });
11964
11965 if let Some(local) = self.as_local() {
11966 let mut buffers_with_language_server = Vec::new();
11967 for handle in self.buffer_store.read(cx).buffers() {
11968 let buffer_id = handle.read(cx).remote_id();
11969 if local
11970 .buffers_opened_in_servers
11971 .get(&buffer_id)
11972 .filter(|s| s.contains(&server_id))
11973 .is_some()
11974 {
11975 buffers_with_language_server.push(handle);
11976 }
11977 }
11978 let triggers = caps
11979 .trigger_characters
11980 .unwrap_or_default()
11981 .into_iter()
11982 .collect::<BTreeSet<_>>();
11983 for handle in buffers_with_language_server {
11984 let triggers = triggers.clone();
11985 let _ = handle.update(cx, move |buffer, cx| {
11986 buffer.set_completion_triggers(server_id, triggers, cx);
11987 });
11988 }
11989 }
11990 notify_server_capabilities_updated(&server, cx);
11991 }
11992 }
11993 "textDocument/hover" => {
11994 let options = parse_register_capabilities(reg)?;
11995 let provider = match options {
11996 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11997 OneOf::Right(caps) => caps,
11998 };
11999 server.update_capabilities(|capabilities| {
12000 capabilities.hover_provider = Some(provider);
12001 });
12002 notify_server_capabilities_updated(&server, cx);
12003 }
12004 "textDocument/signatureHelp" => {
12005 if let Some(caps) = reg
12006 .register_options
12007 .map(serde_json::from_value)
12008 .transpose()?
12009 {
12010 server.update_capabilities(|capabilities| {
12011 capabilities.signature_help_provider = Some(caps);
12012 });
12013 notify_server_capabilities_updated(&server, cx);
12014 }
12015 }
12016 "textDocument/didChange" => {
12017 if let Some(sync_kind) = reg
12018 .register_options
12019 .and_then(|opts| opts.get("syncKind").cloned())
12020 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12021 .transpose()?
12022 {
12023 server.update_capabilities(|capabilities| {
12024 let mut sync_options =
12025 Self::take_text_document_sync_options(capabilities);
12026 sync_options.change = Some(sync_kind);
12027 capabilities.text_document_sync =
12028 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12029 });
12030 notify_server_capabilities_updated(&server, cx);
12031 }
12032 }
12033 "textDocument/didSave" => {
12034 if let Some(include_text) = reg
12035 .register_options
12036 .map(|opts| {
12037 let transpose = opts
12038 .get("includeText")
12039 .cloned()
12040 .map(serde_json::from_value::<Option<bool>>)
12041 .transpose();
12042 match transpose {
12043 Ok(value) => Ok(value.flatten()),
12044 Err(e) => Err(e),
12045 }
12046 })
12047 .transpose()?
12048 {
12049 server.update_capabilities(|capabilities| {
12050 let mut sync_options =
12051 Self::take_text_document_sync_options(capabilities);
12052 sync_options.save =
12053 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12054 include_text,
12055 }));
12056 capabilities.text_document_sync =
12057 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12058 });
12059 notify_server_capabilities_updated(&server, cx);
12060 }
12061 }
12062 "textDocument/codeLens" => {
12063 if let Some(caps) = reg
12064 .register_options
12065 .map(serde_json::from_value)
12066 .transpose()?
12067 {
12068 server.update_capabilities(|capabilities| {
12069 capabilities.code_lens_provider = Some(caps);
12070 });
12071 notify_server_capabilities_updated(&server, cx);
12072 }
12073 }
12074 "textDocument/diagnostic" => {
12075 if let Some(caps) = reg
12076 .register_options
12077 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12078 .transpose()?
12079 {
12080 let local = self
12081 .as_local_mut()
12082 .context("Expected LSP Store to be local")?;
12083 let state = local
12084 .language_servers
12085 .get_mut(&server_id)
12086 .context("Could not obtain Language Servers state")?;
12087 local
12088 .language_server_dynamic_registrations
12089 .entry(server_id)
12090 .or_default()
12091 .diagnostics
12092 .insert(Some(reg.id.clone()), caps.clone());
12093
12094 if let LanguageServerState::Running {
12095 workspace_diagnostics_refresh_tasks,
12096 ..
12097 } = state
12098 && let Some(task) = lsp_workspace_diagnostics_refresh(
12099 Some(reg.id.clone()),
12100 caps.clone(),
12101 server.clone(),
12102 cx,
12103 )
12104 {
12105 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12106 }
12107
12108 let mut did_update_caps = false;
12109 server.update_capabilities(|capabilities| {
12110 if capabilities.diagnostic_provider.as_ref().is_none_or(
12111 |current_caps| {
12112 let supports_workspace_diagnostics =
12113 |capabilities: &DiagnosticServerCapabilities| {
12114 match capabilities {
12115 DiagnosticServerCapabilities::Options(
12116 diagnostic_options,
12117 ) => diagnostic_options.workspace_diagnostics,
12118 DiagnosticServerCapabilities::RegistrationOptions(
12119 diagnostic_registration_options,
12120 ) => {
12121 diagnostic_registration_options
12122 .diagnostic_options
12123 .workspace_diagnostics
12124 }
12125 }
12126 };
12127 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12128 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12129 // as it'll think that they're not supported.
12130 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12131 !supports_workspace_diagnostics(current_caps)
12132 & supports_workspace_diagnostics(&caps)
12133 },
12134 ) {
12135 did_update_caps = true;
12136 capabilities.diagnostic_provider = Some(caps);
12137 }
12138 });
12139 if did_update_caps {
12140 notify_server_capabilities_updated(&server, cx);
12141 }
12142 }
12143 }
12144 "textDocument/documentColor" => {
12145 let options = parse_register_capabilities(reg)?;
12146 let provider = match options {
12147 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12148 OneOf::Right(caps) => caps,
12149 };
12150 server.update_capabilities(|capabilities| {
12151 capabilities.color_provider = Some(provider);
12152 });
12153 notify_server_capabilities_updated(&server, cx);
12154 }
12155 _ => log::warn!("unhandled capability registration: {reg:?}"),
12156 }
12157 }
12158
12159 Ok(())
12160 }
12161
12162 fn unregister_server_capabilities(
12163 &mut self,
12164 server_id: LanguageServerId,
12165 params: lsp::UnregistrationParams,
12166 cx: &mut Context<Self>,
12167 ) -> anyhow::Result<()> {
12168 let server = self
12169 .language_server_for_id(server_id)
12170 .with_context(|| format!("no server {server_id} found"))?;
12171 for unreg in params.unregisterations.iter() {
12172 match unreg.method.as_str() {
12173 "workspace/didChangeWatchedFiles" => {
12174 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12175 local_lsp_store
12176 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12177 true
12178 } else {
12179 false
12180 };
12181 if notify {
12182 notify_server_capabilities_updated(&server, cx);
12183 }
12184 }
12185 "workspace/didChangeConfiguration" => {
12186 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12187 }
12188 "workspace/didChangeWorkspaceFolders" => {
12189 server.update_capabilities(|capabilities| {
12190 capabilities
12191 .workspace
12192 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12193 workspace_folders: None,
12194 file_operations: None,
12195 })
12196 .workspace_folders = None;
12197 });
12198 notify_server_capabilities_updated(&server, cx);
12199 }
12200 "workspace/symbol" => {
12201 server.update_capabilities(|capabilities| {
12202 capabilities.workspace_symbol_provider = None
12203 });
12204 notify_server_capabilities_updated(&server, cx);
12205 }
12206 "workspace/fileOperations" => {
12207 server.update_capabilities(|capabilities| {
12208 capabilities
12209 .workspace
12210 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12211 workspace_folders: None,
12212 file_operations: None,
12213 })
12214 .file_operations = None;
12215 });
12216 notify_server_capabilities_updated(&server, cx);
12217 }
12218 "workspace/executeCommand" => {
12219 server.update_capabilities(|capabilities| {
12220 capabilities.execute_command_provider = None;
12221 });
12222 notify_server_capabilities_updated(&server, cx);
12223 }
12224 "textDocument/rangeFormatting" => {
12225 server.update_capabilities(|capabilities| {
12226 capabilities.document_range_formatting_provider = None
12227 });
12228 notify_server_capabilities_updated(&server, cx);
12229 }
12230 "textDocument/onTypeFormatting" => {
12231 server.update_capabilities(|capabilities| {
12232 capabilities.document_on_type_formatting_provider = None;
12233 });
12234 notify_server_capabilities_updated(&server, cx);
12235 }
12236 "textDocument/formatting" => {
12237 server.update_capabilities(|capabilities| {
12238 capabilities.document_formatting_provider = None;
12239 });
12240 notify_server_capabilities_updated(&server, cx);
12241 }
12242 "textDocument/rename" => {
12243 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12244 notify_server_capabilities_updated(&server, cx);
12245 }
12246 "textDocument/codeAction" => {
12247 server.update_capabilities(|capabilities| {
12248 capabilities.code_action_provider = None;
12249 });
12250 notify_server_capabilities_updated(&server, cx);
12251 }
12252 "textDocument/definition" => {
12253 server.update_capabilities(|capabilities| {
12254 capabilities.definition_provider = None;
12255 });
12256 notify_server_capabilities_updated(&server, cx);
12257 }
12258 "textDocument/completion" => {
12259 server.update_capabilities(|capabilities| {
12260 capabilities.completion_provider = None;
12261 });
12262 notify_server_capabilities_updated(&server, cx);
12263 }
12264 "textDocument/hover" => {
12265 server.update_capabilities(|capabilities| {
12266 capabilities.hover_provider = None;
12267 });
12268 notify_server_capabilities_updated(&server, cx);
12269 }
12270 "textDocument/signatureHelp" => {
12271 server.update_capabilities(|capabilities| {
12272 capabilities.signature_help_provider = None;
12273 });
12274 notify_server_capabilities_updated(&server, cx);
12275 }
12276 "textDocument/didChange" => {
12277 server.update_capabilities(|capabilities| {
12278 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12279 sync_options.change = None;
12280 capabilities.text_document_sync =
12281 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12282 });
12283 notify_server_capabilities_updated(&server, cx);
12284 }
12285 "textDocument/didSave" => {
12286 server.update_capabilities(|capabilities| {
12287 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12288 sync_options.save = None;
12289 capabilities.text_document_sync =
12290 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12291 });
12292 notify_server_capabilities_updated(&server, cx);
12293 }
12294 "textDocument/codeLens" => {
12295 server.update_capabilities(|capabilities| {
12296 capabilities.code_lens_provider = None;
12297 });
12298 notify_server_capabilities_updated(&server, cx);
12299 }
12300 "textDocument/diagnostic" => {
12301 let local = self
12302 .as_local_mut()
12303 .context("Expected LSP Store to be local")?;
12304
12305 let state = local
12306 .language_servers
12307 .get_mut(&server_id)
12308 .context("Could not obtain Language Servers state")?;
12309 let options = local
12310 .language_server_dynamic_registrations
12311 .get_mut(&server_id)
12312 .with_context(|| {
12313 format!("Expected dynamic registration to exist for server {server_id}")
12314 })?.diagnostics
12315 .remove(&Some(unreg.id.clone()))
12316 .with_context(|| format!(
12317 "Attempted to unregister non-existent diagnostic registration with ID {}",
12318 unreg.id)
12319 )?;
12320
12321 let mut has_any_diagnostic_providers_still = true;
12322 if let Some(identifier) = diagnostic_identifier(&options)
12323 && let LanguageServerState::Running {
12324 workspace_diagnostics_refresh_tasks,
12325 ..
12326 } = state
12327 {
12328 workspace_diagnostics_refresh_tasks.remove(&identifier);
12329 has_any_diagnostic_providers_still =
12330 !workspace_diagnostics_refresh_tasks.is_empty();
12331 }
12332
12333 if !has_any_diagnostic_providers_still {
12334 server.update_capabilities(|capabilities| {
12335 debug_assert!(capabilities.diagnostic_provider.is_some());
12336 capabilities.diagnostic_provider = None;
12337 });
12338 }
12339
12340 notify_server_capabilities_updated(&server, cx);
12341 }
12342 "textDocument/documentColor" => {
12343 server.update_capabilities(|capabilities| {
12344 capabilities.color_provider = None;
12345 });
12346 notify_server_capabilities_updated(&server, cx);
12347 }
12348 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12349 }
12350 }
12351
12352 Ok(())
12353 }
12354
12355 async fn deduplicate_range_based_lsp_requests<T>(
12356 lsp_store: &Entity<Self>,
12357 server_id: Option<LanguageServerId>,
12358 lsp_request_id: LspRequestId,
12359 proto_request: &T::ProtoRequest,
12360 range: Range<Anchor>,
12361 cx: &mut AsyncApp,
12362 ) -> Result<()>
12363 where
12364 T: LspCommand,
12365 T::ProtoRequest: proto::LspRequestMessage,
12366 {
12367 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12368 let version = deserialize_version(proto_request.buffer_version());
12369 let buffer = lsp_store.update(cx, |this, cx| {
12370 this.buffer_store.read(cx).get_existing(buffer_id)
12371 })??;
12372 buffer
12373 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12374 .await?;
12375 lsp_store.update(cx, |lsp_store, cx| {
12376 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12377 let chunks_queried_for = lsp_data
12378 .inlay_hints
12379 .applicable_chunks(&[range])
12380 .collect::<Vec<_>>();
12381 match chunks_queried_for.as_slice() {
12382 &[chunk] => {
12383 let key = LspKey {
12384 request_type: TypeId::of::<T>(),
12385 server_queried: server_id,
12386 };
12387 let previous_request = lsp_data
12388 .chunk_lsp_requests
12389 .entry(key)
12390 .or_default()
12391 .insert(chunk, lsp_request_id);
12392 if let Some((previous_request, running_requests)) =
12393 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12394 {
12395 running_requests.remove(&previous_request);
12396 }
12397 }
12398 _ambiguous_chunks => {
12399 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12400 // there, a buffer version-based check will be performed and outdated requests discarded.
12401 }
12402 }
12403 anyhow::Ok(())
12404 })??;
12405
12406 Ok(())
12407 }
12408
12409 async fn query_lsp_locally<T>(
12410 lsp_store: Entity<Self>,
12411 for_server_id: Option<LanguageServerId>,
12412 sender_id: proto::PeerId,
12413 lsp_request_id: LspRequestId,
12414 proto_request: T::ProtoRequest,
12415 position: Option<Anchor>,
12416 cx: &mut AsyncApp,
12417 ) -> Result<()>
12418 where
12419 T: LspCommand + Clone,
12420 T::ProtoRequest: proto::LspRequestMessage,
12421 <T::ProtoRequest as proto::RequestMessage>::Response:
12422 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12423 {
12424 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12425 let version = deserialize_version(proto_request.buffer_version());
12426 let buffer = lsp_store.update(cx, |this, cx| {
12427 this.buffer_store.read(cx).get_existing(buffer_id)
12428 })??;
12429 buffer
12430 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12431 .await?;
12432 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12433 let request =
12434 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12435 let key = LspKey {
12436 request_type: TypeId::of::<T>(),
12437 server_queried: for_server_id,
12438 };
12439 lsp_store.update(cx, |lsp_store, cx| {
12440 let request_task = match for_server_id {
12441 Some(server_id) => {
12442 let server_task = lsp_store.request_lsp(
12443 buffer.clone(),
12444 LanguageServerToQuery::Other(server_id),
12445 request.clone(),
12446 cx,
12447 );
12448 cx.background_spawn(async move {
12449 let mut responses = Vec::new();
12450 match server_task.await {
12451 Ok(response) => responses.push((server_id, response)),
12452 // rust-analyzer likes to error with this when its still loading up
12453 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12454 Err(e) => log::error!(
12455 "Error handling response for request {request:?}: {e:#}"
12456 ),
12457 }
12458 responses
12459 })
12460 }
12461 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12462 };
12463 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12464 if T::ProtoRequest::stop_previous_requests() {
12465 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12466 lsp_requests.clear();
12467 }
12468 }
12469 lsp_data.lsp_requests.entry(key).or_default().insert(
12470 lsp_request_id,
12471 cx.spawn(async move |lsp_store, cx| {
12472 let response = request_task.await;
12473 lsp_store
12474 .update(cx, |lsp_store, cx| {
12475 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12476 {
12477 let response = response
12478 .into_iter()
12479 .map(|(server_id, response)| {
12480 (
12481 server_id.to_proto(),
12482 T::response_to_proto(
12483 response,
12484 lsp_store,
12485 sender_id,
12486 &buffer_version,
12487 cx,
12488 )
12489 .into(),
12490 )
12491 })
12492 .collect::<HashMap<_, _>>();
12493 match client.send_lsp_response::<T::ProtoRequest>(
12494 project_id,
12495 lsp_request_id,
12496 response,
12497 ) {
12498 Ok(()) => {}
12499 Err(e) => {
12500 log::error!("Failed to send LSP response: {e:#}",)
12501 }
12502 }
12503 }
12504 })
12505 .ok();
12506 }),
12507 );
12508 })?;
12509 Ok(())
12510 }
12511
12512 fn take_text_document_sync_options(
12513 capabilities: &mut lsp::ServerCapabilities,
12514 ) -> lsp::TextDocumentSyncOptions {
12515 match capabilities.text_document_sync.take() {
12516 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12517 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12518 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12519 sync_options.change = Some(sync_kind);
12520 sync_options
12521 }
12522 None => lsp::TextDocumentSyncOptions::default(),
12523 }
12524 }
12525
12526 #[cfg(any(test, feature = "test-support"))]
12527 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12528 Some(
12529 self.lsp_data
12530 .get_mut(&buffer_id)?
12531 .code_lens
12532 .take()?
12533 .update
12534 .take()?
12535 .1,
12536 )
12537 }
12538
12539 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12540 self.downstream_client.clone()
12541 }
12542
12543 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12544 self.worktree_store.clone()
12545 }
12546
12547 /// Gets what's stored in the LSP data for the given buffer.
12548 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12549 self.lsp_data.get_mut(&buffer_id)
12550 }
12551
12552 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12553 /// new [`BufferLspData`] will be created to replace the previous state.
12554 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12555 let (buffer_id, buffer_version) =
12556 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12557 let lsp_data = self
12558 .lsp_data
12559 .entry(buffer_id)
12560 .or_insert_with(|| BufferLspData::new(buffer, cx));
12561 if buffer_version.changed_since(&lsp_data.buffer_version) {
12562 *lsp_data = BufferLspData::new(buffer, cx);
12563 }
12564 lsp_data
12565 }
12566}
12567
12568// Registration with registerOptions as null, should fallback to true.
12569// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12570fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12571 reg: lsp::Registration,
12572) -> Result<OneOf<bool, T>> {
12573 Ok(match reg.register_options {
12574 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12575 None => OneOf::Left(true),
12576 })
12577}
12578
12579fn subscribe_to_binary_statuses(
12580 languages: &Arc<LanguageRegistry>,
12581 cx: &mut Context<'_, LspStore>,
12582) -> Task<()> {
12583 let mut server_statuses = languages.language_server_binary_statuses();
12584 cx.spawn(async move |lsp_store, cx| {
12585 while let Some((server_name, binary_status)) = server_statuses.next().await {
12586 if lsp_store
12587 .update(cx, |_, cx| {
12588 let mut message = None;
12589 let binary_status = match binary_status {
12590 BinaryStatus::None => proto::ServerBinaryStatus::None,
12591 BinaryStatus::CheckingForUpdate => {
12592 proto::ServerBinaryStatus::CheckingForUpdate
12593 }
12594 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12595 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12596 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12597 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12598 BinaryStatus::Failed { error } => {
12599 message = Some(error);
12600 proto::ServerBinaryStatus::Failed
12601 }
12602 };
12603 cx.emit(LspStoreEvent::LanguageServerUpdate {
12604 // Binary updates are about the binary that might not have any language server id at that point.
12605 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12606 language_server_id: LanguageServerId(0),
12607 name: Some(server_name),
12608 message: proto::update_language_server::Variant::StatusUpdate(
12609 proto::StatusUpdate {
12610 message,
12611 status: Some(proto::status_update::Status::Binary(
12612 binary_status as i32,
12613 )),
12614 },
12615 ),
12616 });
12617 })
12618 .is_err()
12619 {
12620 break;
12621 }
12622 }
12623 })
12624}
12625
12626fn lsp_workspace_diagnostics_refresh(
12627 registration_id: Option<String>,
12628 options: DiagnosticServerCapabilities,
12629 server: Arc<LanguageServer>,
12630 cx: &mut Context<'_, LspStore>,
12631) -> Option<WorkspaceRefreshTask> {
12632 let identifier = diagnostic_identifier(&options)?;
12633
12634 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12635 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12636 refresh_tx.try_send(()).ok();
12637
12638 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12639 let mut attempts = 0;
12640 let max_attempts = 50;
12641 let mut requests = 0;
12642
12643 loop {
12644 let Some(()) = refresh_rx.recv().await else {
12645 return;
12646 };
12647
12648 'request: loop {
12649 requests += 1;
12650 if attempts > max_attempts {
12651 log::error!(
12652 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12653 );
12654 return;
12655 }
12656 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12657 cx.background_executor()
12658 .timer(Duration::from_millis(backoff_millis))
12659 .await;
12660 attempts += 1;
12661
12662 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12663 lsp_store
12664 .all_result_ids(server.server_id())
12665 .into_iter()
12666 .filter_map(|(abs_path, result_id)| {
12667 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12668 Some(lsp::PreviousResultId {
12669 uri,
12670 value: result_id,
12671 })
12672 })
12673 .collect()
12674 }) else {
12675 return;
12676 };
12677
12678 let token = if let Some(identifier) = ®istration_id {
12679 format!(
12680 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12681 server.server_id(),
12682 )
12683 } else {
12684 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12685 };
12686
12687 progress_rx.try_recv().ok();
12688 let timer =
12689 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12690 let progress = pin!(progress_rx.recv().fuse());
12691 let response_result = server
12692 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12693 lsp::WorkspaceDiagnosticParams {
12694 previous_result_ids,
12695 identifier: identifier.clone(),
12696 work_done_progress_params: Default::default(),
12697 partial_result_params: lsp::PartialResultParams {
12698 partial_result_token: Some(lsp::ProgressToken::String(token)),
12699 },
12700 },
12701 select(timer, progress).then(|either| match either {
12702 Either::Left((message, ..)) => ready(message).left_future(),
12703 Either::Right(..) => pending::<String>().right_future(),
12704 }),
12705 )
12706 .await;
12707
12708 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12709 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12710 match response_result {
12711 ConnectionResult::Timeout => {
12712 log::error!("Timeout during workspace diagnostics pull");
12713 continue 'request;
12714 }
12715 ConnectionResult::ConnectionReset => {
12716 log::error!("Server closed a workspace diagnostics pull request");
12717 continue 'request;
12718 }
12719 ConnectionResult::Result(Err(e)) => {
12720 log::error!("Error during workspace diagnostics pull: {e:#}");
12721 break 'request;
12722 }
12723 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12724 attempts = 0;
12725 if lsp_store
12726 .update(cx, |lsp_store, cx| {
12727 lsp_store.apply_workspace_diagnostic_report(
12728 server.server_id(),
12729 pulled_diagnostics,
12730 cx,
12731 )
12732 })
12733 .is_err()
12734 {
12735 return;
12736 }
12737 break 'request;
12738 }
12739 }
12740 }
12741 }
12742 });
12743
12744 Some(WorkspaceRefreshTask {
12745 refresh_tx,
12746 progress_tx,
12747 task: workspace_query_language_server,
12748 })
12749}
12750
12751fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12752 match &options {
12753 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12754 if !diagnostic_options.workspace_diagnostics {
12755 return None;
12756 }
12757 Some(diagnostic_options.identifier.clone())
12758 }
12759 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12760 let diagnostic_options = ®istration_options.diagnostic_options;
12761 if !diagnostic_options.workspace_diagnostics {
12762 return None;
12763 }
12764 Some(diagnostic_options.identifier.clone())
12765 }
12766 }
12767}
12768
12769fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12770 let CompletionSource::BufferWord {
12771 word_range,
12772 resolved,
12773 } = &mut completion.source
12774 else {
12775 return;
12776 };
12777 if *resolved {
12778 return;
12779 }
12780
12781 if completion.new_text
12782 != snapshot
12783 .text_for_range(word_range.clone())
12784 .collect::<String>()
12785 {
12786 return;
12787 }
12788
12789 let mut offset = 0;
12790 for chunk in snapshot.chunks(word_range.clone(), true) {
12791 let end_offset = offset + chunk.text.len();
12792 if let Some(highlight_id) = chunk.syntax_highlight_id {
12793 completion
12794 .label
12795 .runs
12796 .push((offset..end_offset, highlight_id));
12797 }
12798 offset = end_offset;
12799 }
12800 *resolved = true;
12801}
12802
12803impl EventEmitter<LspStoreEvent> for LspStore {}
12804
12805fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12806 hover
12807 .contents
12808 .retain(|hover_block| !hover_block.text.trim().is_empty());
12809 if hover.contents.is_empty() {
12810 None
12811 } else {
12812 Some(hover)
12813 }
12814}
12815
12816async fn populate_labels_for_completions(
12817 new_completions: Vec<CoreCompletion>,
12818 language: Option<Arc<Language>>,
12819 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12820) -> Vec<Completion> {
12821 let lsp_completions = new_completions
12822 .iter()
12823 .filter_map(|new_completion| {
12824 new_completion
12825 .source
12826 .lsp_completion(true)
12827 .map(|lsp_completion| lsp_completion.into_owned())
12828 })
12829 .collect::<Vec<_>>();
12830
12831 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12832 lsp_adapter
12833 .labels_for_completions(&lsp_completions, language)
12834 .await
12835 .log_err()
12836 .unwrap_or_default()
12837 } else {
12838 Vec::new()
12839 }
12840 .into_iter()
12841 .fuse();
12842
12843 let mut completions = Vec::new();
12844 for completion in new_completions {
12845 match completion.source.lsp_completion(true) {
12846 Some(lsp_completion) => {
12847 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12848
12849 let mut label = labels.next().flatten().unwrap_or_else(|| {
12850 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12851 });
12852 ensure_uniform_list_compatible_label(&mut label);
12853 completions.push(Completion {
12854 label,
12855 documentation,
12856 replace_range: completion.replace_range,
12857 new_text: completion.new_text,
12858 insert_text_mode: lsp_completion.insert_text_mode,
12859 source: completion.source,
12860 icon_path: None,
12861 confirm: None,
12862 match_start: None,
12863 snippet_deduplication_key: None,
12864 });
12865 }
12866 None => {
12867 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12868 ensure_uniform_list_compatible_label(&mut label);
12869 completions.push(Completion {
12870 label,
12871 documentation: None,
12872 replace_range: completion.replace_range,
12873 new_text: completion.new_text,
12874 source: completion.source,
12875 insert_text_mode: None,
12876 icon_path: None,
12877 confirm: None,
12878 match_start: None,
12879 snippet_deduplication_key: None,
12880 });
12881 }
12882 }
12883 }
12884 completions
12885}
12886
12887#[derive(Debug)]
12888pub enum LanguageServerToQuery {
12889 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12890 FirstCapable,
12891 /// Query a specific language server.
12892 Other(LanguageServerId),
12893}
12894
12895#[derive(Default)]
12896struct RenamePathsWatchedForServer {
12897 did_rename: Vec<RenameActionPredicate>,
12898 will_rename: Vec<RenameActionPredicate>,
12899}
12900
12901impl RenamePathsWatchedForServer {
12902 fn with_did_rename_patterns(
12903 mut self,
12904 did_rename: Option<&FileOperationRegistrationOptions>,
12905 ) -> Self {
12906 if let Some(did_rename) = did_rename {
12907 self.did_rename = did_rename
12908 .filters
12909 .iter()
12910 .filter_map(|filter| filter.try_into().log_err())
12911 .collect();
12912 }
12913 self
12914 }
12915 fn with_will_rename_patterns(
12916 mut self,
12917 will_rename: Option<&FileOperationRegistrationOptions>,
12918 ) -> Self {
12919 if let Some(will_rename) = will_rename {
12920 self.will_rename = will_rename
12921 .filters
12922 .iter()
12923 .filter_map(|filter| filter.try_into().log_err())
12924 .collect();
12925 }
12926 self
12927 }
12928
12929 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12930 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12931 }
12932 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12933 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12934 }
12935}
12936
12937impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12938 type Error = globset::Error;
12939 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12940 Ok(Self {
12941 kind: ops.pattern.matches.clone(),
12942 glob: GlobBuilder::new(&ops.pattern.glob)
12943 .case_insensitive(
12944 ops.pattern
12945 .options
12946 .as_ref()
12947 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12948 )
12949 .build()?
12950 .compile_matcher(),
12951 })
12952 }
12953}
12954struct RenameActionPredicate {
12955 glob: GlobMatcher,
12956 kind: Option<FileOperationPatternKind>,
12957}
12958
12959impl RenameActionPredicate {
12960 // Returns true if language server should be notified
12961 fn eval(&self, path: &str, is_dir: bool) -> bool {
12962 self.kind.as_ref().is_none_or(|kind| {
12963 let expected_kind = if is_dir {
12964 FileOperationPatternKind::Folder
12965 } else {
12966 FileOperationPatternKind::File
12967 };
12968 kind == &expected_kind
12969 }) && self.glob.is_match(path)
12970 }
12971}
12972
12973#[derive(Default)]
12974struct LanguageServerWatchedPaths {
12975 worktree_paths: HashMap<WorktreeId, GlobSet>,
12976 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12977}
12978
12979#[derive(Default)]
12980struct LanguageServerWatchedPathsBuilder {
12981 worktree_paths: HashMap<WorktreeId, GlobSet>,
12982 abs_paths: HashMap<Arc<Path>, GlobSet>,
12983}
12984
12985impl LanguageServerWatchedPathsBuilder {
12986 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12987 self.worktree_paths.insert(worktree_id, glob_set);
12988 }
12989 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12990 self.abs_paths.insert(path, glob_set);
12991 }
12992 fn build(
12993 self,
12994 fs: Arc<dyn Fs>,
12995 language_server_id: LanguageServerId,
12996 cx: &mut Context<LspStore>,
12997 ) -> LanguageServerWatchedPaths {
12998 let lsp_store = cx.weak_entity();
12999
13000 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13001 let abs_paths = self
13002 .abs_paths
13003 .into_iter()
13004 .map(|(abs_path, globset)| {
13005 let task = cx.spawn({
13006 let abs_path = abs_path.clone();
13007 let fs = fs.clone();
13008
13009 let lsp_store = lsp_store.clone();
13010 async move |_, cx| {
13011 maybe!(async move {
13012 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13013 while let Some(update) = push_updates.0.next().await {
13014 let action = lsp_store
13015 .update(cx, |this, _| {
13016 let Some(local) = this.as_local() else {
13017 return ControlFlow::Break(());
13018 };
13019 let Some(watcher) = local
13020 .language_server_watched_paths
13021 .get(&language_server_id)
13022 else {
13023 return ControlFlow::Break(());
13024 };
13025 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13026 "Watched abs path is not registered with a watcher",
13027 );
13028 let matching_entries = update
13029 .into_iter()
13030 .filter(|event| globs.is_match(&event.path))
13031 .collect::<Vec<_>>();
13032 this.lsp_notify_abs_paths_changed(
13033 language_server_id,
13034 matching_entries,
13035 );
13036 ControlFlow::Continue(())
13037 })
13038 .ok()?;
13039
13040 if action.is_break() {
13041 break;
13042 }
13043 }
13044 Some(())
13045 })
13046 .await;
13047 }
13048 });
13049 (abs_path, (globset, task))
13050 })
13051 .collect();
13052 LanguageServerWatchedPaths {
13053 worktree_paths: self.worktree_paths,
13054 abs_paths,
13055 }
13056 }
13057}
13058
13059struct LspBufferSnapshot {
13060 version: i32,
13061 snapshot: TextBufferSnapshot,
13062}
13063
13064/// A prompt requested by LSP server.
13065#[derive(Clone, Debug)]
13066pub struct LanguageServerPromptRequest {
13067 pub level: PromptLevel,
13068 pub message: String,
13069 pub actions: Vec<MessageActionItem>,
13070 pub lsp_name: String,
13071 pub(crate) response_channel: Sender<MessageActionItem>,
13072}
13073
13074impl LanguageServerPromptRequest {
13075 pub async fn respond(self, index: usize) -> Option<()> {
13076 if let Some(response) = self.actions.into_iter().nth(index) {
13077 self.response_channel.send(response).await.ok()
13078 } else {
13079 None
13080 }
13081 }
13082}
13083impl PartialEq for LanguageServerPromptRequest {
13084 fn eq(&self, other: &Self) -> bool {
13085 self.message == other.message && self.actions == other.actions
13086 }
13087}
13088
13089#[derive(Clone, Debug, PartialEq)]
13090pub enum LanguageServerLogType {
13091 Log(MessageType),
13092 Trace { verbose_info: Option<String> },
13093 Rpc { received: bool },
13094}
13095
13096impl LanguageServerLogType {
13097 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13098 match self {
13099 Self::Log(log_type) => {
13100 use proto::log_message::LogLevel;
13101 let level = match *log_type {
13102 MessageType::ERROR => LogLevel::Error,
13103 MessageType::WARNING => LogLevel::Warning,
13104 MessageType::INFO => LogLevel::Info,
13105 MessageType::LOG => LogLevel::Log,
13106 other => {
13107 log::warn!("Unknown lsp log message type: {other:?}");
13108 LogLevel::Log
13109 }
13110 };
13111 proto::language_server_log::LogType::Log(proto::LogMessage {
13112 level: level as i32,
13113 })
13114 }
13115 Self::Trace { verbose_info } => {
13116 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13117 verbose_info: verbose_info.to_owned(),
13118 })
13119 }
13120 Self::Rpc { received } => {
13121 let kind = if *received {
13122 proto::rpc_message::Kind::Received
13123 } else {
13124 proto::rpc_message::Kind::Sent
13125 };
13126 let kind = kind as i32;
13127 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13128 }
13129 }
13130 }
13131
13132 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13133 use proto::log_message::LogLevel;
13134 use proto::rpc_message;
13135 match log_type {
13136 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13137 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13138 LogLevel::Error => MessageType::ERROR,
13139 LogLevel::Warning => MessageType::WARNING,
13140 LogLevel::Info => MessageType::INFO,
13141 LogLevel::Log => MessageType::LOG,
13142 },
13143 ),
13144 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13145 verbose_info: trace_message.verbose_info,
13146 },
13147 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13148 received: match rpc_message::Kind::from_i32(message.kind)
13149 .unwrap_or(rpc_message::Kind::Received)
13150 {
13151 rpc_message::Kind::Received => true,
13152 rpc_message::Kind::Sent => false,
13153 },
13154 },
13155 }
13156 }
13157}
13158
13159pub struct WorkspaceRefreshTask {
13160 refresh_tx: mpsc::Sender<()>,
13161 progress_tx: mpsc::Sender<()>,
13162 #[allow(dead_code)]
13163 task: Task<()>,
13164}
13165
13166pub enum LanguageServerState {
13167 Starting {
13168 startup: Task<Option<Arc<LanguageServer>>>,
13169 /// List of language servers that will be added to the workspace once it's initialization completes.
13170 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13171 },
13172
13173 Running {
13174 adapter: Arc<CachedLspAdapter>,
13175 server: Arc<LanguageServer>,
13176 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13177 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13178 },
13179}
13180
13181impl LanguageServerState {
13182 fn add_workspace_folder(&self, uri: Uri) {
13183 match self {
13184 LanguageServerState::Starting {
13185 pending_workspace_folders,
13186 ..
13187 } => {
13188 pending_workspace_folders.lock().insert(uri);
13189 }
13190 LanguageServerState::Running { server, .. } => {
13191 server.add_workspace_folder(uri);
13192 }
13193 }
13194 }
13195 fn _remove_workspace_folder(&self, uri: Uri) {
13196 match self {
13197 LanguageServerState::Starting {
13198 pending_workspace_folders,
13199 ..
13200 } => {
13201 pending_workspace_folders.lock().remove(&uri);
13202 }
13203 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13204 }
13205 }
13206}
13207
13208impl std::fmt::Debug for LanguageServerState {
13209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13210 match self {
13211 LanguageServerState::Starting { .. } => {
13212 f.debug_struct("LanguageServerState::Starting").finish()
13213 }
13214 LanguageServerState::Running { .. } => {
13215 f.debug_struct("LanguageServerState::Running").finish()
13216 }
13217 }
13218 }
13219}
13220
13221#[derive(Clone, Debug, Serialize)]
13222pub struct LanguageServerProgress {
13223 pub is_disk_based_diagnostics_progress: bool,
13224 pub is_cancellable: bool,
13225 pub title: Option<String>,
13226 pub message: Option<String>,
13227 pub percentage: Option<usize>,
13228 #[serde(skip_serializing)]
13229 pub last_update_at: Instant,
13230}
13231
13232#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13233pub struct DiagnosticSummary {
13234 pub error_count: usize,
13235 pub warning_count: usize,
13236}
13237
13238impl DiagnosticSummary {
13239 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13240 let mut this = Self {
13241 error_count: 0,
13242 warning_count: 0,
13243 };
13244
13245 for entry in diagnostics {
13246 if entry.diagnostic.is_primary {
13247 match entry.diagnostic.severity {
13248 DiagnosticSeverity::ERROR => this.error_count += 1,
13249 DiagnosticSeverity::WARNING => this.warning_count += 1,
13250 _ => {}
13251 }
13252 }
13253 }
13254
13255 this
13256 }
13257
13258 pub fn is_empty(&self) -> bool {
13259 self.error_count == 0 && self.warning_count == 0
13260 }
13261
13262 pub fn to_proto(
13263 self,
13264 language_server_id: LanguageServerId,
13265 path: &RelPath,
13266 ) -> proto::DiagnosticSummary {
13267 proto::DiagnosticSummary {
13268 path: path.to_proto(),
13269 language_server_id: language_server_id.0 as u64,
13270 error_count: self.error_count as u32,
13271 warning_count: self.warning_count as u32,
13272 }
13273 }
13274}
13275
13276#[derive(Clone, Debug)]
13277pub enum CompletionDocumentation {
13278 /// There is no documentation for this completion.
13279 Undocumented,
13280 /// A single line of documentation.
13281 SingleLine(SharedString),
13282 /// Multiple lines of plain text documentation.
13283 MultiLinePlainText(SharedString),
13284 /// Markdown documentation.
13285 MultiLineMarkdown(SharedString),
13286 /// Both single line and multiple lines of plain text documentation.
13287 SingleLineAndMultiLinePlainText {
13288 single_line: SharedString,
13289 plain_text: Option<SharedString>,
13290 },
13291}
13292
13293impl CompletionDocumentation {
13294 #[cfg(any(test, feature = "test-support"))]
13295 pub fn text(&self) -> SharedString {
13296 match self {
13297 CompletionDocumentation::Undocumented => "".into(),
13298 CompletionDocumentation::SingleLine(s) => s.clone(),
13299 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13300 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13301 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13302 single_line.clone()
13303 }
13304 }
13305 }
13306}
13307
13308impl From<lsp::Documentation> for CompletionDocumentation {
13309 fn from(docs: lsp::Documentation) -> Self {
13310 match docs {
13311 lsp::Documentation::String(text) => {
13312 if text.lines().count() <= 1 {
13313 CompletionDocumentation::SingleLine(text.into())
13314 } else {
13315 CompletionDocumentation::MultiLinePlainText(text.into())
13316 }
13317 }
13318
13319 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13320 lsp::MarkupKind::PlainText => {
13321 if value.lines().count() <= 1 {
13322 CompletionDocumentation::SingleLine(value.into())
13323 } else {
13324 CompletionDocumentation::MultiLinePlainText(value.into())
13325 }
13326 }
13327
13328 lsp::MarkupKind::Markdown => {
13329 CompletionDocumentation::MultiLineMarkdown(value.into())
13330 }
13331 },
13332 }
13333 }
13334}
13335
13336pub enum ResolvedHint {
13337 Resolved(InlayHint),
13338 Resolving(Shared<Task<()>>),
13339}
13340
13341fn glob_literal_prefix(glob: &Path) -> PathBuf {
13342 glob.components()
13343 .take_while(|component| match component {
13344 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13345 _ => true,
13346 })
13347 .collect()
13348}
13349
13350pub struct SshLspAdapter {
13351 name: LanguageServerName,
13352 binary: LanguageServerBinary,
13353 initialization_options: Option<String>,
13354 code_action_kinds: Option<Vec<CodeActionKind>>,
13355}
13356
13357impl SshLspAdapter {
13358 pub fn new(
13359 name: LanguageServerName,
13360 binary: LanguageServerBinary,
13361 initialization_options: Option<String>,
13362 code_action_kinds: Option<String>,
13363 ) -> Self {
13364 Self {
13365 name,
13366 binary,
13367 initialization_options,
13368 code_action_kinds: code_action_kinds
13369 .as_ref()
13370 .and_then(|c| serde_json::from_str(c).ok()),
13371 }
13372 }
13373}
13374
13375impl LspInstaller for SshLspAdapter {
13376 type BinaryVersion = ();
13377 async fn check_if_user_installed(
13378 &self,
13379 _: &dyn LspAdapterDelegate,
13380 _: Option<Toolchain>,
13381 _: &AsyncApp,
13382 ) -> Option<LanguageServerBinary> {
13383 Some(self.binary.clone())
13384 }
13385
13386 async fn cached_server_binary(
13387 &self,
13388 _: PathBuf,
13389 _: &dyn LspAdapterDelegate,
13390 ) -> Option<LanguageServerBinary> {
13391 None
13392 }
13393
13394 async fn fetch_latest_server_version(
13395 &self,
13396 _: &dyn LspAdapterDelegate,
13397 _: bool,
13398 _: &mut AsyncApp,
13399 ) -> Result<()> {
13400 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13401 }
13402
13403 async fn fetch_server_binary(
13404 &self,
13405 _: (),
13406 _: PathBuf,
13407 _: &dyn LspAdapterDelegate,
13408 ) -> Result<LanguageServerBinary> {
13409 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13410 }
13411}
13412
13413#[async_trait(?Send)]
13414impl LspAdapter for SshLspAdapter {
13415 fn name(&self) -> LanguageServerName {
13416 self.name.clone()
13417 }
13418
13419 async fn initialization_options(
13420 self: Arc<Self>,
13421 _: &Arc<dyn LspAdapterDelegate>,
13422 ) -> Result<Option<serde_json::Value>> {
13423 let Some(options) = &self.initialization_options else {
13424 return Ok(None);
13425 };
13426 let result = serde_json::from_str(options)?;
13427 Ok(result)
13428 }
13429
13430 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13431 self.code_action_kinds.clone()
13432 }
13433}
13434
13435pub fn language_server_settings<'a>(
13436 delegate: &'a dyn LspAdapterDelegate,
13437 language: &LanguageServerName,
13438 cx: &'a App,
13439) -> Option<&'a LspSettings> {
13440 language_server_settings_for(
13441 SettingsLocation {
13442 worktree_id: delegate.worktree_id(),
13443 path: RelPath::empty(),
13444 },
13445 language,
13446 cx,
13447 )
13448}
13449
13450pub(crate) fn language_server_settings_for<'a>(
13451 location: SettingsLocation<'a>,
13452 language: &LanguageServerName,
13453 cx: &'a App,
13454) -> Option<&'a LspSettings> {
13455 ProjectSettings::get(Some(location), cx).lsp.get(language)
13456}
13457
13458pub struct LocalLspAdapterDelegate {
13459 lsp_store: WeakEntity<LspStore>,
13460 worktree: worktree::Snapshot,
13461 fs: Arc<dyn Fs>,
13462 http_client: Arc<dyn HttpClient>,
13463 language_registry: Arc<LanguageRegistry>,
13464 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13465}
13466
13467impl LocalLspAdapterDelegate {
13468 pub fn new(
13469 language_registry: Arc<LanguageRegistry>,
13470 environment: &Entity<ProjectEnvironment>,
13471 lsp_store: WeakEntity<LspStore>,
13472 worktree: &Entity<Worktree>,
13473 http_client: Arc<dyn HttpClient>,
13474 fs: Arc<dyn Fs>,
13475 cx: &mut App,
13476 ) -> Arc<Self> {
13477 let load_shell_env_task =
13478 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13479
13480 Arc::new(Self {
13481 lsp_store,
13482 worktree: worktree.read(cx).snapshot(),
13483 fs,
13484 http_client,
13485 language_registry,
13486 load_shell_env_task,
13487 })
13488 }
13489
13490 fn from_local_lsp(
13491 local: &LocalLspStore,
13492 worktree: &Entity<Worktree>,
13493 cx: &mut App,
13494 ) -> Arc<Self> {
13495 Self::new(
13496 local.languages.clone(),
13497 &local.environment,
13498 local.weak.clone(),
13499 worktree,
13500 local.http_client.clone(),
13501 local.fs.clone(),
13502 cx,
13503 )
13504 }
13505}
13506
13507#[async_trait]
13508impl LspAdapterDelegate for LocalLspAdapterDelegate {
13509 fn show_notification(&self, message: &str, cx: &mut App) {
13510 self.lsp_store
13511 .update(cx, |_, cx| {
13512 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13513 })
13514 .ok();
13515 }
13516
13517 fn http_client(&self) -> Arc<dyn HttpClient> {
13518 self.http_client.clone()
13519 }
13520
13521 fn worktree_id(&self) -> WorktreeId {
13522 self.worktree.id()
13523 }
13524
13525 fn worktree_root_path(&self) -> &Path {
13526 self.worktree.abs_path().as_ref()
13527 }
13528
13529 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13530 self.worktree.resolve_executable_path(path)
13531 }
13532
13533 async fn shell_env(&self) -> HashMap<String, String> {
13534 let task = self.load_shell_env_task.clone();
13535 task.await.unwrap_or_default()
13536 }
13537
13538 async fn npm_package_installed_version(
13539 &self,
13540 package_name: &str,
13541 ) -> Result<Option<(PathBuf, String)>> {
13542 let local_package_directory = self.worktree_root_path();
13543 let node_modules_directory = local_package_directory.join("node_modules");
13544
13545 if let Some(version) =
13546 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13547 {
13548 return Ok(Some((node_modules_directory, version)));
13549 }
13550 let Some(npm) = self.which("npm".as_ref()).await else {
13551 log::warn!(
13552 "Failed to find npm executable for {:?}",
13553 local_package_directory
13554 );
13555 return Ok(None);
13556 };
13557
13558 let env = self.shell_env().await;
13559 let output = util::command::new_smol_command(&npm)
13560 .args(["root", "-g"])
13561 .envs(env)
13562 .current_dir(local_package_directory)
13563 .output()
13564 .await?;
13565 let global_node_modules =
13566 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13567
13568 if let Some(version) =
13569 read_package_installed_version(global_node_modules.clone(), package_name).await?
13570 {
13571 return Ok(Some((global_node_modules, version)));
13572 }
13573 return Ok(None);
13574 }
13575
13576 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13577 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13578 if self.fs.is_file(&worktree_abs_path).await {
13579 worktree_abs_path.pop();
13580 }
13581
13582 let env = self.shell_env().await;
13583
13584 let shell_path = env.get("PATH").cloned();
13585
13586 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13587 }
13588
13589 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13590 let mut working_dir = self.worktree_root_path().to_path_buf();
13591 if self.fs.is_file(&working_dir).await {
13592 working_dir.pop();
13593 }
13594 let output = util::command::new_smol_command(&command.path)
13595 .args(command.arguments)
13596 .envs(command.env.clone().unwrap_or_default())
13597 .current_dir(working_dir)
13598 .output()
13599 .await?;
13600
13601 anyhow::ensure!(
13602 output.status.success(),
13603 "{}, stdout: {:?}, stderr: {:?}",
13604 output.status,
13605 String::from_utf8_lossy(&output.stdout),
13606 String::from_utf8_lossy(&output.stderr)
13607 );
13608 Ok(())
13609 }
13610
13611 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13612 self.language_registry
13613 .update_lsp_binary_status(server_name, status);
13614 }
13615
13616 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13617 self.language_registry
13618 .all_lsp_adapters()
13619 .into_iter()
13620 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13621 .collect()
13622 }
13623
13624 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13625 let dir = self.language_registry.language_server_download_dir(name)?;
13626
13627 if !dir.exists() {
13628 smol::fs::create_dir_all(&dir)
13629 .await
13630 .context("failed to create container directory")
13631 .log_err()?;
13632 }
13633
13634 Some(dir)
13635 }
13636
13637 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13638 let entry = self
13639 .worktree
13640 .entry_for_path(path)
13641 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13642 let abs_path = self.worktree.absolutize(&entry.path);
13643 self.fs.load(&abs_path).await
13644 }
13645}
13646
13647async fn populate_labels_for_symbols(
13648 symbols: Vec<CoreSymbol>,
13649 language_registry: &Arc<LanguageRegistry>,
13650 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13651 output: &mut Vec<Symbol>,
13652) {
13653 #[allow(clippy::mutable_key_type)]
13654 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13655
13656 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13657 for symbol in symbols {
13658 let Some(file_name) = symbol.path.file_name() else {
13659 continue;
13660 };
13661 let language = language_registry
13662 .load_language_for_file_path(Path::new(file_name))
13663 .await
13664 .ok()
13665 .or_else(|| {
13666 unknown_paths.insert(file_name.into());
13667 None
13668 });
13669 symbols_by_language
13670 .entry(language)
13671 .or_default()
13672 .push(symbol);
13673 }
13674
13675 for unknown_path in unknown_paths {
13676 log::info!("no language found for symbol in file {unknown_path:?}");
13677 }
13678
13679 let mut label_params = Vec::new();
13680 for (language, mut symbols) in symbols_by_language {
13681 label_params.clear();
13682 label_params.extend(
13683 symbols
13684 .iter_mut()
13685 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13686 );
13687
13688 let mut labels = Vec::new();
13689 if let Some(language) = language {
13690 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13691 language_registry
13692 .lsp_adapters(&language.name())
13693 .first()
13694 .cloned()
13695 });
13696 if let Some(lsp_adapter) = lsp_adapter {
13697 labels = lsp_adapter
13698 .labels_for_symbols(&label_params, &language)
13699 .await
13700 .log_err()
13701 .unwrap_or_default();
13702 }
13703 }
13704
13705 for ((symbol, (name, _)), label) in symbols
13706 .into_iter()
13707 .zip(label_params.drain(..))
13708 .zip(labels.into_iter().chain(iter::repeat(None)))
13709 {
13710 output.push(Symbol {
13711 language_server_name: symbol.language_server_name,
13712 source_worktree_id: symbol.source_worktree_id,
13713 source_language_server_id: symbol.source_language_server_id,
13714 path: symbol.path,
13715 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13716 name,
13717 kind: symbol.kind,
13718 range: symbol.range,
13719 });
13720 }
13721 }
13722}
13723
13724fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13725 match server.capabilities().text_document_sync.as_ref()? {
13726 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13727 // Server wants didSave but didn't specify includeText.
13728 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13729 // Server doesn't want didSave at all.
13730 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13731 // Server provided SaveOptions.
13732 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13733 Some(save_options.include_text.unwrap_or(false))
13734 }
13735 },
13736 // We do not have any save info. Kind affects didChange only.
13737 lsp::TextDocumentSyncCapability::Kind(_) => None,
13738 }
13739}
13740
13741/// Completion items are displayed in a `UniformList`.
13742/// Usually, those items are single-line strings, but in LSP responses,
13743/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13744/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13745/// 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,
13746/// breaking the completions menu presentation.
13747///
13748/// 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.
13749fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13750 let mut new_text = String::with_capacity(label.text.len());
13751 let mut offset_map = vec![0; label.text.len() + 1];
13752 let mut last_char_was_space = false;
13753 let mut new_idx = 0;
13754 let chars = label.text.char_indices().fuse();
13755 let mut newlines_removed = false;
13756
13757 for (idx, c) in chars {
13758 offset_map[idx] = new_idx;
13759
13760 match c {
13761 '\n' if last_char_was_space => {
13762 newlines_removed = true;
13763 }
13764 '\t' | ' ' if last_char_was_space => {}
13765 '\n' if !last_char_was_space => {
13766 new_text.push(' ');
13767 new_idx += 1;
13768 last_char_was_space = true;
13769 newlines_removed = true;
13770 }
13771 ' ' | '\t' => {
13772 new_text.push(' ');
13773 new_idx += 1;
13774 last_char_was_space = true;
13775 }
13776 _ => {
13777 new_text.push(c);
13778 new_idx += c.len_utf8();
13779 last_char_was_space = false;
13780 }
13781 }
13782 }
13783 offset_map[label.text.len()] = new_idx;
13784
13785 // Only modify the label if newlines were removed.
13786 if !newlines_removed {
13787 return;
13788 }
13789
13790 let last_index = new_idx;
13791 let mut run_ranges_errors = Vec::new();
13792 label.runs.retain_mut(|(range, _)| {
13793 match offset_map.get(range.start) {
13794 Some(&start) => range.start = start,
13795 None => {
13796 run_ranges_errors.push(range.clone());
13797 return false;
13798 }
13799 }
13800
13801 match offset_map.get(range.end) {
13802 Some(&end) => range.end = end,
13803 None => {
13804 run_ranges_errors.push(range.clone());
13805 range.end = last_index;
13806 }
13807 }
13808 true
13809 });
13810 if !run_ranges_errors.is_empty() {
13811 log::error!(
13812 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13813 label.text
13814 );
13815 }
13816
13817 let mut wrong_filter_range = None;
13818 if label.filter_range == (0..label.text.len()) {
13819 label.filter_range = 0..new_text.len();
13820 } else {
13821 let mut original_filter_range = Some(label.filter_range.clone());
13822 match offset_map.get(label.filter_range.start) {
13823 Some(&start) => label.filter_range.start = start,
13824 None => {
13825 wrong_filter_range = original_filter_range.take();
13826 label.filter_range.start = last_index;
13827 }
13828 }
13829
13830 match offset_map.get(label.filter_range.end) {
13831 Some(&end) => label.filter_range.end = end,
13832 None => {
13833 wrong_filter_range = original_filter_range.take();
13834 label.filter_range.end = last_index;
13835 }
13836 }
13837 }
13838 if let Some(wrong_filter_range) = wrong_filter_range {
13839 log::error!(
13840 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13841 label.text
13842 );
13843 }
13844
13845 label.text = new_text;
13846}
13847
13848#[cfg(test)]
13849mod tests {
13850 use language::HighlightId;
13851
13852 use super::*;
13853
13854 #[test]
13855 fn test_glob_literal_prefix() {
13856 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13857 assert_eq!(
13858 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13859 Path::new("node_modules")
13860 );
13861 assert_eq!(
13862 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13863 Path::new("foo")
13864 );
13865 assert_eq!(
13866 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13867 Path::new("foo/bar/baz.js")
13868 );
13869
13870 #[cfg(target_os = "windows")]
13871 {
13872 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13873 assert_eq!(
13874 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13875 Path::new("node_modules")
13876 );
13877 assert_eq!(
13878 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13879 Path::new("foo")
13880 );
13881 assert_eq!(
13882 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13883 Path::new("foo/bar/baz.js")
13884 );
13885 }
13886 }
13887
13888 #[test]
13889 fn test_multi_len_chars_normalization() {
13890 let mut label = CodeLabel::new(
13891 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13892 0..6,
13893 vec![(0..6, HighlightId(1))],
13894 );
13895 ensure_uniform_list_compatible_label(&mut label);
13896 assert_eq!(
13897 label,
13898 CodeLabel::new(
13899 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13900 0..6,
13901 vec![(0..6, HighlightId(1))],
13902 )
13903 );
13904 }
13905}