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