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