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