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