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 .unwrap();
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 .unwrap()
7665 .buffer_snapshots
7666 .get_mut(&buffer.remote_id())
7667 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7668 let previous_snapshot = buffer_snapshots.last()?;
7669
7670 let build_incremental_change = || {
7671 buffer
7672 .edits_since::<Dimensions<PointUtf16, usize>>(
7673 previous_snapshot.snapshot.version(),
7674 )
7675 .map(|edit| {
7676 let edit_start = edit.new.start.0;
7677 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7678 let new_text = next_snapshot
7679 .text_for_range(edit.new.start.1..edit.new.end.1)
7680 .collect();
7681 lsp::TextDocumentContentChangeEvent {
7682 range: Some(lsp::Range::new(
7683 point_to_lsp(edit_start),
7684 point_to_lsp(edit_end),
7685 )),
7686 range_length: None,
7687 text: new_text,
7688 }
7689 })
7690 .collect()
7691 };
7692
7693 let document_sync_kind = language_server
7694 .capabilities()
7695 .text_document_sync
7696 .as_ref()
7697 .and_then(|sync| match sync {
7698 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7699 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7700 });
7701
7702 let content_changes: Vec<_> = match document_sync_kind {
7703 Some(lsp::TextDocumentSyncKind::FULL) => {
7704 vec![lsp::TextDocumentContentChangeEvent {
7705 range: None,
7706 range_length: None,
7707 text: next_snapshot.text(),
7708 }]
7709 }
7710 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7711 _ => {
7712 #[cfg(any(test, feature = "test-support"))]
7713 {
7714 build_incremental_change()
7715 }
7716
7717 #[cfg(not(any(test, feature = "test-support")))]
7718 {
7719 continue;
7720 }
7721 }
7722 };
7723
7724 let next_version = previous_snapshot.version + 1;
7725 buffer_snapshots.push(LspBufferSnapshot {
7726 version: next_version,
7727 snapshot: next_snapshot.clone(),
7728 });
7729
7730 language_server
7731 .notify::<lsp::notification::DidChangeTextDocument>(
7732 lsp::DidChangeTextDocumentParams {
7733 text_document: lsp::VersionedTextDocumentIdentifier::new(
7734 uri.clone(),
7735 next_version,
7736 ),
7737 content_changes,
7738 },
7739 )
7740 .ok();
7741 self.pull_workspace_diagnostics(language_server.server_id());
7742 }
7743
7744 None
7745 }
7746
7747 pub fn on_buffer_saved(
7748 &mut self,
7749 buffer: Entity<Buffer>,
7750 cx: &mut Context<Self>,
7751 ) -> Option<()> {
7752 let file = File::from_dyn(buffer.read(cx).file())?;
7753 let worktree_id = file.worktree_id(cx);
7754 let abs_path = file.as_local()?.abs_path(cx);
7755 let text_document = lsp::TextDocumentIdentifier {
7756 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7757 };
7758 let local = self.as_local()?;
7759
7760 for server in local.language_servers_for_worktree(worktree_id) {
7761 if let Some(include_text) = include_text(server.as_ref()) {
7762 let text = if include_text {
7763 Some(buffer.read(cx).text())
7764 } else {
7765 None
7766 };
7767 server
7768 .notify::<lsp::notification::DidSaveTextDocument>(
7769 lsp::DidSaveTextDocumentParams {
7770 text_document: text_document.clone(),
7771 text,
7772 },
7773 )
7774 .ok();
7775 }
7776 }
7777
7778 let language_servers = buffer.update(cx, |buffer, cx| {
7779 local.language_server_ids_for_buffer(buffer, cx)
7780 });
7781 for language_server_id in language_servers {
7782 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7783 }
7784
7785 None
7786 }
7787
7788 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7789 maybe!(async move {
7790 let mut refreshed_servers = HashSet::default();
7791 let servers = lsp_store
7792 .update(cx, |lsp_store, cx| {
7793 let local = lsp_store.as_local()?;
7794
7795 let servers = local
7796 .language_server_ids
7797 .iter()
7798 .filter_map(|(seed, state)| {
7799 let worktree = lsp_store
7800 .worktree_store
7801 .read(cx)
7802 .worktree_for_id(seed.worktree_id, cx);
7803 let delegate: Arc<dyn LspAdapterDelegate> =
7804 worktree.map(|worktree| {
7805 LocalLspAdapterDelegate::new(
7806 local.languages.clone(),
7807 &local.environment,
7808 cx.weak_entity(),
7809 &worktree,
7810 local.http_client.clone(),
7811 local.fs.clone(),
7812 cx,
7813 )
7814 })?;
7815 let server_id = state.id;
7816
7817 let states = local.language_servers.get(&server_id)?;
7818
7819 match states {
7820 LanguageServerState::Starting { .. } => None,
7821 LanguageServerState::Running {
7822 adapter, server, ..
7823 } => {
7824 let adapter = adapter.clone();
7825 let server = server.clone();
7826 refreshed_servers.insert(server.name());
7827 let toolchain = seed.toolchain.clone();
7828 Some(cx.spawn(async move |_, cx| {
7829 let settings =
7830 LocalLspStore::workspace_configuration_for_adapter(
7831 adapter.adapter.clone(),
7832 &delegate,
7833 toolchain,
7834 cx,
7835 )
7836 .await
7837 .ok()?;
7838 server
7839 .notify::<lsp::notification::DidChangeConfiguration>(
7840 lsp::DidChangeConfigurationParams { settings },
7841 )
7842 .ok()?;
7843 Some(())
7844 }))
7845 }
7846 }
7847 })
7848 .collect::<Vec<_>>();
7849
7850 Some(servers)
7851 })
7852 .ok()
7853 .flatten()?;
7854
7855 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7856 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7857 // to stop and unregister its language server wrapper.
7858 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7859 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7860 let _: Vec<Option<()>> = join_all(servers).await;
7861
7862 Some(())
7863 })
7864 .await;
7865 }
7866
7867 fn maintain_workspace_config(
7868 external_refresh_requests: watch::Receiver<()>,
7869 cx: &mut Context<Self>,
7870 ) -> Task<Result<()>> {
7871 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7872 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7873
7874 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7875 *settings_changed_tx.borrow_mut() = ();
7876 });
7877
7878 let mut joint_future =
7879 futures::stream::select(settings_changed_rx, external_refresh_requests);
7880 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7881 // - 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).
7882 // - 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.
7883 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7884 // - 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,
7885 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7886 cx.spawn(async move |this, cx| {
7887 while let Some(()) = joint_future.next().await {
7888 this.update(cx, |this, cx| {
7889 this.refresh_server_tree(cx);
7890 })
7891 .ok();
7892
7893 Self::refresh_workspace_configurations(&this, cx).await;
7894 }
7895
7896 drop(settings_observation);
7897 anyhow::Ok(())
7898 })
7899 }
7900
7901 pub fn language_servers_for_local_buffer<'a>(
7902 &'a self,
7903 buffer: &Buffer,
7904 cx: &mut App,
7905 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7906 let local = self.as_local();
7907 let language_server_ids = local
7908 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7909 .unwrap_or_default();
7910
7911 language_server_ids
7912 .into_iter()
7913 .filter_map(
7914 move |server_id| match local?.language_servers.get(&server_id)? {
7915 LanguageServerState::Running {
7916 adapter, server, ..
7917 } => Some((adapter, server)),
7918 _ => None,
7919 },
7920 )
7921 }
7922
7923 pub fn language_server_for_local_buffer<'a>(
7924 &'a self,
7925 buffer: &'a Buffer,
7926 server_id: LanguageServerId,
7927 cx: &'a mut App,
7928 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7929 self.as_local()?
7930 .language_servers_for_buffer(buffer, cx)
7931 .find(|(_, s)| s.server_id() == server_id)
7932 }
7933
7934 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7935 self.diagnostic_summaries.remove(&id_to_remove);
7936 if let Some(local) = self.as_local_mut() {
7937 let to_remove = local.remove_worktree(id_to_remove, cx);
7938 for server in to_remove {
7939 self.language_server_statuses.remove(&server);
7940 }
7941 }
7942 }
7943
7944 pub fn shared(
7945 &mut self,
7946 project_id: u64,
7947 downstream_client: AnyProtoClient,
7948 _: &mut Context<Self>,
7949 ) {
7950 self.downstream_client = Some((downstream_client.clone(), project_id));
7951
7952 for (server_id, status) in &self.language_server_statuses {
7953 if let Some(server) = self.language_server_for_id(*server_id) {
7954 downstream_client
7955 .send(proto::StartLanguageServer {
7956 project_id,
7957 server: Some(proto::LanguageServer {
7958 id: server_id.to_proto(),
7959 name: status.name.to_string(),
7960 worktree_id: status.worktree.map(|id| id.to_proto()),
7961 }),
7962 capabilities: serde_json::to_string(&server.capabilities())
7963 .expect("serializing server LSP capabilities"),
7964 })
7965 .log_err();
7966 }
7967 }
7968 }
7969
7970 pub fn disconnected_from_host(&mut self) {
7971 self.downstream_client.take();
7972 }
7973
7974 pub fn disconnected_from_ssh_remote(&mut self) {
7975 if let LspStoreMode::Remote(RemoteLspStore {
7976 upstream_client, ..
7977 }) = &mut self.mode
7978 {
7979 upstream_client.take();
7980 }
7981 }
7982
7983 pub(crate) fn set_language_server_statuses_from_proto(
7984 &mut self,
7985 project: WeakEntity<Project>,
7986 language_servers: Vec<proto::LanguageServer>,
7987 server_capabilities: Vec<String>,
7988 cx: &mut Context<Self>,
7989 ) {
7990 let lsp_logs = cx
7991 .try_global::<GlobalLogStore>()
7992 .map(|lsp_store| lsp_store.0.clone());
7993
7994 self.language_server_statuses = language_servers
7995 .into_iter()
7996 .zip(server_capabilities)
7997 .map(|(server, server_capabilities)| {
7998 let server_id = LanguageServerId(server.id as usize);
7999 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8000 self.lsp_server_capabilities
8001 .insert(server_id, server_capabilities);
8002 }
8003
8004 let name = LanguageServerName::from_proto(server.name);
8005 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8006
8007 if let Some(lsp_logs) = &lsp_logs {
8008 lsp_logs.update(cx, |lsp_logs, cx| {
8009 lsp_logs.add_language_server(
8010 // Only remote clients get their language servers set from proto
8011 LanguageServerKind::Remote {
8012 project: project.clone(),
8013 },
8014 server_id,
8015 Some(name.clone()),
8016 worktree,
8017 None,
8018 cx,
8019 );
8020 });
8021 }
8022
8023 (
8024 server_id,
8025 LanguageServerStatus {
8026 name,
8027 pending_work: Default::default(),
8028 has_pending_diagnostic_updates: false,
8029 progress_tokens: Default::default(),
8030 worktree,
8031 },
8032 )
8033 })
8034 .collect();
8035 }
8036
8037 #[cfg(test)]
8038 pub fn update_diagnostic_entries(
8039 &mut self,
8040 server_id: LanguageServerId,
8041 abs_path: PathBuf,
8042 result_id: Option<String>,
8043 version: Option<i32>,
8044 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8045 cx: &mut Context<Self>,
8046 ) -> anyhow::Result<()> {
8047 self.merge_diagnostic_entries(
8048 vec![DocumentDiagnosticsUpdate {
8049 diagnostics: DocumentDiagnostics {
8050 diagnostics,
8051 document_abs_path: abs_path,
8052 version,
8053 },
8054 result_id,
8055 server_id,
8056 disk_based_sources: Cow::Borrowed(&[]),
8057 }],
8058 |_, _, _| false,
8059 cx,
8060 )?;
8061 Ok(())
8062 }
8063
8064 pub fn merge_diagnostic_entries<'a>(
8065 &mut self,
8066 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8067 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8068 cx: &mut Context<Self>,
8069 ) -> anyhow::Result<()> {
8070 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8071 let mut updated_diagnostics_paths = HashMap::default();
8072 for mut update in diagnostic_updates {
8073 let abs_path = &update.diagnostics.document_abs_path;
8074 let server_id = update.server_id;
8075 let Some((worktree, relative_path)) =
8076 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8077 else {
8078 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8079 return Ok(());
8080 };
8081
8082 let worktree_id = worktree.read(cx).id();
8083 let project_path = ProjectPath {
8084 worktree_id,
8085 path: relative_path,
8086 };
8087
8088 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8089 let snapshot = buffer_handle.read(cx).snapshot();
8090 let buffer = buffer_handle.read(cx);
8091 let reused_diagnostics = buffer
8092 .buffer_diagnostics(Some(server_id))
8093 .iter()
8094 .filter(|v| merge(buffer, &v.diagnostic, cx))
8095 .map(|v| {
8096 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8097 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8098 DiagnosticEntry {
8099 range: start..end,
8100 diagnostic: v.diagnostic.clone(),
8101 }
8102 })
8103 .collect::<Vec<_>>();
8104
8105 self.as_local_mut()
8106 .context("cannot merge diagnostics on a remote LspStore")?
8107 .update_buffer_diagnostics(
8108 &buffer_handle,
8109 server_id,
8110 update.result_id,
8111 update.diagnostics.version,
8112 update.diagnostics.diagnostics.clone(),
8113 reused_diagnostics.clone(),
8114 cx,
8115 )?;
8116
8117 update.diagnostics.diagnostics.extend(reused_diagnostics);
8118 }
8119
8120 let updated = worktree.update(cx, |worktree, cx| {
8121 self.update_worktree_diagnostics(
8122 worktree.id(),
8123 server_id,
8124 project_path.path.clone(),
8125 update.diagnostics.diagnostics,
8126 cx,
8127 )
8128 })?;
8129 match updated {
8130 ControlFlow::Continue(new_summary) => {
8131 if let Some((project_id, new_summary)) = new_summary {
8132 match &mut diagnostics_summary {
8133 Some(diagnostics_summary) => {
8134 diagnostics_summary
8135 .more_summaries
8136 .push(proto::DiagnosticSummary {
8137 path: project_path.path.as_ref().to_proto(),
8138 language_server_id: server_id.0 as u64,
8139 error_count: new_summary.error_count,
8140 warning_count: new_summary.warning_count,
8141 })
8142 }
8143 None => {
8144 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8145 project_id,
8146 worktree_id: worktree_id.to_proto(),
8147 summary: Some(proto::DiagnosticSummary {
8148 path: project_path.path.as_ref().to_proto(),
8149 language_server_id: server_id.0 as u64,
8150 error_count: new_summary.error_count,
8151 warning_count: new_summary.warning_count,
8152 }),
8153 more_summaries: Vec::new(),
8154 })
8155 }
8156 }
8157 }
8158 updated_diagnostics_paths
8159 .entry(server_id)
8160 .or_insert_with(Vec::new)
8161 .push(project_path);
8162 }
8163 ControlFlow::Break(()) => {}
8164 }
8165 }
8166
8167 if let Some((diagnostics_summary, (downstream_client, _))) =
8168 diagnostics_summary.zip(self.downstream_client.as_ref())
8169 {
8170 downstream_client.send(diagnostics_summary).log_err();
8171 }
8172 for (server_id, paths) in updated_diagnostics_paths {
8173 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8174 }
8175 Ok(())
8176 }
8177
8178 fn update_worktree_diagnostics(
8179 &mut self,
8180 worktree_id: WorktreeId,
8181 server_id: LanguageServerId,
8182 path_in_worktree: Arc<RelPath>,
8183 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8184 _: &mut Context<Worktree>,
8185 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8186 let local = match &mut self.mode {
8187 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8188 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8189 };
8190
8191 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8192 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8193 let summaries_by_server_id = summaries_for_tree
8194 .entry(path_in_worktree.clone())
8195 .or_default();
8196
8197 let old_summary = summaries_by_server_id
8198 .remove(&server_id)
8199 .unwrap_or_default();
8200
8201 let new_summary = DiagnosticSummary::new(&diagnostics);
8202 if new_summary.is_empty() {
8203 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8204 {
8205 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8206 diagnostics_by_server_id.remove(ix);
8207 }
8208 if diagnostics_by_server_id.is_empty() {
8209 diagnostics_for_tree.remove(&path_in_worktree);
8210 }
8211 }
8212 } else {
8213 summaries_by_server_id.insert(server_id, new_summary);
8214 let diagnostics_by_server_id = diagnostics_for_tree
8215 .entry(path_in_worktree.clone())
8216 .or_default();
8217 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8218 Ok(ix) => {
8219 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8220 }
8221 Err(ix) => {
8222 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8223 }
8224 }
8225 }
8226
8227 if !old_summary.is_empty() || !new_summary.is_empty() {
8228 if let Some((_, project_id)) = &self.downstream_client {
8229 Ok(ControlFlow::Continue(Some((
8230 *project_id,
8231 proto::DiagnosticSummary {
8232 path: path_in_worktree.to_proto(),
8233 language_server_id: server_id.0 as u64,
8234 error_count: new_summary.error_count as u32,
8235 warning_count: new_summary.warning_count as u32,
8236 },
8237 ))))
8238 } else {
8239 Ok(ControlFlow::Continue(None))
8240 }
8241 } else {
8242 Ok(ControlFlow::Break(()))
8243 }
8244 }
8245
8246 pub fn open_buffer_for_symbol(
8247 &mut self,
8248 symbol: &Symbol,
8249 cx: &mut Context<Self>,
8250 ) -> Task<Result<Entity<Buffer>>> {
8251 if let Some((client, project_id)) = self.upstream_client() {
8252 let request = client.request(proto::OpenBufferForSymbol {
8253 project_id,
8254 symbol: Some(Self::serialize_symbol(symbol)),
8255 });
8256 cx.spawn(async move |this, cx| {
8257 let response = request.await?;
8258 let buffer_id = BufferId::new(response.buffer_id)?;
8259 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8260 .await
8261 })
8262 } else if let Some(local) = self.as_local() {
8263 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8264 seed.worktree_id == symbol.source_worktree_id
8265 && state.id == symbol.source_language_server_id
8266 && symbol.language_server_name == seed.name
8267 });
8268 if !is_valid {
8269 return Task::ready(Err(anyhow!(
8270 "language server for worktree and language not found"
8271 )));
8272 };
8273
8274 let symbol_abs_path = match &symbol.path {
8275 SymbolLocation::InProject(project_path) => self
8276 .worktree_store
8277 .read(cx)
8278 .absolutize(&project_path, cx)
8279 .context("no such worktree"),
8280 SymbolLocation::OutsideProject {
8281 abs_path,
8282 signature: _,
8283 } => Ok(abs_path.to_path_buf()),
8284 };
8285 let symbol_abs_path = match symbol_abs_path {
8286 Ok(abs_path) => abs_path,
8287 Err(err) => return Task::ready(Err(err)),
8288 };
8289 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8290 uri
8291 } else {
8292 return Task::ready(Err(anyhow!("invalid symbol path")));
8293 };
8294
8295 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8296 } else {
8297 Task::ready(Err(anyhow!("no upstream client or local store")))
8298 }
8299 }
8300
8301 pub(crate) fn open_local_buffer_via_lsp(
8302 &mut self,
8303 abs_path: lsp::Uri,
8304 language_server_id: LanguageServerId,
8305 cx: &mut Context<Self>,
8306 ) -> Task<Result<Entity<Buffer>>> {
8307 cx.spawn(async move |lsp_store, cx| {
8308 // Escape percent-encoded string.
8309 let current_scheme = abs_path.scheme().to_owned();
8310 // Uri is immutable, so we can't modify the scheme
8311
8312 let abs_path = abs_path
8313 .to_file_path()
8314 .map_err(|()| anyhow!("can't convert URI to path"))?;
8315 let p = abs_path.clone();
8316 let yarn_worktree = lsp_store
8317 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8318 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8319 cx.spawn(async move |this, cx| {
8320 let t = this
8321 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8322 .ok()?;
8323 t.await
8324 })
8325 }),
8326 None => Task::ready(None),
8327 })?
8328 .await;
8329 let (worktree_root_target, known_relative_path) =
8330 if let Some((zip_root, relative_path)) = yarn_worktree {
8331 (zip_root, Some(relative_path))
8332 } else {
8333 (Arc::<Path>::from(abs_path.as_path()), None)
8334 };
8335 let (worktree, relative_path) = if let Some(result) =
8336 lsp_store.update(cx, |lsp_store, cx| {
8337 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8338 worktree_store.find_worktree(&worktree_root_target, cx)
8339 })
8340 })? {
8341 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8342 (result.0, relative_path)
8343 } else {
8344 let worktree = lsp_store
8345 .update(cx, |lsp_store, cx| {
8346 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8347 worktree_store.create_worktree(&worktree_root_target, false, cx)
8348 })
8349 })?
8350 .await?;
8351 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8352 lsp_store
8353 .update(cx, |lsp_store, cx| {
8354 if let Some(local) = lsp_store.as_local_mut() {
8355 local.register_language_server_for_invisible_worktree(
8356 &worktree,
8357 language_server_id,
8358 cx,
8359 )
8360 }
8361 })
8362 .ok();
8363 }
8364 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8365 let relative_path = if let Some(known_path) = known_relative_path {
8366 known_path
8367 } else {
8368 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8369 .into_arc()
8370 };
8371 (worktree, relative_path)
8372 };
8373 let project_path = ProjectPath {
8374 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8375 path: relative_path,
8376 };
8377 lsp_store
8378 .update(cx, |lsp_store, cx| {
8379 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8380 buffer_store.open_buffer(project_path, cx)
8381 })
8382 })?
8383 .await
8384 })
8385 }
8386
8387 fn request_multiple_lsp_locally<P, R>(
8388 &mut self,
8389 buffer: &Entity<Buffer>,
8390 position: Option<P>,
8391 request: R,
8392 cx: &mut Context<Self>,
8393 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8394 where
8395 P: ToOffset,
8396 R: LspCommand + Clone,
8397 <R::LspRequest as lsp::request::Request>::Result: Send,
8398 <R::LspRequest as lsp::request::Request>::Params: Send,
8399 {
8400 let Some(local) = self.as_local() else {
8401 return Task::ready(Vec::new());
8402 };
8403
8404 let snapshot = buffer.read(cx).snapshot();
8405 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8406
8407 let server_ids = buffer.update(cx, |buffer, cx| {
8408 local
8409 .language_servers_for_buffer(buffer, cx)
8410 .filter(|(adapter, _)| {
8411 scope
8412 .as_ref()
8413 .map(|scope| scope.language_allowed(&adapter.name))
8414 .unwrap_or(true)
8415 })
8416 .map(|(_, server)| server.server_id())
8417 .filter(|server_id| {
8418 self.as_local().is_none_or(|local| {
8419 local
8420 .buffers_opened_in_servers
8421 .get(&snapshot.remote_id())
8422 .is_some_and(|servers| servers.contains(server_id))
8423 })
8424 })
8425 .collect::<Vec<_>>()
8426 });
8427
8428 let mut response_results = server_ids
8429 .into_iter()
8430 .map(|server_id| {
8431 let task = self.request_lsp(
8432 buffer.clone(),
8433 LanguageServerToQuery::Other(server_id),
8434 request.clone(),
8435 cx,
8436 );
8437 async move { (server_id, task.await) }
8438 })
8439 .collect::<FuturesUnordered<_>>();
8440
8441 cx.background_spawn(async move {
8442 let mut responses = Vec::with_capacity(response_results.len());
8443 while let Some((server_id, response_result)) = response_results.next().await {
8444 match response_result {
8445 Ok(response) => responses.push((server_id, response)),
8446 // rust-analyzer likes to error with this when its still loading up
8447 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8448 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8449 }
8450 }
8451 responses
8452 })
8453 }
8454
8455 async fn handle_lsp_command<T: LspCommand>(
8456 this: Entity<Self>,
8457 envelope: TypedEnvelope<T::ProtoRequest>,
8458 mut cx: AsyncApp,
8459 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8460 where
8461 <T::LspRequest as lsp::request::Request>::Params: Send,
8462 <T::LspRequest as lsp::request::Request>::Result: Send,
8463 {
8464 let sender_id = envelope.original_sender_id().unwrap_or_default();
8465 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8466 let buffer_handle = this.update(&mut cx, |this, cx| {
8467 this.buffer_store.read(cx).get_existing(buffer_id)
8468 })??;
8469 let request = T::from_proto(
8470 envelope.payload,
8471 this.clone(),
8472 buffer_handle.clone(),
8473 cx.clone(),
8474 )
8475 .await?;
8476 let response = this
8477 .update(&mut cx, |this, cx| {
8478 this.request_lsp(
8479 buffer_handle.clone(),
8480 LanguageServerToQuery::FirstCapable,
8481 request,
8482 cx,
8483 )
8484 })?
8485 .await?;
8486 this.update(&mut cx, |this, cx| {
8487 Ok(T::response_to_proto(
8488 response,
8489 this,
8490 sender_id,
8491 &buffer_handle.read(cx).version(),
8492 cx,
8493 ))
8494 })?
8495 }
8496
8497 async fn handle_lsp_query(
8498 lsp_store: Entity<Self>,
8499 envelope: TypedEnvelope<proto::LspQuery>,
8500 mut cx: AsyncApp,
8501 ) -> Result<proto::Ack> {
8502 use proto::lsp_query::Request;
8503 let sender_id = envelope.original_sender_id().unwrap_or_default();
8504 let lsp_query = envelope.payload;
8505 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8506 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8507 match lsp_query.request.context("invalid LSP query request")? {
8508 Request::GetReferences(get_references) => {
8509 let position = get_references.position.clone().and_then(deserialize_anchor);
8510 Self::query_lsp_locally::<GetReferences>(
8511 lsp_store,
8512 server_id,
8513 sender_id,
8514 lsp_request_id,
8515 get_references,
8516 position,
8517 &mut cx,
8518 )
8519 .await?;
8520 }
8521 Request::GetDocumentColor(get_document_color) => {
8522 Self::query_lsp_locally::<GetDocumentColor>(
8523 lsp_store,
8524 server_id,
8525 sender_id,
8526 lsp_request_id,
8527 get_document_color,
8528 None,
8529 &mut cx,
8530 )
8531 .await?;
8532 }
8533 Request::GetHover(get_hover) => {
8534 let position = get_hover.position.clone().and_then(deserialize_anchor);
8535 Self::query_lsp_locally::<GetHover>(
8536 lsp_store,
8537 server_id,
8538 sender_id,
8539 lsp_request_id,
8540 get_hover,
8541 position,
8542 &mut cx,
8543 )
8544 .await?;
8545 }
8546 Request::GetCodeActions(get_code_actions) => {
8547 Self::query_lsp_locally::<GetCodeActions>(
8548 lsp_store,
8549 server_id,
8550 sender_id,
8551 lsp_request_id,
8552 get_code_actions,
8553 None,
8554 &mut cx,
8555 )
8556 .await?;
8557 }
8558 Request::GetSignatureHelp(get_signature_help) => {
8559 let position = get_signature_help
8560 .position
8561 .clone()
8562 .and_then(deserialize_anchor);
8563 Self::query_lsp_locally::<GetSignatureHelp>(
8564 lsp_store,
8565 server_id,
8566 sender_id,
8567 lsp_request_id,
8568 get_signature_help,
8569 position,
8570 &mut cx,
8571 )
8572 .await?;
8573 }
8574 Request::GetCodeLens(get_code_lens) => {
8575 Self::query_lsp_locally::<GetCodeLens>(
8576 lsp_store,
8577 server_id,
8578 sender_id,
8579 lsp_request_id,
8580 get_code_lens,
8581 None,
8582 &mut cx,
8583 )
8584 .await?;
8585 }
8586 Request::GetDefinition(get_definition) => {
8587 let position = get_definition.position.clone().and_then(deserialize_anchor);
8588 Self::query_lsp_locally::<GetDefinitions>(
8589 lsp_store,
8590 server_id,
8591 sender_id,
8592 lsp_request_id,
8593 get_definition,
8594 position,
8595 &mut cx,
8596 )
8597 .await?;
8598 }
8599 Request::GetDeclaration(get_declaration) => {
8600 let position = get_declaration
8601 .position
8602 .clone()
8603 .and_then(deserialize_anchor);
8604 Self::query_lsp_locally::<GetDeclarations>(
8605 lsp_store,
8606 server_id,
8607 sender_id,
8608 lsp_request_id,
8609 get_declaration,
8610 position,
8611 &mut cx,
8612 )
8613 .await?;
8614 }
8615 Request::GetTypeDefinition(get_type_definition) => {
8616 let position = get_type_definition
8617 .position
8618 .clone()
8619 .and_then(deserialize_anchor);
8620 Self::query_lsp_locally::<GetTypeDefinitions>(
8621 lsp_store,
8622 server_id,
8623 sender_id,
8624 lsp_request_id,
8625 get_type_definition,
8626 position,
8627 &mut cx,
8628 )
8629 .await?;
8630 }
8631 Request::GetImplementation(get_implementation) => {
8632 let position = get_implementation
8633 .position
8634 .clone()
8635 .and_then(deserialize_anchor);
8636 Self::query_lsp_locally::<GetImplementations>(
8637 lsp_store,
8638 server_id,
8639 sender_id,
8640 lsp_request_id,
8641 get_implementation,
8642 position,
8643 &mut cx,
8644 )
8645 .await?;
8646 }
8647 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8648 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8649 let version = deserialize_version(get_document_diagnostics.buffer_version());
8650 let buffer = lsp_store.update(&mut cx, |this, cx| {
8651 this.buffer_store.read(cx).get_existing(buffer_id)
8652 })??;
8653 buffer
8654 .update(&mut cx, |buffer, _| {
8655 buffer.wait_for_version(version.clone())
8656 })?
8657 .await?;
8658 lsp_store.update(&mut cx, |lsp_store, cx| {
8659 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8660 let key = LspKey {
8661 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8662 server_queried: server_id,
8663 };
8664 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8665 ) {
8666 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8667 lsp_requests.clear();
8668 };
8669 }
8670
8671 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8672 existing_queries.insert(
8673 lsp_request_id,
8674 cx.spawn(async move |lsp_store, cx| {
8675 let diagnostics_pull = lsp_store
8676 .update(cx, |lsp_store, cx| {
8677 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8678 })
8679 .ok();
8680 if let Some(diagnostics_pull) = diagnostics_pull {
8681 match diagnostics_pull.await {
8682 Ok(()) => {}
8683 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8684 };
8685 }
8686 }),
8687 );
8688 })?;
8689 }
8690 Request::InlayHints(inlay_hints) => {
8691 let query_start = inlay_hints
8692 .start
8693 .clone()
8694 .and_then(deserialize_anchor)
8695 .context("invalid inlay hints range start")?;
8696 let query_end = inlay_hints
8697 .end
8698 .clone()
8699 .and_then(deserialize_anchor)
8700 .context("invalid inlay hints range end")?;
8701 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8702 &lsp_store,
8703 server_id,
8704 lsp_request_id,
8705 &inlay_hints,
8706 query_start..query_end,
8707 &mut cx,
8708 )
8709 .await
8710 .context("preparing inlay hints request")?;
8711 Self::query_lsp_locally::<InlayHints>(
8712 lsp_store,
8713 server_id,
8714 sender_id,
8715 lsp_request_id,
8716 inlay_hints,
8717 None,
8718 &mut cx,
8719 )
8720 .await
8721 .context("querying for inlay hints")?
8722 }
8723 }
8724 Ok(proto::Ack {})
8725 }
8726
8727 async fn handle_lsp_query_response(
8728 lsp_store: Entity<Self>,
8729 envelope: TypedEnvelope<proto::LspQueryResponse>,
8730 cx: AsyncApp,
8731 ) -> Result<()> {
8732 lsp_store.read_with(&cx, |lsp_store, _| {
8733 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8734 upstream_client.handle_lsp_response(envelope.clone());
8735 }
8736 })?;
8737 Ok(())
8738 }
8739
8740 async fn handle_apply_code_action(
8741 this: Entity<Self>,
8742 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8743 mut cx: AsyncApp,
8744 ) -> Result<proto::ApplyCodeActionResponse> {
8745 let sender_id = envelope.original_sender_id().unwrap_or_default();
8746 let action =
8747 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8748 let apply_code_action = this.update(&mut cx, |this, cx| {
8749 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8750 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8751 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8752 })??;
8753
8754 let project_transaction = apply_code_action.await?;
8755 let project_transaction = this.update(&mut cx, |this, cx| {
8756 this.buffer_store.update(cx, |buffer_store, cx| {
8757 buffer_store.serialize_project_transaction_for_peer(
8758 project_transaction,
8759 sender_id,
8760 cx,
8761 )
8762 })
8763 })?;
8764 Ok(proto::ApplyCodeActionResponse {
8765 transaction: Some(project_transaction),
8766 })
8767 }
8768
8769 async fn handle_register_buffer_with_language_servers(
8770 this: Entity<Self>,
8771 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8772 mut cx: AsyncApp,
8773 ) -> Result<proto::Ack> {
8774 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8775 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8776 this.update(&mut cx, |this, cx| {
8777 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8778 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8779 project_id: upstream_project_id,
8780 buffer_id: buffer_id.to_proto(),
8781 only_servers: envelope.payload.only_servers,
8782 });
8783 }
8784
8785 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8786 anyhow::bail!("buffer is not open");
8787 };
8788
8789 let handle = this.register_buffer_with_language_servers(
8790 &buffer,
8791 envelope
8792 .payload
8793 .only_servers
8794 .into_iter()
8795 .filter_map(|selector| {
8796 Some(match selector.selector? {
8797 proto::language_server_selector::Selector::ServerId(server_id) => {
8798 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8799 }
8800 proto::language_server_selector::Selector::Name(name) => {
8801 LanguageServerSelector::Name(LanguageServerName(
8802 SharedString::from(name),
8803 ))
8804 }
8805 })
8806 })
8807 .collect(),
8808 false,
8809 cx,
8810 );
8811 this.buffer_store().update(cx, |buffer_store, _| {
8812 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8813 });
8814
8815 Ok(())
8816 })??;
8817 Ok(proto::Ack {})
8818 }
8819
8820 async fn handle_rename_project_entry(
8821 this: Entity<Self>,
8822 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8823 mut cx: AsyncApp,
8824 ) -> Result<proto::ProjectEntryResponse> {
8825 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8826 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8827 let new_path =
8828 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8829
8830 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8831 .update(&mut cx, |this, cx| {
8832 let (worktree, entry) = this
8833 .worktree_store
8834 .read(cx)
8835 .worktree_and_entry_for_id(entry_id, cx)?;
8836 let new_worktree = this
8837 .worktree_store
8838 .read(cx)
8839 .worktree_for_id(new_worktree_id, cx)?;
8840 Some((
8841 this.worktree_store.clone(),
8842 worktree,
8843 new_worktree,
8844 entry.clone(),
8845 ))
8846 })?
8847 .context("worktree not found")?;
8848 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8849 (worktree.absolutize(&old_entry.path), worktree.id())
8850 })?;
8851 let new_abs_path =
8852 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8853
8854 let _transaction = Self::will_rename_entry(
8855 this.downgrade(),
8856 old_worktree_id,
8857 &old_abs_path,
8858 &new_abs_path,
8859 old_entry.is_dir(),
8860 cx.clone(),
8861 )
8862 .await;
8863 let response = WorktreeStore::handle_rename_project_entry(
8864 worktree_store,
8865 envelope.payload,
8866 cx.clone(),
8867 )
8868 .await;
8869 this.read_with(&cx, |this, _| {
8870 this.did_rename_entry(
8871 old_worktree_id,
8872 &old_abs_path,
8873 &new_abs_path,
8874 old_entry.is_dir(),
8875 );
8876 })
8877 .ok();
8878 response
8879 }
8880
8881 async fn handle_update_diagnostic_summary(
8882 this: Entity<Self>,
8883 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8884 mut cx: AsyncApp,
8885 ) -> Result<()> {
8886 this.update(&mut cx, |lsp_store, cx| {
8887 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8888 let mut updated_diagnostics_paths = HashMap::default();
8889 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8890 for message_summary in envelope
8891 .payload
8892 .summary
8893 .into_iter()
8894 .chain(envelope.payload.more_summaries)
8895 {
8896 let project_path = ProjectPath {
8897 worktree_id,
8898 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8899 };
8900 let path = project_path.path.clone();
8901 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8902 let summary = DiagnosticSummary {
8903 error_count: message_summary.error_count as usize,
8904 warning_count: message_summary.warning_count as usize,
8905 };
8906
8907 if summary.is_empty() {
8908 if let Some(worktree_summaries) =
8909 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8910 && let Some(summaries) = worktree_summaries.get_mut(&path)
8911 {
8912 summaries.remove(&server_id);
8913 if summaries.is_empty() {
8914 worktree_summaries.remove(&path);
8915 }
8916 }
8917 } else {
8918 lsp_store
8919 .diagnostic_summaries
8920 .entry(worktree_id)
8921 .or_default()
8922 .entry(path)
8923 .or_default()
8924 .insert(server_id, summary);
8925 }
8926
8927 if let Some((_, project_id)) = &lsp_store.downstream_client {
8928 match &mut diagnostics_summary {
8929 Some(diagnostics_summary) => {
8930 diagnostics_summary
8931 .more_summaries
8932 .push(proto::DiagnosticSummary {
8933 path: project_path.path.as_ref().to_proto(),
8934 language_server_id: server_id.0 as u64,
8935 error_count: summary.error_count as u32,
8936 warning_count: summary.warning_count as u32,
8937 })
8938 }
8939 None => {
8940 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8941 project_id: *project_id,
8942 worktree_id: worktree_id.to_proto(),
8943 summary: Some(proto::DiagnosticSummary {
8944 path: project_path.path.as_ref().to_proto(),
8945 language_server_id: server_id.0 as u64,
8946 error_count: summary.error_count as u32,
8947 warning_count: summary.warning_count as u32,
8948 }),
8949 more_summaries: Vec::new(),
8950 })
8951 }
8952 }
8953 }
8954 updated_diagnostics_paths
8955 .entry(server_id)
8956 .or_insert_with(Vec::new)
8957 .push(project_path);
8958 }
8959
8960 if let Some((diagnostics_summary, (downstream_client, _))) =
8961 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8962 {
8963 downstream_client.send(diagnostics_summary).log_err();
8964 }
8965 for (server_id, paths) in updated_diagnostics_paths {
8966 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8967 }
8968 Ok(())
8969 })?
8970 }
8971
8972 async fn handle_start_language_server(
8973 lsp_store: Entity<Self>,
8974 envelope: TypedEnvelope<proto::StartLanguageServer>,
8975 mut cx: AsyncApp,
8976 ) -> Result<()> {
8977 let server = envelope.payload.server.context("invalid server")?;
8978 let server_capabilities =
8979 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8980 .with_context(|| {
8981 format!(
8982 "incorrect server capabilities {}",
8983 envelope.payload.capabilities
8984 )
8985 })?;
8986 lsp_store.update(&mut cx, |lsp_store, cx| {
8987 let server_id = LanguageServerId(server.id as usize);
8988 let server_name = LanguageServerName::from_proto(server.name.clone());
8989 lsp_store
8990 .lsp_server_capabilities
8991 .insert(server_id, server_capabilities);
8992 lsp_store.language_server_statuses.insert(
8993 server_id,
8994 LanguageServerStatus {
8995 name: server_name.clone(),
8996 pending_work: Default::default(),
8997 has_pending_diagnostic_updates: false,
8998 progress_tokens: Default::default(),
8999 worktree: server.worktree_id.map(WorktreeId::from_proto),
9000 },
9001 );
9002 cx.emit(LspStoreEvent::LanguageServerAdded(
9003 server_id,
9004 server_name,
9005 server.worktree_id.map(WorktreeId::from_proto),
9006 ));
9007 cx.notify();
9008 })?;
9009 Ok(())
9010 }
9011
9012 async fn handle_update_language_server(
9013 lsp_store: Entity<Self>,
9014 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9015 mut cx: AsyncApp,
9016 ) -> Result<()> {
9017 lsp_store.update(&mut cx, |lsp_store, cx| {
9018 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9019
9020 match envelope.payload.variant.context("invalid variant")? {
9021 proto::update_language_server::Variant::WorkStart(payload) => {
9022 lsp_store.on_lsp_work_start(
9023 language_server_id,
9024 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9025 .context("invalid progress token value")?,
9026 LanguageServerProgress {
9027 title: payload.title,
9028 is_disk_based_diagnostics_progress: false,
9029 is_cancellable: payload.is_cancellable.unwrap_or(false),
9030 message: payload.message,
9031 percentage: payload.percentage.map(|p| p as usize),
9032 last_update_at: cx.background_executor().now(),
9033 },
9034 cx,
9035 );
9036 }
9037 proto::update_language_server::Variant::WorkProgress(payload) => {
9038 lsp_store.on_lsp_work_progress(
9039 language_server_id,
9040 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9041 .context("invalid progress token value")?,
9042 LanguageServerProgress {
9043 title: None,
9044 is_disk_based_diagnostics_progress: false,
9045 is_cancellable: payload.is_cancellable.unwrap_or(false),
9046 message: payload.message,
9047 percentage: payload.percentage.map(|p| p as usize),
9048 last_update_at: cx.background_executor().now(),
9049 },
9050 cx,
9051 );
9052 }
9053
9054 proto::update_language_server::Variant::WorkEnd(payload) => {
9055 lsp_store.on_lsp_work_end(
9056 language_server_id,
9057 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9058 .context("invalid progress token value")?,
9059 cx,
9060 );
9061 }
9062
9063 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9064 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9065 }
9066
9067 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9068 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9069 }
9070
9071 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9072 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9073 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9074 cx.emit(LspStoreEvent::LanguageServerUpdate {
9075 language_server_id,
9076 name: envelope
9077 .payload
9078 .server_name
9079 .map(SharedString::new)
9080 .map(LanguageServerName),
9081 message: non_lsp,
9082 });
9083 }
9084 }
9085
9086 Ok(())
9087 })?
9088 }
9089
9090 async fn handle_language_server_log(
9091 this: Entity<Self>,
9092 envelope: TypedEnvelope<proto::LanguageServerLog>,
9093 mut cx: AsyncApp,
9094 ) -> Result<()> {
9095 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9096 let log_type = envelope
9097 .payload
9098 .log_type
9099 .map(LanguageServerLogType::from_proto)
9100 .context("invalid language server log type")?;
9101
9102 let message = envelope.payload.message;
9103
9104 this.update(&mut cx, |_, cx| {
9105 cx.emit(LspStoreEvent::LanguageServerLog(
9106 language_server_id,
9107 log_type,
9108 message,
9109 ));
9110 })
9111 }
9112
9113 async fn handle_lsp_ext_cancel_flycheck(
9114 lsp_store: Entity<Self>,
9115 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9116 cx: AsyncApp,
9117 ) -> Result<proto::Ack> {
9118 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9119 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9120 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9121 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9122 } else {
9123 None
9124 }
9125 })?;
9126 if let Some(task) = task {
9127 task.context("handling lsp ext cancel flycheck")?;
9128 }
9129
9130 Ok(proto::Ack {})
9131 }
9132
9133 async fn handle_lsp_ext_run_flycheck(
9134 lsp_store: Entity<Self>,
9135 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9136 mut cx: AsyncApp,
9137 ) -> Result<proto::Ack> {
9138 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9139 lsp_store.update(&mut cx, |lsp_store, cx| {
9140 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9141 let text_document = if envelope.payload.current_file_only {
9142 let buffer_id = envelope
9143 .payload
9144 .buffer_id
9145 .map(|id| BufferId::new(id))
9146 .transpose()?;
9147 buffer_id
9148 .and_then(|buffer_id| {
9149 lsp_store
9150 .buffer_store()
9151 .read(cx)
9152 .get(buffer_id)
9153 .and_then(|buffer| {
9154 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9155 })
9156 .map(|path| make_text_document_identifier(&path))
9157 })
9158 .transpose()?
9159 } else {
9160 None
9161 };
9162 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9163 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9164 )?;
9165 }
9166 anyhow::Ok(())
9167 })??;
9168
9169 Ok(proto::Ack {})
9170 }
9171
9172 async fn handle_lsp_ext_clear_flycheck(
9173 lsp_store: Entity<Self>,
9174 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9175 cx: AsyncApp,
9176 ) -> Result<proto::Ack> {
9177 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9178 lsp_store
9179 .read_with(&cx, |lsp_store, _| {
9180 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9181 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9182 } else {
9183 None
9184 }
9185 })
9186 .context("handling lsp ext clear flycheck")?;
9187
9188 Ok(proto::Ack {})
9189 }
9190
9191 pub fn disk_based_diagnostics_started(
9192 &mut self,
9193 language_server_id: LanguageServerId,
9194 cx: &mut Context<Self>,
9195 ) {
9196 if let Some(language_server_status) =
9197 self.language_server_statuses.get_mut(&language_server_id)
9198 {
9199 language_server_status.has_pending_diagnostic_updates = true;
9200 }
9201
9202 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9203 cx.emit(LspStoreEvent::LanguageServerUpdate {
9204 language_server_id,
9205 name: self
9206 .language_server_adapter_for_id(language_server_id)
9207 .map(|adapter| adapter.name()),
9208 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9209 Default::default(),
9210 ),
9211 })
9212 }
9213
9214 pub fn disk_based_diagnostics_finished(
9215 &mut self,
9216 language_server_id: LanguageServerId,
9217 cx: &mut Context<Self>,
9218 ) {
9219 if let Some(language_server_status) =
9220 self.language_server_statuses.get_mut(&language_server_id)
9221 {
9222 language_server_status.has_pending_diagnostic_updates = false;
9223 }
9224
9225 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9226 cx.emit(LspStoreEvent::LanguageServerUpdate {
9227 language_server_id,
9228 name: self
9229 .language_server_adapter_for_id(language_server_id)
9230 .map(|adapter| adapter.name()),
9231 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9232 Default::default(),
9233 ),
9234 })
9235 }
9236
9237 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9238 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9239 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9240 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9241 // the language server might take some time to publish diagnostics.
9242 fn simulate_disk_based_diagnostics_events_if_needed(
9243 &mut self,
9244 language_server_id: LanguageServerId,
9245 cx: &mut Context<Self>,
9246 ) {
9247 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9248
9249 let Some(LanguageServerState::Running {
9250 simulate_disk_based_diagnostics_completion,
9251 adapter,
9252 ..
9253 }) = self
9254 .as_local_mut()
9255 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9256 else {
9257 return;
9258 };
9259
9260 if adapter.disk_based_diagnostics_progress_token.is_some() {
9261 return;
9262 }
9263
9264 let prev_task =
9265 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9266 cx.background_executor()
9267 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9268 .await;
9269
9270 this.update(cx, |this, cx| {
9271 this.disk_based_diagnostics_finished(language_server_id, cx);
9272
9273 if let Some(LanguageServerState::Running {
9274 simulate_disk_based_diagnostics_completion,
9275 ..
9276 }) = this.as_local_mut().and_then(|local_store| {
9277 local_store.language_servers.get_mut(&language_server_id)
9278 }) {
9279 *simulate_disk_based_diagnostics_completion = None;
9280 }
9281 })
9282 .ok();
9283 }));
9284
9285 if prev_task.is_none() {
9286 self.disk_based_diagnostics_started(language_server_id, cx);
9287 }
9288 }
9289
9290 pub fn language_server_statuses(
9291 &self,
9292 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9293 self.language_server_statuses
9294 .iter()
9295 .map(|(key, value)| (*key, value))
9296 }
9297
9298 pub(super) fn did_rename_entry(
9299 &self,
9300 worktree_id: WorktreeId,
9301 old_path: &Path,
9302 new_path: &Path,
9303 is_dir: bool,
9304 ) {
9305 maybe!({
9306 let local_store = self.as_local()?;
9307
9308 let old_uri = lsp::Uri::from_file_path(old_path)
9309 .ok()
9310 .map(|uri| uri.to_string())?;
9311 let new_uri = lsp::Uri::from_file_path(new_path)
9312 .ok()
9313 .map(|uri| uri.to_string())?;
9314
9315 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9316 let Some(filter) = local_store
9317 .language_server_paths_watched_for_rename
9318 .get(&language_server.server_id())
9319 else {
9320 continue;
9321 };
9322
9323 if filter.should_send_did_rename(&old_uri, is_dir) {
9324 language_server
9325 .notify::<DidRenameFiles>(RenameFilesParams {
9326 files: vec![FileRename {
9327 old_uri: old_uri.clone(),
9328 new_uri: new_uri.clone(),
9329 }],
9330 })
9331 .ok();
9332 }
9333 }
9334 Some(())
9335 });
9336 }
9337
9338 pub(super) fn will_rename_entry(
9339 this: WeakEntity<Self>,
9340 worktree_id: WorktreeId,
9341 old_path: &Path,
9342 new_path: &Path,
9343 is_dir: bool,
9344 cx: AsyncApp,
9345 ) -> Task<ProjectTransaction> {
9346 let old_uri = lsp::Uri::from_file_path(old_path)
9347 .ok()
9348 .map(|uri| uri.to_string());
9349 let new_uri = lsp::Uri::from_file_path(new_path)
9350 .ok()
9351 .map(|uri| uri.to_string());
9352 cx.spawn(async move |cx| {
9353 let mut tasks = vec![];
9354 this.update(cx, |this, cx| {
9355 let local_store = this.as_local()?;
9356 let old_uri = old_uri?;
9357 let new_uri = new_uri?;
9358 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9359 let Some(filter) = local_store
9360 .language_server_paths_watched_for_rename
9361 .get(&language_server.server_id())
9362 else {
9363 continue;
9364 };
9365
9366 if filter.should_send_will_rename(&old_uri, is_dir) {
9367 let apply_edit = cx.spawn({
9368 let old_uri = old_uri.clone();
9369 let new_uri = new_uri.clone();
9370 let language_server = language_server.clone();
9371 async move |this, cx| {
9372 let edit = language_server
9373 .request::<WillRenameFiles>(RenameFilesParams {
9374 files: vec![FileRename { old_uri, new_uri }],
9375 })
9376 .await
9377 .into_response()
9378 .context("will rename files")
9379 .log_err()
9380 .flatten()?;
9381
9382 let transaction = LocalLspStore::deserialize_workspace_edit(
9383 this.upgrade()?,
9384 edit,
9385 false,
9386 language_server.clone(),
9387 cx,
9388 )
9389 .await
9390 .ok()?;
9391 Some(transaction)
9392 }
9393 });
9394 tasks.push(apply_edit);
9395 }
9396 }
9397 Some(())
9398 })
9399 .ok()
9400 .flatten();
9401 let mut merged_transaction = ProjectTransaction::default();
9402 for task in tasks {
9403 // Await on tasks sequentially so that the order of application of edits is deterministic
9404 // (at least with regards to the order of registration of language servers)
9405 if let Some(transaction) = task.await {
9406 for (buffer, buffer_transaction) in transaction.0 {
9407 merged_transaction.0.insert(buffer, buffer_transaction);
9408 }
9409 }
9410 }
9411 merged_transaction
9412 })
9413 }
9414
9415 fn lsp_notify_abs_paths_changed(
9416 &mut self,
9417 server_id: LanguageServerId,
9418 changes: Vec<PathEvent>,
9419 ) {
9420 maybe!({
9421 let server = self.language_server_for_id(server_id)?;
9422 let changes = changes
9423 .into_iter()
9424 .filter_map(|event| {
9425 let typ = match event.kind? {
9426 PathEventKind::Created => lsp::FileChangeType::CREATED,
9427 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9428 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9429 };
9430 Some(lsp::FileEvent {
9431 uri: file_path_to_lsp_url(&event.path).log_err()?,
9432 typ,
9433 })
9434 })
9435 .collect::<Vec<_>>();
9436 if !changes.is_empty() {
9437 server
9438 .notify::<lsp::notification::DidChangeWatchedFiles>(
9439 lsp::DidChangeWatchedFilesParams { changes },
9440 )
9441 .ok();
9442 }
9443 Some(())
9444 });
9445 }
9446
9447 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9448 self.as_local()?.language_server_for_id(id)
9449 }
9450
9451 fn on_lsp_progress(
9452 &mut self,
9453 progress_params: lsp::ProgressParams,
9454 language_server_id: LanguageServerId,
9455 disk_based_diagnostics_progress_token: Option<String>,
9456 cx: &mut Context<Self>,
9457 ) {
9458 match progress_params.value {
9459 lsp::ProgressParamsValue::WorkDone(progress) => {
9460 self.handle_work_done_progress(
9461 progress,
9462 language_server_id,
9463 disk_based_diagnostics_progress_token,
9464 ProgressToken::from_lsp(progress_params.token),
9465 cx,
9466 );
9467 }
9468 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9469 let identifier = match progress_params.token {
9470 lsp::NumberOrString::Number(_) => None,
9471 lsp::NumberOrString::String(token) => token
9472 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9473 .map(|(_, id)| id.to_owned()),
9474 };
9475 if let Some(LanguageServerState::Running {
9476 workspace_diagnostics_refresh_tasks,
9477 ..
9478 }) = self
9479 .as_local_mut()
9480 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9481 && let Some(workspace_diagnostics) =
9482 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9483 {
9484 workspace_diagnostics.progress_tx.try_send(()).ok();
9485 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9486 }
9487 }
9488 }
9489 }
9490
9491 fn handle_work_done_progress(
9492 &mut self,
9493 progress: lsp::WorkDoneProgress,
9494 language_server_id: LanguageServerId,
9495 disk_based_diagnostics_progress_token: Option<String>,
9496 token: ProgressToken,
9497 cx: &mut Context<Self>,
9498 ) {
9499 let language_server_status =
9500 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9501 status
9502 } else {
9503 return;
9504 };
9505
9506 if !language_server_status.progress_tokens.contains(&token) {
9507 return;
9508 }
9509
9510 let is_disk_based_diagnostics_progress =
9511 if let (Some(disk_based_token), ProgressToken::String(token)) =
9512 (&disk_based_diagnostics_progress_token, &token)
9513 {
9514 token.starts_with(disk_based_token)
9515 } else {
9516 false
9517 };
9518
9519 match progress {
9520 lsp::WorkDoneProgress::Begin(report) => {
9521 if is_disk_based_diagnostics_progress {
9522 self.disk_based_diagnostics_started(language_server_id, cx);
9523 }
9524 self.on_lsp_work_start(
9525 language_server_id,
9526 token.clone(),
9527 LanguageServerProgress {
9528 title: Some(report.title),
9529 is_disk_based_diagnostics_progress,
9530 is_cancellable: report.cancellable.unwrap_or(false),
9531 message: report.message.clone(),
9532 percentage: report.percentage.map(|p| p as usize),
9533 last_update_at: cx.background_executor().now(),
9534 },
9535 cx,
9536 );
9537 }
9538 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9539 language_server_id,
9540 token,
9541 LanguageServerProgress {
9542 title: None,
9543 is_disk_based_diagnostics_progress,
9544 is_cancellable: report.cancellable.unwrap_or(false),
9545 message: report.message,
9546 percentage: report.percentage.map(|p| p as usize),
9547 last_update_at: cx.background_executor().now(),
9548 },
9549 cx,
9550 ),
9551 lsp::WorkDoneProgress::End(_) => {
9552 language_server_status.progress_tokens.remove(&token);
9553 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9554 if is_disk_based_diagnostics_progress {
9555 self.disk_based_diagnostics_finished(language_server_id, cx);
9556 }
9557 }
9558 }
9559 }
9560
9561 fn on_lsp_work_start(
9562 &mut self,
9563 language_server_id: LanguageServerId,
9564 token: ProgressToken,
9565 progress: LanguageServerProgress,
9566 cx: &mut Context<Self>,
9567 ) {
9568 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9569 status.pending_work.insert(token.clone(), progress.clone());
9570 cx.notify();
9571 }
9572 cx.emit(LspStoreEvent::LanguageServerUpdate {
9573 language_server_id,
9574 name: self
9575 .language_server_adapter_for_id(language_server_id)
9576 .map(|adapter| adapter.name()),
9577 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9578 token: Some(token.to_proto()),
9579 title: progress.title,
9580 message: progress.message,
9581 percentage: progress.percentage.map(|p| p as u32),
9582 is_cancellable: Some(progress.is_cancellable),
9583 }),
9584 })
9585 }
9586
9587 fn on_lsp_work_progress(
9588 &mut self,
9589 language_server_id: LanguageServerId,
9590 token: ProgressToken,
9591 progress: LanguageServerProgress,
9592 cx: &mut Context<Self>,
9593 ) {
9594 let mut did_update = false;
9595 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9596 match status.pending_work.entry(token.clone()) {
9597 btree_map::Entry::Vacant(entry) => {
9598 entry.insert(progress.clone());
9599 did_update = true;
9600 }
9601 btree_map::Entry::Occupied(mut entry) => {
9602 let entry = entry.get_mut();
9603 if (progress.last_update_at - entry.last_update_at)
9604 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9605 {
9606 entry.last_update_at = progress.last_update_at;
9607 if progress.message.is_some() {
9608 entry.message = progress.message.clone();
9609 }
9610 if progress.percentage.is_some() {
9611 entry.percentage = progress.percentage;
9612 }
9613 if progress.is_cancellable != entry.is_cancellable {
9614 entry.is_cancellable = progress.is_cancellable;
9615 }
9616 did_update = true;
9617 }
9618 }
9619 }
9620 }
9621
9622 if did_update {
9623 cx.emit(LspStoreEvent::LanguageServerUpdate {
9624 language_server_id,
9625 name: self
9626 .language_server_adapter_for_id(language_server_id)
9627 .map(|adapter| adapter.name()),
9628 message: proto::update_language_server::Variant::WorkProgress(
9629 proto::LspWorkProgress {
9630 token: Some(token.to_proto()),
9631 message: progress.message,
9632 percentage: progress.percentage.map(|p| p as u32),
9633 is_cancellable: Some(progress.is_cancellable),
9634 },
9635 ),
9636 })
9637 }
9638 }
9639
9640 fn on_lsp_work_end(
9641 &mut self,
9642 language_server_id: LanguageServerId,
9643 token: ProgressToken,
9644 cx: &mut Context<Self>,
9645 ) {
9646 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9647 if let Some(work) = status.pending_work.remove(&token)
9648 && !work.is_disk_based_diagnostics_progress
9649 {
9650 cx.emit(LspStoreEvent::RefreshInlayHints {
9651 server_id: language_server_id,
9652 request_id: None,
9653 });
9654 }
9655 cx.notify();
9656 }
9657
9658 cx.emit(LspStoreEvent::LanguageServerUpdate {
9659 language_server_id,
9660 name: self
9661 .language_server_adapter_for_id(language_server_id)
9662 .map(|adapter| adapter.name()),
9663 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9664 token: Some(token.to_proto()),
9665 }),
9666 })
9667 }
9668
9669 pub async fn handle_resolve_completion_documentation(
9670 this: Entity<Self>,
9671 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9672 mut cx: AsyncApp,
9673 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9674 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9675
9676 let completion = this
9677 .read_with(&cx, |this, cx| {
9678 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9679 let server = this
9680 .language_server_for_id(id)
9681 .with_context(|| format!("No language server {id}"))?;
9682
9683 anyhow::Ok(cx.background_spawn(async move {
9684 let can_resolve = server
9685 .capabilities()
9686 .completion_provider
9687 .as_ref()
9688 .and_then(|options| options.resolve_provider)
9689 .unwrap_or(false);
9690 if can_resolve {
9691 server
9692 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9693 .await
9694 .into_response()
9695 .context("resolve completion item")
9696 } else {
9697 anyhow::Ok(lsp_completion)
9698 }
9699 }))
9700 })??
9701 .await?;
9702
9703 let mut documentation_is_markdown = false;
9704 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9705 let documentation = match completion.documentation {
9706 Some(lsp::Documentation::String(text)) => text,
9707
9708 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9709 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9710 value
9711 }
9712
9713 _ => String::new(),
9714 };
9715
9716 // If we have a new buffer_id, that means we're talking to a new client
9717 // and want to check for new text_edits in the completion too.
9718 let mut old_replace_start = None;
9719 let mut old_replace_end = None;
9720 let mut old_insert_start = None;
9721 let mut old_insert_end = None;
9722 let mut new_text = String::default();
9723 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9724 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9725 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9726 anyhow::Ok(buffer.read(cx).snapshot())
9727 })??;
9728
9729 if let Some(text_edit) = completion.text_edit.as_ref() {
9730 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9731
9732 if let Some(mut edit) = edit {
9733 LineEnding::normalize(&mut edit.new_text);
9734
9735 new_text = edit.new_text;
9736 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9737 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9738 if let Some(insert_range) = edit.insert_range {
9739 old_insert_start = Some(serialize_anchor(&insert_range.start));
9740 old_insert_end = Some(serialize_anchor(&insert_range.end));
9741 }
9742 }
9743 }
9744 }
9745
9746 Ok(proto::ResolveCompletionDocumentationResponse {
9747 documentation,
9748 documentation_is_markdown,
9749 old_replace_start,
9750 old_replace_end,
9751 new_text,
9752 lsp_completion,
9753 old_insert_start,
9754 old_insert_end,
9755 })
9756 }
9757
9758 async fn handle_on_type_formatting(
9759 this: Entity<Self>,
9760 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9761 mut cx: AsyncApp,
9762 ) -> Result<proto::OnTypeFormattingResponse> {
9763 let on_type_formatting = this.update(&mut cx, |this, cx| {
9764 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9765 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9766 let position = envelope
9767 .payload
9768 .position
9769 .and_then(deserialize_anchor)
9770 .context("invalid position")?;
9771 anyhow::Ok(this.apply_on_type_formatting(
9772 buffer,
9773 position,
9774 envelope.payload.trigger.clone(),
9775 cx,
9776 ))
9777 })??;
9778
9779 let transaction = on_type_formatting
9780 .await?
9781 .as_ref()
9782 .map(language::proto::serialize_transaction);
9783 Ok(proto::OnTypeFormattingResponse { transaction })
9784 }
9785
9786 async fn handle_refresh_inlay_hints(
9787 lsp_store: Entity<Self>,
9788 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9789 mut cx: AsyncApp,
9790 ) -> Result<proto::Ack> {
9791 lsp_store.update(&mut cx, |_, cx| {
9792 cx.emit(LspStoreEvent::RefreshInlayHints {
9793 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9794 request_id: envelope.payload.request_id.map(|id| id as usize),
9795 });
9796 })?;
9797 Ok(proto::Ack {})
9798 }
9799
9800 async fn handle_pull_workspace_diagnostics(
9801 lsp_store: Entity<Self>,
9802 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9803 mut cx: AsyncApp,
9804 ) -> Result<proto::Ack> {
9805 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9806 lsp_store.update(&mut cx, |lsp_store, _| {
9807 lsp_store.pull_workspace_diagnostics(server_id);
9808 })?;
9809 Ok(proto::Ack {})
9810 }
9811
9812 async fn handle_get_color_presentation(
9813 lsp_store: Entity<Self>,
9814 envelope: TypedEnvelope<proto::GetColorPresentation>,
9815 mut cx: AsyncApp,
9816 ) -> Result<proto::GetColorPresentationResponse> {
9817 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9818 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9819 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9820 })??;
9821
9822 let color = envelope
9823 .payload
9824 .color
9825 .context("invalid color resolve request")?;
9826 let start = color
9827 .lsp_range_start
9828 .context("invalid color resolve request")?;
9829 let end = color
9830 .lsp_range_end
9831 .context("invalid color resolve request")?;
9832
9833 let color = DocumentColor {
9834 lsp_range: lsp::Range {
9835 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9836 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9837 },
9838 color: lsp::Color {
9839 red: color.red,
9840 green: color.green,
9841 blue: color.blue,
9842 alpha: color.alpha,
9843 },
9844 resolved: false,
9845 color_presentations: Vec::new(),
9846 };
9847 let resolved_color = lsp_store
9848 .update(&mut cx, |lsp_store, cx| {
9849 lsp_store.resolve_color_presentation(
9850 color,
9851 buffer.clone(),
9852 LanguageServerId(envelope.payload.server_id as usize),
9853 cx,
9854 )
9855 })?
9856 .await
9857 .context("resolving color presentation")?;
9858
9859 Ok(proto::GetColorPresentationResponse {
9860 presentations: resolved_color
9861 .color_presentations
9862 .into_iter()
9863 .map(|presentation| proto::ColorPresentation {
9864 label: presentation.label.to_string(),
9865 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9866 additional_text_edits: presentation
9867 .additional_text_edits
9868 .into_iter()
9869 .map(serialize_lsp_edit)
9870 .collect(),
9871 })
9872 .collect(),
9873 })
9874 }
9875
9876 async fn handle_resolve_inlay_hint(
9877 lsp_store: Entity<Self>,
9878 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9879 mut cx: AsyncApp,
9880 ) -> Result<proto::ResolveInlayHintResponse> {
9881 let proto_hint = envelope
9882 .payload
9883 .hint
9884 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9885 let hint = InlayHints::proto_to_project_hint(proto_hint)
9886 .context("resolved proto inlay hint conversion")?;
9887 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9888 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9889 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9890 })??;
9891 let response_hint = lsp_store
9892 .update(&mut cx, |lsp_store, cx| {
9893 lsp_store.resolve_inlay_hint(
9894 hint,
9895 buffer,
9896 LanguageServerId(envelope.payload.language_server_id as usize),
9897 cx,
9898 )
9899 })?
9900 .await
9901 .context("inlay hints fetch")?;
9902 Ok(proto::ResolveInlayHintResponse {
9903 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9904 })
9905 }
9906
9907 async fn handle_refresh_code_lens(
9908 this: Entity<Self>,
9909 _: TypedEnvelope<proto::RefreshCodeLens>,
9910 mut cx: AsyncApp,
9911 ) -> Result<proto::Ack> {
9912 this.update(&mut cx, |_, cx| {
9913 cx.emit(LspStoreEvent::RefreshCodeLens);
9914 })?;
9915 Ok(proto::Ack {})
9916 }
9917
9918 async fn handle_open_buffer_for_symbol(
9919 this: Entity<Self>,
9920 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9921 mut cx: AsyncApp,
9922 ) -> Result<proto::OpenBufferForSymbolResponse> {
9923 let peer_id = envelope.original_sender_id().unwrap_or_default();
9924 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9925 let symbol = Self::deserialize_symbol(symbol)?;
9926 this.read_with(&cx, |this, _| {
9927 if let SymbolLocation::OutsideProject {
9928 abs_path,
9929 signature,
9930 } = &symbol.path
9931 {
9932 let new_signature = this.symbol_signature(&abs_path);
9933 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9934 }
9935 Ok(())
9936 })??;
9937 let buffer = this
9938 .update(&mut cx, |this, cx| {
9939 this.open_buffer_for_symbol(
9940 &Symbol {
9941 language_server_name: symbol.language_server_name,
9942 source_worktree_id: symbol.source_worktree_id,
9943 source_language_server_id: symbol.source_language_server_id,
9944 path: symbol.path,
9945 name: symbol.name,
9946 kind: symbol.kind,
9947 range: symbol.range,
9948 label: CodeLabel::default(),
9949 },
9950 cx,
9951 )
9952 })?
9953 .await?;
9954
9955 this.update(&mut cx, |this, cx| {
9956 let is_private = buffer
9957 .read(cx)
9958 .file()
9959 .map(|f| f.is_private())
9960 .unwrap_or_default();
9961 if is_private {
9962 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9963 } else {
9964 this.buffer_store
9965 .update(cx, |buffer_store, cx| {
9966 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9967 })
9968 .detach_and_log_err(cx);
9969 let buffer_id = buffer.read(cx).remote_id().to_proto();
9970 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9971 }
9972 })?
9973 }
9974
9975 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9976 let mut hasher = Sha256::new();
9977 hasher.update(abs_path.to_string_lossy().as_bytes());
9978 hasher.update(self.nonce.to_be_bytes());
9979 hasher.finalize().as_slice().try_into().unwrap()
9980 }
9981
9982 pub async fn handle_get_project_symbols(
9983 this: Entity<Self>,
9984 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9985 mut cx: AsyncApp,
9986 ) -> Result<proto::GetProjectSymbolsResponse> {
9987 let symbols = this
9988 .update(&mut cx, |this, cx| {
9989 this.symbols(&envelope.payload.query, cx)
9990 })?
9991 .await?;
9992
9993 Ok(proto::GetProjectSymbolsResponse {
9994 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9995 })
9996 }
9997
9998 pub async fn handle_restart_language_servers(
9999 this: Entity<Self>,
10000 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10001 mut cx: AsyncApp,
10002 ) -> Result<proto::Ack> {
10003 this.update(&mut cx, |lsp_store, cx| {
10004 let buffers =
10005 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10006 lsp_store.restart_language_servers_for_buffers(
10007 buffers,
10008 envelope
10009 .payload
10010 .only_servers
10011 .into_iter()
10012 .filter_map(|selector| {
10013 Some(match selector.selector? {
10014 proto::language_server_selector::Selector::ServerId(server_id) => {
10015 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10016 }
10017 proto::language_server_selector::Selector::Name(name) => {
10018 LanguageServerSelector::Name(LanguageServerName(
10019 SharedString::from(name),
10020 ))
10021 }
10022 })
10023 })
10024 .collect(),
10025 cx,
10026 );
10027 })?;
10028
10029 Ok(proto::Ack {})
10030 }
10031
10032 pub async fn handle_stop_language_servers(
10033 lsp_store: Entity<Self>,
10034 envelope: TypedEnvelope<proto::StopLanguageServers>,
10035 mut cx: AsyncApp,
10036 ) -> Result<proto::Ack> {
10037 lsp_store.update(&mut cx, |lsp_store, cx| {
10038 if envelope.payload.all
10039 && envelope.payload.also_servers.is_empty()
10040 && envelope.payload.buffer_ids.is_empty()
10041 {
10042 lsp_store.stop_all_language_servers(cx);
10043 } else {
10044 let buffers =
10045 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10046 lsp_store
10047 .stop_language_servers_for_buffers(
10048 buffers,
10049 envelope
10050 .payload
10051 .also_servers
10052 .into_iter()
10053 .filter_map(|selector| {
10054 Some(match selector.selector? {
10055 proto::language_server_selector::Selector::ServerId(
10056 server_id,
10057 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10058 server_id,
10059 )),
10060 proto::language_server_selector::Selector::Name(name) => {
10061 LanguageServerSelector::Name(LanguageServerName(
10062 SharedString::from(name),
10063 ))
10064 }
10065 })
10066 })
10067 .collect(),
10068 cx,
10069 )
10070 .detach_and_log_err(cx);
10071 }
10072 })?;
10073
10074 Ok(proto::Ack {})
10075 }
10076
10077 pub async fn handle_cancel_language_server_work(
10078 lsp_store: Entity<Self>,
10079 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10080 mut cx: AsyncApp,
10081 ) -> Result<proto::Ack> {
10082 lsp_store.update(&mut cx, |lsp_store, cx| {
10083 if let Some(work) = envelope.payload.work {
10084 match work {
10085 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10086 let buffers =
10087 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10088 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10089 }
10090 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10091 let server_id = LanguageServerId::from_proto(work.language_server_id);
10092 let token = work
10093 .token
10094 .map(|token| {
10095 ProgressToken::from_proto(token)
10096 .context("invalid work progress token")
10097 })
10098 .transpose()?;
10099 lsp_store.cancel_language_server_work(server_id, token, cx);
10100 }
10101 }
10102 }
10103 anyhow::Ok(())
10104 })??;
10105
10106 Ok(proto::Ack {})
10107 }
10108
10109 fn buffer_ids_to_buffers(
10110 &mut self,
10111 buffer_ids: impl Iterator<Item = u64>,
10112 cx: &mut Context<Self>,
10113 ) -> Vec<Entity<Buffer>> {
10114 buffer_ids
10115 .into_iter()
10116 .flat_map(|buffer_id| {
10117 self.buffer_store
10118 .read(cx)
10119 .get(BufferId::new(buffer_id).log_err()?)
10120 })
10121 .collect::<Vec<_>>()
10122 }
10123
10124 async fn handle_apply_additional_edits_for_completion(
10125 this: Entity<Self>,
10126 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10127 mut cx: AsyncApp,
10128 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10129 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10130 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10131 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10132 let completion = Self::deserialize_completion(
10133 envelope.payload.completion.context("invalid completion")?,
10134 )?;
10135 anyhow::Ok((buffer, completion))
10136 })??;
10137
10138 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10139 this.apply_additional_edits_for_completion(
10140 buffer,
10141 Rc::new(RefCell::new(Box::new([Completion {
10142 replace_range: completion.replace_range,
10143 new_text: completion.new_text,
10144 source: completion.source,
10145 documentation: None,
10146 label: CodeLabel::default(),
10147 insert_text_mode: None,
10148 icon_path: None,
10149 confirm: None,
10150 }]))),
10151 0,
10152 false,
10153 cx,
10154 )
10155 })?;
10156
10157 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10158 transaction: apply_additional_edits
10159 .await?
10160 .as_ref()
10161 .map(language::proto::serialize_transaction),
10162 })
10163 }
10164
10165 pub fn last_formatting_failure(&self) -> Option<&str> {
10166 self.last_formatting_failure.as_deref()
10167 }
10168
10169 pub fn reset_last_formatting_failure(&mut self) {
10170 self.last_formatting_failure = None;
10171 }
10172
10173 pub fn environment_for_buffer(
10174 &self,
10175 buffer: &Entity<Buffer>,
10176 cx: &mut Context<Self>,
10177 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10178 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10179 environment.update(cx, |env, cx| {
10180 env.buffer_environment(buffer, &self.worktree_store, cx)
10181 })
10182 } else {
10183 Task::ready(None).shared()
10184 }
10185 }
10186
10187 pub fn format(
10188 &mut self,
10189 buffers: HashSet<Entity<Buffer>>,
10190 target: LspFormatTarget,
10191 push_to_history: bool,
10192 trigger: FormatTrigger,
10193 cx: &mut Context<Self>,
10194 ) -> Task<anyhow::Result<ProjectTransaction>> {
10195 let logger = zlog::scoped!("format");
10196 if self.as_local().is_some() {
10197 zlog::trace!(logger => "Formatting locally");
10198 let logger = zlog::scoped!(logger => "local");
10199 let buffers = buffers
10200 .into_iter()
10201 .map(|buffer_handle| {
10202 let buffer = buffer_handle.read(cx);
10203 let buffer_abs_path = File::from_dyn(buffer.file())
10204 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10205
10206 (buffer_handle, buffer_abs_path, buffer.remote_id())
10207 })
10208 .collect::<Vec<_>>();
10209
10210 cx.spawn(async move |lsp_store, cx| {
10211 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10212
10213 for (handle, abs_path, id) in buffers {
10214 let env = lsp_store
10215 .update(cx, |lsp_store, cx| {
10216 lsp_store.environment_for_buffer(&handle, cx)
10217 })?
10218 .await;
10219
10220 let ranges = match &target {
10221 LspFormatTarget::Buffers => None,
10222 LspFormatTarget::Ranges(ranges) => {
10223 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10224 }
10225 };
10226
10227 formattable_buffers.push(FormattableBuffer {
10228 handle,
10229 abs_path,
10230 env,
10231 ranges,
10232 });
10233 }
10234 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10235
10236 let format_timer = zlog::time!(logger => "Formatting buffers");
10237 let result = LocalLspStore::format_locally(
10238 lsp_store.clone(),
10239 formattable_buffers,
10240 push_to_history,
10241 trigger,
10242 logger,
10243 cx,
10244 )
10245 .await;
10246 format_timer.end();
10247
10248 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10249
10250 lsp_store.update(cx, |lsp_store, _| {
10251 lsp_store.update_last_formatting_failure(&result);
10252 })?;
10253
10254 result
10255 })
10256 } else if let Some((client, project_id)) = self.upstream_client() {
10257 zlog::trace!(logger => "Formatting remotely");
10258 let logger = zlog::scoped!(logger => "remote");
10259 // Don't support formatting ranges via remote
10260 match target {
10261 LspFormatTarget::Buffers => {}
10262 LspFormatTarget::Ranges(_) => {
10263 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10264 return Task::ready(Ok(ProjectTransaction::default()));
10265 }
10266 }
10267
10268 let buffer_store = self.buffer_store();
10269 cx.spawn(async move |lsp_store, cx| {
10270 zlog::trace!(logger => "Sending remote format request");
10271 let request_timer = zlog::time!(logger => "remote format request");
10272 let result = client
10273 .request(proto::FormatBuffers {
10274 project_id,
10275 trigger: trigger as i32,
10276 buffer_ids: buffers
10277 .iter()
10278 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10279 .collect::<Result<_>>()?,
10280 })
10281 .await
10282 .and_then(|result| result.transaction.context("missing transaction"));
10283 request_timer.end();
10284
10285 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10286
10287 lsp_store.update(cx, |lsp_store, _| {
10288 lsp_store.update_last_formatting_failure(&result);
10289 })?;
10290
10291 let transaction_response = result?;
10292 let _timer = zlog::time!(logger => "deserializing project transaction");
10293 buffer_store
10294 .update(cx, |buffer_store, cx| {
10295 buffer_store.deserialize_project_transaction(
10296 transaction_response,
10297 push_to_history,
10298 cx,
10299 )
10300 })?
10301 .await
10302 })
10303 } else {
10304 zlog::trace!(logger => "Not formatting");
10305 Task::ready(Ok(ProjectTransaction::default()))
10306 }
10307 }
10308
10309 async fn handle_format_buffers(
10310 this: Entity<Self>,
10311 envelope: TypedEnvelope<proto::FormatBuffers>,
10312 mut cx: AsyncApp,
10313 ) -> Result<proto::FormatBuffersResponse> {
10314 let sender_id = envelope.original_sender_id().unwrap_or_default();
10315 let format = this.update(&mut cx, |this, cx| {
10316 let mut buffers = HashSet::default();
10317 for buffer_id in &envelope.payload.buffer_ids {
10318 let buffer_id = BufferId::new(*buffer_id)?;
10319 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10320 }
10321 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10322 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10323 })??;
10324
10325 let project_transaction = format.await?;
10326 let project_transaction = this.update(&mut cx, |this, cx| {
10327 this.buffer_store.update(cx, |buffer_store, cx| {
10328 buffer_store.serialize_project_transaction_for_peer(
10329 project_transaction,
10330 sender_id,
10331 cx,
10332 )
10333 })
10334 })?;
10335 Ok(proto::FormatBuffersResponse {
10336 transaction: Some(project_transaction),
10337 })
10338 }
10339
10340 async fn handle_apply_code_action_kind(
10341 this: Entity<Self>,
10342 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10343 mut cx: AsyncApp,
10344 ) -> Result<proto::ApplyCodeActionKindResponse> {
10345 let sender_id = envelope.original_sender_id().unwrap_or_default();
10346 let format = this.update(&mut cx, |this, cx| {
10347 let mut buffers = HashSet::default();
10348 for buffer_id in &envelope.payload.buffer_ids {
10349 let buffer_id = BufferId::new(*buffer_id)?;
10350 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10351 }
10352 let kind = match envelope.payload.kind.as_str() {
10353 "" => CodeActionKind::EMPTY,
10354 "quickfix" => CodeActionKind::QUICKFIX,
10355 "refactor" => CodeActionKind::REFACTOR,
10356 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10357 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10358 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10359 "source" => CodeActionKind::SOURCE,
10360 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10361 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10362 _ => anyhow::bail!(
10363 "Invalid code action kind {}",
10364 envelope.payload.kind.as_str()
10365 ),
10366 };
10367 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10368 })??;
10369
10370 let project_transaction = format.await?;
10371 let project_transaction = this.update(&mut cx, |this, cx| {
10372 this.buffer_store.update(cx, |buffer_store, cx| {
10373 buffer_store.serialize_project_transaction_for_peer(
10374 project_transaction,
10375 sender_id,
10376 cx,
10377 )
10378 })
10379 })?;
10380 Ok(proto::ApplyCodeActionKindResponse {
10381 transaction: Some(project_transaction),
10382 })
10383 }
10384
10385 async fn shutdown_language_server(
10386 server_state: Option<LanguageServerState>,
10387 name: LanguageServerName,
10388 cx: &mut AsyncApp,
10389 ) {
10390 let server = match server_state {
10391 Some(LanguageServerState::Starting { startup, .. }) => {
10392 let mut timer = cx
10393 .background_executor()
10394 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10395 .fuse();
10396
10397 select! {
10398 server = startup.fuse() => server,
10399 () = timer => {
10400 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10401 None
10402 },
10403 }
10404 }
10405
10406 Some(LanguageServerState::Running { server, .. }) => Some(server),
10407
10408 None => None,
10409 };
10410
10411 if let Some(server) = server
10412 && let Some(shutdown) = server.shutdown()
10413 {
10414 shutdown.await;
10415 }
10416 }
10417
10418 // Returns a list of all of the worktrees which no longer have a language server and the root path
10419 // for the stopped server
10420 fn stop_local_language_server(
10421 &mut self,
10422 server_id: LanguageServerId,
10423 cx: &mut Context<Self>,
10424 ) -> Task<()> {
10425 let local = match &mut self.mode {
10426 LspStoreMode::Local(local) => local,
10427 _ => {
10428 return Task::ready(());
10429 }
10430 };
10431
10432 // Remove this server ID from all entries in the given worktree.
10433 local
10434 .language_server_ids
10435 .retain(|_, state| state.id != server_id);
10436 self.buffer_store.update(cx, |buffer_store, cx| {
10437 for buffer in buffer_store.buffers() {
10438 buffer.update(cx, |buffer, cx| {
10439 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10440 buffer.set_completion_triggers(server_id, Default::default(), cx);
10441 });
10442 }
10443 });
10444
10445 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10446 summaries.retain(|path, summaries_by_server_id| {
10447 if summaries_by_server_id.remove(&server_id).is_some() {
10448 if let Some((client, project_id)) = self.downstream_client.clone() {
10449 client
10450 .send(proto::UpdateDiagnosticSummary {
10451 project_id,
10452 worktree_id: worktree_id.to_proto(),
10453 summary: Some(proto::DiagnosticSummary {
10454 path: path.as_ref().to_proto(),
10455 language_server_id: server_id.0 as u64,
10456 error_count: 0,
10457 warning_count: 0,
10458 }),
10459 more_summaries: Vec::new(),
10460 })
10461 .log_err();
10462 }
10463 !summaries_by_server_id.is_empty()
10464 } else {
10465 true
10466 }
10467 });
10468 }
10469
10470 let local = self.as_local_mut().unwrap();
10471 for diagnostics in local.diagnostics.values_mut() {
10472 diagnostics.retain(|_, diagnostics_by_server_id| {
10473 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10474 diagnostics_by_server_id.remove(ix);
10475 !diagnostics_by_server_id.is_empty()
10476 } else {
10477 true
10478 }
10479 });
10480 }
10481 local.language_server_watched_paths.remove(&server_id);
10482
10483 let server_state = local.language_servers.remove(&server_id);
10484 self.cleanup_lsp_data(server_id);
10485 let name = self
10486 .language_server_statuses
10487 .remove(&server_id)
10488 .map(|status| status.name)
10489 .or_else(|| {
10490 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10491 Some(adapter.name())
10492 } else {
10493 None
10494 }
10495 });
10496
10497 if let Some(name) = name {
10498 log::info!("stopping language server {name}");
10499 self.languages
10500 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10501 cx.notify();
10502
10503 return cx.spawn(async move |lsp_store, cx| {
10504 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10505 lsp_store
10506 .update(cx, |lsp_store, cx| {
10507 lsp_store
10508 .languages
10509 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10510 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10511 cx.notify();
10512 })
10513 .ok();
10514 });
10515 }
10516
10517 if server_state.is_some() {
10518 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10519 }
10520 Task::ready(())
10521 }
10522
10523 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10524 if let Some((client, project_id)) = self.upstream_client() {
10525 let request = client.request(proto::StopLanguageServers {
10526 project_id,
10527 buffer_ids: Vec::new(),
10528 also_servers: Vec::new(),
10529 all: true,
10530 });
10531 cx.background_spawn(request).detach_and_log_err(cx);
10532 } else {
10533 let Some(local) = self.as_local_mut() else {
10534 return;
10535 };
10536 let language_servers_to_stop = local
10537 .language_server_ids
10538 .values()
10539 .map(|state| state.id)
10540 .collect();
10541 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10542 let tasks = language_servers_to_stop
10543 .into_iter()
10544 .map(|server| self.stop_local_language_server(server, cx))
10545 .collect::<Vec<_>>();
10546 cx.background_spawn(async move {
10547 futures::future::join_all(tasks).await;
10548 })
10549 .detach();
10550 }
10551 }
10552
10553 pub fn restart_language_servers_for_buffers(
10554 &mut self,
10555 buffers: Vec<Entity<Buffer>>,
10556 only_restart_servers: HashSet<LanguageServerSelector>,
10557 cx: &mut Context<Self>,
10558 ) {
10559 if let Some((client, project_id)) = self.upstream_client() {
10560 let request = client.request(proto::RestartLanguageServers {
10561 project_id,
10562 buffer_ids: buffers
10563 .into_iter()
10564 .map(|b| b.read(cx).remote_id().to_proto())
10565 .collect(),
10566 only_servers: only_restart_servers
10567 .into_iter()
10568 .map(|selector| {
10569 let selector = match selector {
10570 LanguageServerSelector::Id(language_server_id) => {
10571 proto::language_server_selector::Selector::ServerId(
10572 language_server_id.to_proto(),
10573 )
10574 }
10575 LanguageServerSelector::Name(language_server_name) => {
10576 proto::language_server_selector::Selector::Name(
10577 language_server_name.to_string(),
10578 )
10579 }
10580 };
10581 proto::LanguageServerSelector {
10582 selector: Some(selector),
10583 }
10584 })
10585 .collect(),
10586 all: false,
10587 });
10588 cx.background_spawn(request).detach_and_log_err(cx);
10589 } else {
10590 let stop_task = if only_restart_servers.is_empty() {
10591 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10592 } else {
10593 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10594 };
10595 cx.spawn(async move |lsp_store, cx| {
10596 stop_task.await;
10597 lsp_store
10598 .update(cx, |lsp_store, cx| {
10599 for buffer in buffers {
10600 lsp_store.register_buffer_with_language_servers(
10601 &buffer,
10602 only_restart_servers.clone(),
10603 true,
10604 cx,
10605 );
10606 }
10607 })
10608 .ok()
10609 })
10610 .detach();
10611 }
10612 }
10613
10614 pub fn stop_language_servers_for_buffers(
10615 &mut self,
10616 buffers: Vec<Entity<Buffer>>,
10617 also_stop_servers: HashSet<LanguageServerSelector>,
10618 cx: &mut Context<Self>,
10619 ) -> Task<Result<()>> {
10620 if let Some((client, project_id)) = self.upstream_client() {
10621 let request = client.request(proto::StopLanguageServers {
10622 project_id,
10623 buffer_ids: buffers
10624 .into_iter()
10625 .map(|b| b.read(cx).remote_id().to_proto())
10626 .collect(),
10627 also_servers: also_stop_servers
10628 .into_iter()
10629 .map(|selector| {
10630 let selector = match selector {
10631 LanguageServerSelector::Id(language_server_id) => {
10632 proto::language_server_selector::Selector::ServerId(
10633 language_server_id.to_proto(),
10634 )
10635 }
10636 LanguageServerSelector::Name(language_server_name) => {
10637 proto::language_server_selector::Selector::Name(
10638 language_server_name.to_string(),
10639 )
10640 }
10641 };
10642 proto::LanguageServerSelector {
10643 selector: Some(selector),
10644 }
10645 })
10646 .collect(),
10647 all: false,
10648 });
10649 cx.background_spawn(async move {
10650 let _ = request.await?;
10651 Ok(())
10652 })
10653 } else {
10654 let task =
10655 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10656 cx.background_spawn(async move {
10657 task.await;
10658 Ok(())
10659 })
10660 }
10661 }
10662
10663 fn stop_local_language_servers_for_buffers(
10664 &mut self,
10665 buffers: &[Entity<Buffer>],
10666 also_stop_servers: HashSet<LanguageServerSelector>,
10667 cx: &mut Context<Self>,
10668 ) -> Task<()> {
10669 let Some(local) = self.as_local_mut() else {
10670 return Task::ready(());
10671 };
10672 let mut language_server_names_to_stop = BTreeSet::default();
10673 let mut language_servers_to_stop = also_stop_servers
10674 .into_iter()
10675 .flat_map(|selector| match selector {
10676 LanguageServerSelector::Id(id) => Some(id),
10677 LanguageServerSelector::Name(name) => {
10678 language_server_names_to_stop.insert(name);
10679 None
10680 }
10681 })
10682 .collect::<BTreeSet<_>>();
10683
10684 let mut covered_worktrees = HashSet::default();
10685 for buffer in buffers {
10686 buffer.update(cx, |buffer, cx| {
10687 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10688 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10689 && covered_worktrees.insert(worktree_id)
10690 {
10691 language_server_names_to_stop.retain(|name| {
10692 let old_ids_count = language_servers_to_stop.len();
10693 let all_language_servers_with_this_name = local
10694 .language_server_ids
10695 .iter()
10696 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10697 language_servers_to_stop.extend(all_language_servers_with_this_name);
10698 old_ids_count == language_servers_to_stop.len()
10699 });
10700 }
10701 });
10702 }
10703 for name in language_server_names_to_stop {
10704 language_servers_to_stop.extend(
10705 local
10706 .language_server_ids
10707 .iter()
10708 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10709 );
10710 }
10711
10712 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10713 let tasks = language_servers_to_stop
10714 .into_iter()
10715 .map(|server| self.stop_local_language_server(server, cx))
10716 .collect::<Vec<_>>();
10717
10718 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10719 }
10720
10721 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10722 let (worktree, relative_path) =
10723 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10724
10725 let project_path = ProjectPath {
10726 worktree_id: worktree.read(cx).id(),
10727 path: relative_path,
10728 };
10729
10730 Some(
10731 self.buffer_store()
10732 .read(cx)
10733 .get_by_path(&project_path)?
10734 .read(cx),
10735 )
10736 }
10737
10738 #[cfg(any(test, feature = "test-support"))]
10739 pub fn update_diagnostics(
10740 &mut self,
10741 server_id: LanguageServerId,
10742 diagnostics: lsp::PublishDiagnosticsParams,
10743 result_id: Option<String>,
10744 source_kind: DiagnosticSourceKind,
10745 disk_based_sources: &[String],
10746 cx: &mut Context<Self>,
10747 ) -> Result<()> {
10748 self.merge_lsp_diagnostics(
10749 source_kind,
10750 vec![DocumentDiagnosticsUpdate {
10751 diagnostics,
10752 result_id,
10753 server_id,
10754 disk_based_sources: Cow::Borrowed(disk_based_sources),
10755 }],
10756 |_, _, _| false,
10757 cx,
10758 )
10759 }
10760
10761 pub fn merge_lsp_diagnostics(
10762 &mut self,
10763 source_kind: DiagnosticSourceKind,
10764 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10765 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10766 cx: &mut Context<Self>,
10767 ) -> Result<()> {
10768 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10769 let updates = lsp_diagnostics
10770 .into_iter()
10771 .filter_map(|update| {
10772 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10773 Some(DocumentDiagnosticsUpdate {
10774 diagnostics: self.lsp_to_document_diagnostics(
10775 abs_path,
10776 source_kind,
10777 update.server_id,
10778 update.diagnostics,
10779 &update.disk_based_sources,
10780 ),
10781 result_id: update.result_id,
10782 server_id: update.server_id,
10783 disk_based_sources: update.disk_based_sources,
10784 })
10785 })
10786 .collect();
10787 self.merge_diagnostic_entries(updates, merge, cx)?;
10788 Ok(())
10789 }
10790
10791 fn lsp_to_document_diagnostics(
10792 &mut self,
10793 document_abs_path: PathBuf,
10794 source_kind: DiagnosticSourceKind,
10795 server_id: LanguageServerId,
10796 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10797 disk_based_sources: &[String],
10798 ) -> DocumentDiagnostics {
10799 let mut diagnostics = Vec::default();
10800 let mut primary_diagnostic_group_ids = HashMap::default();
10801 let mut sources_by_group_id = HashMap::default();
10802 let mut supporting_diagnostics = HashMap::default();
10803
10804 let adapter = self.language_server_adapter_for_id(server_id);
10805
10806 // Ensure that primary diagnostics are always the most severe
10807 lsp_diagnostics
10808 .diagnostics
10809 .sort_by_key(|item| item.severity);
10810
10811 for diagnostic in &lsp_diagnostics.diagnostics {
10812 let source = diagnostic.source.as_ref();
10813 let range = range_from_lsp(diagnostic.range);
10814 let is_supporting = diagnostic
10815 .related_information
10816 .as_ref()
10817 .is_some_and(|infos| {
10818 infos.iter().any(|info| {
10819 primary_diagnostic_group_ids.contains_key(&(
10820 source,
10821 diagnostic.code.clone(),
10822 range_from_lsp(info.location.range),
10823 ))
10824 })
10825 });
10826
10827 let is_unnecessary = diagnostic
10828 .tags
10829 .as_ref()
10830 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10831
10832 let underline = self
10833 .language_server_adapter_for_id(server_id)
10834 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10835
10836 if is_supporting {
10837 supporting_diagnostics.insert(
10838 (source, diagnostic.code.clone(), range),
10839 (diagnostic.severity, is_unnecessary),
10840 );
10841 } else {
10842 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10843 let is_disk_based =
10844 source.is_some_and(|source| disk_based_sources.contains(source));
10845
10846 sources_by_group_id.insert(group_id, source);
10847 primary_diagnostic_group_ids
10848 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10849
10850 diagnostics.push(DiagnosticEntry {
10851 range,
10852 diagnostic: Diagnostic {
10853 source: diagnostic.source.clone(),
10854 source_kind,
10855 code: diagnostic.code.clone(),
10856 code_description: diagnostic
10857 .code_description
10858 .as_ref()
10859 .and_then(|d| d.href.clone()),
10860 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10861 markdown: adapter.as_ref().and_then(|adapter| {
10862 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10863 }),
10864 message: diagnostic.message.trim().to_string(),
10865 group_id,
10866 is_primary: true,
10867 is_disk_based,
10868 is_unnecessary,
10869 underline,
10870 data: diagnostic.data.clone(),
10871 },
10872 });
10873 if let Some(infos) = &diagnostic.related_information {
10874 for info in infos {
10875 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10876 let range = range_from_lsp(info.location.range);
10877 diagnostics.push(DiagnosticEntry {
10878 range,
10879 diagnostic: Diagnostic {
10880 source: diagnostic.source.clone(),
10881 source_kind,
10882 code: diagnostic.code.clone(),
10883 code_description: diagnostic
10884 .code_description
10885 .as_ref()
10886 .and_then(|d| d.href.clone()),
10887 severity: DiagnosticSeverity::INFORMATION,
10888 markdown: adapter.as_ref().and_then(|adapter| {
10889 adapter.diagnostic_message_to_markdown(&info.message)
10890 }),
10891 message: info.message.trim().to_string(),
10892 group_id,
10893 is_primary: false,
10894 is_disk_based,
10895 is_unnecessary: false,
10896 underline,
10897 data: diagnostic.data.clone(),
10898 },
10899 });
10900 }
10901 }
10902 }
10903 }
10904 }
10905
10906 for entry in &mut diagnostics {
10907 let diagnostic = &mut entry.diagnostic;
10908 if !diagnostic.is_primary {
10909 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10910 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10911 source,
10912 diagnostic.code.clone(),
10913 entry.range.clone(),
10914 )) {
10915 if let Some(severity) = severity {
10916 diagnostic.severity = severity;
10917 }
10918 diagnostic.is_unnecessary = is_unnecessary;
10919 }
10920 }
10921 }
10922
10923 DocumentDiagnostics {
10924 diagnostics,
10925 document_abs_path,
10926 version: lsp_diagnostics.version,
10927 }
10928 }
10929
10930 fn insert_newly_running_language_server(
10931 &mut self,
10932 adapter: Arc<CachedLspAdapter>,
10933 language_server: Arc<LanguageServer>,
10934 server_id: LanguageServerId,
10935 key: LanguageServerSeed,
10936 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10937 cx: &mut Context<Self>,
10938 ) {
10939 let Some(local) = self.as_local_mut() else {
10940 return;
10941 };
10942 // If the language server for this key doesn't match the server id, don't store the
10943 // server. Which will cause it to be dropped, killing the process
10944 if local
10945 .language_server_ids
10946 .get(&key)
10947 .map(|state| state.id != server_id)
10948 .unwrap_or(false)
10949 {
10950 return;
10951 }
10952
10953 // Update language_servers collection with Running variant of LanguageServerState
10954 // indicating that the server is up and running and ready
10955 let workspace_folders = workspace_folders.lock().clone();
10956 language_server.set_workspace_folders(workspace_folders);
10957
10958 let workspace_diagnostics_refresh_tasks = language_server
10959 .capabilities()
10960 .diagnostic_provider
10961 .and_then(|provider| {
10962 local
10963 .language_server_dynamic_registrations
10964 .entry(server_id)
10965 .or_default()
10966 .diagnostics
10967 .entry(None)
10968 .or_insert(provider.clone());
10969 let workspace_refresher =
10970 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10971
10972 Some((None, workspace_refresher))
10973 })
10974 .into_iter()
10975 .collect();
10976 local.language_servers.insert(
10977 server_id,
10978 LanguageServerState::Running {
10979 workspace_diagnostics_refresh_tasks,
10980 adapter: adapter.clone(),
10981 server: language_server.clone(),
10982 simulate_disk_based_diagnostics_completion: None,
10983 },
10984 );
10985 local
10986 .languages
10987 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10988 if let Some(file_ops_caps) = language_server
10989 .capabilities()
10990 .workspace
10991 .as_ref()
10992 .and_then(|ws| ws.file_operations.as_ref())
10993 {
10994 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10995 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10996 if did_rename_caps.or(will_rename_caps).is_some() {
10997 let watcher = RenamePathsWatchedForServer::default()
10998 .with_did_rename_patterns(did_rename_caps)
10999 .with_will_rename_patterns(will_rename_caps);
11000 local
11001 .language_server_paths_watched_for_rename
11002 .insert(server_id, watcher);
11003 }
11004 }
11005
11006 self.language_server_statuses.insert(
11007 server_id,
11008 LanguageServerStatus {
11009 name: language_server.name(),
11010 pending_work: Default::default(),
11011 has_pending_diagnostic_updates: false,
11012 progress_tokens: Default::default(),
11013 worktree: Some(key.worktree_id),
11014 },
11015 );
11016
11017 cx.emit(LspStoreEvent::LanguageServerAdded(
11018 server_id,
11019 language_server.name(),
11020 Some(key.worktree_id),
11021 ));
11022
11023 let server_capabilities = language_server.capabilities();
11024 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11025 downstream_client
11026 .send(proto::StartLanguageServer {
11027 project_id: *project_id,
11028 server: Some(proto::LanguageServer {
11029 id: server_id.to_proto(),
11030 name: language_server.name().to_string(),
11031 worktree_id: Some(key.worktree_id.to_proto()),
11032 }),
11033 capabilities: serde_json::to_string(&server_capabilities)
11034 .expect("serializing server LSP capabilities"),
11035 })
11036 .log_err();
11037 }
11038 self.lsp_server_capabilities
11039 .insert(server_id, server_capabilities);
11040
11041 // Tell the language server about every open buffer in the worktree that matches the language.
11042 // Also check for buffers in worktrees that reused this server
11043 let mut worktrees_using_server = vec![key.worktree_id];
11044 if let Some(local) = self.as_local() {
11045 // Find all worktrees that have this server in their language server tree
11046 for (worktree_id, servers) in &local.lsp_tree.instances {
11047 if *worktree_id != key.worktree_id {
11048 for server_map in servers.roots.values() {
11049 if server_map
11050 .values()
11051 .any(|(node, _)| node.id() == Some(server_id))
11052 {
11053 worktrees_using_server.push(*worktree_id);
11054 }
11055 }
11056 }
11057 }
11058 }
11059
11060 let mut buffer_paths_registered = Vec::new();
11061 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11062 let mut lsp_adapters = HashMap::default();
11063 for buffer_handle in buffer_store.buffers() {
11064 let buffer = buffer_handle.read(cx);
11065 let file = match File::from_dyn(buffer.file()) {
11066 Some(file) => file,
11067 None => continue,
11068 };
11069 let language = match buffer.language() {
11070 Some(language) => language,
11071 None => continue,
11072 };
11073
11074 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11075 || !lsp_adapters
11076 .entry(language.name())
11077 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11078 .iter()
11079 .any(|a| a.name == key.name)
11080 {
11081 continue;
11082 }
11083 // didOpen
11084 let file = match file.as_local() {
11085 Some(file) => file,
11086 None => continue,
11087 };
11088
11089 let local = self.as_local_mut().unwrap();
11090
11091 let buffer_id = buffer.remote_id();
11092 if local.registered_buffers.contains_key(&buffer_id) {
11093 let versions = local
11094 .buffer_snapshots
11095 .entry(buffer_id)
11096 .or_default()
11097 .entry(server_id)
11098 .and_modify(|_| {
11099 assert!(
11100 false,
11101 "There should not be an existing snapshot for a newly inserted buffer"
11102 )
11103 })
11104 .or_insert_with(|| {
11105 vec![LspBufferSnapshot {
11106 version: 0,
11107 snapshot: buffer.text_snapshot(),
11108 }]
11109 });
11110
11111 let snapshot = versions.last().unwrap();
11112 let version = snapshot.version;
11113 let initial_snapshot = &snapshot.snapshot;
11114 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11115 language_server.register_buffer(
11116 uri,
11117 adapter.language_id(&language.name()),
11118 version,
11119 initial_snapshot.text(),
11120 );
11121 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11122 local
11123 .buffers_opened_in_servers
11124 .entry(buffer_id)
11125 .or_default()
11126 .insert(server_id);
11127 }
11128 buffer_handle.update(cx, |buffer, cx| {
11129 buffer.set_completion_triggers(
11130 server_id,
11131 language_server
11132 .capabilities()
11133 .completion_provider
11134 .as_ref()
11135 .and_then(|provider| {
11136 provider
11137 .trigger_characters
11138 .as_ref()
11139 .map(|characters| characters.iter().cloned().collect())
11140 })
11141 .unwrap_or_default(),
11142 cx,
11143 )
11144 });
11145 }
11146 });
11147
11148 for (buffer_id, abs_path) in buffer_paths_registered {
11149 cx.emit(LspStoreEvent::LanguageServerUpdate {
11150 language_server_id: server_id,
11151 name: Some(adapter.name()),
11152 message: proto::update_language_server::Variant::RegisteredForBuffer(
11153 proto::RegisteredForBuffer {
11154 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11155 buffer_id: buffer_id.to_proto(),
11156 },
11157 ),
11158 });
11159 }
11160
11161 cx.notify();
11162 }
11163
11164 pub fn language_servers_running_disk_based_diagnostics(
11165 &self,
11166 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11167 self.language_server_statuses
11168 .iter()
11169 .filter_map(|(id, status)| {
11170 if status.has_pending_diagnostic_updates {
11171 Some(*id)
11172 } else {
11173 None
11174 }
11175 })
11176 }
11177
11178 pub(crate) fn cancel_language_server_work_for_buffers(
11179 &mut self,
11180 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11181 cx: &mut Context<Self>,
11182 ) {
11183 if let Some((client, project_id)) = self.upstream_client() {
11184 let request = client.request(proto::CancelLanguageServerWork {
11185 project_id,
11186 work: Some(proto::cancel_language_server_work::Work::Buffers(
11187 proto::cancel_language_server_work::Buffers {
11188 buffer_ids: buffers
11189 .into_iter()
11190 .map(|b| b.read(cx).remote_id().to_proto())
11191 .collect(),
11192 },
11193 )),
11194 });
11195 cx.background_spawn(request).detach_and_log_err(cx);
11196 } else if let Some(local) = self.as_local() {
11197 let servers = buffers
11198 .into_iter()
11199 .flat_map(|buffer| {
11200 buffer.update(cx, |buffer, cx| {
11201 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11202 })
11203 })
11204 .collect::<HashSet<_>>();
11205 for server_id in servers {
11206 self.cancel_language_server_work(server_id, None, cx);
11207 }
11208 }
11209 }
11210
11211 pub(crate) fn cancel_language_server_work(
11212 &mut self,
11213 server_id: LanguageServerId,
11214 token_to_cancel: Option<ProgressToken>,
11215 cx: &mut Context<Self>,
11216 ) {
11217 if let Some(local) = self.as_local() {
11218 let status = self.language_server_statuses.get(&server_id);
11219 let server = local.language_servers.get(&server_id);
11220 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11221 {
11222 for (token, progress) in &status.pending_work {
11223 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11224 && token != token_to_cancel
11225 {
11226 continue;
11227 }
11228 if progress.is_cancellable {
11229 server
11230 .notify::<lsp::notification::WorkDoneProgressCancel>(
11231 WorkDoneProgressCancelParams {
11232 token: token.to_lsp(),
11233 },
11234 )
11235 .ok();
11236 }
11237 }
11238 }
11239 } else if let Some((client, project_id)) = self.upstream_client() {
11240 let request = client.request(proto::CancelLanguageServerWork {
11241 project_id,
11242 work: Some(
11243 proto::cancel_language_server_work::Work::LanguageServerWork(
11244 proto::cancel_language_server_work::LanguageServerWork {
11245 language_server_id: server_id.to_proto(),
11246 token: token_to_cancel.map(|token| token.to_proto()),
11247 },
11248 ),
11249 ),
11250 });
11251 cx.background_spawn(request).detach_and_log_err(cx);
11252 }
11253 }
11254
11255 fn register_supplementary_language_server(
11256 &mut self,
11257 id: LanguageServerId,
11258 name: LanguageServerName,
11259 server: Arc<LanguageServer>,
11260 cx: &mut Context<Self>,
11261 ) {
11262 if let Some(local) = self.as_local_mut() {
11263 local
11264 .supplementary_language_servers
11265 .insert(id, (name.clone(), server));
11266 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11267 }
11268 }
11269
11270 fn unregister_supplementary_language_server(
11271 &mut self,
11272 id: LanguageServerId,
11273 cx: &mut Context<Self>,
11274 ) {
11275 if let Some(local) = self.as_local_mut() {
11276 local.supplementary_language_servers.remove(&id);
11277 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11278 }
11279 }
11280
11281 pub(crate) fn supplementary_language_servers(
11282 &self,
11283 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11284 self.as_local().into_iter().flat_map(|local| {
11285 local
11286 .supplementary_language_servers
11287 .iter()
11288 .map(|(id, (name, _))| (*id, name.clone()))
11289 })
11290 }
11291
11292 pub fn language_server_adapter_for_id(
11293 &self,
11294 id: LanguageServerId,
11295 ) -> Option<Arc<CachedLspAdapter>> {
11296 self.as_local()
11297 .and_then(|local| local.language_servers.get(&id))
11298 .and_then(|language_server_state| match language_server_state {
11299 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11300 _ => None,
11301 })
11302 }
11303
11304 pub(super) fn update_local_worktree_language_servers(
11305 &mut self,
11306 worktree_handle: &Entity<Worktree>,
11307 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11308 cx: &mut Context<Self>,
11309 ) {
11310 if changes.is_empty() {
11311 return;
11312 }
11313
11314 let Some(local) = self.as_local() else { return };
11315
11316 local.prettier_store.update(cx, |prettier_store, cx| {
11317 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11318 });
11319
11320 let worktree_id = worktree_handle.read(cx).id();
11321 let mut language_server_ids = local
11322 .language_server_ids
11323 .iter()
11324 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11325 .collect::<Vec<_>>();
11326 language_server_ids.sort();
11327 language_server_ids.dedup();
11328
11329 // let abs_path = worktree_handle.read(cx).abs_path();
11330 for server_id in &language_server_ids {
11331 if let Some(LanguageServerState::Running { server, .. }) =
11332 local.language_servers.get(server_id)
11333 && let Some(watched_paths) = local
11334 .language_server_watched_paths
11335 .get(server_id)
11336 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11337 {
11338 let params = lsp::DidChangeWatchedFilesParams {
11339 changes: changes
11340 .iter()
11341 .filter_map(|(path, _, change)| {
11342 if !watched_paths.is_match(path.as_std_path()) {
11343 return None;
11344 }
11345 let typ = match change {
11346 PathChange::Loaded => return None,
11347 PathChange::Added => lsp::FileChangeType::CREATED,
11348 PathChange::Removed => lsp::FileChangeType::DELETED,
11349 PathChange::Updated => lsp::FileChangeType::CHANGED,
11350 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11351 };
11352 let uri = lsp::Uri::from_file_path(
11353 worktree_handle.read(cx).absolutize(&path),
11354 )
11355 .ok()?;
11356 Some(lsp::FileEvent { uri, typ })
11357 })
11358 .collect(),
11359 };
11360 if !params.changes.is_empty() {
11361 server
11362 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11363 .ok();
11364 }
11365 }
11366 }
11367 for (path, _, _) in changes {
11368 if let Some(file_name) = path.file_name()
11369 && local.watched_manifest_filenames.contains(file_name)
11370 {
11371 self.request_workspace_config_refresh();
11372 break;
11373 }
11374 }
11375 }
11376
11377 pub fn wait_for_remote_buffer(
11378 &mut self,
11379 id: BufferId,
11380 cx: &mut Context<Self>,
11381 ) -> Task<Result<Entity<Buffer>>> {
11382 self.buffer_store.update(cx, |buffer_store, cx| {
11383 buffer_store.wait_for_remote_buffer(id, cx)
11384 })
11385 }
11386
11387 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11388 let mut result = proto::Symbol {
11389 language_server_name: symbol.language_server_name.0.to_string(),
11390 source_worktree_id: symbol.source_worktree_id.to_proto(),
11391 language_server_id: symbol.source_language_server_id.to_proto(),
11392 name: symbol.name.clone(),
11393 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11394 start: Some(proto::PointUtf16 {
11395 row: symbol.range.start.0.row,
11396 column: symbol.range.start.0.column,
11397 }),
11398 end: Some(proto::PointUtf16 {
11399 row: symbol.range.end.0.row,
11400 column: symbol.range.end.0.column,
11401 }),
11402 worktree_id: Default::default(),
11403 path: Default::default(),
11404 signature: Default::default(),
11405 };
11406 match &symbol.path {
11407 SymbolLocation::InProject(path) => {
11408 result.worktree_id = path.worktree_id.to_proto();
11409 result.path = path.path.to_proto();
11410 }
11411 SymbolLocation::OutsideProject {
11412 abs_path,
11413 signature,
11414 } => {
11415 result.path = abs_path.to_string_lossy().into_owned();
11416 result.signature = signature.to_vec();
11417 }
11418 }
11419 result
11420 }
11421
11422 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11423 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11424 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11425 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11426
11427 let path = if serialized_symbol.signature.is_empty() {
11428 SymbolLocation::InProject(ProjectPath {
11429 worktree_id,
11430 path: RelPath::from_proto(&serialized_symbol.path)
11431 .context("invalid symbol path")?,
11432 })
11433 } else {
11434 SymbolLocation::OutsideProject {
11435 abs_path: Path::new(&serialized_symbol.path).into(),
11436 signature: serialized_symbol
11437 .signature
11438 .try_into()
11439 .map_err(|_| anyhow!("invalid signature"))?,
11440 }
11441 };
11442
11443 let start = serialized_symbol.start.context("invalid start")?;
11444 let end = serialized_symbol.end.context("invalid end")?;
11445 Ok(CoreSymbol {
11446 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11447 source_worktree_id,
11448 source_language_server_id: LanguageServerId::from_proto(
11449 serialized_symbol.language_server_id,
11450 ),
11451 path,
11452 name: serialized_symbol.name,
11453 range: Unclipped(PointUtf16::new(start.row, start.column))
11454 ..Unclipped(PointUtf16::new(end.row, end.column)),
11455 kind,
11456 })
11457 }
11458
11459 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11460 let mut serialized_completion = proto::Completion {
11461 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11462 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11463 new_text: completion.new_text.clone(),
11464 ..proto::Completion::default()
11465 };
11466 match &completion.source {
11467 CompletionSource::Lsp {
11468 insert_range,
11469 server_id,
11470 lsp_completion,
11471 lsp_defaults,
11472 resolved,
11473 } => {
11474 let (old_insert_start, old_insert_end) = insert_range
11475 .as_ref()
11476 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11477 .unzip();
11478
11479 serialized_completion.old_insert_start = old_insert_start;
11480 serialized_completion.old_insert_end = old_insert_end;
11481 serialized_completion.source = proto::completion::Source::Lsp as i32;
11482 serialized_completion.server_id = server_id.0 as u64;
11483 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11484 serialized_completion.lsp_defaults = lsp_defaults
11485 .as_deref()
11486 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11487 serialized_completion.resolved = *resolved;
11488 }
11489 CompletionSource::BufferWord {
11490 word_range,
11491 resolved,
11492 } => {
11493 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11494 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11495 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11496 serialized_completion.resolved = *resolved;
11497 }
11498 CompletionSource::Custom => {
11499 serialized_completion.source = proto::completion::Source::Custom as i32;
11500 serialized_completion.resolved = true;
11501 }
11502 CompletionSource::Dap { sort_text } => {
11503 serialized_completion.source = proto::completion::Source::Dap as i32;
11504 serialized_completion.sort_text = Some(sort_text.clone());
11505 }
11506 }
11507
11508 serialized_completion
11509 }
11510
11511 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11512 let old_replace_start = completion
11513 .old_replace_start
11514 .and_then(deserialize_anchor)
11515 .context("invalid old start")?;
11516 let old_replace_end = completion
11517 .old_replace_end
11518 .and_then(deserialize_anchor)
11519 .context("invalid old end")?;
11520 let insert_range = {
11521 match completion.old_insert_start.zip(completion.old_insert_end) {
11522 Some((start, end)) => {
11523 let start = deserialize_anchor(start).context("invalid insert old start")?;
11524 let end = deserialize_anchor(end).context("invalid insert old end")?;
11525 Some(start..end)
11526 }
11527 None => None,
11528 }
11529 };
11530 Ok(CoreCompletion {
11531 replace_range: old_replace_start..old_replace_end,
11532 new_text: completion.new_text,
11533 source: match proto::completion::Source::from_i32(completion.source) {
11534 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11535 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11536 insert_range,
11537 server_id: LanguageServerId::from_proto(completion.server_id),
11538 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11539 lsp_defaults: completion
11540 .lsp_defaults
11541 .as_deref()
11542 .map(serde_json::from_slice)
11543 .transpose()?,
11544 resolved: completion.resolved,
11545 },
11546 Some(proto::completion::Source::BufferWord) => {
11547 let word_range = completion
11548 .buffer_word_start
11549 .and_then(deserialize_anchor)
11550 .context("invalid buffer word start")?
11551 ..completion
11552 .buffer_word_end
11553 .and_then(deserialize_anchor)
11554 .context("invalid buffer word end")?;
11555 CompletionSource::BufferWord {
11556 word_range,
11557 resolved: completion.resolved,
11558 }
11559 }
11560 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11561 sort_text: completion
11562 .sort_text
11563 .context("expected sort text to exist")?,
11564 },
11565 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11566 },
11567 })
11568 }
11569
11570 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11571 let (kind, lsp_action) = match &action.lsp_action {
11572 LspAction::Action(code_action) => (
11573 proto::code_action::Kind::Action as i32,
11574 serde_json::to_vec(code_action).unwrap(),
11575 ),
11576 LspAction::Command(command) => (
11577 proto::code_action::Kind::Command as i32,
11578 serde_json::to_vec(command).unwrap(),
11579 ),
11580 LspAction::CodeLens(code_lens) => (
11581 proto::code_action::Kind::CodeLens as i32,
11582 serde_json::to_vec(code_lens).unwrap(),
11583 ),
11584 };
11585
11586 proto::CodeAction {
11587 server_id: action.server_id.0 as u64,
11588 start: Some(serialize_anchor(&action.range.start)),
11589 end: Some(serialize_anchor(&action.range.end)),
11590 lsp_action,
11591 kind,
11592 resolved: action.resolved,
11593 }
11594 }
11595
11596 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11597 let start = action
11598 .start
11599 .and_then(deserialize_anchor)
11600 .context("invalid start")?;
11601 let end = action
11602 .end
11603 .and_then(deserialize_anchor)
11604 .context("invalid end")?;
11605 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11606 Some(proto::code_action::Kind::Action) => {
11607 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11608 }
11609 Some(proto::code_action::Kind::Command) => {
11610 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11611 }
11612 Some(proto::code_action::Kind::CodeLens) => {
11613 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11614 }
11615 None => anyhow::bail!("Unknown action kind {}", action.kind),
11616 };
11617 Ok(CodeAction {
11618 server_id: LanguageServerId(action.server_id as usize),
11619 range: start..end,
11620 resolved: action.resolved,
11621 lsp_action,
11622 })
11623 }
11624
11625 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11626 match &formatting_result {
11627 Ok(_) => self.last_formatting_failure = None,
11628 Err(error) => {
11629 let error_string = format!("{error:#}");
11630 log::error!("Formatting failed: {error_string}");
11631 self.last_formatting_failure
11632 .replace(error_string.lines().join(" "));
11633 }
11634 }
11635 }
11636
11637 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11638 self.lsp_server_capabilities.remove(&for_server);
11639 for lsp_data in self.lsp_data.values_mut() {
11640 lsp_data.remove_server_data(for_server);
11641 }
11642 if let Some(local) = self.as_local_mut() {
11643 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11644 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11645 buffer_servers.remove(&for_server);
11646 }
11647 }
11648 }
11649
11650 pub fn result_id(
11651 &self,
11652 server_id: LanguageServerId,
11653 buffer_id: BufferId,
11654 cx: &App,
11655 ) -> Option<String> {
11656 let abs_path = self
11657 .buffer_store
11658 .read(cx)
11659 .get(buffer_id)
11660 .and_then(|b| File::from_dyn(b.read(cx).file()))
11661 .map(|f| f.abs_path(cx))?;
11662 self.as_local()?
11663 .buffer_pull_diagnostics_result_ids
11664 .get(&server_id)?
11665 .get(&abs_path)?
11666 .clone()
11667 }
11668
11669 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11670 let Some(local) = self.as_local() else {
11671 return HashMap::default();
11672 };
11673 local
11674 .buffer_pull_diagnostics_result_ids
11675 .get(&server_id)
11676 .into_iter()
11677 .flatten()
11678 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11679 .collect()
11680 }
11681
11682 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11683 if let Some(LanguageServerState::Running {
11684 workspace_diagnostics_refresh_tasks,
11685 ..
11686 }) = self
11687 .as_local_mut()
11688 .and_then(|local| local.language_servers.get_mut(&server_id))
11689 {
11690 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11691 diagnostics.refresh_tx.try_send(()).ok();
11692 }
11693 }
11694 }
11695
11696 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11697 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11698 return;
11699 };
11700 let Some(local) = self.as_local_mut() else {
11701 return;
11702 };
11703
11704 for server_id in buffer.update(cx, |buffer, cx| {
11705 local.language_server_ids_for_buffer(buffer, cx)
11706 }) {
11707 if let Some(LanguageServerState::Running {
11708 workspace_diagnostics_refresh_tasks,
11709 ..
11710 }) = local.language_servers.get_mut(&server_id)
11711 {
11712 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11713 diagnostics.refresh_tx.try_send(()).ok();
11714 }
11715 }
11716 }
11717 }
11718
11719 fn apply_workspace_diagnostic_report(
11720 &mut self,
11721 server_id: LanguageServerId,
11722 report: lsp::WorkspaceDiagnosticReportResult,
11723 cx: &mut Context<Self>,
11724 ) {
11725 let workspace_diagnostics =
11726 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11727 let mut unchanged_buffers = HashSet::default();
11728 let mut changed_buffers = HashSet::default();
11729 let workspace_diagnostics_updates = workspace_diagnostics
11730 .into_iter()
11731 .filter_map(
11732 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11733 LspPullDiagnostics::Response {
11734 server_id,
11735 uri,
11736 diagnostics,
11737 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11738 LspPullDiagnostics::Default => None,
11739 },
11740 )
11741 .fold(
11742 HashMap::default(),
11743 |mut acc, (server_id, uri, diagnostics, version)| {
11744 let (result_id, diagnostics) = match diagnostics {
11745 PulledDiagnostics::Unchanged { result_id } => {
11746 unchanged_buffers.insert(uri.clone());
11747 (Some(result_id), Vec::new())
11748 }
11749 PulledDiagnostics::Changed {
11750 result_id,
11751 diagnostics,
11752 } => {
11753 changed_buffers.insert(uri.clone());
11754 (result_id, diagnostics)
11755 }
11756 };
11757 let disk_based_sources = Cow::Owned(
11758 self.language_server_adapter_for_id(server_id)
11759 .as_ref()
11760 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11761 .unwrap_or(&[])
11762 .to_vec(),
11763 );
11764 acc.entry(server_id)
11765 .or_insert_with(Vec::new)
11766 .push(DocumentDiagnosticsUpdate {
11767 server_id,
11768 diagnostics: lsp::PublishDiagnosticsParams {
11769 uri,
11770 diagnostics,
11771 version,
11772 },
11773 result_id,
11774 disk_based_sources,
11775 });
11776 acc
11777 },
11778 );
11779
11780 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11781 self.merge_lsp_diagnostics(
11782 DiagnosticSourceKind::Pulled,
11783 diagnostic_updates,
11784 |buffer, old_diagnostic, cx| {
11785 File::from_dyn(buffer.file())
11786 .and_then(|file| {
11787 let abs_path = file.as_local()?.abs_path(cx);
11788 lsp::Uri::from_file_path(abs_path).ok()
11789 })
11790 .is_none_or(|buffer_uri| {
11791 unchanged_buffers.contains(&buffer_uri)
11792 || match old_diagnostic.source_kind {
11793 DiagnosticSourceKind::Pulled => {
11794 !changed_buffers.contains(&buffer_uri)
11795 }
11796 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11797 true
11798 }
11799 }
11800 })
11801 },
11802 cx,
11803 )
11804 .log_err();
11805 }
11806 }
11807
11808 fn register_server_capabilities(
11809 &mut self,
11810 server_id: LanguageServerId,
11811 params: lsp::RegistrationParams,
11812 cx: &mut Context<Self>,
11813 ) -> anyhow::Result<()> {
11814 let server = self
11815 .language_server_for_id(server_id)
11816 .with_context(|| format!("no server {server_id} found"))?;
11817 for reg in params.registrations {
11818 match reg.method.as_str() {
11819 "workspace/didChangeWatchedFiles" => {
11820 if let Some(options) = reg.register_options {
11821 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11822 let caps = serde_json::from_value(options)?;
11823 local_lsp_store
11824 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11825 true
11826 } else {
11827 false
11828 };
11829 if notify {
11830 notify_server_capabilities_updated(&server, cx);
11831 }
11832 }
11833 }
11834 "workspace/didChangeConfiguration" => {
11835 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11836 }
11837 "workspace/didChangeWorkspaceFolders" => {
11838 // In this case register options is an empty object, we can ignore it
11839 let caps = lsp::WorkspaceFoldersServerCapabilities {
11840 supported: Some(true),
11841 change_notifications: Some(OneOf::Right(reg.id)),
11842 };
11843 server.update_capabilities(|capabilities| {
11844 capabilities
11845 .workspace
11846 .get_or_insert_default()
11847 .workspace_folders = Some(caps);
11848 });
11849 notify_server_capabilities_updated(&server, cx);
11850 }
11851 "workspace/symbol" => {
11852 let options = parse_register_capabilities(reg)?;
11853 server.update_capabilities(|capabilities| {
11854 capabilities.workspace_symbol_provider = Some(options);
11855 });
11856 notify_server_capabilities_updated(&server, cx);
11857 }
11858 "workspace/fileOperations" => {
11859 if let Some(options) = reg.register_options {
11860 let caps = serde_json::from_value(options)?;
11861 server.update_capabilities(|capabilities| {
11862 capabilities
11863 .workspace
11864 .get_or_insert_default()
11865 .file_operations = Some(caps);
11866 });
11867 notify_server_capabilities_updated(&server, cx);
11868 }
11869 }
11870 "workspace/executeCommand" => {
11871 if let Some(options) = reg.register_options {
11872 let options = serde_json::from_value(options)?;
11873 server.update_capabilities(|capabilities| {
11874 capabilities.execute_command_provider = Some(options);
11875 });
11876 notify_server_capabilities_updated(&server, cx);
11877 }
11878 }
11879 "textDocument/rangeFormatting" => {
11880 let options = parse_register_capabilities(reg)?;
11881 server.update_capabilities(|capabilities| {
11882 capabilities.document_range_formatting_provider = Some(options);
11883 });
11884 notify_server_capabilities_updated(&server, cx);
11885 }
11886 "textDocument/onTypeFormatting" => {
11887 if let Some(options) = reg
11888 .register_options
11889 .map(serde_json::from_value)
11890 .transpose()?
11891 {
11892 server.update_capabilities(|capabilities| {
11893 capabilities.document_on_type_formatting_provider = Some(options);
11894 });
11895 notify_server_capabilities_updated(&server, cx);
11896 }
11897 }
11898 "textDocument/formatting" => {
11899 let options = parse_register_capabilities(reg)?;
11900 server.update_capabilities(|capabilities| {
11901 capabilities.document_formatting_provider = Some(options);
11902 });
11903 notify_server_capabilities_updated(&server, cx);
11904 }
11905 "textDocument/rename" => {
11906 let options = parse_register_capabilities(reg)?;
11907 server.update_capabilities(|capabilities| {
11908 capabilities.rename_provider = Some(options);
11909 });
11910 notify_server_capabilities_updated(&server, cx);
11911 }
11912 "textDocument/inlayHint" => {
11913 let options = parse_register_capabilities(reg)?;
11914 server.update_capabilities(|capabilities| {
11915 capabilities.inlay_hint_provider = Some(options);
11916 });
11917 notify_server_capabilities_updated(&server, cx);
11918 }
11919 "textDocument/documentSymbol" => {
11920 let options = parse_register_capabilities(reg)?;
11921 server.update_capabilities(|capabilities| {
11922 capabilities.document_symbol_provider = Some(options);
11923 });
11924 notify_server_capabilities_updated(&server, cx);
11925 }
11926 "textDocument/codeAction" => {
11927 let options = parse_register_capabilities(reg)?;
11928 let provider = match options {
11929 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11930 OneOf::Right(caps) => caps,
11931 };
11932 server.update_capabilities(|capabilities| {
11933 capabilities.code_action_provider = Some(provider);
11934 });
11935 notify_server_capabilities_updated(&server, cx);
11936 }
11937 "textDocument/definition" => {
11938 let options = parse_register_capabilities(reg)?;
11939 server.update_capabilities(|capabilities| {
11940 capabilities.definition_provider = Some(options);
11941 });
11942 notify_server_capabilities_updated(&server, cx);
11943 }
11944 "textDocument/completion" => {
11945 if let Some(caps) = reg
11946 .register_options
11947 .map(serde_json::from_value::<CompletionOptions>)
11948 .transpose()?
11949 {
11950 server.update_capabilities(|capabilities| {
11951 capabilities.completion_provider = Some(caps.clone());
11952 });
11953
11954 if let Some(local) = self.as_local() {
11955 let mut buffers_with_language_server = Vec::new();
11956 for handle in self.buffer_store.read(cx).buffers() {
11957 let buffer_id = handle.read(cx).remote_id();
11958 if local
11959 .buffers_opened_in_servers
11960 .get(&buffer_id)
11961 .filter(|s| s.contains(&server_id))
11962 .is_some()
11963 {
11964 buffers_with_language_server.push(handle);
11965 }
11966 }
11967 let triggers = caps
11968 .trigger_characters
11969 .unwrap_or_default()
11970 .into_iter()
11971 .collect::<BTreeSet<_>>();
11972 for handle in buffers_with_language_server {
11973 let triggers = triggers.clone();
11974 let _ = handle.update(cx, move |buffer, cx| {
11975 buffer.set_completion_triggers(server_id, triggers, cx);
11976 });
11977 }
11978 }
11979 notify_server_capabilities_updated(&server, cx);
11980 }
11981 }
11982 "textDocument/hover" => {
11983 let options = parse_register_capabilities(reg)?;
11984 let provider = match options {
11985 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11986 OneOf::Right(caps) => caps,
11987 };
11988 server.update_capabilities(|capabilities| {
11989 capabilities.hover_provider = Some(provider);
11990 });
11991 notify_server_capabilities_updated(&server, cx);
11992 }
11993 "textDocument/signatureHelp" => {
11994 if let Some(caps) = reg
11995 .register_options
11996 .map(serde_json::from_value)
11997 .transpose()?
11998 {
11999 server.update_capabilities(|capabilities| {
12000 capabilities.signature_help_provider = Some(caps);
12001 });
12002 notify_server_capabilities_updated(&server, cx);
12003 }
12004 }
12005 "textDocument/didChange" => {
12006 if let Some(sync_kind) = reg
12007 .register_options
12008 .and_then(|opts| opts.get("syncKind").cloned())
12009 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12010 .transpose()?
12011 {
12012 server.update_capabilities(|capabilities| {
12013 let mut sync_options =
12014 Self::take_text_document_sync_options(capabilities);
12015 sync_options.change = Some(sync_kind);
12016 capabilities.text_document_sync =
12017 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12018 });
12019 notify_server_capabilities_updated(&server, cx);
12020 }
12021 }
12022 "textDocument/didSave" => {
12023 if let Some(include_text) = reg
12024 .register_options
12025 .map(|opts| {
12026 let transpose = opts
12027 .get("includeText")
12028 .cloned()
12029 .map(serde_json::from_value::<Option<bool>>)
12030 .transpose();
12031 match transpose {
12032 Ok(value) => Ok(value.flatten()),
12033 Err(e) => Err(e),
12034 }
12035 })
12036 .transpose()?
12037 {
12038 server.update_capabilities(|capabilities| {
12039 let mut sync_options =
12040 Self::take_text_document_sync_options(capabilities);
12041 sync_options.save =
12042 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12043 include_text,
12044 }));
12045 capabilities.text_document_sync =
12046 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12047 });
12048 notify_server_capabilities_updated(&server, cx);
12049 }
12050 }
12051 "textDocument/codeLens" => {
12052 if let Some(caps) = reg
12053 .register_options
12054 .map(serde_json::from_value)
12055 .transpose()?
12056 {
12057 server.update_capabilities(|capabilities| {
12058 capabilities.code_lens_provider = Some(caps);
12059 });
12060 notify_server_capabilities_updated(&server, cx);
12061 }
12062 }
12063 "textDocument/diagnostic" => {
12064 if let Some(caps) = reg
12065 .register_options
12066 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12067 .transpose()?
12068 {
12069 let local = self
12070 .as_local_mut()
12071 .context("Expected LSP Store to be local")?;
12072 let state = local
12073 .language_servers
12074 .get_mut(&server_id)
12075 .context("Could not obtain Language Servers state")?;
12076 local
12077 .language_server_dynamic_registrations
12078 .entry(server_id)
12079 .or_default()
12080 .diagnostics
12081 .insert(Some(reg.id.clone()), caps.clone());
12082
12083 if let LanguageServerState::Running {
12084 workspace_diagnostics_refresh_tasks,
12085 ..
12086 } = state
12087 && let Some(task) = lsp_workspace_diagnostics_refresh(
12088 Some(reg.id.clone()),
12089 caps.clone(),
12090 server.clone(),
12091 cx,
12092 )
12093 {
12094 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12095 }
12096
12097 let mut did_update_caps = false;
12098 server.update_capabilities(|capabilities| {
12099 if capabilities.diagnostic_provider.as_ref().is_none_or(
12100 |current_caps| {
12101 let supports_workspace_diagnostics =
12102 |capabilities: &DiagnosticServerCapabilities| {
12103 match capabilities {
12104 DiagnosticServerCapabilities::Options(
12105 diagnostic_options,
12106 ) => diagnostic_options.workspace_diagnostics,
12107 DiagnosticServerCapabilities::RegistrationOptions(
12108 diagnostic_registration_options,
12109 ) => {
12110 diagnostic_registration_options
12111 .diagnostic_options
12112 .workspace_diagnostics
12113 }
12114 }
12115 };
12116 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12117 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12118 // as it'll think that they're not supported.
12119 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12120 !supports_workspace_diagnostics(current_caps)
12121 & supports_workspace_diagnostics(&caps)
12122 },
12123 ) {
12124 did_update_caps = true;
12125 capabilities.diagnostic_provider = Some(caps);
12126 }
12127 });
12128 if did_update_caps {
12129 notify_server_capabilities_updated(&server, cx);
12130 }
12131 }
12132 }
12133 "textDocument/documentColor" => {
12134 let options = parse_register_capabilities(reg)?;
12135 let provider = match options {
12136 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12137 OneOf::Right(caps) => caps,
12138 };
12139 server.update_capabilities(|capabilities| {
12140 capabilities.color_provider = Some(provider);
12141 });
12142 notify_server_capabilities_updated(&server, cx);
12143 }
12144 _ => log::warn!("unhandled capability registration: {reg:?}"),
12145 }
12146 }
12147
12148 Ok(())
12149 }
12150
12151 fn unregister_server_capabilities(
12152 &mut self,
12153 server_id: LanguageServerId,
12154 params: lsp::UnregistrationParams,
12155 cx: &mut Context<Self>,
12156 ) -> anyhow::Result<()> {
12157 let server = self
12158 .language_server_for_id(server_id)
12159 .with_context(|| format!("no server {server_id} found"))?;
12160 for unreg in params.unregisterations.iter() {
12161 match unreg.method.as_str() {
12162 "workspace/didChangeWatchedFiles" => {
12163 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12164 local_lsp_store
12165 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12166 true
12167 } else {
12168 false
12169 };
12170 if notify {
12171 notify_server_capabilities_updated(&server, cx);
12172 }
12173 }
12174 "workspace/didChangeConfiguration" => {
12175 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12176 }
12177 "workspace/didChangeWorkspaceFolders" => {
12178 server.update_capabilities(|capabilities| {
12179 capabilities
12180 .workspace
12181 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12182 workspace_folders: None,
12183 file_operations: None,
12184 })
12185 .workspace_folders = None;
12186 });
12187 notify_server_capabilities_updated(&server, cx);
12188 }
12189 "workspace/symbol" => {
12190 server.update_capabilities(|capabilities| {
12191 capabilities.workspace_symbol_provider = None
12192 });
12193 notify_server_capabilities_updated(&server, cx);
12194 }
12195 "workspace/fileOperations" => {
12196 server.update_capabilities(|capabilities| {
12197 capabilities
12198 .workspace
12199 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12200 workspace_folders: None,
12201 file_operations: None,
12202 })
12203 .file_operations = None;
12204 });
12205 notify_server_capabilities_updated(&server, cx);
12206 }
12207 "workspace/executeCommand" => {
12208 server.update_capabilities(|capabilities| {
12209 capabilities.execute_command_provider = None;
12210 });
12211 notify_server_capabilities_updated(&server, cx);
12212 }
12213 "textDocument/rangeFormatting" => {
12214 server.update_capabilities(|capabilities| {
12215 capabilities.document_range_formatting_provider = None
12216 });
12217 notify_server_capabilities_updated(&server, cx);
12218 }
12219 "textDocument/onTypeFormatting" => {
12220 server.update_capabilities(|capabilities| {
12221 capabilities.document_on_type_formatting_provider = None;
12222 });
12223 notify_server_capabilities_updated(&server, cx);
12224 }
12225 "textDocument/formatting" => {
12226 server.update_capabilities(|capabilities| {
12227 capabilities.document_formatting_provider = None;
12228 });
12229 notify_server_capabilities_updated(&server, cx);
12230 }
12231 "textDocument/rename" => {
12232 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12233 notify_server_capabilities_updated(&server, cx);
12234 }
12235 "textDocument/codeAction" => {
12236 server.update_capabilities(|capabilities| {
12237 capabilities.code_action_provider = None;
12238 });
12239 notify_server_capabilities_updated(&server, cx);
12240 }
12241 "textDocument/definition" => {
12242 server.update_capabilities(|capabilities| {
12243 capabilities.definition_provider = None;
12244 });
12245 notify_server_capabilities_updated(&server, cx);
12246 }
12247 "textDocument/completion" => {
12248 server.update_capabilities(|capabilities| {
12249 capabilities.completion_provider = None;
12250 });
12251 notify_server_capabilities_updated(&server, cx);
12252 }
12253 "textDocument/hover" => {
12254 server.update_capabilities(|capabilities| {
12255 capabilities.hover_provider = None;
12256 });
12257 notify_server_capabilities_updated(&server, cx);
12258 }
12259 "textDocument/signatureHelp" => {
12260 server.update_capabilities(|capabilities| {
12261 capabilities.signature_help_provider = None;
12262 });
12263 notify_server_capabilities_updated(&server, cx);
12264 }
12265 "textDocument/didChange" => {
12266 server.update_capabilities(|capabilities| {
12267 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12268 sync_options.change = None;
12269 capabilities.text_document_sync =
12270 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12271 });
12272 notify_server_capabilities_updated(&server, cx);
12273 }
12274 "textDocument/didSave" => {
12275 server.update_capabilities(|capabilities| {
12276 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12277 sync_options.save = None;
12278 capabilities.text_document_sync =
12279 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12280 });
12281 notify_server_capabilities_updated(&server, cx);
12282 }
12283 "textDocument/codeLens" => {
12284 server.update_capabilities(|capabilities| {
12285 capabilities.code_lens_provider = None;
12286 });
12287 notify_server_capabilities_updated(&server, cx);
12288 }
12289 "textDocument/diagnostic" => {
12290 let local = self
12291 .as_local_mut()
12292 .context("Expected LSP Store to be local")?;
12293
12294 let state = local
12295 .language_servers
12296 .get_mut(&server_id)
12297 .context("Could not obtain Language Servers state")?;
12298 let options = local
12299 .language_server_dynamic_registrations
12300 .get_mut(&server_id)
12301 .with_context(|| {
12302 format!("Expected dynamic registration to exist for server {server_id}")
12303 })?.diagnostics
12304 .remove(&Some(unreg.id.clone()))
12305 .with_context(|| format!(
12306 "Attempted to unregister non-existent diagnostic registration with ID {}",
12307 unreg.id)
12308 )?;
12309
12310 let mut has_any_diagnostic_providers_still = true;
12311 if let Some(identifier) = diagnostic_identifier(&options)
12312 && let LanguageServerState::Running {
12313 workspace_diagnostics_refresh_tasks,
12314 ..
12315 } = state
12316 {
12317 workspace_diagnostics_refresh_tasks.remove(&identifier);
12318 has_any_diagnostic_providers_still =
12319 !workspace_diagnostics_refresh_tasks.is_empty();
12320 }
12321
12322 if !has_any_diagnostic_providers_still {
12323 server.update_capabilities(|capabilities| {
12324 debug_assert!(capabilities.diagnostic_provider.is_some());
12325 capabilities.diagnostic_provider = None;
12326 });
12327 }
12328
12329 notify_server_capabilities_updated(&server, cx);
12330 }
12331 "textDocument/documentColor" => {
12332 server.update_capabilities(|capabilities| {
12333 capabilities.color_provider = None;
12334 });
12335 notify_server_capabilities_updated(&server, cx);
12336 }
12337 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12338 }
12339 }
12340
12341 Ok(())
12342 }
12343
12344 async fn deduplicate_range_based_lsp_requests<T>(
12345 lsp_store: &Entity<Self>,
12346 server_id: Option<LanguageServerId>,
12347 lsp_request_id: LspRequestId,
12348 proto_request: &T::ProtoRequest,
12349 range: Range<Anchor>,
12350 cx: &mut AsyncApp,
12351 ) -> Result<()>
12352 where
12353 T: LspCommand,
12354 T::ProtoRequest: proto::LspRequestMessage,
12355 {
12356 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12357 let version = deserialize_version(proto_request.buffer_version());
12358 let buffer = lsp_store.update(cx, |this, cx| {
12359 this.buffer_store.read(cx).get_existing(buffer_id)
12360 })??;
12361 buffer
12362 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12363 .await?;
12364 lsp_store.update(cx, |lsp_store, cx| {
12365 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12366 let chunks_queried_for = lsp_data
12367 .inlay_hints
12368 .applicable_chunks(&[range])
12369 .collect::<Vec<_>>();
12370 match chunks_queried_for.as_slice() {
12371 &[chunk] => {
12372 let key = LspKey {
12373 request_type: TypeId::of::<T>(),
12374 server_queried: server_id,
12375 };
12376 let previous_request = lsp_data
12377 .chunk_lsp_requests
12378 .entry(key)
12379 .or_default()
12380 .insert(chunk, lsp_request_id);
12381 if let Some((previous_request, running_requests)) =
12382 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12383 {
12384 running_requests.remove(&previous_request);
12385 }
12386 }
12387 _ambiguous_chunks => {
12388 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12389 // there, a buffer version-based check will be performed and outdated requests discarded.
12390 }
12391 }
12392 anyhow::Ok(())
12393 })??;
12394
12395 Ok(())
12396 }
12397
12398 async fn query_lsp_locally<T>(
12399 lsp_store: Entity<Self>,
12400 for_server_id: Option<LanguageServerId>,
12401 sender_id: proto::PeerId,
12402 lsp_request_id: LspRequestId,
12403 proto_request: T::ProtoRequest,
12404 position: Option<Anchor>,
12405 cx: &mut AsyncApp,
12406 ) -> Result<()>
12407 where
12408 T: LspCommand + Clone,
12409 T::ProtoRequest: proto::LspRequestMessage,
12410 <T::ProtoRequest as proto::RequestMessage>::Response:
12411 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12412 {
12413 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12414 let version = deserialize_version(proto_request.buffer_version());
12415 let buffer = lsp_store.update(cx, |this, cx| {
12416 this.buffer_store.read(cx).get_existing(buffer_id)
12417 })??;
12418 buffer
12419 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12420 .await?;
12421 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12422 let request =
12423 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12424 let key = LspKey {
12425 request_type: TypeId::of::<T>(),
12426 server_queried: for_server_id,
12427 };
12428 lsp_store.update(cx, |lsp_store, cx| {
12429 let request_task = match for_server_id {
12430 Some(server_id) => {
12431 let server_task = lsp_store.request_lsp(
12432 buffer.clone(),
12433 LanguageServerToQuery::Other(server_id),
12434 request.clone(),
12435 cx,
12436 );
12437 cx.background_spawn(async move {
12438 let mut responses = Vec::new();
12439 match server_task.await {
12440 Ok(response) => responses.push((server_id, response)),
12441 // rust-analyzer likes to error with this when its still loading up
12442 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12443 Err(e) => log::error!(
12444 "Error handling response for request {request:?}: {e:#}"
12445 ),
12446 }
12447 responses
12448 })
12449 }
12450 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12451 };
12452 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12453 if T::ProtoRequest::stop_previous_requests() {
12454 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12455 lsp_requests.clear();
12456 }
12457 }
12458 lsp_data.lsp_requests.entry(key).or_default().insert(
12459 lsp_request_id,
12460 cx.spawn(async move |lsp_store, cx| {
12461 let response = request_task.await;
12462 lsp_store
12463 .update(cx, |lsp_store, cx| {
12464 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12465 {
12466 let response = response
12467 .into_iter()
12468 .map(|(server_id, response)| {
12469 (
12470 server_id.to_proto(),
12471 T::response_to_proto(
12472 response,
12473 lsp_store,
12474 sender_id,
12475 &buffer_version,
12476 cx,
12477 )
12478 .into(),
12479 )
12480 })
12481 .collect::<HashMap<_, _>>();
12482 match client.send_lsp_response::<T::ProtoRequest>(
12483 project_id,
12484 lsp_request_id,
12485 response,
12486 ) {
12487 Ok(()) => {}
12488 Err(e) => {
12489 log::error!("Failed to send LSP response: {e:#}",)
12490 }
12491 }
12492 }
12493 })
12494 .ok();
12495 }),
12496 );
12497 })?;
12498 Ok(())
12499 }
12500
12501 fn take_text_document_sync_options(
12502 capabilities: &mut lsp::ServerCapabilities,
12503 ) -> lsp::TextDocumentSyncOptions {
12504 match capabilities.text_document_sync.take() {
12505 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12506 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12507 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12508 sync_options.change = Some(sync_kind);
12509 sync_options
12510 }
12511 None => lsp::TextDocumentSyncOptions::default(),
12512 }
12513 }
12514
12515 #[cfg(any(test, feature = "test-support"))]
12516 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12517 Some(
12518 self.lsp_data
12519 .get_mut(&buffer_id)?
12520 .code_lens
12521 .take()?
12522 .update
12523 .take()?
12524 .1,
12525 )
12526 }
12527
12528 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12529 self.downstream_client.clone()
12530 }
12531
12532 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12533 self.worktree_store.clone()
12534 }
12535
12536 /// Gets what's stored in the LSP data for the given buffer.
12537 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12538 self.lsp_data.get_mut(&buffer_id)
12539 }
12540
12541 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12542 /// new [`BufferLspData`] will be created to replace the previous state.
12543 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12544 let (buffer_id, buffer_version) =
12545 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12546 let lsp_data = self
12547 .lsp_data
12548 .entry(buffer_id)
12549 .or_insert_with(|| BufferLspData::new(buffer, cx));
12550 if buffer_version.changed_since(&lsp_data.buffer_version) {
12551 *lsp_data = BufferLspData::new(buffer, cx);
12552 }
12553 lsp_data
12554 }
12555}
12556
12557// Registration with registerOptions as null, should fallback to true.
12558// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12559fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12560 reg: lsp::Registration,
12561) -> Result<OneOf<bool, T>> {
12562 Ok(match reg.register_options {
12563 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12564 None => OneOf::Left(true),
12565 })
12566}
12567
12568fn subscribe_to_binary_statuses(
12569 languages: &Arc<LanguageRegistry>,
12570 cx: &mut Context<'_, LspStore>,
12571) -> Task<()> {
12572 let mut server_statuses = languages.language_server_binary_statuses();
12573 cx.spawn(async move |lsp_store, cx| {
12574 while let Some((server_name, binary_status)) = server_statuses.next().await {
12575 if lsp_store
12576 .update(cx, |_, cx| {
12577 let mut message = None;
12578 let binary_status = match binary_status {
12579 BinaryStatus::None => proto::ServerBinaryStatus::None,
12580 BinaryStatus::CheckingForUpdate => {
12581 proto::ServerBinaryStatus::CheckingForUpdate
12582 }
12583 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12584 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12585 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12586 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12587 BinaryStatus::Failed { error } => {
12588 message = Some(error);
12589 proto::ServerBinaryStatus::Failed
12590 }
12591 };
12592 cx.emit(LspStoreEvent::LanguageServerUpdate {
12593 // Binary updates are about the binary that might not have any language server id at that point.
12594 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12595 language_server_id: LanguageServerId(0),
12596 name: Some(server_name),
12597 message: proto::update_language_server::Variant::StatusUpdate(
12598 proto::StatusUpdate {
12599 message,
12600 status: Some(proto::status_update::Status::Binary(
12601 binary_status as i32,
12602 )),
12603 },
12604 ),
12605 });
12606 })
12607 .is_err()
12608 {
12609 break;
12610 }
12611 }
12612 })
12613}
12614
12615fn lsp_workspace_diagnostics_refresh(
12616 registration_id: Option<String>,
12617 options: DiagnosticServerCapabilities,
12618 server: Arc<LanguageServer>,
12619 cx: &mut Context<'_, LspStore>,
12620) -> Option<WorkspaceRefreshTask> {
12621 let identifier = diagnostic_identifier(&options)?;
12622
12623 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12624 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12625 refresh_tx.try_send(()).ok();
12626
12627 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12628 let mut attempts = 0;
12629 let max_attempts = 50;
12630 let mut requests = 0;
12631
12632 loop {
12633 let Some(()) = refresh_rx.recv().await else {
12634 return;
12635 };
12636
12637 'request: loop {
12638 requests += 1;
12639 if attempts > max_attempts {
12640 log::error!(
12641 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12642 );
12643 return;
12644 }
12645 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12646 cx.background_executor()
12647 .timer(Duration::from_millis(backoff_millis))
12648 .await;
12649 attempts += 1;
12650
12651 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12652 lsp_store
12653 .all_result_ids(server.server_id())
12654 .into_iter()
12655 .filter_map(|(abs_path, result_id)| {
12656 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12657 Some(lsp::PreviousResultId {
12658 uri,
12659 value: result_id,
12660 })
12661 })
12662 .collect()
12663 }) else {
12664 return;
12665 };
12666
12667 let token = if let Some(identifier) = ®istration_id {
12668 format!(
12669 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12670 server.server_id(),
12671 )
12672 } else {
12673 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12674 };
12675
12676 progress_rx.try_recv().ok();
12677 let timer =
12678 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12679 let progress = pin!(progress_rx.recv().fuse());
12680 let response_result = server
12681 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12682 lsp::WorkspaceDiagnosticParams {
12683 previous_result_ids,
12684 identifier: identifier.clone(),
12685 work_done_progress_params: Default::default(),
12686 partial_result_params: lsp::PartialResultParams {
12687 partial_result_token: Some(lsp::ProgressToken::String(token)),
12688 },
12689 },
12690 select(timer, progress).then(|either| match either {
12691 Either::Left((message, ..)) => ready(message).left_future(),
12692 Either::Right(..) => pending::<String>().right_future(),
12693 }),
12694 )
12695 .await;
12696
12697 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12698 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12699 match response_result {
12700 ConnectionResult::Timeout => {
12701 log::error!("Timeout during workspace diagnostics pull");
12702 continue 'request;
12703 }
12704 ConnectionResult::ConnectionReset => {
12705 log::error!("Server closed a workspace diagnostics pull request");
12706 continue 'request;
12707 }
12708 ConnectionResult::Result(Err(e)) => {
12709 log::error!("Error during workspace diagnostics pull: {e:#}");
12710 break 'request;
12711 }
12712 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12713 attempts = 0;
12714 if lsp_store
12715 .update(cx, |lsp_store, cx| {
12716 lsp_store.apply_workspace_diagnostic_report(
12717 server.server_id(),
12718 pulled_diagnostics,
12719 cx,
12720 )
12721 })
12722 .is_err()
12723 {
12724 return;
12725 }
12726 break 'request;
12727 }
12728 }
12729 }
12730 }
12731 });
12732
12733 Some(WorkspaceRefreshTask {
12734 refresh_tx,
12735 progress_tx,
12736 task: workspace_query_language_server,
12737 })
12738}
12739
12740fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12741 match &options {
12742 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12743 if !diagnostic_options.workspace_diagnostics {
12744 return None;
12745 }
12746 Some(diagnostic_options.identifier.clone())
12747 }
12748 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12749 let diagnostic_options = ®istration_options.diagnostic_options;
12750 if !diagnostic_options.workspace_diagnostics {
12751 return None;
12752 }
12753 Some(diagnostic_options.identifier.clone())
12754 }
12755 }
12756}
12757
12758fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12759 let CompletionSource::BufferWord {
12760 word_range,
12761 resolved,
12762 } = &mut completion.source
12763 else {
12764 return;
12765 };
12766 if *resolved {
12767 return;
12768 }
12769
12770 if completion.new_text
12771 != snapshot
12772 .text_for_range(word_range.clone())
12773 .collect::<String>()
12774 {
12775 return;
12776 }
12777
12778 let mut offset = 0;
12779 for chunk in snapshot.chunks(word_range.clone(), true) {
12780 let end_offset = offset + chunk.text.len();
12781 if let Some(highlight_id) = chunk.syntax_highlight_id {
12782 completion
12783 .label
12784 .runs
12785 .push((offset..end_offset, highlight_id));
12786 }
12787 offset = end_offset;
12788 }
12789 *resolved = true;
12790}
12791
12792impl EventEmitter<LspStoreEvent> for LspStore {}
12793
12794fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12795 hover
12796 .contents
12797 .retain(|hover_block| !hover_block.text.trim().is_empty());
12798 if hover.contents.is_empty() {
12799 None
12800 } else {
12801 Some(hover)
12802 }
12803}
12804
12805async fn populate_labels_for_completions(
12806 new_completions: Vec<CoreCompletion>,
12807 language: Option<Arc<Language>>,
12808 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12809) -> Vec<Completion> {
12810 let lsp_completions = new_completions
12811 .iter()
12812 .filter_map(|new_completion| {
12813 new_completion
12814 .source
12815 .lsp_completion(true)
12816 .map(|lsp_completion| lsp_completion.into_owned())
12817 })
12818 .collect::<Vec<_>>();
12819
12820 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12821 lsp_adapter
12822 .labels_for_completions(&lsp_completions, language)
12823 .await
12824 .log_err()
12825 .unwrap_or_default()
12826 } else {
12827 Vec::new()
12828 }
12829 .into_iter()
12830 .fuse();
12831
12832 let mut completions = Vec::new();
12833 for completion in new_completions {
12834 match completion.source.lsp_completion(true) {
12835 Some(lsp_completion) => {
12836 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12837
12838 let mut label = labels.next().flatten().unwrap_or_else(|| {
12839 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12840 });
12841 ensure_uniform_list_compatible_label(&mut label);
12842 completions.push(Completion {
12843 label,
12844 documentation,
12845 replace_range: completion.replace_range,
12846 new_text: completion.new_text,
12847 insert_text_mode: lsp_completion.insert_text_mode,
12848 source: completion.source,
12849 icon_path: None,
12850 confirm: None,
12851 });
12852 }
12853 None => {
12854 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12855 ensure_uniform_list_compatible_label(&mut label);
12856 completions.push(Completion {
12857 label,
12858 documentation: None,
12859 replace_range: completion.replace_range,
12860 new_text: completion.new_text,
12861 source: completion.source,
12862 insert_text_mode: None,
12863 icon_path: None,
12864 confirm: None,
12865 });
12866 }
12867 }
12868 }
12869 completions
12870}
12871
12872#[derive(Debug)]
12873pub enum LanguageServerToQuery {
12874 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12875 FirstCapable,
12876 /// Query a specific language server.
12877 Other(LanguageServerId),
12878}
12879
12880#[derive(Default)]
12881struct RenamePathsWatchedForServer {
12882 did_rename: Vec<RenameActionPredicate>,
12883 will_rename: Vec<RenameActionPredicate>,
12884}
12885
12886impl RenamePathsWatchedForServer {
12887 fn with_did_rename_patterns(
12888 mut self,
12889 did_rename: Option<&FileOperationRegistrationOptions>,
12890 ) -> Self {
12891 if let Some(did_rename) = did_rename {
12892 self.did_rename = did_rename
12893 .filters
12894 .iter()
12895 .filter_map(|filter| filter.try_into().log_err())
12896 .collect();
12897 }
12898 self
12899 }
12900 fn with_will_rename_patterns(
12901 mut self,
12902 will_rename: Option<&FileOperationRegistrationOptions>,
12903 ) -> Self {
12904 if let Some(will_rename) = will_rename {
12905 self.will_rename = will_rename
12906 .filters
12907 .iter()
12908 .filter_map(|filter| filter.try_into().log_err())
12909 .collect();
12910 }
12911 self
12912 }
12913
12914 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12915 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12916 }
12917 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12918 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12919 }
12920}
12921
12922impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12923 type Error = globset::Error;
12924 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12925 Ok(Self {
12926 kind: ops.pattern.matches.clone(),
12927 glob: GlobBuilder::new(&ops.pattern.glob)
12928 .case_insensitive(
12929 ops.pattern
12930 .options
12931 .as_ref()
12932 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12933 )
12934 .build()?
12935 .compile_matcher(),
12936 })
12937 }
12938}
12939struct RenameActionPredicate {
12940 glob: GlobMatcher,
12941 kind: Option<FileOperationPatternKind>,
12942}
12943
12944impl RenameActionPredicate {
12945 // Returns true if language server should be notified
12946 fn eval(&self, path: &str, is_dir: bool) -> bool {
12947 self.kind.as_ref().is_none_or(|kind| {
12948 let expected_kind = if is_dir {
12949 FileOperationPatternKind::Folder
12950 } else {
12951 FileOperationPatternKind::File
12952 };
12953 kind == &expected_kind
12954 }) && self.glob.is_match(path)
12955 }
12956}
12957
12958#[derive(Default)]
12959struct LanguageServerWatchedPaths {
12960 worktree_paths: HashMap<WorktreeId, GlobSet>,
12961 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12962}
12963
12964#[derive(Default)]
12965struct LanguageServerWatchedPathsBuilder {
12966 worktree_paths: HashMap<WorktreeId, GlobSet>,
12967 abs_paths: HashMap<Arc<Path>, GlobSet>,
12968}
12969
12970impl LanguageServerWatchedPathsBuilder {
12971 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12972 self.worktree_paths.insert(worktree_id, glob_set);
12973 }
12974 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12975 self.abs_paths.insert(path, glob_set);
12976 }
12977 fn build(
12978 self,
12979 fs: Arc<dyn Fs>,
12980 language_server_id: LanguageServerId,
12981 cx: &mut Context<LspStore>,
12982 ) -> LanguageServerWatchedPaths {
12983 let lsp_store = cx.weak_entity();
12984
12985 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12986 let abs_paths = self
12987 .abs_paths
12988 .into_iter()
12989 .map(|(abs_path, globset)| {
12990 let task = cx.spawn({
12991 let abs_path = abs_path.clone();
12992 let fs = fs.clone();
12993
12994 let lsp_store = lsp_store.clone();
12995 async move |_, cx| {
12996 maybe!(async move {
12997 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12998 while let Some(update) = push_updates.0.next().await {
12999 let action = lsp_store
13000 .update(cx, |this, _| {
13001 let Some(local) = this.as_local() else {
13002 return ControlFlow::Break(());
13003 };
13004 let Some(watcher) = local
13005 .language_server_watched_paths
13006 .get(&language_server_id)
13007 else {
13008 return ControlFlow::Break(());
13009 };
13010 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13011 "Watched abs path is not registered with a watcher",
13012 );
13013 let matching_entries = update
13014 .into_iter()
13015 .filter(|event| globs.is_match(&event.path))
13016 .collect::<Vec<_>>();
13017 this.lsp_notify_abs_paths_changed(
13018 language_server_id,
13019 matching_entries,
13020 );
13021 ControlFlow::Continue(())
13022 })
13023 .ok()?;
13024
13025 if action.is_break() {
13026 break;
13027 }
13028 }
13029 Some(())
13030 })
13031 .await;
13032 }
13033 });
13034 (abs_path, (globset, task))
13035 })
13036 .collect();
13037 LanguageServerWatchedPaths {
13038 worktree_paths: self.worktree_paths,
13039 abs_paths,
13040 }
13041 }
13042}
13043
13044struct LspBufferSnapshot {
13045 version: i32,
13046 snapshot: TextBufferSnapshot,
13047}
13048
13049/// A prompt requested by LSP server.
13050#[derive(Clone, Debug)]
13051pub struct LanguageServerPromptRequest {
13052 pub level: PromptLevel,
13053 pub message: String,
13054 pub actions: Vec<MessageActionItem>,
13055 pub lsp_name: String,
13056 pub(crate) response_channel: Sender<MessageActionItem>,
13057}
13058
13059impl LanguageServerPromptRequest {
13060 pub async fn respond(self, index: usize) -> Option<()> {
13061 if let Some(response) = self.actions.into_iter().nth(index) {
13062 self.response_channel.send(response).await.ok()
13063 } else {
13064 None
13065 }
13066 }
13067}
13068impl PartialEq for LanguageServerPromptRequest {
13069 fn eq(&self, other: &Self) -> bool {
13070 self.message == other.message && self.actions == other.actions
13071 }
13072}
13073
13074#[derive(Clone, Debug, PartialEq)]
13075pub enum LanguageServerLogType {
13076 Log(MessageType),
13077 Trace { verbose_info: Option<String> },
13078 Rpc { received: bool },
13079}
13080
13081impl LanguageServerLogType {
13082 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13083 match self {
13084 Self::Log(log_type) => {
13085 use proto::log_message::LogLevel;
13086 let level = match *log_type {
13087 MessageType::ERROR => LogLevel::Error,
13088 MessageType::WARNING => LogLevel::Warning,
13089 MessageType::INFO => LogLevel::Info,
13090 MessageType::LOG => LogLevel::Log,
13091 other => {
13092 log::warn!("Unknown lsp log message type: {other:?}");
13093 LogLevel::Log
13094 }
13095 };
13096 proto::language_server_log::LogType::Log(proto::LogMessage {
13097 level: level as i32,
13098 })
13099 }
13100 Self::Trace { verbose_info } => {
13101 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13102 verbose_info: verbose_info.to_owned(),
13103 })
13104 }
13105 Self::Rpc { received } => {
13106 let kind = if *received {
13107 proto::rpc_message::Kind::Received
13108 } else {
13109 proto::rpc_message::Kind::Sent
13110 };
13111 let kind = kind as i32;
13112 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13113 }
13114 }
13115 }
13116
13117 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13118 use proto::log_message::LogLevel;
13119 use proto::rpc_message;
13120 match log_type {
13121 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13122 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13123 LogLevel::Error => MessageType::ERROR,
13124 LogLevel::Warning => MessageType::WARNING,
13125 LogLevel::Info => MessageType::INFO,
13126 LogLevel::Log => MessageType::LOG,
13127 },
13128 ),
13129 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13130 verbose_info: trace_message.verbose_info,
13131 },
13132 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13133 received: match rpc_message::Kind::from_i32(message.kind)
13134 .unwrap_or(rpc_message::Kind::Received)
13135 {
13136 rpc_message::Kind::Received => true,
13137 rpc_message::Kind::Sent => false,
13138 },
13139 },
13140 }
13141 }
13142}
13143
13144pub struct WorkspaceRefreshTask {
13145 refresh_tx: mpsc::Sender<()>,
13146 progress_tx: mpsc::Sender<()>,
13147 #[allow(dead_code)]
13148 task: Task<()>,
13149}
13150
13151pub enum LanguageServerState {
13152 Starting {
13153 startup: Task<Option<Arc<LanguageServer>>>,
13154 /// List of language servers that will be added to the workspace once it's initialization completes.
13155 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13156 },
13157
13158 Running {
13159 adapter: Arc<CachedLspAdapter>,
13160 server: Arc<LanguageServer>,
13161 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13162 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13163 },
13164}
13165
13166impl LanguageServerState {
13167 fn add_workspace_folder(&self, uri: Uri) {
13168 match self {
13169 LanguageServerState::Starting {
13170 pending_workspace_folders,
13171 ..
13172 } => {
13173 pending_workspace_folders.lock().insert(uri);
13174 }
13175 LanguageServerState::Running { server, .. } => {
13176 server.add_workspace_folder(uri);
13177 }
13178 }
13179 }
13180 fn _remove_workspace_folder(&self, uri: Uri) {
13181 match self {
13182 LanguageServerState::Starting {
13183 pending_workspace_folders,
13184 ..
13185 } => {
13186 pending_workspace_folders.lock().remove(&uri);
13187 }
13188 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13189 }
13190 }
13191}
13192
13193impl std::fmt::Debug for LanguageServerState {
13194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13195 match self {
13196 LanguageServerState::Starting { .. } => {
13197 f.debug_struct("LanguageServerState::Starting").finish()
13198 }
13199 LanguageServerState::Running { .. } => {
13200 f.debug_struct("LanguageServerState::Running").finish()
13201 }
13202 }
13203 }
13204}
13205
13206#[derive(Clone, Debug, Serialize)]
13207pub struct LanguageServerProgress {
13208 pub is_disk_based_diagnostics_progress: bool,
13209 pub is_cancellable: bool,
13210 pub title: Option<String>,
13211 pub message: Option<String>,
13212 pub percentage: Option<usize>,
13213 #[serde(skip_serializing)]
13214 pub last_update_at: Instant,
13215}
13216
13217#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13218pub struct DiagnosticSummary {
13219 pub error_count: usize,
13220 pub warning_count: usize,
13221}
13222
13223impl DiagnosticSummary {
13224 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13225 let mut this = Self {
13226 error_count: 0,
13227 warning_count: 0,
13228 };
13229
13230 for entry in diagnostics {
13231 if entry.diagnostic.is_primary {
13232 match entry.diagnostic.severity {
13233 DiagnosticSeverity::ERROR => this.error_count += 1,
13234 DiagnosticSeverity::WARNING => this.warning_count += 1,
13235 _ => {}
13236 }
13237 }
13238 }
13239
13240 this
13241 }
13242
13243 pub fn is_empty(&self) -> bool {
13244 self.error_count == 0 && self.warning_count == 0
13245 }
13246
13247 pub fn to_proto(
13248 self,
13249 language_server_id: LanguageServerId,
13250 path: &RelPath,
13251 ) -> proto::DiagnosticSummary {
13252 proto::DiagnosticSummary {
13253 path: path.to_proto(),
13254 language_server_id: language_server_id.0 as u64,
13255 error_count: self.error_count as u32,
13256 warning_count: self.warning_count as u32,
13257 }
13258 }
13259}
13260
13261#[derive(Clone, Debug)]
13262pub enum CompletionDocumentation {
13263 /// There is no documentation for this completion.
13264 Undocumented,
13265 /// A single line of documentation.
13266 SingleLine(SharedString),
13267 /// Multiple lines of plain text documentation.
13268 MultiLinePlainText(SharedString),
13269 /// Markdown documentation.
13270 MultiLineMarkdown(SharedString),
13271 /// Both single line and multiple lines of plain text documentation.
13272 SingleLineAndMultiLinePlainText {
13273 single_line: SharedString,
13274 plain_text: Option<SharedString>,
13275 },
13276}
13277
13278impl CompletionDocumentation {
13279 #[cfg(any(test, feature = "test-support"))]
13280 pub fn text(&self) -> SharedString {
13281 match self {
13282 CompletionDocumentation::Undocumented => "".into(),
13283 CompletionDocumentation::SingleLine(s) => s.clone(),
13284 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13285 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13286 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13287 single_line.clone()
13288 }
13289 }
13290 }
13291}
13292
13293impl From<lsp::Documentation> for CompletionDocumentation {
13294 fn from(docs: lsp::Documentation) -> Self {
13295 match docs {
13296 lsp::Documentation::String(text) => {
13297 if text.lines().count() <= 1 {
13298 CompletionDocumentation::SingleLine(text.into())
13299 } else {
13300 CompletionDocumentation::MultiLinePlainText(text.into())
13301 }
13302 }
13303
13304 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13305 lsp::MarkupKind::PlainText => {
13306 if value.lines().count() <= 1 {
13307 CompletionDocumentation::SingleLine(value.into())
13308 } else {
13309 CompletionDocumentation::MultiLinePlainText(value.into())
13310 }
13311 }
13312
13313 lsp::MarkupKind::Markdown => {
13314 CompletionDocumentation::MultiLineMarkdown(value.into())
13315 }
13316 },
13317 }
13318 }
13319}
13320
13321pub enum ResolvedHint {
13322 Resolved(InlayHint),
13323 Resolving(Shared<Task<()>>),
13324}
13325
13326fn glob_literal_prefix(glob: &Path) -> PathBuf {
13327 glob.components()
13328 .take_while(|component| match component {
13329 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13330 _ => true,
13331 })
13332 .collect()
13333}
13334
13335pub struct SshLspAdapter {
13336 name: LanguageServerName,
13337 binary: LanguageServerBinary,
13338 initialization_options: Option<String>,
13339 code_action_kinds: Option<Vec<CodeActionKind>>,
13340}
13341
13342impl SshLspAdapter {
13343 pub fn new(
13344 name: LanguageServerName,
13345 binary: LanguageServerBinary,
13346 initialization_options: Option<String>,
13347 code_action_kinds: Option<String>,
13348 ) -> Self {
13349 Self {
13350 name,
13351 binary,
13352 initialization_options,
13353 code_action_kinds: code_action_kinds
13354 .as_ref()
13355 .and_then(|c| serde_json::from_str(c).ok()),
13356 }
13357 }
13358}
13359
13360impl LspInstaller for SshLspAdapter {
13361 type BinaryVersion = ();
13362 async fn check_if_user_installed(
13363 &self,
13364 _: &dyn LspAdapterDelegate,
13365 _: Option<Toolchain>,
13366 _: &AsyncApp,
13367 ) -> Option<LanguageServerBinary> {
13368 Some(self.binary.clone())
13369 }
13370
13371 async fn cached_server_binary(
13372 &self,
13373 _: PathBuf,
13374 _: &dyn LspAdapterDelegate,
13375 ) -> Option<LanguageServerBinary> {
13376 None
13377 }
13378
13379 async fn fetch_latest_server_version(
13380 &self,
13381 _: &dyn LspAdapterDelegate,
13382 _: bool,
13383 _: &mut AsyncApp,
13384 ) -> Result<()> {
13385 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13386 }
13387
13388 async fn fetch_server_binary(
13389 &self,
13390 _: (),
13391 _: PathBuf,
13392 _: &dyn LspAdapterDelegate,
13393 ) -> Result<LanguageServerBinary> {
13394 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13395 }
13396}
13397
13398#[async_trait(?Send)]
13399impl LspAdapter for SshLspAdapter {
13400 fn name(&self) -> LanguageServerName {
13401 self.name.clone()
13402 }
13403
13404 async fn initialization_options(
13405 self: Arc<Self>,
13406 _: &Arc<dyn LspAdapterDelegate>,
13407 ) -> Result<Option<serde_json::Value>> {
13408 let Some(options) = &self.initialization_options else {
13409 return Ok(None);
13410 };
13411 let result = serde_json::from_str(options)?;
13412 Ok(result)
13413 }
13414
13415 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13416 self.code_action_kinds.clone()
13417 }
13418}
13419
13420pub fn language_server_settings<'a>(
13421 delegate: &'a dyn LspAdapterDelegate,
13422 language: &LanguageServerName,
13423 cx: &'a App,
13424) -> Option<&'a LspSettings> {
13425 language_server_settings_for(
13426 SettingsLocation {
13427 worktree_id: delegate.worktree_id(),
13428 path: RelPath::empty(),
13429 },
13430 language,
13431 cx,
13432 )
13433}
13434
13435pub(crate) fn language_server_settings_for<'a>(
13436 location: SettingsLocation<'a>,
13437 language: &LanguageServerName,
13438 cx: &'a App,
13439) -> Option<&'a LspSettings> {
13440 ProjectSettings::get(Some(location), cx).lsp.get(language)
13441}
13442
13443pub struct LocalLspAdapterDelegate {
13444 lsp_store: WeakEntity<LspStore>,
13445 worktree: worktree::Snapshot,
13446 fs: Arc<dyn Fs>,
13447 http_client: Arc<dyn HttpClient>,
13448 language_registry: Arc<LanguageRegistry>,
13449 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13450}
13451
13452impl LocalLspAdapterDelegate {
13453 pub fn new(
13454 language_registry: Arc<LanguageRegistry>,
13455 environment: &Entity<ProjectEnvironment>,
13456 lsp_store: WeakEntity<LspStore>,
13457 worktree: &Entity<Worktree>,
13458 http_client: Arc<dyn HttpClient>,
13459 fs: Arc<dyn Fs>,
13460 cx: &mut App,
13461 ) -> Arc<Self> {
13462 let load_shell_env_task =
13463 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13464
13465 Arc::new(Self {
13466 lsp_store,
13467 worktree: worktree.read(cx).snapshot(),
13468 fs,
13469 http_client,
13470 language_registry,
13471 load_shell_env_task,
13472 })
13473 }
13474
13475 fn from_local_lsp(
13476 local: &LocalLspStore,
13477 worktree: &Entity<Worktree>,
13478 cx: &mut App,
13479 ) -> Arc<Self> {
13480 Self::new(
13481 local.languages.clone(),
13482 &local.environment,
13483 local.weak.clone(),
13484 worktree,
13485 local.http_client.clone(),
13486 local.fs.clone(),
13487 cx,
13488 )
13489 }
13490}
13491
13492#[async_trait]
13493impl LspAdapterDelegate for LocalLspAdapterDelegate {
13494 fn show_notification(&self, message: &str, cx: &mut App) {
13495 self.lsp_store
13496 .update(cx, |_, cx| {
13497 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13498 })
13499 .ok();
13500 }
13501
13502 fn http_client(&self) -> Arc<dyn HttpClient> {
13503 self.http_client.clone()
13504 }
13505
13506 fn worktree_id(&self) -> WorktreeId {
13507 self.worktree.id()
13508 }
13509
13510 fn worktree_root_path(&self) -> &Path {
13511 self.worktree.abs_path().as_ref()
13512 }
13513
13514 async fn shell_env(&self) -> HashMap<String, String> {
13515 let task = self.load_shell_env_task.clone();
13516 task.await.unwrap_or_default()
13517 }
13518
13519 async fn npm_package_installed_version(
13520 &self,
13521 package_name: &str,
13522 ) -> Result<Option<(PathBuf, String)>> {
13523 let local_package_directory = self.worktree_root_path();
13524 let node_modules_directory = local_package_directory.join("node_modules");
13525
13526 if let Some(version) =
13527 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13528 {
13529 return Ok(Some((node_modules_directory, version)));
13530 }
13531 let Some(npm) = self.which("npm".as_ref()).await else {
13532 log::warn!(
13533 "Failed to find npm executable for {:?}",
13534 local_package_directory
13535 );
13536 return Ok(None);
13537 };
13538
13539 let env = self.shell_env().await;
13540 let output = util::command::new_smol_command(&npm)
13541 .args(["root", "-g"])
13542 .envs(env)
13543 .current_dir(local_package_directory)
13544 .output()
13545 .await?;
13546 let global_node_modules =
13547 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13548
13549 if let Some(version) =
13550 read_package_installed_version(global_node_modules.clone(), package_name).await?
13551 {
13552 return Ok(Some((global_node_modules, version)));
13553 }
13554 return Ok(None);
13555 }
13556
13557 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13558 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13559 if self.fs.is_file(&worktree_abs_path).await {
13560 worktree_abs_path.pop();
13561 }
13562
13563 let env = self.shell_env().await;
13564
13565 let shell_path = env.get("PATH").cloned();
13566
13567 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13568 }
13569
13570 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13571 let mut working_dir = self.worktree_root_path().to_path_buf();
13572 if self.fs.is_file(&working_dir).await {
13573 working_dir.pop();
13574 }
13575 let output = util::command::new_smol_command(&command.path)
13576 .args(command.arguments)
13577 .envs(command.env.clone().unwrap_or_default())
13578 .current_dir(working_dir)
13579 .output()
13580 .await?;
13581
13582 anyhow::ensure!(
13583 output.status.success(),
13584 "{}, stdout: {:?}, stderr: {:?}",
13585 output.status,
13586 String::from_utf8_lossy(&output.stdout),
13587 String::from_utf8_lossy(&output.stderr)
13588 );
13589 Ok(())
13590 }
13591
13592 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13593 self.language_registry
13594 .update_lsp_binary_status(server_name, status);
13595 }
13596
13597 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13598 self.language_registry
13599 .all_lsp_adapters()
13600 .into_iter()
13601 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13602 .collect()
13603 }
13604
13605 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13606 let dir = self.language_registry.language_server_download_dir(name)?;
13607
13608 if !dir.exists() {
13609 smol::fs::create_dir_all(&dir)
13610 .await
13611 .context("failed to create container directory")
13612 .log_err()?;
13613 }
13614
13615 Some(dir)
13616 }
13617
13618 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13619 let entry = self
13620 .worktree
13621 .entry_for_path(path)
13622 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13623 let abs_path = self.worktree.absolutize(&entry.path);
13624 self.fs.load(&abs_path).await
13625 }
13626}
13627
13628async fn populate_labels_for_symbols(
13629 symbols: Vec<CoreSymbol>,
13630 language_registry: &Arc<LanguageRegistry>,
13631 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13632 output: &mut Vec<Symbol>,
13633) {
13634 #[allow(clippy::mutable_key_type)]
13635 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13636
13637 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13638 for symbol in symbols {
13639 let Some(file_name) = symbol.path.file_name() else {
13640 continue;
13641 };
13642 let language = language_registry
13643 .load_language_for_file_path(Path::new(file_name))
13644 .await
13645 .ok()
13646 .or_else(|| {
13647 unknown_paths.insert(file_name.into());
13648 None
13649 });
13650 symbols_by_language
13651 .entry(language)
13652 .or_default()
13653 .push(symbol);
13654 }
13655
13656 for unknown_path in unknown_paths {
13657 log::info!("no language found for symbol in file {unknown_path:?}");
13658 }
13659
13660 let mut label_params = Vec::new();
13661 for (language, mut symbols) in symbols_by_language {
13662 label_params.clear();
13663 label_params.extend(
13664 symbols
13665 .iter_mut()
13666 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13667 );
13668
13669 let mut labels = Vec::new();
13670 if let Some(language) = language {
13671 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13672 language_registry
13673 .lsp_adapters(&language.name())
13674 .first()
13675 .cloned()
13676 });
13677 if let Some(lsp_adapter) = lsp_adapter {
13678 labels = lsp_adapter
13679 .labels_for_symbols(&label_params, &language)
13680 .await
13681 .log_err()
13682 .unwrap_or_default();
13683 }
13684 }
13685
13686 for ((symbol, (name, _)), label) in symbols
13687 .into_iter()
13688 .zip(label_params.drain(..))
13689 .zip(labels.into_iter().chain(iter::repeat(None)))
13690 {
13691 output.push(Symbol {
13692 language_server_name: symbol.language_server_name,
13693 source_worktree_id: symbol.source_worktree_id,
13694 source_language_server_id: symbol.source_language_server_id,
13695 path: symbol.path,
13696 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13697 name,
13698 kind: symbol.kind,
13699 range: symbol.range,
13700 });
13701 }
13702 }
13703}
13704
13705fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13706 match server.capabilities().text_document_sync.as_ref()? {
13707 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13708 // Server wants didSave but didn't specify includeText.
13709 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13710 // Server doesn't want didSave at all.
13711 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13712 // Server provided SaveOptions.
13713 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13714 Some(save_options.include_text.unwrap_or(false))
13715 }
13716 },
13717 // We do not have any save info. Kind affects didChange only.
13718 lsp::TextDocumentSyncCapability::Kind(_) => None,
13719 }
13720}
13721
13722/// Completion items are displayed in a `UniformList`.
13723/// Usually, those items are single-line strings, but in LSP responses,
13724/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13725/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13726/// 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,
13727/// breaking the completions menu presentation.
13728///
13729/// 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.
13730fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13731 let mut new_text = String::with_capacity(label.text.len());
13732 let mut offset_map = vec![0; label.text.len() + 1];
13733 let mut last_char_was_space = false;
13734 let mut new_idx = 0;
13735 let chars = label.text.char_indices().fuse();
13736 let mut newlines_removed = false;
13737
13738 for (idx, c) in chars {
13739 offset_map[idx] = new_idx;
13740
13741 match c {
13742 '\n' if last_char_was_space => {
13743 newlines_removed = true;
13744 }
13745 '\t' | ' ' if last_char_was_space => {}
13746 '\n' if !last_char_was_space => {
13747 new_text.push(' ');
13748 new_idx += 1;
13749 last_char_was_space = true;
13750 newlines_removed = true;
13751 }
13752 ' ' | '\t' => {
13753 new_text.push(' ');
13754 new_idx += 1;
13755 last_char_was_space = true;
13756 }
13757 _ => {
13758 new_text.push(c);
13759 new_idx += c.len_utf8();
13760 last_char_was_space = false;
13761 }
13762 }
13763 }
13764 offset_map[label.text.len()] = new_idx;
13765
13766 // Only modify the label if newlines were removed.
13767 if !newlines_removed {
13768 return;
13769 }
13770
13771 let last_index = new_idx;
13772 let mut run_ranges_errors = Vec::new();
13773 label.runs.retain_mut(|(range, _)| {
13774 match offset_map.get(range.start) {
13775 Some(&start) => range.start = start,
13776 None => {
13777 run_ranges_errors.push(range.clone());
13778 return false;
13779 }
13780 }
13781
13782 match offset_map.get(range.end) {
13783 Some(&end) => range.end = end,
13784 None => {
13785 run_ranges_errors.push(range.clone());
13786 range.end = last_index;
13787 }
13788 }
13789 true
13790 });
13791 if !run_ranges_errors.is_empty() {
13792 log::error!(
13793 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13794 label.text
13795 );
13796 }
13797
13798 let mut wrong_filter_range = None;
13799 if label.filter_range == (0..label.text.len()) {
13800 label.filter_range = 0..new_text.len();
13801 } else {
13802 let mut original_filter_range = Some(label.filter_range.clone());
13803 match offset_map.get(label.filter_range.start) {
13804 Some(&start) => label.filter_range.start = start,
13805 None => {
13806 wrong_filter_range = original_filter_range.take();
13807 label.filter_range.start = last_index;
13808 }
13809 }
13810
13811 match offset_map.get(label.filter_range.end) {
13812 Some(&end) => label.filter_range.end = end,
13813 None => {
13814 wrong_filter_range = original_filter_range.take();
13815 label.filter_range.end = last_index;
13816 }
13817 }
13818 }
13819 if let Some(wrong_filter_range) = wrong_filter_range {
13820 log::error!(
13821 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13822 label.text
13823 );
13824 }
13825
13826 label.text = new_text;
13827}
13828
13829#[cfg(test)]
13830mod tests {
13831 use language::HighlightId;
13832
13833 use super::*;
13834
13835 #[test]
13836 fn test_glob_literal_prefix() {
13837 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13838 assert_eq!(
13839 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13840 Path::new("node_modules")
13841 );
13842 assert_eq!(
13843 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13844 Path::new("foo")
13845 );
13846 assert_eq!(
13847 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13848 Path::new("foo/bar/baz.js")
13849 );
13850
13851 #[cfg(target_os = "windows")]
13852 {
13853 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13854 assert_eq!(
13855 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13856 Path::new("node_modules")
13857 );
13858 assert_eq!(
13859 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13860 Path::new("foo")
13861 );
13862 assert_eq!(
13863 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13864 Path::new("foo/bar/baz.js")
13865 );
13866 }
13867 }
13868
13869 #[test]
13870 fn test_multi_len_chars_normalization() {
13871 let mut label = CodeLabel::new(
13872 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13873 0..6,
13874 vec![(0..6, HighlightId(1))],
13875 );
13876 ensure_uniform_list_compatible_label(&mut label);
13877 assert_eq!(
13878 label,
13879 CodeLabel::new(
13880 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13881 0..6,
13882 vec![(0..6, HighlightId(1))],
13883 )
13884 );
13885 }
13886}