1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default, Debug)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = &settings.binary
567 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
568 {
569 let settings = settings.clone();
570
571 return cx.background_spawn(async move {
572 let mut env = delegate.shell_env().await;
573 env.extend(settings.env.unwrap_or_default());
574
575 Ok(LanguageServerBinary {
576 // if `path` is absolute, `.join()` will keep it unmodified
577 path: delegate.worktree_root_path().join(path),
578 env: Some(env),
579 arguments: settings
580 .arguments
581 .unwrap_or_default()
582 .iter()
583 .map(Into::into)
584 .collect(),
585 })
586 });
587 }
588 let lsp_binary_options = LanguageServerBinaryOptions {
589 allow_path_lookup: !settings
590 .binary
591 .as_ref()
592 .and_then(|b| b.ignore_system_version)
593 .unwrap_or_default(),
594 allow_binary_download,
595 pre_release: settings
596 .fetch
597 .as_ref()
598 .and_then(|f| f.pre_release)
599 .unwrap_or(false),
600 };
601
602 cx.spawn(async move |cx| {
603 let binary_result = adapter
604 .clone()
605 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
606 .await;
607
608 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
609
610 let mut binary = binary_result?;
611 let mut shell_env = delegate.shell_env().await;
612
613 shell_env.extend(binary.env.unwrap_or_default());
614
615 if let Some(settings) = settings.binary.as_ref() {
616 if let Some(arguments) = &settings.arguments {
617 binary.arguments = arguments.iter().map(Into::into).collect();
618 }
619 if let Some(env) = &settings.env {
620 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
621 }
622 }
623
624 binary.env = Some(shell_env);
625 Ok(binary)
626 })
627 }
628
629 fn setup_lsp_messages(
630 lsp_store: WeakEntity<LspStore>,
631 language_server: &LanguageServer,
632 delegate: Arc<dyn LspAdapterDelegate>,
633 adapter: Arc<CachedLspAdapter>,
634 ) {
635 let name = language_server.name();
636 let server_id = language_server.server_id();
637 language_server
638 .on_notification::<lsp::notification::PublishDiagnostics, _>({
639 let adapter = adapter.clone();
640 let this = lsp_store.clone();
641 move |mut params, cx| {
642 let adapter = adapter.clone();
643 if let Some(this) = this.upgrade() {
644 this.update(cx, |this, cx| {
645 {
646 let buffer = params
647 .uri
648 .to_file_path()
649 .map(|file_path| this.get_buffer(&file_path, cx))
650 .ok()
651 .flatten();
652 adapter.process_diagnostics(&mut params, server_id, buffer);
653 }
654
655 this.merge_lsp_diagnostics(
656 DiagnosticSourceKind::Pushed,
657 vec![DocumentDiagnosticsUpdate {
658 server_id,
659 diagnostics: params,
660 result_id: None,
661 disk_based_sources: Cow::Borrowed(
662 &adapter.disk_based_diagnostic_sources,
663 ),
664 }],
665 |_, diagnostic, cx| match diagnostic.source_kind {
666 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
667 adapter.retain_old_diagnostic(diagnostic, cx)
668 }
669 DiagnosticSourceKind::Pulled => true,
670 },
671 cx,
672 )
673 .log_err();
674 })
675 .ok();
676 }
677 }
678 })
679 .detach();
680 language_server
681 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
682 let adapter = adapter.adapter.clone();
683 let delegate = delegate.clone();
684 let this = lsp_store.clone();
685 move |params, cx| {
686 let adapter = adapter.clone();
687 let delegate = delegate.clone();
688 let this = this.clone();
689 let mut cx = cx.clone();
690 async move {
691 let toolchain_for_id = this
692 .update(&mut cx, |this, _| {
693 this.as_local()?.language_server_ids.iter().find_map(
694 |(seed, value)| {
695 (value.id == server_id).then(|| seed.toolchain.clone())
696 },
697 )
698 })?
699 .context("Expected the LSP store to be in a local mode")?;
700 let workspace_config = Self::workspace_configuration_for_adapter(
701 adapter.clone(),
702 &delegate,
703 toolchain_for_id,
704 &mut cx,
705 )
706 .await?;
707
708 Ok(params
709 .items
710 .into_iter()
711 .map(|item| {
712 if let Some(section) = &item.section {
713 workspace_config
714 .get(section)
715 .cloned()
716 .unwrap_or(serde_json::Value::Null)
717 } else {
718 workspace_config.clone()
719 }
720 })
721 .collect())
722 }
723 }
724 })
725 .detach();
726
727 language_server
728 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
729 let this = lsp_store.clone();
730 move |_, cx| {
731 let this = this.clone();
732 let cx = cx.clone();
733 async move {
734 let Some(server) =
735 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
736 else {
737 return Ok(None);
738 };
739 let root = server.workspace_folders();
740 Ok(Some(
741 root.into_iter()
742 .map(|uri| WorkspaceFolder {
743 uri,
744 name: Default::default(),
745 })
746 .collect(),
747 ))
748 }
749 }
750 })
751 .detach();
752 // Even though we don't have handling for these requests, respond to them to
753 // avoid stalling any language server like `gopls` which waits for a response
754 // to these requests when initializing.
755 language_server
756 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
757 let this = lsp_store.clone();
758 move |params, cx| {
759 let this = this.clone();
760 let mut cx = cx.clone();
761 async move {
762 this.update(&mut cx, |this, _| {
763 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
764 {
765 status
766 .progress_tokens
767 .insert(ProgressToken::from_lsp(params.token));
768 }
769 })?;
770
771 Ok(())
772 }
773 }
774 })
775 .detach();
776
777 language_server
778 .on_request::<lsp::request::RegisterCapability, _, _>({
779 let lsp_store = lsp_store.clone();
780 move |params, cx| {
781 let lsp_store = lsp_store.clone();
782 let mut cx = cx.clone();
783 async move {
784 lsp_store
785 .update(&mut cx, |lsp_store, cx| {
786 if lsp_store.as_local().is_some() {
787 match lsp_store
788 .register_server_capabilities(server_id, params, cx)
789 {
790 Ok(()) => {}
791 Err(e) => {
792 log::error!(
793 "Failed to register server capabilities: {e:#}"
794 );
795 }
796 };
797 }
798 })
799 .ok();
800 Ok(())
801 }
802 }
803 })
804 .detach();
805
806 language_server
807 .on_request::<lsp::request::UnregisterCapability, _, _>({
808 let lsp_store = lsp_store.clone();
809 move |params, cx| {
810 let lsp_store = lsp_store.clone();
811 let mut cx = cx.clone();
812 async move {
813 lsp_store
814 .update(&mut cx, |lsp_store, cx| {
815 if lsp_store.as_local().is_some() {
816 match lsp_store
817 .unregister_server_capabilities(server_id, params, cx)
818 {
819 Ok(()) => {}
820 Err(e) => {
821 log::error!(
822 "Failed to unregister server capabilities: {e:#}"
823 );
824 }
825 }
826 }
827 })
828 .ok();
829 Ok(())
830 }
831 }
832 })
833 .detach();
834
835 language_server
836 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
837 let this = lsp_store.clone();
838 move |params, cx| {
839 let mut cx = cx.clone();
840 let this = this.clone();
841 async move {
842 LocalLspStore::on_lsp_workspace_edit(
843 this.clone(),
844 params,
845 server_id,
846 &mut cx,
847 )
848 .await
849 }
850 }
851 })
852 .detach();
853
854 language_server
855 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
856 let lsp_store = lsp_store.clone();
857 let request_id = Arc::new(AtomicUsize::new(0));
858 move |(), cx| {
859 let lsp_store = lsp_store.clone();
860 let request_id = request_id.clone();
861 let mut cx = cx.clone();
862 async move {
863 lsp_store
864 .update(&mut cx, |lsp_store, cx| {
865 let request_id =
866 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
867 cx.emit(LspStoreEvent::RefreshInlayHints {
868 server_id,
869 request_id,
870 });
871 lsp_store
872 .downstream_client
873 .as_ref()
874 .map(|(client, project_id)| {
875 client.send(proto::RefreshInlayHints {
876 project_id: *project_id,
877 server_id: server_id.to_proto(),
878 request_id: request_id.map(|id| id as u64),
879 })
880 })
881 })?
882 .transpose()?;
883 Ok(())
884 }
885 }
886 })
887 .detach();
888
889 language_server
890 .on_request::<lsp::request::CodeLensRefresh, _, _>({
891 let this = lsp_store.clone();
892 move |(), cx| {
893 let this = this.clone();
894 let mut cx = cx.clone();
895 async move {
896 this.update(&mut cx, |this, cx| {
897 cx.emit(LspStoreEvent::RefreshCodeLens);
898 this.downstream_client.as_ref().map(|(client, project_id)| {
899 client.send(proto::RefreshCodeLens {
900 project_id: *project_id,
901 })
902 })
903 })?
904 .transpose()?;
905 Ok(())
906 }
907 }
908 })
909 .detach();
910
911 language_server
912 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
913 let this = lsp_store.clone();
914 move |(), cx| {
915 let this = this.clone();
916 let mut cx = cx.clone();
917 async move {
918 this.update(&mut cx, |lsp_store, _| {
919 lsp_store.pull_workspace_diagnostics(server_id);
920 lsp_store
921 .downstream_client
922 .as_ref()
923 .map(|(client, project_id)| {
924 client.send(proto::PullWorkspaceDiagnostics {
925 project_id: *project_id,
926 server_id: server_id.to_proto(),
927 })
928 })
929 })?
930 .transpose()?;
931 Ok(())
932 }
933 }
934 })
935 .detach();
936
937 language_server
938 .on_request::<lsp::request::ShowMessageRequest, _, _>({
939 let this = lsp_store.clone();
940 let name = name.to_string();
941 move |params, cx| {
942 let this = this.clone();
943 let name = name.to_string();
944 let mut cx = cx.clone();
945 async move {
946 let actions = params.actions.unwrap_or_default();
947 let (tx, rx) = smol::channel::bounded(1);
948 let request = LanguageServerPromptRequest {
949 level: match params.typ {
950 lsp::MessageType::ERROR => PromptLevel::Critical,
951 lsp::MessageType::WARNING => PromptLevel::Warning,
952 _ => PromptLevel::Info,
953 },
954 message: params.message,
955 actions,
956 response_channel: tx,
957 lsp_name: name.clone(),
958 };
959
960 let did_update = this
961 .update(&mut cx, |_, cx| {
962 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
963 })
964 .is_ok();
965 if did_update {
966 let response = rx.recv().await.ok();
967 Ok(response)
968 } else {
969 Ok(None)
970 }
971 }
972 }
973 })
974 .detach();
975 language_server
976 .on_notification::<lsp::notification::ShowMessage, _>({
977 let this = lsp_store.clone();
978 let name = name.to_string();
979 move |params, cx| {
980 let this = this.clone();
981 let name = name.to_string();
982 let mut cx = cx.clone();
983
984 let (tx, _) = smol::channel::bounded(1);
985 let request = LanguageServerPromptRequest {
986 level: match params.typ {
987 lsp::MessageType::ERROR => PromptLevel::Critical,
988 lsp::MessageType::WARNING => PromptLevel::Warning,
989 _ => PromptLevel::Info,
990 },
991 message: params.message,
992 actions: vec![],
993 response_channel: tx,
994 lsp_name: name,
995 };
996
997 let _ = this.update(&mut cx, |_, cx| {
998 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
999 });
1000 }
1001 })
1002 .detach();
1003
1004 let disk_based_diagnostics_progress_token =
1005 adapter.disk_based_diagnostics_progress_token.clone();
1006
1007 language_server
1008 .on_notification::<lsp::notification::Progress, _>({
1009 let this = lsp_store.clone();
1010 move |params, cx| {
1011 if let Some(this) = this.upgrade() {
1012 this.update(cx, |this, cx| {
1013 this.on_lsp_progress(
1014 params,
1015 server_id,
1016 disk_based_diagnostics_progress_token.clone(),
1017 cx,
1018 );
1019 })
1020 .ok();
1021 }
1022 }
1023 })
1024 .detach();
1025
1026 language_server
1027 .on_notification::<lsp::notification::LogMessage, _>({
1028 let this = lsp_store.clone();
1029 move |params, cx| {
1030 if let Some(this) = this.upgrade() {
1031 this.update(cx, |_, cx| {
1032 cx.emit(LspStoreEvent::LanguageServerLog(
1033 server_id,
1034 LanguageServerLogType::Log(params.typ),
1035 params.message,
1036 ));
1037 })
1038 .ok();
1039 }
1040 }
1041 })
1042 .detach();
1043
1044 language_server
1045 .on_notification::<lsp::notification::LogTrace, _>({
1046 let this = lsp_store.clone();
1047 move |params, cx| {
1048 let mut cx = cx.clone();
1049 if let Some(this) = this.upgrade() {
1050 this.update(&mut cx, |_, cx| {
1051 cx.emit(LspStoreEvent::LanguageServerLog(
1052 server_id,
1053 LanguageServerLogType::Trace {
1054 verbose_info: params.verbose,
1055 },
1056 params.message,
1057 ));
1058 })
1059 .ok();
1060 }
1061 }
1062 })
1063 .detach();
1064
1065 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1066 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1067 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1068 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1069 }
1070
1071 fn shutdown_language_servers_on_quit(
1072 &mut self,
1073 _: &mut Context<LspStore>,
1074 ) -> impl Future<Output = ()> + use<> {
1075 let shutdown_futures = self
1076 .language_servers
1077 .drain()
1078 .map(|(_, server_state)| Self::shutdown_server(server_state))
1079 .collect::<Vec<_>>();
1080
1081 async move {
1082 join_all(shutdown_futures).await;
1083 }
1084 }
1085
1086 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1087 match server_state {
1088 LanguageServerState::Running { server, .. } => {
1089 if let Some(shutdown) = server.shutdown() {
1090 shutdown.await;
1091 }
1092 }
1093 LanguageServerState::Starting { startup, .. } => {
1094 if let Some(server) = startup.await
1095 && let Some(shutdown) = server.shutdown()
1096 {
1097 shutdown.await;
1098 }
1099 }
1100 }
1101 Ok(())
1102 }
1103
1104 fn language_servers_for_worktree(
1105 &self,
1106 worktree_id: WorktreeId,
1107 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1108 self.language_server_ids
1109 .iter()
1110 .filter_map(move |(seed, state)| {
1111 if seed.worktree_id != worktree_id {
1112 return None;
1113 }
1114
1115 if let Some(LanguageServerState::Running { server, .. }) =
1116 self.language_servers.get(&state.id)
1117 {
1118 Some(server)
1119 } else {
1120 None
1121 }
1122 })
1123 }
1124
1125 fn language_server_ids_for_project_path(
1126 &self,
1127 project_path: ProjectPath,
1128 language: &Language,
1129 cx: &mut App,
1130 ) -> Vec<LanguageServerId> {
1131 let Some(worktree) = self
1132 .worktree_store
1133 .read(cx)
1134 .worktree_for_id(project_path.worktree_id, cx)
1135 else {
1136 return Vec::new();
1137 };
1138 let delegate: Arc<dyn ManifestDelegate> =
1139 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1140
1141 self.lsp_tree
1142 .get(
1143 project_path,
1144 language.name(),
1145 language.manifest(),
1146 &delegate,
1147 cx,
1148 )
1149 .collect::<Vec<_>>()
1150 }
1151
1152 fn language_server_ids_for_buffer(
1153 &self,
1154 buffer: &Buffer,
1155 cx: &mut App,
1156 ) -> Vec<LanguageServerId> {
1157 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1158 let worktree_id = file.worktree_id(cx);
1159
1160 let path: Arc<RelPath> = file
1161 .path()
1162 .parent()
1163 .map(Arc::from)
1164 .unwrap_or_else(|| file.path().clone());
1165 let worktree_path = ProjectPath { worktree_id, path };
1166 self.language_server_ids_for_project_path(worktree_path, language, cx)
1167 } else {
1168 Vec::new()
1169 }
1170 }
1171
1172 fn language_servers_for_buffer<'a>(
1173 &'a self,
1174 buffer: &'a Buffer,
1175 cx: &'a mut App,
1176 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1177 self.language_server_ids_for_buffer(buffer, cx)
1178 .into_iter()
1179 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1180 LanguageServerState::Running {
1181 adapter, server, ..
1182 } => Some((adapter, server)),
1183 _ => None,
1184 })
1185 }
1186
1187 async fn execute_code_action_kind_locally(
1188 lsp_store: WeakEntity<LspStore>,
1189 mut buffers: Vec<Entity<Buffer>>,
1190 kind: CodeActionKind,
1191 push_to_history: bool,
1192 cx: &mut AsyncApp,
1193 ) -> anyhow::Result<ProjectTransaction> {
1194 // Do not allow multiple concurrent code actions requests for the
1195 // same buffer.
1196 lsp_store.update(cx, |this, cx| {
1197 let this = this.as_local_mut().unwrap();
1198 buffers.retain(|buffer| {
1199 this.buffers_being_formatted
1200 .insert(buffer.read(cx).remote_id())
1201 });
1202 })?;
1203 let _cleanup = defer({
1204 let this = lsp_store.clone();
1205 let mut cx = cx.clone();
1206 let buffers = &buffers;
1207 move || {
1208 this.update(&mut cx, |this, cx| {
1209 let this = this.as_local_mut().unwrap();
1210 for buffer in buffers {
1211 this.buffers_being_formatted
1212 .remove(&buffer.read(cx).remote_id());
1213 }
1214 })
1215 .ok();
1216 }
1217 });
1218 let mut project_transaction = ProjectTransaction::default();
1219
1220 for buffer in &buffers {
1221 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1222 buffer.update(cx, |buffer, cx| {
1223 lsp_store
1224 .as_local()
1225 .unwrap()
1226 .language_servers_for_buffer(buffer, cx)
1227 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1228 .collect::<Vec<_>>()
1229 })
1230 })?;
1231 for (_, language_server) in adapters_and_servers.iter() {
1232 let actions = Self::get_server_code_actions_from_action_kinds(
1233 &lsp_store,
1234 language_server.server_id(),
1235 vec![kind.clone()],
1236 buffer,
1237 cx,
1238 )
1239 .await?;
1240 Self::execute_code_actions_on_server(
1241 &lsp_store,
1242 language_server,
1243 actions,
1244 push_to_history,
1245 &mut project_transaction,
1246 cx,
1247 )
1248 .await?;
1249 }
1250 }
1251 Ok(project_transaction)
1252 }
1253
1254 async fn format_locally(
1255 lsp_store: WeakEntity<LspStore>,
1256 mut buffers: Vec<FormattableBuffer>,
1257 push_to_history: bool,
1258 trigger: FormatTrigger,
1259 logger: zlog::Logger,
1260 cx: &mut AsyncApp,
1261 ) -> anyhow::Result<ProjectTransaction> {
1262 // Do not allow multiple concurrent formatting requests for the
1263 // same buffer.
1264 lsp_store.update(cx, |this, cx| {
1265 let this = this.as_local_mut().unwrap();
1266 buffers.retain(|buffer| {
1267 this.buffers_being_formatted
1268 .insert(buffer.handle.read(cx).remote_id())
1269 });
1270 })?;
1271
1272 let _cleanup = defer({
1273 let this = lsp_store.clone();
1274 let mut cx = cx.clone();
1275 let buffers = &buffers;
1276 move || {
1277 this.update(&mut cx, |this, cx| {
1278 let this = this.as_local_mut().unwrap();
1279 for buffer in buffers {
1280 this.buffers_being_formatted
1281 .remove(&buffer.handle.read(cx).remote_id());
1282 }
1283 })
1284 .ok();
1285 }
1286 });
1287
1288 let mut project_transaction = ProjectTransaction::default();
1289
1290 for buffer in &buffers {
1291 zlog::debug!(
1292 logger =>
1293 "formatting buffer '{:?}'",
1294 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1295 );
1296 // Create an empty transaction to hold all of the formatting edits.
1297 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1298 // ensure no transactions created while formatting are
1299 // grouped with the previous transaction in the history
1300 // based on the transaction group interval
1301 buffer.finalize_last_transaction();
1302 buffer
1303 .start_transaction()
1304 .context("transaction already open")?;
1305 buffer.end_transaction(cx);
1306 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1307 buffer.finalize_last_transaction();
1308 anyhow::Ok(transaction_id)
1309 })??;
1310
1311 let result = Self::format_buffer_locally(
1312 lsp_store.clone(),
1313 buffer,
1314 formatting_transaction_id,
1315 trigger,
1316 logger,
1317 cx,
1318 )
1319 .await;
1320
1321 buffer.handle.update(cx, |buffer, cx| {
1322 let Some(formatting_transaction) =
1323 buffer.get_transaction(formatting_transaction_id).cloned()
1324 else {
1325 zlog::warn!(logger => "no formatting transaction");
1326 return;
1327 };
1328 if formatting_transaction.edit_ids.is_empty() {
1329 zlog::debug!(logger => "no changes made while formatting");
1330 buffer.forget_transaction(formatting_transaction_id);
1331 return;
1332 }
1333 if !push_to_history {
1334 zlog::trace!(logger => "forgetting format transaction");
1335 buffer.forget_transaction(formatting_transaction.id);
1336 }
1337 project_transaction
1338 .0
1339 .insert(cx.entity(), formatting_transaction);
1340 })?;
1341
1342 result?;
1343 }
1344
1345 Ok(project_transaction)
1346 }
1347
1348 async fn format_buffer_locally(
1349 lsp_store: WeakEntity<LspStore>,
1350 buffer: &FormattableBuffer,
1351 formatting_transaction_id: clock::Lamport,
1352 trigger: FormatTrigger,
1353 logger: zlog::Logger,
1354 cx: &mut AsyncApp,
1355 ) -> Result<()> {
1356 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1357 buffer.handle.update(cx, |buffer, cx| {
1358 let adapters_and_servers = lsp_store
1359 .as_local()
1360 .unwrap()
1361 .language_servers_for_buffer(buffer, cx)
1362 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1363 .collect::<Vec<_>>();
1364 let settings =
1365 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1366 .into_owned();
1367 (adapters_and_servers, settings)
1368 })
1369 })?;
1370
1371 /// Apply edits to the buffer that will become part of the formatting transaction.
1372 /// Fails if the buffer has been edited since the start of that transaction.
1373 fn extend_formatting_transaction(
1374 buffer: &FormattableBuffer,
1375 formatting_transaction_id: text::TransactionId,
1376 cx: &mut AsyncApp,
1377 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1378 ) -> anyhow::Result<()> {
1379 buffer.handle.update(cx, |buffer, cx| {
1380 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1381 if last_transaction_id != Some(formatting_transaction_id) {
1382 anyhow::bail!("Buffer edited while formatting. Aborting")
1383 }
1384 buffer.start_transaction();
1385 operation(buffer, cx);
1386 if let Some(transaction_id) = buffer.end_transaction(cx) {
1387 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1388 }
1389 Ok(())
1390 })?
1391 }
1392
1393 // handle whitespace formatting
1394 if settings.remove_trailing_whitespace_on_save {
1395 zlog::trace!(logger => "removing trailing whitespace");
1396 let diff = buffer
1397 .handle
1398 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1399 .await;
1400 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1401 buffer.apply_diff(diff, cx);
1402 })?;
1403 }
1404
1405 if settings.ensure_final_newline_on_save {
1406 zlog::trace!(logger => "ensuring final newline");
1407 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1408 buffer.ensure_final_newline(cx);
1409 })?;
1410 }
1411
1412 // Formatter for `code_actions_on_format` that runs before
1413 // the rest of the formatters
1414 let mut code_actions_on_format_formatters = None;
1415 let should_run_code_actions_on_format = !matches!(
1416 (trigger, &settings.format_on_save),
1417 (FormatTrigger::Save, &FormatOnSave::Off)
1418 );
1419 if should_run_code_actions_on_format {
1420 let have_code_actions_to_run_on_format = settings
1421 .code_actions_on_format
1422 .values()
1423 .any(|enabled| *enabled);
1424 if have_code_actions_to_run_on_format {
1425 zlog::trace!(logger => "going to run code actions on format");
1426 code_actions_on_format_formatters = Some(
1427 settings
1428 .code_actions_on_format
1429 .iter()
1430 .filter_map(|(action, enabled)| enabled.then_some(action))
1431 .cloned()
1432 .map(Formatter::CodeAction)
1433 .collect::<Vec<_>>(),
1434 );
1435 }
1436 }
1437
1438 let formatters = match (trigger, &settings.format_on_save) {
1439 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1440 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1441 settings.formatter.as_ref()
1442 }
1443 };
1444
1445 let formatters = code_actions_on_format_formatters
1446 .iter()
1447 .flatten()
1448 .chain(formatters);
1449
1450 for formatter in formatters {
1451 let formatter = if formatter == &Formatter::Auto {
1452 if settings.prettier.allowed {
1453 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1454 &Formatter::Prettier
1455 } else {
1456 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1457 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1458 }
1459 } else {
1460 formatter
1461 };
1462 match formatter {
1463 Formatter::Auto => unreachable!("Auto resolved above"),
1464 Formatter::Prettier => {
1465 let logger = zlog::scoped!(logger => "prettier");
1466 zlog::trace!(logger => "formatting");
1467 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1468
1469 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1470 lsp_store.prettier_store().unwrap().downgrade()
1471 })?;
1472 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1473 .await
1474 .transpose()?;
1475 let Some(diff) = diff else {
1476 zlog::trace!(logger => "No changes");
1477 continue;
1478 };
1479
1480 extend_formatting_transaction(
1481 buffer,
1482 formatting_transaction_id,
1483 cx,
1484 |buffer, cx| {
1485 buffer.apply_diff(diff, cx);
1486 },
1487 )?;
1488 }
1489 Formatter::External { command, arguments } => {
1490 let logger = zlog::scoped!(logger => "command");
1491 zlog::trace!(logger => "formatting");
1492 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1493
1494 let diff = Self::format_via_external_command(
1495 buffer,
1496 command.as_ref(),
1497 arguments.as_deref(),
1498 cx,
1499 )
1500 .await
1501 .with_context(|| {
1502 format!("Failed to format buffer via external command: {}", command)
1503 })?;
1504 let Some(diff) = diff else {
1505 zlog::trace!(logger => "No changes");
1506 continue;
1507 };
1508
1509 extend_formatting_transaction(
1510 buffer,
1511 formatting_transaction_id,
1512 cx,
1513 |buffer, cx| {
1514 buffer.apply_diff(diff, cx);
1515 },
1516 )?;
1517 }
1518 Formatter::LanguageServer(specifier) => {
1519 let logger = zlog::scoped!(logger => "language-server");
1520 zlog::trace!(logger => "formatting");
1521 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1522
1523 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1524 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1525 continue;
1526 };
1527
1528 let language_server = match specifier {
1529 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1530 adapters_and_servers.iter().find_map(|(adapter, server)| {
1531 if adapter.name.0.as_ref() == name {
1532 Some(server.clone())
1533 } else {
1534 None
1535 }
1536 })
1537 }
1538 settings::LanguageServerFormatterSpecifier::Current => {
1539 adapters_and_servers.first().map(|e| e.1.clone())
1540 }
1541 };
1542
1543 let Some(language_server) = language_server else {
1544 log::debug!(
1545 "No language server found to format buffer '{:?}'. Skipping",
1546 buffer_path_abs.as_path().to_string_lossy()
1547 );
1548 continue;
1549 };
1550
1551 zlog::trace!(
1552 logger =>
1553 "Formatting buffer '{:?}' using language server '{:?}'",
1554 buffer_path_abs.as_path().to_string_lossy(),
1555 language_server.name()
1556 );
1557
1558 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1559 zlog::trace!(logger => "formatting ranges");
1560 Self::format_ranges_via_lsp(
1561 &lsp_store,
1562 &buffer.handle,
1563 ranges,
1564 buffer_path_abs,
1565 &language_server,
1566 &settings,
1567 cx,
1568 )
1569 .await
1570 .context("Failed to format ranges via language server")?
1571 } else {
1572 zlog::trace!(logger => "formatting full");
1573 Self::format_via_lsp(
1574 &lsp_store,
1575 &buffer.handle,
1576 buffer_path_abs,
1577 &language_server,
1578 &settings,
1579 cx,
1580 )
1581 .await
1582 .context("failed to format via language server")?
1583 };
1584
1585 if edits.is_empty() {
1586 zlog::trace!(logger => "No changes");
1587 continue;
1588 }
1589 extend_formatting_transaction(
1590 buffer,
1591 formatting_transaction_id,
1592 cx,
1593 |buffer, cx| {
1594 buffer.edit(edits, None, cx);
1595 },
1596 )?;
1597 }
1598 Formatter::CodeAction(code_action_name) => {
1599 let logger = zlog::scoped!(logger => "code-actions");
1600 zlog::trace!(logger => "formatting");
1601 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1602
1603 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1604 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1605 continue;
1606 };
1607
1608 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1609 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1610
1611 let mut actions_and_servers = Vec::new();
1612
1613 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1614 let actions_result = Self::get_server_code_actions_from_action_kinds(
1615 &lsp_store,
1616 language_server.server_id(),
1617 vec![code_action_kind.clone()],
1618 &buffer.handle,
1619 cx,
1620 )
1621 .await
1622 .with_context(|| {
1623 format!(
1624 "Failed to resolve code action {:?} with language server {}",
1625 code_action_kind,
1626 language_server.name()
1627 )
1628 });
1629 let Ok(actions) = actions_result else {
1630 // note: it may be better to set result to the error and break formatters here
1631 // but for now we try to execute the actions that we can resolve and skip the rest
1632 zlog::error!(
1633 logger =>
1634 "Failed to resolve code action {:?} with language server {}",
1635 code_action_kind,
1636 language_server.name()
1637 );
1638 continue;
1639 };
1640 for action in actions {
1641 actions_and_servers.push((action, index));
1642 }
1643 }
1644
1645 if actions_and_servers.is_empty() {
1646 zlog::warn!(logger => "No code actions were resolved, continuing");
1647 continue;
1648 }
1649
1650 'actions: for (mut action, server_index) in actions_and_servers {
1651 let server = &adapters_and_servers[server_index].1;
1652
1653 let describe_code_action = |action: &CodeAction| {
1654 format!(
1655 "code action '{}' with title \"{}\" on server {}",
1656 action
1657 .lsp_action
1658 .action_kind()
1659 .unwrap_or("unknown".into())
1660 .as_str(),
1661 action.lsp_action.title(),
1662 server.name(),
1663 )
1664 };
1665
1666 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1667
1668 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1669 zlog::error!(
1670 logger =>
1671 "Failed to resolve {}. Error: {}",
1672 describe_code_action(&action),
1673 err
1674 );
1675 continue;
1676 }
1677
1678 if let Some(edit) = action.lsp_action.edit().cloned() {
1679 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1680 // but filters out and logs warnings for code actions that require unreasonably
1681 // difficult handling on our part, such as:
1682 // - applying edits that call commands
1683 // which can result in arbitrary workspace edits being sent from the server that
1684 // have no way of being tied back to the command that initiated them (i.e. we
1685 // can't know which edits are part of the format request, or if the server is done sending
1686 // actions in response to the command)
1687 // - actions that create/delete/modify/rename files other than the one we are formatting
1688 // as we then would need to handle such changes correctly in the local history as well
1689 // as the remote history through the ProjectTransaction
1690 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1691 // Supporting these actions is not impossible, but not supported as of yet.
1692 if edit.changes.is_none() && edit.document_changes.is_none() {
1693 zlog::trace!(
1694 logger =>
1695 "No changes for code action. Skipping {}",
1696 describe_code_action(&action),
1697 );
1698 continue;
1699 }
1700
1701 let mut operations = Vec::new();
1702 if let Some(document_changes) = edit.document_changes {
1703 match document_changes {
1704 lsp::DocumentChanges::Edits(edits) => operations.extend(
1705 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1706 ),
1707 lsp::DocumentChanges::Operations(ops) => operations = ops,
1708 }
1709 } else if let Some(changes) = edit.changes {
1710 operations.extend(changes.into_iter().map(|(uri, edits)| {
1711 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1712 text_document:
1713 lsp::OptionalVersionedTextDocumentIdentifier {
1714 uri,
1715 version: None,
1716 },
1717 edits: edits.into_iter().map(Edit::Plain).collect(),
1718 })
1719 }));
1720 }
1721
1722 let mut edits = Vec::with_capacity(operations.len());
1723
1724 if operations.is_empty() {
1725 zlog::trace!(
1726 logger =>
1727 "No changes for code action. Skipping {}",
1728 describe_code_action(&action),
1729 );
1730 continue;
1731 }
1732 for operation in operations {
1733 let op = match operation {
1734 lsp::DocumentChangeOperation::Edit(op) => op,
1735 lsp::DocumentChangeOperation::Op(_) => {
1736 zlog::warn!(
1737 logger =>
1738 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1739 describe_code_action(&action),
1740 );
1741 continue 'actions;
1742 }
1743 };
1744 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1745 zlog::warn!(
1746 logger =>
1747 "Failed to convert URI '{:?}' to file path. Skipping {}",
1748 &op.text_document.uri,
1749 describe_code_action(&action),
1750 );
1751 continue 'actions;
1752 };
1753 if &file_path != buffer_path_abs {
1754 zlog::warn!(
1755 logger =>
1756 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1757 file_path,
1758 buffer_path_abs,
1759 describe_code_action(&action),
1760 );
1761 continue 'actions;
1762 }
1763
1764 let mut lsp_edits = Vec::new();
1765 for edit in op.edits {
1766 match edit {
1767 Edit::Plain(edit) => {
1768 if !lsp_edits.contains(&edit) {
1769 lsp_edits.push(edit);
1770 }
1771 }
1772 Edit::Annotated(edit) => {
1773 if !lsp_edits.contains(&edit.text_edit) {
1774 lsp_edits.push(edit.text_edit);
1775 }
1776 }
1777 Edit::Snippet(_) => {
1778 zlog::warn!(
1779 logger =>
1780 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1781 describe_code_action(&action),
1782 );
1783 continue 'actions;
1784 }
1785 }
1786 }
1787 let edits_result = lsp_store
1788 .update(cx, |lsp_store, cx| {
1789 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1790 &buffer.handle,
1791 lsp_edits,
1792 server.server_id(),
1793 op.text_document.version,
1794 cx,
1795 )
1796 })?
1797 .await;
1798 let Ok(resolved_edits) = edits_result else {
1799 zlog::warn!(
1800 logger =>
1801 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1802 buffer_path_abs.as_path(),
1803 describe_code_action(&action),
1804 );
1805 continue 'actions;
1806 };
1807 edits.extend(resolved_edits);
1808 }
1809
1810 if edits.is_empty() {
1811 zlog::warn!(logger => "No edits resolved from LSP");
1812 continue;
1813 }
1814
1815 extend_formatting_transaction(
1816 buffer,
1817 formatting_transaction_id,
1818 cx,
1819 |buffer, cx| {
1820 zlog::info!(
1821 "Applying edits {edits:?}. Content: {:?}",
1822 buffer.text()
1823 );
1824 buffer.edit(edits, None, cx);
1825 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1826 },
1827 )?;
1828 }
1829
1830 if let Some(command) = action.lsp_action.command() {
1831 zlog::warn!(
1832 logger =>
1833 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1834 &command.command,
1835 );
1836
1837 // bail early if command is invalid
1838 let server_capabilities = server.capabilities();
1839 let available_commands = server_capabilities
1840 .execute_command_provider
1841 .as_ref()
1842 .map(|options| options.commands.as_slice())
1843 .unwrap_or_default();
1844 if !available_commands.contains(&command.command) {
1845 zlog::warn!(
1846 logger =>
1847 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1848 command.command,
1849 server.name(),
1850 );
1851 continue;
1852 }
1853
1854 // noop so we just ensure buffer hasn't been edited since resolving code actions
1855 extend_formatting_transaction(
1856 buffer,
1857 formatting_transaction_id,
1858 cx,
1859 |_, _| {},
1860 )?;
1861 zlog::info!(logger => "Executing command {}", &command.command);
1862
1863 lsp_store.update(cx, |this, _| {
1864 this.as_local_mut()
1865 .unwrap()
1866 .last_workspace_edits_by_language_server
1867 .remove(&server.server_id());
1868 })?;
1869
1870 let execute_command_result = server
1871 .request::<lsp::request::ExecuteCommand>(
1872 lsp::ExecuteCommandParams {
1873 command: command.command.clone(),
1874 arguments: command.arguments.clone().unwrap_or_default(),
1875 ..Default::default()
1876 },
1877 )
1878 .await
1879 .into_response();
1880
1881 if execute_command_result.is_err() {
1882 zlog::error!(
1883 logger =>
1884 "Failed to execute command '{}' as part of {}",
1885 &command.command,
1886 describe_code_action(&action),
1887 );
1888 continue 'actions;
1889 }
1890
1891 let mut project_transaction_command =
1892 lsp_store.update(cx, |this, _| {
1893 this.as_local_mut()
1894 .unwrap()
1895 .last_workspace_edits_by_language_server
1896 .remove(&server.server_id())
1897 .unwrap_or_default()
1898 })?;
1899
1900 if let Some(transaction) =
1901 project_transaction_command.0.remove(&buffer.handle)
1902 {
1903 zlog::trace!(
1904 logger =>
1905 "Successfully captured {} edits that resulted from command {}",
1906 transaction.edit_ids.len(),
1907 &command.command,
1908 );
1909 let transaction_id_project_transaction = transaction.id;
1910 buffer.handle.update(cx, |buffer, _| {
1911 // it may have been removed from history if push_to_history was
1912 // false in deserialize_workspace_edit. If so push it so we
1913 // can merge it with the format transaction
1914 // and pop the combined transaction off the history stack
1915 // later if push_to_history is false
1916 if buffer.get_transaction(transaction.id).is_none() {
1917 buffer.push_transaction(transaction, Instant::now());
1918 }
1919 buffer.merge_transactions(
1920 transaction_id_project_transaction,
1921 formatting_transaction_id,
1922 );
1923 })?;
1924 }
1925
1926 if !project_transaction_command.0.is_empty() {
1927 let mut extra_buffers = String::new();
1928 for buffer in project_transaction_command.0.keys() {
1929 buffer
1930 .read_with(cx, |b, cx| {
1931 if let Some(path) = b.project_path(cx) {
1932 if !extra_buffers.is_empty() {
1933 extra_buffers.push_str(", ");
1934 }
1935 extra_buffers.push_str(path.path.as_unix_str());
1936 }
1937 })
1938 .ok();
1939 }
1940 zlog::warn!(
1941 logger =>
1942 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1943 &command.command,
1944 extra_buffers,
1945 );
1946 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1947 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1948 // add it so it's included, and merge it into the format transaction when its created later
1949 }
1950 }
1951 }
1952 }
1953 }
1954 }
1955
1956 Ok(())
1957 }
1958
1959 pub async fn format_ranges_via_lsp(
1960 this: &WeakEntity<LspStore>,
1961 buffer_handle: &Entity<Buffer>,
1962 ranges: &[Range<Anchor>],
1963 abs_path: &Path,
1964 language_server: &Arc<LanguageServer>,
1965 settings: &LanguageSettings,
1966 cx: &mut AsyncApp,
1967 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1968 let capabilities = &language_server.capabilities();
1969 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1970 if range_formatting_provider == Some(&OneOf::Left(false)) {
1971 anyhow::bail!(
1972 "{} language server does not support range formatting",
1973 language_server.name()
1974 );
1975 }
1976
1977 let uri = file_path_to_lsp_url(abs_path)?;
1978 let text_document = lsp::TextDocumentIdentifier::new(uri);
1979
1980 let lsp_edits = {
1981 let mut lsp_ranges = Vec::new();
1982 this.update(cx, |_this, cx| {
1983 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1984 // not have been sent to the language server. This seems like a fairly systemic
1985 // issue, though, the resolution probably is not specific to formatting.
1986 //
1987 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1988 // LSP.
1989 let snapshot = buffer_handle.read(cx).snapshot();
1990 for range in ranges {
1991 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1992 }
1993 anyhow::Ok(())
1994 })??;
1995
1996 let mut edits = None;
1997 for range in lsp_ranges {
1998 if let Some(mut edit) = language_server
1999 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2000 text_document: text_document.clone(),
2001 range,
2002 options: lsp_command::lsp_formatting_options(settings),
2003 work_done_progress_params: Default::default(),
2004 })
2005 .await
2006 .into_response()?
2007 {
2008 edits.get_or_insert_with(Vec::new).append(&mut edit);
2009 }
2010 }
2011 edits
2012 };
2013
2014 if let Some(lsp_edits) = lsp_edits {
2015 this.update(cx, |this, cx| {
2016 this.as_local_mut().unwrap().edits_from_lsp(
2017 buffer_handle,
2018 lsp_edits,
2019 language_server.server_id(),
2020 None,
2021 cx,
2022 )
2023 })?
2024 .await
2025 } else {
2026 Ok(Vec::with_capacity(0))
2027 }
2028 }
2029
2030 async fn format_via_lsp(
2031 this: &WeakEntity<LspStore>,
2032 buffer: &Entity<Buffer>,
2033 abs_path: &Path,
2034 language_server: &Arc<LanguageServer>,
2035 settings: &LanguageSettings,
2036 cx: &mut AsyncApp,
2037 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2038 let logger = zlog::scoped!("lsp_format");
2039 zlog::debug!(logger => "Formatting via LSP");
2040
2041 let uri = file_path_to_lsp_url(abs_path)?;
2042 let text_document = lsp::TextDocumentIdentifier::new(uri);
2043 let capabilities = &language_server.capabilities();
2044
2045 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2046 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2047
2048 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2049 let _timer = zlog::time!(logger => "format-full");
2050 language_server
2051 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2052 text_document,
2053 options: lsp_command::lsp_formatting_options(settings),
2054 work_done_progress_params: Default::default(),
2055 })
2056 .await
2057 .into_response()?
2058 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2059 let _timer = zlog::time!(logger => "format-range");
2060 let buffer_start = lsp::Position::new(0, 0);
2061 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2062 language_server
2063 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2064 text_document: text_document.clone(),
2065 range: lsp::Range::new(buffer_start, buffer_end),
2066 options: lsp_command::lsp_formatting_options(settings),
2067 work_done_progress_params: Default::default(),
2068 })
2069 .await
2070 .into_response()?
2071 } else {
2072 None
2073 };
2074
2075 if let Some(lsp_edits) = lsp_edits {
2076 this.update(cx, |this, cx| {
2077 this.as_local_mut().unwrap().edits_from_lsp(
2078 buffer,
2079 lsp_edits,
2080 language_server.server_id(),
2081 None,
2082 cx,
2083 )
2084 })?
2085 .await
2086 } else {
2087 Ok(Vec::with_capacity(0))
2088 }
2089 }
2090
2091 async fn format_via_external_command(
2092 buffer: &FormattableBuffer,
2093 command: &str,
2094 arguments: Option<&[String]>,
2095 cx: &mut AsyncApp,
2096 ) -> Result<Option<Diff>> {
2097 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2098 let file = File::from_dyn(buffer.file())?;
2099 let worktree = file.worktree.read(cx);
2100 let mut worktree_path = worktree.abs_path().to_path_buf();
2101 if worktree.root_entry()?.is_file() {
2102 worktree_path.pop();
2103 }
2104 Some(worktree_path)
2105 })?;
2106
2107 let mut child = util::command::new_smol_command(command);
2108
2109 if let Some(buffer_env) = buffer.env.as_ref() {
2110 child.envs(buffer_env);
2111 }
2112
2113 if let Some(working_dir_path) = working_dir_path {
2114 child.current_dir(working_dir_path);
2115 }
2116
2117 if let Some(arguments) = arguments {
2118 child.args(arguments.iter().map(|arg| {
2119 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2120 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2121 } else {
2122 arg.replace("{buffer_path}", "Untitled")
2123 }
2124 }));
2125 }
2126
2127 let mut child = child
2128 .stdin(smol::process::Stdio::piped())
2129 .stdout(smol::process::Stdio::piped())
2130 .stderr(smol::process::Stdio::piped())
2131 .spawn()?;
2132
2133 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2134 let text = buffer
2135 .handle
2136 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2137 for chunk in text.chunks() {
2138 stdin.write_all(chunk.as_bytes()).await?;
2139 }
2140 stdin.flush().await?;
2141
2142 let output = child.output().await?;
2143 anyhow::ensure!(
2144 output.status.success(),
2145 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2146 output.status.code(),
2147 String::from_utf8_lossy(&output.stdout),
2148 String::from_utf8_lossy(&output.stderr),
2149 );
2150
2151 let stdout = String::from_utf8(output.stdout)?;
2152 Ok(Some(
2153 buffer
2154 .handle
2155 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2156 .await,
2157 ))
2158 }
2159
2160 async fn try_resolve_code_action(
2161 lang_server: &LanguageServer,
2162 action: &mut CodeAction,
2163 ) -> anyhow::Result<()> {
2164 match &mut action.lsp_action {
2165 LspAction::Action(lsp_action) => {
2166 if !action.resolved
2167 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2168 && lsp_action.data.is_some()
2169 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2170 {
2171 *lsp_action = Box::new(
2172 lang_server
2173 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2174 .await
2175 .into_response()?,
2176 );
2177 }
2178 }
2179 LspAction::CodeLens(lens) => {
2180 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2181 *lens = lang_server
2182 .request::<lsp::request::CodeLensResolve>(lens.clone())
2183 .await
2184 .into_response()?;
2185 }
2186 }
2187 LspAction::Command(_) => {}
2188 }
2189
2190 action.resolved = true;
2191 anyhow::Ok(())
2192 }
2193
2194 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2195 let buffer = buffer_handle.read(cx);
2196
2197 let file = buffer.file().cloned();
2198
2199 let Some(file) = File::from_dyn(file.as_ref()) else {
2200 return;
2201 };
2202 if !file.is_local() {
2203 return;
2204 }
2205 let path = ProjectPath::from_file(file, cx);
2206 let worktree_id = file.worktree_id(cx);
2207 let language = buffer.language().cloned();
2208
2209 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2210 for (server_id, diagnostics) in
2211 diagnostics.get(file.path()).cloned().unwrap_or_default()
2212 {
2213 self.update_buffer_diagnostics(
2214 buffer_handle,
2215 server_id,
2216 None,
2217 None,
2218 diagnostics,
2219 Vec::new(),
2220 cx,
2221 )
2222 .log_err();
2223 }
2224 }
2225 let Some(language) = language else {
2226 return;
2227 };
2228 let Some(snapshot) = self
2229 .worktree_store
2230 .read(cx)
2231 .worktree_for_id(worktree_id, cx)
2232 .map(|worktree| worktree.read(cx).snapshot())
2233 else {
2234 return;
2235 };
2236 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2237
2238 for server_id in
2239 self.lsp_tree
2240 .get(path, language.name(), language.manifest(), &delegate, cx)
2241 {
2242 let server = self
2243 .language_servers
2244 .get(&server_id)
2245 .and_then(|server_state| {
2246 if let LanguageServerState::Running { server, .. } = server_state {
2247 Some(server.clone())
2248 } else {
2249 None
2250 }
2251 });
2252 let server = match server {
2253 Some(server) => server,
2254 None => continue,
2255 };
2256
2257 buffer_handle.update(cx, |buffer, cx| {
2258 buffer.set_completion_triggers(
2259 server.server_id(),
2260 server
2261 .capabilities()
2262 .completion_provider
2263 .as_ref()
2264 .and_then(|provider| {
2265 provider
2266 .trigger_characters
2267 .as_ref()
2268 .map(|characters| characters.iter().cloned().collect())
2269 })
2270 .unwrap_or_default(),
2271 cx,
2272 );
2273 });
2274 }
2275 }
2276
2277 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2278 buffer.update(cx, |buffer, cx| {
2279 let Some(language) = buffer.language() else {
2280 return;
2281 };
2282 let path = ProjectPath {
2283 worktree_id: old_file.worktree_id(cx),
2284 path: old_file.path.clone(),
2285 };
2286 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2287 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2288 buffer.set_completion_triggers(server_id, Default::default(), cx);
2289 }
2290 });
2291 }
2292
2293 fn update_buffer_diagnostics(
2294 &mut self,
2295 buffer: &Entity<Buffer>,
2296 server_id: LanguageServerId,
2297 result_id: Option<String>,
2298 version: Option<i32>,
2299 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2300 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2301 cx: &mut Context<LspStore>,
2302 ) -> Result<()> {
2303 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2304 Ordering::Equal
2305 .then_with(|| b.is_primary.cmp(&a.is_primary))
2306 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2307 .then_with(|| a.severity.cmp(&b.severity))
2308 .then_with(|| a.message.cmp(&b.message))
2309 }
2310
2311 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2312 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2313 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2314
2315 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2316 Ordering::Equal
2317 .then_with(|| a.range.start.cmp(&b.range.start))
2318 .then_with(|| b.range.end.cmp(&a.range.end))
2319 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2320 });
2321
2322 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2323
2324 let edits_since_save = std::cell::LazyCell::new(|| {
2325 let saved_version = buffer.read(cx).saved_version();
2326 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2327 });
2328
2329 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2330
2331 for (new_diagnostic, entry) in diagnostics {
2332 let start;
2333 let end;
2334 if new_diagnostic && entry.diagnostic.is_disk_based {
2335 // Some diagnostics are based on files on disk instead of buffers'
2336 // current contents. Adjust these diagnostics' ranges to reflect
2337 // any unsaved edits.
2338 // Do not alter the reused ones though, as their coordinates were stored as anchors
2339 // and were properly adjusted on reuse.
2340 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2341 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2342 } else {
2343 start = entry.range.start;
2344 end = entry.range.end;
2345 }
2346
2347 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2348 ..snapshot.clip_point_utf16(end, Bias::Right);
2349
2350 // Expand empty ranges by one codepoint
2351 if range.start == range.end {
2352 // This will be go to the next boundary when being clipped
2353 range.end.column += 1;
2354 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2355 if range.start == range.end && range.end.column > 0 {
2356 range.start.column -= 1;
2357 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2358 }
2359 }
2360
2361 sanitized_diagnostics.push(DiagnosticEntry {
2362 range,
2363 diagnostic: entry.diagnostic,
2364 });
2365 }
2366 drop(edits_since_save);
2367
2368 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2369 buffer.update(cx, |buffer, cx| {
2370 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2371 self.buffer_pull_diagnostics_result_ids
2372 .entry(server_id)
2373 .or_default()
2374 .insert(abs_path, result_id);
2375 }
2376
2377 buffer.update_diagnostics(server_id, set, cx)
2378 });
2379
2380 Ok(())
2381 }
2382
2383 fn register_language_server_for_invisible_worktree(
2384 &mut self,
2385 worktree: &Entity<Worktree>,
2386 language_server_id: LanguageServerId,
2387 cx: &mut App,
2388 ) {
2389 let worktree = worktree.read(cx);
2390 let worktree_id = worktree.id();
2391 debug_assert!(!worktree.is_visible());
2392 let Some(mut origin_seed) = self
2393 .language_server_ids
2394 .iter()
2395 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2396 else {
2397 return;
2398 };
2399 origin_seed.worktree_id = worktree_id;
2400 self.language_server_ids
2401 .entry(origin_seed)
2402 .or_insert_with(|| UnifiedLanguageServer {
2403 id: language_server_id,
2404 project_roots: Default::default(),
2405 });
2406 }
2407
2408 fn register_buffer_with_language_servers(
2409 &mut self,
2410 buffer_handle: &Entity<Buffer>,
2411 only_register_servers: HashSet<LanguageServerSelector>,
2412 cx: &mut Context<LspStore>,
2413 ) {
2414 let buffer = buffer_handle.read(cx);
2415 let buffer_id = buffer.remote_id();
2416
2417 let Some(file) = File::from_dyn(buffer.file()) else {
2418 return;
2419 };
2420 if !file.is_local() {
2421 return;
2422 }
2423
2424 let abs_path = file.abs_path(cx);
2425 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2426 return;
2427 };
2428 let initial_snapshot = buffer.text_snapshot();
2429 let worktree_id = file.worktree_id(cx);
2430
2431 let Some(language) = buffer.language().cloned() else {
2432 return;
2433 };
2434 let path: Arc<RelPath> = file
2435 .path()
2436 .parent()
2437 .map(Arc::from)
2438 .unwrap_or_else(|| file.path().clone());
2439 let Some(worktree) = self
2440 .worktree_store
2441 .read(cx)
2442 .worktree_for_id(worktree_id, cx)
2443 else {
2444 return;
2445 };
2446 let language_name = language.name();
2447 let (reused, delegate, servers) = self
2448 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2449 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2450 .unwrap_or_else(|| {
2451 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2452 let delegate: Arc<dyn ManifestDelegate> =
2453 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2454
2455 let servers = self
2456 .lsp_tree
2457 .walk(
2458 ProjectPath { worktree_id, path },
2459 language.name(),
2460 language.manifest(),
2461 &delegate,
2462 cx,
2463 )
2464 .collect::<Vec<_>>();
2465 (false, lsp_delegate, servers)
2466 });
2467 let servers_and_adapters = servers
2468 .into_iter()
2469 .filter_map(|server_node| {
2470 if reused && server_node.server_id().is_none() {
2471 return None;
2472 }
2473 if !only_register_servers.is_empty() {
2474 if let Some(server_id) = server_node.server_id()
2475 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2476 {
2477 return None;
2478 }
2479 if let Some(name) = server_node.name()
2480 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2481 {
2482 return None;
2483 }
2484 }
2485
2486 let server_id = server_node.server_id_or_init(|disposition| {
2487 let path = &disposition.path;
2488
2489 {
2490 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2491
2492 let server_id = self.get_or_insert_language_server(
2493 &worktree,
2494 delegate.clone(),
2495 disposition,
2496 &language_name,
2497 cx,
2498 );
2499
2500 if let Some(state) = self.language_servers.get(&server_id)
2501 && let Ok(uri) = uri
2502 {
2503 state.add_workspace_folder(uri);
2504 };
2505 server_id
2506 }
2507 })?;
2508 let server_state = self.language_servers.get(&server_id)?;
2509 if let LanguageServerState::Running {
2510 server, adapter, ..
2511 } = server_state
2512 {
2513 Some((server.clone(), adapter.clone()))
2514 } else {
2515 None
2516 }
2517 })
2518 .collect::<Vec<_>>();
2519 for (server, adapter) in servers_and_adapters {
2520 buffer_handle.update(cx, |buffer, cx| {
2521 buffer.set_completion_triggers(
2522 server.server_id(),
2523 server
2524 .capabilities()
2525 .completion_provider
2526 .as_ref()
2527 .and_then(|provider| {
2528 provider
2529 .trigger_characters
2530 .as_ref()
2531 .map(|characters| characters.iter().cloned().collect())
2532 })
2533 .unwrap_or_default(),
2534 cx,
2535 );
2536 });
2537
2538 let snapshot = LspBufferSnapshot {
2539 version: 0,
2540 snapshot: initial_snapshot.clone(),
2541 };
2542
2543 let mut registered = false;
2544 self.buffer_snapshots
2545 .entry(buffer_id)
2546 .or_default()
2547 .entry(server.server_id())
2548 .or_insert_with(|| {
2549 registered = true;
2550 server.register_buffer(
2551 uri.clone(),
2552 adapter.language_id(&language.name()),
2553 0,
2554 initial_snapshot.text(),
2555 );
2556
2557 vec![snapshot]
2558 });
2559
2560 self.buffers_opened_in_servers
2561 .entry(buffer_id)
2562 .or_default()
2563 .insert(server.server_id());
2564 if registered {
2565 cx.emit(LspStoreEvent::LanguageServerUpdate {
2566 language_server_id: server.server_id(),
2567 name: None,
2568 message: proto::update_language_server::Variant::RegisteredForBuffer(
2569 proto::RegisteredForBuffer {
2570 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2571 buffer_id: buffer_id.to_proto(),
2572 },
2573 ),
2574 });
2575 }
2576 }
2577 }
2578
2579 fn reuse_existing_language_server<'lang_name>(
2580 &self,
2581 server_tree: &LanguageServerTree,
2582 worktree: &Entity<Worktree>,
2583 language_name: &'lang_name LanguageName,
2584 cx: &mut App,
2585 ) -> Option<(
2586 Arc<LocalLspAdapterDelegate>,
2587 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2588 )> {
2589 if worktree.read(cx).is_visible() {
2590 return None;
2591 }
2592
2593 let worktree_store = self.worktree_store.read(cx);
2594 let servers = server_tree
2595 .instances
2596 .iter()
2597 .filter(|(worktree_id, _)| {
2598 worktree_store
2599 .worktree_for_id(**worktree_id, cx)
2600 .is_some_and(|worktree| worktree.read(cx).is_visible())
2601 })
2602 .flat_map(|(worktree_id, servers)| {
2603 servers
2604 .roots
2605 .iter()
2606 .flat_map(|(_, language_servers)| language_servers)
2607 .map(move |(_, (server_node, server_languages))| {
2608 (worktree_id, server_node, server_languages)
2609 })
2610 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2611 .map(|(worktree_id, server_node, _)| {
2612 (
2613 *worktree_id,
2614 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2615 )
2616 })
2617 })
2618 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2619 acc.entry(worktree_id)
2620 .or_insert_with(Vec::new)
2621 .push(server_node);
2622 acc
2623 })
2624 .into_values()
2625 .max_by_key(|servers| servers.len())?;
2626
2627 let worktree_id = worktree.read(cx).id();
2628 let apply = move |tree: &mut LanguageServerTree| {
2629 for server_node in &servers {
2630 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2631 }
2632 servers
2633 };
2634
2635 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2636 Some((delegate, apply))
2637 }
2638
2639 pub(crate) fn unregister_old_buffer_from_language_servers(
2640 &mut self,
2641 buffer: &Entity<Buffer>,
2642 old_file: &File,
2643 cx: &mut App,
2644 ) {
2645 let old_path = match old_file.as_local() {
2646 Some(local) => local.abs_path(cx),
2647 None => return,
2648 };
2649
2650 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2651 debug_panic!("{old_path:?} is not parseable as an URI");
2652 return;
2653 };
2654 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2655 }
2656
2657 pub(crate) fn unregister_buffer_from_language_servers(
2658 &mut self,
2659 buffer: &Entity<Buffer>,
2660 file_url: &lsp::Uri,
2661 cx: &mut App,
2662 ) {
2663 buffer.update(cx, |buffer, cx| {
2664 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2665
2666 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2667 language_server.unregister_buffer(file_url.clone());
2668 }
2669 });
2670 }
2671
2672 fn buffer_snapshot_for_lsp_version(
2673 &mut self,
2674 buffer: &Entity<Buffer>,
2675 server_id: LanguageServerId,
2676 version: Option<i32>,
2677 cx: &App,
2678 ) -> Result<TextBufferSnapshot> {
2679 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2680
2681 if let Some(version) = version {
2682 let buffer_id = buffer.read(cx).remote_id();
2683 let snapshots = if let Some(snapshots) = self
2684 .buffer_snapshots
2685 .get_mut(&buffer_id)
2686 .and_then(|m| m.get_mut(&server_id))
2687 {
2688 snapshots
2689 } else if version == 0 {
2690 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2691 // We detect this case and treat it as if the version was `None`.
2692 return Ok(buffer.read(cx).text_snapshot());
2693 } else {
2694 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2695 };
2696
2697 let found_snapshot = snapshots
2698 .binary_search_by_key(&version, |e| e.version)
2699 .map(|ix| snapshots[ix].snapshot.clone())
2700 .map_err(|_| {
2701 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2702 })?;
2703
2704 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2705 Ok(found_snapshot)
2706 } else {
2707 Ok((buffer.read(cx)).text_snapshot())
2708 }
2709 }
2710
2711 async fn get_server_code_actions_from_action_kinds(
2712 lsp_store: &WeakEntity<LspStore>,
2713 language_server_id: LanguageServerId,
2714 code_action_kinds: Vec<lsp::CodeActionKind>,
2715 buffer: &Entity<Buffer>,
2716 cx: &mut AsyncApp,
2717 ) -> Result<Vec<CodeAction>> {
2718 let actions = lsp_store
2719 .update(cx, move |this, cx| {
2720 let request = GetCodeActions {
2721 range: text::Anchor::MIN..text::Anchor::MAX,
2722 kinds: Some(code_action_kinds),
2723 };
2724 let server = LanguageServerToQuery::Other(language_server_id);
2725 this.request_lsp(buffer.clone(), server, request, cx)
2726 })?
2727 .await?;
2728 Ok(actions)
2729 }
2730
2731 pub async fn execute_code_actions_on_server(
2732 lsp_store: &WeakEntity<LspStore>,
2733 language_server: &Arc<LanguageServer>,
2734
2735 actions: Vec<CodeAction>,
2736 push_to_history: bool,
2737 project_transaction: &mut ProjectTransaction,
2738 cx: &mut AsyncApp,
2739 ) -> anyhow::Result<()> {
2740 for mut action in actions {
2741 Self::try_resolve_code_action(language_server, &mut action)
2742 .await
2743 .context("resolving a formatting code action")?;
2744
2745 if let Some(edit) = action.lsp_action.edit() {
2746 if edit.changes.is_none() && edit.document_changes.is_none() {
2747 continue;
2748 }
2749
2750 let new = Self::deserialize_workspace_edit(
2751 lsp_store.upgrade().context("project dropped")?,
2752 edit.clone(),
2753 push_to_history,
2754 language_server.clone(),
2755 cx,
2756 )
2757 .await?;
2758 project_transaction.0.extend(new.0);
2759 }
2760
2761 if let Some(command) = action.lsp_action.command() {
2762 let server_capabilities = language_server.capabilities();
2763 let available_commands = server_capabilities
2764 .execute_command_provider
2765 .as_ref()
2766 .map(|options| options.commands.as_slice())
2767 .unwrap_or_default();
2768 if available_commands.contains(&command.command) {
2769 lsp_store.update(cx, |lsp_store, _| {
2770 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2771 mode.last_workspace_edits_by_language_server
2772 .remove(&language_server.server_id());
2773 }
2774 })?;
2775
2776 language_server
2777 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2778 command: command.command.clone(),
2779 arguments: command.arguments.clone().unwrap_or_default(),
2780 ..Default::default()
2781 })
2782 .await
2783 .into_response()
2784 .context("execute command")?;
2785
2786 lsp_store.update(cx, |this, _| {
2787 if let LspStoreMode::Local(mode) = &mut this.mode {
2788 project_transaction.0.extend(
2789 mode.last_workspace_edits_by_language_server
2790 .remove(&language_server.server_id())
2791 .unwrap_or_default()
2792 .0,
2793 )
2794 }
2795 })?;
2796 } else {
2797 log::warn!(
2798 "Cannot execute a command {} not listed in the language server capabilities",
2799 command.command
2800 )
2801 }
2802 }
2803 }
2804 Ok(())
2805 }
2806
2807 pub async fn deserialize_text_edits(
2808 this: Entity<LspStore>,
2809 buffer_to_edit: Entity<Buffer>,
2810 edits: Vec<lsp::TextEdit>,
2811 push_to_history: bool,
2812 _: Arc<CachedLspAdapter>,
2813 language_server: Arc<LanguageServer>,
2814 cx: &mut AsyncApp,
2815 ) -> Result<Option<Transaction>> {
2816 let edits = this
2817 .update(cx, |this, cx| {
2818 this.as_local_mut().unwrap().edits_from_lsp(
2819 &buffer_to_edit,
2820 edits,
2821 language_server.server_id(),
2822 None,
2823 cx,
2824 )
2825 })?
2826 .await?;
2827
2828 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2829 buffer.finalize_last_transaction();
2830 buffer.start_transaction();
2831 for (range, text) in edits {
2832 buffer.edit([(range, text)], None, cx);
2833 }
2834
2835 if buffer.end_transaction(cx).is_some() {
2836 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2837 if !push_to_history {
2838 buffer.forget_transaction(transaction.id);
2839 }
2840 Some(transaction)
2841 } else {
2842 None
2843 }
2844 })?;
2845
2846 Ok(transaction)
2847 }
2848
2849 #[allow(clippy::type_complexity)]
2850 pub(crate) fn edits_from_lsp(
2851 &mut self,
2852 buffer: &Entity<Buffer>,
2853 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2854 server_id: LanguageServerId,
2855 version: Option<i32>,
2856 cx: &mut Context<LspStore>,
2857 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2858 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2859 cx.background_spawn(async move {
2860 let snapshot = snapshot?;
2861 let mut lsp_edits = lsp_edits
2862 .into_iter()
2863 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2864 .collect::<Vec<_>>();
2865
2866 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2867
2868 let mut lsp_edits = lsp_edits.into_iter().peekable();
2869 let mut edits = Vec::new();
2870 while let Some((range, mut new_text)) = lsp_edits.next() {
2871 // Clip invalid ranges provided by the language server.
2872 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2873 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2874
2875 // Combine any LSP edits that are adjacent.
2876 //
2877 // Also, combine LSP edits that are separated from each other by only
2878 // a newline. This is important because for some code actions,
2879 // Rust-analyzer rewrites the entire buffer via a series of edits that
2880 // are separated by unchanged newline characters.
2881 //
2882 // In order for the diffing logic below to work properly, any edits that
2883 // cancel each other out must be combined into one.
2884 while let Some((next_range, next_text)) = lsp_edits.peek() {
2885 if next_range.start.0 > range.end {
2886 if next_range.start.0.row > range.end.row + 1
2887 || next_range.start.0.column > 0
2888 || snapshot.clip_point_utf16(
2889 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2890 Bias::Left,
2891 ) > range.end
2892 {
2893 break;
2894 }
2895 new_text.push('\n');
2896 }
2897 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2898 new_text.push_str(next_text);
2899 lsp_edits.next();
2900 }
2901
2902 // For multiline edits, perform a diff of the old and new text so that
2903 // we can identify the changes more precisely, preserving the locations
2904 // of any anchors positioned in the unchanged regions.
2905 if range.end.row > range.start.row {
2906 let offset = range.start.to_offset(&snapshot);
2907 let old_text = snapshot.text_for_range(range).collect::<String>();
2908 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2909 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2910 (
2911 snapshot.anchor_after(offset + range.start)
2912 ..snapshot.anchor_before(offset + range.end),
2913 replacement,
2914 )
2915 }));
2916 } else if range.end == range.start {
2917 let anchor = snapshot.anchor_after(range.start);
2918 edits.push((anchor..anchor, new_text.into()));
2919 } else {
2920 let edit_start = snapshot.anchor_after(range.start);
2921 let edit_end = snapshot.anchor_before(range.end);
2922 edits.push((edit_start..edit_end, new_text.into()));
2923 }
2924 }
2925
2926 Ok(edits)
2927 })
2928 }
2929
2930 pub(crate) async fn deserialize_workspace_edit(
2931 this: Entity<LspStore>,
2932 edit: lsp::WorkspaceEdit,
2933 push_to_history: bool,
2934 language_server: Arc<LanguageServer>,
2935 cx: &mut AsyncApp,
2936 ) -> Result<ProjectTransaction> {
2937 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2938
2939 let mut operations = Vec::new();
2940 if let Some(document_changes) = edit.document_changes {
2941 match document_changes {
2942 lsp::DocumentChanges::Edits(edits) => {
2943 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2944 }
2945 lsp::DocumentChanges::Operations(ops) => operations = ops,
2946 }
2947 } else if let Some(changes) = edit.changes {
2948 operations.extend(changes.into_iter().map(|(uri, edits)| {
2949 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2950 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2951 uri,
2952 version: None,
2953 },
2954 edits: edits.into_iter().map(Edit::Plain).collect(),
2955 })
2956 }));
2957 }
2958
2959 let mut project_transaction = ProjectTransaction::default();
2960 for operation in operations {
2961 match operation {
2962 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2963 let abs_path = op
2964 .uri
2965 .to_file_path()
2966 .map_err(|()| anyhow!("can't convert URI to path"))?;
2967
2968 if let Some(parent_path) = abs_path.parent() {
2969 fs.create_dir(parent_path).await?;
2970 }
2971 if abs_path.ends_with("/") {
2972 fs.create_dir(&abs_path).await?;
2973 } else {
2974 fs.create_file(
2975 &abs_path,
2976 op.options
2977 .map(|options| fs::CreateOptions {
2978 overwrite: options.overwrite.unwrap_or(false),
2979 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2980 })
2981 .unwrap_or_default(),
2982 )
2983 .await?;
2984 }
2985 }
2986
2987 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2988 let source_abs_path = op
2989 .old_uri
2990 .to_file_path()
2991 .map_err(|()| anyhow!("can't convert URI to path"))?;
2992 let target_abs_path = op
2993 .new_uri
2994 .to_file_path()
2995 .map_err(|()| anyhow!("can't convert URI to path"))?;
2996 fs.rename(
2997 &source_abs_path,
2998 &target_abs_path,
2999 op.options
3000 .map(|options| fs::RenameOptions {
3001 overwrite: options.overwrite.unwrap_or(false),
3002 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3003 })
3004 .unwrap_or_default(),
3005 )
3006 .await?;
3007 }
3008
3009 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3010 let abs_path = op
3011 .uri
3012 .to_file_path()
3013 .map_err(|()| anyhow!("can't convert URI to path"))?;
3014 let options = op
3015 .options
3016 .map(|options| fs::RemoveOptions {
3017 recursive: options.recursive.unwrap_or(false),
3018 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3019 })
3020 .unwrap_or_default();
3021 if abs_path.ends_with("/") {
3022 fs.remove_dir(&abs_path, options).await?;
3023 } else {
3024 fs.remove_file(&abs_path, options).await?;
3025 }
3026 }
3027
3028 lsp::DocumentChangeOperation::Edit(op) => {
3029 let buffer_to_edit = this
3030 .update(cx, |this, cx| {
3031 this.open_local_buffer_via_lsp(
3032 op.text_document.uri.clone(),
3033 language_server.server_id(),
3034 cx,
3035 )
3036 })?
3037 .await?;
3038
3039 let edits = this
3040 .update(cx, |this, cx| {
3041 let path = buffer_to_edit.read(cx).project_path(cx);
3042 let active_entry = this.active_entry;
3043 let is_active_entry = path.is_some_and(|project_path| {
3044 this.worktree_store
3045 .read(cx)
3046 .entry_for_path(&project_path, cx)
3047 .is_some_and(|entry| Some(entry.id) == active_entry)
3048 });
3049 let local = this.as_local_mut().unwrap();
3050
3051 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3052 for edit in op.edits {
3053 match edit {
3054 Edit::Plain(edit) => {
3055 if !edits.contains(&edit) {
3056 edits.push(edit)
3057 }
3058 }
3059 Edit::Annotated(edit) => {
3060 if !edits.contains(&edit.text_edit) {
3061 edits.push(edit.text_edit)
3062 }
3063 }
3064 Edit::Snippet(edit) => {
3065 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3066 else {
3067 continue;
3068 };
3069
3070 if is_active_entry {
3071 snippet_edits.push((edit.range, snippet));
3072 } else {
3073 // Since this buffer is not focused, apply a normal edit.
3074 let new_edit = TextEdit {
3075 range: edit.range,
3076 new_text: snippet.text,
3077 };
3078 if !edits.contains(&new_edit) {
3079 edits.push(new_edit);
3080 }
3081 }
3082 }
3083 }
3084 }
3085 if !snippet_edits.is_empty() {
3086 let buffer_id = buffer_to_edit.read(cx).remote_id();
3087 let version = if let Some(buffer_version) = op.text_document.version
3088 {
3089 local
3090 .buffer_snapshot_for_lsp_version(
3091 &buffer_to_edit,
3092 language_server.server_id(),
3093 Some(buffer_version),
3094 cx,
3095 )
3096 .ok()
3097 .map(|snapshot| snapshot.version)
3098 } else {
3099 Some(buffer_to_edit.read(cx).saved_version().clone())
3100 };
3101
3102 let most_recent_edit =
3103 version.and_then(|version| version.most_recent());
3104 // Check if the edit that triggered that edit has been made by this participant.
3105
3106 if let Some(most_recent_edit) = most_recent_edit {
3107 cx.emit(LspStoreEvent::SnippetEdit {
3108 buffer_id,
3109 edits: snippet_edits,
3110 most_recent_edit,
3111 });
3112 }
3113 }
3114
3115 local.edits_from_lsp(
3116 &buffer_to_edit,
3117 edits,
3118 language_server.server_id(),
3119 op.text_document.version,
3120 cx,
3121 )
3122 })?
3123 .await?;
3124
3125 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3126 buffer.finalize_last_transaction();
3127 buffer.start_transaction();
3128 for (range, text) in edits {
3129 buffer.edit([(range, text)], None, cx);
3130 }
3131
3132 buffer.end_transaction(cx).and_then(|transaction_id| {
3133 if push_to_history {
3134 buffer.finalize_last_transaction();
3135 buffer.get_transaction(transaction_id).cloned()
3136 } else {
3137 buffer.forget_transaction(transaction_id)
3138 }
3139 })
3140 })?;
3141 if let Some(transaction) = transaction {
3142 project_transaction.0.insert(buffer_to_edit, transaction);
3143 }
3144 }
3145 }
3146 }
3147
3148 Ok(project_transaction)
3149 }
3150
3151 async fn on_lsp_workspace_edit(
3152 this: WeakEntity<LspStore>,
3153 params: lsp::ApplyWorkspaceEditParams,
3154 server_id: LanguageServerId,
3155 cx: &mut AsyncApp,
3156 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3157 let this = this.upgrade().context("project project closed")?;
3158 let language_server = this
3159 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3160 .context("language server not found")?;
3161 let transaction = Self::deserialize_workspace_edit(
3162 this.clone(),
3163 params.edit,
3164 true,
3165 language_server.clone(),
3166 cx,
3167 )
3168 .await
3169 .log_err();
3170 this.update(cx, |this, _| {
3171 if let Some(transaction) = transaction {
3172 this.as_local_mut()
3173 .unwrap()
3174 .last_workspace_edits_by_language_server
3175 .insert(server_id, transaction);
3176 }
3177 })?;
3178 Ok(lsp::ApplyWorkspaceEditResponse {
3179 applied: true,
3180 failed_change: None,
3181 failure_reason: None,
3182 })
3183 }
3184
3185 fn remove_worktree(
3186 &mut self,
3187 id_to_remove: WorktreeId,
3188 cx: &mut Context<LspStore>,
3189 ) -> Vec<LanguageServerId> {
3190 self.diagnostics.remove(&id_to_remove);
3191 self.prettier_store.update(cx, |prettier_store, cx| {
3192 prettier_store.remove_worktree(id_to_remove, cx);
3193 });
3194
3195 let mut servers_to_remove = BTreeSet::default();
3196 let mut servers_to_preserve = HashSet::default();
3197 for (seed, state) in &self.language_server_ids {
3198 if seed.worktree_id == id_to_remove {
3199 servers_to_remove.insert(state.id);
3200 } else {
3201 servers_to_preserve.insert(state.id);
3202 }
3203 }
3204 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3205 self.language_server_ids
3206 .retain(|_, state| !servers_to_remove.contains(&state.id));
3207 for server_id_to_remove in &servers_to_remove {
3208 self.language_server_watched_paths
3209 .remove(server_id_to_remove);
3210 self.language_server_paths_watched_for_rename
3211 .remove(server_id_to_remove);
3212 self.last_workspace_edits_by_language_server
3213 .remove(server_id_to_remove);
3214 self.language_servers.remove(server_id_to_remove);
3215 self.buffer_pull_diagnostics_result_ids
3216 .remove(server_id_to_remove);
3217 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3218 buffer_servers.remove(server_id_to_remove);
3219 }
3220 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3221 }
3222 servers_to_remove.into_iter().collect()
3223 }
3224
3225 fn rebuild_watched_paths_inner<'a>(
3226 &'a self,
3227 language_server_id: LanguageServerId,
3228 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3229 cx: &mut Context<LspStore>,
3230 ) -> LanguageServerWatchedPathsBuilder {
3231 let worktrees = self
3232 .worktree_store
3233 .read(cx)
3234 .worktrees()
3235 .filter_map(|worktree| {
3236 self.language_servers_for_worktree(worktree.read(cx).id())
3237 .find(|server| server.server_id() == language_server_id)
3238 .map(|_| worktree)
3239 })
3240 .collect::<Vec<_>>();
3241
3242 let mut worktree_globs = HashMap::default();
3243 let mut abs_globs = HashMap::default();
3244 log::trace!(
3245 "Processing new watcher paths for language server with id {}",
3246 language_server_id
3247 );
3248
3249 for watcher in watchers {
3250 if let Some((worktree, literal_prefix, pattern)) =
3251 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3252 {
3253 worktree.update(cx, |worktree, _| {
3254 if let Some((tree, glob)) =
3255 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3256 {
3257 tree.add_path_prefix_to_scan(literal_prefix);
3258 worktree_globs
3259 .entry(tree.id())
3260 .or_insert_with(GlobSetBuilder::new)
3261 .add(glob);
3262 }
3263 });
3264 } else {
3265 let (path, pattern) = match &watcher.glob_pattern {
3266 lsp::GlobPattern::String(s) => {
3267 let watcher_path = SanitizedPath::new(s);
3268 let path = glob_literal_prefix(watcher_path.as_path());
3269 let pattern = watcher_path
3270 .as_path()
3271 .strip_prefix(&path)
3272 .map(|p| p.to_string_lossy().into_owned())
3273 .unwrap_or_else(|e| {
3274 debug_panic!(
3275 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3276 s,
3277 path.display(),
3278 e
3279 );
3280 watcher_path.as_path().to_string_lossy().into_owned()
3281 });
3282 (path, pattern)
3283 }
3284 lsp::GlobPattern::Relative(rp) => {
3285 let Ok(mut base_uri) = match &rp.base_uri {
3286 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3287 lsp::OneOf::Right(base_uri) => base_uri,
3288 }
3289 .to_file_path() else {
3290 continue;
3291 };
3292
3293 let path = glob_literal_prefix(Path::new(&rp.pattern));
3294 let pattern = Path::new(&rp.pattern)
3295 .strip_prefix(&path)
3296 .map(|p| p.to_string_lossy().into_owned())
3297 .unwrap_or_else(|e| {
3298 debug_panic!(
3299 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3300 rp.pattern,
3301 path.display(),
3302 e
3303 );
3304 rp.pattern.clone()
3305 });
3306 base_uri.push(path);
3307 (base_uri, pattern)
3308 }
3309 };
3310
3311 if let Some(glob) = Glob::new(&pattern).log_err() {
3312 if !path
3313 .components()
3314 .any(|c| matches!(c, path::Component::Normal(_)))
3315 {
3316 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3317 // rather than adding a new watcher for `/`.
3318 for worktree in &worktrees {
3319 worktree_globs
3320 .entry(worktree.read(cx).id())
3321 .or_insert_with(GlobSetBuilder::new)
3322 .add(glob.clone());
3323 }
3324 } else {
3325 abs_globs
3326 .entry(path.into())
3327 .or_insert_with(GlobSetBuilder::new)
3328 .add(glob);
3329 }
3330 }
3331 }
3332 }
3333
3334 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3335 for (worktree_id, builder) in worktree_globs {
3336 if let Ok(globset) = builder.build() {
3337 watch_builder.watch_worktree(worktree_id, globset);
3338 }
3339 }
3340 for (abs_path, builder) in abs_globs {
3341 if let Ok(globset) = builder.build() {
3342 watch_builder.watch_abs_path(abs_path, globset);
3343 }
3344 }
3345 watch_builder
3346 }
3347
3348 fn worktree_and_path_for_file_watcher(
3349 worktrees: &[Entity<Worktree>],
3350 watcher: &FileSystemWatcher,
3351 cx: &App,
3352 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3353 worktrees.iter().find_map(|worktree| {
3354 let tree = worktree.read(cx);
3355 let worktree_root_path = tree.abs_path();
3356 let path_style = tree.path_style();
3357 match &watcher.glob_pattern {
3358 lsp::GlobPattern::String(s) => {
3359 let watcher_path = SanitizedPath::new(s);
3360 let relative = watcher_path
3361 .as_path()
3362 .strip_prefix(&worktree_root_path)
3363 .ok()?;
3364 let literal_prefix = glob_literal_prefix(relative);
3365 Some((
3366 worktree.clone(),
3367 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3368 relative.to_string_lossy().into_owned(),
3369 ))
3370 }
3371 lsp::GlobPattern::Relative(rp) => {
3372 let base_uri = match &rp.base_uri {
3373 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3374 lsp::OneOf::Right(base_uri) => base_uri,
3375 }
3376 .to_file_path()
3377 .ok()?;
3378 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3379 let mut literal_prefix = relative.to_owned();
3380 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3381 Some((
3382 worktree.clone(),
3383 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3384 rp.pattern.clone(),
3385 ))
3386 }
3387 }
3388 })
3389 }
3390
3391 fn rebuild_watched_paths(
3392 &mut self,
3393 language_server_id: LanguageServerId,
3394 cx: &mut Context<LspStore>,
3395 ) {
3396 let Some(registrations) = self
3397 .language_server_dynamic_registrations
3398 .get(&language_server_id)
3399 else {
3400 return;
3401 };
3402
3403 let watch_builder = self.rebuild_watched_paths_inner(
3404 language_server_id,
3405 registrations.did_change_watched_files.values().flatten(),
3406 cx,
3407 );
3408 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3409 self.language_server_watched_paths
3410 .insert(language_server_id, watcher);
3411
3412 cx.notify();
3413 }
3414
3415 fn on_lsp_did_change_watched_files(
3416 &mut self,
3417 language_server_id: LanguageServerId,
3418 registration_id: &str,
3419 params: DidChangeWatchedFilesRegistrationOptions,
3420 cx: &mut Context<LspStore>,
3421 ) {
3422 let registrations = self
3423 .language_server_dynamic_registrations
3424 .entry(language_server_id)
3425 .or_default();
3426
3427 registrations
3428 .did_change_watched_files
3429 .insert(registration_id.to_string(), params.watchers);
3430
3431 self.rebuild_watched_paths(language_server_id, cx);
3432 }
3433
3434 fn on_lsp_unregister_did_change_watched_files(
3435 &mut self,
3436 language_server_id: LanguageServerId,
3437 registration_id: &str,
3438 cx: &mut Context<LspStore>,
3439 ) {
3440 let registrations = self
3441 .language_server_dynamic_registrations
3442 .entry(language_server_id)
3443 .or_default();
3444
3445 if registrations
3446 .did_change_watched_files
3447 .remove(registration_id)
3448 .is_some()
3449 {
3450 log::info!(
3451 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3452 language_server_id,
3453 registration_id
3454 );
3455 } else {
3456 log::warn!(
3457 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3458 language_server_id,
3459 registration_id
3460 );
3461 }
3462
3463 self.rebuild_watched_paths(language_server_id, cx);
3464 }
3465
3466 async fn initialization_options_for_adapter(
3467 adapter: Arc<dyn LspAdapter>,
3468 delegate: &Arc<dyn LspAdapterDelegate>,
3469 ) -> Result<Option<serde_json::Value>> {
3470 let Some(mut initialization_config) =
3471 adapter.clone().initialization_options(delegate).await?
3472 else {
3473 return Ok(None);
3474 };
3475
3476 for other_adapter in delegate.registered_lsp_adapters() {
3477 if other_adapter.name() == adapter.name() {
3478 continue;
3479 }
3480 if let Ok(Some(target_config)) = other_adapter
3481 .clone()
3482 .additional_initialization_options(adapter.name(), delegate)
3483 .await
3484 {
3485 merge_json_value_into(target_config.clone(), &mut initialization_config);
3486 }
3487 }
3488
3489 Ok(Some(initialization_config))
3490 }
3491
3492 async fn workspace_configuration_for_adapter(
3493 adapter: Arc<dyn LspAdapter>,
3494 delegate: &Arc<dyn LspAdapterDelegate>,
3495 toolchain: Option<Toolchain>,
3496 cx: &mut AsyncApp,
3497 ) -> Result<serde_json::Value> {
3498 let mut workspace_config = adapter
3499 .clone()
3500 .workspace_configuration(delegate, toolchain, cx)
3501 .await?;
3502
3503 for other_adapter in delegate.registered_lsp_adapters() {
3504 if other_adapter.name() == adapter.name() {
3505 continue;
3506 }
3507 if let Ok(Some(target_config)) = other_adapter
3508 .clone()
3509 .additional_workspace_configuration(adapter.name(), delegate, cx)
3510 .await
3511 {
3512 merge_json_value_into(target_config.clone(), &mut workspace_config);
3513 }
3514 }
3515
3516 Ok(workspace_config)
3517 }
3518
3519 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3520 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3521 Some(server.clone())
3522 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3523 Some(Arc::clone(server))
3524 } else {
3525 None
3526 }
3527 }
3528}
3529
3530fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3531 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3532 cx.emit(LspStoreEvent::LanguageServerUpdate {
3533 language_server_id: server.server_id(),
3534 name: Some(server.name()),
3535 message: proto::update_language_server::Variant::MetadataUpdated(
3536 proto::ServerMetadataUpdated {
3537 capabilities: Some(capabilities),
3538 },
3539 ),
3540 });
3541 }
3542}
3543
3544#[derive(Debug)]
3545pub struct FormattableBuffer {
3546 handle: Entity<Buffer>,
3547 abs_path: Option<PathBuf>,
3548 env: Option<HashMap<String, String>>,
3549 ranges: Option<Vec<Range<Anchor>>>,
3550}
3551
3552pub struct RemoteLspStore {
3553 upstream_client: Option<AnyProtoClient>,
3554 upstream_project_id: u64,
3555}
3556
3557pub(crate) enum LspStoreMode {
3558 Local(LocalLspStore), // ssh host and collab host
3559 Remote(RemoteLspStore), // collab guest
3560}
3561
3562impl LspStoreMode {
3563 fn is_local(&self) -> bool {
3564 matches!(self, LspStoreMode::Local(_))
3565 }
3566}
3567
3568pub struct LspStore {
3569 mode: LspStoreMode,
3570 last_formatting_failure: Option<String>,
3571 downstream_client: Option<(AnyProtoClient, u64)>,
3572 nonce: u128,
3573 buffer_store: Entity<BufferStore>,
3574 worktree_store: Entity<WorktreeStore>,
3575 pub languages: Arc<LanguageRegistry>,
3576 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3577 active_entry: Option<ProjectEntryId>,
3578 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3579 _maintain_buffer_languages: Task<()>,
3580 diagnostic_summaries:
3581 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3582 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3583 lsp_data: HashMap<BufferId, BufferLspData>,
3584 next_hint_id: Arc<AtomicUsize>,
3585}
3586
3587#[derive(Debug)]
3588pub struct BufferLspData {
3589 buffer_version: Global,
3590 document_colors: Option<DocumentColorData>,
3591 code_lens: Option<CodeLensData>,
3592 inlay_hints: BufferInlayHints,
3593 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3594 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3595}
3596
3597#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3598struct LspKey {
3599 request_type: TypeId,
3600 server_queried: Option<LanguageServerId>,
3601}
3602
3603impl BufferLspData {
3604 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3605 Self {
3606 buffer_version: buffer.read(cx).version(),
3607 document_colors: None,
3608 code_lens: None,
3609 inlay_hints: BufferInlayHints::new(buffer, cx),
3610 lsp_requests: HashMap::default(),
3611 chunk_lsp_requests: HashMap::default(),
3612 }
3613 }
3614
3615 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3616 if let Some(document_colors) = &mut self.document_colors {
3617 document_colors.colors.remove(&for_server);
3618 document_colors.cache_version += 1;
3619 }
3620
3621 if let Some(code_lens) = &mut self.code_lens {
3622 code_lens.lens.remove(&for_server);
3623 }
3624
3625 self.inlay_hints.remove_server_data(for_server);
3626 }
3627
3628 #[cfg(any(test, feature = "test-support"))]
3629 pub fn inlay_hints(&self) -> &BufferInlayHints {
3630 &self.inlay_hints
3631 }
3632}
3633
3634#[derive(Debug, Default, Clone)]
3635pub struct DocumentColors {
3636 pub colors: HashSet<DocumentColor>,
3637 pub cache_version: Option<usize>,
3638}
3639
3640type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3641type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3642
3643#[derive(Debug, Default)]
3644struct DocumentColorData {
3645 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3646 cache_version: usize,
3647 colors_update: Option<(Global, DocumentColorTask)>,
3648}
3649
3650#[derive(Debug, Default)]
3651struct CodeLensData {
3652 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3653 update: Option<(Global, CodeLensTask)>,
3654}
3655
3656#[derive(Debug)]
3657pub enum LspStoreEvent {
3658 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3659 LanguageServerRemoved(LanguageServerId),
3660 LanguageServerUpdate {
3661 language_server_id: LanguageServerId,
3662 name: Option<LanguageServerName>,
3663 message: proto::update_language_server::Variant,
3664 },
3665 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3666 LanguageServerPrompt(LanguageServerPromptRequest),
3667 LanguageDetected {
3668 buffer: Entity<Buffer>,
3669 new_language: Option<Arc<Language>>,
3670 },
3671 Notification(String),
3672 RefreshInlayHints {
3673 server_id: LanguageServerId,
3674 request_id: Option<usize>,
3675 },
3676 RefreshCodeLens,
3677 DiagnosticsUpdated {
3678 server_id: LanguageServerId,
3679 paths: Vec<ProjectPath>,
3680 },
3681 DiskBasedDiagnosticsStarted {
3682 language_server_id: LanguageServerId,
3683 },
3684 DiskBasedDiagnosticsFinished {
3685 language_server_id: LanguageServerId,
3686 },
3687 SnippetEdit {
3688 buffer_id: BufferId,
3689 edits: Vec<(lsp::Range, Snippet)>,
3690 most_recent_edit: clock::Lamport,
3691 },
3692}
3693
3694#[derive(Clone, Debug, Serialize)]
3695pub struct LanguageServerStatus {
3696 pub name: LanguageServerName,
3697 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3698 pub has_pending_diagnostic_updates: bool,
3699 progress_tokens: HashSet<ProgressToken>,
3700 pub worktree: Option<WorktreeId>,
3701}
3702
3703#[derive(Clone, Debug)]
3704struct CoreSymbol {
3705 pub language_server_name: LanguageServerName,
3706 pub source_worktree_id: WorktreeId,
3707 pub source_language_server_id: LanguageServerId,
3708 pub path: SymbolLocation,
3709 pub name: String,
3710 pub kind: lsp::SymbolKind,
3711 pub range: Range<Unclipped<PointUtf16>>,
3712}
3713
3714#[derive(Clone, Debug, PartialEq, Eq)]
3715pub enum SymbolLocation {
3716 InProject(ProjectPath),
3717 OutsideProject {
3718 abs_path: Arc<Path>,
3719 signature: [u8; 32],
3720 },
3721}
3722
3723impl SymbolLocation {
3724 fn file_name(&self) -> Option<&str> {
3725 match self {
3726 Self::InProject(path) => path.path.file_name(),
3727 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3728 }
3729 }
3730}
3731
3732impl LspStore {
3733 pub fn init(client: &AnyProtoClient) {
3734 client.add_entity_request_handler(Self::handle_lsp_query);
3735 client.add_entity_message_handler(Self::handle_lsp_query_response);
3736 client.add_entity_request_handler(Self::handle_restart_language_servers);
3737 client.add_entity_request_handler(Self::handle_stop_language_servers);
3738 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3739 client.add_entity_message_handler(Self::handle_start_language_server);
3740 client.add_entity_message_handler(Self::handle_update_language_server);
3741 client.add_entity_message_handler(Self::handle_language_server_log);
3742 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3743 client.add_entity_request_handler(Self::handle_format_buffers);
3744 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3745 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3746 client.add_entity_request_handler(Self::handle_apply_code_action);
3747 client.add_entity_request_handler(Self::handle_get_project_symbols);
3748 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3749 client.add_entity_request_handler(Self::handle_get_color_presentation);
3750 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3751 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3752 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3753 client.add_entity_request_handler(Self::handle_on_type_formatting);
3754 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3755 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3756 client.add_entity_request_handler(Self::handle_rename_project_entry);
3757 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3758 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3759 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3760 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3761 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3762 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3763 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3764
3765 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3766 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3767 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3768 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3769 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3770 client.add_entity_request_handler(
3771 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3772 );
3773 client.add_entity_request_handler(
3774 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3775 );
3776 client.add_entity_request_handler(
3777 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3778 );
3779 }
3780
3781 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3782 match &self.mode {
3783 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3784 _ => None,
3785 }
3786 }
3787
3788 pub fn as_local(&self) -> Option<&LocalLspStore> {
3789 match &self.mode {
3790 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3791 _ => None,
3792 }
3793 }
3794
3795 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3796 match &mut self.mode {
3797 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3798 _ => None,
3799 }
3800 }
3801
3802 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3803 match &self.mode {
3804 LspStoreMode::Remote(RemoteLspStore {
3805 upstream_client: Some(upstream_client),
3806 upstream_project_id,
3807 ..
3808 }) => Some((upstream_client.clone(), *upstream_project_id)),
3809
3810 LspStoreMode::Remote(RemoteLspStore {
3811 upstream_client: None,
3812 ..
3813 }) => None,
3814 LspStoreMode::Local(_) => None,
3815 }
3816 }
3817
3818 pub fn new_local(
3819 buffer_store: Entity<BufferStore>,
3820 worktree_store: Entity<WorktreeStore>,
3821 prettier_store: Entity<PrettierStore>,
3822 toolchain_store: Entity<LocalToolchainStore>,
3823 environment: Entity<ProjectEnvironment>,
3824 manifest_tree: Entity<ManifestTree>,
3825 languages: Arc<LanguageRegistry>,
3826 http_client: Arc<dyn HttpClient>,
3827 fs: Arc<dyn Fs>,
3828 cx: &mut Context<Self>,
3829 ) -> Self {
3830 let yarn = YarnPathStore::new(fs.clone(), cx);
3831 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3832 .detach();
3833 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3834 .detach();
3835 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3836 .detach();
3837 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3838 .detach();
3839 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3840 .detach();
3841 subscribe_to_binary_statuses(&languages, cx).detach();
3842
3843 let _maintain_workspace_config = {
3844 let (sender, receiver) = watch::channel();
3845 (Self::maintain_workspace_config(receiver, cx), sender)
3846 };
3847
3848 Self {
3849 mode: LspStoreMode::Local(LocalLspStore {
3850 weak: cx.weak_entity(),
3851 worktree_store: worktree_store.clone(),
3852
3853 supplementary_language_servers: Default::default(),
3854 languages: languages.clone(),
3855 language_server_ids: Default::default(),
3856 language_servers: Default::default(),
3857 last_workspace_edits_by_language_server: Default::default(),
3858 language_server_watched_paths: Default::default(),
3859 language_server_paths_watched_for_rename: Default::default(),
3860 language_server_dynamic_registrations: Default::default(),
3861 buffers_being_formatted: Default::default(),
3862 buffer_snapshots: Default::default(),
3863 prettier_store,
3864 environment,
3865 http_client,
3866 fs,
3867 yarn,
3868 next_diagnostic_group_id: Default::default(),
3869 diagnostics: Default::default(),
3870 _subscription: cx.on_app_quit(|this, cx| {
3871 this.as_local_mut()
3872 .unwrap()
3873 .shutdown_language_servers_on_quit(cx)
3874 }),
3875 lsp_tree: LanguageServerTree::new(
3876 manifest_tree,
3877 languages.clone(),
3878 toolchain_store.clone(),
3879 ),
3880 toolchain_store,
3881 registered_buffers: HashMap::default(),
3882 buffers_opened_in_servers: HashMap::default(),
3883 buffer_pull_diagnostics_result_ids: HashMap::default(),
3884 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3885 .manifest_file_names(),
3886 }),
3887 last_formatting_failure: None,
3888 downstream_client: None,
3889 buffer_store,
3890 worktree_store,
3891 languages: languages.clone(),
3892 language_server_statuses: Default::default(),
3893 nonce: StdRng::from_os_rng().random(),
3894 diagnostic_summaries: HashMap::default(),
3895 lsp_server_capabilities: HashMap::default(),
3896 lsp_data: HashMap::default(),
3897 next_hint_id: Arc::default(),
3898 active_entry: None,
3899 _maintain_workspace_config,
3900 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3901 }
3902 }
3903
3904 fn send_lsp_proto_request<R: LspCommand>(
3905 &self,
3906 buffer: Entity<Buffer>,
3907 client: AnyProtoClient,
3908 upstream_project_id: u64,
3909 request: R,
3910 cx: &mut Context<LspStore>,
3911 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3912 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3913 return Task::ready(Ok(R::Response::default()));
3914 }
3915 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3916 cx.spawn(async move |this, cx| {
3917 let response = client.request(message).await?;
3918 let this = this.upgrade().context("project dropped")?;
3919 request
3920 .response_from_proto(response, this, buffer, cx.clone())
3921 .await
3922 })
3923 }
3924
3925 pub(super) fn new_remote(
3926 buffer_store: Entity<BufferStore>,
3927 worktree_store: Entity<WorktreeStore>,
3928 languages: Arc<LanguageRegistry>,
3929 upstream_client: AnyProtoClient,
3930 project_id: u64,
3931 cx: &mut Context<Self>,
3932 ) -> Self {
3933 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3934 .detach();
3935 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3936 .detach();
3937 subscribe_to_binary_statuses(&languages, cx).detach();
3938 let _maintain_workspace_config = {
3939 let (sender, receiver) = watch::channel();
3940 (Self::maintain_workspace_config(receiver, cx), sender)
3941 };
3942 Self {
3943 mode: LspStoreMode::Remote(RemoteLspStore {
3944 upstream_client: Some(upstream_client),
3945 upstream_project_id: project_id,
3946 }),
3947 downstream_client: None,
3948 last_formatting_failure: None,
3949 buffer_store,
3950 worktree_store,
3951 languages: languages.clone(),
3952 language_server_statuses: Default::default(),
3953 nonce: StdRng::from_os_rng().random(),
3954 diagnostic_summaries: HashMap::default(),
3955 lsp_server_capabilities: HashMap::default(),
3956 next_hint_id: Arc::default(),
3957 lsp_data: HashMap::default(),
3958 active_entry: None,
3959
3960 _maintain_workspace_config,
3961 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3962 }
3963 }
3964
3965 fn on_buffer_store_event(
3966 &mut self,
3967 _: Entity<BufferStore>,
3968 event: &BufferStoreEvent,
3969 cx: &mut Context<Self>,
3970 ) {
3971 match event {
3972 BufferStoreEvent::BufferAdded(buffer) => {
3973 self.on_buffer_added(buffer, cx).log_err();
3974 }
3975 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3976 let buffer_id = buffer.read(cx).remote_id();
3977 if let Some(local) = self.as_local_mut()
3978 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3979 {
3980 local.reset_buffer(buffer, old_file, cx);
3981
3982 if local.registered_buffers.contains_key(&buffer_id) {
3983 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3984 }
3985 }
3986
3987 self.detect_language_for_buffer(buffer, cx);
3988 if let Some(local) = self.as_local_mut() {
3989 local.initialize_buffer(buffer, cx);
3990 if local.registered_buffers.contains_key(&buffer_id) {
3991 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3992 }
3993 }
3994 }
3995 _ => {}
3996 }
3997 }
3998
3999 fn on_worktree_store_event(
4000 &mut self,
4001 _: Entity<WorktreeStore>,
4002 event: &WorktreeStoreEvent,
4003 cx: &mut Context<Self>,
4004 ) {
4005 match event {
4006 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4007 if !worktree.read(cx).is_local() {
4008 return;
4009 }
4010 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4011 worktree::Event::UpdatedEntries(changes) => {
4012 this.update_local_worktree_language_servers(&worktree, changes, cx);
4013 }
4014 worktree::Event::UpdatedGitRepositories(_)
4015 | worktree::Event::DeletedEntry(_) => {}
4016 })
4017 .detach()
4018 }
4019 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4020 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4021 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4022 }
4023 WorktreeStoreEvent::WorktreeReleased(..)
4024 | WorktreeStoreEvent::WorktreeOrderChanged
4025 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4026 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4027 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4028 }
4029 }
4030
4031 fn on_prettier_store_event(
4032 &mut self,
4033 _: Entity<PrettierStore>,
4034 event: &PrettierStoreEvent,
4035 cx: &mut Context<Self>,
4036 ) {
4037 match event {
4038 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4039 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4040 }
4041 PrettierStoreEvent::LanguageServerAdded {
4042 new_server_id,
4043 name,
4044 prettier_server,
4045 } => {
4046 self.register_supplementary_language_server(
4047 *new_server_id,
4048 name.clone(),
4049 prettier_server.clone(),
4050 cx,
4051 );
4052 }
4053 }
4054 }
4055
4056 fn on_toolchain_store_event(
4057 &mut self,
4058 _: Entity<LocalToolchainStore>,
4059 event: &ToolchainStoreEvent,
4060 _: &mut Context<Self>,
4061 ) {
4062 if let ToolchainStoreEvent::ToolchainActivated = event {
4063 self.request_workspace_config_refresh()
4064 }
4065 }
4066
4067 fn request_workspace_config_refresh(&mut self) {
4068 *self._maintain_workspace_config.1.borrow_mut() = ();
4069 }
4070
4071 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4072 self.as_local().map(|local| local.prettier_store.clone())
4073 }
4074
4075 fn on_buffer_event(
4076 &mut self,
4077 buffer: Entity<Buffer>,
4078 event: &language::BufferEvent,
4079 cx: &mut Context<Self>,
4080 ) {
4081 match event {
4082 language::BufferEvent::Edited => {
4083 self.on_buffer_edited(buffer, cx);
4084 }
4085
4086 language::BufferEvent::Saved => {
4087 self.on_buffer_saved(buffer, cx);
4088 }
4089
4090 _ => {}
4091 }
4092 }
4093
4094 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4095 buffer
4096 .read(cx)
4097 .set_language_registry(self.languages.clone());
4098
4099 cx.subscribe(buffer, |this, buffer, event, cx| {
4100 this.on_buffer_event(buffer, event, cx);
4101 })
4102 .detach();
4103
4104 self.detect_language_for_buffer(buffer, cx);
4105 if let Some(local) = self.as_local_mut() {
4106 local.initialize_buffer(buffer, cx);
4107 }
4108
4109 Ok(())
4110 }
4111
4112 pub(crate) fn register_buffer_with_language_servers(
4113 &mut self,
4114 buffer: &Entity<Buffer>,
4115 only_register_servers: HashSet<LanguageServerSelector>,
4116 ignore_refcounts: bool,
4117 cx: &mut Context<Self>,
4118 ) -> OpenLspBufferHandle {
4119 let buffer_id = buffer.read(cx).remote_id();
4120 let handle = cx.new(|_| buffer.clone());
4121 if let Some(local) = self.as_local_mut() {
4122 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4123 if !ignore_refcounts {
4124 *refcount += 1;
4125 }
4126
4127 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4128 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4129 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4130 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4131 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4132 return handle;
4133 };
4134 if !file.is_local() {
4135 return handle;
4136 }
4137
4138 if ignore_refcounts || *refcount == 1 {
4139 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4140 }
4141 if !ignore_refcounts {
4142 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4143 let refcount = {
4144 let local = lsp_store.as_local_mut().unwrap();
4145 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4146 debug_panic!("bad refcounting");
4147 return;
4148 };
4149
4150 *refcount -= 1;
4151 *refcount
4152 };
4153 if refcount == 0 {
4154 lsp_store.lsp_data.remove(&buffer_id);
4155 let local = lsp_store.as_local_mut().unwrap();
4156 local.registered_buffers.remove(&buffer_id);
4157 local.buffers_opened_in_servers.remove(&buffer_id);
4158 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4159 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4160 }
4161 }
4162 })
4163 .detach();
4164 }
4165 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4166 let buffer_id = buffer.read(cx).remote_id().to_proto();
4167 cx.background_spawn(async move {
4168 upstream_client
4169 .request(proto::RegisterBufferWithLanguageServers {
4170 project_id: upstream_project_id,
4171 buffer_id,
4172 only_servers: only_register_servers
4173 .into_iter()
4174 .map(|selector| {
4175 let selector = match selector {
4176 LanguageServerSelector::Id(language_server_id) => {
4177 proto::language_server_selector::Selector::ServerId(
4178 language_server_id.to_proto(),
4179 )
4180 }
4181 LanguageServerSelector::Name(language_server_name) => {
4182 proto::language_server_selector::Selector::Name(
4183 language_server_name.to_string(),
4184 )
4185 }
4186 };
4187 proto::LanguageServerSelector {
4188 selector: Some(selector),
4189 }
4190 })
4191 .collect(),
4192 })
4193 .await
4194 })
4195 .detach();
4196 } else {
4197 // Our remote connection got closed
4198 }
4199 handle
4200 }
4201
4202 fn maintain_buffer_languages(
4203 languages: Arc<LanguageRegistry>,
4204 cx: &mut Context<Self>,
4205 ) -> Task<()> {
4206 let mut subscription = languages.subscribe();
4207 let mut prev_reload_count = languages.reload_count();
4208 cx.spawn(async move |this, cx| {
4209 while let Some(()) = subscription.next().await {
4210 if let Some(this) = this.upgrade() {
4211 // If the language registry has been reloaded, then remove and
4212 // re-assign the languages on all open buffers.
4213 let reload_count = languages.reload_count();
4214 if reload_count > prev_reload_count {
4215 prev_reload_count = reload_count;
4216 this.update(cx, |this, cx| {
4217 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4218 for buffer in buffer_store.buffers() {
4219 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4220 {
4221 buffer
4222 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4223 if let Some(local) = this.as_local_mut() {
4224 local.reset_buffer(&buffer, &f, cx);
4225
4226 if local
4227 .registered_buffers
4228 .contains_key(&buffer.read(cx).remote_id())
4229 && let Some(file_url) =
4230 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4231 {
4232 local.unregister_buffer_from_language_servers(
4233 &buffer, &file_url, cx,
4234 );
4235 }
4236 }
4237 }
4238 }
4239 });
4240 })
4241 .ok();
4242 }
4243
4244 this.update(cx, |this, cx| {
4245 let mut plain_text_buffers = Vec::new();
4246 let mut buffers_with_unknown_injections = Vec::new();
4247 for handle in this.buffer_store.read(cx).buffers() {
4248 let buffer = handle.read(cx);
4249 if buffer.language().is_none()
4250 || buffer.language() == Some(&*language::PLAIN_TEXT)
4251 {
4252 plain_text_buffers.push(handle);
4253 } else if buffer.contains_unknown_injections() {
4254 buffers_with_unknown_injections.push(handle);
4255 }
4256 }
4257
4258 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4259 // and reused later in the invisible worktrees.
4260 plain_text_buffers.sort_by_key(|buffer| {
4261 Reverse(
4262 File::from_dyn(buffer.read(cx).file())
4263 .map(|file| file.worktree.read(cx).is_visible()),
4264 )
4265 });
4266
4267 for buffer in plain_text_buffers {
4268 this.detect_language_for_buffer(&buffer, cx);
4269 if let Some(local) = this.as_local_mut() {
4270 local.initialize_buffer(&buffer, cx);
4271 if local
4272 .registered_buffers
4273 .contains_key(&buffer.read(cx).remote_id())
4274 {
4275 local.register_buffer_with_language_servers(
4276 &buffer,
4277 HashSet::default(),
4278 cx,
4279 );
4280 }
4281 }
4282 }
4283
4284 for buffer in buffers_with_unknown_injections {
4285 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4286 }
4287 })
4288 .ok();
4289 }
4290 }
4291 })
4292 }
4293
4294 fn detect_language_for_buffer(
4295 &mut self,
4296 buffer_handle: &Entity<Buffer>,
4297 cx: &mut Context<Self>,
4298 ) -> Option<language::AvailableLanguage> {
4299 // If the buffer has a language, set it and start the language server if we haven't already.
4300 let buffer = buffer_handle.read(cx);
4301 let file = buffer.file()?;
4302
4303 let content = buffer.as_rope();
4304 let available_language = self.languages.language_for_file(file, Some(content), cx);
4305 if let Some(available_language) = &available_language {
4306 if let Some(Ok(Ok(new_language))) = self
4307 .languages
4308 .load_language(available_language)
4309 .now_or_never()
4310 {
4311 self.set_language_for_buffer(buffer_handle, new_language, cx);
4312 }
4313 } else {
4314 cx.emit(LspStoreEvent::LanguageDetected {
4315 buffer: buffer_handle.clone(),
4316 new_language: None,
4317 });
4318 }
4319
4320 available_language
4321 }
4322
4323 pub(crate) fn set_language_for_buffer(
4324 &mut self,
4325 buffer_entity: &Entity<Buffer>,
4326 new_language: Arc<Language>,
4327 cx: &mut Context<Self>,
4328 ) {
4329 let buffer = buffer_entity.read(cx);
4330 let buffer_file = buffer.file().cloned();
4331 let buffer_id = buffer.remote_id();
4332 if let Some(local_store) = self.as_local_mut()
4333 && local_store.registered_buffers.contains_key(&buffer_id)
4334 && let Some(abs_path) =
4335 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4336 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4337 {
4338 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4339 }
4340 buffer_entity.update(cx, |buffer, cx| {
4341 if buffer
4342 .language()
4343 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4344 {
4345 buffer.set_language(Some(new_language.clone()), cx);
4346 }
4347 });
4348
4349 let settings =
4350 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4351 let buffer_file = File::from_dyn(buffer_file.as_ref());
4352
4353 let worktree_id = if let Some(file) = buffer_file {
4354 let worktree = file.worktree.clone();
4355
4356 if let Some(local) = self.as_local_mut()
4357 && local.registered_buffers.contains_key(&buffer_id)
4358 {
4359 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4360 }
4361 Some(worktree.read(cx).id())
4362 } else {
4363 None
4364 };
4365
4366 if settings.prettier.allowed
4367 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4368 {
4369 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4370 if let Some(prettier_store) = prettier_store {
4371 prettier_store.update(cx, |prettier_store, cx| {
4372 prettier_store.install_default_prettier(
4373 worktree_id,
4374 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4375 cx,
4376 )
4377 })
4378 }
4379 }
4380
4381 cx.emit(LspStoreEvent::LanguageDetected {
4382 buffer: buffer_entity.clone(),
4383 new_language: Some(new_language),
4384 })
4385 }
4386
4387 pub fn buffer_store(&self) -> Entity<BufferStore> {
4388 self.buffer_store.clone()
4389 }
4390
4391 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4392 self.active_entry = active_entry;
4393 }
4394
4395 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4396 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4397 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4398 {
4399 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4400 summaries
4401 .iter()
4402 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4403 });
4404 if let Some(summary) = summaries.next() {
4405 client
4406 .send(proto::UpdateDiagnosticSummary {
4407 project_id: downstream_project_id,
4408 worktree_id: worktree.id().to_proto(),
4409 summary: Some(summary),
4410 more_summaries: summaries.collect(),
4411 })
4412 .log_err();
4413 }
4414 }
4415 }
4416
4417 fn is_capable_for_proto_request<R>(
4418 &self,
4419 buffer: &Entity<Buffer>,
4420 request: &R,
4421 cx: &App,
4422 ) -> bool
4423 where
4424 R: LspCommand,
4425 {
4426 self.check_if_capable_for_proto_request(
4427 buffer,
4428 |capabilities| {
4429 request.check_capabilities(AdapterServerCapabilities {
4430 server_capabilities: capabilities.clone(),
4431 code_action_kinds: None,
4432 })
4433 },
4434 cx,
4435 )
4436 }
4437
4438 fn check_if_capable_for_proto_request<F>(
4439 &self,
4440 buffer: &Entity<Buffer>,
4441 check: F,
4442 cx: &App,
4443 ) -> bool
4444 where
4445 F: FnMut(&lsp::ServerCapabilities) -> bool,
4446 {
4447 let Some(language) = buffer.read(cx).language().cloned() else {
4448 return false;
4449 };
4450 let relevant_language_servers = self
4451 .languages
4452 .lsp_adapters(&language.name())
4453 .into_iter()
4454 .map(|lsp_adapter| lsp_adapter.name())
4455 .collect::<HashSet<_>>();
4456 self.language_server_statuses
4457 .iter()
4458 .filter_map(|(server_id, server_status)| {
4459 relevant_language_servers
4460 .contains(&server_status.name)
4461 .then_some(server_id)
4462 })
4463 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4464 .any(check)
4465 }
4466
4467 pub fn request_lsp<R>(
4468 &mut self,
4469 buffer: Entity<Buffer>,
4470 server: LanguageServerToQuery,
4471 request: R,
4472 cx: &mut Context<Self>,
4473 ) -> Task<Result<R::Response>>
4474 where
4475 R: LspCommand,
4476 <R::LspRequest as lsp::request::Request>::Result: Send,
4477 <R::LspRequest as lsp::request::Request>::Params: Send,
4478 {
4479 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4480 return self.send_lsp_proto_request(
4481 buffer,
4482 upstream_client,
4483 upstream_project_id,
4484 request,
4485 cx,
4486 );
4487 }
4488
4489 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4490 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4491 local
4492 .language_servers_for_buffer(buffer, cx)
4493 .find(|(_, server)| {
4494 request.check_capabilities(server.adapter_server_capabilities())
4495 })
4496 .map(|(_, server)| server.clone())
4497 }),
4498 LanguageServerToQuery::Other(id) => self
4499 .language_server_for_local_buffer(buffer, id, cx)
4500 .and_then(|(_, server)| {
4501 request
4502 .check_capabilities(server.adapter_server_capabilities())
4503 .then(|| Arc::clone(server))
4504 }),
4505 }) else {
4506 return Task::ready(Ok(Default::default()));
4507 };
4508
4509 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4510
4511 let Some(file) = file else {
4512 return Task::ready(Ok(Default::default()));
4513 };
4514
4515 let lsp_params = match request.to_lsp_params_or_response(
4516 &file.abs_path(cx),
4517 buffer.read(cx),
4518 &language_server,
4519 cx,
4520 ) {
4521 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4522 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4523 Err(err) => {
4524 let message = format!(
4525 "{} via {} failed: {}",
4526 request.display_name(),
4527 language_server.name(),
4528 err
4529 );
4530 // rust-analyzer likes to error with this when its still loading up
4531 if !message.ends_with("content modified") {
4532 log::warn!("{message}");
4533 }
4534 return Task::ready(Err(anyhow!(message)));
4535 }
4536 };
4537
4538 let status = request.status();
4539 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4540 return Task::ready(Ok(Default::default()));
4541 }
4542 cx.spawn(async move |this, cx| {
4543 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4544
4545 let id = lsp_request.id();
4546 let _cleanup = if status.is_some() {
4547 cx.update(|cx| {
4548 this.update(cx, |this, cx| {
4549 this.on_lsp_work_start(
4550 language_server.server_id(),
4551 ProgressToken::Number(id),
4552 LanguageServerProgress {
4553 is_disk_based_diagnostics_progress: false,
4554 is_cancellable: false,
4555 title: None,
4556 message: status.clone(),
4557 percentage: None,
4558 last_update_at: cx.background_executor().now(),
4559 },
4560 cx,
4561 );
4562 })
4563 })
4564 .log_err();
4565
4566 Some(defer(|| {
4567 cx.update(|cx| {
4568 this.update(cx, |this, cx| {
4569 this.on_lsp_work_end(
4570 language_server.server_id(),
4571 ProgressToken::Number(id),
4572 cx,
4573 );
4574 })
4575 })
4576 .log_err();
4577 }))
4578 } else {
4579 None
4580 };
4581
4582 let result = lsp_request.await.into_response();
4583
4584 let response = result.map_err(|err| {
4585 let message = format!(
4586 "{} via {} failed: {}",
4587 request.display_name(),
4588 language_server.name(),
4589 err
4590 );
4591 // rust-analyzer likes to error with this when its still loading up
4592 if !message.ends_with("content modified") {
4593 log::warn!("{message}");
4594 }
4595 anyhow::anyhow!(message)
4596 })?;
4597
4598 request
4599 .response_from_lsp(
4600 response,
4601 this.upgrade().context("no app context")?,
4602 buffer,
4603 language_server.server_id(),
4604 cx.clone(),
4605 )
4606 .await
4607 })
4608 }
4609
4610 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4611 let mut language_formatters_to_check = Vec::new();
4612 for buffer in self.buffer_store.read(cx).buffers() {
4613 let buffer = buffer.read(cx);
4614 let buffer_file = File::from_dyn(buffer.file());
4615 let buffer_language = buffer.language();
4616 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4617 if buffer_language.is_some() {
4618 language_formatters_to_check.push((
4619 buffer_file.map(|f| f.worktree_id(cx)),
4620 settings.into_owned(),
4621 ));
4622 }
4623 }
4624
4625 self.request_workspace_config_refresh();
4626
4627 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4628 prettier_store.update(cx, |prettier_store, cx| {
4629 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4630 })
4631 }
4632
4633 cx.notify();
4634 }
4635
4636 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4637 let buffer_store = self.buffer_store.clone();
4638 let Some(local) = self.as_local_mut() else {
4639 return;
4640 };
4641 let mut adapters = BTreeMap::default();
4642 let get_adapter = {
4643 let languages = local.languages.clone();
4644 let environment = local.environment.clone();
4645 let weak = local.weak.clone();
4646 let worktree_store = local.worktree_store.clone();
4647 let http_client = local.http_client.clone();
4648 let fs = local.fs.clone();
4649 move |worktree_id, cx: &mut App| {
4650 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4651 Some(LocalLspAdapterDelegate::new(
4652 languages.clone(),
4653 &environment,
4654 weak.clone(),
4655 &worktree,
4656 http_client.clone(),
4657 fs.clone(),
4658 cx,
4659 ))
4660 }
4661 };
4662
4663 let mut messages_to_report = Vec::new();
4664 let (new_tree, to_stop) = {
4665 let mut rebase = local.lsp_tree.rebase();
4666 let buffers = buffer_store
4667 .read(cx)
4668 .buffers()
4669 .filter_map(|buffer| {
4670 let raw_buffer = buffer.read(cx);
4671 if !local
4672 .registered_buffers
4673 .contains_key(&raw_buffer.remote_id())
4674 {
4675 return None;
4676 }
4677 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4678 let language = raw_buffer.language().cloned()?;
4679 Some((file, language, raw_buffer.remote_id()))
4680 })
4681 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4682 for (file, language, buffer_id) in buffers {
4683 let worktree_id = file.worktree_id(cx);
4684 let Some(worktree) = local
4685 .worktree_store
4686 .read(cx)
4687 .worktree_for_id(worktree_id, cx)
4688 else {
4689 continue;
4690 };
4691
4692 if let Some((_, apply)) = local.reuse_existing_language_server(
4693 rebase.server_tree(),
4694 &worktree,
4695 &language.name(),
4696 cx,
4697 ) {
4698 (apply)(rebase.server_tree());
4699 } else if let Some(lsp_delegate) = adapters
4700 .entry(worktree_id)
4701 .or_insert_with(|| get_adapter(worktree_id, cx))
4702 .clone()
4703 {
4704 let delegate =
4705 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4706 let path = file
4707 .path()
4708 .parent()
4709 .map(Arc::from)
4710 .unwrap_or_else(|| file.path().clone());
4711 let worktree_path = ProjectPath { worktree_id, path };
4712 let abs_path = file.abs_path(cx);
4713 let nodes = rebase
4714 .walk(
4715 worktree_path,
4716 language.name(),
4717 language.manifest(),
4718 delegate.clone(),
4719 cx,
4720 )
4721 .collect::<Vec<_>>();
4722 for node in nodes {
4723 let server_id = node.server_id_or_init(|disposition| {
4724 let path = &disposition.path;
4725 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4726 let key = LanguageServerSeed {
4727 worktree_id,
4728 name: disposition.server_name.clone(),
4729 settings: disposition.settings.clone(),
4730 toolchain: local.toolchain_store.read(cx).active_toolchain(
4731 path.worktree_id,
4732 &path.path,
4733 language.name(),
4734 ),
4735 };
4736 local.language_server_ids.remove(&key);
4737
4738 let server_id = local.get_or_insert_language_server(
4739 &worktree,
4740 lsp_delegate.clone(),
4741 disposition,
4742 &language.name(),
4743 cx,
4744 );
4745 if let Some(state) = local.language_servers.get(&server_id)
4746 && let Ok(uri) = uri
4747 {
4748 state.add_workspace_folder(uri);
4749 };
4750 server_id
4751 });
4752
4753 if let Some(language_server_id) = server_id {
4754 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4755 language_server_id,
4756 name: node.name(),
4757 message:
4758 proto::update_language_server::Variant::RegisteredForBuffer(
4759 proto::RegisteredForBuffer {
4760 buffer_abs_path: abs_path
4761 .to_string_lossy()
4762 .into_owned(),
4763 buffer_id: buffer_id.to_proto(),
4764 },
4765 ),
4766 });
4767 }
4768 }
4769 } else {
4770 continue;
4771 }
4772 }
4773 rebase.finish()
4774 };
4775 for message in messages_to_report {
4776 cx.emit(message);
4777 }
4778 local.lsp_tree = new_tree;
4779 for (id, _) in to_stop {
4780 self.stop_local_language_server(id, cx).detach();
4781 }
4782 }
4783
4784 pub fn apply_code_action(
4785 &self,
4786 buffer_handle: Entity<Buffer>,
4787 mut action: CodeAction,
4788 push_to_history: bool,
4789 cx: &mut Context<Self>,
4790 ) -> Task<Result<ProjectTransaction>> {
4791 if let Some((upstream_client, project_id)) = self.upstream_client() {
4792 let request = proto::ApplyCodeAction {
4793 project_id,
4794 buffer_id: buffer_handle.read(cx).remote_id().into(),
4795 action: Some(Self::serialize_code_action(&action)),
4796 };
4797 let buffer_store = self.buffer_store();
4798 cx.spawn(async move |_, cx| {
4799 let response = upstream_client
4800 .request(request)
4801 .await?
4802 .transaction
4803 .context("missing transaction")?;
4804
4805 buffer_store
4806 .update(cx, |buffer_store, cx| {
4807 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4808 })?
4809 .await
4810 })
4811 } else if self.mode.is_local() {
4812 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4813 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4814 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4815 }) else {
4816 return Task::ready(Ok(ProjectTransaction::default()));
4817 };
4818 cx.spawn(async move |this, cx| {
4819 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4820 .await
4821 .context("resolving a code action")?;
4822 if let Some(edit) = action.lsp_action.edit()
4823 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4824 return LocalLspStore::deserialize_workspace_edit(
4825 this.upgrade().context("no app present")?,
4826 edit.clone(),
4827 push_to_history,
4828
4829 lang_server.clone(),
4830 cx,
4831 )
4832 .await;
4833 }
4834
4835 if let Some(command) = action.lsp_action.command() {
4836 let server_capabilities = lang_server.capabilities();
4837 let available_commands = server_capabilities
4838 .execute_command_provider
4839 .as_ref()
4840 .map(|options| options.commands.as_slice())
4841 .unwrap_or_default();
4842 if available_commands.contains(&command.command) {
4843 this.update(cx, |this, _| {
4844 this.as_local_mut()
4845 .unwrap()
4846 .last_workspace_edits_by_language_server
4847 .remove(&lang_server.server_id());
4848 })?;
4849
4850 let _result = lang_server
4851 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4852 command: command.command.clone(),
4853 arguments: command.arguments.clone().unwrap_or_default(),
4854 ..lsp::ExecuteCommandParams::default()
4855 })
4856 .await.into_response()
4857 .context("execute command")?;
4858
4859 return this.update(cx, |this, _| {
4860 this.as_local_mut()
4861 .unwrap()
4862 .last_workspace_edits_by_language_server
4863 .remove(&lang_server.server_id())
4864 .unwrap_or_default()
4865 });
4866 } else {
4867 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4868 }
4869 }
4870
4871 Ok(ProjectTransaction::default())
4872 })
4873 } else {
4874 Task::ready(Err(anyhow!("no upstream client and not local")))
4875 }
4876 }
4877
4878 pub fn apply_code_action_kind(
4879 &mut self,
4880 buffers: HashSet<Entity<Buffer>>,
4881 kind: CodeActionKind,
4882 push_to_history: bool,
4883 cx: &mut Context<Self>,
4884 ) -> Task<anyhow::Result<ProjectTransaction>> {
4885 if self.as_local().is_some() {
4886 cx.spawn(async move |lsp_store, cx| {
4887 let buffers = buffers.into_iter().collect::<Vec<_>>();
4888 let result = LocalLspStore::execute_code_action_kind_locally(
4889 lsp_store.clone(),
4890 buffers,
4891 kind,
4892 push_to_history,
4893 cx,
4894 )
4895 .await;
4896 lsp_store.update(cx, |lsp_store, _| {
4897 lsp_store.update_last_formatting_failure(&result);
4898 })?;
4899 result
4900 })
4901 } else if let Some((client, project_id)) = self.upstream_client() {
4902 let buffer_store = self.buffer_store();
4903 cx.spawn(async move |lsp_store, cx| {
4904 let result = client
4905 .request(proto::ApplyCodeActionKind {
4906 project_id,
4907 kind: kind.as_str().to_owned(),
4908 buffer_ids: buffers
4909 .iter()
4910 .map(|buffer| {
4911 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4912 })
4913 .collect::<Result<_>>()?,
4914 })
4915 .await
4916 .and_then(|result| result.transaction.context("missing transaction"));
4917 lsp_store.update(cx, |lsp_store, _| {
4918 lsp_store.update_last_formatting_failure(&result);
4919 })?;
4920
4921 let transaction_response = result?;
4922 buffer_store
4923 .update(cx, |buffer_store, cx| {
4924 buffer_store.deserialize_project_transaction(
4925 transaction_response,
4926 push_to_history,
4927 cx,
4928 )
4929 })?
4930 .await
4931 })
4932 } else {
4933 Task::ready(Ok(ProjectTransaction::default()))
4934 }
4935 }
4936
4937 pub fn resolved_hint(
4938 &mut self,
4939 buffer_id: BufferId,
4940 id: InlayId,
4941 cx: &mut Context<Self>,
4942 ) -> Option<ResolvedHint> {
4943 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4944
4945 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4946 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4947 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4948 let (server_id, resolve_data) = match &hint.resolve_state {
4949 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4950 ResolveState::Resolving => {
4951 return Some(ResolvedHint::Resolving(
4952 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4953 ));
4954 }
4955 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4956 };
4957
4958 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4959 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4960 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4961 id,
4962 cx.spawn(async move |lsp_store, cx| {
4963 let resolved_hint = resolve_task.await;
4964 lsp_store
4965 .update(cx, |lsp_store, _| {
4966 if let Some(old_inlay_hint) = lsp_store
4967 .lsp_data
4968 .get_mut(&buffer_id)
4969 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4970 {
4971 match resolved_hint {
4972 Ok(resolved_hint) => {
4973 *old_inlay_hint = resolved_hint;
4974 }
4975 Err(e) => {
4976 old_inlay_hint.resolve_state =
4977 ResolveState::CanResolve(server_id, resolve_data);
4978 log::error!("Inlay hint resolve failed: {e:#}");
4979 }
4980 }
4981 }
4982 })
4983 .ok();
4984 })
4985 .shared(),
4986 );
4987 debug_assert!(
4988 previous_task.is_none(),
4989 "Did not change hint's resolve state after spawning its resolve"
4990 );
4991 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4992 None
4993 }
4994
4995 fn resolve_inlay_hint(
4996 &self,
4997 mut hint: InlayHint,
4998 buffer: Entity<Buffer>,
4999 server_id: LanguageServerId,
5000 cx: &mut Context<Self>,
5001 ) -> Task<anyhow::Result<InlayHint>> {
5002 if let Some((upstream_client, project_id)) = self.upstream_client() {
5003 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5004 {
5005 hint.resolve_state = ResolveState::Resolved;
5006 return Task::ready(Ok(hint));
5007 }
5008 let request = proto::ResolveInlayHint {
5009 project_id,
5010 buffer_id: buffer.read(cx).remote_id().into(),
5011 language_server_id: server_id.0 as u64,
5012 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5013 };
5014 cx.background_spawn(async move {
5015 let response = upstream_client
5016 .request(request)
5017 .await
5018 .context("inlay hints proto request")?;
5019 match response.hint {
5020 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5021 .context("inlay hints proto resolve response conversion"),
5022 None => Ok(hint),
5023 }
5024 })
5025 } else {
5026 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5027 self.language_server_for_local_buffer(buffer, server_id, cx)
5028 .map(|(_, server)| server.clone())
5029 }) else {
5030 return Task::ready(Ok(hint));
5031 };
5032 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5033 return Task::ready(Ok(hint));
5034 }
5035 let buffer_snapshot = buffer.read(cx).snapshot();
5036 cx.spawn(async move |_, cx| {
5037 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5038 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5039 );
5040 let resolved_hint = resolve_task
5041 .await
5042 .into_response()
5043 .context("inlay hint resolve LSP request")?;
5044 let resolved_hint = InlayHints::lsp_to_project_hint(
5045 resolved_hint,
5046 &buffer,
5047 server_id,
5048 ResolveState::Resolved,
5049 false,
5050 cx,
5051 )
5052 .await?;
5053 Ok(resolved_hint)
5054 })
5055 }
5056 }
5057
5058 pub fn resolve_color_presentation(
5059 &mut self,
5060 mut color: DocumentColor,
5061 buffer: Entity<Buffer>,
5062 server_id: LanguageServerId,
5063 cx: &mut Context<Self>,
5064 ) -> Task<Result<DocumentColor>> {
5065 if color.resolved {
5066 return Task::ready(Ok(color));
5067 }
5068
5069 if let Some((upstream_client, project_id)) = self.upstream_client() {
5070 let start = color.lsp_range.start;
5071 let end = color.lsp_range.end;
5072 let request = proto::GetColorPresentation {
5073 project_id,
5074 server_id: server_id.to_proto(),
5075 buffer_id: buffer.read(cx).remote_id().into(),
5076 color: Some(proto::ColorInformation {
5077 red: color.color.red,
5078 green: color.color.green,
5079 blue: color.color.blue,
5080 alpha: color.color.alpha,
5081 lsp_range_start: Some(proto::PointUtf16 {
5082 row: start.line,
5083 column: start.character,
5084 }),
5085 lsp_range_end: Some(proto::PointUtf16 {
5086 row: end.line,
5087 column: end.character,
5088 }),
5089 }),
5090 };
5091 cx.background_spawn(async move {
5092 let response = upstream_client
5093 .request(request)
5094 .await
5095 .context("color presentation proto request")?;
5096 color.resolved = true;
5097 color.color_presentations = response
5098 .presentations
5099 .into_iter()
5100 .map(|presentation| ColorPresentation {
5101 label: SharedString::from(presentation.label),
5102 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5103 additional_text_edits: presentation
5104 .additional_text_edits
5105 .into_iter()
5106 .filter_map(deserialize_lsp_edit)
5107 .collect(),
5108 })
5109 .collect();
5110 Ok(color)
5111 })
5112 } else {
5113 let path = match buffer
5114 .update(cx, |buffer, cx| {
5115 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5116 })
5117 .context("buffer with the missing path")
5118 {
5119 Ok(path) => path,
5120 Err(e) => return Task::ready(Err(e)),
5121 };
5122 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5123 self.language_server_for_local_buffer(buffer, server_id, cx)
5124 .map(|(_, server)| server.clone())
5125 }) else {
5126 return Task::ready(Ok(color));
5127 };
5128 cx.background_spawn(async move {
5129 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5130 lsp::ColorPresentationParams {
5131 text_document: make_text_document_identifier(&path)?,
5132 color: color.color,
5133 range: color.lsp_range,
5134 work_done_progress_params: Default::default(),
5135 partial_result_params: Default::default(),
5136 },
5137 );
5138 color.color_presentations = resolve_task
5139 .await
5140 .into_response()
5141 .context("color presentation resolve LSP request")?
5142 .into_iter()
5143 .map(|presentation| ColorPresentation {
5144 label: SharedString::from(presentation.label),
5145 text_edit: presentation.text_edit,
5146 additional_text_edits: presentation
5147 .additional_text_edits
5148 .unwrap_or_default(),
5149 })
5150 .collect();
5151 color.resolved = true;
5152 Ok(color)
5153 })
5154 }
5155 }
5156
5157 pub(crate) fn linked_edits(
5158 &mut self,
5159 buffer: &Entity<Buffer>,
5160 position: Anchor,
5161 cx: &mut Context<Self>,
5162 ) -> Task<Result<Vec<Range<Anchor>>>> {
5163 let snapshot = buffer.read(cx).snapshot();
5164 let scope = snapshot.language_scope_at(position);
5165 let Some(server_id) = self
5166 .as_local()
5167 .and_then(|local| {
5168 buffer.update(cx, |buffer, cx| {
5169 local
5170 .language_servers_for_buffer(buffer, cx)
5171 .filter(|(_, server)| {
5172 LinkedEditingRange::check_server_capabilities(server.capabilities())
5173 })
5174 .filter(|(adapter, _)| {
5175 scope
5176 .as_ref()
5177 .map(|scope| scope.language_allowed(&adapter.name))
5178 .unwrap_or(true)
5179 })
5180 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5181 .next()
5182 })
5183 })
5184 .or_else(|| {
5185 self.upstream_client()
5186 .is_some()
5187 .then_some(LanguageServerToQuery::FirstCapable)
5188 })
5189 .filter(|_| {
5190 maybe!({
5191 let language = buffer.read(cx).language_at(position)?;
5192 Some(
5193 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5194 .linked_edits,
5195 )
5196 }) == Some(true)
5197 })
5198 else {
5199 return Task::ready(Ok(Vec::new()));
5200 };
5201
5202 self.request_lsp(
5203 buffer.clone(),
5204 server_id,
5205 LinkedEditingRange { position },
5206 cx,
5207 )
5208 }
5209
5210 fn apply_on_type_formatting(
5211 &mut self,
5212 buffer: Entity<Buffer>,
5213 position: Anchor,
5214 trigger: String,
5215 cx: &mut Context<Self>,
5216 ) -> Task<Result<Option<Transaction>>> {
5217 if let Some((client, project_id)) = self.upstream_client() {
5218 if !self.check_if_capable_for_proto_request(
5219 &buffer,
5220 |capabilities| {
5221 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5222 },
5223 cx,
5224 ) {
5225 return Task::ready(Ok(None));
5226 }
5227 let request = proto::OnTypeFormatting {
5228 project_id,
5229 buffer_id: buffer.read(cx).remote_id().into(),
5230 position: Some(serialize_anchor(&position)),
5231 trigger,
5232 version: serialize_version(&buffer.read(cx).version()),
5233 };
5234 cx.background_spawn(async move {
5235 client
5236 .request(request)
5237 .await?
5238 .transaction
5239 .map(language::proto::deserialize_transaction)
5240 .transpose()
5241 })
5242 } else if let Some(local) = self.as_local_mut() {
5243 let buffer_id = buffer.read(cx).remote_id();
5244 local.buffers_being_formatted.insert(buffer_id);
5245 cx.spawn(async move |this, cx| {
5246 let _cleanup = defer({
5247 let this = this.clone();
5248 let mut cx = cx.clone();
5249 move || {
5250 this.update(&mut cx, |this, _| {
5251 if let Some(local) = this.as_local_mut() {
5252 local.buffers_being_formatted.remove(&buffer_id);
5253 }
5254 })
5255 .ok();
5256 }
5257 });
5258
5259 buffer
5260 .update(cx, |buffer, _| {
5261 buffer.wait_for_edits(Some(position.timestamp))
5262 })?
5263 .await?;
5264 this.update(cx, |this, cx| {
5265 let position = position.to_point_utf16(buffer.read(cx));
5266 this.on_type_format(buffer, position, trigger, false, cx)
5267 })?
5268 .await
5269 })
5270 } else {
5271 Task::ready(Err(anyhow!("No upstream client or local language server")))
5272 }
5273 }
5274
5275 pub fn on_type_format<T: ToPointUtf16>(
5276 &mut self,
5277 buffer: Entity<Buffer>,
5278 position: T,
5279 trigger: String,
5280 push_to_history: bool,
5281 cx: &mut Context<Self>,
5282 ) -> Task<Result<Option<Transaction>>> {
5283 let position = position.to_point_utf16(buffer.read(cx));
5284 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5285 }
5286
5287 fn on_type_format_impl(
5288 &mut self,
5289 buffer: Entity<Buffer>,
5290 position: PointUtf16,
5291 trigger: String,
5292 push_to_history: bool,
5293 cx: &mut Context<Self>,
5294 ) -> Task<Result<Option<Transaction>>> {
5295 let options = buffer.update(cx, |buffer, cx| {
5296 lsp_command::lsp_formatting_options(
5297 language_settings(
5298 buffer.language_at(position).map(|l| l.name()),
5299 buffer.file(),
5300 cx,
5301 )
5302 .as_ref(),
5303 )
5304 });
5305
5306 cx.spawn(async move |this, cx| {
5307 if let Some(waiter) =
5308 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5309 {
5310 waiter.await?;
5311 }
5312 cx.update(|cx| {
5313 this.update(cx, |this, cx| {
5314 this.request_lsp(
5315 buffer.clone(),
5316 LanguageServerToQuery::FirstCapable,
5317 OnTypeFormatting {
5318 position,
5319 trigger,
5320 options,
5321 push_to_history,
5322 },
5323 cx,
5324 )
5325 })
5326 })??
5327 .await
5328 })
5329 }
5330
5331 pub fn definitions(
5332 &mut self,
5333 buffer: &Entity<Buffer>,
5334 position: PointUtf16,
5335 cx: &mut Context<Self>,
5336 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5337 if let Some((upstream_client, project_id)) = self.upstream_client() {
5338 let request = GetDefinitions { position };
5339 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5340 return Task::ready(Ok(None));
5341 }
5342 let request_task = upstream_client.request_lsp(
5343 project_id,
5344 None,
5345 LSP_REQUEST_TIMEOUT,
5346 cx.background_executor().clone(),
5347 request.to_proto(project_id, buffer.read(cx)),
5348 );
5349 let buffer = buffer.clone();
5350 cx.spawn(async move |weak_lsp_store, cx| {
5351 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5352 return Ok(None);
5353 };
5354 let Some(responses) = request_task.await? else {
5355 return Ok(None);
5356 };
5357 let actions = join_all(responses.payload.into_iter().map(|response| {
5358 GetDefinitions { position }.response_from_proto(
5359 response.response,
5360 lsp_store.clone(),
5361 buffer.clone(),
5362 cx.clone(),
5363 )
5364 }))
5365 .await;
5366
5367 Ok(Some(
5368 actions
5369 .into_iter()
5370 .collect::<Result<Vec<Vec<_>>>>()?
5371 .into_iter()
5372 .flatten()
5373 .dedup()
5374 .collect(),
5375 ))
5376 })
5377 } else {
5378 let definitions_task = self.request_multiple_lsp_locally(
5379 buffer,
5380 Some(position),
5381 GetDefinitions { position },
5382 cx,
5383 );
5384 cx.background_spawn(async move {
5385 Ok(Some(
5386 definitions_task
5387 .await
5388 .into_iter()
5389 .flat_map(|(_, definitions)| definitions)
5390 .dedup()
5391 .collect(),
5392 ))
5393 })
5394 }
5395 }
5396
5397 pub fn declarations(
5398 &mut self,
5399 buffer: &Entity<Buffer>,
5400 position: PointUtf16,
5401 cx: &mut Context<Self>,
5402 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5403 if let Some((upstream_client, project_id)) = self.upstream_client() {
5404 let request = GetDeclarations { position };
5405 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5406 return Task::ready(Ok(None));
5407 }
5408 let request_task = upstream_client.request_lsp(
5409 project_id,
5410 None,
5411 LSP_REQUEST_TIMEOUT,
5412 cx.background_executor().clone(),
5413 request.to_proto(project_id, buffer.read(cx)),
5414 );
5415 let buffer = buffer.clone();
5416 cx.spawn(async move |weak_lsp_store, cx| {
5417 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5418 return Ok(None);
5419 };
5420 let Some(responses) = request_task.await? else {
5421 return Ok(None);
5422 };
5423 let actions = join_all(responses.payload.into_iter().map(|response| {
5424 GetDeclarations { position }.response_from_proto(
5425 response.response,
5426 lsp_store.clone(),
5427 buffer.clone(),
5428 cx.clone(),
5429 )
5430 }))
5431 .await;
5432
5433 Ok(Some(
5434 actions
5435 .into_iter()
5436 .collect::<Result<Vec<Vec<_>>>>()?
5437 .into_iter()
5438 .flatten()
5439 .dedup()
5440 .collect(),
5441 ))
5442 })
5443 } else {
5444 let declarations_task = self.request_multiple_lsp_locally(
5445 buffer,
5446 Some(position),
5447 GetDeclarations { position },
5448 cx,
5449 );
5450 cx.background_spawn(async move {
5451 Ok(Some(
5452 declarations_task
5453 .await
5454 .into_iter()
5455 .flat_map(|(_, declarations)| declarations)
5456 .dedup()
5457 .collect(),
5458 ))
5459 })
5460 }
5461 }
5462
5463 pub fn type_definitions(
5464 &mut self,
5465 buffer: &Entity<Buffer>,
5466 position: PointUtf16,
5467 cx: &mut Context<Self>,
5468 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5469 if let Some((upstream_client, project_id)) = self.upstream_client() {
5470 let request = GetTypeDefinitions { position };
5471 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5472 return Task::ready(Ok(None));
5473 }
5474 let request_task = upstream_client.request_lsp(
5475 project_id,
5476 None,
5477 LSP_REQUEST_TIMEOUT,
5478 cx.background_executor().clone(),
5479 request.to_proto(project_id, buffer.read(cx)),
5480 );
5481 let buffer = buffer.clone();
5482 cx.spawn(async move |weak_lsp_store, cx| {
5483 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5484 return Ok(None);
5485 };
5486 let Some(responses) = request_task.await? else {
5487 return Ok(None);
5488 };
5489 let actions = join_all(responses.payload.into_iter().map(|response| {
5490 GetTypeDefinitions { position }.response_from_proto(
5491 response.response,
5492 lsp_store.clone(),
5493 buffer.clone(),
5494 cx.clone(),
5495 )
5496 }))
5497 .await;
5498
5499 Ok(Some(
5500 actions
5501 .into_iter()
5502 .collect::<Result<Vec<Vec<_>>>>()?
5503 .into_iter()
5504 .flatten()
5505 .dedup()
5506 .collect(),
5507 ))
5508 })
5509 } else {
5510 let type_definitions_task = self.request_multiple_lsp_locally(
5511 buffer,
5512 Some(position),
5513 GetTypeDefinitions { position },
5514 cx,
5515 );
5516 cx.background_spawn(async move {
5517 Ok(Some(
5518 type_definitions_task
5519 .await
5520 .into_iter()
5521 .flat_map(|(_, type_definitions)| type_definitions)
5522 .dedup()
5523 .collect(),
5524 ))
5525 })
5526 }
5527 }
5528
5529 pub fn implementations(
5530 &mut self,
5531 buffer: &Entity<Buffer>,
5532 position: PointUtf16,
5533 cx: &mut Context<Self>,
5534 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5535 if let Some((upstream_client, project_id)) = self.upstream_client() {
5536 let request = GetImplementations { position };
5537 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5538 return Task::ready(Ok(None));
5539 }
5540 let request_task = upstream_client.request_lsp(
5541 project_id,
5542 None,
5543 LSP_REQUEST_TIMEOUT,
5544 cx.background_executor().clone(),
5545 request.to_proto(project_id, buffer.read(cx)),
5546 );
5547 let buffer = buffer.clone();
5548 cx.spawn(async move |weak_lsp_store, cx| {
5549 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5550 return Ok(None);
5551 };
5552 let Some(responses) = request_task.await? else {
5553 return Ok(None);
5554 };
5555 let actions = join_all(responses.payload.into_iter().map(|response| {
5556 GetImplementations { position }.response_from_proto(
5557 response.response,
5558 lsp_store.clone(),
5559 buffer.clone(),
5560 cx.clone(),
5561 )
5562 }))
5563 .await;
5564
5565 Ok(Some(
5566 actions
5567 .into_iter()
5568 .collect::<Result<Vec<Vec<_>>>>()?
5569 .into_iter()
5570 .flatten()
5571 .dedup()
5572 .collect(),
5573 ))
5574 })
5575 } else {
5576 let implementations_task = self.request_multiple_lsp_locally(
5577 buffer,
5578 Some(position),
5579 GetImplementations { position },
5580 cx,
5581 );
5582 cx.background_spawn(async move {
5583 Ok(Some(
5584 implementations_task
5585 .await
5586 .into_iter()
5587 .flat_map(|(_, implementations)| implementations)
5588 .dedup()
5589 .collect(),
5590 ))
5591 })
5592 }
5593 }
5594
5595 pub fn references(
5596 &mut self,
5597 buffer: &Entity<Buffer>,
5598 position: PointUtf16,
5599 cx: &mut Context<Self>,
5600 ) -> Task<Result<Option<Vec<Location>>>> {
5601 if let Some((upstream_client, project_id)) = self.upstream_client() {
5602 let request = GetReferences { position };
5603 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5604 return Task::ready(Ok(None));
5605 }
5606
5607 let request_task = upstream_client.request_lsp(
5608 project_id,
5609 None,
5610 LSP_REQUEST_TIMEOUT,
5611 cx.background_executor().clone(),
5612 request.to_proto(project_id, buffer.read(cx)),
5613 );
5614 let buffer = buffer.clone();
5615 cx.spawn(async move |weak_lsp_store, cx| {
5616 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5617 return Ok(None);
5618 };
5619 let Some(responses) = request_task.await? else {
5620 return Ok(None);
5621 };
5622
5623 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5624 GetReferences { position }.response_from_proto(
5625 lsp_response.response,
5626 lsp_store.clone(),
5627 buffer.clone(),
5628 cx.clone(),
5629 )
5630 }))
5631 .await
5632 .into_iter()
5633 .collect::<Result<Vec<Vec<_>>>>()?
5634 .into_iter()
5635 .flatten()
5636 .dedup()
5637 .collect();
5638 Ok(Some(locations))
5639 })
5640 } else {
5641 let references_task = self.request_multiple_lsp_locally(
5642 buffer,
5643 Some(position),
5644 GetReferences { position },
5645 cx,
5646 );
5647 cx.background_spawn(async move {
5648 Ok(Some(
5649 references_task
5650 .await
5651 .into_iter()
5652 .flat_map(|(_, references)| references)
5653 .dedup()
5654 .collect(),
5655 ))
5656 })
5657 }
5658 }
5659
5660 pub fn code_actions(
5661 &mut self,
5662 buffer: &Entity<Buffer>,
5663 range: Range<Anchor>,
5664 kinds: Option<Vec<CodeActionKind>>,
5665 cx: &mut Context<Self>,
5666 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5667 if let Some((upstream_client, project_id)) = self.upstream_client() {
5668 let request = GetCodeActions {
5669 range: range.clone(),
5670 kinds: kinds.clone(),
5671 };
5672 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5673 return Task::ready(Ok(None));
5674 }
5675 let request_task = upstream_client.request_lsp(
5676 project_id,
5677 None,
5678 LSP_REQUEST_TIMEOUT,
5679 cx.background_executor().clone(),
5680 request.to_proto(project_id, buffer.read(cx)),
5681 );
5682 let buffer = buffer.clone();
5683 cx.spawn(async move |weak_lsp_store, cx| {
5684 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5685 return Ok(None);
5686 };
5687 let Some(responses) = request_task.await? else {
5688 return Ok(None);
5689 };
5690 let actions = join_all(responses.payload.into_iter().map(|response| {
5691 GetCodeActions {
5692 range: range.clone(),
5693 kinds: kinds.clone(),
5694 }
5695 .response_from_proto(
5696 response.response,
5697 lsp_store.clone(),
5698 buffer.clone(),
5699 cx.clone(),
5700 )
5701 }))
5702 .await;
5703
5704 Ok(Some(
5705 actions
5706 .into_iter()
5707 .collect::<Result<Vec<Vec<_>>>>()?
5708 .into_iter()
5709 .flatten()
5710 .collect(),
5711 ))
5712 })
5713 } else {
5714 let all_actions_task = self.request_multiple_lsp_locally(
5715 buffer,
5716 Some(range.start),
5717 GetCodeActions { range, kinds },
5718 cx,
5719 );
5720 cx.background_spawn(async move {
5721 Ok(Some(
5722 all_actions_task
5723 .await
5724 .into_iter()
5725 .flat_map(|(_, actions)| actions)
5726 .collect(),
5727 ))
5728 })
5729 }
5730 }
5731
5732 pub fn code_lens_actions(
5733 &mut self,
5734 buffer: &Entity<Buffer>,
5735 cx: &mut Context<Self>,
5736 ) -> CodeLensTask {
5737 let version_queried_for = buffer.read(cx).version();
5738 let buffer_id = buffer.read(cx).remote_id();
5739 let existing_servers = self.as_local().map(|local| {
5740 local
5741 .buffers_opened_in_servers
5742 .get(&buffer_id)
5743 .cloned()
5744 .unwrap_or_default()
5745 });
5746
5747 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5748 if let Some(cached_lens) = &lsp_data.code_lens {
5749 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5750 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5751 existing_servers != cached_lens.lens.keys().copied().collect()
5752 });
5753 if !has_different_servers {
5754 return Task::ready(Ok(Some(
5755 cached_lens.lens.values().flatten().cloned().collect(),
5756 )))
5757 .shared();
5758 }
5759 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5760 if !version_queried_for.changed_since(updating_for) {
5761 return running_update.clone();
5762 }
5763 }
5764 }
5765 }
5766
5767 let lens_lsp_data = self
5768 .latest_lsp_data(buffer, cx)
5769 .code_lens
5770 .get_or_insert_default();
5771 let buffer = buffer.clone();
5772 let query_version_queried_for = version_queried_for.clone();
5773 let new_task = cx
5774 .spawn(async move |lsp_store, cx| {
5775 cx.background_executor()
5776 .timer(Duration::from_millis(30))
5777 .await;
5778 let fetched_lens = lsp_store
5779 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5780 .map_err(Arc::new)?
5781 .await
5782 .context("fetching code lens")
5783 .map_err(Arc::new);
5784 let fetched_lens = match fetched_lens {
5785 Ok(fetched_lens) => fetched_lens,
5786 Err(e) => {
5787 lsp_store
5788 .update(cx, |lsp_store, _| {
5789 if let Some(lens_lsp_data) = lsp_store
5790 .lsp_data
5791 .get_mut(&buffer_id)
5792 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5793 {
5794 lens_lsp_data.update = None;
5795 }
5796 })
5797 .ok();
5798 return Err(e);
5799 }
5800 };
5801
5802 lsp_store
5803 .update(cx, |lsp_store, _| {
5804 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5805 let code_lens = lsp_data.code_lens.as_mut()?;
5806 if let Some(fetched_lens) = fetched_lens {
5807 if lsp_data.buffer_version == query_version_queried_for {
5808 code_lens.lens.extend(fetched_lens);
5809 } else if !lsp_data
5810 .buffer_version
5811 .changed_since(&query_version_queried_for)
5812 {
5813 lsp_data.buffer_version = query_version_queried_for;
5814 code_lens.lens = fetched_lens;
5815 }
5816 }
5817 code_lens.update = None;
5818 Some(code_lens.lens.values().flatten().cloned().collect())
5819 })
5820 .map_err(Arc::new)
5821 })
5822 .shared();
5823 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5824 new_task
5825 }
5826
5827 fn fetch_code_lens(
5828 &mut self,
5829 buffer: &Entity<Buffer>,
5830 cx: &mut Context<Self>,
5831 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5832 if let Some((upstream_client, project_id)) = self.upstream_client() {
5833 let request = GetCodeLens;
5834 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5835 return Task::ready(Ok(None));
5836 }
5837 let request_task = upstream_client.request_lsp(
5838 project_id,
5839 None,
5840 LSP_REQUEST_TIMEOUT,
5841 cx.background_executor().clone(),
5842 request.to_proto(project_id, buffer.read(cx)),
5843 );
5844 let buffer = buffer.clone();
5845 cx.spawn(async move |weak_lsp_store, cx| {
5846 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5847 return Ok(None);
5848 };
5849 let Some(responses) = request_task.await? else {
5850 return Ok(None);
5851 };
5852
5853 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5854 let lsp_store = lsp_store.clone();
5855 let buffer = buffer.clone();
5856 let cx = cx.clone();
5857 async move {
5858 (
5859 LanguageServerId::from_proto(response.server_id),
5860 GetCodeLens
5861 .response_from_proto(response.response, lsp_store, buffer, cx)
5862 .await,
5863 )
5864 }
5865 }))
5866 .await;
5867
5868 let mut has_errors = false;
5869 let code_lens_actions = code_lens_actions
5870 .into_iter()
5871 .filter_map(|(server_id, code_lens)| match code_lens {
5872 Ok(code_lens) => Some((server_id, code_lens)),
5873 Err(e) => {
5874 has_errors = true;
5875 log::error!("{e:#}");
5876 None
5877 }
5878 })
5879 .collect::<HashMap<_, _>>();
5880 anyhow::ensure!(
5881 !has_errors || !code_lens_actions.is_empty(),
5882 "Failed to fetch code lens"
5883 );
5884 Ok(Some(code_lens_actions))
5885 })
5886 } else {
5887 let code_lens_actions_task =
5888 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5889 cx.background_spawn(async move {
5890 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5891 })
5892 }
5893 }
5894
5895 #[inline(never)]
5896 pub fn completions(
5897 &self,
5898 buffer: &Entity<Buffer>,
5899 position: PointUtf16,
5900 context: CompletionContext,
5901 cx: &mut Context<Self>,
5902 ) -> Task<Result<Vec<CompletionResponse>>> {
5903 let language_registry = self.languages.clone();
5904
5905 if let Some((upstream_client, project_id)) = self.upstream_client() {
5906 let request = GetCompletions { position, context };
5907 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5908 return Task::ready(Ok(Vec::new()));
5909 }
5910 let task = self.send_lsp_proto_request(
5911 buffer.clone(),
5912 upstream_client,
5913 project_id,
5914 request,
5915 cx,
5916 );
5917 let language = buffer.read(cx).language().cloned();
5918
5919 // In the future, we should provide project guests with the names of LSP adapters,
5920 // so that they can use the correct LSP adapter when computing labels. For now,
5921 // guests just use the first LSP adapter associated with the buffer's language.
5922 let lsp_adapter = language.as_ref().and_then(|language| {
5923 language_registry
5924 .lsp_adapters(&language.name())
5925 .first()
5926 .cloned()
5927 });
5928
5929 cx.foreground_executor().spawn(async move {
5930 let completion_response = task.await?;
5931 let completions = populate_labels_for_completions(
5932 completion_response.completions,
5933 language,
5934 lsp_adapter,
5935 )
5936 .await;
5937 Ok(vec![CompletionResponse {
5938 completions,
5939 display_options: CompletionDisplayOptions::default(),
5940 is_incomplete: completion_response.is_incomplete,
5941 }])
5942 })
5943 } else if let Some(local) = self.as_local() {
5944 let snapshot = buffer.read(cx).snapshot();
5945 let offset = position.to_offset(&snapshot);
5946 let scope = snapshot.language_scope_at(offset);
5947 let language = snapshot.language().cloned();
5948 let completion_settings = language_settings(
5949 language.as_ref().map(|language| language.name()),
5950 buffer.read(cx).file(),
5951 cx,
5952 )
5953 .completions
5954 .clone();
5955 if !completion_settings.lsp {
5956 return Task::ready(Ok(Vec::new()));
5957 }
5958
5959 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5960 local
5961 .language_servers_for_buffer(buffer, cx)
5962 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5963 .filter(|(adapter, _)| {
5964 scope
5965 .as_ref()
5966 .map(|scope| scope.language_allowed(&adapter.name))
5967 .unwrap_or(true)
5968 })
5969 .map(|(_, server)| server.server_id())
5970 .collect()
5971 });
5972
5973 let buffer = buffer.clone();
5974 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5975 let lsp_timeout = if lsp_timeout > 0 {
5976 Some(Duration::from_millis(lsp_timeout))
5977 } else {
5978 None
5979 };
5980 cx.spawn(async move |this, cx| {
5981 let mut tasks = Vec::with_capacity(server_ids.len());
5982 this.update(cx, |lsp_store, cx| {
5983 for server_id in server_ids {
5984 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5985 let lsp_timeout = lsp_timeout
5986 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5987 let mut timeout = cx.background_spawn(async move {
5988 match lsp_timeout {
5989 Some(lsp_timeout) => {
5990 lsp_timeout.await;
5991 true
5992 },
5993 None => false,
5994 }
5995 }).fuse();
5996 let mut lsp_request = lsp_store.request_lsp(
5997 buffer.clone(),
5998 LanguageServerToQuery::Other(server_id),
5999 GetCompletions {
6000 position,
6001 context: context.clone(),
6002 },
6003 cx,
6004 ).fuse();
6005 let new_task = cx.background_spawn(async move {
6006 select_biased! {
6007 response = lsp_request => anyhow::Ok(Some(response?)),
6008 timeout_happened = timeout => {
6009 if timeout_happened {
6010 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6011 Ok(None)
6012 } else {
6013 let completions = lsp_request.await?;
6014 Ok(Some(completions))
6015 }
6016 },
6017 }
6018 });
6019 tasks.push((lsp_adapter, new_task));
6020 }
6021 })?;
6022
6023 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6024 let completion_response = task.await.ok()??;
6025 let completions = populate_labels_for_completions(
6026 completion_response.completions,
6027 language.clone(),
6028 lsp_adapter,
6029 )
6030 .await;
6031 Some(CompletionResponse {
6032 completions,
6033 display_options: CompletionDisplayOptions::default(),
6034 is_incomplete: completion_response.is_incomplete,
6035 })
6036 });
6037
6038 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6039
6040 Ok(responses.into_iter().flatten().collect())
6041 })
6042 } else {
6043 Task::ready(Err(anyhow!("No upstream client or local language server")))
6044 }
6045 }
6046
6047 pub fn resolve_completions(
6048 &self,
6049 buffer: Entity<Buffer>,
6050 completion_indices: Vec<usize>,
6051 completions: Rc<RefCell<Box<[Completion]>>>,
6052 cx: &mut Context<Self>,
6053 ) -> Task<Result<bool>> {
6054 let client = self.upstream_client();
6055 let buffer_id = buffer.read(cx).remote_id();
6056 let buffer_snapshot = buffer.read(cx).snapshot();
6057
6058 if !self.check_if_capable_for_proto_request(
6059 &buffer,
6060 GetCompletions::can_resolve_completions,
6061 cx,
6062 ) {
6063 return Task::ready(Ok(false));
6064 }
6065 cx.spawn(async move |lsp_store, cx| {
6066 let mut did_resolve = false;
6067 if let Some((client, project_id)) = client {
6068 for completion_index in completion_indices {
6069 let server_id = {
6070 let completion = &completions.borrow()[completion_index];
6071 completion.source.server_id()
6072 };
6073 if let Some(server_id) = server_id {
6074 if Self::resolve_completion_remote(
6075 project_id,
6076 server_id,
6077 buffer_id,
6078 completions.clone(),
6079 completion_index,
6080 client.clone(),
6081 )
6082 .await
6083 .log_err()
6084 .is_some()
6085 {
6086 did_resolve = true;
6087 }
6088 } else {
6089 resolve_word_completion(
6090 &buffer_snapshot,
6091 &mut completions.borrow_mut()[completion_index],
6092 );
6093 }
6094 }
6095 } else {
6096 for completion_index in completion_indices {
6097 let server_id = {
6098 let completion = &completions.borrow()[completion_index];
6099 completion.source.server_id()
6100 };
6101 if let Some(server_id) = server_id {
6102 let server_and_adapter = lsp_store
6103 .read_with(cx, |lsp_store, _| {
6104 let server = lsp_store.language_server_for_id(server_id)?;
6105 let adapter =
6106 lsp_store.language_server_adapter_for_id(server.server_id())?;
6107 Some((server, adapter))
6108 })
6109 .ok()
6110 .flatten();
6111 let Some((server, adapter)) = server_and_adapter else {
6112 continue;
6113 };
6114
6115 let resolved = Self::resolve_completion_local(
6116 server,
6117 completions.clone(),
6118 completion_index,
6119 )
6120 .await
6121 .log_err()
6122 .is_some();
6123 if resolved {
6124 Self::regenerate_completion_labels(
6125 adapter,
6126 &buffer_snapshot,
6127 completions.clone(),
6128 completion_index,
6129 )
6130 .await
6131 .log_err();
6132 did_resolve = true;
6133 }
6134 } else {
6135 resolve_word_completion(
6136 &buffer_snapshot,
6137 &mut completions.borrow_mut()[completion_index],
6138 );
6139 }
6140 }
6141 }
6142
6143 Ok(did_resolve)
6144 })
6145 }
6146
6147 async fn resolve_completion_local(
6148 server: Arc<lsp::LanguageServer>,
6149 completions: Rc<RefCell<Box<[Completion]>>>,
6150 completion_index: usize,
6151 ) -> Result<()> {
6152 let server_id = server.server_id();
6153 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6154 return Ok(());
6155 }
6156
6157 let request = {
6158 let completion = &completions.borrow()[completion_index];
6159 match &completion.source {
6160 CompletionSource::Lsp {
6161 lsp_completion,
6162 resolved,
6163 server_id: completion_server_id,
6164 ..
6165 } => {
6166 if *resolved {
6167 return Ok(());
6168 }
6169 anyhow::ensure!(
6170 server_id == *completion_server_id,
6171 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6172 );
6173 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6174 }
6175 CompletionSource::BufferWord { .. }
6176 | CompletionSource::Dap { .. }
6177 | CompletionSource::Custom => {
6178 return Ok(());
6179 }
6180 }
6181 };
6182 let resolved_completion = request
6183 .await
6184 .into_response()
6185 .context("resolve completion")?;
6186
6187 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6188 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6189
6190 let mut completions = completions.borrow_mut();
6191 let completion = &mut completions[completion_index];
6192 if let CompletionSource::Lsp {
6193 lsp_completion,
6194 resolved,
6195 server_id: completion_server_id,
6196 ..
6197 } = &mut completion.source
6198 {
6199 if *resolved {
6200 return Ok(());
6201 }
6202 anyhow::ensure!(
6203 server_id == *completion_server_id,
6204 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6205 );
6206 *lsp_completion = Box::new(resolved_completion);
6207 *resolved = true;
6208 }
6209 Ok(())
6210 }
6211
6212 async fn regenerate_completion_labels(
6213 adapter: Arc<CachedLspAdapter>,
6214 snapshot: &BufferSnapshot,
6215 completions: Rc<RefCell<Box<[Completion]>>>,
6216 completion_index: usize,
6217 ) -> Result<()> {
6218 let completion_item = completions.borrow()[completion_index]
6219 .source
6220 .lsp_completion(true)
6221 .map(Cow::into_owned);
6222 if let Some(lsp_documentation) = completion_item
6223 .as_ref()
6224 .and_then(|completion_item| completion_item.documentation.clone())
6225 {
6226 let mut completions = completions.borrow_mut();
6227 let completion = &mut completions[completion_index];
6228 completion.documentation = Some(lsp_documentation.into());
6229 } else {
6230 let mut completions = completions.borrow_mut();
6231 let completion = &mut completions[completion_index];
6232 completion.documentation = Some(CompletionDocumentation::Undocumented);
6233 }
6234
6235 let mut new_label = match completion_item {
6236 Some(completion_item) => {
6237 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6238 // So we have to update the label here anyway...
6239 let language = snapshot.language();
6240 match language {
6241 Some(language) => {
6242 adapter
6243 .labels_for_completions(
6244 std::slice::from_ref(&completion_item),
6245 language,
6246 )
6247 .await?
6248 }
6249 None => Vec::new(),
6250 }
6251 .pop()
6252 .flatten()
6253 .unwrap_or_else(|| {
6254 CodeLabel::fallback_for_completion(
6255 &completion_item,
6256 language.map(|language| language.as_ref()),
6257 )
6258 })
6259 }
6260 None => CodeLabel::plain(
6261 completions.borrow()[completion_index].new_text.clone(),
6262 None,
6263 ),
6264 };
6265 ensure_uniform_list_compatible_label(&mut new_label);
6266
6267 let mut completions = completions.borrow_mut();
6268 let completion = &mut completions[completion_index];
6269 if completion.label.filter_text() == new_label.filter_text() {
6270 completion.label = new_label;
6271 } else {
6272 log::error!(
6273 "Resolved completion changed display label from {} to {}. \
6274 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6275 completion.label.text(),
6276 new_label.text(),
6277 completion.label.filter_text(),
6278 new_label.filter_text()
6279 );
6280 }
6281
6282 Ok(())
6283 }
6284
6285 async fn resolve_completion_remote(
6286 project_id: u64,
6287 server_id: LanguageServerId,
6288 buffer_id: BufferId,
6289 completions: Rc<RefCell<Box<[Completion]>>>,
6290 completion_index: usize,
6291 client: AnyProtoClient,
6292 ) -> Result<()> {
6293 let lsp_completion = {
6294 let completion = &completions.borrow()[completion_index];
6295 match &completion.source {
6296 CompletionSource::Lsp {
6297 lsp_completion,
6298 resolved,
6299 server_id: completion_server_id,
6300 ..
6301 } => {
6302 anyhow::ensure!(
6303 server_id == *completion_server_id,
6304 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6305 );
6306 if *resolved {
6307 return Ok(());
6308 }
6309 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6310 }
6311 CompletionSource::Custom
6312 | CompletionSource::Dap { .. }
6313 | CompletionSource::BufferWord { .. } => {
6314 return Ok(());
6315 }
6316 }
6317 };
6318 let request = proto::ResolveCompletionDocumentation {
6319 project_id,
6320 language_server_id: server_id.0 as u64,
6321 lsp_completion,
6322 buffer_id: buffer_id.into(),
6323 };
6324
6325 let response = client
6326 .request(request)
6327 .await
6328 .context("completion documentation resolve proto request")?;
6329 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6330
6331 let documentation = if response.documentation.is_empty() {
6332 CompletionDocumentation::Undocumented
6333 } else if response.documentation_is_markdown {
6334 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6335 } else if response.documentation.lines().count() <= 1 {
6336 CompletionDocumentation::SingleLine(response.documentation.into())
6337 } else {
6338 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6339 };
6340
6341 let mut completions = completions.borrow_mut();
6342 let completion = &mut completions[completion_index];
6343 completion.documentation = Some(documentation);
6344 if let CompletionSource::Lsp {
6345 insert_range,
6346 lsp_completion,
6347 resolved,
6348 server_id: completion_server_id,
6349 lsp_defaults: _,
6350 } = &mut completion.source
6351 {
6352 let completion_insert_range = response
6353 .old_insert_start
6354 .and_then(deserialize_anchor)
6355 .zip(response.old_insert_end.and_then(deserialize_anchor));
6356 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6357
6358 if *resolved {
6359 return Ok(());
6360 }
6361 anyhow::ensure!(
6362 server_id == *completion_server_id,
6363 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6364 );
6365 *lsp_completion = Box::new(resolved_lsp_completion);
6366 *resolved = true;
6367 }
6368
6369 let replace_range = response
6370 .old_replace_start
6371 .and_then(deserialize_anchor)
6372 .zip(response.old_replace_end.and_then(deserialize_anchor));
6373 if let Some((old_replace_start, old_replace_end)) = replace_range
6374 && !response.new_text.is_empty()
6375 {
6376 completion.new_text = response.new_text;
6377 completion.replace_range = old_replace_start..old_replace_end;
6378 }
6379
6380 Ok(())
6381 }
6382
6383 pub fn apply_additional_edits_for_completion(
6384 &self,
6385 buffer_handle: Entity<Buffer>,
6386 completions: Rc<RefCell<Box<[Completion]>>>,
6387 completion_index: usize,
6388 push_to_history: bool,
6389 cx: &mut Context<Self>,
6390 ) -> Task<Result<Option<Transaction>>> {
6391 if let Some((client, project_id)) = self.upstream_client() {
6392 let buffer = buffer_handle.read(cx);
6393 let buffer_id = buffer.remote_id();
6394 cx.spawn(async move |_, cx| {
6395 let request = {
6396 let completion = completions.borrow()[completion_index].clone();
6397 proto::ApplyCompletionAdditionalEdits {
6398 project_id,
6399 buffer_id: buffer_id.into(),
6400 completion: Some(Self::serialize_completion(&CoreCompletion {
6401 replace_range: completion.replace_range,
6402 new_text: completion.new_text,
6403 source: completion.source,
6404 })),
6405 }
6406 };
6407
6408 if let Some(transaction) = client.request(request).await?.transaction {
6409 let transaction = language::proto::deserialize_transaction(transaction)?;
6410 buffer_handle
6411 .update(cx, |buffer, _| {
6412 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6413 })?
6414 .await?;
6415 if push_to_history {
6416 buffer_handle.update(cx, |buffer, _| {
6417 buffer.push_transaction(transaction.clone(), Instant::now());
6418 buffer.finalize_last_transaction();
6419 })?;
6420 }
6421 Ok(Some(transaction))
6422 } else {
6423 Ok(None)
6424 }
6425 })
6426 } else {
6427 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6428 let completion = &completions.borrow()[completion_index];
6429 let server_id = completion.source.server_id()?;
6430 Some(
6431 self.language_server_for_local_buffer(buffer, server_id, cx)?
6432 .1
6433 .clone(),
6434 )
6435 }) else {
6436 return Task::ready(Ok(None));
6437 };
6438
6439 cx.spawn(async move |this, cx| {
6440 Self::resolve_completion_local(
6441 server.clone(),
6442 completions.clone(),
6443 completion_index,
6444 )
6445 .await
6446 .context("resolving completion")?;
6447 let completion = completions.borrow()[completion_index].clone();
6448 let additional_text_edits = completion
6449 .source
6450 .lsp_completion(true)
6451 .as_ref()
6452 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6453 if let Some(edits) = additional_text_edits {
6454 let edits = this
6455 .update(cx, |this, cx| {
6456 this.as_local_mut().unwrap().edits_from_lsp(
6457 &buffer_handle,
6458 edits,
6459 server.server_id(),
6460 None,
6461 cx,
6462 )
6463 })?
6464 .await?;
6465
6466 buffer_handle.update(cx, |buffer, cx| {
6467 buffer.finalize_last_transaction();
6468 buffer.start_transaction();
6469
6470 for (range, text) in edits {
6471 let primary = &completion.replace_range;
6472
6473 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6474 // and the primary completion is just an insertion (empty range), then this is likely
6475 // an auto-import scenario and should not be considered overlapping
6476 // https://github.com/zed-industries/zed/issues/26136
6477 let is_file_start_auto_import = {
6478 let snapshot = buffer.snapshot();
6479 let primary_start_point = primary.start.to_point(&snapshot);
6480 let range_start_point = range.start.to_point(&snapshot);
6481
6482 let result = primary_start_point.row == 0
6483 && primary_start_point.column == 0
6484 && range_start_point.row == 0
6485 && range_start_point.column == 0;
6486
6487 result
6488 };
6489
6490 let has_overlap = if is_file_start_auto_import {
6491 false
6492 } else {
6493 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6494 && primary.end.cmp(&range.start, buffer).is_ge();
6495 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6496 && range.end.cmp(&primary.end, buffer).is_ge();
6497 let result = start_within || end_within;
6498 result
6499 };
6500
6501 //Skip additional edits which overlap with the primary completion edit
6502 //https://github.com/zed-industries/zed/pull/1871
6503 if !has_overlap {
6504 buffer.edit([(range, text)], None, cx);
6505 }
6506 }
6507
6508 let transaction = if buffer.end_transaction(cx).is_some() {
6509 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6510 if !push_to_history {
6511 buffer.forget_transaction(transaction.id);
6512 }
6513 Some(transaction)
6514 } else {
6515 None
6516 };
6517 Ok(transaction)
6518 })?
6519 } else {
6520 Ok(None)
6521 }
6522 })
6523 }
6524 }
6525
6526 pub fn pull_diagnostics(
6527 &mut self,
6528 buffer: Entity<Buffer>,
6529 cx: &mut Context<Self>,
6530 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6531 let buffer_id = buffer.read(cx).remote_id();
6532
6533 if let Some((client, upstream_project_id)) = self.upstream_client() {
6534 let mut suitable_capabilities = None;
6535 // Are we capable for proto request?
6536 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6537 &buffer,
6538 |capabilities| {
6539 if let Some(caps) = &capabilities.diagnostic_provider {
6540 suitable_capabilities = Some(caps.clone());
6541 true
6542 } else {
6543 false
6544 }
6545 },
6546 cx,
6547 );
6548 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6549 let Some(dynamic_caps) = suitable_capabilities else {
6550 return Task::ready(Ok(None));
6551 };
6552 assert!(any_server_has_diagnostics_provider);
6553
6554 let request = GetDocumentDiagnostics {
6555 previous_result_id: None,
6556 dynamic_caps,
6557 };
6558 let request_task = client.request_lsp(
6559 upstream_project_id,
6560 None,
6561 LSP_REQUEST_TIMEOUT,
6562 cx.background_executor().clone(),
6563 request.to_proto(upstream_project_id, buffer.read(cx)),
6564 );
6565 cx.background_spawn(async move {
6566 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6567 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6568 // Do not attempt to further process the dummy responses here.
6569 let _response = request_task.await?;
6570 Ok(None)
6571 })
6572 } else {
6573 let servers = buffer.update(cx, |buffer, cx| {
6574 self.language_servers_for_local_buffer(buffer, cx)
6575 .map(|(_, server)| server.clone())
6576 .collect::<Vec<_>>()
6577 });
6578
6579 let pull_diagnostics = servers
6580 .into_iter()
6581 .flat_map(|server| {
6582 let result = maybe!({
6583 let local = self.as_local()?;
6584 let server_id = server.server_id();
6585 let providers_with_identifiers = local
6586 .language_server_dynamic_registrations
6587 .get(&server_id)
6588 .into_iter()
6589 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6590 .collect::<Vec<_>>();
6591 Some(
6592 providers_with_identifiers
6593 .into_iter()
6594 .map(|dynamic_caps| {
6595 let result_id = self.result_id(server_id, buffer_id, cx);
6596 self.request_lsp(
6597 buffer.clone(),
6598 LanguageServerToQuery::Other(server_id),
6599 GetDocumentDiagnostics {
6600 previous_result_id: result_id,
6601 dynamic_caps,
6602 },
6603 cx,
6604 )
6605 })
6606 .collect::<Vec<_>>(),
6607 )
6608 });
6609
6610 result.unwrap_or_default()
6611 })
6612 .collect::<Vec<_>>();
6613
6614 cx.background_spawn(async move {
6615 let mut responses = Vec::new();
6616 for diagnostics in join_all(pull_diagnostics).await {
6617 responses.extend(diagnostics?);
6618 }
6619 Ok(Some(responses))
6620 })
6621 }
6622 }
6623
6624 pub fn applicable_inlay_chunks(
6625 &mut self,
6626 buffer: &Entity<Buffer>,
6627 ranges: &[Range<text::Anchor>],
6628 cx: &mut Context<Self>,
6629 ) -> Vec<Range<BufferRow>> {
6630 self.latest_lsp_data(buffer, cx)
6631 .inlay_hints
6632 .applicable_chunks(ranges)
6633 .map(|chunk| chunk.start..chunk.end)
6634 .collect()
6635 }
6636
6637 pub fn invalidate_inlay_hints<'a>(
6638 &'a mut self,
6639 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6640 ) {
6641 for buffer_id in for_buffers {
6642 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6643 lsp_data.inlay_hints.clear();
6644 }
6645 }
6646 }
6647
6648 pub fn inlay_hints(
6649 &mut self,
6650 invalidate: InvalidationStrategy,
6651 buffer: Entity<Buffer>,
6652 ranges: Vec<Range<text::Anchor>>,
6653 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6654 cx: &mut Context<Self>,
6655 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6656 let buffer_snapshot = buffer.read(cx).snapshot();
6657 let next_hint_id = self.next_hint_id.clone();
6658 let lsp_data = self.latest_lsp_data(&buffer, cx);
6659 let mut lsp_refresh_requested = false;
6660 let for_server = if let InvalidationStrategy::RefreshRequested {
6661 server_id,
6662 request_id,
6663 } = invalidate
6664 {
6665 let invalidated = lsp_data
6666 .inlay_hints
6667 .invalidate_for_server_refresh(server_id, request_id);
6668 lsp_refresh_requested = invalidated;
6669 Some(server_id)
6670 } else {
6671 None
6672 };
6673 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6674 let known_chunks = known_chunks
6675 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6676 .map(|(_, known_chunks)| known_chunks)
6677 .unwrap_or_default();
6678
6679 let mut hint_fetch_tasks = Vec::new();
6680 let mut cached_inlay_hints = None;
6681 let mut ranges_to_query = None;
6682 let applicable_chunks = existing_inlay_hints
6683 .applicable_chunks(ranges.as_slice())
6684 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6685 .collect::<Vec<_>>();
6686 if applicable_chunks.is_empty() {
6687 return HashMap::default();
6688 }
6689
6690 let last_chunk_number = existing_inlay_hints.buffer_chunks_len() - 1;
6691
6692 for row_chunk in applicable_chunks {
6693 match (
6694 existing_inlay_hints
6695 .cached_hints(&row_chunk)
6696 .filter(|_| !lsp_refresh_requested)
6697 .cloned(),
6698 existing_inlay_hints
6699 .fetched_hints(&row_chunk)
6700 .as_ref()
6701 .filter(|_| !lsp_refresh_requested)
6702 .cloned(),
6703 ) {
6704 (None, None) => {
6705 let end = if last_chunk_number == row_chunk.id {
6706 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6707 } else {
6708 Point::new(row_chunk.end, 0)
6709 };
6710 ranges_to_query.get_or_insert_with(Vec::new).push((
6711 row_chunk,
6712 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6713 ..buffer_snapshot.anchor_after(end),
6714 ));
6715 }
6716 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6717 (Some(cached_hints), None) => {
6718 for (server_id, cached_hints) in cached_hints {
6719 if for_server.is_none_or(|for_server| for_server == server_id) {
6720 cached_inlay_hints
6721 .get_or_insert_with(HashMap::default)
6722 .entry(row_chunk.start..row_chunk.end)
6723 .or_insert_with(HashMap::default)
6724 .entry(server_id)
6725 .or_insert_with(Vec::new)
6726 .extend(cached_hints);
6727 }
6728 }
6729 }
6730 (Some(cached_hints), Some(fetched_hints)) => {
6731 hint_fetch_tasks.push((row_chunk, fetched_hints));
6732 for (server_id, cached_hints) in cached_hints {
6733 if for_server.is_none_or(|for_server| for_server == server_id) {
6734 cached_inlay_hints
6735 .get_or_insert_with(HashMap::default)
6736 .entry(row_chunk.start..row_chunk.end)
6737 .or_insert_with(HashMap::default)
6738 .entry(server_id)
6739 .or_insert_with(Vec::new)
6740 .extend(cached_hints);
6741 }
6742 }
6743 }
6744 }
6745 }
6746
6747 if hint_fetch_tasks.is_empty()
6748 && ranges_to_query
6749 .as_ref()
6750 .is_none_or(|ranges| ranges.is_empty())
6751 && let Some(cached_inlay_hints) = cached_inlay_hints
6752 {
6753 cached_inlay_hints
6754 .into_iter()
6755 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6756 .collect()
6757 } else {
6758 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6759 let next_hint_id = next_hint_id.clone();
6760 let buffer = buffer.clone();
6761 let new_inlay_hints = cx
6762 .spawn(async move |lsp_store, cx| {
6763 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6764 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6765 })?;
6766 new_fetch_task
6767 .await
6768 .and_then(|new_hints_by_server| {
6769 lsp_store.update(cx, |lsp_store, cx| {
6770 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6771 let update_cache = !lsp_data
6772 .buffer_version
6773 .changed_since(&buffer.read(cx).version());
6774 if new_hints_by_server.is_empty() {
6775 if update_cache {
6776 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6777 }
6778 HashMap::default()
6779 } else {
6780 new_hints_by_server
6781 .into_iter()
6782 .map(|(server_id, new_hints)| {
6783 let new_hints = new_hints
6784 .into_iter()
6785 .map(|new_hint| {
6786 (
6787 InlayId::Hint(next_hint_id.fetch_add(
6788 1,
6789 atomic::Ordering::AcqRel,
6790 )),
6791 new_hint,
6792 )
6793 })
6794 .collect::<Vec<_>>();
6795 if update_cache {
6796 lsp_data.inlay_hints.insert_new_hints(
6797 chunk,
6798 server_id,
6799 new_hints.clone(),
6800 );
6801 }
6802 (server_id, new_hints)
6803 })
6804 .collect()
6805 }
6806 })
6807 })
6808 .map_err(Arc::new)
6809 })
6810 .shared();
6811
6812 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6813 *fetch_task = Some(new_inlay_hints.clone());
6814 hint_fetch_tasks.push((chunk, new_inlay_hints));
6815 }
6816
6817 cached_inlay_hints
6818 .unwrap_or_default()
6819 .into_iter()
6820 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6821 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6822 (
6823 chunk.start..chunk.end,
6824 cx.spawn(async move |_, _| {
6825 hints_fetch.await.map_err(|e| {
6826 if e.error_code() != ErrorCode::Internal {
6827 anyhow!(e.error_code())
6828 } else {
6829 anyhow!("{e:#}")
6830 }
6831 })
6832 }),
6833 )
6834 }))
6835 .collect()
6836 }
6837 }
6838
6839 fn fetch_inlay_hints(
6840 &mut self,
6841 for_server: Option<LanguageServerId>,
6842 buffer: &Entity<Buffer>,
6843 range: Range<Anchor>,
6844 cx: &mut Context<Self>,
6845 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6846 let request = InlayHints {
6847 range: range.clone(),
6848 };
6849 if let Some((upstream_client, project_id)) = self.upstream_client() {
6850 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6851 return Task::ready(Ok(HashMap::default()));
6852 }
6853 let request_task = upstream_client.request_lsp(
6854 project_id,
6855 for_server.map(|id| id.to_proto()),
6856 LSP_REQUEST_TIMEOUT,
6857 cx.background_executor().clone(),
6858 request.to_proto(project_id, buffer.read(cx)),
6859 );
6860 let buffer = buffer.clone();
6861 cx.spawn(async move |weak_lsp_store, cx| {
6862 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6863 return Ok(HashMap::default());
6864 };
6865 let Some(responses) = request_task.await? else {
6866 return Ok(HashMap::default());
6867 };
6868
6869 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6870 let lsp_store = lsp_store.clone();
6871 let buffer = buffer.clone();
6872 let cx = cx.clone();
6873 let request = request.clone();
6874 async move {
6875 (
6876 LanguageServerId::from_proto(response.server_id),
6877 request
6878 .response_from_proto(response.response, lsp_store, buffer, cx)
6879 .await,
6880 )
6881 }
6882 }))
6883 .await;
6884
6885 let mut has_errors = false;
6886 let inlay_hints = inlay_hints
6887 .into_iter()
6888 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6889 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6890 Err(e) => {
6891 has_errors = true;
6892 log::error!("{e:#}");
6893 None
6894 }
6895 })
6896 .collect::<HashMap<_, _>>();
6897 anyhow::ensure!(
6898 !has_errors || !inlay_hints.is_empty(),
6899 "Failed to fetch inlay hints"
6900 );
6901 Ok(inlay_hints)
6902 })
6903 } else {
6904 let inlay_hints_task = match for_server {
6905 Some(server_id) => {
6906 let server_task = self.request_lsp(
6907 buffer.clone(),
6908 LanguageServerToQuery::Other(server_id),
6909 request,
6910 cx,
6911 );
6912 cx.background_spawn(async move {
6913 let mut responses = Vec::new();
6914 match server_task.await {
6915 Ok(response) => responses.push((server_id, response)),
6916 // rust-analyzer likes to error with this when its still loading up
6917 Err(e) if format!("{e:#}").ends_with("content modified") => (),
6918 Err(e) => log::error!(
6919 "Error handling response for inlay hints request: {e:#}"
6920 ),
6921 }
6922 responses
6923 })
6924 }
6925 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6926 };
6927 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6928 cx.background_spawn(async move {
6929 Ok(inlay_hints_task
6930 .await
6931 .into_iter()
6932 .map(|(server_id, mut new_hints)| {
6933 new_hints.retain(|hint| {
6934 hint.position.is_valid(&buffer_snapshot)
6935 && range.start.is_valid(&buffer_snapshot)
6936 && range.end.is_valid(&buffer_snapshot)
6937 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6938 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6939 });
6940 (server_id, new_hints)
6941 })
6942 .collect())
6943 })
6944 }
6945 }
6946
6947 pub fn pull_diagnostics_for_buffer(
6948 &mut self,
6949 buffer: Entity<Buffer>,
6950 cx: &mut Context<Self>,
6951 ) -> Task<anyhow::Result<()>> {
6952 let diagnostics = self.pull_diagnostics(buffer, cx);
6953 cx.spawn(async move |lsp_store, cx| {
6954 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6955 return Ok(());
6956 };
6957 lsp_store.update(cx, |lsp_store, cx| {
6958 if lsp_store.as_local().is_none() {
6959 return;
6960 }
6961
6962 let mut unchanged_buffers = HashSet::default();
6963 let mut changed_buffers = HashSet::default();
6964 let server_diagnostics_updates = diagnostics
6965 .into_iter()
6966 .filter_map(|diagnostics_set| match diagnostics_set {
6967 LspPullDiagnostics::Response {
6968 server_id,
6969 uri,
6970 diagnostics,
6971 } => Some((server_id, uri, diagnostics)),
6972 LspPullDiagnostics::Default => None,
6973 })
6974 .fold(
6975 HashMap::default(),
6976 |mut acc, (server_id, uri, diagnostics)| {
6977 let (result_id, diagnostics) = match diagnostics {
6978 PulledDiagnostics::Unchanged { result_id } => {
6979 unchanged_buffers.insert(uri.clone());
6980 (Some(result_id), Vec::new())
6981 }
6982 PulledDiagnostics::Changed {
6983 result_id,
6984 diagnostics,
6985 } => {
6986 changed_buffers.insert(uri.clone());
6987 (result_id, diagnostics)
6988 }
6989 };
6990 let disk_based_sources = Cow::Owned(
6991 lsp_store
6992 .language_server_adapter_for_id(server_id)
6993 .as_ref()
6994 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6995 .unwrap_or(&[])
6996 .to_vec(),
6997 );
6998 acc.entry(server_id).or_insert_with(Vec::new).push(
6999 DocumentDiagnosticsUpdate {
7000 server_id,
7001 diagnostics: lsp::PublishDiagnosticsParams {
7002 uri,
7003 diagnostics,
7004 version: None,
7005 },
7006 result_id,
7007 disk_based_sources,
7008 },
7009 );
7010 acc
7011 },
7012 );
7013
7014 for diagnostic_updates in server_diagnostics_updates.into_values() {
7015 lsp_store
7016 .merge_lsp_diagnostics(
7017 DiagnosticSourceKind::Pulled,
7018 diagnostic_updates,
7019 |buffer, old_diagnostic, cx| {
7020 File::from_dyn(buffer.file())
7021 .and_then(|file| {
7022 let abs_path = file.as_local()?.abs_path(cx);
7023 lsp::Uri::from_file_path(abs_path).ok()
7024 })
7025 .is_none_or(|buffer_uri| {
7026 unchanged_buffers.contains(&buffer_uri)
7027 || match old_diagnostic.source_kind {
7028 DiagnosticSourceKind::Pulled => {
7029 !changed_buffers.contains(&buffer_uri)
7030 }
7031 DiagnosticSourceKind::Other
7032 | DiagnosticSourceKind::Pushed => true,
7033 }
7034 })
7035 },
7036 cx,
7037 )
7038 .log_err();
7039 }
7040 })
7041 })
7042 }
7043
7044 pub fn document_colors(
7045 &mut self,
7046 known_cache_version: Option<usize>,
7047 buffer: Entity<Buffer>,
7048 cx: &mut Context<Self>,
7049 ) -> Option<DocumentColorTask> {
7050 let version_queried_for = buffer.read(cx).version();
7051 let buffer_id = buffer.read(cx).remote_id();
7052
7053 let current_language_servers = self.as_local().map(|local| {
7054 local
7055 .buffers_opened_in_servers
7056 .get(&buffer_id)
7057 .cloned()
7058 .unwrap_or_default()
7059 });
7060
7061 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7062 if let Some(cached_colors) = &lsp_data.document_colors {
7063 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7064 let has_different_servers =
7065 current_language_servers.is_some_and(|current_language_servers| {
7066 current_language_servers
7067 != cached_colors.colors.keys().copied().collect()
7068 });
7069 if !has_different_servers {
7070 let cache_version = cached_colors.cache_version;
7071 if Some(cache_version) == known_cache_version {
7072 return None;
7073 } else {
7074 return Some(
7075 Task::ready(Ok(DocumentColors {
7076 colors: cached_colors
7077 .colors
7078 .values()
7079 .flatten()
7080 .cloned()
7081 .collect(),
7082 cache_version: Some(cache_version),
7083 }))
7084 .shared(),
7085 );
7086 }
7087 }
7088 }
7089 }
7090 }
7091
7092 let color_lsp_data = self
7093 .latest_lsp_data(&buffer, cx)
7094 .document_colors
7095 .get_or_insert_default();
7096 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7097 && !version_queried_for.changed_since(updating_for)
7098 {
7099 return Some(running_update.clone());
7100 }
7101 let buffer_version_queried_for = version_queried_for.clone();
7102 let new_task = cx
7103 .spawn(async move |lsp_store, cx| {
7104 cx.background_executor()
7105 .timer(Duration::from_millis(30))
7106 .await;
7107 let fetched_colors = lsp_store
7108 .update(cx, |lsp_store, cx| {
7109 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7110 })?
7111 .await
7112 .context("fetching document colors")
7113 .map_err(Arc::new);
7114 let fetched_colors = match fetched_colors {
7115 Ok(fetched_colors) => {
7116 if Some(true)
7117 == buffer
7118 .update(cx, |buffer, _| {
7119 buffer.version() != buffer_version_queried_for
7120 })
7121 .ok()
7122 {
7123 return Ok(DocumentColors::default());
7124 }
7125 fetched_colors
7126 }
7127 Err(e) => {
7128 lsp_store
7129 .update(cx, |lsp_store, _| {
7130 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7131 if let Some(document_colors) = &mut lsp_data.document_colors {
7132 document_colors.colors_update = None;
7133 }
7134 }
7135 })
7136 .ok();
7137 return Err(e);
7138 }
7139 };
7140
7141 lsp_store
7142 .update(cx, |lsp_store, cx| {
7143 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7144 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7145
7146 if let Some(fetched_colors) = fetched_colors {
7147 if lsp_data.buffer_version == buffer_version_queried_for {
7148 lsp_colors.colors.extend(fetched_colors);
7149 lsp_colors.cache_version += 1;
7150 } else if !lsp_data
7151 .buffer_version
7152 .changed_since(&buffer_version_queried_for)
7153 {
7154 lsp_data.buffer_version = buffer_version_queried_for;
7155 lsp_colors.colors = fetched_colors;
7156 lsp_colors.cache_version += 1;
7157 }
7158 }
7159 lsp_colors.colors_update = None;
7160 let colors = lsp_colors
7161 .colors
7162 .values()
7163 .flatten()
7164 .cloned()
7165 .collect::<HashSet<_>>();
7166 DocumentColors {
7167 colors,
7168 cache_version: Some(lsp_colors.cache_version),
7169 }
7170 })
7171 .map_err(Arc::new)
7172 })
7173 .shared();
7174 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7175 Some(new_task)
7176 }
7177
7178 fn fetch_document_colors_for_buffer(
7179 &mut self,
7180 buffer: &Entity<Buffer>,
7181 cx: &mut Context<Self>,
7182 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7183 if let Some((client, project_id)) = self.upstream_client() {
7184 let request = GetDocumentColor {};
7185 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7186 return Task::ready(Ok(None));
7187 }
7188
7189 let request_task = client.request_lsp(
7190 project_id,
7191 None,
7192 LSP_REQUEST_TIMEOUT,
7193 cx.background_executor().clone(),
7194 request.to_proto(project_id, buffer.read(cx)),
7195 );
7196 let buffer = buffer.clone();
7197 cx.spawn(async move |lsp_store, cx| {
7198 let Some(lsp_store) = lsp_store.upgrade() else {
7199 return Ok(None);
7200 };
7201 let colors = join_all(
7202 request_task
7203 .await
7204 .log_err()
7205 .flatten()
7206 .map(|response| response.payload)
7207 .unwrap_or_default()
7208 .into_iter()
7209 .map(|color_response| {
7210 let response = request.response_from_proto(
7211 color_response.response,
7212 lsp_store.clone(),
7213 buffer.clone(),
7214 cx.clone(),
7215 );
7216 async move {
7217 (
7218 LanguageServerId::from_proto(color_response.server_id),
7219 response.await.log_err().unwrap_or_default(),
7220 )
7221 }
7222 }),
7223 )
7224 .await
7225 .into_iter()
7226 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7227 acc.entry(server_id)
7228 .or_insert_with(HashSet::default)
7229 .extend(colors);
7230 acc
7231 });
7232 Ok(Some(colors))
7233 })
7234 } else {
7235 let document_colors_task =
7236 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7237 cx.background_spawn(async move {
7238 Ok(Some(
7239 document_colors_task
7240 .await
7241 .into_iter()
7242 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7243 acc.entry(server_id)
7244 .or_insert_with(HashSet::default)
7245 .extend(colors);
7246 acc
7247 })
7248 .into_iter()
7249 .collect(),
7250 ))
7251 })
7252 }
7253 }
7254
7255 pub fn signature_help<T: ToPointUtf16>(
7256 &mut self,
7257 buffer: &Entity<Buffer>,
7258 position: T,
7259 cx: &mut Context<Self>,
7260 ) -> Task<Option<Vec<SignatureHelp>>> {
7261 let position = position.to_point_utf16(buffer.read(cx));
7262
7263 if let Some((client, upstream_project_id)) = self.upstream_client() {
7264 let request = GetSignatureHelp { position };
7265 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7266 return Task::ready(None);
7267 }
7268 let request_task = client.request_lsp(
7269 upstream_project_id,
7270 None,
7271 LSP_REQUEST_TIMEOUT,
7272 cx.background_executor().clone(),
7273 request.to_proto(upstream_project_id, buffer.read(cx)),
7274 );
7275 let buffer = buffer.clone();
7276 cx.spawn(async move |weak_lsp_store, cx| {
7277 let lsp_store = weak_lsp_store.upgrade()?;
7278 let signatures = join_all(
7279 request_task
7280 .await
7281 .log_err()
7282 .flatten()
7283 .map(|response| response.payload)
7284 .unwrap_or_default()
7285 .into_iter()
7286 .map(|response| {
7287 let response = GetSignatureHelp { position }.response_from_proto(
7288 response.response,
7289 lsp_store.clone(),
7290 buffer.clone(),
7291 cx.clone(),
7292 );
7293 async move { response.await.log_err().flatten() }
7294 }),
7295 )
7296 .await
7297 .into_iter()
7298 .flatten()
7299 .collect();
7300 Some(signatures)
7301 })
7302 } else {
7303 let all_actions_task = self.request_multiple_lsp_locally(
7304 buffer,
7305 Some(position),
7306 GetSignatureHelp { position },
7307 cx,
7308 );
7309 cx.background_spawn(async move {
7310 Some(
7311 all_actions_task
7312 .await
7313 .into_iter()
7314 .flat_map(|(_, actions)| actions)
7315 .collect::<Vec<_>>(),
7316 )
7317 })
7318 }
7319 }
7320
7321 pub fn hover(
7322 &mut self,
7323 buffer: &Entity<Buffer>,
7324 position: PointUtf16,
7325 cx: &mut Context<Self>,
7326 ) -> Task<Option<Vec<Hover>>> {
7327 if let Some((client, upstream_project_id)) = self.upstream_client() {
7328 let request = GetHover { position };
7329 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7330 return Task::ready(None);
7331 }
7332 let request_task = client.request_lsp(
7333 upstream_project_id,
7334 None,
7335 LSP_REQUEST_TIMEOUT,
7336 cx.background_executor().clone(),
7337 request.to_proto(upstream_project_id, buffer.read(cx)),
7338 );
7339 let buffer = buffer.clone();
7340 cx.spawn(async move |weak_lsp_store, cx| {
7341 let lsp_store = weak_lsp_store.upgrade()?;
7342 let hovers = join_all(
7343 request_task
7344 .await
7345 .log_err()
7346 .flatten()
7347 .map(|response| response.payload)
7348 .unwrap_or_default()
7349 .into_iter()
7350 .map(|response| {
7351 let response = GetHover { position }.response_from_proto(
7352 response.response,
7353 lsp_store.clone(),
7354 buffer.clone(),
7355 cx.clone(),
7356 );
7357 async move {
7358 response
7359 .await
7360 .log_err()
7361 .flatten()
7362 .and_then(remove_empty_hover_blocks)
7363 }
7364 }),
7365 )
7366 .await
7367 .into_iter()
7368 .flatten()
7369 .collect();
7370 Some(hovers)
7371 })
7372 } else {
7373 let all_actions_task = self.request_multiple_lsp_locally(
7374 buffer,
7375 Some(position),
7376 GetHover { position },
7377 cx,
7378 );
7379 cx.background_spawn(async move {
7380 Some(
7381 all_actions_task
7382 .await
7383 .into_iter()
7384 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7385 .collect::<Vec<Hover>>(),
7386 )
7387 })
7388 }
7389 }
7390
7391 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7392 let language_registry = self.languages.clone();
7393
7394 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7395 let request = upstream_client.request(proto::GetProjectSymbols {
7396 project_id: *project_id,
7397 query: query.to_string(),
7398 });
7399 cx.foreground_executor().spawn(async move {
7400 let response = request.await?;
7401 let mut symbols = Vec::new();
7402 let core_symbols = response
7403 .symbols
7404 .into_iter()
7405 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7406 .collect::<Vec<_>>();
7407 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7408 .await;
7409 Ok(symbols)
7410 })
7411 } else if let Some(local) = self.as_local() {
7412 struct WorkspaceSymbolsResult {
7413 server_id: LanguageServerId,
7414 lsp_adapter: Arc<CachedLspAdapter>,
7415 worktree: WeakEntity<Worktree>,
7416 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7417 }
7418
7419 let mut requests = Vec::new();
7420 let mut requested_servers = BTreeSet::new();
7421 for (seed, state) in local.language_server_ids.iter() {
7422 let Some(worktree_handle) = self
7423 .worktree_store
7424 .read(cx)
7425 .worktree_for_id(seed.worktree_id, cx)
7426 else {
7427 continue;
7428 };
7429 let worktree = worktree_handle.read(cx);
7430 if !worktree.is_visible() {
7431 continue;
7432 }
7433
7434 if !requested_servers.insert(state.id) {
7435 continue;
7436 }
7437
7438 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7439 Some(LanguageServerState::Running {
7440 adapter, server, ..
7441 }) => (adapter.clone(), server),
7442
7443 _ => continue,
7444 };
7445 let supports_workspace_symbol_request =
7446 match server.capabilities().workspace_symbol_provider {
7447 Some(OneOf::Left(supported)) => supported,
7448 Some(OneOf::Right(_)) => true,
7449 None => false,
7450 };
7451 if !supports_workspace_symbol_request {
7452 continue;
7453 }
7454 let worktree_handle = worktree_handle.clone();
7455 let server_id = server.server_id();
7456 requests.push(
7457 server
7458 .request::<lsp::request::WorkspaceSymbolRequest>(
7459 lsp::WorkspaceSymbolParams {
7460 query: query.to_string(),
7461 ..Default::default()
7462 },
7463 )
7464 .map(move |response| {
7465 let lsp_symbols = response.into_response()
7466 .context("workspace symbols request")
7467 .log_err()
7468 .flatten()
7469 .map(|symbol_response| match symbol_response {
7470 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7471 flat_responses.into_iter().map(|lsp_symbol| {
7472 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7473 }).collect::<Vec<_>>()
7474 }
7475 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7476 nested_responses.into_iter().filter_map(|lsp_symbol| {
7477 let location = match lsp_symbol.location {
7478 OneOf::Left(location) => location,
7479 OneOf::Right(_) => {
7480 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7481 return None
7482 }
7483 };
7484 Some((lsp_symbol.name, lsp_symbol.kind, location))
7485 }).collect::<Vec<_>>()
7486 }
7487 }).unwrap_or_default();
7488
7489 WorkspaceSymbolsResult {
7490 server_id,
7491 lsp_adapter,
7492 worktree: worktree_handle.downgrade(),
7493 lsp_symbols,
7494 }
7495 }),
7496 );
7497 }
7498
7499 cx.spawn(async move |this, cx| {
7500 let responses = futures::future::join_all(requests).await;
7501 let this = match this.upgrade() {
7502 Some(this) => this,
7503 None => return Ok(Vec::new()),
7504 };
7505
7506 let mut symbols = Vec::new();
7507 for result in responses {
7508 let core_symbols = this.update(cx, |this, cx| {
7509 result
7510 .lsp_symbols
7511 .into_iter()
7512 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7513 let abs_path = symbol_location.uri.to_file_path().ok()?;
7514 let source_worktree = result.worktree.upgrade()?;
7515 let source_worktree_id = source_worktree.read(cx).id();
7516
7517 let path = if let Some((tree, rel_path)) =
7518 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7519 {
7520 let worktree_id = tree.read(cx).id();
7521 SymbolLocation::InProject(ProjectPath {
7522 worktree_id,
7523 path: rel_path,
7524 })
7525 } else {
7526 SymbolLocation::OutsideProject {
7527 signature: this.symbol_signature(&abs_path),
7528 abs_path: abs_path.into(),
7529 }
7530 };
7531
7532 Some(CoreSymbol {
7533 source_language_server_id: result.server_id,
7534 language_server_name: result.lsp_adapter.name.clone(),
7535 source_worktree_id,
7536 path,
7537 kind: symbol_kind,
7538 name: symbol_name,
7539 range: range_from_lsp(symbol_location.range),
7540 })
7541 })
7542 .collect()
7543 })?;
7544
7545 populate_labels_for_symbols(
7546 core_symbols,
7547 &language_registry,
7548 Some(result.lsp_adapter),
7549 &mut symbols,
7550 )
7551 .await;
7552 }
7553
7554 Ok(symbols)
7555 })
7556 } else {
7557 Task::ready(Err(anyhow!("No upstream client or local language server")))
7558 }
7559 }
7560
7561 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7562 let mut summary = DiagnosticSummary::default();
7563 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7564 summary.error_count += path_summary.error_count;
7565 summary.warning_count += path_summary.warning_count;
7566 }
7567 summary
7568 }
7569
7570 /// Returns the diagnostic summary for a specific project path.
7571 pub fn diagnostic_summary_for_path(
7572 &self,
7573 project_path: &ProjectPath,
7574 _: &App,
7575 ) -> DiagnosticSummary {
7576 if let Some(summaries) = self
7577 .diagnostic_summaries
7578 .get(&project_path.worktree_id)
7579 .and_then(|map| map.get(&project_path.path))
7580 {
7581 let (error_count, warning_count) = summaries.iter().fold(
7582 (0, 0),
7583 |(error_count, warning_count), (_language_server_id, summary)| {
7584 (
7585 error_count + summary.error_count,
7586 warning_count + summary.warning_count,
7587 )
7588 },
7589 );
7590
7591 DiagnosticSummary {
7592 error_count,
7593 warning_count,
7594 }
7595 } else {
7596 DiagnosticSummary::default()
7597 }
7598 }
7599
7600 pub fn diagnostic_summaries<'a>(
7601 &'a self,
7602 include_ignored: bool,
7603 cx: &'a App,
7604 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7605 self.worktree_store
7606 .read(cx)
7607 .visible_worktrees(cx)
7608 .filter_map(|worktree| {
7609 let worktree = worktree.read(cx);
7610 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7611 })
7612 .flat_map(move |(worktree, summaries)| {
7613 let worktree_id = worktree.id();
7614 summaries
7615 .iter()
7616 .filter(move |(path, _)| {
7617 include_ignored
7618 || worktree
7619 .entry_for_path(path.as_ref())
7620 .is_some_and(|entry| !entry.is_ignored)
7621 })
7622 .flat_map(move |(path, summaries)| {
7623 summaries.iter().map(move |(server_id, summary)| {
7624 (
7625 ProjectPath {
7626 worktree_id,
7627 path: path.clone(),
7628 },
7629 *server_id,
7630 *summary,
7631 )
7632 })
7633 })
7634 })
7635 }
7636
7637 pub fn on_buffer_edited(
7638 &mut self,
7639 buffer: Entity<Buffer>,
7640 cx: &mut Context<Self>,
7641 ) -> Option<()> {
7642 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7643 Some(
7644 self.as_local()?
7645 .language_servers_for_buffer(buffer, cx)
7646 .map(|i| i.1.clone())
7647 .collect(),
7648 )
7649 })?;
7650
7651 let buffer = buffer.read(cx);
7652 let file = File::from_dyn(buffer.file())?;
7653 let abs_path = file.as_local()?.abs_path(cx);
7654 let uri = lsp::Uri::from_file_path(&abs_path)
7655 .ok()
7656 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7657 .log_err()?;
7658 let next_snapshot = buffer.text_snapshot();
7659 for language_server in language_servers {
7660 let language_server = language_server.clone();
7661
7662 let buffer_snapshots = self
7663 .as_local_mut()?
7664 .buffer_snapshots
7665 .get_mut(&buffer.remote_id())
7666 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7667 let previous_snapshot = buffer_snapshots.last()?;
7668
7669 let build_incremental_change = || {
7670 buffer
7671 .edits_since::<Dimensions<PointUtf16, usize>>(
7672 previous_snapshot.snapshot.version(),
7673 )
7674 .map(|edit| {
7675 let edit_start = edit.new.start.0;
7676 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7677 let new_text = next_snapshot
7678 .text_for_range(edit.new.start.1..edit.new.end.1)
7679 .collect();
7680 lsp::TextDocumentContentChangeEvent {
7681 range: Some(lsp::Range::new(
7682 point_to_lsp(edit_start),
7683 point_to_lsp(edit_end),
7684 )),
7685 range_length: None,
7686 text: new_text,
7687 }
7688 })
7689 .collect()
7690 };
7691
7692 let document_sync_kind = language_server
7693 .capabilities()
7694 .text_document_sync
7695 .as_ref()
7696 .and_then(|sync| match sync {
7697 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7698 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7699 });
7700
7701 let content_changes: Vec<_> = match document_sync_kind {
7702 Some(lsp::TextDocumentSyncKind::FULL) => {
7703 vec![lsp::TextDocumentContentChangeEvent {
7704 range: None,
7705 range_length: None,
7706 text: next_snapshot.text(),
7707 }]
7708 }
7709 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7710 _ => {
7711 #[cfg(any(test, feature = "test-support"))]
7712 {
7713 build_incremental_change()
7714 }
7715
7716 #[cfg(not(any(test, feature = "test-support")))]
7717 {
7718 continue;
7719 }
7720 }
7721 };
7722
7723 let next_version = previous_snapshot.version + 1;
7724 buffer_snapshots.push(LspBufferSnapshot {
7725 version: next_version,
7726 snapshot: next_snapshot.clone(),
7727 });
7728
7729 language_server
7730 .notify::<lsp::notification::DidChangeTextDocument>(
7731 lsp::DidChangeTextDocumentParams {
7732 text_document: lsp::VersionedTextDocumentIdentifier::new(
7733 uri.clone(),
7734 next_version,
7735 ),
7736 content_changes,
7737 },
7738 )
7739 .ok();
7740 self.pull_workspace_diagnostics(language_server.server_id());
7741 }
7742
7743 None
7744 }
7745
7746 pub fn on_buffer_saved(
7747 &mut self,
7748 buffer: Entity<Buffer>,
7749 cx: &mut Context<Self>,
7750 ) -> Option<()> {
7751 let file = File::from_dyn(buffer.read(cx).file())?;
7752 let worktree_id = file.worktree_id(cx);
7753 let abs_path = file.as_local()?.abs_path(cx);
7754 let text_document = lsp::TextDocumentIdentifier {
7755 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7756 };
7757 let local = self.as_local()?;
7758
7759 for server in local.language_servers_for_worktree(worktree_id) {
7760 if let Some(include_text) = include_text(server.as_ref()) {
7761 let text = if include_text {
7762 Some(buffer.read(cx).text())
7763 } else {
7764 None
7765 };
7766 server
7767 .notify::<lsp::notification::DidSaveTextDocument>(
7768 lsp::DidSaveTextDocumentParams {
7769 text_document: text_document.clone(),
7770 text,
7771 },
7772 )
7773 .ok();
7774 }
7775 }
7776
7777 let language_servers = buffer.update(cx, |buffer, cx| {
7778 local.language_server_ids_for_buffer(buffer, cx)
7779 });
7780 for language_server_id in language_servers {
7781 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7782 }
7783
7784 None
7785 }
7786
7787 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7788 maybe!(async move {
7789 let mut refreshed_servers = HashSet::default();
7790 let servers = lsp_store
7791 .update(cx, |lsp_store, cx| {
7792 let local = lsp_store.as_local()?;
7793
7794 let servers = local
7795 .language_server_ids
7796 .iter()
7797 .filter_map(|(seed, state)| {
7798 let worktree = lsp_store
7799 .worktree_store
7800 .read(cx)
7801 .worktree_for_id(seed.worktree_id, cx);
7802 let delegate: Arc<dyn LspAdapterDelegate> =
7803 worktree.map(|worktree| {
7804 LocalLspAdapterDelegate::new(
7805 local.languages.clone(),
7806 &local.environment,
7807 cx.weak_entity(),
7808 &worktree,
7809 local.http_client.clone(),
7810 local.fs.clone(),
7811 cx,
7812 )
7813 })?;
7814 let server_id = state.id;
7815
7816 let states = local.language_servers.get(&server_id)?;
7817
7818 match states {
7819 LanguageServerState::Starting { .. } => None,
7820 LanguageServerState::Running {
7821 adapter, server, ..
7822 } => {
7823 let adapter = adapter.clone();
7824 let server = server.clone();
7825 refreshed_servers.insert(server.name());
7826 let toolchain = seed.toolchain.clone();
7827 Some(cx.spawn(async move |_, cx| {
7828 let settings =
7829 LocalLspStore::workspace_configuration_for_adapter(
7830 adapter.adapter.clone(),
7831 &delegate,
7832 toolchain,
7833 cx,
7834 )
7835 .await
7836 .ok()?;
7837 server
7838 .notify::<lsp::notification::DidChangeConfiguration>(
7839 lsp::DidChangeConfigurationParams { settings },
7840 )
7841 .ok()?;
7842 Some(())
7843 }))
7844 }
7845 }
7846 })
7847 .collect::<Vec<_>>();
7848
7849 Some(servers)
7850 })
7851 .ok()
7852 .flatten()?;
7853
7854 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7855 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7856 // to stop and unregister its language server wrapper.
7857 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7858 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7859 let _: Vec<Option<()>> = join_all(servers).await;
7860
7861 Some(())
7862 })
7863 .await;
7864 }
7865
7866 fn maintain_workspace_config(
7867 external_refresh_requests: watch::Receiver<()>,
7868 cx: &mut Context<Self>,
7869 ) -> Task<Result<()>> {
7870 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7871 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7872
7873 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7874 *settings_changed_tx.borrow_mut() = ();
7875 });
7876
7877 let mut joint_future =
7878 futures::stream::select(settings_changed_rx, external_refresh_requests);
7879 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7880 // - We might shut down a language server if it's no longer enabled for a given language (and there are no buffers using it otherwise).
7881 // - We might also shut it down when the workspace configuration of all of the users of a given language server converges onto that of the other.
7882 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7883 // - In the easiest case (where we're not wrangling the lifetime of a language server anyhow), if none of the roots of a single language server diverge in their configuration,
7884 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7885 cx.spawn(async move |this, cx| {
7886 while let Some(()) = joint_future.next().await {
7887 this.update(cx, |this, cx| {
7888 this.refresh_server_tree(cx);
7889 })
7890 .ok();
7891
7892 Self::refresh_workspace_configurations(&this, cx).await;
7893 }
7894
7895 drop(settings_observation);
7896 anyhow::Ok(())
7897 })
7898 }
7899
7900 pub fn language_servers_for_local_buffer<'a>(
7901 &'a self,
7902 buffer: &Buffer,
7903 cx: &mut App,
7904 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7905 let local = self.as_local();
7906 let language_server_ids = local
7907 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7908 .unwrap_or_default();
7909
7910 language_server_ids
7911 .into_iter()
7912 .filter_map(
7913 move |server_id| match local?.language_servers.get(&server_id)? {
7914 LanguageServerState::Running {
7915 adapter, server, ..
7916 } => Some((adapter, server)),
7917 _ => None,
7918 },
7919 )
7920 }
7921
7922 pub fn language_server_for_local_buffer<'a>(
7923 &'a self,
7924 buffer: &'a Buffer,
7925 server_id: LanguageServerId,
7926 cx: &'a mut App,
7927 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7928 self.as_local()?
7929 .language_servers_for_buffer(buffer, cx)
7930 .find(|(_, s)| s.server_id() == server_id)
7931 }
7932
7933 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7934 self.diagnostic_summaries.remove(&id_to_remove);
7935 if let Some(local) = self.as_local_mut() {
7936 let to_remove = local.remove_worktree(id_to_remove, cx);
7937 for server in to_remove {
7938 self.language_server_statuses.remove(&server);
7939 }
7940 }
7941 }
7942
7943 pub fn shared(
7944 &mut self,
7945 project_id: u64,
7946 downstream_client: AnyProtoClient,
7947 _: &mut Context<Self>,
7948 ) {
7949 self.downstream_client = Some((downstream_client.clone(), project_id));
7950
7951 for (server_id, status) in &self.language_server_statuses {
7952 if let Some(server) = self.language_server_for_id(*server_id) {
7953 downstream_client
7954 .send(proto::StartLanguageServer {
7955 project_id,
7956 server: Some(proto::LanguageServer {
7957 id: server_id.to_proto(),
7958 name: status.name.to_string(),
7959 worktree_id: status.worktree.map(|id| id.to_proto()),
7960 }),
7961 capabilities: serde_json::to_string(&server.capabilities())
7962 .expect("serializing server LSP capabilities"),
7963 })
7964 .log_err();
7965 }
7966 }
7967 }
7968
7969 pub fn disconnected_from_host(&mut self) {
7970 self.downstream_client.take();
7971 }
7972
7973 pub fn disconnected_from_ssh_remote(&mut self) {
7974 if let LspStoreMode::Remote(RemoteLspStore {
7975 upstream_client, ..
7976 }) = &mut self.mode
7977 {
7978 upstream_client.take();
7979 }
7980 }
7981
7982 pub(crate) fn set_language_server_statuses_from_proto(
7983 &mut self,
7984 project: WeakEntity<Project>,
7985 language_servers: Vec<proto::LanguageServer>,
7986 server_capabilities: Vec<String>,
7987 cx: &mut Context<Self>,
7988 ) {
7989 let lsp_logs = cx
7990 .try_global::<GlobalLogStore>()
7991 .map(|lsp_store| lsp_store.0.clone());
7992
7993 self.language_server_statuses = language_servers
7994 .into_iter()
7995 .zip(server_capabilities)
7996 .map(|(server, server_capabilities)| {
7997 let server_id = LanguageServerId(server.id as usize);
7998 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7999 self.lsp_server_capabilities
8000 .insert(server_id, server_capabilities);
8001 }
8002
8003 let name = LanguageServerName::from_proto(server.name);
8004 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8005
8006 if let Some(lsp_logs) = &lsp_logs {
8007 lsp_logs.update(cx, |lsp_logs, cx| {
8008 lsp_logs.add_language_server(
8009 // Only remote clients get their language servers set from proto
8010 LanguageServerKind::Remote {
8011 project: project.clone(),
8012 },
8013 server_id,
8014 Some(name.clone()),
8015 worktree,
8016 None,
8017 cx,
8018 );
8019 });
8020 }
8021
8022 (
8023 server_id,
8024 LanguageServerStatus {
8025 name,
8026 pending_work: Default::default(),
8027 has_pending_diagnostic_updates: false,
8028 progress_tokens: Default::default(),
8029 worktree,
8030 },
8031 )
8032 })
8033 .collect();
8034 }
8035
8036 #[cfg(test)]
8037 pub fn update_diagnostic_entries(
8038 &mut self,
8039 server_id: LanguageServerId,
8040 abs_path: PathBuf,
8041 result_id: Option<String>,
8042 version: Option<i32>,
8043 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8044 cx: &mut Context<Self>,
8045 ) -> anyhow::Result<()> {
8046 self.merge_diagnostic_entries(
8047 vec![DocumentDiagnosticsUpdate {
8048 diagnostics: DocumentDiagnostics {
8049 diagnostics,
8050 document_abs_path: abs_path,
8051 version,
8052 },
8053 result_id,
8054 server_id,
8055 disk_based_sources: Cow::Borrowed(&[]),
8056 }],
8057 |_, _, _| false,
8058 cx,
8059 )?;
8060 Ok(())
8061 }
8062
8063 pub fn merge_diagnostic_entries<'a>(
8064 &mut self,
8065 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8066 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8067 cx: &mut Context<Self>,
8068 ) -> anyhow::Result<()> {
8069 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8070 let mut updated_diagnostics_paths = HashMap::default();
8071 for mut update in diagnostic_updates {
8072 let abs_path = &update.diagnostics.document_abs_path;
8073 let server_id = update.server_id;
8074 let Some((worktree, relative_path)) =
8075 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8076 else {
8077 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8078 return Ok(());
8079 };
8080
8081 let worktree_id = worktree.read(cx).id();
8082 let project_path = ProjectPath {
8083 worktree_id,
8084 path: relative_path,
8085 };
8086
8087 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8088 let snapshot = buffer_handle.read(cx).snapshot();
8089 let buffer = buffer_handle.read(cx);
8090 let reused_diagnostics = buffer
8091 .buffer_diagnostics(Some(server_id))
8092 .iter()
8093 .filter(|v| merge(buffer, &v.diagnostic, cx))
8094 .map(|v| {
8095 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8096 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8097 DiagnosticEntry {
8098 range: start..end,
8099 diagnostic: v.diagnostic.clone(),
8100 }
8101 })
8102 .collect::<Vec<_>>();
8103
8104 self.as_local_mut()
8105 .context("cannot merge diagnostics on a remote LspStore")?
8106 .update_buffer_diagnostics(
8107 &buffer_handle,
8108 server_id,
8109 update.result_id,
8110 update.diagnostics.version,
8111 update.diagnostics.diagnostics.clone(),
8112 reused_diagnostics.clone(),
8113 cx,
8114 )?;
8115
8116 update.diagnostics.diagnostics.extend(reused_diagnostics);
8117 }
8118
8119 let updated = worktree.update(cx, |worktree, cx| {
8120 self.update_worktree_diagnostics(
8121 worktree.id(),
8122 server_id,
8123 project_path.path.clone(),
8124 update.diagnostics.diagnostics,
8125 cx,
8126 )
8127 })?;
8128 match updated {
8129 ControlFlow::Continue(new_summary) => {
8130 if let Some((project_id, new_summary)) = new_summary {
8131 match &mut diagnostics_summary {
8132 Some(diagnostics_summary) => {
8133 diagnostics_summary
8134 .more_summaries
8135 .push(proto::DiagnosticSummary {
8136 path: project_path.path.as_ref().to_proto(),
8137 language_server_id: server_id.0 as u64,
8138 error_count: new_summary.error_count,
8139 warning_count: new_summary.warning_count,
8140 })
8141 }
8142 None => {
8143 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8144 project_id,
8145 worktree_id: worktree_id.to_proto(),
8146 summary: Some(proto::DiagnosticSummary {
8147 path: project_path.path.as_ref().to_proto(),
8148 language_server_id: server_id.0 as u64,
8149 error_count: new_summary.error_count,
8150 warning_count: new_summary.warning_count,
8151 }),
8152 more_summaries: Vec::new(),
8153 })
8154 }
8155 }
8156 }
8157 updated_diagnostics_paths
8158 .entry(server_id)
8159 .or_insert_with(Vec::new)
8160 .push(project_path);
8161 }
8162 ControlFlow::Break(()) => {}
8163 }
8164 }
8165
8166 if let Some((diagnostics_summary, (downstream_client, _))) =
8167 diagnostics_summary.zip(self.downstream_client.as_ref())
8168 {
8169 downstream_client.send(diagnostics_summary).log_err();
8170 }
8171 for (server_id, paths) in updated_diagnostics_paths {
8172 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8173 }
8174 Ok(())
8175 }
8176
8177 fn update_worktree_diagnostics(
8178 &mut self,
8179 worktree_id: WorktreeId,
8180 server_id: LanguageServerId,
8181 path_in_worktree: Arc<RelPath>,
8182 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8183 _: &mut Context<Worktree>,
8184 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8185 let local = match &mut self.mode {
8186 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8187 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8188 };
8189
8190 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8191 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8192 let summaries_by_server_id = summaries_for_tree
8193 .entry(path_in_worktree.clone())
8194 .or_default();
8195
8196 let old_summary = summaries_by_server_id
8197 .remove(&server_id)
8198 .unwrap_or_default();
8199
8200 let new_summary = DiagnosticSummary::new(&diagnostics);
8201 if new_summary.is_empty() {
8202 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8203 {
8204 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8205 diagnostics_by_server_id.remove(ix);
8206 }
8207 if diagnostics_by_server_id.is_empty() {
8208 diagnostics_for_tree.remove(&path_in_worktree);
8209 }
8210 }
8211 } else {
8212 summaries_by_server_id.insert(server_id, new_summary);
8213 let diagnostics_by_server_id = diagnostics_for_tree
8214 .entry(path_in_worktree.clone())
8215 .or_default();
8216 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8217 Ok(ix) => {
8218 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8219 }
8220 Err(ix) => {
8221 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8222 }
8223 }
8224 }
8225
8226 if !old_summary.is_empty() || !new_summary.is_empty() {
8227 if let Some((_, project_id)) = &self.downstream_client {
8228 Ok(ControlFlow::Continue(Some((
8229 *project_id,
8230 proto::DiagnosticSummary {
8231 path: path_in_worktree.to_proto(),
8232 language_server_id: server_id.0 as u64,
8233 error_count: new_summary.error_count as u32,
8234 warning_count: new_summary.warning_count as u32,
8235 },
8236 ))))
8237 } else {
8238 Ok(ControlFlow::Continue(None))
8239 }
8240 } else {
8241 Ok(ControlFlow::Break(()))
8242 }
8243 }
8244
8245 pub fn open_buffer_for_symbol(
8246 &mut self,
8247 symbol: &Symbol,
8248 cx: &mut Context<Self>,
8249 ) -> Task<Result<Entity<Buffer>>> {
8250 if let Some((client, project_id)) = self.upstream_client() {
8251 let request = client.request(proto::OpenBufferForSymbol {
8252 project_id,
8253 symbol: Some(Self::serialize_symbol(symbol)),
8254 });
8255 cx.spawn(async move |this, cx| {
8256 let response = request.await?;
8257 let buffer_id = BufferId::new(response.buffer_id)?;
8258 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8259 .await
8260 })
8261 } else if let Some(local) = self.as_local() {
8262 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8263 seed.worktree_id == symbol.source_worktree_id
8264 && state.id == symbol.source_language_server_id
8265 && symbol.language_server_name == seed.name
8266 });
8267 if !is_valid {
8268 return Task::ready(Err(anyhow!(
8269 "language server for worktree and language not found"
8270 )));
8271 };
8272
8273 let symbol_abs_path = match &symbol.path {
8274 SymbolLocation::InProject(project_path) => self
8275 .worktree_store
8276 .read(cx)
8277 .absolutize(&project_path, cx)
8278 .context("no such worktree"),
8279 SymbolLocation::OutsideProject {
8280 abs_path,
8281 signature: _,
8282 } => Ok(abs_path.to_path_buf()),
8283 };
8284 let symbol_abs_path = match symbol_abs_path {
8285 Ok(abs_path) => abs_path,
8286 Err(err) => return Task::ready(Err(err)),
8287 };
8288 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8289 uri
8290 } else {
8291 return Task::ready(Err(anyhow!("invalid symbol path")));
8292 };
8293
8294 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8295 } else {
8296 Task::ready(Err(anyhow!("no upstream client or local store")))
8297 }
8298 }
8299
8300 pub(crate) fn open_local_buffer_via_lsp(
8301 &mut self,
8302 abs_path: lsp::Uri,
8303 language_server_id: LanguageServerId,
8304 cx: &mut Context<Self>,
8305 ) -> Task<Result<Entity<Buffer>>> {
8306 cx.spawn(async move |lsp_store, cx| {
8307 // Escape percent-encoded string.
8308 let current_scheme = abs_path.scheme().to_owned();
8309 // Uri is immutable, so we can't modify the scheme
8310
8311 let abs_path = abs_path
8312 .to_file_path()
8313 .map_err(|()| anyhow!("can't convert URI to path"))?;
8314 let p = abs_path.clone();
8315 let yarn_worktree = lsp_store
8316 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8317 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8318 cx.spawn(async move |this, cx| {
8319 let t = this
8320 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8321 .ok()?;
8322 t.await
8323 })
8324 }),
8325 None => Task::ready(None),
8326 })?
8327 .await;
8328 let (worktree_root_target, known_relative_path) =
8329 if let Some((zip_root, relative_path)) = yarn_worktree {
8330 (zip_root, Some(relative_path))
8331 } else {
8332 (Arc::<Path>::from(abs_path.as_path()), None)
8333 };
8334 let (worktree, relative_path) = if let Some(result) =
8335 lsp_store.update(cx, |lsp_store, cx| {
8336 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8337 worktree_store.find_worktree(&worktree_root_target, cx)
8338 })
8339 })? {
8340 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8341 (result.0, relative_path)
8342 } else {
8343 let worktree = lsp_store
8344 .update(cx, |lsp_store, cx| {
8345 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8346 worktree_store.create_worktree(&worktree_root_target, false, cx)
8347 })
8348 })?
8349 .await?;
8350 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8351 lsp_store
8352 .update(cx, |lsp_store, cx| {
8353 if let Some(local) = lsp_store.as_local_mut() {
8354 local.register_language_server_for_invisible_worktree(
8355 &worktree,
8356 language_server_id,
8357 cx,
8358 )
8359 }
8360 })
8361 .ok();
8362 }
8363 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8364 let relative_path = if let Some(known_path) = known_relative_path {
8365 known_path
8366 } else {
8367 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8368 .into_arc()
8369 };
8370 (worktree, relative_path)
8371 };
8372 let project_path = ProjectPath {
8373 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8374 path: relative_path,
8375 };
8376 lsp_store
8377 .update(cx, |lsp_store, cx| {
8378 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8379 buffer_store.open_buffer(project_path, cx)
8380 })
8381 })?
8382 .await
8383 })
8384 }
8385
8386 fn request_multiple_lsp_locally<P, R>(
8387 &mut self,
8388 buffer: &Entity<Buffer>,
8389 position: Option<P>,
8390 request: R,
8391 cx: &mut Context<Self>,
8392 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8393 where
8394 P: ToOffset,
8395 R: LspCommand + Clone,
8396 <R::LspRequest as lsp::request::Request>::Result: Send,
8397 <R::LspRequest as lsp::request::Request>::Params: Send,
8398 {
8399 let Some(local) = self.as_local() else {
8400 return Task::ready(Vec::new());
8401 };
8402
8403 let snapshot = buffer.read(cx).snapshot();
8404 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8405
8406 let server_ids = buffer.update(cx, |buffer, cx| {
8407 local
8408 .language_servers_for_buffer(buffer, cx)
8409 .filter(|(adapter, _)| {
8410 scope
8411 .as_ref()
8412 .map(|scope| scope.language_allowed(&adapter.name))
8413 .unwrap_or(true)
8414 })
8415 .map(|(_, server)| server.server_id())
8416 .filter(|server_id| {
8417 self.as_local().is_none_or(|local| {
8418 local
8419 .buffers_opened_in_servers
8420 .get(&snapshot.remote_id())
8421 .is_some_and(|servers| servers.contains(server_id))
8422 })
8423 })
8424 .collect::<Vec<_>>()
8425 });
8426
8427 let mut response_results = server_ids
8428 .into_iter()
8429 .map(|server_id| {
8430 let task = self.request_lsp(
8431 buffer.clone(),
8432 LanguageServerToQuery::Other(server_id),
8433 request.clone(),
8434 cx,
8435 );
8436 async move { (server_id, task.await) }
8437 })
8438 .collect::<FuturesUnordered<_>>();
8439
8440 cx.background_spawn(async move {
8441 let mut responses = Vec::with_capacity(response_results.len());
8442 while let Some((server_id, response_result)) = response_results.next().await {
8443 match response_result {
8444 Ok(response) => responses.push((server_id, response)),
8445 // rust-analyzer likes to error with this when its still loading up
8446 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8447 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8448 }
8449 }
8450 responses
8451 })
8452 }
8453
8454 async fn handle_lsp_command<T: LspCommand>(
8455 this: Entity<Self>,
8456 envelope: TypedEnvelope<T::ProtoRequest>,
8457 mut cx: AsyncApp,
8458 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8459 where
8460 <T::LspRequest as lsp::request::Request>::Params: Send,
8461 <T::LspRequest as lsp::request::Request>::Result: Send,
8462 {
8463 let sender_id = envelope.original_sender_id().unwrap_or_default();
8464 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8465 let buffer_handle = this.update(&mut cx, |this, cx| {
8466 this.buffer_store.read(cx).get_existing(buffer_id)
8467 })??;
8468 let request = T::from_proto(
8469 envelope.payload,
8470 this.clone(),
8471 buffer_handle.clone(),
8472 cx.clone(),
8473 )
8474 .await?;
8475 let response = this
8476 .update(&mut cx, |this, cx| {
8477 this.request_lsp(
8478 buffer_handle.clone(),
8479 LanguageServerToQuery::FirstCapable,
8480 request,
8481 cx,
8482 )
8483 })?
8484 .await?;
8485 this.update(&mut cx, |this, cx| {
8486 Ok(T::response_to_proto(
8487 response,
8488 this,
8489 sender_id,
8490 &buffer_handle.read(cx).version(),
8491 cx,
8492 ))
8493 })?
8494 }
8495
8496 async fn handle_lsp_query(
8497 lsp_store: Entity<Self>,
8498 envelope: TypedEnvelope<proto::LspQuery>,
8499 mut cx: AsyncApp,
8500 ) -> Result<proto::Ack> {
8501 use proto::lsp_query::Request;
8502 let sender_id = envelope.original_sender_id().unwrap_or_default();
8503 let lsp_query = envelope.payload;
8504 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8505 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8506 match lsp_query.request.context("invalid LSP query request")? {
8507 Request::GetReferences(get_references) => {
8508 let position = get_references.position.clone().and_then(deserialize_anchor);
8509 Self::query_lsp_locally::<GetReferences>(
8510 lsp_store,
8511 server_id,
8512 sender_id,
8513 lsp_request_id,
8514 get_references,
8515 position,
8516 &mut cx,
8517 )
8518 .await?;
8519 }
8520 Request::GetDocumentColor(get_document_color) => {
8521 Self::query_lsp_locally::<GetDocumentColor>(
8522 lsp_store,
8523 server_id,
8524 sender_id,
8525 lsp_request_id,
8526 get_document_color,
8527 None,
8528 &mut cx,
8529 )
8530 .await?;
8531 }
8532 Request::GetHover(get_hover) => {
8533 let position = get_hover.position.clone().and_then(deserialize_anchor);
8534 Self::query_lsp_locally::<GetHover>(
8535 lsp_store,
8536 server_id,
8537 sender_id,
8538 lsp_request_id,
8539 get_hover,
8540 position,
8541 &mut cx,
8542 )
8543 .await?;
8544 }
8545 Request::GetCodeActions(get_code_actions) => {
8546 Self::query_lsp_locally::<GetCodeActions>(
8547 lsp_store,
8548 server_id,
8549 sender_id,
8550 lsp_request_id,
8551 get_code_actions,
8552 None,
8553 &mut cx,
8554 )
8555 .await?;
8556 }
8557 Request::GetSignatureHelp(get_signature_help) => {
8558 let position = get_signature_help
8559 .position
8560 .clone()
8561 .and_then(deserialize_anchor);
8562 Self::query_lsp_locally::<GetSignatureHelp>(
8563 lsp_store,
8564 server_id,
8565 sender_id,
8566 lsp_request_id,
8567 get_signature_help,
8568 position,
8569 &mut cx,
8570 )
8571 .await?;
8572 }
8573 Request::GetCodeLens(get_code_lens) => {
8574 Self::query_lsp_locally::<GetCodeLens>(
8575 lsp_store,
8576 server_id,
8577 sender_id,
8578 lsp_request_id,
8579 get_code_lens,
8580 None,
8581 &mut cx,
8582 )
8583 .await?;
8584 }
8585 Request::GetDefinition(get_definition) => {
8586 let position = get_definition.position.clone().and_then(deserialize_anchor);
8587 Self::query_lsp_locally::<GetDefinitions>(
8588 lsp_store,
8589 server_id,
8590 sender_id,
8591 lsp_request_id,
8592 get_definition,
8593 position,
8594 &mut cx,
8595 )
8596 .await?;
8597 }
8598 Request::GetDeclaration(get_declaration) => {
8599 let position = get_declaration
8600 .position
8601 .clone()
8602 .and_then(deserialize_anchor);
8603 Self::query_lsp_locally::<GetDeclarations>(
8604 lsp_store,
8605 server_id,
8606 sender_id,
8607 lsp_request_id,
8608 get_declaration,
8609 position,
8610 &mut cx,
8611 )
8612 .await?;
8613 }
8614 Request::GetTypeDefinition(get_type_definition) => {
8615 let position = get_type_definition
8616 .position
8617 .clone()
8618 .and_then(deserialize_anchor);
8619 Self::query_lsp_locally::<GetTypeDefinitions>(
8620 lsp_store,
8621 server_id,
8622 sender_id,
8623 lsp_request_id,
8624 get_type_definition,
8625 position,
8626 &mut cx,
8627 )
8628 .await?;
8629 }
8630 Request::GetImplementation(get_implementation) => {
8631 let position = get_implementation
8632 .position
8633 .clone()
8634 .and_then(deserialize_anchor);
8635 Self::query_lsp_locally::<GetImplementations>(
8636 lsp_store,
8637 server_id,
8638 sender_id,
8639 lsp_request_id,
8640 get_implementation,
8641 position,
8642 &mut cx,
8643 )
8644 .await?;
8645 }
8646 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8647 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8648 let version = deserialize_version(get_document_diagnostics.buffer_version());
8649 let buffer = lsp_store.update(&mut cx, |this, cx| {
8650 this.buffer_store.read(cx).get_existing(buffer_id)
8651 })??;
8652 buffer
8653 .update(&mut cx, |buffer, _| {
8654 buffer.wait_for_version(version.clone())
8655 })?
8656 .await?;
8657 lsp_store.update(&mut cx, |lsp_store, cx| {
8658 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8659 let key = LspKey {
8660 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8661 server_queried: server_id,
8662 };
8663 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8664 ) {
8665 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8666 lsp_requests.clear();
8667 };
8668 }
8669
8670 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8671 existing_queries.insert(
8672 lsp_request_id,
8673 cx.spawn(async move |lsp_store, cx| {
8674 let diagnostics_pull = lsp_store
8675 .update(cx, |lsp_store, cx| {
8676 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8677 })
8678 .ok();
8679 if let Some(diagnostics_pull) = diagnostics_pull {
8680 match diagnostics_pull.await {
8681 Ok(()) => {}
8682 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8683 };
8684 }
8685 }),
8686 );
8687 })?;
8688 }
8689 Request::InlayHints(inlay_hints) => {
8690 let query_start = inlay_hints
8691 .start
8692 .clone()
8693 .and_then(deserialize_anchor)
8694 .context("invalid inlay hints range start")?;
8695 let query_end = inlay_hints
8696 .end
8697 .clone()
8698 .and_then(deserialize_anchor)
8699 .context("invalid inlay hints range end")?;
8700 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8701 &lsp_store,
8702 server_id,
8703 lsp_request_id,
8704 &inlay_hints,
8705 query_start..query_end,
8706 &mut cx,
8707 )
8708 .await
8709 .context("preparing inlay hints request")?;
8710 Self::query_lsp_locally::<InlayHints>(
8711 lsp_store,
8712 server_id,
8713 sender_id,
8714 lsp_request_id,
8715 inlay_hints,
8716 None,
8717 &mut cx,
8718 )
8719 .await
8720 .context("querying for inlay hints")?
8721 }
8722 }
8723 Ok(proto::Ack {})
8724 }
8725
8726 async fn handle_lsp_query_response(
8727 lsp_store: Entity<Self>,
8728 envelope: TypedEnvelope<proto::LspQueryResponse>,
8729 cx: AsyncApp,
8730 ) -> Result<()> {
8731 lsp_store.read_with(&cx, |lsp_store, _| {
8732 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8733 upstream_client.handle_lsp_response(envelope.clone());
8734 }
8735 })?;
8736 Ok(())
8737 }
8738
8739 async fn handle_apply_code_action(
8740 this: Entity<Self>,
8741 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8742 mut cx: AsyncApp,
8743 ) -> Result<proto::ApplyCodeActionResponse> {
8744 let sender_id = envelope.original_sender_id().unwrap_or_default();
8745 let action =
8746 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8747 let apply_code_action = this.update(&mut cx, |this, cx| {
8748 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8749 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8750 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8751 })??;
8752
8753 let project_transaction = apply_code_action.await?;
8754 let project_transaction = this.update(&mut cx, |this, cx| {
8755 this.buffer_store.update(cx, |buffer_store, cx| {
8756 buffer_store.serialize_project_transaction_for_peer(
8757 project_transaction,
8758 sender_id,
8759 cx,
8760 )
8761 })
8762 })?;
8763 Ok(proto::ApplyCodeActionResponse {
8764 transaction: Some(project_transaction),
8765 })
8766 }
8767
8768 async fn handle_register_buffer_with_language_servers(
8769 this: Entity<Self>,
8770 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8771 mut cx: AsyncApp,
8772 ) -> Result<proto::Ack> {
8773 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8774 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8775 this.update(&mut cx, |this, cx| {
8776 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8777 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8778 project_id: upstream_project_id,
8779 buffer_id: buffer_id.to_proto(),
8780 only_servers: envelope.payload.only_servers,
8781 });
8782 }
8783
8784 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8785 anyhow::bail!("buffer is not open");
8786 };
8787
8788 let handle = this.register_buffer_with_language_servers(
8789 &buffer,
8790 envelope
8791 .payload
8792 .only_servers
8793 .into_iter()
8794 .filter_map(|selector| {
8795 Some(match selector.selector? {
8796 proto::language_server_selector::Selector::ServerId(server_id) => {
8797 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8798 }
8799 proto::language_server_selector::Selector::Name(name) => {
8800 LanguageServerSelector::Name(LanguageServerName(
8801 SharedString::from(name),
8802 ))
8803 }
8804 })
8805 })
8806 .collect(),
8807 false,
8808 cx,
8809 );
8810 this.buffer_store().update(cx, |buffer_store, _| {
8811 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8812 });
8813
8814 Ok(())
8815 })??;
8816 Ok(proto::Ack {})
8817 }
8818
8819 async fn handle_rename_project_entry(
8820 this: Entity<Self>,
8821 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8822 mut cx: AsyncApp,
8823 ) -> Result<proto::ProjectEntryResponse> {
8824 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8825 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8826 let new_path =
8827 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8828
8829 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8830 .update(&mut cx, |this, cx| {
8831 let (worktree, entry) = this
8832 .worktree_store
8833 .read(cx)
8834 .worktree_and_entry_for_id(entry_id, cx)?;
8835 let new_worktree = this
8836 .worktree_store
8837 .read(cx)
8838 .worktree_for_id(new_worktree_id, cx)?;
8839 Some((
8840 this.worktree_store.clone(),
8841 worktree,
8842 new_worktree,
8843 entry.clone(),
8844 ))
8845 })?
8846 .context("worktree not found")?;
8847 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8848 (worktree.absolutize(&old_entry.path), worktree.id())
8849 })?;
8850 let new_abs_path =
8851 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8852
8853 let _transaction = Self::will_rename_entry(
8854 this.downgrade(),
8855 old_worktree_id,
8856 &old_abs_path,
8857 &new_abs_path,
8858 old_entry.is_dir(),
8859 cx.clone(),
8860 )
8861 .await;
8862 let response = WorktreeStore::handle_rename_project_entry(
8863 worktree_store,
8864 envelope.payload,
8865 cx.clone(),
8866 )
8867 .await;
8868 this.read_with(&cx, |this, _| {
8869 this.did_rename_entry(
8870 old_worktree_id,
8871 &old_abs_path,
8872 &new_abs_path,
8873 old_entry.is_dir(),
8874 );
8875 })
8876 .ok();
8877 response
8878 }
8879
8880 async fn handle_update_diagnostic_summary(
8881 this: Entity<Self>,
8882 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8883 mut cx: AsyncApp,
8884 ) -> Result<()> {
8885 this.update(&mut cx, |lsp_store, cx| {
8886 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8887 let mut updated_diagnostics_paths = HashMap::default();
8888 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8889 for message_summary in envelope
8890 .payload
8891 .summary
8892 .into_iter()
8893 .chain(envelope.payload.more_summaries)
8894 {
8895 let project_path = ProjectPath {
8896 worktree_id,
8897 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8898 };
8899 let path = project_path.path.clone();
8900 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8901 let summary = DiagnosticSummary {
8902 error_count: message_summary.error_count as usize,
8903 warning_count: message_summary.warning_count as usize,
8904 };
8905
8906 if summary.is_empty() {
8907 if let Some(worktree_summaries) =
8908 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8909 && let Some(summaries) = worktree_summaries.get_mut(&path)
8910 {
8911 summaries.remove(&server_id);
8912 if summaries.is_empty() {
8913 worktree_summaries.remove(&path);
8914 }
8915 }
8916 } else {
8917 lsp_store
8918 .diagnostic_summaries
8919 .entry(worktree_id)
8920 .or_default()
8921 .entry(path)
8922 .or_default()
8923 .insert(server_id, summary);
8924 }
8925
8926 if let Some((_, project_id)) = &lsp_store.downstream_client {
8927 match &mut diagnostics_summary {
8928 Some(diagnostics_summary) => {
8929 diagnostics_summary
8930 .more_summaries
8931 .push(proto::DiagnosticSummary {
8932 path: project_path.path.as_ref().to_proto(),
8933 language_server_id: server_id.0 as u64,
8934 error_count: summary.error_count as u32,
8935 warning_count: summary.warning_count as u32,
8936 })
8937 }
8938 None => {
8939 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8940 project_id: *project_id,
8941 worktree_id: worktree_id.to_proto(),
8942 summary: Some(proto::DiagnosticSummary {
8943 path: project_path.path.as_ref().to_proto(),
8944 language_server_id: server_id.0 as u64,
8945 error_count: summary.error_count as u32,
8946 warning_count: summary.warning_count as u32,
8947 }),
8948 more_summaries: Vec::new(),
8949 })
8950 }
8951 }
8952 }
8953 updated_diagnostics_paths
8954 .entry(server_id)
8955 .or_insert_with(Vec::new)
8956 .push(project_path);
8957 }
8958
8959 if let Some((diagnostics_summary, (downstream_client, _))) =
8960 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8961 {
8962 downstream_client.send(diagnostics_summary).log_err();
8963 }
8964 for (server_id, paths) in updated_diagnostics_paths {
8965 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8966 }
8967 Ok(())
8968 })?
8969 }
8970
8971 async fn handle_start_language_server(
8972 lsp_store: Entity<Self>,
8973 envelope: TypedEnvelope<proto::StartLanguageServer>,
8974 mut cx: AsyncApp,
8975 ) -> Result<()> {
8976 let server = envelope.payload.server.context("invalid server")?;
8977 let server_capabilities =
8978 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8979 .with_context(|| {
8980 format!(
8981 "incorrect server capabilities {}",
8982 envelope.payload.capabilities
8983 )
8984 })?;
8985 lsp_store.update(&mut cx, |lsp_store, cx| {
8986 let server_id = LanguageServerId(server.id as usize);
8987 let server_name = LanguageServerName::from_proto(server.name.clone());
8988 lsp_store
8989 .lsp_server_capabilities
8990 .insert(server_id, server_capabilities);
8991 lsp_store.language_server_statuses.insert(
8992 server_id,
8993 LanguageServerStatus {
8994 name: server_name.clone(),
8995 pending_work: Default::default(),
8996 has_pending_diagnostic_updates: false,
8997 progress_tokens: Default::default(),
8998 worktree: server.worktree_id.map(WorktreeId::from_proto),
8999 },
9000 );
9001 cx.emit(LspStoreEvent::LanguageServerAdded(
9002 server_id,
9003 server_name,
9004 server.worktree_id.map(WorktreeId::from_proto),
9005 ));
9006 cx.notify();
9007 })?;
9008 Ok(())
9009 }
9010
9011 async fn handle_update_language_server(
9012 lsp_store: Entity<Self>,
9013 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9014 mut cx: AsyncApp,
9015 ) -> Result<()> {
9016 lsp_store.update(&mut cx, |lsp_store, cx| {
9017 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9018
9019 match envelope.payload.variant.context("invalid variant")? {
9020 proto::update_language_server::Variant::WorkStart(payload) => {
9021 lsp_store.on_lsp_work_start(
9022 language_server_id,
9023 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9024 .context("invalid progress token value")?,
9025 LanguageServerProgress {
9026 title: payload.title,
9027 is_disk_based_diagnostics_progress: false,
9028 is_cancellable: payload.is_cancellable.unwrap_or(false),
9029 message: payload.message,
9030 percentage: payload.percentage.map(|p| p as usize),
9031 last_update_at: cx.background_executor().now(),
9032 },
9033 cx,
9034 );
9035 }
9036 proto::update_language_server::Variant::WorkProgress(payload) => {
9037 lsp_store.on_lsp_work_progress(
9038 language_server_id,
9039 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9040 .context("invalid progress token value")?,
9041 LanguageServerProgress {
9042 title: None,
9043 is_disk_based_diagnostics_progress: false,
9044 is_cancellable: payload.is_cancellable.unwrap_or(false),
9045 message: payload.message,
9046 percentage: payload.percentage.map(|p| p as usize),
9047 last_update_at: cx.background_executor().now(),
9048 },
9049 cx,
9050 );
9051 }
9052
9053 proto::update_language_server::Variant::WorkEnd(payload) => {
9054 lsp_store.on_lsp_work_end(
9055 language_server_id,
9056 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9057 .context("invalid progress token value")?,
9058 cx,
9059 );
9060 }
9061
9062 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9063 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9064 }
9065
9066 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9067 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9068 }
9069
9070 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9071 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9072 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9073 cx.emit(LspStoreEvent::LanguageServerUpdate {
9074 language_server_id,
9075 name: envelope
9076 .payload
9077 .server_name
9078 .map(SharedString::new)
9079 .map(LanguageServerName),
9080 message: non_lsp,
9081 });
9082 }
9083 }
9084
9085 Ok(())
9086 })?
9087 }
9088
9089 async fn handle_language_server_log(
9090 this: Entity<Self>,
9091 envelope: TypedEnvelope<proto::LanguageServerLog>,
9092 mut cx: AsyncApp,
9093 ) -> Result<()> {
9094 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9095 let log_type = envelope
9096 .payload
9097 .log_type
9098 .map(LanguageServerLogType::from_proto)
9099 .context("invalid language server log type")?;
9100
9101 let message = envelope.payload.message;
9102
9103 this.update(&mut cx, |_, cx| {
9104 cx.emit(LspStoreEvent::LanguageServerLog(
9105 language_server_id,
9106 log_type,
9107 message,
9108 ));
9109 })
9110 }
9111
9112 async fn handle_lsp_ext_cancel_flycheck(
9113 lsp_store: Entity<Self>,
9114 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9115 cx: AsyncApp,
9116 ) -> Result<proto::Ack> {
9117 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9118 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9119 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9120 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9121 } else {
9122 None
9123 }
9124 })?;
9125 if let Some(task) = task {
9126 task.context("handling lsp ext cancel flycheck")?;
9127 }
9128
9129 Ok(proto::Ack {})
9130 }
9131
9132 async fn handle_lsp_ext_run_flycheck(
9133 lsp_store: Entity<Self>,
9134 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9135 mut cx: AsyncApp,
9136 ) -> Result<proto::Ack> {
9137 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9138 lsp_store.update(&mut cx, |lsp_store, cx| {
9139 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9140 let text_document = if envelope.payload.current_file_only {
9141 let buffer_id = envelope
9142 .payload
9143 .buffer_id
9144 .map(|id| BufferId::new(id))
9145 .transpose()?;
9146 buffer_id
9147 .and_then(|buffer_id| {
9148 lsp_store
9149 .buffer_store()
9150 .read(cx)
9151 .get(buffer_id)
9152 .and_then(|buffer| {
9153 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9154 })
9155 .map(|path| make_text_document_identifier(&path))
9156 })
9157 .transpose()?
9158 } else {
9159 None
9160 };
9161 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9162 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9163 )?;
9164 }
9165 anyhow::Ok(())
9166 })??;
9167
9168 Ok(proto::Ack {})
9169 }
9170
9171 async fn handle_lsp_ext_clear_flycheck(
9172 lsp_store: Entity<Self>,
9173 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9174 cx: AsyncApp,
9175 ) -> Result<proto::Ack> {
9176 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9177 lsp_store
9178 .read_with(&cx, |lsp_store, _| {
9179 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9180 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9181 } else {
9182 None
9183 }
9184 })
9185 .context("handling lsp ext clear flycheck")?;
9186
9187 Ok(proto::Ack {})
9188 }
9189
9190 pub fn disk_based_diagnostics_started(
9191 &mut self,
9192 language_server_id: LanguageServerId,
9193 cx: &mut Context<Self>,
9194 ) {
9195 if let Some(language_server_status) =
9196 self.language_server_statuses.get_mut(&language_server_id)
9197 {
9198 language_server_status.has_pending_diagnostic_updates = true;
9199 }
9200
9201 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9202 cx.emit(LspStoreEvent::LanguageServerUpdate {
9203 language_server_id,
9204 name: self
9205 .language_server_adapter_for_id(language_server_id)
9206 .map(|adapter| adapter.name()),
9207 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9208 Default::default(),
9209 ),
9210 })
9211 }
9212
9213 pub fn disk_based_diagnostics_finished(
9214 &mut self,
9215 language_server_id: LanguageServerId,
9216 cx: &mut Context<Self>,
9217 ) {
9218 if let Some(language_server_status) =
9219 self.language_server_statuses.get_mut(&language_server_id)
9220 {
9221 language_server_status.has_pending_diagnostic_updates = false;
9222 }
9223
9224 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9225 cx.emit(LspStoreEvent::LanguageServerUpdate {
9226 language_server_id,
9227 name: self
9228 .language_server_adapter_for_id(language_server_id)
9229 .map(|adapter| adapter.name()),
9230 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9231 Default::default(),
9232 ),
9233 })
9234 }
9235
9236 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9237 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9238 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9239 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9240 // the language server might take some time to publish diagnostics.
9241 fn simulate_disk_based_diagnostics_events_if_needed(
9242 &mut self,
9243 language_server_id: LanguageServerId,
9244 cx: &mut Context<Self>,
9245 ) {
9246 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9247
9248 let Some(LanguageServerState::Running {
9249 simulate_disk_based_diagnostics_completion,
9250 adapter,
9251 ..
9252 }) = self
9253 .as_local_mut()
9254 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9255 else {
9256 return;
9257 };
9258
9259 if adapter.disk_based_diagnostics_progress_token.is_some() {
9260 return;
9261 }
9262
9263 let prev_task =
9264 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9265 cx.background_executor()
9266 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9267 .await;
9268
9269 this.update(cx, |this, cx| {
9270 this.disk_based_diagnostics_finished(language_server_id, cx);
9271
9272 if let Some(LanguageServerState::Running {
9273 simulate_disk_based_diagnostics_completion,
9274 ..
9275 }) = this.as_local_mut().and_then(|local_store| {
9276 local_store.language_servers.get_mut(&language_server_id)
9277 }) {
9278 *simulate_disk_based_diagnostics_completion = None;
9279 }
9280 })
9281 .ok();
9282 }));
9283
9284 if prev_task.is_none() {
9285 self.disk_based_diagnostics_started(language_server_id, cx);
9286 }
9287 }
9288
9289 pub fn language_server_statuses(
9290 &self,
9291 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9292 self.language_server_statuses
9293 .iter()
9294 .map(|(key, value)| (*key, value))
9295 }
9296
9297 pub(super) fn did_rename_entry(
9298 &self,
9299 worktree_id: WorktreeId,
9300 old_path: &Path,
9301 new_path: &Path,
9302 is_dir: bool,
9303 ) {
9304 maybe!({
9305 let local_store = self.as_local()?;
9306
9307 let old_uri = lsp::Uri::from_file_path(old_path)
9308 .ok()
9309 .map(|uri| uri.to_string())?;
9310 let new_uri = lsp::Uri::from_file_path(new_path)
9311 .ok()
9312 .map(|uri| uri.to_string())?;
9313
9314 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9315 let Some(filter) = local_store
9316 .language_server_paths_watched_for_rename
9317 .get(&language_server.server_id())
9318 else {
9319 continue;
9320 };
9321
9322 if filter.should_send_did_rename(&old_uri, is_dir) {
9323 language_server
9324 .notify::<DidRenameFiles>(RenameFilesParams {
9325 files: vec![FileRename {
9326 old_uri: old_uri.clone(),
9327 new_uri: new_uri.clone(),
9328 }],
9329 })
9330 .ok();
9331 }
9332 }
9333 Some(())
9334 });
9335 }
9336
9337 pub(super) fn will_rename_entry(
9338 this: WeakEntity<Self>,
9339 worktree_id: WorktreeId,
9340 old_path: &Path,
9341 new_path: &Path,
9342 is_dir: bool,
9343 cx: AsyncApp,
9344 ) -> Task<ProjectTransaction> {
9345 let old_uri = lsp::Uri::from_file_path(old_path)
9346 .ok()
9347 .map(|uri| uri.to_string());
9348 let new_uri = lsp::Uri::from_file_path(new_path)
9349 .ok()
9350 .map(|uri| uri.to_string());
9351 cx.spawn(async move |cx| {
9352 let mut tasks = vec![];
9353 this.update(cx, |this, cx| {
9354 let local_store = this.as_local()?;
9355 let old_uri = old_uri?;
9356 let new_uri = new_uri?;
9357 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9358 let Some(filter) = local_store
9359 .language_server_paths_watched_for_rename
9360 .get(&language_server.server_id())
9361 else {
9362 continue;
9363 };
9364
9365 if filter.should_send_will_rename(&old_uri, is_dir) {
9366 let apply_edit = cx.spawn({
9367 let old_uri = old_uri.clone();
9368 let new_uri = new_uri.clone();
9369 let language_server = language_server.clone();
9370 async move |this, cx| {
9371 let edit = language_server
9372 .request::<WillRenameFiles>(RenameFilesParams {
9373 files: vec![FileRename { old_uri, new_uri }],
9374 })
9375 .await
9376 .into_response()
9377 .context("will rename files")
9378 .log_err()
9379 .flatten()?;
9380
9381 let transaction = LocalLspStore::deserialize_workspace_edit(
9382 this.upgrade()?,
9383 edit,
9384 false,
9385 language_server.clone(),
9386 cx,
9387 )
9388 .await
9389 .ok()?;
9390 Some(transaction)
9391 }
9392 });
9393 tasks.push(apply_edit);
9394 }
9395 }
9396 Some(())
9397 })
9398 .ok()
9399 .flatten();
9400 let mut merged_transaction = ProjectTransaction::default();
9401 for task in tasks {
9402 // Await on tasks sequentially so that the order of application of edits is deterministic
9403 // (at least with regards to the order of registration of language servers)
9404 if let Some(transaction) = task.await {
9405 for (buffer, buffer_transaction) in transaction.0 {
9406 merged_transaction.0.insert(buffer, buffer_transaction);
9407 }
9408 }
9409 }
9410 merged_transaction
9411 })
9412 }
9413
9414 fn lsp_notify_abs_paths_changed(
9415 &mut self,
9416 server_id: LanguageServerId,
9417 changes: Vec<PathEvent>,
9418 ) {
9419 maybe!({
9420 let server = self.language_server_for_id(server_id)?;
9421 let changes = changes
9422 .into_iter()
9423 .filter_map(|event| {
9424 let typ = match event.kind? {
9425 PathEventKind::Created => lsp::FileChangeType::CREATED,
9426 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9427 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9428 };
9429 Some(lsp::FileEvent {
9430 uri: file_path_to_lsp_url(&event.path).log_err()?,
9431 typ,
9432 })
9433 })
9434 .collect::<Vec<_>>();
9435 if !changes.is_empty() {
9436 server
9437 .notify::<lsp::notification::DidChangeWatchedFiles>(
9438 lsp::DidChangeWatchedFilesParams { changes },
9439 )
9440 .ok();
9441 }
9442 Some(())
9443 });
9444 }
9445
9446 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9447 self.as_local()?.language_server_for_id(id)
9448 }
9449
9450 fn on_lsp_progress(
9451 &mut self,
9452 progress_params: lsp::ProgressParams,
9453 language_server_id: LanguageServerId,
9454 disk_based_diagnostics_progress_token: Option<String>,
9455 cx: &mut Context<Self>,
9456 ) {
9457 match progress_params.value {
9458 lsp::ProgressParamsValue::WorkDone(progress) => {
9459 self.handle_work_done_progress(
9460 progress,
9461 language_server_id,
9462 disk_based_diagnostics_progress_token,
9463 ProgressToken::from_lsp(progress_params.token),
9464 cx,
9465 );
9466 }
9467 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9468 let identifier = match progress_params.token {
9469 lsp::NumberOrString::Number(_) => None,
9470 lsp::NumberOrString::String(token) => token
9471 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9472 .map(|(_, id)| id.to_owned()),
9473 };
9474 if let Some(LanguageServerState::Running {
9475 workspace_diagnostics_refresh_tasks,
9476 ..
9477 }) = self
9478 .as_local_mut()
9479 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9480 && let Some(workspace_diagnostics) =
9481 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9482 {
9483 workspace_diagnostics.progress_tx.try_send(()).ok();
9484 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9485 }
9486 }
9487 }
9488 }
9489
9490 fn handle_work_done_progress(
9491 &mut self,
9492 progress: lsp::WorkDoneProgress,
9493 language_server_id: LanguageServerId,
9494 disk_based_diagnostics_progress_token: Option<String>,
9495 token: ProgressToken,
9496 cx: &mut Context<Self>,
9497 ) {
9498 let language_server_status =
9499 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9500 status
9501 } else {
9502 return;
9503 };
9504
9505 if !language_server_status.progress_tokens.contains(&token) {
9506 return;
9507 }
9508
9509 let is_disk_based_diagnostics_progress =
9510 if let (Some(disk_based_token), ProgressToken::String(token)) =
9511 (&disk_based_diagnostics_progress_token, &token)
9512 {
9513 token.starts_with(disk_based_token)
9514 } else {
9515 false
9516 };
9517
9518 match progress {
9519 lsp::WorkDoneProgress::Begin(report) => {
9520 if is_disk_based_diagnostics_progress {
9521 self.disk_based_diagnostics_started(language_server_id, cx);
9522 }
9523 self.on_lsp_work_start(
9524 language_server_id,
9525 token.clone(),
9526 LanguageServerProgress {
9527 title: Some(report.title),
9528 is_disk_based_diagnostics_progress,
9529 is_cancellable: report.cancellable.unwrap_or(false),
9530 message: report.message.clone(),
9531 percentage: report.percentage.map(|p| p as usize),
9532 last_update_at: cx.background_executor().now(),
9533 },
9534 cx,
9535 );
9536 }
9537 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9538 language_server_id,
9539 token,
9540 LanguageServerProgress {
9541 title: None,
9542 is_disk_based_diagnostics_progress,
9543 is_cancellable: report.cancellable.unwrap_or(false),
9544 message: report.message,
9545 percentage: report.percentage.map(|p| p as usize),
9546 last_update_at: cx.background_executor().now(),
9547 },
9548 cx,
9549 ),
9550 lsp::WorkDoneProgress::End(_) => {
9551 language_server_status.progress_tokens.remove(&token);
9552 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9553 if is_disk_based_diagnostics_progress {
9554 self.disk_based_diagnostics_finished(language_server_id, cx);
9555 }
9556 }
9557 }
9558 }
9559
9560 fn on_lsp_work_start(
9561 &mut self,
9562 language_server_id: LanguageServerId,
9563 token: ProgressToken,
9564 progress: LanguageServerProgress,
9565 cx: &mut Context<Self>,
9566 ) {
9567 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9568 status.pending_work.insert(token.clone(), progress.clone());
9569 cx.notify();
9570 }
9571 cx.emit(LspStoreEvent::LanguageServerUpdate {
9572 language_server_id,
9573 name: self
9574 .language_server_adapter_for_id(language_server_id)
9575 .map(|adapter| adapter.name()),
9576 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9577 token: Some(token.to_proto()),
9578 title: progress.title,
9579 message: progress.message,
9580 percentage: progress.percentage.map(|p| p as u32),
9581 is_cancellable: Some(progress.is_cancellable),
9582 }),
9583 })
9584 }
9585
9586 fn on_lsp_work_progress(
9587 &mut self,
9588 language_server_id: LanguageServerId,
9589 token: ProgressToken,
9590 progress: LanguageServerProgress,
9591 cx: &mut Context<Self>,
9592 ) {
9593 let mut did_update = false;
9594 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9595 match status.pending_work.entry(token.clone()) {
9596 btree_map::Entry::Vacant(entry) => {
9597 entry.insert(progress.clone());
9598 did_update = true;
9599 }
9600 btree_map::Entry::Occupied(mut entry) => {
9601 let entry = entry.get_mut();
9602 if (progress.last_update_at - entry.last_update_at)
9603 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9604 {
9605 entry.last_update_at = progress.last_update_at;
9606 if progress.message.is_some() {
9607 entry.message = progress.message.clone();
9608 }
9609 if progress.percentage.is_some() {
9610 entry.percentage = progress.percentage;
9611 }
9612 if progress.is_cancellable != entry.is_cancellable {
9613 entry.is_cancellable = progress.is_cancellable;
9614 }
9615 did_update = true;
9616 }
9617 }
9618 }
9619 }
9620
9621 if did_update {
9622 cx.emit(LspStoreEvent::LanguageServerUpdate {
9623 language_server_id,
9624 name: self
9625 .language_server_adapter_for_id(language_server_id)
9626 .map(|adapter| adapter.name()),
9627 message: proto::update_language_server::Variant::WorkProgress(
9628 proto::LspWorkProgress {
9629 token: Some(token.to_proto()),
9630 message: progress.message,
9631 percentage: progress.percentage.map(|p| p as u32),
9632 is_cancellable: Some(progress.is_cancellable),
9633 },
9634 ),
9635 })
9636 }
9637 }
9638
9639 fn on_lsp_work_end(
9640 &mut self,
9641 language_server_id: LanguageServerId,
9642 token: ProgressToken,
9643 cx: &mut Context<Self>,
9644 ) {
9645 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9646 if let Some(work) = status.pending_work.remove(&token)
9647 && !work.is_disk_based_diagnostics_progress
9648 {
9649 cx.emit(LspStoreEvent::RefreshInlayHints {
9650 server_id: language_server_id,
9651 request_id: None,
9652 });
9653 }
9654 cx.notify();
9655 }
9656
9657 cx.emit(LspStoreEvent::LanguageServerUpdate {
9658 language_server_id,
9659 name: self
9660 .language_server_adapter_for_id(language_server_id)
9661 .map(|adapter| adapter.name()),
9662 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9663 token: Some(token.to_proto()),
9664 }),
9665 })
9666 }
9667
9668 pub async fn handle_resolve_completion_documentation(
9669 this: Entity<Self>,
9670 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9671 mut cx: AsyncApp,
9672 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9673 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9674
9675 let completion = this
9676 .read_with(&cx, |this, cx| {
9677 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9678 let server = this
9679 .language_server_for_id(id)
9680 .with_context(|| format!("No language server {id}"))?;
9681
9682 anyhow::Ok(cx.background_spawn(async move {
9683 let can_resolve = server
9684 .capabilities()
9685 .completion_provider
9686 .as_ref()
9687 .and_then(|options| options.resolve_provider)
9688 .unwrap_or(false);
9689 if can_resolve {
9690 server
9691 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9692 .await
9693 .into_response()
9694 .context("resolve completion item")
9695 } else {
9696 anyhow::Ok(lsp_completion)
9697 }
9698 }))
9699 })??
9700 .await?;
9701
9702 let mut documentation_is_markdown = false;
9703 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9704 let documentation = match completion.documentation {
9705 Some(lsp::Documentation::String(text)) => text,
9706
9707 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9708 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9709 value
9710 }
9711
9712 _ => String::new(),
9713 };
9714
9715 // If we have a new buffer_id, that means we're talking to a new client
9716 // and want to check for new text_edits in the completion too.
9717 let mut old_replace_start = None;
9718 let mut old_replace_end = None;
9719 let mut old_insert_start = None;
9720 let mut old_insert_end = None;
9721 let mut new_text = String::default();
9722 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9723 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9724 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9725 anyhow::Ok(buffer.read(cx).snapshot())
9726 })??;
9727
9728 if let Some(text_edit) = completion.text_edit.as_ref() {
9729 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9730
9731 if let Some(mut edit) = edit {
9732 LineEnding::normalize(&mut edit.new_text);
9733
9734 new_text = edit.new_text;
9735 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9736 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9737 if let Some(insert_range) = edit.insert_range {
9738 old_insert_start = Some(serialize_anchor(&insert_range.start));
9739 old_insert_end = Some(serialize_anchor(&insert_range.end));
9740 }
9741 }
9742 }
9743 }
9744
9745 Ok(proto::ResolveCompletionDocumentationResponse {
9746 documentation,
9747 documentation_is_markdown,
9748 old_replace_start,
9749 old_replace_end,
9750 new_text,
9751 lsp_completion,
9752 old_insert_start,
9753 old_insert_end,
9754 })
9755 }
9756
9757 async fn handle_on_type_formatting(
9758 this: Entity<Self>,
9759 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9760 mut cx: AsyncApp,
9761 ) -> Result<proto::OnTypeFormattingResponse> {
9762 let on_type_formatting = this.update(&mut cx, |this, cx| {
9763 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9764 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9765 let position = envelope
9766 .payload
9767 .position
9768 .and_then(deserialize_anchor)
9769 .context("invalid position")?;
9770 anyhow::Ok(this.apply_on_type_formatting(
9771 buffer,
9772 position,
9773 envelope.payload.trigger.clone(),
9774 cx,
9775 ))
9776 })??;
9777
9778 let transaction = on_type_formatting
9779 .await?
9780 .as_ref()
9781 .map(language::proto::serialize_transaction);
9782 Ok(proto::OnTypeFormattingResponse { transaction })
9783 }
9784
9785 async fn handle_refresh_inlay_hints(
9786 lsp_store: Entity<Self>,
9787 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9788 mut cx: AsyncApp,
9789 ) -> Result<proto::Ack> {
9790 lsp_store.update(&mut cx, |_, cx| {
9791 cx.emit(LspStoreEvent::RefreshInlayHints {
9792 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9793 request_id: envelope.payload.request_id.map(|id| id as usize),
9794 });
9795 })?;
9796 Ok(proto::Ack {})
9797 }
9798
9799 async fn handle_pull_workspace_diagnostics(
9800 lsp_store: Entity<Self>,
9801 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9802 mut cx: AsyncApp,
9803 ) -> Result<proto::Ack> {
9804 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9805 lsp_store.update(&mut cx, |lsp_store, _| {
9806 lsp_store.pull_workspace_diagnostics(server_id);
9807 })?;
9808 Ok(proto::Ack {})
9809 }
9810
9811 async fn handle_get_color_presentation(
9812 lsp_store: Entity<Self>,
9813 envelope: TypedEnvelope<proto::GetColorPresentation>,
9814 mut cx: AsyncApp,
9815 ) -> Result<proto::GetColorPresentationResponse> {
9816 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9817 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9818 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9819 })??;
9820
9821 let color = envelope
9822 .payload
9823 .color
9824 .context("invalid color resolve request")?;
9825 let start = color
9826 .lsp_range_start
9827 .context("invalid color resolve request")?;
9828 let end = color
9829 .lsp_range_end
9830 .context("invalid color resolve request")?;
9831
9832 let color = DocumentColor {
9833 lsp_range: lsp::Range {
9834 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9835 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9836 },
9837 color: lsp::Color {
9838 red: color.red,
9839 green: color.green,
9840 blue: color.blue,
9841 alpha: color.alpha,
9842 },
9843 resolved: false,
9844 color_presentations: Vec::new(),
9845 };
9846 let resolved_color = lsp_store
9847 .update(&mut cx, |lsp_store, cx| {
9848 lsp_store.resolve_color_presentation(
9849 color,
9850 buffer.clone(),
9851 LanguageServerId(envelope.payload.server_id as usize),
9852 cx,
9853 )
9854 })?
9855 .await
9856 .context("resolving color presentation")?;
9857
9858 Ok(proto::GetColorPresentationResponse {
9859 presentations: resolved_color
9860 .color_presentations
9861 .into_iter()
9862 .map(|presentation| proto::ColorPresentation {
9863 label: presentation.label.to_string(),
9864 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9865 additional_text_edits: presentation
9866 .additional_text_edits
9867 .into_iter()
9868 .map(serialize_lsp_edit)
9869 .collect(),
9870 })
9871 .collect(),
9872 })
9873 }
9874
9875 async fn handle_resolve_inlay_hint(
9876 lsp_store: Entity<Self>,
9877 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9878 mut cx: AsyncApp,
9879 ) -> Result<proto::ResolveInlayHintResponse> {
9880 let proto_hint = envelope
9881 .payload
9882 .hint
9883 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9884 let hint = InlayHints::proto_to_project_hint(proto_hint)
9885 .context("resolved proto inlay hint conversion")?;
9886 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9887 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9888 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9889 })??;
9890 let response_hint = lsp_store
9891 .update(&mut cx, |lsp_store, cx| {
9892 lsp_store.resolve_inlay_hint(
9893 hint,
9894 buffer,
9895 LanguageServerId(envelope.payload.language_server_id as usize),
9896 cx,
9897 )
9898 })?
9899 .await
9900 .context("inlay hints fetch")?;
9901 Ok(proto::ResolveInlayHintResponse {
9902 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9903 })
9904 }
9905
9906 async fn handle_refresh_code_lens(
9907 this: Entity<Self>,
9908 _: TypedEnvelope<proto::RefreshCodeLens>,
9909 mut cx: AsyncApp,
9910 ) -> Result<proto::Ack> {
9911 this.update(&mut cx, |_, cx| {
9912 cx.emit(LspStoreEvent::RefreshCodeLens);
9913 })?;
9914 Ok(proto::Ack {})
9915 }
9916
9917 async fn handle_open_buffer_for_symbol(
9918 this: Entity<Self>,
9919 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9920 mut cx: AsyncApp,
9921 ) -> Result<proto::OpenBufferForSymbolResponse> {
9922 let peer_id = envelope.original_sender_id().unwrap_or_default();
9923 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9924 let symbol = Self::deserialize_symbol(symbol)?;
9925 this.read_with(&cx, |this, _| {
9926 if let SymbolLocation::OutsideProject {
9927 abs_path,
9928 signature,
9929 } = &symbol.path
9930 {
9931 let new_signature = this.symbol_signature(&abs_path);
9932 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9933 }
9934 Ok(())
9935 })??;
9936 let buffer = this
9937 .update(&mut cx, |this, cx| {
9938 this.open_buffer_for_symbol(
9939 &Symbol {
9940 language_server_name: symbol.language_server_name,
9941 source_worktree_id: symbol.source_worktree_id,
9942 source_language_server_id: symbol.source_language_server_id,
9943 path: symbol.path,
9944 name: symbol.name,
9945 kind: symbol.kind,
9946 range: symbol.range,
9947 label: CodeLabel::default(),
9948 },
9949 cx,
9950 )
9951 })?
9952 .await?;
9953
9954 this.update(&mut cx, |this, cx| {
9955 let is_private = buffer
9956 .read(cx)
9957 .file()
9958 .map(|f| f.is_private())
9959 .unwrap_or_default();
9960 if is_private {
9961 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9962 } else {
9963 this.buffer_store
9964 .update(cx, |buffer_store, cx| {
9965 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9966 })
9967 .detach_and_log_err(cx);
9968 let buffer_id = buffer.read(cx).remote_id().to_proto();
9969 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9970 }
9971 })?
9972 }
9973
9974 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9975 let mut hasher = Sha256::new();
9976 hasher.update(abs_path.to_string_lossy().as_bytes());
9977 hasher.update(self.nonce.to_be_bytes());
9978 hasher.finalize().as_slice().try_into().unwrap()
9979 }
9980
9981 pub async fn handle_get_project_symbols(
9982 this: Entity<Self>,
9983 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9984 mut cx: AsyncApp,
9985 ) -> Result<proto::GetProjectSymbolsResponse> {
9986 let symbols = this
9987 .update(&mut cx, |this, cx| {
9988 this.symbols(&envelope.payload.query, cx)
9989 })?
9990 .await?;
9991
9992 Ok(proto::GetProjectSymbolsResponse {
9993 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9994 })
9995 }
9996
9997 pub async fn handle_restart_language_servers(
9998 this: Entity<Self>,
9999 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10000 mut cx: AsyncApp,
10001 ) -> Result<proto::Ack> {
10002 this.update(&mut cx, |lsp_store, cx| {
10003 let buffers =
10004 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10005 lsp_store.restart_language_servers_for_buffers(
10006 buffers,
10007 envelope
10008 .payload
10009 .only_servers
10010 .into_iter()
10011 .filter_map(|selector| {
10012 Some(match selector.selector? {
10013 proto::language_server_selector::Selector::ServerId(server_id) => {
10014 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10015 }
10016 proto::language_server_selector::Selector::Name(name) => {
10017 LanguageServerSelector::Name(LanguageServerName(
10018 SharedString::from(name),
10019 ))
10020 }
10021 })
10022 })
10023 .collect(),
10024 cx,
10025 );
10026 })?;
10027
10028 Ok(proto::Ack {})
10029 }
10030
10031 pub async fn handle_stop_language_servers(
10032 lsp_store: Entity<Self>,
10033 envelope: TypedEnvelope<proto::StopLanguageServers>,
10034 mut cx: AsyncApp,
10035 ) -> Result<proto::Ack> {
10036 lsp_store.update(&mut cx, |lsp_store, cx| {
10037 if envelope.payload.all
10038 && envelope.payload.also_servers.is_empty()
10039 && envelope.payload.buffer_ids.is_empty()
10040 {
10041 lsp_store.stop_all_language_servers(cx);
10042 } else {
10043 let buffers =
10044 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10045 lsp_store
10046 .stop_language_servers_for_buffers(
10047 buffers,
10048 envelope
10049 .payload
10050 .also_servers
10051 .into_iter()
10052 .filter_map(|selector| {
10053 Some(match selector.selector? {
10054 proto::language_server_selector::Selector::ServerId(
10055 server_id,
10056 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10057 server_id,
10058 )),
10059 proto::language_server_selector::Selector::Name(name) => {
10060 LanguageServerSelector::Name(LanguageServerName(
10061 SharedString::from(name),
10062 ))
10063 }
10064 })
10065 })
10066 .collect(),
10067 cx,
10068 )
10069 .detach_and_log_err(cx);
10070 }
10071 })?;
10072
10073 Ok(proto::Ack {})
10074 }
10075
10076 pub async fn handle_cancel_language_server_work(
10077 lsp_store: Entity<Self>,
10078 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10079 mut cx: AsyncApp,
10080 ) -> Result<proto::Ack> {
10081 lsp_store.update(&mut cx, |lsp_store, cx| {
10082 if let Some(work) = envelope.payload.work {
10083 match work {
10084 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10085 let buffers =
10086 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10087 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10088 }
10089 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10090 let server_id = LanguageServerId::from_proto(work.language_server_id);
10091 let token = work
10092 .token
10093 .map(|token| {
10094 ProgressToken::from_proto(token)
10095 .context("invalid work progress token")
10096 })
10097 .transpose()?;
10098 lsp_store.cancel_language_server_work(server_id, token, cx);
10099 }
10100 }
10101 }
10102 anyhow::Ok(())
10103 })??;
10104
10105 Ok(proto::Ack {})
10106 }
10107
10108 fn buffer_ids_to_buffers(
10109 &mut self,
10110 buffer_ids: impl Iterator<Item = u64>,
10111 cx: &mut Context<Self>,
10112 ) -> Vec<Entity<Buffer>> {
10113 buffer_ids
10114 .into_iter()
10115 .flat_map(|buffer_id| {
10116 self.buffer_store
10117 .read(cx)
10118 .get(BufferId::new(buffer_id).log_err()?)
10119 })
10120 .collect::<Vec<_>>()
10121 }
10122
10123 async fn handle_apply_additional_edits_for_completion(
10124 this: Entity<Self>,
10125 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10126 mut cx: AsyncApp,
10127 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10128 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10129 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10130 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10131 let completion = Self::deserialize_completion(
10132 envelope.payload.completion.context("invalid completion")?,
10133 )?;
10134 anyhow::Ok((buffer, completion))
10135 })??;
10136
10137 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10138 this.apply_additional_edits_for_completion(
10139 buffer,
10140 Rc::new(RefCell::new(Box::new([Completion {
10141 replace_range: completion.replace_range,
10142 new_text: completion.new_text,
10143 source: completion.source,
10144 documentation: None,
10145 label: CodeLabel::default(),
10146 match_start: None,
10147 snippet_deduplication_key: None,
10148 insert_text_mode: None,
10149 icon_path: None,
10150 confirm: None,
10151 }]))),
10152 0,
10153 false,
10154 cx,
10155 )
10156 })?;
10157
10158 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10159 transaction: apply_additional_edits
10160 .await?
10161 .as_ref()
10162 .map(language::proto::serialize_transaction),
10163 })
10164 }
10165
10166 pub fn last_formatting_failure(&self) -> Option<&str> {
10167 self.last_formatting_failure.as_deref()
10168 }
10169
10170 pub fn reset_last_formatting_failure(&mut self) {
10171 self.last_formatting_failure = None;
10172 }
10173
10174 pub fn environment_for_buffer(
10175 &self,
10176 buffer: &Entity<Buffer>,
10177 cx: &mut Context<Self>,
10178 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10179 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10180 environment.update(cx, |env, cx| {
10181 env.buffer_environment(buffer, &self.worktree_store, cx)
10182 })
10183 } else {
10184 Task::ready(None).shared()
10185 }
10186 }
10187
10188 pub fn format(
10189 &mut self,
10190 buffers: HashSet<Entity<Buffer>>,
10191 target: LspFormatTarget,
10192 push_to_history: bool,
10193 trigger: FormatTrigger,
10194 cx: &mut Context<Self>,
10195 ) -> Task<anyhow::Result<ProjectTransaction>> {
10196 let logger = zlog::scoped!("format");
10197 if self.as_local().is_some() {
10198 zlog::trace!(logger => "Formatting locally");
10199 let logger = zlog::scoped!(logger => "local");
10200 let buffers = buffers
10201 .into_iter()
10202 .map(|buffer_handle| {
10203 let buffer = buffer_handle.read(cx);
10204 let buffer_abs_path = File::from_dyn(buffer.file())
10205 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10206
10207 (buffer_handle, buffer_abs_path, buffer.remote_id())
10208 })
10209 .collect::<Vec<_>>();
10210
10211 cx.spawn(async move |lsp_store, cx| {
10212 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10213
10214 for (handle, abs_path, id) in buffers {
10215 let env = lsp_store
10216 .update(cx, |lsp_store, cx| {
10217 lsp_store.environment_for_buffer(&handle, cx)
10218 })?
10219 .await;
10220
10221 let ranges = match &target {
10222 LspFormatTarget::Buffers => None,
10223 LspFormatTarget::Ranges(ranges) => {
10224 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10225 }
10226 };
10227
10228 formattable_buffers.push(FormattableBuffer {
10229 handle,
10230 abs_path,
10231 env,
10232 ranges,
10233 });
10234 }
10235 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10236
10237 let format_timer = zlog::time!(logger => "Formatting buffers");
10238 let result = LocalLspStore::format_locally(
10239 lsp_store.clone(),
10240 formattable_buffers,
10241 push_to_history,
10242 trigger,
10243 logger,
10244 cx,
10245 )
10246 .await;
10247 format_timer.end();
10248
10249 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10250
10251 lsp_store.update(cx, |lsp_store, _| {
10252 lsp_store.update_last_formatting_failure(&result);
10253 })?;
10254
10255 result
10256 })
10257 } else if let Some((client, project_id)) = self.upstream_client() {
10258 zlog::trace!(logger => "Formatting remotely");
10259 let logger = zlog::scoped!(logger => "remote");
10260 // Don't support formatting ranges via remote
10261 match target {
10262 LspFormatTarget::Buffers => {}
10263 LspFormatTarget::Ranges(_) => {
10264 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10265 return Task::ready(Ok(ProjectTransaction::default()));
10266 }
10267 }
10268
10269 let buffer_store = self.buffer_store();
10270 cx.spawn(async move |lsp_store, cx| {
10271 zlog::trace!(logger => "Sending remote format request");
10272 let request_timer = zlog::time!(logger => "remote format request");
10273 let result = client
10274 .request(proto::FormatBuffers {
10275 project_id,
10276 trigger: trigger as i32,
10277 buffer_ids: buffers
10278 .iter()
10279 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10280 .collect::<Result<_>>()?,
10281 })
10282 .await
10283 .and_then(|result| result.transaction.context("missing transaction"));
10284 request_timer.end();
10285
10286 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10287
10288 lsp_store.update(cx, |lsp_store, _| {
10289 lsp_store.update_last_formatting_failure(&result);
10290 })?;
10291
10292 let transaction_response = result?;
10293 let _timer = zlog::time!(logger => "deserializing project transaction");
10294 buffer_store
10295 .update(cx, |buffer_store, cx| {
10296 buffer_store.deserialize_project_transaction(
10297 transaction_response,
10298 push_to_history,
10299 cx,
10300 )
10301 })?
10302 .await
10303 })
10304 } else {
10305 zlog::trace!(logger => "Not formatting");
10306 Task::ready(Ok(ProjectTransaction::default()))
10307 }
10308 }
10309
10310 async fn handle_format_buffers(
10311 this: Entity<Self>,
10312 envelope: TypedEnvelope<proto::FormatBuffers>,
10313 mut cx: AsyncApp,
10314 ) -> Result<proto::FormatBuffersResponse> {
10315 let sender_id = envelope.original_sender_id().unwrap_or_default();
10316 let format = this.update(&mut cx, |this, cx| {
10317 let mut buffers = HashSet::default();
10318 for buffer_id in &envelope.payload.buffer_ids {
10319 let buffer_id = BufferId::new(*buffer_id)?;
10320 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10321 }
10322 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10323 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10324 })??;
10325
10326 let project_transaction = format.await?;
10327 let project_transaction = this.update(&mut cx, |this, cx| {
10328 this.buffer_store.update(cx, |buffer_store, cx| {
10329 buffer_store.serialize_project_transaction_for_peer(
10330 project_transaction,
10331 sender_id,
10332 cx,
10333 )
10334 })
10335 })?;
10336 Ok(proto::FormatBuffersResponse {
10337 transaction: Some(project_transaction),
10338 })
10339 }
10340
10341 async fn handle_apply_code_action_kind(
10342 this: Entity<Self>,
10343 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10344 mut cx: AsyncApp,
10345 ) -> Result<proto::ApplyCodeActionKindResponse> {
10346 let sender_id = envelope.original_sender_id().unwrap_or_default();
10347 let format = this.update(&mut cx, |this, cx| {
10348 let mut buffers = HashSet::default();
10349 for buffer_id in &envelope.payload.buffer_ids {
10350 let buffer_id = BufferId::new(*buffer_id)?;
10351 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10352 }
10353 let kind = match envelope.payload.kind.as_str() {
10354 "" => CodeActionKind::EMPTY,
10355 "quickfix" => CodeActionKind::QUICKFIX,
10356 "refactor" => CodeActionKind::REFACTOR,
10357 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10358 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10359 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10360 "source" => CodeActionKind::SOURCE,
10361 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10362 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10363 _ => anyhow::bail!(
10364 "Invalid code action kind {}",
10365 envelope.payload.kind.as_str()
10366 ),
10367 };
10368 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10369 })??;
10370
10371 let project_transaction = format.await?;
10372 let project_transaction = this.update(&mut cx, |this, cx| {
10373 this.buffer_store.update(cx, |buffer_store, cx| {
10374 buffer_store.serialize_project_transaction_for_peer(
10375 project_transaction,
10376 sender_id,
10377 cx,
10378 )
10379 })
10380 })?;
10381 Ok(proto::ApplyCodeActionKindResponse {
10382 transaction: Some(project_transaction),
10383 })
10384 }
10385
10386 async fn shutdown_language_server(
10387 server_state: Option<LanguageServerState>,
10388 name: LanguageServerName,
10389 cx: &mut AsyncApp,
10390 ) {
10391 let server = match server_state {
10392 Some(LanguageServerState::Starting { startup, .. }) => {
10393 let mut timer = cx
10394 .background_executor()
10395 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10396 .fuse();
10397
10398 select! {
10399 server = startup.fuse() => server,
10400 () = timer => {
10401 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10402 None
10403 },
10404 }
10405 }
10406
10407 Some(LanguageServerState::Running { server, .. }) => Some(server),
10408
10409 None => None,
10410 };
10411
10412 if let Some(server) = server
10413 && let Some(shutdown) = server.shutdown()
10414 {
10415 shutdown.await;
10416 }
10417 }
10418
10419 // Returns a list of all of the worktrees which no longer have a language server and the root path
10420 // for the stopped server
10421 fn stop_local_language_server(
10422 &mut self,
10423 server_id: LanguageServerId,
10424 cx: &mut Context<Self>,
10425 ) -> Task<()> {
10426 let local = match &mut self.mode {
10427 LspStoreMode::Local(local) => local,
10428 _ => {
10429 return Task::ready(());
10430 }
10431 };
10432
10433 // Remove this server ID from all entries in the given worktree.
10434 local
10435 .language_server_ids
10436 .retain(|_, state| state.id != server_id);
10437 self.buffer_store.update(cx, |buffer_store, cx| {
10438 for buffer in buffer_store.buffers() {
10439 buffer.update(cx, |buffer, cx| {
10440 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10441 buffer.set_completion_triggers(server_id, Default::default(), cx);
10442 });
10443 }
10444 });
10445
10446 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10447 summaries.retain(|path, summaries_by_server_id| {
10448 if summaries_by_server_id.remove(&server_id).is_some() {
10449 if let Some((client, project_id)) = self.downstream_client.clone() {
10450 client
10451 .send(proto::UpdateDiagnosticSummary {
10452 project_id,
10453 worktree_id: worktree_id.to_proto(),
10454 summary: Some(proto::DiagnosticSummary {
10455 path: path.as_ref().to_proto(),
10456 language_server_id: server_id.0 as u64,
10457 error_count: 0,
10458 warning_count: 0,
10459 }),
10460 more_summaries: Vec::new(),
10461 })
10462 .log_err();
10463 }
10464 !summaries_by_server_id.is_empty()
10465 } else {
10466 true
10467 }
10468 });
10469 }
10470
10471 let local = self.as_local_mut().unwrap();
10472 for diagnostics in local.diagnostics.values_mut() {
10473 diagnostics.retain(|_, diagnostics_by_server_id| {
10474 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10475 diagnostics_by_server_id.remove(ix);
10476 !diagnostics_by_server_id.is_empty()
10477 } else {
10478 true
10479 }
10480 });
10481 }
10482 local.language_server_watched_paths.remove(&server_id);
10483
10484 let server_state = local.language_servers.remove(&server_id);
10485 self.cleanup_lsp_data(server_id);
10486 let name = self
10487 .language_server_statuses
10488 .remove(&server_id)
10489 .map(|status| status.name)
10490 .or_else(|| {
10491 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10492 Some(adapter.name())
10493 } else {
10494 None
10495 }
10496 });
10497
10498 if let Some(name) = name {
10499 log::info!("stopping language server {name}");
10500 self.languages
10501 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10502 cx.notify();
10503
10504 return cx.spawn(async move |lsp_store, cx| {
10505 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10506 lsp_store
10507 .update(cx, |lsp_store, cx| {
10508 lsp_store
10509 .languages
10510 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10511 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10512 cx.notify();
10513 })
10514 .ok();
10515 });
10516 }
10517
10518 if server_state.is_some() {
10519 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10520 }
10521 Task::ready(())
10522 }
10523
10524 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10525 if let Some((client, project_id)) = self.upstream_client() {
10526 let request = client.request(proto::StopLanguageServers {
10527 project_id,
10528 buffer_ids: Vec::new(),
10529 also_servers: Vec::new(),
10530 all: true,
10531 });
10532 cx.background_spawn(request).detach_and_log_err(cx);
10533 } else {
10534 let Some(local) = self.as_local_mut() else {
10535 return;
10536 };
10537 let language_servers_to_stop = local
10538 .language_server_ids
10539 .values()
10540 .map(|state| state.id)
10541 .collect();
10542 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10543 let tasks = language_servers_to_stop
10544 .into_iter()
10545 .map(|server| self.stop_local_language_server(server, cx))
10546 .collect::<Vec<_>>();
10547 cx.background_spawn(async move {
10548 futures::future::join_all(tasks).await;
10549 })
10550 .detach();
10551 }
10552 }
10553
10554 pub fn restart_language_servers_for_buffers(
10555 &mut self,
10556 buffers: Vec<Entity<Buffer>>,
10557 only_restart_servers: HashSet<LanguageServerSelector>,
10558 cx: &mut Context<Self>,
10559 ) {
10560 if let Some((client, project_id)) = self.upstream_client() {
10561 let request = client.request(proto::RestartLanguageServers {
10562 project_id,
10563 buffer_ids: buffers
10564 .into_iter()
10565 .map(|b| b.read(cx).remote_id().to_proto())
10566 .collect(),
10567 only_servers: only_restart_servers
10568 .into_iter()
10569 .map(|selector| {
10570 let selector = match selector {
10571 LanguageServerSelector::Id(language_server_id) => {
10572 proto::language_server_selector::Selector::ServerId(
10573 language_server_id.to_proto(),
10574 )
10575 }
10576 LanguageServerSelector::Name(language_server_name) => {
10577 proto::language_server_selector::Selector::Name(
10578 language_server_name.to_string(),
10579 )
10580 }
10581 };
10582 proto::LanguageServerSelector {
10583 selector: Some(selector),
10584 }
10585 })
10586 .collect(),
10587 all: false,
10588 });
10589 cx.background_spawn(request).detach_and_log_err(cx);
10590 } else {
10591 let stop_task = if only_restart_servers.is_empty() {
10592 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10593 } else {
10594 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10595 };
10596 cx.spawn(async move |lsp_store, cx| {
10597 stop_task.await;
10598 lsp_store
10599 .update(cx, |lsp_store, cx| {
10600 for buffer in buffers {
10601 lsp_store.register_buffer_with_language_servers(
10602 &buffer,
10603 only_restart_servers.clone(),
10604 true,
10605 cx,
10606 );
10607 }
10608 })
10609 .ok()
10610 })
10611 .detach();
10612 }
10613 }
10614
10615 pub fn stop_language_servers_for_buffers(
10616 &mut self,
10617 buffers: Vec<Entity<Buffer>>,
10618 also_stop_servers: HashSet<LanguageServerSelector>,
10619 cx: &mut Context<Self>,
10620 ) -> Task<Result<()>> {
10621 if let Some((client, project_id)) = self.upstream_client() {
10622 let request = client.request(proto::StopLanguageServers {
10623 project_id,
10624 buffer_ids: buffers
10625 .into_iter()
10626 .map(|b| b.read(cx).remote_id().to_proto())
10627 .collect(),
10628 also_servers: also_stop_servers
10629 .into_iter()
10630 .map(|selector| {
10631 let selector = match selector {
10632 LanguageServerSelector::Id(language_server_id) => {
10633 proto::language_server_selector::Selector::ServerId(
10634 language_server_id.to_proto(),
10635 )
10636 }
10637 LanguageServerSelector::Name(language_server_name) => {
10638 proto::language_server_selector::Selector::Name(
10639 language_server_name.to_string(),
10640 )
10641 }
10642 };
10643 proto::LanguageServerSelector {
10644 selector: Some(selector),
10645 }
10646 })
10647 .collect(),
10648 all: false,
10649 });
10650 cx.background_spawn(async move {
10651 let _ = request.await?;
10652 Ok(())
10653 })
10654 } else {
10655 let task =
10656 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10657 cx.background_spawn(async move {
10658 task.await;
10659 Ok(())
10660 })
10661 }
10662 }
10663
10664 fn stop_local_language_servers_for_buffers(
10665 &mut self,
10666 buffers: &[Entity<Buffer>],
10667 also_stop_servers: HashSet<LanguageServerSelector>,
10668 cx: &mut Context<Self>,
10669 ) -> Task<()> {
10670 let Some(local) = self.as_local_mut() else {
10671 return Task::ready(());
10672 };
10673 let mut language_server_names_to_stop = BTreeSet::default();
10674 let mut language_servers_to_stop = also_stop_servers
10675 .into_iter()
10676 .flat_map(|selector| match selector {
10677 LanguageServerSelector::Id(id) => Some(id),
10678 LanguageServerSelector::Name(name) => {
10679 language_server_names_to_stop.insert(name);
10680 None
10681 }
10682 })
10683 .collect::<BTreeSet<_>>();
10684
10685 let mut covered_worktrees = HashSet::default();
10686 for buffer in buffers {
10687 buffer.update(cx, |buffer, cx| {
10688 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10689 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10690 && covered_worktrees.insert(worktree_id)
10691 {
10692 language_server_names_to_stop.retain(|name| {
10693 let old_ids_count = language_servers_to_stop.len();
10694 let all_language_servers_with_this_name = local
10695 .language_server_ids
10696 .iter()
10697 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10698 language_servers_to_stop.extend(all_language_servers_with_this_name);
10699 old_ids_count == language_servers_to_stop.len()
10700 });
10701 }
10702 });
10703 }
10704 for name in language_server_names_to_stop {
10705 language_servers_to_stop.extend(
10706 local
10707 .language_server_ids
10708 .iter()
10709 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10710 );
10711 }
10712
10713 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10714 let tasks = language_servers_to_stop
10715 .into_iter()
10716 .map(|server| self.stop_local_language_server(server, cx))
10717 .collect::<Vec<_>>();
10718
10719 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10720 }
10721
10722 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10723 let (worktree, relative_path) =
10724 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10725
10726 let project_path = ProjectPath {
10727 worktree_id: worktree.read(cx).id(),
10728 path: relative_path,
10729 };
10730
10731 Some(
10732 self.buffer_store()
10733 .read(cx)
10734 .get_by_path(&project_path)?
10735 .read(cx),
10736 )
10737 }
10738
10739 #[cfg(any(test, feature = "test-support"))]
10740 pub fn update_diagnostics(
10741 &mut self,
10742 server_id: LanguageServerId,
10743 diagnostics: lsp::PublishDiagnosticsParams,
10744 result_id: Option<String>,
10745 source_kind: DiagnosticSourceKind,
10746 disk_based_sources: &[String],
10747 cx: &mut Context<Self>,
10748 ) -> Result<()> {
10749 self.merge_lsp_diagnostics(
10750 source_kind,
10751 vec![DocumentDiagnosticsUpdate {
10752 diagnostics,
10753 result_id,
10754 server_id,
10755 disk_based_sources: Cow::Borrowed(disk_based_sources),
10756 }],
10757 |_, _, _| false,
10758 cx,
10759 )
10760 }
10761
10762 pub fn merge_lsp_diagnostics(
10763 &mut self,
10764 source_kind: DiagnosticSourceKind,
10765 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10766 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10767 cx: &mut Context<Self>,
10768 ) -> Result<()> {
10769 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10770 let updates = lsp_diagnostics
10771 .into_iter()
10772 .filter_map(|update| {
10773 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10774 Some(DocumentDiagnosticsUpdate {
10775 diagnostics: self.lsp_to_document_diagnostics(
10776 abs_path,
10777 source_kind,
10778 update.server_id,
10779 update.diagnostics,
10780 &update.disk_based_sources,
10781 ),
10782 result_id: update.result_id,
10783 server_id: update.server_id,
10784 disk_based_sources: update.disk_based_sources,
10785 })
10786 })
10787 .collect();
10788 self.merge_diagnostic_entries(updates, merge, cx)?;
10789 Ok(())
10790 }
10791
10792 fn lsp_to_document_diagnostics(
10793 &mut self,
10794 document_abs_path: PathBuf,
10795 source_kind: DiagnosticSourceKind,
10796 server_id: LanguageServerId,
10797 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10798 disk_based_sources: &[String],
10799 ) -> DocumentDiagnostics {
10800 let mut diagnostics = Vec::default();
10801 let mut primary_diagnostic_group_ids = HashMap::default();
10802 let mut sources_by_group_id = HashMap::default();
10803 let mut supporting_diagnostics = HashMap::default();
10804
10805 let adapter = self.language_server_adapter_for_id(server_id);
10806
10807 // Ensure that primary diagnostics are always the most severe
10808 lsp_diagnostics
10809 .diagnostics
10810 .sort_by_key(|item| item.severity);
10811
10812 for diagnostic in &lsp_diagnostics.diagnostics {
10813 let source = diagnostic.source.as_ref();
10814 let range = range_from_lsp(diagnostic.range);
10815 let is_supporting = diagnostic
10816 .related_information
10817 .as_ref()
10818 .is_some_and(|infos| {
10819 infos.iter().any(|info| {
10820 primary_diagnostic_group_ids.contains_key(&(
10821 source,
10822 diagnostic.code.clone(),
10823 range_from_lsp(info.location.range),
10824 ))
10825 })
10826 });
10827
10828 let is_unnecessary = diagnostic
10829 .tags
10830 .as_ref()
10831 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10832
10833 let underline = self
10834 .language_server_adapter_for_id(server_id)
10835 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10836
10837 if is_supporting {
10838 supporting_diagnostics.insert(
10839 (source, diagnostic.code.clone(), range),
10840 (diagnostic.severity, is_unnecessary),
10841 );
10842 } else {
10843 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10844 let is_disk_based =
10845 source.is_some_and(|source| disk_based_sources.contains(source));
10846
10847 sources_by_group_id.insert(group_id, source);
10848 primary_diagnostic_group_ids
10849 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10850
10851 diagnostics.push(DiagnosticEntry {
10852 range,
10853 diagnostic: Diagnostic {
10854 source: diagnostic.source.clone(),
10855 source_kind,
10856 code: diagnostic.code.clone(),
10857 code_description: diagnostic
10858 .code_description
10859 .as_ref()
10860 .and_then(|d| d.href.clone()),
10861 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10862 markdown: adapter.as_ref().and_then(|adapter| {
10863 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10864 }),
10865 message: diagnostic.message.trim().to_string(),
10866 group_id,
10867 is_primary: true,
10868 is_disk_based,
10869 is_unnecessary,
10870 underline,
10871 data: diagnostic.data.clone(),
10872 },
10873 });
10874 if let Some(infos) = &diagnostic.related_information {
10875 for info in infos {
10876 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10877 let range = range_from_lsp(info.location.range);
10878 diagnostics.push(DiagnosticEntry {
10879 range,
10880 diagnostic: Diagnostic {
10881 source: diagnostic.source.clone(),
10882 source_kind,
10883 code: diagnostic.code.clone(),
10884 code_description: diagnostic
10885 .code_description
10886 .as_ref()
10887 .and_then(|d| d.href.clone()),
10888 severity: DiagnosticSeverity::INFORMATION,
10889 markdown: adapter.as_ref().and_then(|adapter| {
10890 adapter.diagnostic_message_to_markdown(&info.message)
10891 }),
10892 message: info.message.trim().to_string(),
10893 group_id,
10894 is_primary: false,
10895 is_disk_based,
10896 is_unnecessary: false,
10897 underline,
10898 data: diagnostic.data.clone(),
10899 },
10900 });
10901 }
10902 }
10903 }
10904 }
10905 }
10906
10907 for entry in &mut diagnostics {
10908 let diagnostic = &mut entry.diagnostic;
10909 if !diagnostic.is_primary {
10910 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10911 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10912 source,
10913 diagnostic.code.clone(),
10914 entry.range.clone(),
10915 )) {
10916 if let Some(severity) = severity {
10917 diagnostic.severity = severity;
10918 }
10919 diagnostic.is_unnecessary = is_unnecessary;
10920 }
10921 }
10922 }
10923
10924 DocumentDiagnostics {
10925 diagnostics,
10926 document_abs_path,
10927 version: lsp_diagnostics.version,
10928 }
10929 }
10930
10931 fn insert_newly_running_language_server(
10932 &mut self,
10933 adapter: Arc<CachedLspAdapter>,
10934 language_server: Arc<LanguageServer>,
10935 server_id: LanguageServerId,
10936 key: LanguageServerSeed,
10937 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10938 cx: &mut Context<Self>,
10939 ) {
10940 let Some(local) = self.as_local_mut() else {
10941 return;
10942 };
10943 // If the language server for this key doesn't match the server id, don't store the
10944 // server. Which will cause it to be dropped, killing the process
10945 if local
10946 .language_server_ids
10947 .get(&key)
10948 .map(|state| state.id != server_id)
10949 .unwrap_or(false)
10950 {
10951 return;
10952 }
10953
10954 // Update language_servers collection with Running variant of LanguageServerState
10955 // indicating that the server is up and running and ready
10956 let workspace_folders = workspace_folders.lock().clone();
10957 language_server.set_workspace_folders(workspace_folders);
10958
10959 let workspace_diagnostics_refresh_tasks = language_server
10960 .capabilities()
10961 .diagnostic_provider
10962 .and_then(|provider| {
10963 local
10964 .language_server_dynamic_registrations
10965 .entry(server_id)
10966 .or_default()
10967 .diagnostics
10968 .entry(None)
10969 .or_insert(provider.clone());
10970 let workspace_refresher =
10971 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10972
10973 Some((None, workspace_refresher))
10974 })
10975 .into_iter()
10976 .collect();
10977 local.language_servers.insert(
10978 server_id,
10979 LanguageServerState::Running {
10980 workspace_diagnostics_refresh_tasks,
10981 adapter: adapter.clone(),
10982 server: language_server.clone(),
10983 simulate_disk_based_diagnostics_completion: None,
10984 },
10985 );
10986 local
10987 .languages
10988 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10989 if let Some(file_ops_caps) = language_server
10990 .capabilities()
10991 .workspace
10992 .as_ref()
10993 .and_then(|ws| ws.file_operations.as_ref())
10994 {
10995 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10996 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10997 if did_rename_caps.or(will_rename_caps).is_some() {
10998 let watcher = RenamePathsWatchedForServer::default()
10999 .with_did_rename_patterns(did_rename_caps)
11000 .with_will_rename_patterns(will_rename_caps);
11001 local
11002 .language_server_paths_watched_for_rename
11003 .insert(server_id, watcher);
11004 }
11005 }
11006
11007 self.language_server_statuses.insert(
11008 server_id,
11009 LanguageServerStatus {
11010 name: language_server.name(),
11011 pending_work: Default::default(),
11012 has_pending_diagnostic_updates: false,
11013 progress_tokens: Default::default(),
11014 worktree: Some(key.worktree_id),
11015 },
11016 );
11017
11018 cx.emit(LspStoreEvent::LanguageServerAdded(
11019 server_id,
11020 language_server.name(),
11021 Some(key.worktree_id),
11022 ));
11023
11024 let server_capabilities = language_server.capabilities();
11025 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11026 downstream_client
11027 .send(proto::StartLanguageServer {
11028 project_id: *project_id,
11029 server: Some(proto::LanguageServer {
11030 id: server_id.to_proto(),
11031 name: language_server.name().to_string(),
11032 worktree_id: Some(key.worktree_id.to_proto()),
11033 }),
11034 capabilities: serde_json::to_string(&server_capabilities)
11035 .expect("serializing server LSP capabilities"),
11036 })
11037 .log_err();
11038 }
11039 self.lsp_server_capabilities
11040 .insert(server_id, server_capabilities);
11041
11042 // Tell the language server about every open buffer in the worktree that matches the language.
11043 // Also check for buffers in worktrees that reused this server
11044 let mut worktrees_using_server = vec![key.worktree_id];
11045 if let Some(local) = self.as_local() {
11046 // Find all worktrees that have this server in their language server tree
11047 for (worktree_id, servers) in &local.lsp_tree.instances {
11048 if *worktree_id != key.worktree_id {
11049 for server_map in servers.roots.values() {
11050 if server_map
11051 .values()
11052 .any(|(node, _)| node.id() == Some(server_id))
11053 {
11054 worktrees_using_server.push(*worktree_id);
11055 }
11056 }
11057 }
11058 }
11059 }
11060
11061 let mut buffer_paths_registered = Vec::new();
11062 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11063 let mut lsp_adapters = HashMap::default();
11064 for buffer_handle in buffer_store.buffers() {
11065 let buffer = buffer_handle.read(cx);
11066 let file = match File::from_dyn(buffer.file()) {
11067 Some(file) => file,
11068 None => continue,
11069 };
11070 let language = match buffer.language() {
11071 Some(language) => language,
11072 None => continue,
11073 };
11074
11075 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11076 || !lsp_adapters
11077 .entry(language.name())
11078 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11079 .iter()
11080 .any(|a| a.name == key.name)
11081 {
11082 continue;
11083 }
11084 // didOpen
11085 let file = match file.as_local() {
11086 Some(file) => file,
11087 None => continue,
11088 };
11089
11090 let local = self.as_local_mut().unwrap();
11091
11092 let buffer_id = buffer.remote_id();
11093 if local.registered_buffers.contains_key(&buffer_id) {
11094 let versions = local
11095 .buffer_snapshots
11096 .entry(buffer_id)
11097 .or_default()
11098 .entry(server_id)
11099 .and_modify(|_| {
11100 assert!(
11101 false,
11102 "There should not be an existing snapshot for a newly inserted buffer"
11103 )
11104 })
11105 .or_insert_with(|| {
11106 vec![LspBufferSnapshot {
11107 version: 0,
11108 snapshot: buffer.text_snapshot(),
11109 }]
11110 });
11111
11112 let snapshot = versions.last().unwrap();
11113 let version = snapshot.version;
11114 let initial_snapshot = &snapshot.snapshot;
11115 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11116 language_server.register_buffer(
11117 uri,
11118 adapter.language_id(&language.name()),
11119 version,
11120 initial_snapshot.text(),
11121 );
11122 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11123 local
11124 .buffers_opened_in_servers
11125 .entry(buffer_id)
11126 .or_default()
11127 .insert(server_id);
11128 }
11129 buffer_handle.update(cx, |buffer, cx| {
11130 buffer.set_completion_triggers(
11131 server_id,
11132 language_server
11133 .capabilities()
11134 .completion_provider
11135 .as_ref()
11136 .and_then(|provider| {
11137 provider
11138 .trigger_characters
11139 .as_ref()
11140 .map(|characters| characters.iter().cloned().collect())
11141 })
11142 .unwrap_or_default(),
11143 cx,
11144 )
11145 });
11146 }
11147 });
11148
11149 for (buffer_id, abs_path) in buffer_paths_registered {
11150 cx.emit(LspStoreEvent::LanguageServerUpdate {
11151 language_server_id: server_id,
11152 name: Some(adapter.name()),
11153 message: proto::update_language_server::Variant::RegisteredForBuffer(
11154 proto::RegisteredForBuffer {
11155 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11156 buffer_id: buffer_id.to_proto(),
11157 },
11158 ),
11159 });
11160 }
11161
11162 cx.notify();
11163 }
11164
11165 pub fn language_servers_running_disk_based_diagnostics(
11166 &self,
11167 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11168 self.language_server_statuses
11169 .iter()
11170 .filter_map(|(id, status)| {
11171 if status.has_pending_diagnostic_updates {
11172 Some(*id)
11173 } else {
11174 None
11175 }
11176 })
11177 }
11178
11179 pub(crate) fn cancel_language_server_work_for_buffers(
11180 &mut self,
11181 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11182 cx: &mut Context<Self>,
11183 ) {
11184 if let Some((client, project_id)) = self.upstream_client() {
11185 let request = client.request(proto::CancelLanguageServerWork {
11186 project_id,
11187 work: Some(proto::cancel_language_server_work::Work::Buffers(
11188 proto::cancel_language_server_work::Buffers {
11189 buffer_ids: buffers
11190 .into_iter()
11191 .map(|b| b.read(cx).remote_id().to_proto())
11192 .collect(),
11193 },
11194 )),
11195 });
11196 cx.background_spawn(request).detach_and_log_err(cx);
11197 } else if let Some(local) = self.as_local() {
11198 let servers = buffers
11199 .into_iter()
11200 .flat_map(|buffer| {
11201 buffer.update(cx, |buffer, cx| {
11202 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11203 })
11204 })
11205 .collect::<HashSet<_>>();
11206 for server_id in servers {
11207 self.cancel_language_server_work(server_id, None, cx);
11208 }
11209 }
11210 }
11211
11212 pub(crate) fn cancel_language_server_work(
11213 &mut self,
11214 server_id: LanguageServerId,
11215 token_to_cancel: Option<ProgressToken>,
11216 cx: &mut Context<Self>,
11217 ) {
11218 if let Some(local) = self.as_local() {
11219 let status = self.language_server_statuses.get(&server_id);
11220 let server = local.language_servers.get(&server_id);
11221 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11222 {
11223 for (token, progress) in &status.pending_work {
11224 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11225 && token != token_to_cancel
11226 {
11227 continue;
11228 }
11229 if progress.is_cancellable {
11230 server
11231 .notify::<lsp::notification::WorkDoneProgressCancel>(
11232 WorkDoneProgressCancelParams {
11233 token: token.to_lsp(),
11234 },
11235 )
11236 .ok();
11237 }
11238 }
11239 }
11240 } else if let Some((client, project_id)) = self.upstream_client() {
11241 let request = client.request(proto::CancelLanguageServerWork {
11242 project_id,
11243 work: Some(
11244 proto::cancel_language_server_work::Work::LanguageServerWork(
11245 proto::cancel_language_server_work::LanguageServerWork {
11246 language_server_id: server_id.to_proto(),
11247 token: token_to_cancel.map(|token| token.to_proto()),
11248 },
11249 ),
11250 ),
11251 });
11252 cx.background_spawn(request).detach_and_log_err(cx);
11253 }
11254 }
11255
11256 fn register_supplementary_language_server(
11257 &mut self,
11258 id: LanguageServerId,
11259 name: LanguageServerName,
11260 server: Arc<LanguageServer>,
11261 cx: &mut Context<Self>,
11262 ) {
11263 if let Some(local) = self.as_local_mut() {
11264 local
11265 .supplementary_language_servers
11266 .insert(id, (name.clone(), server));
11267 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11268 }
11269 }
11270
11271 fn unregister_supplementary_language_server(
11272 &mut self,
11273 id: LanguageServerId,
11274 cx: &mut Context<Self>,
11275 ) {
11276 if let Some(local) = self.as_local_mut() {
11277 local.supplementary_language_servers.remove(&id);
11278 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11279 }
11280 }
11281
11282 pub(crate) fn supplementary_language_servers(
11283 &self,
11284 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11285 self.as_local().into_iter().flat_map(|local| {
11286 local
11287 .supplementary_language_servers
11288 .iter()
11289 .map(|(id, (name, _))| (*id, name.clone()))
11290 })
11291 }
11292
11293 pub fn language_server_adapter_for_id(
11294 &self,
11295 id: LanguageServerId,
11296 ) -> Option<Arc<CachedLspAdapter>> {
11297 self.as_local()
11298 .and_then(|local| local.language_servers.get(&id))
11299 .and_then(|language_server_state| match language_server_state {
11300 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11301 _ => None,
11302 })
11303 }
11304
11305 pub(super) fn update_local_worktree_language_servers(
11306 &mut self,
11307 worktree_handle: &Entity<Worktree>,
11308 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11309 cx: &mut Context<Self>,
11310 ) {
11311 if changes.is_empty() {
11312 return;
11313 }
11314
11315 let Some(local) = self.as_local() else { return };
11316
11317 local.prettier_store.update(cx, |prettier_store, cx| {
11318 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11319 });
11320
11321 let worktree_id = worktree_handle.read(cx).id();
11322 let mut language_server_ids = local
11323 .language_server_ids
11324 .iter()
11325 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11326 .collect::<Vec<_>>();
11327 language_server_ids.sort();
11328 language_server_ids.dedup();
11329
11330 // let abs_path = worktree_handle.read(cx).abs_path();
11331 for server_id in &language_server_ids {
11332 if let Some(LanguageServerState::Running { server, .. }) =
11333 local.language_servers.get(server_id)
11334 && let Some(watched_paths) = local
11335 .language_server_watched_paths
11336 .get(server_id)
11337 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11338 {
11339 let params = lsp::DidChangeWatchedFilesParams {
11340 changes: changes
11341 .iter()
11342 .filter_map(|(path, _, change)| {
11343 if !watched_paths.is_match(path.as_std_path()) {
11344 return None;
11345 }
11346 let typ = match change {
11347 PathChange::Loaded => return None,
11348 PathChange::Added => lsp::FileChangeType::CREATED,
11349 PathChange::Removed => lsp::FileChangeType::DELETED,
11350 PathChange::Updated => lsp::FileChangeType::CHANGED,
11351 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11352 };
11353 let uri = lsp::Uri::from_file_path(
11354 worktree_handle.read(cx).absolutize(&path),
11355 )
11356 .ok()?;
11357 Some(lsp::FileEvent { uri, typ })
11358 })
11359 .collect(),
11360 };
11361 if !params.changes.is_empty() {
11362 server
11363 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11364 .ok();
11365 }
11366 }
11367 }
11368 for (path, _, _) in changes {
11369 if let Some(file_name) = path.file_name()
11370 && local.watched_manifest_filenames.contains(file_name)
11371 {
11372 self.request_workspace_config_refresh();
11373 break;
11374 }
11375 }
11376 }
11377
11378 pub fn wait_for_remote_buffer(
11379 &mut self,
11380 id: BufferId,
11381 cx: &mut Context<Self>,
11382 ) -> Task<Result<Entity<Buffer>>> {
11383 self.buffer_store.update(cx, |buffer_store, cx| {
11384 buffer_store.wait_for_remote_buffer(id, cx)
11385 })
11386 }
11387
11388 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11389 let mut result = proto::Symbol {
11390 language_server_name: symbol.language_server_name.0.to_string(),
11391 source_worktree_id: symbol.source_worktree_id.to_proto(),
11392 language_server_id: symbol.source_language_server_id.to_proto(),
11393 name: symbol.name.clone(),
11394 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11395 start: Some(proto::PointUtf16 {
11396 row: symbol.range.start.0.row,
11397 column: symbol.range.start.0.column,
11398 }),
11399 end: Some(proto::PointUtf16 {
11400 row: symbol.range.end.0.row,
11401 column: symbol.range.end.0.column,
11402 }),
11403 worktree_id: Default::default(),
11404 path: Default::default(),
11405 signature: Default::default(),
11406 };
11407 match &symbol.path {
11408 SymbolLocation::InProject(path) => {
11409 result.worktree_id = path.worktree_id.to_proto();
11410 result.path = path.path.to_proto();
11411 }
11412 SymbolLocation::OutsideProject {
11413 abs_path,
11414 signature,
11415 } => {
11416 result.path = abs_path.to_string_lossy().into_owned();
11417 result.signature = signature.to_vec();
11418 }
11419 }
11420 result
11421 }
11422
11423 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11424 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11425 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11426 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11427
11428 let path = if serialized_symbol.signature.is_empty() {
11429 SymbolLocation::InProject(ProjectPath {
11430 worktree_id,
11431 path: RelPath::from_proto(&serialized_symbol.path)
11432 .context("invalid symbol path")?,
11433 })
11434 } else {
11435 SymbolLocation::OutsideProject {
11436 abs_path: Path::new(&serialized_symbol.path).into(),
11437 signature: serialized_symbol
11438 .signature
11439 .try_into()
11440 .map_err(|_| anyhow!("invalid signature"))?,
11441 }
11442 };
11443
11444 let start = serialized_symbol.start.context("invalid start")?;
11445 let end = serialized_symbol.end.context("invalid end")?;
11446 Ok(CoreSymbol {
11447 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11448 source_worktree_id,
11449 source_language_server_id: LanguageServerId::from_proto(
11450 serialized_symbol.language_server_id,
11451 ),
11452 path,
11453 name: serialized_symbol.name,
11454 range: Unclipped(PointUtf16::new(start.row, start.column))
11455 ..Unclipped(PointUtf16::new(end.row, end.column)),
11456 kind,
11457 })
11458 }
11459
11460 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11461 let mut serialized_completion = proto::Completion {
11462 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11463 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11464 new_text: completion.new_text.clone(),
11465 ..proto::Completion::default()
11466 };
11467 match &completion.source {
11468 CompletionSource::Lsp {
11469 insert_range,
11470 server_id,
11471 lsp_completion,
11472 lsp_defaults,
11473 resolved,
11474 } => {
11475 let (old_insert_start, old_insert_end) = insert_range
11476 .as_ref()
11477 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11478 .unzip();
11479
11480 serialized_completion.old_insert_start = old_insert_start;
11481 serialized_completion.old_insert_end = old_insert_end;
11482 serialized_completion.source = proto::completion::Source::Lsp as i32;
11483 serialized_completion.server_id = server_id.0 as u64;
11484 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11485 serialized_completion.lsp_defaults = lsp_defaults
11486 .as_deref()
11487 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11488 serialized_completion.resolved = *resolved;
11489 }
11490 CompletionSource::BufferWord {
11491 word_range,
11492 resolved,
11493 } => {
11494 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11495 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11496 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11497 serialized_completion.resolved = *resolved;
11498 }
11499 CompletionSource::Custom => {
11500 serialized_completion.source = proto::completion::Source::Custom as i32;
11501 serialized_completion.resolved = true;
11502 }
11503 CompletionSource::Dap { sort_text } => {
11504 serialized_completion.source = proto::completion::Source::Dap as i32;
11505 serialized_completion.sort_text = Some(sort_text.clone());
11506 }
11507 }
11508
11509 serialized_completion
11510 }
11511
11512 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11513 let old_replace_start = completion
11514 .old_replace_start
11515 .and_then(deserialize_anchor)
11516 .context("invalid old start")?;
11517 let old_replace_end = completion
11518 .old_replace_end
11519 .and_then(deserialize_anchor)
11520 .context("invalid old end")?;
11521 let insert_range = {
11522 match completion.old_insert_start.zip(completion.old_insert_end) {
11523 Some((start, end)) => {
11524 let start = deserialize_anchor(start).context("invalid insert old start")?;
11525 let end = deserialize_anchor(end).context("invalid insert old end")?;
11526 Some(start..end)
11527 }
11528 None => None,
11529 }
11530 };
11531 Ok(CoreCompletion {
11532 replace_range: old_replace_start..old_replace_end,
11533 new_text: completion.new_text,
11534 source: match proto::completion::Source::from_i32(completion.source) {
11535 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11536 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11537 insert_range,
11538 server_id: LanguageServerId::from_proto(completion.server_id),
11539 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11540 lsp_defaults: completion
11541 .lsp_defaults
11542 .as_deref()
11543 .map(serde_json::from_slice)
11544 .transpose()?,
11545 resolved: completion.resolved,
11546 },
11547 Some(proto::completion::Source::BufferWord) => {
11548 let word_range = completion
11549 .buffer_word_start
11550 .and_then(deserialize_anchor)
11551 .context("invalid buffer word start")?
11552 ..completion
11553 .buffer_word_end
11554 .and_then(deserialize_anchor)
11555 .context("invalid buffer word end")?;
11556 CompletionSource::BufferWord {
11557 word_range,
11558 resolved: completion.resolved,
11559 }
11560 }
11561 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11562 sort_text: completion
11563 .sort_text
11564 .context("expected sort text to exist")?,
11565 },
11566 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11567 },
11568 })
11569 }
11570
11571 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11572 let (kind, lsp_action) = match &action.lsp_action {
11573 LspAction::Action(code_action) => (
11574 proto::code_action::Kind::Action as i32,
11575 serde_json::to_vec(code_action).unwrap(),
11576 ),
11577 LspAction::Command(command) => (
11578 proto::code_action::Kind::Command as i32,
11579 serde_json::to_vec(command).unwrap(),
11580 ),
11581 LspAction::CodeLens(code_lens) => (
11582 proto::code_action::Kind::CodeLens as i32,
11583 serde_json::to_vec(code_lens).unwrap(),
11584 ),
11585 };
11586
11587 proto::CodeAction {
11588 server_id: action.server_id.0 as u64,
11589 start: Some(serialize_anchor(&action.range.start)),
11590 end: Some(serialize_anchor(&action.range.end)),
11591 lsp_action,
11592 kind,
11593 resolved: action.resolved,
11594 }
11595 }
11596
11597 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11598 let start = action
11599 .start
11600 .and_then(deserialize_anchor)
11601 .context("invalid start")?;
11602 let end = action
11603 .end
11604 .and_then(deserialize_anchor)
11605 .context("invalid end")?;
11606 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11607 Some(proto::code_action::Kind::Action) => {
11608 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11609 }
11610 Some(proto::code_action::Kind::Command) => {
11611 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11612 }
11613 Some(proto::code_action::Kind::CodeLens) => {
11614 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11615 }
11616 None => anyhow::bail!("Unknown action kind {}", action.kind),
11617 };
11618 Ok(CodeAction {
11619 server_id: LanguageServerId(action.server_id as usize),
11620 range: start..end,
11621 resolved: action.resolved,
11622 lsp_action,
11623 })
11624 }
11625
11626 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11627 match &formatting_result {
11628 Ok(_) => self.last_formatting_failure = None,
11629 Err(error) => {
11630 let error_string = format!("{error:#}");
11631 log::error!("Formatting failed: {error_string}");
11632 self.last_formatting_failure
11633 .replace(error_string.lines().join(" "));
11634 }
11635 }
11636 }
11637
11638 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11639 self.lsp_server_capabilities.remove(&for_server);
11640 for lsp_data in self.lsp_data.values_mut() {
11641 lsp_data.remove_server_data(for_server);
11642 }
11643 if let Some(local) = self.as_local_mut() {
11644 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11645 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11646 buffer_servers.remove(&for_server);
11647 }
11648 }
11649 }
11650
11651 pub fn result_id(
11652 &self,
11653 server_id: LanguageServerId,
11654 buffer_id: BufferId,
11655 cx: &App,
11656 ) -> Option<String> {
11657 let abs_path = self
11658 .buffer_store
11659 .read(cx)
11660 .get(buffer_id)
11661 .and_then(|b| File::from_dyn(b.read(cx).file()))
11662 .map(|f| f.abs_path(cx))?;
11663 self.as_local()?
11664 .buffer_pull_diagnostics_result_ids
11665 .get(&server_id)?
11666 .get(&abs_path)?
11667 .clone()
11668 }
11669
11670 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11671 let Some(local) = self.as_local() else {
11672 return HashMap::default();
11673 };
11674 local
11675 .buffer_pull_diagnostics_result_ids
11676 .get(&server_id)
11677 .into_iter()
11678 .flatten()
11679 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11680 .collect()
11681 }
11682
11683 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11684 if let Some(LanguageServerState::Running {
11685 workspace_diagnostics_refresh_tasks,
11686 ..
11687 }) = self
11688 .as_local_mut()
11689 .and_then(|local| local.language_servers.get_mut(&server_id))
11690 {
11691 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11692 diagnostics.refresh_tx.try_send(()).ok();
11693 }
11694 }
11695 }
11696
11697 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11698 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11699 return;
11700 };
11701 let Some(local) = self.as_local_mut() else {
11702 return;
11703 };
11704
11705 for server_id in buffer.update(cx, |buffer, cx| {
11706 local.language_server_ids_for_buffer(buffer, cx)
11707 }) {
11708 if let Some(LanguageServerState::Running {
11709 workspace_diagnostics_refresh_tasks,
11710 ..
11711 }) = local.language_servers.get_mut(&server_id)
11712 {
11713 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11714 diagnostics.refresh_tx.try_send(()).ok();
11715 }
11716 }
11717 }
11718 }
11719
11720 fn apply_workspace_diagnostic_report(
11721 &mut self,
11722 server_id: LanguageServerId,
11723 report: lsp::WorkspaceDiagnosticReportResult,
11724 cx: &mut Context<Self>,
11725 ) {
11726 let workspace_diagnostics =
11727 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11728 let mut unchanged_buffers = HashSet::default();
11729 let mut changed_buffers = HashSet::default();
11730 let workspace_diagnostics_updates = workspace_diagnostics
11731 .into_iter()
11732 .filter_map(
11733 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11734 LspPullDiagnostics::Response {
11735 server_id,
11736 uri,
11737 diagnostics,
11738 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11739 LspPullDiagnostics::Default => None,
11740 },
11741 )
11742 .fold(
11743 HashMap::default(),
11744 |mut acc, (server_id, uri, diagnostics, version)| {
11745 let (result_id, diagnostics) = match diagnostics {
11746 PulledDiagnostics::Unchanged { result_id } => {
11747 unchanged_buffers.insert(uri.clone());
11748 (Some(result_id), Vec::new())
11749 }
11750 PulledDiagnostics::Changed {
11751 result_id,
11752 diagnostics,
11753 } => {
11754 changed_buffers.insert(uri.clone());
11755 (result_id, diagnostics)
11756 }
11757 };
11758 let disk_based_sources = Cow::Owned(
11759 self.language_server_adapter_for_id(server_id)
11760 .as_ref()
11761 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11762 .unwrap_or(&[])
11763 .to_vec(),
11764 );
11765 acc.entry(server_id)
11766 .or_insert_with(Vec::new)
11767 .push(DocumentDiagnosticsUpdate {
11768 server_id,
11769 diagnostics: lsp::PublishDiagnosticsParams {
11770 uri,
11771 diagnostics,
11772 version,
11773 },
11774 result_id,
11775 disk_based_sources,
11776 });
11777 acc
11778 },
11779 );
11780
11781 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11782 self.merge_lsp_diagnostics(
11783 DiagnosticSourceKind::Pulled,
11784 diagnostic_updates,
11785 |buffer, old_diagnostic, cx| {
11786 File::from_dyn(buffer.file())
11787 .and_then(|file| {
11788 let abs_path = file.as_local()?.abs_path(cx);
11789 lsp::Uri::from_file_path(abs_path).ok()
11790 })
11791 .is_none_or(|buffer_uri| {
11792 unchanged_buffers.contains(&buffer_uri)
11793 || match old_diagnostic.source_kind {
11794 DiagnosticSourceKind::Pulled => {
11795 !changed_buffers.contains(&buffer_uri)
11796 }
11797 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11798 true
11799 }
11800 }
11801 })
11802 },
11803 cx,
11804 )
11805 .log_err();
11806 }
11807 }
11808
11809 fn register_server_capabilities(
11810 &mut self,
11811 server_id: LanguageServerId,
11812 params: lsp::RegistrationParams,
11813 cx: &mut Context<Self>,
11814 ) -> anyhow::Result<()> {
11815 let server = self
11816 .language_server_for_id(server_id)
11817 .with_context(|| format!("no server {server_id} found"))?;
11818 for reg in params.registrations {
11819 match reg.method.as_str() {
11820 "workspace/didChangeWatchedFiles" => {
11821 if let Some(options) = reg.register_options {
11822 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11823 let caps = serde_json::from_value(options)?;
11824 local_lsp_store
11825 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11826 true
11827 } else {
11828 false
11829 };
11830 if notify {
11831 notify_server_capabilities_updated(&server, cx);
11832 }
11833 }
11834 }
11835 "workspace/didChangeConfiguration" => {
11836 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11837 }
11838 "workspace/didChangeWorkspaceFolders" => {
11839 // In this case register options is an empty object, we can ignore it
11840 let caps = lsp::WorkspaceFoldersServerCapabilities {
11841 supported: Some(true),
11842 change_notifications: Some(OneOf::Right(reg.id)),
11843 };
11844 server.update_capabilities(|capabilities| {
11845 capabilities
11846 .workspace
11847 .get_or_insert_default()
11848 .workspace_folders = Some(caps);
11849 });
11850 notify_server_capabilities_updated(&server, cx);
11851 }
11852 "workspace/symbol" => {
11853 let options = parse_register_capabilities(reg)?;
11854 server.update_capabilities(|capabilities| {
11855 capabilities.workspace_symbol_provider = Some(options);
11856 });
11857 notify_server_capabilities_updated(&server, cx);
11858 }
11859 "workspace/fileOperations" => {
11860 if let Some(options) = reg.register_options {
11861 let caps = serde_json::from_value(options)?;
11862 server.update_capabilities(|capabilities| {
11863 capabilities
11864 .workspace
11865 .get_or_insert_default()
11866 .file_operations = Some(caps);
11867 });
11868 notify_server_capabilities_updated(&server, cx);
11869 }
11870 }
11871 "workspace/executeCommand" => {
11872 if let Some(options) = reg.register_options {
11873 let options = serde_json::from_value(options)?;
11874 server.update_capabilities(|capabilities| {
11875 capabilities.execute_command_provider = Some(options);
11876 });
11877 notify_server_capabilities_updated(&server, cx);
11878 }
11879 }
11880 "textDocument/rangeFormatting" => {
11881 let options = parse_register_capabilities(reg)?;
11882 server.update_capabilities(|capabilities| {
11883 capabilities.document_range_formatting_provider = Some(options);
11884 });
11885 notify_server_capabilities_updated(&server, cx);
11886 }
11887 "textDocument/onTypeFormatting" => {
11888 if let Some(options) = reg
11889 .register_options
11890 .map(serde_json::from_value)
11891 .transpose()?
11892 {
11893 server.update_capabilities(|capabilities| {
11894 capabilities.document_on_type_formatting_provider = Some(options);
11895 });
11896 notify_server_capabilities_updated(&server, cx);
11897 }
11898 }
11899 "textDocument/formatting" => {
11900 let options = parse_register_capabilities(reg)?;
11901 server.update_capabilities(|capabilities| {
11902 capabilities.document_formatting_provider = Some(options);
11903 });
11904 notify_server_capabilities_updated(&server, cx);
11905 }
11906 "textDocument/rename" => {
11907 let options = parse_register_capabilities(reg)?;
11908 server.update_capabilities(|capabilities| {
11909 capabilities.rename_provider = Some(options);
11910 });
11911 notify_server_capabilities_updated(&server, cx);
11912 }
11913 "textDocument/inlayHint" => {
11914 let options = parse_register_capabilities(reg)?;
11915 server.update_capabilities(|capabilities| {
11916 capabilities.inlay_hint_provider = Some(options);
11917 });
11918 notify_server_capabilities_updated(&server, cx);
11919 }
11920 "textDocument/documentSymbol" => {
11921 let options = parse_register_capabilities(reg)?;
11922 server.update_capabilities(|capabilities| {
11923 capabilities.document_symbol_provider = Some(options);
11924 });
11925 notify_server_capabilities_updated(&server, cx);
11926 }
11927 "textDocument/codeAction" => {
11928 let options = parse_register_capabilities(reg)?;
11929 let provider = match options {
11930 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11931 OneOf::Right(caps) => caps,
11932 };
11933 server.update_capabilities(|capabilities| {
11934 capabilities.code_action_provider = Some(provider);
11935 });
11936 notify_server_capabilities_updated(&server, cx);
11937 }
11938 "textDocument/definition" => {
11939 let options = parse_register_capabilities(reg)?;
11940 server.update_capabilities(|capabilities| {
11941 capabilities.definition_provider = Some(options);
11942 });
11943 notify_server_capabilities_updated(&server, cx);
11944 }
11945 "textDocument/completion" => {
11946 if let Some(caps) = reg
11947 .register_options
11948 .map(serde_json::from_value::<CompletionOptions>)
11949 .transpose()?
11950 {
11951 server.update_capabilities(|capabilities| {
11952 capabilities.completion_provider = Some(caps.clone());
11953 });
11954
11955 if let Some(local) = self.as_local() {
11956 let mut buffers_with_language_server = Vec::new();
11957 for handle in self.buffer_store.read(cx).buffers() {
11958 let buffer_id = handle.read(cx).remote_id();
11959 if local
11960 .buffers_opened_in_servers
11961 .get(&buffer_id)
11962 .filter(|s| s.contains(&server_id))
11963 .is_some()
11964 {
11965 buffers_with_language_server.push(handle);
11966 }
11967 }
11968 let triggers = caps
11969 .trigger_characters
11970 .unwrap_or_default()
11971 .into_iter()
11972 .collect::<BTreeSet<_>>();
11973 for handle in buffers_with_language_server {
11974 let triggers = triggers.clone();
11975 let _ = handle.update(cx, move |buffer, cx| {
11976 buffer.set_completion_triggers(server_id, triggers, cx);
11977 });
11978 }
11979 }
11980 notify_server_capabilities_updated(&server, cx);
11981 }
11982 }
11983 "textDocument/hover" => {
11984 let options = parse_register_capabilities(reg)?;
11985 let provider = match options {
11986 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11987 OneOf::Right(caps) => caps,
11988 };
11989 server.update_capabilities(|capabilities| {
11990 capabilities.hover_provider = Some(provider);
11991 });
11992 notify_server_capabilities_updated(&server, cx);
11993 }
11994 "textDocument/signatureHelp" => {
11995 if let Some(caps) = reg
11996 .register_options
11997 .map(serde_json::from_value)
11998 .transpose()?
11999 {
12000 server.update_capabilities(|capabilities| {
12001 capabilities.signature_help_provider = Some(caps);
12002 });
12003 notify_server_capabilities_updated(&server, cx);
12004 }
12005 }
12006 "textDocument/didChange" => {
12007 if let Some(sync_kind) = reg
12008 .register_options
12009 .and_then(|opts| opts.get("syncKind").cloned())
12010 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12011 .transpose()?
12012 {
12013 server.update_capabilities(|capabilities| {
12014 let mut sync_options =
12015 Self::take_text_document_sync_options(capabilities);
12016 sync_options.change = Some(sync_kind);
12017 capabilities.text_document_sync =
12018 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12019 });
12020 notify_server_capabilities_updated(&server, cx);
12021 }
12022 }
12023 "textDocument/didSave" => {
12024 if let Some(include_text) = reg
12025 .register_options
12026 .map(|opts| {
12027 let transpose = opts
12028 .get("includeText")
12029 .cloned()
12030 .map(serde_json::from_value::<Option<bool>>)
12031 .transpose();
12032 match transpose {
12033 Ok(value) => Ok(value.flatten()),
12034 Err(e) => Err(e),
12035 }
12036 })
12037 .transpose()?
12038 {
12039 server.update_capabilities(|capabilities| {
12040 let mut sync_options =
12041 Self::take_text_document_sync_options(capabilities);
12042 sync_options.save =
12043 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12044 include_text,
12045 }));
12046 capabilities.text_document_sync =
12047 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12048 });
12049 notify_server_capabilities_updated(&server, cx);
12050 }
12051 }
12052 "textDocument/codeLens" => {
12053 if let Some(caps) = reg
12054 .register_options
12055 .map(serde_json::from_value)
12056 .transpose()?
12057 {
12058 server.update_capabilities(|capabilities| {
12059 capabilities.code_lens_provider = Some(caps);
12060 });
12061 notify_server_capabilities_updated(&server, cx);
12062 }
12063 }
12064 "textDocument/diagnostic" => {
12065 if let Some(caps) = reg
12066 .register_options
12067 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12068 .transpose()?
12069 {
12070 let local = self
12071 .as_local_mut()
12072 .context("Expected LSP Store to be local")?;
12073 let state = local
12074 .language_servers
12075 .get_mut(&server_id)
12076 .context("Could not obtain Language Servers state")?;
12077 local
12078 .language_server_dynamic_registrations
12079 .entry(server_id)
12080 .or_default()
12081 .diagnostics
12082 .insert(Some(reg.id.clone()), caps.clone());
12083
12084 if let LanguageServerState::Running {
12085 workspace_diagnostics_refresh_tasks,
12086 ..
12087 } = state
12088 && let Some(task) = lsp_workspace_diagnostics_refresh(
12089 Some(reg.id.clone()),
12090 caps.clone(),
12091 server.clone(),
12092 cx,
12093 )
12094 {
12095 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12096 }
12097
12098 let mut did_update_caps = false;
12099 server.update_capabilities(|capabilities| {
12100 if capabilities.diagnostic_provider.as_ref().is_none_or(
12101 |current_caps| {
12102 let supports_workspace_diagnostics =
12103 |capabilities: &DiagnosticServerCapabilities| {
12104 match capabilities {
12105 DiagnosticServerCapabilities::Options(
12106 diagnostic_options,
12107 ) => diagnostic_options.workspace_diagnostics,
12108 DiagnosticServerCapabilities::RegistrationOptions(
12109 diagnostic_registration_options,
12110 ) => {
12111 diagnostic_registration_options
12112 .diagnostic_options
12113 .workspace_diagnostics
12114 }
12115 }
12116 };
12117 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12118 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12119 // as it'll think that they're not supported.
12120 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12121 !supports_workspace_diagnostics(current_caps)
12122 & supports_workspace_diagnostics(&caps)
12123 },
12124 ) {
12125 did_update_caps = true;
12126 capabilities.diagnostic_provider = Some(caps);
12127 }
12128 });
12129 if did_update_caps {
12130 notify_server_capabilities_updated(&server, cx);
12131 }
12132 }
12133 }
12134 "textDocument/documentColor" => {
12135 let options = parse_register_capabilities(reg)?;
12136 let provider = match options {
12137 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12138 OneOf::Right(caps) => caps,
12139 };
12140 server.update_capabilities(|capabilities| {
12141 capabilities.color_provider = Some(provider);
12142 });
12143 notify_server_capabilities_updated(&server, cx);
12144 }
12145 _ => log::warn!("unhandled capability registration: {reg:?}"),
12146 }
12147 }
12148
12149 Ok(())
12150 }
12151
12152 fn unregister_server_capabilities(
12153 &mut self,
12154 server_id: LanguageServerId,
12155 params: lsp::UnregistrationParams,
12156 cx: &mut Context<Self>,
12157 ) -> anyhow::Result<()> {
12158 let server = self
12159 .language_server_for_id(server_id)
12160 .with_context(|| format!("no server {server_id} found"))?;
12161 for unreg in params.unregisterations.iter() {
12162 match unreg.method.as_str() {
12163 "workspace/didChangeWatchedFiles" => {
12164 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12165 local_lsp_store
12166 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12167 true
12168 } else {
12169 false
12170 };
12171 if notify {
12172 notify_server_capabilities_updated(&server, cx);
12173 }
12174 }
12175 "workspace/didChangeConfiguration" => {
12176 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12177 }
12178 "workspace/didChangeWorkspaceFolders" => {
12179 server.update_capabilities(|capabilities| {
12180 capabilities
12181 .workspace
12182 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12183 workspace_folders: None,
12184 file_operations: None,
12185 })
12186 .workspace_folders = None;
12187 });
12188 notify_server_capabilities_updated(&server, cx);
12189 }
12190 "workspace/symbol" => {
12191 server.update_capabilities(|capabilities| {
12192 capabilities.workspace_symbol_provider = None
12193 });
12194 notify_server_capabilities_updated(&server, cx);
12195 }
12196 "workspace/fileOperations" => {
12197 server.update_capabilities(|capabilities| {
12198 capabilities
12199 .workspace
12200 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12201 workspace_folders: None,
12202 file_operations: None,
12203 })
12204 .file_operations = None;
12205 });
12206 notify_server_capabilities_updated(&server, cx);
12207 }
12208 "workspace/executeCommand" => {
12209 server.update_capabilities(|capabilities| {
12210 capabilities.execute_command_provider = None;
12211 });
12212 notify_server_capabilities_updated(&server, cx);
12213 }
12214 "textDocument/rangeFormatting" => {
12215 server.update_capabilities(|capabilities| {
12216 capabilities.document_range_formatting_provider = None
12217 });
12218 notify_server_capabilities_updated(&server, cx);
12219 }
12220 "textDocument/onTypeFormatting" => {
12221 server.update_capabilities(|capabilities| {
12222 capabilities.document_on_type_formatting_provider = None;
12223 });
12224 notify_server_capabilities_updated(&server, cx);
12225 }
12226 "textDocument/formatting" => {
12227 server.update_capabilities(|capabilities| {
12228 capabilities.document_formatting_provider = None;
12229 });
12230 notify_server_capabilities_updated(&server, cx);
12231 }
12232 "textDocument/rename" => {
12233 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12234 notify_server_capabilities_updated(&server, cx);
12235 }
12236 "textDocument/codeAction" => {
12237 server.update_capabilities(|capabilities| {
12238 capabilities.code_action_provider = None;
12239 });
12240 notify_server_capabilities_updated(&server, cx);
12241 }
12242 "textDocument/definition" => {
12243 server.update_capabilities(|capabilities| {
12244 capabilities.definition_provider = None;
12245 });
12246 notify_server_capabilities_updated(&server, cx);
12247 }
12248 "textDocument/completion" => {
12249 server.update_capabilities(|capabilities| {
12250 capabilities.completion_provider = None;
12251 });
12252 notify_server_capabilities_updated(&server, cx);
12253 }
12254 "textDocument/hover" => {
12255 server.update_capabilities(|capabilities| {
12256 capabilities.hover_provider = None;
12257 });
12258 notify_server_capabilities_updated(&server, cx);
12259 }
12260 "textDocument/signatureHelp" => {
12261 server.update_capabilities(|capabilities| {
12262 capabilities.signature_help_provider = None;
12263 });
12264 notify_server_capabilities_updated(&server, cx);
12265 }
12266 "textDocument/didChange" => {
12267 server.update_capabilities(|capabilities| {
12268 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12269 sync_options.change = None;
12270 capabilities.text_document_sync =
12271 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12272 });
12273 notify_server_capabilities_updated(&server, cx);
12274 }
12275 "textDocument/didSave" => {
12276 server.update_capabilities(|capabilities| {
12277 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12278 sync_options.save = None;
12279 capabilities.text_document_sync =
12280 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12281 });
12282 notify_server_capabilities_updated(&server, cx);
12283 }
12284 "textDocument/codeLens" => {
12285 server.update_capabilities(|capabilities| {
12286 capabilities.code_lens_provider = None;
12287 });
12288 notify_server_capabilities_updated(&server, cx);
12289 }
12290 "textDocument/diagnostic" => {
12291 let local = self
12292 .as_local_mut()
12293 .context("Expected LSP Store to be local")?;
12294
12295 let state = local
12296 .language_servers
12297 .get_mut(&server_id)
12298 .context("Could not obtain Language Servers state")?;
12299 let options = local
12300 .language_server_dynamic_registrations
12301 .get_mut(&server_id)
12302 .with_context(|| {
12303 format!("Expected dynamic registration to exist for server {server_id}")
12304 })?.diagnostics
12305 .remove(&Some(unreg.id.clone()))
12306 .with_context(|| format!(
12307 "Attempted to unregister non-existent diagnostic registration with ID {}",
12308 unreg.id)
12309 )?;
12310
12311 let mut has_any_diagnostic_providers_still = true;
12312 if let Some(identifier) = diagnostic_identifier(&options)
12313 && let LanguageServerState::Running {
12314 workspace_diagnostics_refresh_tasks,
12315 ..
12316 } = state
12317 {
12318 workspace_diagnostics_refresh_tasks.remove(&identifier);
12319 has_any_diagnostic_providers_still =
12320 !workspace_diagnostics_refresh_tasks.is_empty();
12321 }
12322
12323 if !has_any_diagnostic_providers_still {
12324 server.update_capabilities(|capabilities| {
12325 debug_assert!(capabilities.diagnostic_provider.is_some());
12326 capabilities.diagnostic_provider = None;
12327 });
12328 }
12329
12330 notify_server_capabilities_updated(&server, cx);
12331 }
12332 "textDocument/documentColor" => {
12333 server.update_capabilities(|capabilities| {
12334 capabilities.color_provider = None;
12335 });
12336 notify_server_capabilities_updated(&server, cx);
12337 }
12338 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12339 }
12340 }
12341
12342 Ok(())
12343 }
12344
12345 async fn deduplicate_range_based_lsp_requests<T>(
12346 lsp_store: &Entity<Self>,
12347 server_id: Option<LanguageServerId>,
12348 lsp_request_id: LspRequestId,
12349 proto_request: &T::ProtoRequest,
12350 range: Range<Anchor>,
12351 cx: &mut AsyncApp,
12352 ) -> Result<()>
12353 where
12354 T: LspCommand,
12355 T::ProtoRequest: proto::LspRequestMessage,
12356 {
12357 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12358 let version = deserialize_version(proto_request.buffer_version());
12359 let buffer = lsp_store.update(cx, |this, cx| {
12360 this.buffer_store.read(cx).get_existing(buffer_id)
12361 })??;
12362 buffer
12363 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12364 .await?;
12365 lsp_store.update(cx, |lsp_store, cx| {
12366 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12367 let chunks_queried_for = lsp_data
12368 .inlay_hints
12369 .applicable_chunks(&[range])
12370 .collect::<Vec<_>>();
12371 match chunks_queried_for.as_slice() {
12372 &[chunk] => {
12373 let key = LspKey {
12374 request_type: TypeId::of::<T>(),
12375 server_queried: server_id,
12376 };
12377 let previous_request = lsp_data
12378 .chunk_lsp_requests
12379 .entry(key)
12380 .or_default()
12381 .insert(chunk, lsp_request_id);
12382 if let Some((previous_request, running_requests)) =
12383 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12384 {
12385 running_requests.remove(&previous_request);
12386 }
12387 }
12388 _ambiguous_chunks => {
12389 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12390 // there, a buffer version-based check will be performed and outdated requests discarded.
12391 }
12392 }
12393 anyhow::Ok(())
12394 })??;
12395
12396 Ok(())
12397 }
12398
12399 async fn query_lsp_locally<T>(
12400 lsp_store: Entity<Self>,
12401 for_server_id: Option<LanguageServerId>,
12402 sender_id: proto::PeerId,
12403 lsp_request_id: LspRequestId,
12404 proto_request: T::ProtoRequest,
12405 position: Option<Anchor>,
12406 cx: &mut AsyncApp,
12407 ) -> Result<()>
12408 where
12409 T: LspCommand + Clone,
12410 T::ProtoRequest: proto::LspRequestMessage,
12411 <T::ProtoRequest as proto::RequestMessage>::Response:
12412 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12413 {
12414 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12415 let version = deserialize_version(proto_request.buffer_version());
12416 let buffer = lsp_store.update(cx, |this, cx| {
12417 this.buffer_store.read(cx).get_existing(buffer_id)
12418 })??;
12419 buffer
12420 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12421 .await?;
12422 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12423 let request =
12424 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12425 let key = LspKey {
12426 request_type: TypeId::of::<T>(),
12427 server_queried: for_server_id,
12428 };
12429 lsp_store.update(cx, |lsp_store, cx| {
12430 let request_task = match for_server_id {
12431 Some(server_id) => {
12432 let server_task = lsp_store.request_lsp(
12433 buffer.clone(),
12434 LanguageServerToQuery::Other(server_id),
12435 request.clone(),
12436 cx,
12437 );
12438 cx.background_spawn(async move {
12439 let mut responses = Vec::new();
12440 match server_task.await {
12441 Ok(response) => responses.push((server_id, response)),
12442 // rust-analyzer likes to error with this when its still loading up
12443 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12444 Err(e) => log::error!(
12445 "Error handling response for request {request:?}: {e:#}"
12446 ),
12447 }
12448 responses
12449 })
12450 }
12451 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12452 };
12453 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12454 if T::ProtoRequest::stop_previous_requests() {
12455 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12456 lsp_requests.clear();
12457 }
12458 }
12459 lsp_data.lsp_requests.entry(key).or_default().insert(
12460 lsp_request_id,
12461 cx.spawn(async move |lsp_store, cx| {
12462 let response = request_task.await;
12463 lsp_store
12464 .update(cx, |lsp_store, cx| {
12465 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12466 {
12467 let response = response
12468 .into_iter()
12469 .map(|(server_id, response)| {
12470 (
12471 server_id.to_proto(),
12472 T::response_to_proto(
12473 response,
12474 lsp_store,
12475 sender_id,
12476 &buffer_version,
12477 cx,
12478 )
12479 .into(),
12480 )
12481 })
12482 .collect::<HashMap<_, _>>();
12483 match client.send_lsp_response::<T::ProtoRequest>(
12484 project_id,
12485 lsp_request_id,
12486 response,
12487 ) {
12488 Ok(()) => {}
12489 Err(e) => {
12490 log::error!("Failed to send LSP response: {e:#}",)
12491 }
12492 }
12493 }
12494 })
12495 .ok();
12496 }),
12497 );
12498 })?;
12499 Ok(())
12500 }
12501
12502 fn take_text_document_sync_options(
12503 capabilities: &mut lsp::ServerCapabilities,
12504 ) -> lsp::TextDocumentSyncOptions {
12505 match capabilities.text_document_sync.take() {
12506 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12507 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12508 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12509 sync_options.change = Some(sync_kind);
12510 sync_options
12511 }
12512 None => lsp::TextDocumentSyncOptions::default(),
12513 }
12514 }
12515
12516 #[cfg(any(test, feature = "test-support"))]
12517 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12518 Some(
12519 self.lsp_data
12520 .get_mut(&buffer_id)?
12521 .code_lens
12522 .take()?
12523 .update
12524 .take()?
12525 .1,
12526 )
12527 }
12528
12529 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12530 self.downstream_client.clone()
12531 }
12532
12533 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12534 self.worktree_store.clone()
12535 }
12536
12537 /// Gets what's stored in the LSP data for the given buffer.
12538 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12539 self.lsp_data.get_mut(&buffer_id)
12540 }
12541
12542 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12543 /// new [`BufferLspData`] will be created to replace the previous state.
12544 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12545 let (buffer_id, buffer_version) =
12546 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12547 let lsp_data = self
12548 .lsp_data
12549 .entry(buffer_id)
12550 .or_insert_with(|| BufferLspData::new(buffer, cx));
12551 if buffer_version.changed_since(&lsp_data.buffer_version) {
12552 *lsp_data = BufferLspData::new(buffer, cx);
12553 }
12554 lsp_data
12555 }
12556}
12557
12558// Registration with registerOptions as null, should fallback to true.
12559// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12560fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12561 reg: lsp::Registration,
12562) -> Result<OneOf<bool, T>> {
12563 Ok(match reg.register_options {
12564 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12565 None => OneOf::Left(true),
12566 })
12567}
12568
12569fn subscribe_to_binary_statuses(
12570 languages: &Arc<LanguageRegistry>,
12571 cx: &mut Context<'_, LspStore>,
12572) -> Task<()> {
12573 let mut server_statuses = languages.language_server_binary_statuses();
12574 cx.spawn(async move |lsp_store, cx| {
12575 while let Some((server_name, binary_status)) = server_statuses.next().await {
12576 if lsp_store
12577 .update(cx, |_, cx| {
12578 let mut message = None;
12579 let binary_status = match binary_status {
12580 BinaryStatus::None => proto::ServerBinaryStatus::None,
12581 BinaryStatus::CheckingForUpdate => {
12582 proto::ServerBinaryStatus::CheckingForUpdate
12583 }
12584 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12585 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12586 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12587 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12588 BinaryStatus::Failed { error } => {
12589 message = Some(error);
12590 proto::ServerBinaryStatus::Failed
12591 }
12592 };
12593 cx.emit(LspStoreEvent::LanguageServerUpdate {
12594 // Binary updates are about the binary that might not have any language server id at that point.
12595 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12596 language_server_id: LanguageServerId(0),
12597 name: Some(server_name),
12598 message: proto::update_language_server::Variant::StatusUpdate(
12599 proto::StatusUpdate {
12600 message,
12601 status: Some(proto::status_update::Status::Binary(
12602 binary_status as i32,
12603 )),
12604 },
12605 ),
12606 });
12607 })
12608 .is_err()
12609 {
12610 break;
12611 }
12612 }
12613 })
12614}
12615
12616fn lsp_workspace_diagnostics_refresh(
12617 registration_id: Option<String>,
12618 options: DiagnosticServerCapabilities,
12619 server: Arc<LanguageServer>,
12620 cx: &mut Context<'_, LspStore>,
12621) -> Option<WorkspaceRefreshTask> {
12622 let identifier = diagnostic_identifier(&options)?;
12623
12624 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12625 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12626 refresh_tx.try_send(()).ok();
12627
12628 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12629 let mut attempts = 0;
12630 let max_attempts = 50;
12631 let mut requests = 0;
12632
12633 loop {
12634 let Some(()) = refresh_rx.recv().await else {
12635 return;
12636 };
12637
12638 'request: loop {
12639 requests += 1;
12640 if attempts > max_attempts {
12641 log::error!(
12642 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12643 );
12644 return;
12645 }
12646 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12647 cx.background_executor()
12648 .timer(Duration::from_millis(backoff_millis))
12649 .await;
12650 attempts += 1;
12651
12652 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12653 lsp_store
12654 .all_result_ids(server.server_id())
12655 .into_iter()
12656 .filter_map(|(abs_path, result_id)| {
12657 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12658 Some(lsp::PreviousResultId {
12659 uri,
12660 value: result_id,
12661 })
12662 })
12663 .collect()
12664 }) else {
12665 return;
12666 };
12667
12668 let token = if let Some(identifier) = ®istration_id {
12669 format!(
12670 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12671 server.server_id(),
12672 )
12673 } else {
12674 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12675 };
12676
12677 progress_rx.try_recv().ok();
12678 let timer =
12679 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12680 let progress = pin!(progress_rx.recv().fuse());
12681 let response_result = server
12682 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12683 lsp::WorkspaceDiagnosticParams {
12684 previous_result_ids,
12685 identifier: identifier.clone(),
12686 work_done_progress_params: Default::default(),
12687 partial_result_params: lsp::PartialResultParams {
12688 partial_result_token: Some(lsp::ProgressToken::String(token)),
12689 },
12690 },
12691 select(timer, progress).then(|either| match either {
12692 Either::Left((message, ..)) => ready(message).left_future(),
12693 Either::Right(..) => pending::<String>().right_future(),
12694 }),
12695 )
12696 .await;
12697
12698 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12699 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12700 match response_result {
12701 ConnectionResult::Timeout => {
12702 log::error!("Timeout during workspace diagnostics pull");
12703 continue 'request;
12704 }
12705 ConnectionResult::ConnectionReset => {
12706 log::error!("Server closed a workspace diagnostics pull request");
12707 continue 'request;
12708 }
12709 ConnectionResult::Result(Err(e)) => {
12710 log::error!("Error during workspace diagnostics pull: {e:#}");
12711 break 'request;
12712 }
12713 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12714 attempts = 0;
12715 if lsp_store
12716 .update(cx, |lsp_store, cx| {
12717 lsp_store.apply_workspace_diagnostic_report(
12718 server.server_id(),
12719 pulled_diagnostics,
12720 cx,
12721 )
12722 })
12723 .is_err()
12724 {
12725 return;
12726 }
12727 break 'request;
12728 }
12729 }
12730 }
12731 }
12732 });
12733
12734 Some(WorkspaceRefreshTask {
12735 refresh_tx,
12736 progress_tx,
12737 task: workspace_query_language_server,
12738 })
12739}
12740
12741fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12742 match &options {
12743 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12744 if !diagnostic_options.workspace_diagnostics {
12745 return None;
12746 }
12747 Some(diagnostic_options.identifier.clone())
12748 }
12749 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12750 let diagnostic_options = ®istration_options.diagnostic_options;
12751 if !diagnostic_options.workspace_diagnostics {
12752 return None;
12753 }
12754 Some(diagnostic_options.identifier.clone())
12755 }
12756 }
12757}
12758
12759fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12760 let CompletionSource::BufferWord {
12761 word_range,
12762 resolved,
12763 } = &mut completion.source
12764 else {
12765 return;
12766 };
12767 if *resolved {
12768 return;
12769 }
12770
12771 if completion.new_text
12772 != snapshot
12773 .text_for_range(word_range.clone())
12774 .collect::<String>()
12775 {
12776 return;
12777 }
12778
12779 let mut offset = 0;
12780 for chunk in snapshot.chunks(word_range.clone(), true) {
12781 let end_offset = offset + chunk.text.len();
12782 if let Some(highlight_id) = chunk.syntax_highlight_id {
12783 completion
12784 .label
12785 .runs
12786 .push((offset..end_offset, highlight_id));
12787 }
12788 offset = end_offset;
12789 }
12790 *resolved = true;
12791}
12792
12793impl EventEmitter<LspStoreEvent> for LspStore {}
12794
12795fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12796 hover
12797 .contents
12798 .retain(|hover_block| !hover_block.text.trim().is_empty());
12799 if hover.contents.is_empty() {
12800 None
12801 } else {
12802 Some(hover)
12803 }
12804}
12805
12806async fn populate_labels_for_completions(
12807 new_completions: Vec<CoreCompletion>,
12808 language: Option<Arc<Language>>,
12809 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12810) -> Vec<Completion> {
12811 let lsp_completions = new_completions
12812 .iter()
12813 .filter_map(|new_completion| {
12814 new_completion
12815 .source
12816 .lsp_completion(true)
12817 .map(|lsp_completion| lsp_completion.into_owned())
12818 })
12819 .collect::<Vec<_>>();
12820
12821 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12822 lsp_adapter
12823 .labels_for_completions(&lsp_completions, language)
12824 .await
12825 .log_err()
12826 .unwrap_or_default()
12827 } else {
12828 Vec::new()
12829 }
12830 .into_iter()
12831 .fuse();
12832
12833 let mut completions = Vec::new();
12834 for completion in new_completions {
12835 match completion.source.lsp_completion(true) {
12836 Some(lsp_completion) => {
12837 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12838
12839 let mut label = labels.next().flatten().unwrap_or_else(|| {
12840 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12841 });
12842 ensure_uniform_list_compatible_label(&mut label);
12843 completions.push(Completion {
12844 label,
12845 documentation,
12846 replace_range: completion.replace_range,
12847 new_text: completion.new_text,
12848 insert_text_mode: lsp_completion.insert_text_mode,
12849 source: completion.source,
12850 icon_path: None,
12851 confirm: None,
12852 match_start: None,
12853 snippet_deduplication_key: None,
12854 });
12855 }
12856 None => {
12857 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12858 ensure_uniform_list_compatible_label(&mut label);
12859 completions.push(Completion {
12860 label,
12861 documentation: None,
12862 replace_range: completion.replace_range,
12863 new_text: completion.new_text,
12864 source: completion.source,
12865 insert_text_mode: None,
12866 icon_path: None,
12867 confirm: None,
12868 match_start: None,
12869 snippet_deduplication_key: None,
12870 });
12871 }
12872 }
12873 }
12874 completions
12875}
12876
12877#[derive(Debug)]
12878pub enum LanguageServerToQuery {
12879 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12880 FirstCapable,
12881 /// Query a specific language server.
12882 Other(LanguageServerId),
12883}
12884
12885#[derive(Default)]
12886struct RenamePathsWatchedForServer {
12887 did_rename: Vec<RenameActionPredicate>,
12888 will_rename: Vec<RenameActionPredicate>,
12889}
12890
12891impl RenamePathsWatchedForServer {
12892 fn with_did_rename_patterns(
12893 mut self,
12894 did_rename: Option<&FileOperationRegistrationOptions>,
12895 ) -> Self {
12896 if let Some(did_rename) = did_rename {
12897 self.did_rename = did_rename
12898 .filters
12899 .iter()
12900 .filter_map(|filter| filter.try_into().log_err())
12901 .collect();
12902 }
12903 self
12904 }
12905 fn with_will_rename_patterns(
12906 mut self,
12907 will_rename: Option<&FileOperationRegistrationOptions>,
12908 ) -> Self {
12909 if let Some(will_rename) = will_rename {
12910 self.will_rename = will_rename
12911 .filters
12912 .iter()
12913 .filter_map(|filter| filter.try_into().log_err())
12914 .collect();
12915 }
12916 self
12917 }
12918
12919 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12920 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12921 }
12922 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12923 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12924 }
12925}
12926
12927impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12928 type Error = globset::Error;
12929 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12930 Ok(Self {
12931 kind: ops.pattern.matches.clone(),
12932 glob: GlobBuilder::new(&ops.pattern.glob)
12933 .case_insensitive(
12934 ops.pattern
12935 .options
12936 .as_ref()
12937 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12938 )
12939 .build()?
12940 .compile_matcher(),
12941 })
12942 }
12943}
12944struct RenameActionPredicate {
12945 glob: GlobMatcher,
12946 kind: Option<FileOperationPatternKind>,
12947}
12948
12949impl RenameActionPredicate {
12950 // Returns true if language server should be notified
12951 fn eval(&self, path: &str, is_dir: bool) -> bool {
12952 self.kind.as_ref().is_none_or(|kind| {
12953 let expected_kind = if is_dir {
12954 FileOperationPatternKind::Folder
12955 } else {
12956 FileOperationPatternKind::File
12957 };
12958 kind == &expected_kind
12959 }) && self.glob.is_match(path)
12960 }
12961}
12962
12963#[derive(Default)]
12964struct LanguageServerWatchedPaths {
12965 worktree_paths: HashMap<WorktreeId, GlobSet>,
12966 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12967}
12968
12969#[derive(Default)]
12970struct LanguageServerWatchedPathsBuilder {
12971 worktree_paths: HashMap<WorktreeId, GlobSet>,
12972 abs_paths: HashMap<Arc<Path>, GlobSet>,
12973}
12974
12975impl LanguageServerWatchedPathsBuilder {
12976 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12977 self.worktree_paths.insert(worktree_id, glob_set);
12978 }
12979 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12980 self.abs_paths.insert(path, glob_set);
12981 }
12982 fn build(
12983 self,
12984 fs: Arc<dyn Fs>,
12985 language_server_id: LanguageServerId,
12986 cx: &mut Context<LspStore>,
12987 ) -> LanguageServerWatchedPaths {
12988 let lsp_store = cx.weak_entity();
12989
12990 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12991 let abs_paths = self
12992 .abs_paths
12993 .into_iter()
12994 .map(|(abs_path, globset)| {
12995 let task = cx.spawn({
12996 let abs_path = abs_path.clone();
12997 let fs = fs.clone();
12998
12999 let lsp_store = lsp_store.clone();
13000 async move |_, cx| {
13001 maybe!(async move {
13002 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13003 while let Some(update) = push_updates.0.next().await {
13004 let action = lsp_store
13005 .update(cx, |this, _| {
13006 let Some(local) = this.as_local() else {
13007 return ControlFlow::Break(());
13008 };
13009 let Some(watcher) = local
13010 .language_server_watched_paths
13011 .get(&language_server_id)
13012 else {
13013 return ControlFlow::Break(());
13014 };
13015 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13016 "Watched abs path is not registered with a watcher",
13017 );
13018 let matching_entries = update
13019 .into_iter()
13020 .filter(|event| globs.is_match(&event.path))
13021 .collect::<Vec<_>>();
13022 this.lsp_notify_abs_paths_changed(
13023 language_server_id,
13024 matching_entries,
13025 );
13026 ControlFlow::Continue(())
13027 })
13028 .ok()?;
13029
13030 if action.is_break() {
13031 break;
13032 }
13033 }
13034 Some(())
13035 })
13036 .await;
13037 }
13038 });
13039 (abs_path, (globset, task))
13040 })
13041 .collect();
13042 LanguageServerWatchedPaths {
13043 worktree_paths: self.worktree_paths,
13044 abs_paths,
13045 }
13046 }
13047}
13048
13049struct LspBufferSnapshot {
13050 version: i32,
13051 snapshot: TextBufferSnapshot,
13052}
13053
13054/// A prompt requested by LSP server.
13055#[derive(Clone, Debug)]
13056pub struct LanguageServerPromptRequest {
13057 pub level: PromptLevel,
13058 pub message: String,
13059 pub actions: Vec<MessageActionItem>,
13060 pub lsp_name: String,
13061 pub(crate) response_channel: Sender<MessageActionItem>,
13062}
13063
13064impl LanguageServerPromptRequest {
13065 pub async fn respond(self, index: usize) -> Option<()> {
13066 if let Some(response) = self.actions.into_iter().nth(index) {
13067 self.response_channel.send(response).await.ok()
13068 } else {
13069 None
13070 }
13071 }
13072}
13073impl PartialEq for LanguageServerPromptRequest {
13074 fn eq(&self, other: &Self) -> bool {
13075 self.message == other.message && self.actions == other.actions
13076 }
13077}
13078
13079#[derive(Clone, Debug, PartialEq)]
13080pub enum LanguageServerLogType {
13081 Log(MessageType),
13082 Trace { verbose_info: Option<String> },
13083 Rpc { received: bool },
13084}
13085
13086impl LanguageServerLogType {
13087 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13088 match self {
13089 Self::Log(log_type) => {
13090 use proto::log_message::LogLevel;
13091 let level = match *log_type {
13092 MessageType::ERROR => LogLevel::Error,
13093 MessageType::WARNING => LogLevel::Warning,
13094 MessageType::INFO => LogLevel::Info,
13095 MessageType::LOG => LogLevel::Log,
13096 other => {
13097 log::warn!("Unknown lsp log message type: {other:?}");
13098 LogLevel::Log
13099 }
13100 };
13101 proto::language_server_log::LogType::Log(proto::LogMessage {
13102 level: level as i32,
13103 })
13104 }
13105 Self::Trace { verbose_info } => {
13106 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13107 verbose_info: verbose_info.to_owned(),
13108 })
13109 }
13110 Self::Rpc { received } => {
13111 let kind = if *received {
13112 proto::rpc_message::Kind::Received
13113 } else {
13114 proto::rpc_message::Kind::Sent
13115 };
13116 let kind = kind as i32;
13117 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13118 }
13119 }
13120 }
13121
13122 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13123 use proto::log_message::LogLevel;
13124 use proto::rpc_message;
13125 match log_type {
13126 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13127 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13128 LogLevel::Error => MessageType::ERROR,
13129 LogLevel::Warning => MessageType::WARNING,
13130 LogLevel::Info => MessageType::INFO,
13131 LogLevel::Log => MessageType::LOG,
13132 },
13133 ),
13134 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13135 verbose_info: trace_message.verbose_info,
13136 },
13137 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13138 received: match rpc_message::Kind::from_i32(message.kind)
13139 .unwrap_or(rpc_message::Kind::Received)
13140 {
13141 rpc_message::Kind::Received => true,
13142 rpc_message::Kind::Sent => false,
13143 },
13144 },
13145 }
13146 }
13147}
13148
13149pub struct WorkspaceRefreshTask {
13150 refresh_tx: mpsc::Sender<()>,
13151 progress_tx: mpsc::Sender<()>,
13152 #[allow(dead_code)]
13153 task: Task<()>,
13154}
13155
13156pub enum LanguageServerState {
13157 Starting {
13158 startup: Task<Option<Arc<LanguageServer>>>,
13159 /// List of language servers that will be added to the workspace once it's initialization completes.
13160 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13161 },
13162
13163 Running {
13164 adapter: Arc<CachedLspAdapter>,
13165 server: Arc<LanguageServer>,
13166 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13167 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13168 },
13169}
13170
13171impl LanguageServerState {
13172 fn add_workspace_folder(&self, uri: Uri) {
13173 match self {
13174 LanguageServerState::Starting {
13175 pending_workspace_folders,
13176 ..
13177 } => {
13178 pending_workspace_folders.lock().insert(uri);
13179 }
13180 LanguageServerState::Running { server, .. } => {
13181 server.add_workspace_folder(uri);
13182 }
13183 }
13184 }
13185 fn _remove_workspace_folder(&self, uri: Uri) {
13186 match self {
13187 LanguageServerState::Starting {
13188 pending_workspace_folders,
13189 ..
13190 } => {
13191 pending_workspace_folders.lock().remove(&uri);
13192 }
13193 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13194 }
13195 }
13196}
13197
13198impl std::fmt::Debug for LanguageServerState {
13199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13200 match self {
13201 LanguageServerState::Starting { .. } => {
13202 f.debug_struct("LanguageServerState::Starting").finish()
13203 }
13204 LanguageServerState::Running { .. } => {
13205 f.debug_struct("LanguageServerState::Running").finish()
13206 }
13207 }
13208 }
13209}
13210
13211#[derive(Clone, Debug, Serialize)]
13212pub struct LanguageServerProgress {
13213 pub is_disk_based_diagnostics_progress: bool,
13214 pub is_cancellable: bool,
13215 pub title: Option<String>,
13216 pub message: Option<String>,
13217 pub percentage: Option<usize>,
13218 #[serde(skip_serializing)]
13219 pub last_update_at: Instant,
13220}
13221
13222#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13223pub struct DiagnosticSummary {
13224 pub error_count: usize,
13225 pub warning_count: usize,
13226}
13227
13228impl DiagnosticSummary {
13229 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13230 let mut this = Self {
13231 error_count: 0,
13232 warning_count: 0,
13233 };
13234
13235 for entry in diagnostics {
13236 if entry.diagnostic.is_primary {
13237 match entry.diagnostic.severity {
13238 DiagnosticSeverity::ERROR => this.error_count += 1,
13239 DiagnosticSeverity::WARNING => this.warning_count += 1,
13240 _ => {}
13241 }
13242 }
13243 }
13244
13245 this
13246 }
13247
13248 pub fn is_empty(&self) -> bool {
13249 self.error_count == 0 && self.warning_count == 0
13250 }
13251
13252 pub fn to_proto(
13253 self,
13254 language_server_id: LanguageServerId,
13255 path: &RelPath,
13256 ) -> proto::DiagnosticSummary {
13257 proto::DiagnosticSummary {
13258 path: path.to_proto(),
13259 language_server_id: language_server_id.0 as u64,
13260 error_count: self.error_count as u32,
13261 warning_count: self.warning_count as u32,
13262 }
13263 }
13264}
13265
13266#[derive(Clone, Debug)]
13267pub enum CompletionDocumentation {
13268 /// There is no documentation for this completion.
13269 Undocumented,
13270 /// A single line of documentation.
13271 SingleLine(SharedString),
13272 /// Multiple lines of plain text documentation.
13273 MultiLinePlainText(SharedString),
13274 /// Markdown documentation.
13275 MultiLineMarkdown(SharedString),
13276 /// Both single line and multiple lines of plain text documentation.
13277 SingleLineAndMultiLinePlainText {
13278 single_line: SharedString,
13279 plain_text: Option<SharedString>,
13280 },
13281}
13282
13283impl CompletionDocumentation {
13284 #[cfg(any(test, feature = "test-support"))]
13285 pub fn text(&self) -> SharedString {
13286 match self {
13287 CompletionDocumentation::Undocumented => "".into(),
13288 CompletionDocumentation::SingleLine(s) => s.clone(),
13289 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13290 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13291 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13292 single_line.clone()
13293 }
13294 }
13295 }
13296}
13297
13298impl From<lsp::Documentation> for CompletionDocumentation {
13299 fn from(docs: lsp::Documentation) -> Self {
13300 match docs {
13301 lsp::Documentation::String(text) => {
13302 if text.lines().count() <= 1 {
13303 CompletionDocumentation::SingleLine(text.into())
13304 } else {
13305 CompletionDocumentation::MultiLinePlainText(text.into())
13306 }
13307 }
13308
13309 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13310 lsp::MarkupKind::PlainText => {
13311 if value.lines().count() <= 1 {
13312 CompletionDocumentation::SingleLine(value.into())
13313 } else {
13314 CompletionDocumentation::MultiLinePlainText(value.into())
13315 }
13316 }
13317
13318 lsp::MarkupKind::Markdown => {
13319 CompletionDocumentation::MultiLineMarkdown(value.into())
13320 }
13321 },
13322 }
13323 }
13324}
13325
13326pub enum ResolvedHint {
13327 Resolved(InlayHint),
13328 Resolving(Shared<Task<()>>),
13329}
13330
13331fn glob_literal_prefix(glob: &Path) -> PathBuf {
13332 glob.components()
13333 .take_while(|component| match component {
13334 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13335 _ => true,
13336 })
13337 .collect()
13338}
13339
13340pub struct SshLspAdapter {
13341 name: LanguageServerName,
13342 binary: LanguageServerBinary,
13343 initialization_options: Option<String>,
13344 code_action_kinds: Option<Vec<CodeActionKind>>,
13345}
13346
13347impl SshLspAdapter {
13348 pub fn new(
13349 name: LanguageServerName,
13350 binary: LanguageServerBinary,
13351 initialization_options: Option<String>,
13352 code_action_kinds: Option<String>,
13353 ) -> Self {
13354 Self {
13355 name,
13356 binary,
13357 initialization_options,
13358 code_action_kinds: code_action_kinds
13359 .as_ref()
13360 .and_then(|c| serde_json::from_str(c).ok()),
13361 }
13362 }
13363}
13364
13365impl LspInstaller for SshLspAdapter {
13366 type BinaryVersion = ();
13367 async fn check_if_user_installed(
13368 &self,
13369 _: &dyn LspAdapterDelegate,
13370 _: Option<Toolchain>,
13371 _: &AsyncApp,
13372 ) -> Option<LanguageServerBinary> {
13373 Some(self.binary.clone())
13374 }
13375
13376 async fn cached_server_binary(
13377 &self,
13378 _: PathBuf,
13379 _: &dyn LspAdapterDelegate,
13380 ) -> Option<LanguageServerBinary> {
13381 None
13382 }
13383
13384 async fn fetch_latest_server_version(
13385 &self,
13386 _: &dyn LspAdapterDelegate,
13387 _: bool,
13388 _: &mut AsyncApp,
13389 ) -> Result<()> {
13390 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13391 }
13392
13393 async fn fetch_server_binary(
13394 &self,
13395 _: (),
13396 _: PathBuf,
13397 _: &dyn LspAdapterDelegate,
13398 ) -> Result<LanguageServerBinary> {
13399 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13400 }
13401}
13402
13403#[async_trait(?Send)]
13404impl LspAdapter for SshLspAdapter {
13405 fn name(&self) -> LanguageServerName {
13406 self.name.clone()
13407 }
13408
13409 async fn initialization_options(
13410 self: Arc<Self>,
13411 _: &Arc<dyn LspAdapterDelegate>,
13412 ) -> Result<Option<serde_json::Value>> {
13413 let Some(options) = &self.initialization_options else {
13414 return Ok(None);
13415 };
13416 let result = serde_json::from_str(options)?;
13417 Ok(result)
13418 }
13419
13420 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13421 self.code_action_kinds.clone()
13422 }
13423}
13424
13425pub fn language_server_settings<'a>(
13426 delegate: &'a dyn LspAdapterDelegate,
13427 language: &LanguageServerName,
13428 cx: &'a App,
13429) -> Option<&'a LspSettings> {
13430 language_server_settings_for(
13431 SettingsLocation {
13432 worktree_id: delegate.worktree_id(),
13433 path: RelPath::empty(),
13434 },
13435 language,
13436 cx,
13437 )
13438}
13439
13440pub(crate) fn language_server_settings_for<'a>(
13441 location: SettingsLocation<'a>,
13442 language: &LanguageServerName,
13443 cx: &'a App,
13444) -> Option<&'a LspSettings> {
13445 ProjectSettings::get(Some(location), cx).lsp.get(language)
13446}
13447
13448pub struct LocalLspAdapterDelegate {
13449 lsp_store: WeakEntity<LspStore>,
13450 worktree: worktree::Snapshot,
13451 fs: Arc<dyn Fs>,
13452 http_client: Arc<dyn HttpClient>,
13453 language_registry: Arc<LanguageRegistry>,
13454 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13455}
13456
13457impl LocalLspAdapterDelegate {
13458 pub fn new(
13459 language_registry: Arc<LanguageRegistry>,
13460 environment: &Entity<ProjectEnvironment>,
13461 lsp_store: WeakEntity<LspStore>,
13462 worktree: &Entity<Worktree>,
13463 http_client: Arc<dyn HttpClient>,
13464 fs: Arc<dyn Fs>,
13465 cx: &mut App,
13466 ) -> Arc<Self> {
13467 let load_shell_env_task =
13468 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13469
13470 Arc::new(Self {
13471 lsp_store,
13472 worktree: worktree.read(cx).snapshot(),
13473 fs,
13474 http_client,
13475 language_registry,
13476 load_shell_env_task,
13477 })
13478 }
13479
13480 fn from_local_lsp(
13481 local: &LocalLspStore,
13482 worktree: &Entity<Worktree>,
13483 cx: &mut App,
13484 ) -> Arc<Self> {
13485 Self::new(
13486 local.languages.clone(),
13487 &local.environment,
13488 local.weak.clone(),
13489 worktree,
13490 local.http_client.clone(),
13491 local.fs.clone(),
13492 cx,
13493 )
13494 }
13495}
13496
13497#[async_trait]
13498impl LspAdapterDelegate for LocalLspAdapterDelegate {
13499 fn show_notification(&self, message: &str, cx: &mut App) {
13500 self.lsp_store
13501 .update(cx, |_, cx| {
13502 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13503 })
13504 .ok();
13505 }
13506
13507 fn http_client(&self) -> Arc<dyn HttpClient> {
13508 self.http_client.clone()
13509 }
13510
13511 fn worktree_id(&self) -> WorktreeId {
13512 self.worktree.id()
13513 }
13514
13515 fn worktree_root_path(&self) -> &Path {
13516 self.worktree.abs_path().as_ref()
13517 }
13518
13519 async fn shell_env(&self) -> HashMap<String, String> {
13520 let task = self.load_shell_env_task.clone();
13521 task.await.unwrap_or_default()
13522 }
13523
13524 async fn npm_package_installed_version(
13525 &self,
13526 package_name: &str,
13527 ) -> Result<Option<(PathBuf, String)>> {
13528 let local_package_directory = self.worktree_root_path();
13529 let node_modules_directory = local_package_directory.join("node_modules");
13530
13531 if let Some(version) =
13532 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13533 {
13534 return Ok(Some((node_modules_directory, version)));
13535 }
13536 let Some(npm) = self.which("npm".as_ref()).await else {
13537 log::warn!(
13538 "Failed to find npm executable for {:?}",
13539 local_package_directory
13540 );
13541 return Ok(None);
13542 };
13543
13544 let env = self.shell_env().await;
13545 let output = util::command::new_smol_command(&npm)
13546 .args(["root", "-g"])
13547 .envs(env)
13548 .current_dir(local_package_directory)
13549 .output()
13550 .await?;
13551 let global_node_modules =
13552 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13553
13554 if let Some(version) =
13555 read_package_installed_version(global_node_modules.clone(), package_name).await?
13556 {
13557 return Ok(Some((global_node_modules, version)));
13558 }
13559 return Ok(None);
13560 }
13561
13562 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13563 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13564 if self.fs.is_file(&worktree_abs_path).await {
13565 worktree_abs_path.pop();
13566 }
13567
13568 let env = self.shell_env().await;
13569
13570 let shell_path = env.get("PATH").cloned();
13571
13572 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13573 }
13574
13575 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13576 let mut working_dir = self.worktree_root_path().to_path_buf();
13577 if self.fs.is_file(&working_dir).await {
13578 working_dir.pop();
13579 }
13580 let output = util::command::new_smol_command(&command.path)
13581 .args(command.arguments)
13582 .envs(command.env.clone().unwrap_or_default())
13583 .current_dir(working_dir)
13584 .output()
13585 .await?;
13586
13587 anyhow::ensure!(
13588 output.status.success(),
13589 "{}, stdout: {:?}, stderr: {:?}",
13590 output.status,
13591 String::from_utf8_lossy(&output.stdout),
13592 String::from_utf8_lossy(&output.stderr)
13593 );
13594 Ok(())
13595 }
13596
13597 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13598 self.language_registry
13599 .update_lsp_binary_status(server_name, status);
13600 }
13601
13602 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13603 self.language_registry
13604 .all_lsp_adapters()
13605 .into_iter()
13606 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13607 .collect()
13608 }
13609
13610 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13611 let dir = self.language_registry.language_server_download_dir(name)?;
13612
13613 if !dir.exists() {
13614 smol::fs::create_dir_all(&dir)
13615 .await
13616 .context("failed to create container directory")
13617 .log_err()?;
13618 }
13619
13620 Some(dir)
13621 }
13622
13623 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13624 let entry = self
13625 .worktree
13626 .entry_for_path(path)
13627 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13628 let abs_path = self.worktree.absolutize(&entry.path);
13629 self.fs.load(&abs_path).await
13630 }
13631}
13632
13633async fn populate_labels_for_symbols(
13634 symbols: Vec<CoreSymbol>,
13635 language_registry: &Arc<LanguageRegistry>,
13636 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13637 output: &mut Vec<Symbol>,
13638) {
13639 #[allow(clippy::mutable_key_type)]
13640 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13641
13642 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13643 for symbol in symbols {
13644 let Some(file_name) = symbol.path.file_name() else {
13645 continue;
13646 };
13647 let language = language_registry
13648 .load_language_for_file_path(Path::new(file_name))
13649 .await
13650 .ok()
13651 .or_else(|| {
13652 unknown_paths.insert(file_name.into());
13653 None
13654 });
13655 symbols_by_language
13656 .entry(language)
13657 .or_default()
13658 .push(symbol);
13659 }
13660
13661 for unknown_path in unknown_paths {
13662 log::info!("no language found for symbol in file {unknown_path:?}");
13663 }
13664
13665 let mut label_params = Vec::new();
13666 for (language, mut symbols) in symbols_by_language {
13667 label_params.clear();
13668 label_params.extend(
13669 symbols
13670 .iter_mut()
13671 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13672 );
13673
13674 let mut labels = Vec::new();
13675 if let Some(language) = language {
13676 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13677 language_registry
13678 .lsp_adapters(&language.name())
13679 .first()
13680 .cloned()
13681 });
13682 if let Some(lsp_adapter) = lsp_adapter {
13683 labels = lsp_adapter
13684 .labels_for_symbols(&label_params, &language)
13685 .await
13686 .log_err()
13687 .unwrap_or_default();
13688 }
13689 }
13690
13691 for ((symbol, (name, _)), label) in symbols
13692 .into_iter()
13693 .zip(label_params.drain(..))
13694 .zip(labels.into_iter().chain(iter::repeat(None)))
13695 {
13696 output.push(Symbol {
13697 language_server_name: symbol.language_server_name,
13698 source_worktree_id: symbol.source_worktree_id,
13699 source_language_server_id: symbol.source_language_server_id,
13700 path: symbol.path,
13701 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13702 name,
13703 kind: symbol.kind,
13704 range: symbol.range,
13705 });
13706 }
13707 }
13708}
13709
13710fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13711 match server.capabilities().text_document_sync.as_ref()? {
13712 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13713 // Server wants didSave but didn't specify includeText.
13714 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13715 // Server doesn't want didSave at all.
13716 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13717 // Server provided SaveOptions.
13718 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13719 Some(save_options.include_text.unwrap_or(false))
13720 }
13721 },
13722 // We do not have any save info. Kind affects didChange only.
13723 lsp::TextDocumentSyncCapability::Kind(_) => None,
13724 }
13725}
13726
13727/// Completion items are displayed in a `UniformList`.
13728/// Usually, those items are single-line strings, but in LSP responses,
13729/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13730/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13731/// 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,
13732/// breaking the completions menu presentation.
13733///
13734/// 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.
13735fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13736 let mut new_text = String::with_capacity(label.text.len());
13737 let mut offset_map = vec![0; label.text.len() + 1];
13738 let mut last_char_was_space = false;
13739 let mut new_idx = 0;
13740 let chars = label.text.char_indices().fuse();
13741 let mut newlines_removed = false;
13742
13743 for (idx, c) in chars {
13744 offset_map[idx] = new_idx;
13745
13746 match c {
13747 '\n' if last_char_was_space => {
13748 newlines_removed = true;
13749 }
13750 '\t' | ' ' if last_char_was_space => {}
13751 '\n' if !last_char_was_space => {
13752 new_text.push(' ');
13753 new_idx += 1;
13754 last_char_was_space = true;
13755 newlines_removed = true;
13756 }
13757 ' ' | '\t' => {
13758 new_text.push(' ');
13759 new_idx += 1;
13760 last_char_was_space = true;
13761 }
13762 _ => {
13763 new_text.push(c);
13764 new_idx += c.len_utf8();
13765 last_char_was_space = false;
13766 }
13767 }
13768 }
13769 offset_map[label.text.len()] = new_idx;
13770
13771 // Only modify the label if newlines were removed.
13772 if !newlines_removed {
13773 return;
13774 }
13775
13776 let last_index = new_idx;
13777 let mut run_ranges_errors = Vec::new();
13778 label.runs.retain_mut(|(range, _)| {
13779 match offset_map.get(range.start) {
13780 Some(&start) => range.start = start,
13781 None => {
13782 run_ranges_errors.push(range.clone());
13783 return false;
13784 }
13785 }
13786
13787 match offset_map.get(range.end) {
13788 Some(&end) => range.end = end,
13789 None => {
13790 run_ranges_errors.push(range.clone());
13791 range.end = last_index;
13792 }
13793 }
13794 true
13795 });
13796 if !run_ranges_errors.is_empty() {
13797 log::error!(
13798 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13799 label.text
13800 );
13801 }
13802
13803 let mut wrong_filter_range = None;
13804 if label.filter_range == (0..label.text.len()) {
13805 label.filter_range = 0..new_text.len();
13806 } else {
13807 let mut original_filter_range = Some(label.filter_range.clone());
13808 match offset_map.get(label.filter_range.start) {
13809 Some(&start) => label.filter_range.start = start,
13810 None => {
13811 wrong_filter_range = original_filter_range.take();
13812 label.filter_range.start = last_index;
13813 }
13814 }
13815
13816 match offset_map.get(label.filter_range.end) {
13817 Some(&end) => label.filter_range.end = end,
13818 None => {
13819 wrong_filter_range = original_filter_range.take();
13820 label.filter_range.end = last_index;
13821 }
13822 }
13823 }
13824 if let Some(wrong_filter_range) = wrong_filter_range {
13825 log::error!(
13826 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13827 label.text
13828 );
13829 }
13830
13831 label.text = new_text;
13832}
13833
13834#[cfg(test)]
13835mod tests {
13836 use language::HighlightId;
13837
13838 use super::*;
13839
13840 #[test]
13841 fn test_glob_literal_prefix() {
13842 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13843 assert_eq!(
13844 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13845 Path::new("node_modules")
13846 );
13847 assert_eq!(
13848 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13849 Path::new("foo")
13850 );
13851 assert_eq!(
13852 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13853 Path::new("foo/bar/baz.js")
13854 );
13855
13856 #[cfg(target_os = "windows")]
13857 {
13858 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13859 assert_eq!(
13860 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13861 Path::new("node_modules")
13862 );
13863 assert_eq!(
13864 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13865 Path::new("foo")
13866 );
13867 assert_eq!(
13868 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13869 Path::new("foo/bar/baz.js")
13870 );
13871 }
13872 }
13873
13874 #[test]
13875 fn test_multi_len_chars_normalization() {
13876 let mut label = CodeLabel::new(
13877 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13878 0..6,
13879 vec![(0..6, HighlightId(1))],
13880 );
13881 ensure_uniform_list_compatible_label(&mut label);
13882 assert_eq!(
13883 label,
13884 CodeLabel::new(
13885 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13886 0..6,
13887 vec![(0..6, HighlightId(1))],
13888 )
13889 );
13890 }
13891}