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