1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default, Debug)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = settings.binary.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<BufferChunk, 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 // Our remote connection got closed
4197 }
4198 handle
4199 }
4200
4201 fn maintain_buffer_languages(
4202 languages: Arc<LanguageRegistry>,
4203 cx: &mut Context<Self>,
4204 ) -> Task<()> {
4205 let mut subscription = languages.subscribe();
4206 let mut prev_reload_count = languages.reload_count();
4207 cx.spawn(async move |this, cx| {
4208 while let Some(()) = subscription.next().await {
4209 if let Some(this) = this.upgrade() {
4210 // If the language registry has been reloaded, then remove and
4211 // re-assign the languages on all open buffers.
4212 let reload_count = languages.reload_count();
4213 if reload_count > prev_reload_count {
4214 prev_reload_count = reload_count;
4215 this.update(cx, |this, cx| {
4216 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4217 for buffer in buffer_store.buffers() {
4218 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4219 {
4220 buffer
4221 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4222 if let Some(local) = this.as_local_mut() {
4223 local.reset_buffer(&buffer, &f, cx);
4224
4225 if local
4226 .registered_buffers
4227 .contains_key(&buffer.read(cx).remote_id())
4228 && let Some(file_url) =
4229 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4230 {
4231 local.unregister_buffer_from_language_servers(
4232 &buffer, &file_url, cx,
4233 );
4234 }
4235 }
4236 }
4237 }
4238 });
4239 })
4240 .ok();
4241 }
4242
4243 this.update(cx, |this, cx| {
4244 let mut plain_text_buffers = Vec::new();
4245 let mut buffers_with_unknown_injections = Vec::new();
4246 for handle in this.buffer_store.read(cx).buffers() {
4247 let buffer = handle.read(cx);
4248 if buffer.language().is_none()
4249 || buffer.language() == Some(&*language::PLAIN_TEXT)
4250 {
4251 plain_text_buffers.push(handle);
4252 } else if buffer.contains_unknown_injections() {
4253 buffers_with_unknown_injections.push(handle);
4254 }
4255 }
4256
4257 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4258 // and reused later in the invisible worktrees.
4259 plain_text_buffers.sort_by_key(|buffer| {
4260 Reverse(
4261 File::from_dyn(buffer.read(cx).file())
4262 .map(|file| file.worktree.read(cx).is_visible()),
4263 )
4264 });
4265
4266 for buffer in plain_text_buffers {
4267 this.detect_language_for_buffer(&buffer, cx);
4268 if let Some(local) = this.as_local_mut() {
4269 local.initialize_buffer(&buffer, cx);
4270 if local
4271 .registered_buffers
4272 .contains_key(&buffer.read(cx).remote_id())
4273 {
4274 local.register_buffer_with_language_servers(
4275 &buffer,
4276 HashSet::default(),
4277 cx,
4278 );
4279 }
4280 }
4281 }
4282
4283 for buffer in buffers_with_unknown_injections {
4284 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4285 }
4286 })
4287 .ok();
4288 }
4289 }
4290 })
4291 }
4292
4293 fn detect_language_for_buffer(
4294 &mut self,
4295 buffer_handle: &Entity<Buffer>,
4296 cx: &mut Context<Self>,
4297 ) -> Option<language::AvailableLanguage> {
4298 // If the buffer has a language, set it and start the language server if we haven't already.
4299 let buffer = buffer_handle.read(cx);
4300 let file = buffer.file()?;
4301
4302 let content = buffer.as_rope();
4303 let available_language = self.languages.language_for_file(file, Some(content), cx);
4304 if let Some(available_language) = &available_language {
4305 if let Some(Ok(Ok(new_language))) = self
4306 .languages
4307 .load_language(available_language)
4308 .now_or_never()
4309 {
4310 self.set_language_for_buffer(buffer_handle, new_language, cx);
4311 }
4312 } else {
4313 cx.emit(LspStoreEvent::LanguageDetected {
4314 buffer: buffer_handle.clone(),
4315 new_language: None,
4316 });
4317 }
4318
4319 available_language
4320 }
4321
4322 pub(crate) fn set_language_for_buffer(
4323 &mut self,
4324 buffer_entity: &Entity<Buffer>,
4325 new_language: Arc<Language>,
4326 cx: &mut Context<Self>,
4327 ) {
4328 let buffer = buffer_entity.read(cx);
4329 let buffer_file = buffer.file().cloned();
4330 let buffer_id = buffer.remote_id();
4331 if let Some(local_store) = self.as_local_mut()
4332 && local_store.registered_buffers.contains_key(&buffer_id)
4333 && let Some(abs_path) =
4334 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4335 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4336 {
4337 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4338 }
4339 buffer_entity.update(cx, |buffer, cx| {
4340 if buffer
4341 .language()
4342 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4343 {
4344 buffer.set_language(Some(new_language.clone()), cx);
4345 }
4346 });
4347
4348 let settings =
4349 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4350 let buffer_file = File::from_dyn(buffer_file.as_ref());
4351
4352 let worktree_id = if let Some(file) = buffer_file {
4353 let worktree = file.worktree.clone();
4354
4355 if let Some(local) = self.as_local_mut()
4356 && local.registered_buffers.contains_key(&buffer_id)
4357 {
4358 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4359 }
4360 Some(worktree.read(cx).id())
4361 } else {
4362 None
4363 };
4364
4365 if settings.prettier.allowed
4366 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4367 {
4368 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4369 if let Some(prettier_store) = prettier_store {
4370 prettier_store.update(cx, |prettier_store, cx| {
4371 prettier_store.install_default_prettier(
4372 worktree_id,
4373 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4374 cx,
4375 )
4376 })
4377 }
4378 }
4379
4380 cx.emit(LspStoreEvent::LanguageDetected {
4381 buffer: buffer_entity.clone(),
4382 new_language: Some(new_language),
4383 })
4384 }
4385
4386 pub fn buffer_store(&self) -> Entity<BufferStore> {
4387 self.buffer_store.clone()
4388 }
4389
4390 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4391 self.active_entry = active_entry;
4392 }
4393
4394 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4395 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4396 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4397 {
4398 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4399 summaries
4400 .iter()
4401 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4402 });
4403 if let Some(summary) = summaries.next() {
4404 client
4405 .send(proto::UpdateDiagnosticSummary {
4406 project_id: downstream_project_id,
4407 worktree_id: worktree.id().to_proto(),
4408 summary: Some(summary),
4409 more_summaries: summaries.collect(),
4410 })
4411 .log_err();
4412 }
4413 }
4414 }
4415
4416 fn is_capable_for_proto_request<R>(
4417 &self,
4418 buffer: &Entity<Buffer>,
4419 request: &R,
4420 cx: &App,
4421 ) -> bool
4422 where
4423 R: LspCommand,
4424 {
4425 self.check_if_capable_for_proto_request(
4426 buffer,
4427 |capabilities| {
4428 request.check_capabilities(AdapterServerCapabilities {
4429 server_capabilities: capabilities.clone(),
4430 code_action_kinds: None,
4431 })
4432 },
4433 cx,
4434 )
4435 }
4436
4437 fn check_if_capable_for_proto_request<F>(
4438 &self,
4439 buffer: &Entity<Buffer>,
4440 check: F,
4441 cx: &App,
4442 ) -> bool
4443 where
4444 F: FnMut(&lsp::ServerCapabilities) -> bool,
4445 {
4446 let Some(language) = buffer.read(cx).language().cloned() else {
4447 return false;
4448 };
4449 let relevant_language_servers = self
4450 .languages
4451 .lsp_adapters(&language.name())
4452 .into_iter()
4453 .map(|lsp_adapter| lsp_adapter.name())
4454 .collect::<HashSet<_>>();
4455 self.language_server_statuses
4456 .iter()
4457 .filter_map(|(server_id, server_status)| {
4458 relevant_language_servers
4459 .contains(&server_status.name)
4460 .then_some(server_id)
4461 })
4462 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4463 .any(check)
4464 }
4465
4466 pub fn request_lsp<R>(
4467 &mut self,
4468 buffer: Entity<Buffer>,
4469 server: LanguageServerToQuery,
4470 request: R,
4471 cx: &mut Context<Self>,
4472 ) -> Task<Result<R::Response>>
4473 where
4474 R: LspCommand,
4475 <R::LspRequest as lsp::request::Request>::Result: Send,
4476 <R::LspRequest as lsp::request::Request>::Params: Send,
4477 {
4478 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4479 return self.send_lsp_proto_request(
4480 buffer,
4481 upstream_client,
4482 upstream_project_id,
4483 request,
4484 cx,
4485 );
4486 }
4487
4488 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4489 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4490 local
4491 .language_servers_for_buffer(buffer, cx)
4492 .find(|(_, server)| {
4493 request.check_capabilities(server.adapter_server_capabilities())
4494 })
4495 .map(|(_, server)| server.clone())
4496 }),
4497 LanguageServerToQuery::Other(id) => self
4498 .language_server_for_local_buffer(buffer, id, cx)
4499 .and_then(|(_, server)| {
4500 request
4501 .check_capabilities(server.adapter_server_capabilities())
4502 .then(|| Arc::clone(server))
4503 }),
4504 }) else {
4505 return Task::ready(Ok(Default::default()));
4506 };
4507
4508 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4509
4510 let Some(file) = file else {
4511 return Task::ready(Ok(Default::default()));
4512 };
4513
4514 let lsp_params = match request.to_lsp_params_or_response(
4515 &file.abs_path(cx),
4516 buffer.read(cx),
4517 &language_server,
4518 cx,
4519 ) {
4520 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4521 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4522
4523 Err(err) => {
4524 let message = format!(
4525 "{} via {} failed: {}",
4526 request.display_name(),
4527 language_server.name(),
4528 err
4529 );
4530 log::warn!("{message}");
4531 return Task::ready(Err(anyhow!(message)));
4532 }
4533 };
4534
4535 let status = request.status();
4536 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4537 return Task::ready(Ok(Default::default()));
4538 }
4539 cx.spawn(async move |this, cx| {
4540 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4541
4542 let id = lsp_request.id();
4543 let _cleanup = if status.is_some() {
4544 cx.update(|cx| {
4545 this.update(cx, |this, cx| {
4546 this.on_lsp_work_start(
4547 language_server.server_id(),
4548 ProgressToken::Number(id),
4549 LanguageServerProgress {
4550 is_disk_based_diagnostics_progress: false,
4551 is_cancellable: false,
4552 title: None,
4553 message: status.clone(),
4554 percentage: None,
4555 last_update_at: cx.background_executor().now(),
4556 },
4557 cx,
4558 );
4559 })
4560 })
4561 .log_err();
4562
4563 Some(defer(|| {
4564 cx.update(|cx| {
4565 this.update(cx, |this, cx| {
4566 this.on_lsp_work_end(
4567 language_server.server_id(),
4568 ProgressToken::Number(id),
4569 cx,
4570 );
4571 })
4572 })
4573 .log_err();
4574 }))
4575 } else {
4576 None
4577 };
4578
4579 let result = lsp_request.await.into_response();
4580
4581 let response = result.map_err(|err| {
4582 let message = format!(
4583 "{} via {} failed: {}",
4584 request.display_name(),
4585 language_server.name(),
4586 err
4587 );
4588 log::warn!("{message}");
4589 anyhow::anyhow!(message)
4590 })?;
4591
4592 request
4593 .response_from_lsp(
4594 response,
4595 this.upgrade().context("no app context")?,
4596 buffer,
4597 language_server.server_id(),
4598 cx.clone(),
4599 )
4600 .await
4601 })
4602 }
4603
4604 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4605 let mut language_formatters_to_check = Vec::new();
4606 for buffer in self.buffer_store.read(cx).buffers() {
4607 let buffer = buffer.read(cx);
4608 let buffer_file = File::from_dyn(buffer.file());
4609 let buffer_language = buffer.language();
4610 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4611 if buffer_language.is_some() {
4612 language_formatters_to_check.push((
4613 buffer_file.map(|f| f.worktree_id(cx)),
4614 settings.into_owned(),
4615 ));
4616 }
4617 }
4618
4619 self.request_workspace_config_refresh();
4620
4621 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4622 prettier_store.update(cx, |prettier_store, cx| {
4623 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4624 })
4625 }
4626
4627 cx.notify();
4628 }
4629
4630 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4631 let buffer_store = self.buffer_store.clone();
4632 let Some(local) = self.as_local_mut() else {
4633 return;
4634 };
4635 let mut adapters = BTreeMap::default();
4636 let get_adapter = {
4637 let languages = local.languages.clone();
4638 let environment = local.environment.clone();
4639 let weak = local.weak.clone();
4640 let worktree_store = local.worktree_store.clone();
4641 let http_client = local.http_client.clone();
4642 let fs = local.fs.clone();
4643 move |worktree_id, cx: &mut App| {
4644 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4645 Some(LocalLspAdapterDelegate::new(
4646 languages.clone(),
4647 &environment,
4648 weak.clone(),
4649 &worktree,
4650 http_client.clone(),
4651 fs.clone(),
4652 cx,
4653 ))
4654 }
4655 };
4656
4657 let mut messages_to_report = Vec::new();
4658 let (new_tree, to_stop) = {
4659 let mut rebase = local.lsp_tree.rebase();
4660 let buffers = buffer_store
4661 .read(cx)
4662 .buffers()
4663 .filter_map(|buffer| {
4664 let raw_buffer = buffer.read(cx);
4665 if !local
4666 .registered_buffers
4667 .contains_key(&raw_buffer.remote_id())
4668 {
4669 return None;
4670 }
4671 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4672 let language = raw_buffer.language().cloned()?;
4673 Some((file, language, raw_buffer.remote_id()))
4674 })
4675 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4676 for (file, language, buffer_id) in buffers {
4677 let worktree_id = file.worktree_id(cx);
4678 let Some(worktree) = local
4679 .worktree_store
4680 .read(cx)
4681 .worktree_for_id(worktree_id, cx)
4682 else {
4683 continue;
4684 };
4685
4686 if let Some((_, apply)) = local.reuse_existing_language_server(
4687 rebase.server_tree(),
4688 &worktree,
4689 &language.name(),
4690 cx,
4691 ) {
4692 (apply)(rebase.server_tree());
4693 } else if let Some(lsp_delegate) = adapters
4694 .entry(worktree_id)
4695 .or_insert_with(|| get_adapter(worktree_id, cx))
4696 .clone()
4697 {
4698 let delegate =
4699 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4700 let path = file
4701 .path()
4702 .parent()
4703 .map(Arc::from)
4704 .unwrap_or_else(|| file.path().clone());
4705 let worktree_path = ProjectPath { worktree_id, path };
4706 let abs_path = file.abs_path(cx);
4707 let nodes = rebase
4708 .walk(
4709 worktree_path,
4710 language.name(),
4711 language.manifest(),
4712 delegate.clone(),
4713 cx,
4714 )
4715 .collect::<Vec<_>>();
4716 for node in nodes {
4717 let server_id = node.server_id_or_init(|disposition| {
4718 let path = &disposition.path;
4719 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4720 let key = LanguageServerSeed {
4721 worktree_id,
4722 name: disposition.server_name.clone(),
4723 settings: disposition.settings.clone(),
4724 toolchain: local.toolchain_store.read(cx).active_toolchain(
4725 path.worktree_id,
4726 &path.path,
4727 language.name(),
4728 ),
4729 };
4730 local.language_server_ids.remove(&key);
4731
4732 let server_id = local.get_or_insert_language_server(
4733 &worktree,
4734 lsp_delegate.clone(),
4735 disposition,
4736 &language.name(),
4737 cx,
4738 );
4739 if let Some(state) = local.language_servers.get(&server_id)
4740 && let Ok(uri) = uri
4741 {
4742 state.add_workspace_folder(uri);
4743 };
4744 server_id
4745 });
4746
4747 if let Some(language_server_id) = server_id {
4748 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4749 language_server_id,
4750 name: node.name(),
4751 message:
4752 proto::update_language_server::Variant::RegisteredForBuffer(
4753 proto::RegisteredForBuffer {
4754 buffer_abs_path: abs_path
4755 .to_string_lossy()
4756 .into_owned(),
4757 buffer_id: buffer_id.to_proto(),
4758 },
4759 ),
4760 });
4761 }
4762 }
4763 } else {
4764 continue;
4765 }
4766 }
4767 rebase.finish()
4768 };
4769 for message in messages_to_report {
4770 cx.emit(message);
4771 }
4772 local.lsp_tree = new_tree;
4773 for (id, _) in to_stop {
4774 self.stop_local_language_server(id, cx).detach();
4775 }
4776 }
4777
4778 pub fn apply_code_action(
4779 &self,
4780 buffer_handle: Entity<Buffer>,
4781 mut action: CodeAction,
4782 push_to_history: bool,
4783 cx: &mut Context<Self>,
4784 ) -> Task<Result<ProjectTransaction>> {
4785 if let Some((upstream_client, project_id)) = self.upstream_client() {
4786 let request = proto::ApplyCodeAction {
4787 project_id,
4788 buffer_id: buffer_handle.read(cx).remote_id().into(),
4789 action: Some(Self::serialize_code_action(&action)),
4790 };
4791 let buffer_store = self.buffer_store();
4792 cx.spawn(async move |_, cx| {
4793 let response = upstream_client
4794 .request(request)
4795 .await?
4796 .transaction
4797 .context("missing transaction")?;
4798
4799 buffer_store
4800 .update(cx, |buffer_store, cx| {
4801 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4802 })?
4803 .await
4804 })
4805 } else if self.mode.is_local() {
4806 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4807 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4808 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4809 }) else {
4810 return Task::ready(Ok(ProjectTransaction::default()));
4811 };
4812 cx.spawn(async move |this, cx| {
4813 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4814 .await
4815 .context("resolving a code action")?;
4816 if let Some(edit) = action.lsp_action.edit()
4817 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4818 return LocalLspStore::deserialize_workspace_edit(
4819 this.upgrade().context("no app present")?,
4820 edit.clone(),
4821 push_to_history,
4822
4823 lang_server.clone(),
4824 cx,
4825 )
4826 .await;
4827 }
4828
4829 if let Some(command) = action.lsp_action.command() {
4830 let server_capabilities = lang_server.capabilities();
4831 let available_commands = server_capabilities
4832 .execute_command_provider
4833 .as_ref()
4834 .map(|options| options.commands.as_slice())
4835 .unwrap_or_default();
4836 if available_commands.contains(&command.command) {
4837 this.update(cx, |this, _| {
4838 this.as_local_mut()
4839 .unwrap()
4840 .last_workspace_edits_by_language_server
4841 .remove(&lang_server.server_id());
4842 })?;
4843
4844 let _result = lang_server
4845 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4846 command: command.command.clone(),
4847 arguments: command.arguments.clone().unwrap_or_default(),
4848 ..lsp::ExecuteCommandParams::default()
4849 })
4850 .await.into_response()
4851 .context("execute command")?;
4852
4853 return this.update(cx, |this, _| {
4854 this.as_local_mut()
4855 .unwrap()
4856 .last_workspace_edits_by_language_server
4857 .remove(&lang_server.server_id())
4858 .unwrap_or_default()
4859 });
4860 } else {
4861 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4862 }
4863 }
4864
4865 Ok(ProjectTransaction::default())
4866 })
4867 } else {
4868 Task::ready(Err(anyhow!("no upstream client and not local")))
4869 }
4870 }
4871
4872 pub fn apply_code_action_kind(
4873 &mut self,
4874 buffers: HashSet<Entity<Buffer>>,
4875 kind: CodeActionKind,
4876 push_to_history: bool,
4877 cx: &mut Context<Self>,
4878 ) -> Task<anyhow::Result<ProjectTransaction>> {
4879 if self.as_local().is_some() {
4880 cx.spawn(async move |lsp_store, cx| {
4881 let buffers = buffers.into_iter().collect::<Vec<_>>();
4882 let result = LocalLspStore::execute_code_action_kind_locally(
4883 lsp_store.clone(),
4884 buffers,
4885 kind,
4886 push_to_history,
4887 cx,
4888 )
4889 .await;
4890 lsp_store.update(cx, |lsp_store, _| {
4891 lsp_store.update_last_formatting_failure(&result);
4892 })?;
4893 result
4894 })
4895 } else if let Some((client, project_id)) = self.upstream_client() {
4896 let buffer_store = self.buffer_store();
4897 cx.spawn(async move |lsp_store, cx| {
4898 let result = client
4899 .request(proto::ApplyCodeActionKind {
4900 project_id,
4901 kind: kind.as_str().to_owned(),
4902 buffer_ids: buffers
4903 .iter()
4904 .map(|buffer| {
4905 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4906 })
4907 .collect::<Result<_>>()?,
4908 })
4909 .await
4910 .and_then(|result| result.transaction.context("missing transaction"));
4911 lsp_store.update(cx, |lsp_store, _| {
4912 lsp_store.update_last_formatting_failure(&result);
4913 })?;
4914
4915 let transaction_response = result?;
4916 buffer_store
4917 .update(cx, |buffer_store, cx| {
4918 buffer_store.deserialize_project_transaction(
4919 transaction_response,
4920 push_to_history,
4921 cx,
4922 )
4923 })?
4924 .await
4925 })
4926 } else {
4927 Task::ready(Ok(ProjectTransaction::default()))
4928 }
4929 }
4930
4931 pub fn resolved_hint(
4932 &mut self,
4933 buffer_id: BufferId,
4934 id: InlayId,
4935 cx: &mut Context<Self>,
4936 ) -> Option<ResolvedHint> {
4937 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4938
4939 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4940 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4941 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4942 let (server_id, resolve_data) = match &hint.resolve_state {
4943 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4944 ResolveState::Resolving => {
4945 return Some(ResolvedHint::Resolving(
4946 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4947 ));
4948 }
4949 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4950 };
4951
4952 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4953 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4954 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4955 id,
4956 cx.spawn(async move |lsp_store, cx| {
4957 let resolved_hint = resolve_task.await;
4958 lsp_store
4959 .update(cx, |lsp_store, _| {
4960 if let Some(old_inlay_hint) = lsp_store
4961 .lsp_data
4962 .get_mut(&buffer_id)
4963 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4964 {
4965 match resolved_hint {
4966 Ok(resolved_hint) => {
4967 *old_inlay_hint = resolved_hint;
4968 }
4969 Err(e) => {
4970 old_inlay_hint.resolve_state =
4971 ResolveState::CanResolve(server_id, resolve_data);
4972 log::error!("Inlay hint resolve failed: {e:#}");
4973 }
4974 }
4975 }
4976 })
4977 .ok();
4978 })
4979 .shared(),
4980 );
4981 debug_assert!(
4982 previous_task.is_none(),
4983 "Did not change hint's resolve state after spawning its resolve"
4984 );
4985 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4986 None
4987 }
4988
4989 fn resolve_inlay_hint(
4990 &self,
4991 mut hint: InlayHint,
4992 buffer: Entity<Buffer>,
4993 server_id: LanguageServerId,
4994 cx: &mut Context<Self>,
4995 ) -> Task<anyhow::Result<InlayHint>> {
4996 if let Some((upstream_client, project_id)) = self.upstream_client() {
4997 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4998 {
4999 hint.resolve_state = ResolveState::Resolved;
5000 return Task::ready(Ok(hint));
5001 }
5002 let request = proto::ResolveInlayHint {
5003 project_id,
5004 buffer_id: buffer.read(cx).remote_id().into(),
5005 language_server_id: server_id.0 as u64,
5006 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5007 };
5008 cx.background_spawn(async move {
5009 let response = upstream_client
5010 .request(request)
5011 .await
5012 .context("inlay hints proto request")?;
5013 match response.hint {
5014 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5015 .context("inlay hints proto resolve response conversion"),
5016 None => Ok(hint),
5017 }
5018 })
5019 } else {
5020 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5021 self.language_server_for_local_buffer(buffer, server_id, cx)
5022 .map(|(_, server)| server.clone())
5023 }) else {
5024 return Task::ready(Ok(hint));
5025 };
5026 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5027 return Task::ready(Ok(hint));
5028 }
5029 let buffer_snapshot = buffer.read(cx).snapshot();
5030 cx.spawn(async move |_, cx| {
5031 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5032 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5033 );
5034 let resolved_hint = resolve_task
5035 .await
5036 .into_response()
5037 .context("inlay hint resolve LSP request")?;
5038 let resolved_hint = InlayHints::lsp_to_project_hint(
5039 resolved_hint,
5040 &buffer,
5041 server_id,
5042 ResolveState::Resolved,
5043 false,
5044 cx,
5045 )
5046 .await?;
5047 Ok(resolved_hint)
5048 })
5049 }
5050 }
5051
5052 pub fn resolve_color_presentation(
5053 &mut self,
5054 mut color: DocumentColor,
5055 buffer: Entity<Buffer>,
5056 server_id: LanguageServerId,
5057 cx: &mut Context<Self>,
5058 ) -> Task<Result<DocumentColor>> {
5059 if color.resolved {
5060 return Task::ready(Ok(color));
5061 }
5062
5063 if let Some((upstream_client, project_id)) = self.upstream_client() {
5064 let start = color.lsp_range.start;
5065 let end = color.lsp_range.end;
5066 let request = proto::GetColorPresentation {
5067 project_id,
5068 server_id: server_id.to_proto(),
5069 buffer_id: buffer.read(cx).remote_id().into(),
5070 color: Some(proto::ColorInformation {
5071 red: color.color.red,
5072 green: color.color.green,
5073 blue: color.color.blue,
5074 alpha: color.color.alpha,
5075 lsp_range_start: Some(proto::PointUtf16 {
5076 row: start.line,
5077 column: start.character,
5078 }),
5079 lsp_range_end: Some(proto::PointUtf16 {
5080 row: end.line,
5081 column: end.character,
5082 }),
5083 }),
5084 };
5085 cx.background_spawn(async move {
5086 let response = upstream_client
5087 .request(request)
5088 .await
5089 .context("color presentation proto request")?;
5090 color.resolved = true;
5091 color.color_presentations = response
5092 .presentations
5093 .into_iter()
5094 .map(|presentation| ColorPresentation {
5095 label: SharedString::from(presentation.label),
5096 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5097 additional_text_edits: presentation
5098 .additional_text_edits
5099 .into_iter()
5100 .filter_map(deserialize_lsp_edit)
5101 .collect(),
5102 })
5103 .collect();
5104 Ok(color)
5105 })
5106 } else {
5107 let path = match buffer
5108 .update(cx, |buffer, cx| {
5109 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5110 })
5111 .context("buffer with the missing path")
5112 {
5113 Ok(path) => path,
5114 Err(e) => return Task::ready(Err(e)),
5115 };
5116 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5117 self.language_server_for_local_buffer(buffer, server_id, cx)
5118 .map(|(_, server)| server.clone())
5119 }) else {
5120 return Task::ready(Ok(color));
5121 };
5122 cx.background_spawn(async move {
5123 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5124 lsp::ColorPresentationParams {
5125 text_document: make_text_document_identifier(&path)?,
5126 color: color.color,
5127 range: color.lsp_range,
5128 work_done_progress_params: Default::default(),
5129 partial_result_params: Default::default(),
5130 },
5131 );
5132 color.color_presentations = resolve_task
5133 .await
5134 .into_response()
5135 .context("color presentation resolve LSP request")?
5136 .into_iter()
5137 .map(|presentation| ColorPresentation {
5138 label: SharedString::from(presentation.label),
5139 text_edit: presentation.text_edit,
5140 additional_text_edits: presentation
5141 .additional_text_edits
5142 .unwrap_or_default(),
5143 })
5144 .collect();
5145 color.resolved = true;
5146 Ok(color)
5147 })
5148 }
5149 }
5150
5151 pub(crate) fn linked_edits(
5152 &mut self,
5153 buffer: &Entity<Buffer>,
5154 position: Anchor,
5155 cx: &mut Context<Self>,
5156 ) -> Task<Result<Vec<Range<Anchor>>>> {
5157 let snapshot = buffer.read(cx).snapshot();
5158 let scope = snapshot.language_scope_at(position);
5159 let Some(server_id) = self
5160 .as_local()
5161 .and_then(|local| {
5162 buffer.update(cx, |buffer, cx| {
5163 local
5164 .language_servers_for_buffer(buffer, cx)
5165 .filter(|(_, server)| {
5166 LinkedEditingRange::check_server_capabilities(server.capabilities())
5167 })
5168 .filter(|(adapter, _)| {
5169 scope
5170 .as_ref()
5171 .map(|scope| scope.language_allowed(&adapter.name))
5172 .unwrap_or(true)
5173 })
5174 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5175 .next()
5176 })
5177 })
5178 .or_else(|| {
5179 self.upstream_client()
5180 .is_some()
5181 .then_some(LanguageServerToQuery::FirstCapable)
5182 })
5183 .filter(|_| {
5184 maybe!({
5185 let language = buffer.read(cx).language_at(position)?;
5186 Some(
5187 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5188 .linked_edits,
5189 )
5190 }) == Some(true)
5191 })
5192 else {
5193 return Task::ready(Ok(Vec::new()));
5194 };
5195
5196 self.request_lsp(
5197 buffer.clone(),
5198 server_id,
5199 LinkedEditingRange { position },
5200 cx,
5201 )
5202 }
5203
5204 fn apply_on_type_formatting(
5205 &mut self,
5206 buffer: Entity<Buffer>,
5207 position: Anchor,
5208 trigger: String,
5209 cx: &mut Context<Self>,
5210 ) -> Task<Result<Option<Transaction>>> {
5211 if let Some((client, project_id)) = self.upstream_client() {
5212 if !self.check_if_capable_for_proto_request(
5213 &buffer,
5214 |capabilities| {
5215 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5216 },
5217 cx,
5218 ) {
5219 return Task::ready(Ok(None));
5220 }
5221 let request = proto::OnTypeFormatting {
5222 project_id,
5223 buffer_id: buffer.read(cx).remote_id().into(),
5224 position: Some(serialize_anchor(&position)),
5225 trigger,
5226 version: serialize_version(&buffer.read(cx).version()),
5227 };
5228 cx.background_spawn(async move {
5229 client
5230 .request(request)
5231 .await?
5232 .transaction
5233 .map(language::proto::deserialize_transaction)
5234 .transpose()
5235 })
5236 } else if let Some(local) = self.as_local_mut() {
5237 let buffer_id = buffer.read(cx).remote_id();
5238 local.buffers_being_formatted.insert(buffer_id);
5239 cx.spawn(async move |this, cx| {
5240 let _cleanup = defer({
5241 let this = this.clone();
5242 let mut cx = cx.clone();
5243 move || {
5244 this.update(&mut cx, |this, _| {
5245 if let Some(local) = this.as_local_mut() {
5246 local.buffers_being_formatted.remove(&buffer_id);
5247 }
5248 })
5249 .ok();
5250 }
5251 });
5252
5253 buffer
5254 .update(cx, |buffer, _| {
5255 buffer.wait_for_edits(Some(position.timestamp))
5256 })?
5257 .await?;
5258 this.update(cx, |this, cx| {
5259 let position = position.to_point_utf16(buffer.read(cx));
5260 this.on_type_format(buffer, position, trigger, false, cx)
5261 })?
5262 .await
5263 })
5264 } else {
5265 Task::ready(Err(anyhow!("No upstream client or local language server")))
5266 }
5267 }
5268
5269 pub fn on_type_format<T: ToPointUtf16>(
5270 &mut self,
5271 buffer: Entity<Buffer>,
5272 position: T,
5273 trigger: String,
5274 push_to_history: bool,
5275 cx: &mut Context<Self>,
5276 ) -> Task<Result<Option<Transaction>>> {
5277 let position = position.to_point_utf16(buffer.read(cx));
5278 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5279 }
5280
5281 fn on_type_format_impl(
5282 &mut self,
5283 buffer: Entity<Buffer>,
5284 position: PointUtf16,
5285 trigger: String,
5286 push_to_history: bool,
5287 cx: &mut Context<Self>,
5288 ) -> Task<Result<Option<Transaction>>> {
5289 let options = buffer.update(cx, |buffer, cx| {
5290 lsp_command::lsp_formatting_options(
5291 language_settings(
5292 buffer.language_at(position).map(|l| l.name()),
5293 buffer.file(),
5294 cx,
5295 )
5296 .as_ref(),
5297 )
5298 });
5299
5300 cx.spawn(async move |this, cx| {
5301 if let Some(waiter) =
5302 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5303 {
5304 waiter.await?;
5305 }
5306 cx.update(|cx| {
5307 this.update(cx, |this, cx| {
5308 this.request_lsp(
5309 buffer.clone(),
5310 LanguageServerToQuery::FirstCapable,
5311 OnTypeFormatting {
5312 position,
5313 trigger,
5314 options,
5315 push_to_history,
5316 },
5317 cx,
5318 )
5319 })
5320 })??
5321 .await
5322 })
5323 }
5324
5325 pub fn definitions(
5326 &mut self,
5327 buffer: &Entity<Buffer>,
5328 position: PointUtf16,
5329 cx: &mut Context<Self>,
5330 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5331 if let Some((upstream_client, project_id)) = self.upstream_client() {
5332 let request = GetDefinitions { position };
5333 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5334 return Task::ready(Ok(None));
5335 }
5336 let request_task = upstream_client.request_lsp(
5337 project_id,
5338 None,
5339 LSP_REQUEST_TIMEOUT,
5340 cx.background_executor().clone(),
5341 request.to_proto(project_id, buffer.read(cx)),
5342 );
5343 let buffer = buffer.clone();
5344 cx.spawn(async move |weak_lsp_store, cx| {
5345 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5346 return Ok(None);
5347 };
5348 let Some(responses) = request_task.await? else {
5349 return Ok(None);
5350 };
5351 let actions = join_all(responses.payload.into_iter().map(|response| {
5352 GetDefinitions { position }.response_from_proto(
5353 response.response,
5354 lsp_store.clone(),
5355 buffer.clone(),
5356 cx.clone(),
5357 )
5358 }))
5359 .await;
5360
5361 Ok(Some(
5362 actions
5363 .into_iter()
5364 .collect::<Result<Vec<Vec<_>>>>()?
5365 .into_iter()
5366 .flatten()
5367 .dedup()
5368 .collect(),
5369 ))
5370 })
5371 } else {
5372 let definitions_task = self.request_multiple_lsp_locally(
5373 buffer,
5374 Some(position),
5375 GetDefinitions { position },
5376 cx,
5377 );
5378 cx.background_spawn(async move {
5379 Ok(Some(
5380 definitions_task
5381 .await
5382 .into_iter()
5383 .flat_map(|(_, definitions)| definitions)
5384 .dedup()
5385 .collect(),
5386 ))
5387 })
5388 }
5389 }
5390
5391 pub fn declarations(
5392 &mut self,
5393 buffer: &Entity<Buffer>,
5394 position: PointUtf16,
5395 cx: &mut Context<Self>,
5396 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5397 if let Some((upstream_client, project_id)) = self.upstream_client() {
5398 let request = GetDeclarations { position };
5399 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5400 return Task::ready(Ok(None));
5401 }
5402 let request_task = upstream_client.request_lsp(
5403 project_id,
5404 None,
5405 LSP_REQUEST_TIMEOUT,
5406 cx.background_executor().clone(),
5407 request.to_proto(project_id, buffer.read(cx)),
5408 );
5409 let buffer = buffer.clone();
5410 cx.spawn(async move |weak_lsp_store, cx| {
5411 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5412 return Ok(None);
5413 };
5414 let Some(responses) = request_task.await? else {
5415 return Ok(None);
5416 };
5417 let actions = join_all(responses.payload.into_iter().map(|response| {
5418 GetDeclarations { position }.response_from_proto(
5419 response.response,
5420 lsp_store.clone(),
5421 buffer.clone(),
5422 cx.clone(),
5423 )
5424 }))
5425 .await;
5426
5427 Ok(Some(
5428 actions
5429 .into_iter()
5430 .collect::<Result<Vec<Vec<_>>>>()?
5431 .into_iter()
5432 .flatten()
5433 .dedup()
5434 .collect(),
5435 ))
5436 })
5437 } else {
5438 let declarations_task = self.request_multiple_lsp_locally(
5439 buffer,
5440 Some(position),
5441 GetDeclarations { position },
5442 cx,
5443 );
5444 cx.background_spawn(async move {
5445 Ok(Some(
5446 declarations_task
5447 .await
5448 .into_iter()
5449 .flat_map(|(_, declarations)| declarations)
5450 .dedup()
5451 .collect(),
5452 ))
5453 })
5454 }
5455 }
5456
5457 pub fn type_definitions(
5458 &mut self,
5459 buffer: &Entity<Buffer>,
5460 position: PointUtf16,
5461 cx: &mut Context<Self>,
5462 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5463 if let Some((upstream_client, project_id)) = self.upstream_client() {
5464 let request = GetTypeDefinitions { position };
5465 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5466 return Task::ready(Ok(None));
5467 }
5468 let request_task = upstream_client.request_lsp(
5469 project_id,
5470 None,
5471 LSP_REQUEST_TIMEOUT,
5472 cx.background_executor().clone(),
5473 request.to_proto(project_id, buffer.read(cx)),
5474 );
5475 let buffer = buffer.clone();
5476 cx.spawn(async move |weak_lsp_store, cx| {
5477 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5478 return Ok(None);
5479 };
5480 let Some(responses) = request_task.await? else {
5481 return Ok(None);
5482 };
5483 let actions = join_all(responses.payload.into_iter().map(|response| {
5484 GetTypeDefinitions { position }.response_from_proto(
5485 response.response,
5486 lsp_store.clone(),
5487 buffer.clone(),
5488 cx.clone(),
5489 )
5490 }))
5491 .await;
5492
5493 Ok(Some(
5494 actions
5495 .into_iter()
5496 .collect::<Result<Vec<Vec<_>>>>()?
5497 .into_iter()
5498 .flatten()
5499 .dedup()
5500 .collect(),
5501 ))
5502 })
5503 } else {
5504 let type_definitions_task = self.request_multiple_lsp_locally(
5505 buffer,
5506 Some(position),
5507 GetTypeDefinitions { position },
5508 cx,
5509 );
5510 cx.background_spawn(async move {
5511 Ok(Some(
5512 type_definitions_task
5513 .await
5514 .into_iter()
5515 .flat_map(|(_, type_definitions)| type_definitions)
5516 .dedup()
5517 .collect(),
5518 ))
5519 })
5520 }
5521 }
5522
5523 pub fn implementations(
5524 &mut self,
5525 buffer: &Entity<Buffer>,
5526 position: PointUtf16,
5527 cx: &mut Context<Self>,
5528 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5529 if let Some((upstream_client, project_id)) = self.upstream_client() {
5530 let request = GetImplementations { position };
5531 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5532 return Task::ready(Ok(None));
5533 }
5534 let request_task = upstream_client.request_lsp(
5535 project_id,
5536 None,
5537 LSP_REQUEST_TIMEOUT,
5538 cx.background_executor().clone(),
5539 request.to_proto(project_id, buffer.read(cx)),
5540 );
5541 let buffer = buffer.clone();
5542 cx.spawn(async move |weak_lsp_store, cx| {
5543 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5544 return Ok(None);
5545 };
5546 let Some(responses) = request_task.await? else {
5547 return Ok(None);
5548 };
5549 let actions = join_all(responses.payload.into_iter().map(|response| {
5550 GetImplementations { position }.response_from_proto(
5551 response.response,
5552 lsp_store.clone(),
5553 buffer.clone(),
5554 cx.clone(),
5555 )
5556 }))
5557 .await;
5558
5559 Ok(Some(
5560 actions
5561 .into_iter()
5562 .collect::<Result<Vec<Vec<_>>>>()?
5563 .into_iter()
5564 .flatten()
5565 .dedup()
5566 .collect(),
5567 ))
5568 })
5569 } else {
5570 let implementations_task = self.request_multiple_lsp_locally(
5571 buffer,
5572 Some(position),
5573 GetImplementations { position },
5574 cx,
5575 );
5576 cx.background_spawn(async move {
5577 Ok(Some(
5578 implementations_task
5579 .await
5580 .into_iter()
5581 .flat_map(|(_, implementations)| implementations)
5582 .dedup()
5583 .collect(),
5584 ))
5585 })
5586 }
5587 }
5588
5589 pub fn references(
5590 &mut self,
5591 buffer: &Entity<Buffer>,
5592 position: PointUtf16,
5593 cx: &mut Context<Self>,
5594 ) -> Task<Result<Option<Vec<Location>>>> {
5595 if let Some((upstream_client, project_id)) = self.upstream_client() {
5596 let request = GetReferences { position };
5597 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5598 return Task::ready(Ok(None));
5599 }
5600
5601 let request_task = upstream_client.request_lsp(
5602 project_id,
5603 None,
5604 LSP_REQUEST_TIMEOUT,
5605 cx.background_executor().clone(),
5606 request.to_proto(project_id, buffer.read(cx)),
5607 );
5608 let buffer = buffer.clone();
5609 cx.spawn(async move |weak_lsp_store, cx| {
5610 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5611 return Ok(None);
5612 };
5613 let Some(responses) = request_task.await? else {
5614 return Ok(None);
5615 };
5616
5617 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5618 GetReferences { position }.response_from_proto(
5619 lsp_response.response,
5620 lsp_store.clone(),
5621 buffer.clone(),
5622 cx.clone(),
5623 )
5624 }))
5625 .await
5626 .into_iter()
5627 .collect::<Result<Vec<Vec<_>>>>()?
5628 .into_iter()
5629 .flatten()
5630 .dedup()
5631 .collect();
5632 Ok(Some(locations))
5633 })
5634 } else {
5635 let references_task = self.request_multiple_lsp_locally(
5636 buffer,
5637 Some(position),
5638 GetReferences { position },
5639 cx,
5640 );
5641 cx.background_spawn(async move {
5642 Ok(Some(
5643 references_task
5644 .await
5645 .into_iter()
5646 .flat_map(|(_, references)| references)
5647 .dedup()
5648 .collect(),
5649 ))
5650 })
5651 }
5652 }
5653
5654 pub fn code_actions(
5655 &mut self,
5656 buffer: &Entity<Buffer>,
5657 range: Range<Anchor>,
5658 kinds: Option<Vec<CodeActionKind>>,
5659 cx: &mut Context<Self>,
5660 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5661 if let Some((upstream_client, project_id)) = self.upstream_client() {
5662 let request = GetCodeActions {
5663 range: range.clone(),
5664 kinds: kinds.clone(),
5665 };
5666 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5667 return Task::ready(Ok(None));
5668 }
5669 let request_task = upstream_client.request_lsp(
5670 project_id,
5671 None,
5672 LSP_REQUEST_TIMEOUT,
5673 cx.background_executor().clone(),
5674 request.to_proto(project_id, buffer.read(cx)),
5675 );
5676 let buffer = buffer.clone();
5677 cx.spawn(async move |weak_lsp_store, cx| {
5678 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5679 return Ok(None);
5680 };
5681 let Some(responses) = request_task.await? else {
5682 return Ok(None);
5683 };
5684 let actions = join_all(responses.payload.into_iter().map(|response| {
5685 GetCodeActions {
5686 range: range.clone(),
5687 kinds: kinds.clone(),
5688 }
5689 .response_from_proto(
5690 response.response,
5691 lsp_store.clone(),
5692 buffer.clone(),
5693 cx.clone(),
5694 )
5695 }))
5696 .await;
5697
5698 Ok(Some(
5699 actions
5700 .into_iter()
5701 .collect::<Result<Vec<Vec<_>>>>()?
5702 .into_iter()
5703 .flatten()
5704 .collect(),
5705 ))
5706 })
5707 } else {
5708 let all_actions_task = self.request_multiple_lsp_locally(
5709 buffer,
5710 Some(range.start),
5711 GetCodeActions { range, kinds },
5712 cx,
5713 );
5714 cx.background_spawn(async move {
5715 Ok(Some(
5716 all_actions_task
5717 .await
5718 .into_iter()
5719 .flat_map(|(_, actions)| actions)
5720 .collect(),
5721 ))
5722 })
5723 }
5724 }
5725
5726 pub fn code_lens_actions(
5727 &mut self,
5728 buffer: &Entity<Buffer>,
5729 cx: &mut Context<Self>,
5730 ) -> CodeLensTask {
5731 let version_queried_for = buffer.read(cx).version();
5732 let buffer_id = buffer.read(cx).remote_id();
5733 let existing_servers = self.as_local().map(|local| {
5734 local
5735 .buffers_opened_in_servers
5736 .get(&buffer_id)
5737 .cloned()
5738 .unwrap_or_default()
5739 });
5740
5741 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5742 if let Some(cached_lens) = &lsp_data.code_lens {
5743 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5744 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5745 existing_servers != cached_lens.lens.keys().copied().collect()
5746 });
5747 if !has_different_servers {
5748 return Task::ready(Ok(Some(
5749 cached_lens.lens.values().flatten().cloned().collect(),
5750 )))
5751 .shared();
5752 }
5753 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5754 if !version_queried_for.changed_since(updating_for) {
5755 return running_update.clone();
5756 }
5757 }
5758 }
5759 }
5760
5761 let lens_lsp_data = self
5762 .latest_lsp_data(buffer, cx)
5763 .code_lens
5764 .get_or_insert_default();
5765 let buffer = buffer.clone();
5766 let query_version_queried_for = version_queried_for.clone();
5767 let new_task = cx
5768 .spawn(async move |lsp_store, cx| {
5769 cx.background_executor()
5770 .timer(Duration::from_millis(30))
5771 .await;
5772 let fetched_lens = lsp_store
5773 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5774 .map_err(Arc::new)?
5775 .await
5776 .context("fetching code lens")
5777 .map_err(Arc::new);
5778 let fetched_lens = match fetched_lens {
5779 Ok(fetched_lens) => fetched_lens,
5780 Err(e) => {
5781 lsp_store
5782 .update(cx, |lsp_store, _| {
5783 if let Some(lens_lsp_data) = lsp_store
5784 .lsp_data
5785 .get_mut(&buffer_id)
5786 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5787 {
5788 lens_lsp_data.update = None;
5789 }
5790 })
5791 .ok();
5792 return Err(e);
5793 }
5794 };
5795
5796 lsp_store
5797 .update(cx, |lsp_store, _| {
5798 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5799 let code_lens = lsp_data.code_lens.as_mut()?;
5800 if let Some(fetched_lens) = fetched_lens {
5801 if lsp_data.buffer_version == query_version_queried_for {
5802 code_lens.lens.extend(fetched_lens);
5803 } else if !lsp_data
5804 .buffer_version
5805 .changed_since(&query_version_queried_for)
5806 {
5807 lsp_data.buffer_version = query_version_queried_for;
5808 code_lens.lens = fetched_lens;
5809 }
5810 }
5811 code_lens.update = None;
5812 Some(code_lens.lens.values().flatten().cloned().collect())
5813 })
5814 .map_err(Arc::new)
5815 })
5816 .shared();
5817 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5818 new_task
5819 }
5820
5821 fn fetch_code_lens(
5822 &mut self,
5823 buffer: &Entity<Buffer>,
5824 cx: &mut Context<Self>,
5825 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5826 if let Some((upstream_client, project_id)) = self.upstream_client() {
5827 let request = GetCodeLens;
5828 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5829 return Task::ready(Ok(None));
5830 }
5831 let request_task = upstream_client.request_lsp(
5832 project_id,
5833 None,
5834 LSP_REQUEST_TIMEOUT,
5835 cx.background_executor().clone(),
5836 request.to_proto(project_id, buffer.read(cx)),
5837 );
5838 let buffer = buffer.clone();
5839 cx.spawn(async move |weak_lsp_store, cx| {
5840 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5841 return Ok(None);
5842 };
5843 let Some(responses) = request_task.await? else {
5844 return Ok(None);
5845 };
5846
5847 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5848 let lsp_store = lsp_store.clone();
5849 let buffer = buffer.clone();
5850 let cx = cx.clone();
5851 async move {
5852 (
5853 LanguageServerId::from_proto(response.server_id),
5854 GetCodeLens
5855 .response_from_proto(response.response, lsp_store, buffer, cx)
5856 .await,
5857 )
5858 }
5859 }))
5860 .await;
5861
5862 let mut has_errors = false;
5863 let code_lens_actions = code_lens_actions
5864 .into_iter()
5865 .filter_map(|(server_id, code_lens)| match code_lens {
5866 Ok(code_lens) => Some((server_id, code_lens)),
5867 Err(e) => {
5868 has_errors = true;
5869 log::error!("{e:#}");
5870 None
5871 }
5872 })
5873 .collect::<HashMap<_, _>>();
5874 anyhow::ensure!(
5875 !has_errors || !code_lens_actions.is_empty(),
5876 "Failed to fetch code lens"
5877 );
5878 Ok(Some(code_lens_actions))
5879 })
5880 } else {
5881 let code_lens_actions_task =
5882 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5883 cx.background_spawn(async move {
5884 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5885 })
5886 }
5887 }
5888
5889 #[inline(never)]
5890 pub fn completions(
5891 &self,
5892 buffer: &Entity<Buffer>,
5893 position: PointUtf16,
5894 context: CompletionContext,
5895 cx: &mut Context<Self>,
5896 ) -> Task<Result<Vec<CompletionResponse>>> {
5897 let language_registry = self.languages.clone();
5898
5899 if let Some((upstream_client, project_id)) = self.upstream_client() {
5900 let request = GetCompletions { position, context };
5901 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5902 return Task::ready(Ok(Vec::new()));
5903 }
5904 let task = self.send_lsp_proto_request(
5905 buffer.clone(),
5906 upstream_client,
5907 project_id,
5908 request,
5909 cx,
5910 );
5911 let language = buffer.read(cx).language().cloned();
5912
5913 // In the future, we should provide project guests with the names of LSP adapters,
5914 // so that they can use the correct LSP adapter when computing labels. For now,
5915 // guests just use the first LSP adapter associated with the buffer's language.
5916 let lsp_adapter = language.as_ref().and_then(|language| {
5917 language_registry
5918 .lsp_adapters(&language.name())
5919 .first()
5920 .cloned()
5921 });
5922
5923 cx.foreground_executor().spawn(async move {
5924 let completion_response = task.await?;
5925 let completions = populate_labels_for_completions(
5926 completion_response.completions,
5927 language,
5928 lsp_adapter,
5929 )
5930 .await;
5931 Ok(vec![CompletionResponse {
5932 completions,
5933 display_options: CompletionDisplayOptions::default(),
5934 is_incomplete: completion_response.is_incomplete,
5935 }])
5936 })
5937 } else if let Some(local) = self.as_local() {
5938 let snapshot = buffer.read(cx).snapshot();
5939 let offset = position.to_offset(&snapshot);
5940 let scope = snapshot.language_scope_at(offset);
5941 let language = snapshot.language().cloned();
5942 let completion_settings = language_settings(
5943 language.as_ref().map(|language| language.name()),
5944 buffer.read(cx).file(),
5945 cx,
5946 )
5947 .completions
5948 .clone();
5949 if !completion_settings.lsp {
5950 return Task::ready(Ok(Vec::new()));
5951 }
5952
5953 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5954 local
5955 .language_servers_for_buffer(buffer, cx)
5956 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5957 .filter(|(adapter, _)| {
5958 scope
5959 .as_ref()
5960 .map(|scope| scope.language_allowed(&adapter.name))
5961 .unwrap_or(true)
5962 })
5963 .map(|(_, server)| server.server_id())
5964 .collect()
5965 });
5966
5967 let buffer = buffer.clone();
5968 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5969 let lsp_timeout = if lsp_timeout > 0 {
5970 Some(Duration::from_millis(lsp_timeout))
5971 } else {
5972 None
5973 };
5974 cx.spawn(async move |this, cx| {
5975 let mut tasks = Vec::with_capacity(server_ids.len());
5976 this.update(cx, |lsp_store, cx| {
5977 for server_id in server_ids {
5978 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5979 let lsp_timeout = lsp_timeout
5980 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5981 let mut timeout = cx.background_spawn(async move {
5982 match lsp_timeout {
5983 Some(lsp_timeout) => {
5984 lsp_timeout.await;
5985 true
5986 },
5987 None => false,
5988 }
5989 }).fuse();
5990 let mut lsp_request = lsp_store.request_lsp(
5991 buffer.clone(),
5992 LanguageServerToQuery::Other(server_id),
5993 GetCompletions {
5994 position,
5995 context: context.clone(),
5996 },
5997 cx,
5998 ).fuse();
5999 let new_task = cx.background_spawn(async move {
6000 select_biased! {
6001 response = lsp_request => anyhow::Ok(Some(response?)),
6002 timeout_happened = timeout => {
6003 if timeout_happened {
6004 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6005 Ok(None)
6006 } else {
6007 let completions = lsp_request.await?;
6008 Ok(Some(completions))
6009 }
6010 },
6011 }
6012 });
6013 tasks.push((lsp_adapter, new_task));
6014 }
6015 })?;
6016
6017 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6018 let completion_response = task.await.ok()??;
6019 let completions = populate_labels_for_completions(
6020 completion_response.completions,
6021 language.clone(),
6022 lsp_adapter,
6023 )
6024 .await;
6025 Some(CompletionResponse {
6026 completions,
6027 display_options: CompletionDisplayOptions::default(),
6028 is_incomplete: completion_response.is_incomplete,
6029 })
6030 });
6031
6032 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6033
6034 Ok(responses.into_iter().flatten().collect())
6035 })
6036 } else {
6037 Task::ready(Err(anyhow!("No upstream client or local language server")))
6038 }
6039 }
6040
6041 pub fn resolve_completions(
6042 &self,
6043 buffer: Entity<Buffer>,
6044 completion_indices: Vec<usize>,
6045 completions: Rc<RefCell<Box<[Completion]>>>,
6046 cx: &mut Context<Self>,
6047 ) -> Task<Result<bool>> {
6048 let client = self.upstream_client();
6049 let buffer_id = buffer.read(cx).remote_id();
6050 let buffer_snapshot = buffer.read(cx).snapshot();
6051
6052 if !self.check_if_capable_for_proto_request(
6053 &buffer,
6054 GetCompletions::can_resolve_completions,
6055 cx,
6056 ) {
6057 return Task::ready(Ok(false));
6058 }
6059 cx.spawn(async move |lsp_store, cx| {
6060 let mut did_resolve = false;
6061 if let Some((client, project_id)) = client {
6062 for completion_index in completion_indices {
6063 let server_id = {
6064 let completion = &completions.borrow()[completion_index];
6065 completion.source.server_id()
6066 };
6067 if let Some(server_id) = server_id {
6068 if Self::resolve_completion_remote(
6069 project_id,
6070 server_id,
6071 buffer_id,
6072 completions.clone(),
6073 completion_index,
6074 client.clone(),
6075 )
6076 .await
6077 .log_err()
6078 .is_some()
6079 {
6080 did_resolve = true;
6081 }
6082 } else {
6083 resolve_word_completion(
6084 &buffer_snapshot,
6085 &mut completions.borrow_mut()[completion_index],
6086 );
6087 }
6088 }
6089 } else {
6090 for completion_index in completion_indices {
6091 let server_id = {
6092 let completion = &completions.borrow()[completion_index];
6093 completion.source.server_id()
6094 };
6095 if let Some(server_id) = server_id {
6096 let server_and_adapter = lsp_store
6097 .read_with(cx, |lsp_store, _| {
6098 let server = lsp_store.language_server_for_id(server_id)?;
6099 let adapter =
6100 lsp_store.language_server_adapter_for_id(server.server_id())?;
6101 Some((server, adapter))
6102 })
6103 .ok()
6104 .flatten();
6105 let Some((server, adapter)) = server_and_adapter else {
6106 continue;
6107 };
6108
6109 let resolved = Self::resolve_completion_local(
6110 server,
6111 completions.clone(),
6112 completion_index,
6113 )
6114 .await
6115 .log_err()
6116 .is_some();
6117 if resolved {
6118 Self::regenerate_completion_labels(
6119 adapter,
6120 &buffer_snapshot,
6121 completions.clone(),
6122 completion_index,
6123 )
6124 .await
6125 .log_err();
6126 did_resolve = true;
6127 }
6128 } else {
6129 resolve_word_completion(
6130 &buffer_snapshot,
6131 &mut completions.borrow_mut()[completion_index],
6132 );
6133 }
6134 }
6135 }
6136
6137 Ok(did_resolve)
6138 })
6139 }
6140
6141 async fn resolve_completion_local(
6142 server: Arc<lsp::LanguageServer>,
6143 completions: Rc<RefCell<Box<[Completion]>>>,
6144 completion_index: usize,
6145 ) -> Result<()> {
6146 let server_id = server.server_id();
6147 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6148 return Ok(());
6149 }
6150
6151 let request = {
6152 let completion = &completions.borrow()[completion_index];
6153 match &completion.source {
6154 CompletionSource::Lsp {
6155 lsp_completion,
6156 resolved,
6157 server_id: completion_server_id,
6158 ..
6159 } => {
6160 if *resolved {
6161 return Ok(());
6162 }
6163 anyhow::ensure!(
6164 server_id == *completion_server_id,
6165 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6166 );
6167 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6168 }
6169 CompletionSource::BufferWord { .. }
6170 | CompletionSource::Dap { .. }
6171 | CompletionSource::Custom => {
6172 return Ok(());
6173 }
6174 }
6175 };
6176 let resolved_completion = request
6177 .await
6178 .into_response()
6179 .context("resolve completion")?;
6180
6181 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6182 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6183
6184 let mut completions = completions.borrow_mut();
6185 let completion = &mut completions[completion_index];
6186 if let CompletionSource::Lsp {
6187 lsp_completion,
6188 resolved,
6189 server_id: completion_server_id,
6190 ..
6191 } = &mut completion.source
6192 {
6193 if *resolved {
6194 return Ok(());
6195 }
6196 anyhow::ensure!(
6197 server_id == *completion_server_id,
6198 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6199 );
6200 *lsp_completion = Box::new(resolved_completion);
6201 *resolved = true;
6202 }
6203 Ok(())
6204 }
6205
6206 async fn regenerate_completion_labels(
6207 adapter: Arc<CachedLspAdapter>,
6208 snapshot: &BufferSnapshot,
6209 completions: Rc<RefCell<Box<[Completion]>>>,
6210 completion_index: usize,
6211 ) -> Result<()> {
6212 let completion_item = completions.borrow()[completion_index]
6213 .source
6214 .lsp_completion(true)
6215 .map(Cow::into_owned);
6216 if let Some(lsp_documentation) = completion_item
6217 .as_ref()
6218 .and_then(|completion_item| completion_item.documentation.clone())
6219 {
6220 let mut completions = completions.borrow_mut();
6221 let completion = &mut completions[completion_index];
6222 completion.documentation = Some(lsp_documentation.into());
6223 } else {
6224 let mut completions = completions.borrow_mut();
6225 let completion = &mut completions[completion_index];
6226 completion.documentation = Some(CompletionDocumentation::Undocumented);
6227 }
6228
6229 let mut new_label = match completion_item {
6230 Some(completion_item) => {
6231 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6232 // So we have to update the label here anyway...
6233 let language = snapshot.language();
6234 match language {
6235 Some(language) => {
6236 adapter
6237 .labels_for_completions(
6238 std::slice::from_ref(&completion_item),
6239 language,
6240 )
6241 .await?
6242 }
6243 None => Vec::new(),
6244 }
6245 .pop()
6246 .flatten()
6247 .unwrap_or_else(|| {
6248 CodeLabel::fallback_for_completion(
6249 &completion_item,
6250 language.map(|language| language.as_ref()),
6251 )
6252 })
6253 }
6254 None => CodeLabel::plain(
6255 completions.borrow()[completion_index].new_text.clone(),
6256 None,
6257 ),
6258 };
6259 ensure_uniform_list_compatible_label(&mut new_label);
6260
6261 let mut completions = completions.borrow_mut();
6262 let completion = &mut completions[completion_index];
6263 if completion.label.filter_text() == new_label.filter_text() {
6264 completion.label = new_label;
6265 } else {
6266 log::error!(
6267 "Resolved completion changed display label from {} to {}. \
6268 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6269 completion.label.text(),
6270 new_label.text(),
6271 completion.label.filter_text(),
6272 new_label.filter_text()
6273 );
6274 }
6275
6276 Ok(())
6277 }
6278
6279 async fn resolve_completion_remote(
6280 project_id: u64,
6281 server_id: LanguageServerId,
6282 buffer_id: BufferId,
6283 completions: Rc<RefCell<Box<[Completion]>>>,
6284 completion_index: usize,
6285 client: AnyProtoClient,
6286 ) -> Result<()> {
6287 let lsp_completion = {
6288 let completion = &completions.borrow()[completion_index];
6289 match &completion.source {
6290 CompletionSource::Lsp {
6291 lsp_completion,
6292 resolved,
6293 server_id: completion_server_id,
6294 ..
6295 } => {
6296 anyhow::ensure!(
6297 server_id == *completion_server_id,
6298 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6299 );
6300 if *resolved {
6301 return Ok(());
6302 }
6303 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6304 }
6305 CompletionSource::Custom
6306 | CompletionSource::Dap { .. }
6307 | CompletionSource::BufferWord { .. } => {
6308 return Ok(());
6309 }
6310 }
6311 };
6312 let request = proto::ResolveCompletionDocumentation {
6313 project_id,
6314 language_server_id: server_id.0 as u64,
6315 lsp_completion,
6316 buffer_id: buffer_id.into(),
6317 };
6318
6319 let response = client
6320 .request(request)
6321 .await
6322 .context("completion documentation resolve proto request")?;
6323 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6324
6325 let documentation = if response.documentation.is_empty() {
6326 CompletionDocumentation::Undocumented
6327 } else if response.documentation_is_markdown {
6328 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6329 } else if response.documentation.lines().count() <= 1 {
6330 CompletionDocumentation::SingleLine(response.documentation.into())
6331 } else {
6332 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6333 };
6334
6335 let mut completions = completions.borrow_mut();
6336 let completion = &mut completions[completion_index];
6337 completion.documentation = Some(documentation);
6338 if let CompletionSource::Lsp {
6339 insert_range,
6340 lsp_completion,
6341 resolved,
6342 server_id: completion_server_id,
6343 lsp_defaults: _,
6344 } = &mut completion.source
6345 {
6346 let completion_insert_range = response
6347 .old_insert_start
6348 .and_then(deserialize_anchor)
6349 .zip(response.old_insert_end.and_then(deserialize_anchor));
6350 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6351
6352 if *resolved {
6353 return Ok(());
6354 }
6355 anyhow::ensure!(
6356 server_id == *completion_server_id,
6357 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6358 );
6359 *lsp_completion = Box::new(resolved_lsp_completion);
6360 *resolved = true;
6361 }
6362
6363 let replace_range = response
6364 .old_replace_start
6365 .and_then(deserialize_anchor)
6366 .zip(response.old_replace_end.and_then(deserialize_anchor));
6367 if let Some((old_replace_start, old_replace_end)) = replace_range
6368 && !response.new_text.is_empty()
6369 {
6370 completion.new_text = response.new_text;
6371 completion.replace_range = old_replace_start..old_replace_end;
6372 }
6373
6374 Ok(())
6375 }
6376
6377 pub fn apply_additional_edits_for_completion(
6378 &self,
6379 buffer_handle: Entity<Buffer>,
6380 completions: Rc<RefCell<Box<[Completion]>>>,
6381 completion_index: usize,
6382 push_to_history: bool,
6383 cx: &mut Context<Self>,
6384 ) -> Task<Result<Option<Transaction>>> {
6385 if let Some((client, project_id)) = self.upstream_client() {
6386 let buffer = buffer_handle.read(cx);
6387 let buffer_id = buffer.remote_id();
6388 cx.spawn(async move |_, cx| {
6389 let request = {
6390 let completion = completions.borrow()[completion_index].clone();
6391 proto::ApplyCompletionAdditionalEdits {
6392 project_id,
6393 buffer_id: buffer_id.into(),
6394 completion: Some(Self::serialize_completion(&CoreCompletion {
6395 replace_range: completion.replace_range,
6396 new_text: completion.new_text,
6397 source: completion.source,
6398 })),
6399 }
6400 };
6401
6402 if let Some(transaction) = client.request(request).await?.transaction {
6403 let transaction = language::proto::deserialize_transaction(transaction)?;
6404 buffer_handle
6405 .update(cx, |buffer, _| {
6406 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6407 })?
6408 .await?;
6409 if push_to_history {
6410 buffer_handle.update(cx, |buffer, _| {
6411 buffer.push_transaction(transaction.clone(), Instant::now());
6412 buffer.finalize_last_transaction();
6413 })?;
6414 }
6415 Ok(Some(transaction))
6416 } else {
6417 Ok(None)
6418 }
6419 })
6420 } else {
6421 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6422 let completion = &completions.borrow()[completion_index];
6423 let server_id = completion.source.server_id()?;
6424 Some(
6425 self.language_server_for_local_buffer(buffer, server_id, cx)?
6426 .1
6427 .clone(),
6428 )
6429 }) else {
6430 return Task::ready(Ok(None));
6431 };
6432
6433 cx.spawn(async move |this, cx| {
6434 Self::resolve_completion_local(
6435 server.clone(),
6436 completions.clone(),
6437 completion_index,
6438 )
6439 .await
6440 .context("resolving completion")?;
6441 let completion = completions.borrow()[completion_index].clone();
6442 let additional_text_edits = completion
6443 .source
6444 .lsp_completion(true)
6445 .as_ref()
6446 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6447 if let Some(edits) = additional_text_edits {
6448 let edits = this
6449 .update(cx, |this, cx| {
6450 this.as_local_mut().unwrap().edits_from_lsp(
6451 &buffer_handle,
6452 edits,
6453 server.server_id(),
6454 None,
6455 cx,
6456 )
6457 })?
6458 .await?;
6459
6460 buffer_handle.update(cx, |buffer, cx| {
6461 buffer.finalize_last_transaction();
6462 buffer.start_transaction();
6463
6464 for (range, text) in edits {
6465 let primary = &completion.replace_range;
6466
6467 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6468 // and the primary completion is just an insertion (empty range), then this is likely
6469 // an auto-import scenario and should not be considered overlapping
6470 // https://github.com/zed-industries/zed/issues/26136
6471 let is_file_start_auto_import = {
6472 let snapshot = buffer.snapshot();
6473 let primary_start_point = primary.start.to_point(&snapshot);
6474 let range_start_point = range.start.to_point(&snapshot);
6475
6476 let result = primary_start_point.row == 0
6477 && primary_start_point.column == 0
6478 && range_start_point.row == 0
6479 && range_start_point.column == 0;
6480
6481 result
6482 };
6483
6484 let has_overlap = if is_file_start_auto_import {
6485 false
6486 } else {
6487 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6488 && primary.end.cmp(&range.start, buffer).is_ge();
6489 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6490 && range.end.cmp(&primary.end, buffer).is_ge();
6491 let result = start_within || end_within;
6492 result
6493 };
6494
6495 //Skip additional edits which overlap with the primary completion edit
6496 //https://github.com/zed-industries/zed/pull/1871
6497 if !has_overlap {
6498 buffer.edit([(range, text)], None, cx);
6499 }
6500 }
6501
6502 let transaction = if buffer.end_transaction(cx).is_some() {
6503 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6504 if !push_to_history {
6505 buffer.forget_transaction(transaction.id);
6506 }
6507 Some(transaction)
6508 } else {
6509 None
6510 };
6511 Ok(transaction)
6512 })?
6513 } else {
6514 Ok(None)
6515 }
6516 })
6517 }
6518 }
6519
6520 pub fn pull_diagnostics(
6521 &mut self,
6522 buffer: Entity<Buffer>,
6523 cx: &mut Context<Self>,
6524 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6525 let buffer_id = buffer.read(cx).remote_id();
6526
6527 if let Some((client, upstream_project_id)) = self.upstream_client() {
6528 let mut suitable_capabilities = None;
6529 // Are we capable for proto request?
6530 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6531 &buffer,
6532 |capabilities| {
6533 if let Some(caps) = &capabilities.diagnostic_provider {
6534 suitable_capabilities = Some(caps.clone());
6535 true
6536 } else {
6537 false
6538 }
6539 },
6540 cx,
6541 );
6542 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6543 let Some(dynamic_caps) = suitable_capabilities else {
6544 return Task::ready(Ok(None));
6545 };
6546 assert!(any_server_has_diagnostics_provider);
6547
6548 let request = GetDocumentDiagnostics {
6549 previous_result_id: None,
6550 dynamic_caps,
6551 };
6552 let request_task = client.request_lsp(
6553 upstream_project_id,
6554 None,
6555 LSP_REQUEST_TIMEOUT,
6556 cx.background_executor().clone(),
6557 request.to_proto(upstream_project_id, buffer.read(cx)),
6558 );
6559 cx.background_spawn(async move {
6560 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6561 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6562 // Do not attempt to further process the dummy responses here.
6563 let _response = request_task.await?;
6564 Ok(None)
6565 })
6566 } else {
6567 let servers = buffer.update(cx, |buffer, cx| {
6568 self.language_servers_for_local_buffer(buffer, cx)
6569 .map(|(_, server)| server.clone())
6570 .collect::<Vec<_>>()
6571 });
6572
6573 let pull_diagnostics = servers
6574 .into_iter()
6575 .flat_map(|server| {
6576 let result = maybe!({
6577 let local = self.as_local()?;
6578 let server_id = server.server_id();
6579 let providers_with_identifiers = local
6580 .language_server_dynamic_registrations
6581 .get(&server_id)
6582 .into_iter()
6583 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6584 .collect::<Vec<_>>();
6585 Some(
6586 providers_with_identifiers
6587 .into_iter()
6588 .map(|dynamic_caps| {
6589 let result_id = self.result_id(server_id, buffer_id, cx);
6590 self.request_lsp(
6591 buffer.clone(),
6592 LanguageServerToQuery::Other(server_id),
6593 GetDocumentDiagnostics {
6594 previous_result_id: result_id,
6595 dynamic_caps,
6596 },
6597 cx,
6598 )
6599 })
6600 .collect::<Vec<_>>(),
6601 )
6602 });
6603
6604 result.unwrap_or_default()
6605 })
6606 .collect::<Vec<_>>();
6607
6608 cx.background_spawn(async move {
6609 let mut responses = Vec::new();
6610 for diagnostics in join_all(pull_diagnostics).await {
6611 responses.extend(diagnostics?);
6612 }
6613 Ok(Some(responses))
6614 })
6615 }
6616 }
6617
6618 pub fn applicable_inlay_chunks(
6619 &mut self,
6620 buffer: &Entity<Buffer>,
6621 ranges: &[Range<text::Anchor>],
6622 cx: &mut Context<Self>,
6623 ) -> Vec<Range<BufferRow>> {
6624 self.latest_lsp_data(buffer, cx)
6625 .inlay_hints
6626 .applicable_chunks(ranges)
6627 .map(|chunk| chunk.start..chunk.end)
6628 .collect()
6629 }
6630
6631 pub fn invalidate_inlay_hints<'a>(
6632 &'a mut self,
6633 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6634 ) {
6635 for buffer_id in for_buffers {
6636 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6637 lsp_data.inlay_hints.clear();
6638 }
6639 }
6640 }
6641
6642 pub fn inlay_hints(
6643 &mut self,
6644 invalidate: InvalidationStrategy,
6645 buffer: Entity<Buffer>,
6646 ranges: Vec<Range<text::Anchor>>,
6647 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6648 cx: &mut Context<Self>,
6649 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6650 let buffer_snapshot = buffer.read(cx).snapshot();
6651 let next_hint_id = self.next_hint_id.clone();
6652 let lsp_data = self.latest_lsp_data(&buffer, cx);
6653 let query_version = lsp_data.buffer_version.clone();
6654 let mut lsp_refresh_requested = false;
6655 let for_server = if let InvalidationStrategy::RefreshRequested {
6656 server_id,
6657 request_id,
6658 } = invalidate
6659 {
6660 let invalidated = lsp_data
6661 .inlay_hints
6662 .invalidate_for_server_refresh(server_id, request_id);
6663 lsp_refresh_requested = invalidated;
6664 Some(server_id)
6665 } else {
6666 None
6667 };
6668 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6669 let known_chunks = known_chunks
6670 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6671 .map(|(_, known_chunks)| known_chunks)
6672 .unwrap_or_default();
6673
6674 let mut hint_fetch_tasks = Vec::new();
6675 let mut cached_inlay_hints = None;
6676 let mut ranges_to_query = None;
6677 let applicable_chunks = existing_inlay_hints
6678 .applicable_chunks(ranges.as_slice())
6679 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6680 .collect::<Vec<_>>();
6681 if applicable_chunks.is_empty() {
6682 return HashMap::default();
6683 }
6684
6685 let last_chunk_number = existing_inlay_hints.buffer_chunks_len() - 1;
6686
6687 for row_chunk in applicable_chunks {
6688 match (
6689 existing_inlay_hints
6690 .cached_hints(&row_chunk)
6691 .filter(|_| !lsp_refresh_requested)
6692 .cloned(),
6693 existing_inlay_hints
6694 .fetched_hints(&row_chunk)
6695 .as_ref()
6696 .filter(|_| !lsp_refresh_requested)
6697 .cloned(),
6698 ) {
6699 (None, None) => {
6700 let end = if last_chunk_number == row_chunk.id {
6701 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6702 } else {
6703 Point::new(row_chunk.end, 0)
6704 };
6705 ranges_to_query.get_or_insert_with(Vec::new).push((
6706 row_chunk,
6707 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6708 ..buffer_snapshot.anchor_after(end),
6709 ));
6710 }
6711 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6712 (Some(cached_hints), None) => {
6713 for (server_id, cached_hints) in cached_hints {
6714 if for_server.is_none_or(|for_server| for_server == server_id) {
6715 cached_inlay_hints
6716 .get_or_insert_with(HashMap::default)
6717 .entry(row_chunk.start..row_chunk.end)
6718 .or_insert_with(HashMap::default)
6719 .entry(server_id)
6720 .or_insert_with(Vec::new)
6721 .extend(cached_hints);
6722 }
6723 }
6724 }
6725 (Some(cached_hints), Some(fetched_hints)) => {
6726 hint_fetch_tasks.push((row_chunk, fetched_hints));
6727 for (server_id, cached_hints) in cached_hints {
6728 if for_server.is_none_or(|for_server| for_server == server_id) {
6729 cached_inlay_hints
6730 .get_or_insert_with(HashMap::default)
6731 .entry(row_chunk.start..row_chunk.end)
6732 .or_insert_with(HashMap::default)
6733 .entry(server_id)
6734 .or_insert_with(Vec::new)
6735 .extend(cached_hints);
6736 }
6737 }
6738 }
6739 }
6740 }
6741
6742 if hint_fetch_tasks.is_empty()
6743 && ranges_to_query
6744 .as_ref()
6745 .is_none_or(|ranges| ranges.is_empty())
6746 && let Some(cached_inlay_hints) = cached_inlay_hints
6747 {
6748 cached_inlay_hints
6749 .into_iter()
6750 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6751 .collect()
6752 } else {
6753 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6754 let next_hint_id = next_hint_id.clone();
6755 let buffer = buffer.clone();
6756 let query_version = query_version.clone();
6757 let new_inlay_hints = cx
6758 .spawn(async move |lsp_store, cx| {
6759 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6760 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6761 })?;
6762 new_fetch_task
6763 .await
6764 .and_then(|new_hints_by_server| {
6765 lsp_store.update(cx, |lsp_store, cx| {
6766 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6767 let update_cache = lsp_data.buffer_version == query_version;
6768 if new_hints_by_server.is_empty() {
6769 if update_cache {
6770 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6771 }
6772 HashMap::default()
6773 } else {
6774 new_hints_by_server
6775 .into_iter()
6776 .map(|(server_id, new_hints)| {
6777 let new_hints = new_hints
6778 .into_iter()
6779 .map(|new_hint| {
6780 (
6781 InlayId::Hint(next_hint_id.fetch_add(
6782 1,
6783 atomic::Ordering::AcqRel,
6784 )),
6785 new_hint,
6786 )
6787 })
6788 .collect::<Vec<_>>();
6789 if update_cache {
6790 lsp_data.inlay_hints.insert_new_hints(
6791 chunk,
6792 server_id,
6793 new_hints.clone(),
6794 );
6795 }
6796 (server_id, new_hints)
6797 })
6798 .collect()
6799 }
6800 })
6801 })
6802 .map_err(Arc::new)
6803 })
6804 .shared();
6805
6806 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6807 *fetch_task = Some(new_inlay_hints.clone());
6808 hint_fetch_tasks.push((chunk, new_inlay_hints));
6809 }
6810
6811 cached_inlay_hints
6812 .unwrap_or_default()
6813 .into_iter()
6814 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6815 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6816 (
6817 chunk.start..chunk.end,
6818 cx.spawn(async move |_, _| {
6819 hints_fetch.await.map_err(|e| {
6820 if e.error_code() != ErrorCode::Internal {
6821 anyhow!(e.error_code())
6822 } else {
6823 anyhow!("{e:#}")
6824 }
6825 })
6826 }),
6827 )
6828 }))
6829 .collect()
6830 }
6831 }
6832
6833 fn fetch_inlay_hints(
6834 &mut self,
6835 for_server: Option<LanguageServerId>,
6836 buffer: &Entity<Buffer>,
6837 range: Range<Anchor>,
6838 cx: &mut Context<Self>,
6839 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6840 let request = InlayHints {
6841 range: range.clone(),
6842 };
6843 if let Some((upstream_client, project_id)) = self.upstream_client() {
6844 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6845 return Task::ready(Ok(HashMap::default()));
6846 }
6847 let request_task = upstream_client.request_lsp(
6848 project_id,
6849 for_server.map(|id| id.to_proto()),
6850 LSP_REQUEST_TIMEOUT,
6851 cx.background_executor().clone(),
6852 request.to_proto(project_id, buffer.read(cx)),
6853 );
6854 let buffer = buffer.clone();
6855 cx.spawn(async move |weak_lsp_store, cx| {
6856 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6857 return Ok(HashMap::default());
6858 };
6859 let Some(responses) = request_task.await? else {
6860 return Ok(HashMap::default());
6861 };
6862
6863 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6864 let lsp_store = lsp_store.clone();
6865 let buffer = buffer.clone();
6866 let cx = cx.clone();
6867 let request = request.clone();
6868 async move {
6869 (
6870 LanguageServerId::from_proto(response.server_id),
6871 request
6872 .response_from_proto(response.response, lsp_store, buffer, cx)
6873 .await,
6874 )
6875 }
6876 }))
6877 .await;
6878
6879 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
6880 let mut has_errors = false;
6881 let inlay_hints = inlay_hints
6882 .into_iter()
6883 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6884 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6885 Err(e) => {
6886 has_errors = true;
6887 log::error!("{e:#}");
6888 None
6889 }
6890 })
6891 .map(|(server_id, mut new_hints)| {
6892 new_hints.retain(|hint| {
6893 hint.position.is_valid(&buffer_snapshot)
6894 && range.start.is_valid(&buffer_snapshot)
6895 && range.end.is_valid(&buffer_snapshot)
6896 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6897 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6898 });
6899 (server_id, new_hints)
6900 })
6901 .collect::<HashMap<_, _>>();
6902 anyhow::ensure!(
6903 !has_errors || !inlay_hints.is_empty(),
6904 "Failed to fetch inlay hints"
6905 );
6906 Ok(inlay_hints)
6907 })
6908 } else {
6909 let inlay_hints_task = match for_server {
6910 Some(server_id) => {
6911 let server_task = self.request_lsp(
6912 buffer.clone(),
6913 LanguageServerToQuery::Other(server_id),
6914 request,
6915 cx,
6916 );
6917 cx.background_spawn(async move {
6918 let mut responses = Vec::new();
6919 match server_task.await {
6920 Ok(response) => responses.push((server_id, response)),
6921 Err(e) => log::error!(
6922 "Error handling response for inlay hints request: {e:#}"
6923 ),
6924 }
6925 responses
6926 })
6927 }
6928 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6929 };
6930 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6931 cx.background_spawn(async move {
6932 Ok(inlay_hints_task
6933 .await
6934 .into_iter()
6935 .map(|(server_id, mut new_hints)| {
6936 new_hints.retain(|hint| {
6937 hint.position.is_valid(&buffer_snapshot)
6938 && range.start.is_valid(&buffer_snapshot)
6939 && range.end.is_valid(&buffer_snapshot)
6940 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6941 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6942 });
6943 (server_id, new_hints)
6944 })
6945 .collect())
6946 })
6947 }
6948 }
6949
6950 pub fn pull_diagnostics_for_buffer(
6951 &mut self,
6952 buffer: Entity<Buffer>,
6953 cx: &mut Context<Self>,
6954 ) -> Task<anyhow::Result<()>> {
6955 let diagnostics = self.pull_diagnostics(buffer, cx);
6956 cx.spawn(async move |lsp_store, cx| {
6957 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6958 return Ok(());
6959 };
6960 lsp_store.update(cx, |lsp_store, cx| {
6961 if lsp_store.as_local().is_none() {
6962 return;
6963 }
6964
6965 let mut unchanged_buffers = HashSet::default();
6966 let mut changed_buffers = HashSet::default();
6967 let server_diagnostics_updates = diagnostics
6968 .into_iter()
6969 .filter_map(|diagnostics_set| match diagnostics_set {
6970 LspPullDiagnostics::Response {
6971 server_id,
6972 uri,
6973 diagnostics,
6974 } => Some((server_id, uri, diagnostics)),
6975 LspPullDiagnostics::Default => None,
6976 })
6977 .fold(
6978 HashMap::default(),
6979 |mut acc, (server_id, uri, diagnostics)| {
6980 let (result_id, diagnostics) = match diagnostics {
6981 PulledDiagnostics::Unchanged { result_id } => {
6982 unchanged_buffers.insert(uri.clone());
6983 (Some(result_id), Vec::new())
6984 }
6985 PulledDiagnostics::Changed {
6986 result_id,
6987 diagnostics,
6988 } => {
6989 changed_buffers.insert(uri.clone());
6990 (result_id, diagnostics)
6991 }
6992 };
6993 let disk_based_sources = Cow::Owned(
6994 lsp_store
6995 .language_server_adapter_for_id(server_id)
6996 .as_ref()
6997 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6998 .unwrap_or(&[])
6999 .to_vec(),
7000 );
7001 acc.entry(server_id).or_insert_with(Vec::new).push(
7002 DocumentDiagnosticsUpdate {
7003 server_id,
7004 diagnostics: lsp::PublishDiagnosticsParams {
7005 uri,
7006 diagnostics,
7007 version: None,
7008 },
7009 result_id,
7010 disk_based_sources,
7011 },
7012 );
7013 acc
7014 },
7015 );
7016
7017 for diagnostic_updates in server_diagnostics_updates.into_values() {
7018 lsp_store
7019 .merge_lsp_diagnostics(
7020 DiagnosticSourceKind::Pulled,
7021 diagnostic_updates,
7022 |buffer, old_diagnostic, cx| {
7023 File::from_dyn(buffer.file())
7024 .and_then(|file| {
7025 let abs_path = file.as_local()?.abs_path(cx);
7026 lsp::Uri::from_file_path(abs_path).ok()
7027 })
7028 .is_none_or(|buffer_uri| {
7029 unchanged_buffers.contains(&buffer_uri)
7030 || match old_diagnostic.source_kind {
7031 DiagnosticSourceKind::Pulled => {
7032 !changed_buffers.contains(&buffer_uri)
7033 }
7034 DiagnosticSourceKind::Other
7035 | DiagnosticSourceKind::Pushed => true,
7036 }
7037 })
7038 },
7039 cx,
7040 )
7041 .log_err();
7042 }
7043 })
7044 })
7045 }
7046
7047 pub fn document_colors(
7048 &mut self,
7049 known_cache_version: Option<usize>,
7050 buffer: Entity<Buffer>,
7051 cx: &mut Context<Self>,
7052 ) -> Option<DocumentColorTask> {
7053 let version_queried_for = buffer.read(cx).version();
7054 let buffer_id = buffer.read(cx).remote_id();
7055
7056 let current_language_servers = self.as_local().map(|local| {
7057 local
7058 .buffers_opened_in_servers
7059 .get(&buffer_id)
7060 .cloned()
7061 .unwrap_or_default()
7062 });
7063
7064 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7065 if let Some(cached_colors) = &lsp_data.document_colors {
7066 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7067 let has_different_servers =
7068 current_language_servers.is_some_and(|current_language_servers| {
7069 current_language_servers
7070 != cached_colors.colors.keys().copied().collect()
7071 });
7072 if !has_different_servers {
7073 let cache_version = cached_colors.cache_version;
7074 if Some(cache_version) == known_cache_version {
7075 return None;
7076 } else {
7077 return Some(
7078 Task::ready(Ok(DocumentColors {
7079 colors: cached_colors
7080 .colors
7081 .values()
7082 .flatten()
7083 .cloned()
7084 .collect(),
7085 cache_version: Some(cache_version),
7086 }))
7087 .shared(),
7088 );
7089 }
7090 }
7091 }
7092 }
7093 }
7094
7095 let color_lsp_data = self
7096 .latest_lsp_data(&buffer, cx)
7097 .document_colors
7098 .get_or_insert_default();
7099 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7100 && !version_queried_for.changed_since(updating_for)
7101 {
7102 return Some(running_update.clone());
7103 }
7104 let buffer_version_queried_for = version_queried_for.clone();
7105 let new_task = cx
7106 .spawn(async move |lsp_store, cx| {
7107 cx.background_executor()
7108 .timer(Duration::from_millis(30))
7109 .await;
7110 let fetched_colors = lsp_store
7111 .update(cx, |lsp_store, cx| {
7112 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7113 })?
7114 .await
7115 .context("fetching document colors")
7116 .map_err(Arc::new);
7117 let fetched_colors = match fetched_colors {
7118 Ok(fetched_colors) => {
7119 if Some(true)
7120 == buffer
7121 .update(cx, |buffer, _| {
7122 buffer.version() != buffer_version_queried_for
7123 })
7124 .ok()
7125 {
7126 return Ok(DocumentColors::default());
7127 }
7128 fetched_colors
7129 }
7130 Err(e) => {
7131 lsp_store
7132 .update(cx, |lsp_store, _| {
7133 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7134 if let Some(document_colors) = &mut lsp_data.document_colors {
7135 document_colors.colors_update = None;
7136 }
7137 }
7138 })
7139 .ok();
7140 return Err(e);
7141 }
7142 };
7143
7144 lsp_store
7145 .update(cx, |lsp_store, cx| {
7146 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7147 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7148
7149 if let Some(fetched_colors) = fetched_colors {
7150 if lsp_data.buffer_version == buffer_version_queried_for {
7151 lsp_colors.colors.extend(fetched_colors);
7152 lsp_colors.cache_version += 1;
7153 } else if !lsp_data
7154 .buffer_version
7155 .changed_since(&buffer_version_queried_for)
7156 {
7157 lsp_data.buffer_version = buffer_version_queried_for;
7158 lsp_colors.colors = fetched_colors;
7159 lsp_colors.cache_version += 1;
7160 }
7161 }
7162 lsp_colors.colors_update = None;
7163 let colors = lsp_colors
7164 .colors
7165 .values()
7166 .flatten()
7167 .cloned()
7168 .collect::<HashSet<_>>();
7169 DocumentColors {
7170 colors,
7171 cache_version: Some(lsp_colors.cache_version),
7172 }
7173 })
7174 .map_err(Arc::new)
7175 })
7176 .shared();
7177 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7178 Some(new_task)
7179 }
7180
7181 fn fetch_document_colors_for_buffer(
7182 &mut self,
7183 buffer: &Entity<Buffer>,
7184 cx: &mut Context<Self>,
7185 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7186 if let Some((client, project_id)) = self.upstream_client() {
7187 let request = GetDocumentColor {};
7188 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7189 return Task::ready(Ok(None));
7190 }
7191
7192 let request_task = client.request_lsp(
7193 project_id,
7194 None,
7195 LSP_REQUEST_TIMEOUT,
7196 cx.background_executor().clone(),
7197 request.to_proto(project_id, buffer.read(cx)),
7198 );
7199 let buffer = buffer.clone();
7200 cx.spawn(async move |lsp_store, cx| {
7201 let Some(lsp_store) = lsp_store.upgrade() else {
7202 return Ok(None);
7203 };
7204 let colors = join_all(
7205 request_task
7206 .await
7207 .log_err()
7208 .flatten()
7209 .map(|response| response.payload)
7210 .unwrap_or_default()
7211 .into_iter()
7212 .map(|color_response| {
7213 let response = request.response_from_proto(
7214 color_response.response,
7215 lsp_store.clone(),
7216 buffer.clone(),
7217 cx.clone(),
7218 );
7219 async move {
7220 (
7221 LanguageServerId::from_proto(color_response.server_id),
7222 response.await.log_err().unwrap_or_default(),
7223 )
7224 }
7225 }),
7226 )
7227 .await
7228 .into_iter()
7229 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7230 acc.entry(server_id)
7231 .or_insert_with(HashSet::default)
7232 .extend(colors);
7233 acc
7234 });
7235 Ok(Some(colors))
7236 })
7237 } else {
7238 let document_colors_task =
7239 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7240 cx.background_spawn(async move {
7241 Ok(Some(
7242 document_colors_task
7243 .await
7244 .into_iter()
7245 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7246 acc.entry(server_id)
7247 .or_insert_with(HashSet::default)
7248 .extend(colors);
7249 acc
7250 })
7251 .into_iter()
7252 .collect(),
7253 ))
7254 })
7255 }
7256 }
7257
7258 pub fn signature_help<T: ToPointUtf16>(
7259 &mut self,
7260 buffer: &Entity<Buffer>,
7261 position: T,
7262 cx: &mut Context<Self>,
7263 ) -> Task<Option<Vec<SignatureHelp>>> {
7264 let position = position.to_point_utf16(buffer.read(cx));
7265
7266 if let Some((client, upstream_project_id)) = self.upstream_client() {
7267 let request = GetSignatureHelp { position };
7268 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7269 return Task::ready(None);
7270 }
7271 let request_task = client.request_lsp(
7272 upstream_project_id,
7273 None,
7274 LSP_REQUEST_TIMEOUT,
7275 cx.background_executor().clone(),
7276 request.to_proto(upstream_project_id, buffer.read(cx)),
7277 );
7278 let buffer = buffer.clone();
7279 cx.spawn(async move |weak_lsp_store, cx| {
7280 let lsp_store = weak_lsp_store.upgrade()?;
7281 let signatures = join_all(
7282 request_task
7283 .await
7284 .log_err()
7285 .flatten()
7286 .map(|response| response.payload)
7287 .unwrap_or_default()
7288 .into_iter()
7289 .map(|response| {
7290 let response = GetSignatureHelp { position }.response_from_proto(
7291 response.response,
7292 lsp_store.clone(),
7293 buffer.clone(),
7294 cx.clone(),
7295 );
7296 async move { response.await.log_err().flatten() }
7297 }),
7298 )
7299 .await
7300 .into_iter()
7301 .flatten()
7302 .collect();
7303 Some(signatures)
7304 })
7305 } else {
7306 let all_actions_task = self.request_multiple_lsp_locally(
7307 buffer,
7308 Some(position),
7309 GetSignatureHelp { position },
7310 cx,
7311 );
7312 cx.background_spawn(async move {
7313 Some(
7314 all_actions_task
7315 .await
7316 .into_iter()
7317 .flat_map(|(_, actions)| actions)
7318 .collect::<Vec<_>>(),
7319 )
7320 })
7321 }
7322 }
7323
7324 pub fn hover(
7325 &mut self,
7326 buffer: &Entity<Buffer>,
7327 position: PointUtf16,
7328 cx: &mut Context<Self>,
7329 ) -> Task<Option<Vec<Hover>>> {
7330 if let Some((client, upstream_project_id)) = self.upstream_client() {
7331 let request = GetHover { position };
7332 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7333 return Task::ready(None);
7334 }
7335 let request_task = client.request_lsp(
7336 upstream_project_id,
7337 None,
7338 LSP_REQUEST_TIMEOUT,
7339 cx.background_executor().clone(),
7340 request.to_proto(upstream_project_id, buffer.read(cx)),
7341 );
7342 let buffer = buffer.clone();
7343 cx.spawn(async move |weak_lsp_store, cx| {
7344 let lsp_store = weak_lsp_store.upgrade()?;
7345 let hovers = join_all(
7346 request_task
7347 .await
7348 .log_err()
7349 .flatten()
7350 .map(|response| response.payload)
7351 .unwrap_or_default()
7352 .into_iter()
7353 .map(|response| {
7354 let response = GetHover { position }.response_from_proto(
7355 response.response,
7356 lsp_store.clone(),
7357 buffer.clone(),
7358 cx.clone(),
7359 );
7360 async move {
7361 response
7362 .await
7363 .log_err()
7364 .flatten()
7365 .and_then(remove_empty_hover_blocks)
7366 }
7367 }),
7368 )
7369 .await
7370 .into_iter()
7371 .flatten()
7372 .collect();
7373 Some(hovers)
7374 })
7375 } else {
7376 let all_actions_task = self.request_multiple_lsp_locally(
7377 buffer,
7378 Some(position),
7379 GetHover { position },
7380 cx,
7381 );
7382 cx.background_spawn(async move {
7383 Some(
7384 all_actions_task
7385 .await
7386 .into_iter()
7387 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7388 .collect::<Vec<Hover>>(),
7389 )
7390 })
7391 }
7392 }
7393
7394 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7395 let language_registry = self.languages.clone();
7396
7397 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7398 let request = upstream_client.request(proto::GetProjectSymbols {
7399 project_id: *project_id,
7400 query: query.to_string(),
7401 });
7402 cx.foreground_executor().spawn(async move {
7403 let response = request.await?;
7404 let mut symbols = Vec::new();
7405 let core_symbols = response
7406 .symbols
7407 .into_iter()
7408 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7409 .collect::<Vec<_>>();
7410 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7411 .await;
7412 Ok(symbols)
7413 })
7414 } else if let Some(local) = self.as_local() {
7415 struct WorkspaceSymbolsResult {
7416 server_id: LanguageServerId,
7417 lsp_adapter: Arc<CachedLspAdapter>,
7418 worktree: WeakEntity<Worktree>,
7419 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7420 }
7421
7422 let mut requests = Vec::new();
7423 let mut requested_servers = BTreeSet::new();
7424 for (seed, state) in local.language_server_ids.iter() {
7425 let Some(worktree_handle) = self
7426 .worktree_store
7427 .read(cx)
7428 .worktree_for_id(seed.worktree_id, cx)
7429 else {
7430 continue;
7431 };
7432 let worktree = worktree_handle.read(cx);
7433 if !worktree.is_visible() {
7434 continue;
7435 }
7436
7437 if !requested_servers.insert(state.id) {
7438 continue;
7439 }
7440
7441 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7442 Some(LanguageServerState::Running {
7443 adapter, server, ..
7444 }) => (adapter.clone(), server),
7445
7446 _ => continue,
7447 };
7448 let supports_workspace_symbol_request =
7449 match server.capabilities().workspace_symbol_provider {
7450 Some(OneOf::Left(supported)) => supported,
7451 Some(OneOf::Right(_)) => true,
7452 None => false,
7453 };
7454 if !supports_workspace_symbol_request {
7455 continue;
7456 }
7457 let worktree_handle = worktree_handle.clone();
7458 let server_id = server.server_id();
7459 requests.push(
7460 server
7461 .request::<lsp::request::WorkspaceSymbolRequest>(
7462 lsp::WorkspaceSymbolParams {
7463 query: query.to_string(),
7464 ..Default::default()
7465 },
7466 )
7467 .map(move |response| {
7468 let lsp_symbols = response.into_response()
7469 .context("workspace symbols request")
7470 .log_err()
7471 .flatten()
7472 .map(|symbol_response| match symbol_response {
7473 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7474 flat_responses.into_iter().map(|lsp_symbol| {
7475 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7476 }).collect::<Vec<_>>()
7477 }
7478 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7479 nested_responses.into_iter().filter_map(|lsp_symbol| {
7480 let location = match lsp_symbol.location {
7481 OneOf::Left(location) => location,
7482 OneOf::Right(_) => {
7483 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7484 return None
7485 }
7486 };
7487 Some((lsp_symbol.name, lsp_symbol.kind, location))
7488 }).collect::<Vec<_>>()
7489 }
7490 }).unwrap_or_default();
7491
7492 WorkspaceSymbolsResult {
7493 server_id,
7494 lsp_adapter,
7495 worktree: worktree_handle.downgrade(),
7496 lsp_symbols,
7497 }
7498 }),
7499 );
7500 }
7501
7502 cx.spawn(async move |this, cx| {
7503 let responses = futures::future::join_all(requests).await;
7504 let this = match this.upgrade() {
7505 Some(this) => this,
7506 None => return Ok(Vec::new()),
7507 };
7508
7509 let mut symbols = Vec::new();
7510 for result in responses {
7511 let core_symbols = this.update(cx, |this, cx| {
7512 result
7513 .lsp_symbols
7514 .into_iter()
7515 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7516 let abs_path = symbol_location.uri.to_file_path().ok()?;
7517 let source_worktree = result.worktree.upgrade()?;
7518 let source_worktree_id = source_worktree.read(cx).id();
7519
7520 let path = if let Some((tree, rel_path)) =
7521 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7522 {
7523 let worktree_id = tree.read(cx).id();
7524 SymbolLocation::InProject(ProjectPath {
7525 worktree_id,
7526 path: rel_path,
7527 })
7528 } else {
7529 SymbolLocation::OutsideProject {
7530 signature: this.symbol_signature(&abs_path),
7531 abs_path: abs_path.into(),
7532 }
7533 };
7534
7535 Some(CoreSymbol {
7536 source_language_server_id: result.server_id,
7537 language_server_name: result.lsp_adapter.name.clone(),
7538 source_worktree_id,
7539 path,
7540 kind: symbol_kind,
7541 name: symbol_name,
7542 range: range_from_lsp(symbol_location.range),
7543 })
7544 })
7545 .collect()
7546 })?;
7547
7548 populate_labels_for_symbols(
7549 core_symbols,
7550 &language_registry,
7551 Some(result.lsp_adapter),
7552 &mut symbols,
7553 )
7554 .await;
7555 }
7556
7557 Ok(symbols)
7558 })
7559 } else {
7560 Task::ready(Err(anyhow!("No upstream client or local language server")))
7561 }
7562 }
7563
7564 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7565 let mut summary = DiagnosticSummary::default();
7566 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7567 summary.error_count += path_summary.error_count;
7568 summary.warning_count += path_summary.warning_count;
7569 }
7570 summary
7571 }
7572
7573 /// Returns the diagnostic summary for a specific project path.
7574 pub fn diagnostic_summary_for_path(
7575 &self,
7576 project_path: &ProjectPath,
7577 _: &App,
7578 ) -> DiagnosticSummary {
7579 if let Some(summaries) = self
7580 .diagnostic_summaries
7581 .get(&project_path.worktree_id)
7582 .and_then(|map| map.get(&project_path.path))
7583 {
7584 let (error_count, warning_count) = summaries.iter().fold(
7585 (0, 0),
7586 |(error_count, warning_count), (_language_server_id, summary)| {
7587 (
7588 error_count + summary.error_count,
7589 warning_count + summary.warning_count,
7590 )
7591 },
7592 );
7593
7594 DiagnosticSummary {
7595 error_count,
7596 warning_count,
7597 }
7598 } else {
7599 DiagnosticSummary::default()
7600 }
7601 }
7602
7603 pub fn diagnostic_summaries<'a>(
7604 &'a self,
7605 include_ignored: bool,
7606 cx: &'a App,
7607 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7608 self.worktree_store
7609 .read(cx)
7610 .visible_worktrees(cx)
7611 .filter_map(|worktree| {
7612 let worktree = worktree.read(cx);
7613 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7614 })
7615 .flat_map(move |(worktree, summaries)| {
7616 let worktree_id = worktree.id();
7617 summaries
7618 .iter()
7619 .filter(move |(path, _)| {
7620 include_ignored
7621 || worktree
7622 .entry_for_path(path.as_ref())
7623 .is_some_and(|entry| !entry.is_ignored)
7624 })
7625 .flat_map(move |(path, summaries)| {
7626 summaries.iter().map(move |(server_id, summary)| {
7627 (
7628 ProjectPath {
7629 worktree_id,
7630 path: path.clone(),
7631 },
7632 *server_id,
7633 *summary,
7634 )
7635 })
7636 })
7637 })
7638 }
7639
7640 pub fn on_buffer_edited(
7641 &mut self,
7642 buffer: Entity<Buffer>,
7643 cx: &mut Context<Self>,
7644 ) -> Option<()> {
7645 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7646 Some(
7647 self.as_local()?
7648 .language_servers_for_buffer(buffer, cx)
7649 .map(|i| i.1.clone())
7650 .collect(),
7651 )
7652 })?;
7653
7654 let buffer = buffer.read(cx);
7655 let file = File::from_dyn(buffer.file())?;
7656 let abs_path = file.as_local()?.abs_path(cx);
7657 let uri = lsp::Uri::from_file_path(&abs_path)
7658 .ok()
7659 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7660 .unwrap();
7661 let next_snapshot = buffer.text_snapshot();
7662 for language_server in language_servers {
7663 let language_server = language_server.clone();
7664
7665 let buffer_snapshots = self
7666 .as_local_mut()
7667 .unwrap()
7668 .buffer_snapshots
7669 .get_mut(&buffer.remote_id())
7670 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7671 let previous_snapshot = buffer_snapshots.last()?;
7672
7673 let build_incremental_change = || {
7674 buffer
7675 .edits_since::<Dimensions<PointUtf16, usize>>(
7676 previous_snapshot.snapshot.version(),
7677 )
7678 .map(|edit| {
7679 let edit_start = edit.new.start.0;
7680 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7681 let new_text = next_snapshot
7682 .text_for_range(edit.new.start.1..edit.new.end.1)
7683 .collect();
7684 lsp::TextDocumentContentChangeEvent {
7685 range: Some(lsp::Range::new(
7686 point_to_lsp(edit_start),
7687 point_to_lsp(edit_end),
7688 )),
7689 range_length: None,
7690 text: new_text,
7691 }
7692 })
7693 .collect()
7694 };
7695
7696 let document_sync_kind = language_server
7697 .capabilities()
7698 .text_document_sync
7699 .as_ref()
7700 .and_then(|sync| match sync {
7701 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7702 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7703 });
7704
7705 let content_changes: Vec<_> = match document_sync_kind {
7706 Some(lsp::TextDocumentSyncKind::FULL) => {
7707 vec![lsp::TextDocumentContentChangeEvent {
7708 range: None,
7709 range_length: None,
7710 text: next_snapshot.text(),
7711 }]
7712 }
7713 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7714 _ => {
7715 #[cfg(any(test, feature = "test-support"))]
7716 {
7717 build_incremental_change()
7718 }
7719
7720 #[cfg(not(any(test, feature = "test-support")))]
7721 {
7722 continue;
7723 }
7724 }
7725 };
7726
7727 let next_version = previous_snapshot.version + 1;
7728 buffer_snapshots.push(LspBufferSnapshot {
7729 version: next_version,
7730 snapshot: next_snapshot.clone(),
7731 });
7732
7733 language_server
7734 .notify::<lsp::notification::DidChangeTextDocument>(
7735 lsp::DidChangeTextDocumentParams {
7736 text_document: lsp::VersionedTextDocumentIdentifier::new(
7737 uri.clone(),
7738 next_version,
7739 ),
7740 content_changes,
7741 },
7742 )
7743 .ok();
7744 self.pull_workspace_diagnostics(language_server.server_id());
7745 }
7746
7747 None
7748 }
7749
7750 pub fn on_buffer_saved(
7751 &mut self,
7752 buffer: Entity<Buffer>,
7753 cx: &mut Context<Self>,
7754 ) -> Option<()> {
7755 let file = File::from_dyn(buffer.read(cx).file())?;
7756 let worktree_id = file.worktree_id(cx);
7757 let abs_path = file.as_local()?.abs_path(cx);
7758 let text_document = lsp::TextDocumentIdentifier {
7759 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7760 };
7761 let local = self.as_local()?;
7762
7763 for server in local.language_servers_for_worktree(worktree_id) {
7764 if let Some(include_text) = include_text(server.as_ref()) {
7765 let text = if include_text {
7766 Some(buffer.read(cx).text())
7767 } else {
7768 None
7769 };
7770 server
7771 .notify::<lsp::notification::DidSaveTextDocument>(
7772 lsp::DidSaveTextDocumentParams {
7773 text_document: text_document.clone(),
7774 text,
7775 },
7776 )
7777 .ok();
7778 }
7779 }
7780
7781 let language_servers = buffer.update(cx, |buffer, cx| {
7782 local.language_server_ids_for_buffer(buffer, cx)
7783 });
7784 for language_server_id in language_servers {
7785 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7786 }
7787
7788 None
7789 }
7790
7791 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7792 maybe!(async move {
7793 let mut refreshed_servers = HashSet::default();
7794 let servers = lsp_store
7795 .update(cx, |lsp_store, cx| {
7796 let local = lsp_store.as_local()?;
7797
7798 let servers = local
7799 .language_server_ids
7800 .iter()
7801 .filter_map(|(seed, state)| {
7802 let worktree = lsp_store
7803 .worktree_store
7804 .read(cx)
7805 .worktree_for_id(seed.worktree_id, cx);
7806 let delegate: Arc<dyn LspAdapterDelegate> =
7807 worktree.map(|worktree| {
7808 LocalLspAdapterDelegate::new(
7809 local.languages.clone(),
7810 &local.environment,
7811 cx.weak_entity(),
7812 &worktree,
7813 local.http_client.clone(),
7814 local.fs.clone(),
7815 cx,
7816 )
7817 })?;
7818 let server_id = state.id;
7819
7820 let states = local.language_servers.get(&server_id)?;
7821
7822 match states {
7823 LanguageServerState::Starting { .. } => None,
7824 LanguageServerState::Running {
7825 adapter, server, ..
7826 } => {
7827 let adapter = adapter.clone();
7828 let server = server.clone();
7829 refreshed_servers.insert(server.name());
7830 let toolchain = seed.toolchain.clone();
7831 Some(cx.spawn(async move |_, cx| {
7832 let settings =
7833 LocalLspStore::workspace_configuration_for_adapter(
7834 adapter.adapter.clone(),
7835 &delegate,
7836 toolchain,
7837 cx,
7838 )
7839 .await
7840 .ok()?;
7841 server
7842 .notify::<lsp::notification::DidChangeConfiguration>(
7843 lsp::DidChangeConfigurationParams { settings },
7844 )
7845 .ok()?;
7846 Some(())
7847 }))
7848 }
7849 }
7850 })
7851 .collect::<Vec<_>>();
7852
7853 Some(servers)
7854 })
7855 .ok()
7856 .flatten()?;
7857
7858 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7859 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7860 // to stop and unregister its language server wrapper.
7861 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7862 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7863 let _: Vec<Option<()>> = join_all(servers).await;
7864
7865 Some(())
7866 })
7867 .await;
7868 }
7869
7870 fn maintain_workspace_config(
7871 external_refresh_requests: watch::Receiver<()>,
7872 cx: &mut Context<Self>,
7873 ) -> Task<Result<()>> {
7874 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7875 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7876
7877 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7878 *settings_changed_tx.borrow_mut() = ();
7879 });
7880
7881 let mut joint_future =
7882 futures::stream::select(settings_changed_rx, external_refresh_requests);
7883 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7884 // - 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).
7885 // - 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.
7886 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7887 // - 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,
7888 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7889 cx.spawn(async move |this, cx| {
7890 while let Some(()) = joint_future.next().await {
7891 this.update(cx, |this, cx| {
7892 this.refresh_server_tree(cx);
7893 })
7894 .ok();
7895
7896 Self::refresh_workspace_configurations(&this, cx).await;
7897 }
7898
7899 drop(settings_observation);
7900 anyhow::Ok(())
7901 })
7902 }
7903
7904 pub fn language_servers_for_local_buffer<'a>(
7905 &'a self,
7906 buffer: &Buffer,
7907 cx: &mut App,
7908 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7909 let local = self.as_local();
7910 let language_server_ids = local
7911 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7912 .unwrap_or_default();
7913
7914 language_server_ids
7915 .into_iter()
7916 .filter_map(
7917 move |server_id| match local?.language_servers.get(&server_id)? {
7918 LanguageServerState::Running {
7919 adapter, server, ..
7920 } => Some((adapter, server)),
7921 _ => None,
7922 },
7923 )
7924 }
7925
7926 pub fn language_server_for_local_buffer<'a>(
7927 &'a self,
7928 buffer: &'a Buffer,
7929 server_id: LanguageServerId,
7930 cx: &'a mut App,
7931 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7932 self.as_local()?
7933 .language_servers_for_buffer(buffer, cx)
7934 .find(|(_, s)| s.server_id() == server_id)
7935 }
7936
7937 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7938 self.diagnostic_summaries.remove(&id_to_remove);
7939 if let Some(local) = self.as_local_mut() {
7940 let to_remove = local.remove_worktree(id_to_remove, cx);
7941 for server in to_remove {
7942 self.language_server_statuses.remove(&server);
7943 }
7944 }
7945 }
7946
7947 pub fn shared(
7948 &mut self,
7949 project_id: u64,
7950 downstream_client: AnyProtoClient,
7951 _: &mut Context<Self>,
7952 ) {
7953 self.downstream_client = Some((downstream_client.clone(), project_id));
7954
7955 for (server_id, status) in &self.language_server_statuses {
7956 if let Some(server) = self.language_server_for_id(*server_id) {
7957 downstream_client
7958 .send(proto::StartLanguageServer {
7959 project_id,
7960 server: Some(proto::LanguageServer {
7961 id: server_id.to_proto(),
7962 name: status.name.to_string(),
7963 worktree_id: status.worktree.map(|id| id.to_proto()),
7964 }),
7965 capabilities: serde_json::to_string(&server.capabilities())
7966 .expect("serializing server LSP capabilities"),
7967 })
7968 .log_err();
7969 }
7970 }
7971 }
7972
7973 pub fn disconnected_from_host(&mut self) {
7974 self.downstream_client.take();
7975 }
7976
7977 pub fn disconnected_from_ssh_remote(&mut self) {
7978 if let LspStoreMode::Remote(RemoteLspStore {
7979 upstream_client, ..
7980 }) = &mut self.mode
7981 {
7982 upstream_client.take();
7983 }
7984 }
7985
7986 pub(crate) fn set_language_server_statuses_from_proto(
7987 &mut self,
7988 project: WeakEntity<Project>,
7989 language_servers: Vec<proto::LanguageServer>,
7990 server_capabilities: Vec<String>,
7991 cx: &mut Context<Self>,
7992 ) {
7993 let lsp_logs = cx
7994 .try_global::<GlobalLogStore>()
7995 .map(|lsp_store| lsp_store.0.clone());
7996
7997 self.language_server_statuses = language_servers
7998 .into_iter()
7999 .zip(server_capabilities)
8000 .map(|(server, server_capabilities)| {
8001 let server_id = LanguageServerId(server.id as usize);
8002 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8003 self.lsp_server_capabilities
8004 .insert(server_id, server_capabilities);
8005 }
8006
8007 let name = LanguageServerName::from_proto(server.name);
8008 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8009
8010 if let Some(lsp_logs) = &lsp_logs {
8011 lsp_logs.update(cx, |lsp_logs, cx| {
8012 lsp_logs.add_language_server(
8013 // Only remote clients get their language servers set from proto
8014 LanguageServerKind::Remote {
8015 project: project.clone(),
8016 },
8017 server_id,
8018 Some(name.clone()),
8019 worktree,
8020 None,
8021 cx,
8022 );
8023 });
8024 }
8025
8026 (
8027 server_id,
8028 LanguageServerStatus {
8029 name,
8030 pending_work: Default::default(),
8031 has_pending_diagnostic_updates: false,
8032 progress_tokens: Default::default(),
8033 worktree,
8034 },
8035 )
8036 })
8037 .collect();
8038 }
8039
8040 #[cfg(test)]
8041 pub fn update_diagnostic_entries(
8042 &mut self,
8043 server_id: LanguageServerId,
8044 abs_path: PathBuf,
8045 result_id: Option<String>,
8046 version: Option<i32>,
8047 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8048 cx: &mut Context<Self>,
8049 ) -> anyhow::Result<()> {
8050 self.merge_diagnostic_entries(
8051 vec![DocumentDiagnosticsUpdate {
8052 diagnostics: DocumentDiagnostics {
8053 diagnostics,
8054 document_abs_path: abs_path,
8055 version,
8056 },
8057 result_id,
8058 server_id,
8059 disk_based_sources: Cow::Borrowed(&[]),
8060 }],
8061 |_, _, _| false,
8062 cx,
8063 )?;
8064 Ok(())
8065 }
8066
8067 pub fn merge_diagnostic_entries<'a>(
8068 &mut self,
8069 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8070 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8071 cx: &mut Context<Self>,
8072 ) -> anyhow::Result<()> {
8073 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8074 let mut updated_diagnostics_paths = HashMap::default();
8075 for mut update in diagnostic_updates {
8076 let abs_path = &update.diagnostics.document_abs_path;
8077 let server_id = update.server_id;
8078 let Some((worktree, relative_path)) =
8079 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8080 else {
8081 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8082 return Ok(());
8083 };
8084
8085 let worktree_id = worktree.read(cx).id();
8086 let project_path = ProjectPath {
8087 worktree_id,
8088 path: relative_path,
8089 };
8090
8091 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8092 let snapshot = buffer_handle.read(cx).snapshot();
8093 let buffer = buffer_handle.read(cx);
8094 let reused_diagnostics = buffer
8095 .buffer_diagnostics(Some(server_id))
8096 .iter()
8097 .filter(|v| merge(buffer, &v.diagnostic, cx))
8098 .map(|v| {
8099 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8100 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8101 DiagnosticEntry {
8102 range: start..end,
8103 diagnostic: v.diagnostic.clone(),
8104 }
8105 })
8106 .collect::<Vec<_>>();
8107
8108 self.as_local_mut()
8109 .context("cannot merge diagnostics on a remote LspStore")?
8110 .update_buffer_diagnostics(
8111 &buffer_handle,
8112 server_id,
8113 update.result_id,
8114 update.diagnostics.version,
8115 update.diagnostics.diagnostics.clone(),
8116 reused_diagnostics.clone(),
8117 cx,
8118 )?;
8119
8120 update.diagnostics.diagnostics.extend(reused_diagnostics);
8121 }
8122
8123 let updated = worktree.update(cx, |worktree, cx| {
8124 self.update_worktree_diagnostics(
8125 worktree.id(),
8126 server_id,
8127 project_path.path.clone(),
8128 update.diagnostics.diagnostics,
8129 cx,
8130 )
8131 })?;
8132 match updated {
8133 ControlFlow::Continue(new_summary) => {
8134 if let Some((project_id, new_summary)) = new_summary {
8135 match &mut diagnostics_summary {
8136 Some(diagnostics_summary) => {
8137 diagnostics_summary
8138 .more_summaries
8139 .push(proto::DiagnosticSummary {
8140 path: project_path.path.as_ref().to_proto(),
8141 language_server_id: server_id.0 as u64,
8142 error_count: new_summary.error_count,
8143 warning_count: new_summary.warning_count,
8144 })
8145 }
8146 None => {
8147 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8148 project_id,
8149 worktree_id: worktree_id.to_proto(),
8150 summary: Some(proto::DiagnosticSummary {
8151 path: project_path.path.as_ref().to_proto(),
8152 language_server_id: server_id.0 as u64,
8153 error_count: new_summary.error_count,
8154 warning_count: new_summary.warning_count,
8155 }),
8156 more_summaries: Vec::new(),
8157 })
8158 }
8159 }
8160 }
8161 updated_diagnostics_paths
8162 .entry(server_id)
8163 .or_insert_with(Vec::new)
8164 .push(project_path);
8165 }
8166 ControlFlow::Break(()) => {}
8167 }
8168 }
8169
8170 if let Some((diagnostics_summary, (downstream_client, _))) =
8171 diagnostics_summary.zip(self.downstream_client.as_ref())
8172 {
8173 downstream_client.send(diagnostics_summary).log_err();
8174 }
8175 for (server_id, paths) in updated_diagnostics_paths {
8176 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8177 }
8178 Ok(())
8179 }
8180
8181 fn update_worktree_diagnostics(
8182 &mut self,
8183 worktree_id: WorktreeId,
8184 server_id: LanguageServerId,
8185 path_in_worktree: Arc<RelPath>,
8186 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8187 _: &mut Context<Worktree>,
8188 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8189 let local = match &mut self.mode {
8190 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8191 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8192 };
8193
8194 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8195 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8196 let summaries_by_server_id = summaries_for_tree
8197 .entry(path_in_worktree.clone())
8198 .or_default();
8199
8200 let old_summary = summaries_by_server_id
8201 .remove(&server_id)
8202 .unwrap_or_default();
8203
8204 let new_summary = DiagnosticSummary::new(&diagnostics);
8205 if new_summary.is_empty() {
8206 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8207 {
8208 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8209 diagnostics_by_server_id.remove(ix);
8210 }
8211 if diagnostics_by_server_id.is_empty() {
8212 diagnostics_for_tree.remove(&path_in_worktree);
8213 }
8214 }
8215 } else {
8216 summaries_by_server_id.insert(server_id, new_summary);
8217 let diagnostics_by_server_id = diagnostics_for_tree
8218 .entry(path_in_worktree.clone())
8219 .or_default();
8220 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8221 Ok(ix) => {
8222 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8223 }
8224 Err(ix) => {
8225 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8226 }
8227 }
8228 }
8229
8230 if !old_summary.is_empty() || !new_summary.is_empty() {
8231 if let Some((_, project_id)) = &self.downstream_client {
8232 Ok(ControlFlow::Continue(Some((
8233 *project_id,
8234 proto::DiagnosticSummary {
8235 path: path_in_worktree.to_proto(),
8236 language_server_id: server_id.0 as u64,
8237 error_count: new_summary.error_count as u32,
8238 warning_count: new_summary.warning_count as u32,
8239 },
8240 ))))
8241 } else {
8242 Ok(ControlFlow::Continue(None))
8243 }
8244 } else {
8245 Ok(ControlFlow::Break(()))
8246 }
8247 }
8248
8249 pub fn open_buffer_for_symbol(
8250 &mut self,
8251 symbol: &Symbol,
8252 cx: &mut Context<Self>,
8253 ) -> Task<Result<Entity<Buffer>>> {
8254 if let Some((client, project_id)) = self.upstream_client() {
8255 let request = client.request(proto::OpenBufferForSymbol {
8256 project_id,
8257 symbol: Some(Self::serialize_symbol(symbol)),
8258 });
8259 cx.spawn(async move |this, cx| {
8260 let response = request.await?;
8261 let buffer_id = BufferId::new(response.buffer_id)?;
8262 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8263 .await
8264 })
8265 } else if let Some(local) = self.as_local() {
8266 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8267 seed.worktree_id == symbol.source_worktree_id
8268 && state.id == symbol.source_language_server_id
8269 && symbol.language_server_name == seed.name
8270 });
8271 if !is_valid {
8272 return Task::ready(Err(anyhow!(
8273 "language server for worktree and language not found"
8274 )));
8275 };
8276
8277 let symbol_abs_path = match &symbol.path {
8278 SymbolLocation::InProject(project_path) => self
8279 .worktree_store
8280 .read(cx)
8281 .absolutize(&project_path, cx)
8282 .context("no such worktree"),
8283 SymbolLocation::OutsideProject {
8284 abs_path,
8285 signature: _,
8286 } => Ok(abs_path.to_path_buf()),
8287 };
8288 let symbol_abs_path = match symbol_abs_path {
8289 Ok(abs_path) => abs_path,
8290 Err(err) => return Task::ready(Err(err)),
8291 };
8292 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8293 uri
8294 } else {
8295 return Task::ready(Err(anyhow!("invalid symbol path")));
8296 };
8297
8298 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8299 } else {
8300 Task::ready(Err(anyhow!("no upstream client or local store")))
8301 }
8302 }
8303
8304 pub(crate) fn open_local_buffer_via_lsp(
8305 &mut self,
8306 abs_path: lsp::Uri,
8307 language_server_id: LanguageServerId,
8308 cx: &mut Context<Self>,
8309 ) -> Task<Result<Entity<Buffer>>> {
8310 cx.spawn(async move |lsp_store, cx| {
8311 // Escape percent-encoded string.
8312 let current_scheme = abs_path.scheme().to_owned();
8313 // Uri is immutable, so we can't modify the scheme
8314
8315 let abs_path = abs_path
8316 .to_file_path()
8317 .map_err(|()| anyhow!("can't convert URI to path"))?;
8318 let p = abs_path.clone();
8319 let yarn_worktree = lsp_store
8320 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8321 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8322 cx.spawn(async move |this, cx| {
8323 let t = this
8324 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8325 .ok()?;
8326 t.await
8327 })
8328 }),
8329 None => Task::ready(None),
8330 })?
8331 .await;
8332 let (worktree_root_target, known_relative_path) =
8333 if let Some((zip_root, relative_path)) = yarn_worktree {
8334 (zip_root, Some(relative_path))
8335 } else {
8336 (Arc::<Path>::from(abs_path.as_path()), None)
8337 };
8338 let (worktree, relative_path) = if let Some(result) =
8339 lsp_store.update(cx, |lsp_store, cx| {
8340 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8341 worktree_store.find_worktree(&worktree_root_target, cx)
8342 })
8343 })? {
8344 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8345 (result.0, relative_path)
8346 } else {
8347 let worktree = lsp_store
8348 .update(cx, |lsp_store, cx| {
8349 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8350 worktree_store.create_worktree(&worktree_root_target, false, cx)
8351 })
8352 })?
8353 .await?;
8354 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8355 lsp_store
8356 .update(cx, |lsp_store, cx| {
8357 if let Some(local) = lsp_store.as_local_mut() {
8358 local.register_language_server_for_invisible_worktree(
8359 &worktree,
8360 language_server_id,
8361 cx,
8362 )
8363 }
8364 })
8365 .ok();
8366 }
8367 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8368 let relative_path = if let Some(known_path) = known_relative_path {
8369 known_path
8370 } else {
8371 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8372 .into_arc()
8373 };
8374 (worktree, relative_path)
8375 };
8376 let project_path = ProjectPath {
8377 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8378 path: relative_path,
8379 };
8380 lsp_store
8381 .update(cx, |lsp_store, cx| {
8382 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8383 buffer_store.open_buffer(project_path, cx)
8384 })
8385 })?
8386 .await
8387 })
8388 }
8389
8390 fn request_multiple_lsp_locally<P, R>(
8391 &mut self,
8392 buffer: &Entity<Buffer>,
8393 position: Option<P>,
8394 request: R,
8395 cx: &mut Context<Self>,
8396 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8397 where
8398 P: ToOffset,
8399 R: LspCommand + Clone,
8400 <R::LspRequest as lsp::request::Request>::Result: Send,
8401 <R::LspRequest as lsp::request::Request>::Params: Send,
8402 {
8403 let Some(local) = self.as_local() else {
8404 return Task::ready(Vec::new());
8405 };
8406
8407 let snapshot = buffer.read(cx).snapshot();
8408 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8409
8410 let server_ids = buffer.update(cx, |buffer, cx| {
8411 local
8412 .language_servers_for_buffer(buffer, cx)
8413 .filter(|(adapter, _)| {
8414 scope
8415 .as_ref()
8416 .map(|scope| scope.language_allowed(&adapter.name))
8417 .unwrap_or(true)
8418 })
8419 .map(|(_, server)| server.server_id())
8420 .filter(|server_id| {
8421 self.as_local().is_none_or(|local| {
8422 local
8423 .buffers_opened_in_servers
8424 .get(&snapshot.remote_id())
8425 .is_some_and(|servers| servers.contains(server_id))
8426 })
8427 })
8428 .collect::<Vec<_>>()
8429 });
8430
8431 let mut response_results = server_ids
8432 .into_iter()
8433 .map(|server_id| {
8434 let task = self.request_lsp(
8435 buffer.clone(),
8436 LanguageServerToQuery::Other(server_id),
8437 request.clone(),
8438 cx,
8439 );
8440 async move { (server_id, task.await) }
8441 })
8442 .collect::<FuturesUnordered<_>>();
8443
8444 cx.background_spawn(async move {
8445 let mut responses = Vec::with_capacity(response_results.len());
8446 while let Some((server_id, response_result)) = response_results.next().await {
8447 match response_result {
8448 Ok(response) => responses.push((server_id, response)),
8449 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8450 }
8451 }
8452 responses
8453 })
8454 }
8455
8456 async fn handle_lsp_command<T: LspCommand>(
8457 this: Entity<Self>,
8458 envelope: TypedEnvelope<T::ProtoRequest>,
8459 mut cx: AsyncApp,
8460 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8461 where
8462 <T::LspRequest as lsp::request::Request>::Params: Send,
8463 <T::LspRequest as lsp::request::Request>::Result: Send,
8464 {
8465 let sender_id = envelope.original_sender_id().unwrap_or_default();
8466 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8467 let buffer_handle = this.update(&mut cx, |this, cx| {
8468 this.buffer_store.read(cx).get_existing(buffer_id)
8469 })??;
8470 let request = T::from_proto(
8471 envelope.payload,
8472 this.clone(),
8473 buffer_handle.clone(),
8474 cx.clone(),
8475 )
8476 .await?;
8477 let response = this
8478 .update(&mut cx, |this, cx| {
8479 this.request_lsp(
8480 buffer_handle.clone(),
8481 LanguageServerToQuery::FirstCapable,
8482 request,
8483 cx,
8484 )
8485 })?
8486 .await?;
8487 this.update(&mut cx, |this, cx| {
8488 Ok(T::response_to_proto(
8489 response,
8490 this,
8491 sender_id,
8492 &buffer_handle.read(cx).version(),
8493 cx,
8494 ))
8495 })?
8496 }
8497
8498 async fn handle_lsp_query(
8499 lsp_store: Entity<Self>,
8500 envelope: TypedEnvelope<proto::LspQuery>,
8501 mut cx: AsyncApp,
8502 ) -> Result<proto::Ack> {
8503 use proto::lsp_query::Request;
8504 let sender_id = envelope.original_sender_id().unwrap_or_default();
8505 let lsp_query = envelope.payload;
8506 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8507 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8508 match lsp_query.request.context("invalid LSP query request")? {
8509 Request::GetReferences(get_references) => {
8510 let position = get_references.position.clone().and_then(deserialize_anchor);
8511 Self::query_lsp_locally::<GetReferences>(
8512 lsp_store,
8513 server_id,
8514 sender_id,
8515 lsp_request_id,
8516 get_references,
8517 position,
8518 &mut cx,
8519 )
8520 .await?;
8521 }
8522 Request::GetDocumentColor(get_document_color) => {
8523 Self::query_lsp_locally::<GetDocumentColor>(
8524 lsp_store,
8525 server_id,
8526 sender_id,
8527 lsp_request_id,
8528 get_document_color,
8529 None,
8530 &mut cx,
8531 )
8532 .await?;
8533 }
8534 Request::GetHover(get_hover) => {
8535 let position = get_hover.position.clone().and_then(deserialize_anchor);
8536 Self::query_lsp_locally::<GetHover>(
8537 lsp_store,
8538 server_id,
8539 sender_id,
8540 lsp_request_id,
8541 get_hover,
8542 position,
8543 &mut cx,
8544 )
8545 .await?;
8546 }
8547 Request::GetCodeActions(get_code_actions) => {
8548 Self::query_lsp_locally::<GetCodeActions>(
8549 lsp_store,
8550 server_id,
8551 sender_id,
8552 lsp_request_id,
8553 get_code_actions,
8554 None,
8555 &mut cx,
8556 )
8557 .await?;
8558 }
8559 Request::GetSignatureHelp(get_signature_help) => {
8560 let position = get_signature_help
8561 .position
8562 .clone()
8563 .and_then(deserialize_anchor);
8564 Self::query_lsp_locally::<GetSignatureHelp>(
8565 lsp_store,
8566 server_id,
8567 sender_id,
8568 lsp_request_id,
8569 get_signature_help,
8570 position,
8571 &mut cx,
8572 )
8573 .await?;
8574 }
8575 Request::GetCodeLens(get_code_lens) => {
8576 Self::query_lsp_locally::<GetCodeLens>(
8577 lsp_store,
8578 server_id,
8579 sender_id,
8580 lsp_request_id,
8581 get_code_lens,
8582 None,
8583 &mut cx,
8584 )
8585 .await?;
8586 }
8587 Request::GetDefinition(get_definition) => {
8588 let position = get_definition.position.clone().and_then(deserialize_anchor);
8589 Self::query_lsp_locally::<GetDefinitions>(
8590 lsp_store,
8591 server_id,
8592 sender_id,
8593 lsp_request_id,
8594 get_definition,
8595 position,
8596 &mut cx,
8597 )
8598 .await?;
8599 }
8600 Request::GetDeclaration(get_declaration) => {
8601 let position = get_declaration
8602 .position
8603 .clone()
8604 .and_then(deserialize_anchor);
8605 Self::query_lsp_locally::<GetDeclarations>(
8606 lsp_store,
8607 server_id,
8608 sender_id,
8609 lsp_request_id,
8610 get_declaration,
8611 position,
8612 &mut cx,
8613 )
8614 .await?;
8615 }
8616 Request::GetTypeDefinition(get_type_definition) => {
8617 let position = get_type_definition
8618 .position
8619 .clone()
8620 .and_then(deserialize_anchor);
8621 Self::query_lsp_locally::<GetTypeDefinitions>(
8622 lsp_store,
8623 server_id,
8624 sender_id,
8625 lsp_request_id,
8626 get_type_definition,
8627 position,
8628 &mut cx,
8629 )
8630 .await?;
8631 }
8632 Request::GetImplementation(get_implementation) => {
8633 let position = get_implementation
8634 .position
8635 .clone()
8636 .and_then(deserialize_anchor);
8637 Self::query_lsp_locally::<GetImplementations>(
8638 lsp_store,
8639 server_id,
8640 sender_id,
8641 lsp_request_id,
8642 get_implementation,
8643 position,
8644 &mut cx,
8645 )
8646 .await?;
8647 }
8648 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8649 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8650 let version = deserialize_version(get_document_diagnostics.buffer_version());
8651 let buffer = lsp_store.update(&mut cx, |this, cx| {
8652 this.buffer_store.read(cx).get_existing(buffer_id)
8653 })??;
8654 buffer
8655 .update(&mut cx, |buffer, _| {
8656 buffer.wait_for_version(version.clone())
8657 })?
8658 .await?;
8659 lsp_store.update(&mut cx, |lsp_store, cx| {
8660 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8661 let key = LspKey {
8662 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8663 server_queried: server_id,
8664 };
8665 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8666 ) {
8667 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8668 lsp_requests.clear();
8669 };
8670 }
8671
8672 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8673 existing_queries.insert(
8674 lsp_request_id,
8675 cx.spawn(async move |lsp_store, cx| {
8676 let diagnostics_pull = lsp_store
8677 .update(cx, |lsp_store, cx| {
8678 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8679 })
8680 .ok();
8681 if let Some(diagnostics_pull) = diagnostics_pull {
8682 match diagnostics_pull.await {
8683 Ok(()) => {}
8684 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8685 };
8686 }
8687 }),
8688 );
8689 })?;
8690 }
8691 Request::InlayHints(inlay_hints) => {
8692 let query_start = inlay_hints
8693 .start
8694 .clone()
8695 .and_then(deserialize_anchor)
8696 .context("invalid inlay hints range start")?;
8697 let query_end = inlay_hints
8698 .end
8699 .clone()
8700 .and_then(deserialize_anchor)
8701 .context("invalid inlay hints range end")?;
8702 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8703 &lsp_store,
8704 server_id,
8705 lsp_request_id,
8706 &inlay_hints,
8707 query_start..query_end,
8708 &mut cx,
8709 )
8710 .await
8711 .context("preparing inlay hints request")?;
8712 Self::query_lsp_locally::<InlayHints>(
8713 lsp_store,
8714 server_id,
8715 sender_id,
8716 lsp_request_id,
8717 inlay_hints,
8718 None,
8719 &mut cx,
8720 )
8721 .await
8722 .context("querying for inlay hints")?
8723 }
8724 }
8725 Ok(proto::Ack {})
8726 }
8727
8728 async fn handle_lsp_query_response(
8729 lsp_store: Entity<Self>,
8730 envelope: TypedEnvelope<proto::LspQueryResponse>,
8731 cx: AsyncApp,
8732 ) -> Result<()> {
8733 lsp_store.read_with(&cx, |lsp_store, _| {
8734 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8735 upstream_client.handle_lsp_response(envelope.clone());
8736 }
8737 })?;
8738 Ok(())
8739 }
8740
8741 async fn handle_apply_code_action(
8742 this: Entity<Self>,
8743 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8744 mut cx: AsyncApp,
8745 ) -> Result<proto::ApplyCodeActionResponse> {
8746 let sender_id = envelope.original_sender_id().unwrap_or_default();
8747 let action =
8748 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8749 let apply_code_action = this.update(&mut cx, |this, cx| {
8750 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8751 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8752 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8753 })??;
8754
8755 let project_transaction = apply_code_action.await?;
8756 let project_transaction = this.update(&mut cx, |this, cx| {
8757 this.buffer_store.update(cx, |buffer_store, cx| {
8758 buffer_store.serialize_project_transaction_for_peer(
8759 project_transaction,
8760 sender_id,
8761 cx,
8762 )
8763 })
8764 })?;
8765 Ok(proto::ApplyCodeActionResponse {
8766 transaction: Some(project_transaction),
8767 })
8768 }
8769
8770 async fn handle_register_buffer_with_language_servers(
8771 this: Entity<Self>,
8772 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8773 mut cx: AsyncApp,
8774 ) -> Result<proto::Ack> {
8775 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8776 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8777 this.update(&mut cx, |this, cx| {
8778 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8779 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8780 project_id: upstream_project_id,
8781 buffer_id: buffer_id.to_proto(),
8782 only_servers: envelope.payload.only_servers,
8783 });
8784 }
8785
8786 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8787 anyhow::bail!("buffer is not open");
8788 };
8789
8790 let handle = this.register_buffer_with_language_servers(
8791 &buffer,
8792 envelope
8793 .payload
8794 .only_servers
8795 .into_iter()
8796 .filter_map(|selector| {
8797 Some(match selector.selector? {
8798 proto::language_server_selector::Selector::ServerId(server_id) => {
8799 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8800 }
8801 proto::language_server_selector::Selector::Name(name) => {
8802 LanguageServerSelector::Name(LanguageServerName(
8803 SharedString::from(name),
8804 ))
8805 }
8806 })
8807 })
8808 .collect(),
8809 false,
8810 cx,
8811 );
8812 this.buffer_store().update(cx, |buffer_store, _| {
8813 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8814 });
8815
8816 Ok(())
8817 })??;
8818 Ok(proto::Ack {})
8819 }
8820
8821 async fn handle_rename_project_entry(
8822 this: Entity<Self>,
8823 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8824 mut cx: AsyncApp,
8825 ) -> Result<proto::ProjectEntryResponse> {
8826 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8827 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8828 let new_path =
8829 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8830
8831 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8832 .update(&mut cx, |this, cx| {
8833 let (worktree, entry) = this
8834 .worktree_store
8835 .read(cx)
8836 .worktree_and_entry_for_id(entry_id, cx)?;
8837 let new_worktree = this
8838 .worktree_store
8839 .read(cx)
8840 .worktree_for_id(new_worktree_id, cx)?;
8841 Some((
8842 this.worktree_store.clone(),
8843 worktree,
8844 new_worktree,
8845 entry.clone(),
8846 ))
8847 })?
8848 .context("worktree not found")?;
8849 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8850 (worktree.absolutize(&old_entry.path), worktree.id())
8851 })?;
8852 let new_abs_path =
8853 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8854
8855 let _transaction = Self::will_rename_entry(
8856 this.downgrade(),
8857 old_worktree_id,
8858 &old_abs_path,
8859 &new_abs_path,
8860 old_entry.is_dir(),
8861 cx.clone(),
8862 )
8863 .await;
8864 let response = WorktreeStore::handle_rename_project_entry(
8865 worktree_store,
8866 envelope.payload,
8867 cx.clone(),
8868 )
8869 .await;
8870 this.read_with(&cx, |this, _| {
8871 this.did_rename_entry(
8872 old_worktree_id,
8873 &old_abs_path,
8874 &new_abs_path,
8875 old_entry.is_dir(),
8876 );
8877 })
8878 .ok();
8879 response
8880 }
8881
8882 async fn handle_update_diagnostic_summary(
8883 this: Entity<Self>,
8884 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8885 mut cx: AsyncApp,
8886 ) -> Result<()> {
8887 this.update(&mut cx, |lsp_store, cx| {
8888 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8889 let mut updated_diagnostics_paths = HashMap::default();
8890 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8891 for message_summary in envelope
8892 .payload
8893 .summary
8894 .into_iter()
8895 .chain(envelope.payload.more_summaries)
8896 {
8897 let project_path = ProjectPath {
8898 worktree_id,
8899 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8900 };
8901 let path = project_path.path.clone();
8902 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8903 let summary = DiagnosticSummary {
8904 error_count: message_summary.error_count as usize,
8905 warning_count: message_summary.warning_count as usize,
8906 };
8907
8908 if summary.is_empty() {
8909 if let Some(worktree_summaries) =
8910 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8911 && let Some(summaries) = worktree_summaries.get_mut(&path)
8912 {
8913 summaries.remove(&server_id);
8914 if summaries.is_empty() {
8915 worktree_summaries.remove(&path);
8916 }
8917 }
8918 } else {
8919 lsp_store
8920 .diagnostic_summaries
8921 .entry(worktree_id)
8922 .or_default()
8923 .entry(path)
8924 .or_default()
8925 .insert(server_id, summary);
8926 }
8927
8928 if let Some((_, project_id)) = &lsp_store.downstream_client {
8929 match &mut diagnostics_summary {
8930 Some(diagnostics_summary) => {
8931 diagnostics_summary
8932 .more_summaries
8933 .push(proto::DiagnosticSummary {
8934 path: project_path.path.as_ref().to_proto(),
8935 language_server_id: server_id.0 as u64,
8936 error_count: summary.error_count as u32,
8937 warning_count: summary.warning_count as u32,
8938 })
8939 }
8940 None => {
8941 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8942 project_id: *project_id,
8943 worktree_id: worktree_id.to_proto(),
8944 summary: Some(proto::DiagnosticSummary {
8945 path: project_path.path.as_ref().to_proto(),
8946 language_server_id: server_id.0 as u64,
8947 error_count: summary.error_count as u32,
8948 warning_count: summary.warning_count as u32,
8949 }),
8950 more_summaries: Vec::new(),
8951 })
8952 }
8953 }
8954 }
8955 updated_diagnostics_paths
8956 .entry(server_id)
8957 .or_insert_with(Vec::new)
8958 .push(project_path);
8959 }
8960
8961 if let Some((diagnostics_summary, (downstream_client, _))) =
8962 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8963 {
8964 downstream_client.send(diagnostics_summary).log_err();
8965 }
8966 for (server_id, paths) in updated_diagnostics_paths {
8967 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8968 }
8969 Ok(())
8970 })?
8971 }
8972
8973 async fn handle_start_language_server(
8974 lsp_store: Entity<Self>,
8975 envelope: TypedEnvelope<proto::StartLanguageServer>,
8976 mut cx: AsyncApp,
8977 ) -> Result<()> {
8978 let server = envelope.payload.server.context("invalid server")?;
8979 let server_capabilities =
8980 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8981 .with_context(|| {
8982 format!(
8983 "incorrect server capabilities {}",
8984 envelope.payload.capabilities
8985 )
8986 })?;
8987 lsp_store.update(&mut cx, |lsp_store, cx| {
8988 let server_id = LanguageServerId(server.id as usize);
8989 let server_name = LanguageServerName::from_proto(server.name.clone());
8990 lsp_store
8991 .lsp_server_capabilities
8992 .insert(server_id, server_capabilities);
8993 lsp_store.language_server_statuses.insert(
8994 server_id,
8995 LanguageServerStatus {
8996 name: server_name.clone(),
8997 pending_work: Default::default(),
8998 has_pending_diagnostic_updates: false,
8999 progress_tokens: Default::default(),
9000 worktree: server.worktree_id.map(WorktreeId::from_proto),
9001 },
9002 );
9003 cx.emit(LspStoreEvent::LanguageServerAdded(
9004 server_id,
9005 server_name,
9006 server.worktree_id.map(WorktreeId::from_proto),
9007 ));
9008 cx.notify();
9009 })?;
9010 Ok(())
9011 }
9012
9013 async fn handle_update_language_server(
9014 lsp_store: Entity<Self>,
9015 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9016 mut cx: AsyncApp,
9017 ) -> Result<()> {
9018 lsp_store.update(&mut cx, |lsp_store, cx| {
9019 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9020
9021 match envelope.payload.variant.context("invalid variant")? {
9022 proto::update_language_server::Variant::WorkStart(payload) => {
9023 lsp_store.on_lsp_work_start(
9024 language_server_id,
9025 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9026 .context("invalid progress token value")?,
9027 LanguageServerProgress {
9028 title: payload.title,
9029 is_disk_based_diagnostics_progress: false,
9030 is_cancellable: payload.is_cancellable.unwrap_or(false),
9031 message: payload.message,
9032 percentage: payload.percentage.map(|p| p as usize),
9033 last_update_at: cx.background_executor().now(),
9034 },
9035 cx,
9036 );
9037 }
9038 proto::update_language_server::Variant::WorkProgress(payload) => {
9039 lsp_store.on_lsp_work_progress(
9040 language_server_id,
9041 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9042 .context("invalid progress token value")?,
9043 LanguageServerProgress {
9044 title: None,
9045 is_disk_based_diagnostics_progress: false,
9046 is_cancellable: payload.is_cancellable.unwrap_or(false),
9047 message: payload.message,
9048 percentage: payload.percentage.map(|p| p as usize),
9049 last_update_at: cx.background_executor().now(),
9050 },
9051 cx,
9052 );
9053 }
9054
9055 proto::update_language_server::Variant::WorkEnd(payload) => {
9056 lsp_store.on_lsp_work_end(
9057 language_server_id,
9058 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9059 .context("invalid progress token value")?,
9060 cx,
9061 );
9062 }
9063
9064 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9065 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9066 }
9067
9068 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9069 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9070 }
9071
9072 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9073 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9074 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9075 cx.emit(LspStoreEvent::LanguageServerUpdate {
9076 language_server_id,
9077 name: envelope
9078 .payload
9079 .server_name
9080 .map(SharedString::new)
9081 .map(LanguageServerName),
9082 message: non_lsp,
9083 });
9084 }
9085 }
9086
9087 Ok(())
9088 })?
9089 }
9090
9091 async fn handle_language_server_log(
9092 this: Entity<Self>,
9093 envelope: TypedEnvelope<proto::LanguageServerLog>,
9094 mut cx: AsyncApp,
9095 ) -> Result<()> {
9096 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9097 let log_type = envelope
9098 .payload
9099 .log_type
9100 .map(LanguageServerLogType::from_proto)
9101 .context("invalid language server log type")?;
9102
9103 let message = envelope.payload.message;
9104
9105 this.update(&mut cx, |_, cx| {
9106 cx.emit(LspStoreEvent::LanguageServerLog(
9107 language_server_id,
9108 log_type,
9109 message,
9110 ));
9111 })
9112 }
9113
9114 async fn handle_lsp_ext_cancel_flycheck(
9115 lsp_store: Entity<Self>,
9116 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9117 cx: AsyncApp,
9118 ) -> Result<proto::Ack> {
9119 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9120 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9121 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9122 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9123 } else {
9124 None
9125 }
9126 })?;
9127 if let Some(task) = task {
9128 task.context("handling lsp ext cancel flycheck")?;
9129 }
9130
9131 Ok(proto::Ack {})
9132 }
9133
9134 async fn handle_lsp_ext_run_flycheck(
9135 lsp_store: Entity<Self>,
9136 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9137 mut cx: AsyncApp,
9138 ) -> Result<proto::Ack> {
9139 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9140 lsp_store.update(&mut cx, |lsp_store, cx| {
9141 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9142 let text_document = if envelope.payload.current_file_only {
9143 let buffer_id = envelope
9144 .payload
9145 .buffer_id
9146 .map(|id| BufferId::new(id))
9147 .transpose()?;
9148 buffer_id
9149 .and_then(|buffer_id| {
9150 lsp_store
9151 .buffer_store()
9152 .read(cx)
9153 .get(buffer_id)
9154 .and_then(|buffer| {
9155 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9156 })
9157 .map(|path| make_text_document_identifier(&path))
9158 })
9159 .transpose()?
9160 } else {
9161 None
9162 };
9163 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9164 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9165 )?;
9166 }
9167 anyhow::Ok(())
9168 })??;
9169
9170 Ok(proto::Ack {})
9171 }
9172
9173 async fn handle_lsp_ext_clear_flycheck(
9174 lsp_store: Entity<Self>,
9175 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9176 cx: AsyncApp,
9177 ) -> Result<proto::Ack> {
9178 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9179 lsp_store
9180 .read_with(&cx, |lsp_store, _| {
9181 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9182 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9183 } else {
9184 None
9185 }
9186 })
9187 .context("handling lsp ext clear flycheck")?;
9188
9189 Ok(proto::Ack {})
9190 }
9191
9192 pub fn disk_based_diagnostics_started(
9193 &mut self,
9194 language_server_id: LanguageServerId,
9195 cx: &mut Context<Self>,
9196 ) {
9197 if let Some(language_server_status) =
9198 self.language_server_statuses.get_mut(&language_server_id)
9199 {
9200 language_server_status.has_pending_diagnostic_updates = true;
9201 }
9202
9203 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9204 cx.emit(LspStoreEvent::LanguageServerUpdate {
9205 language_server_id,
9206 name: self
9207 .language_server_adapter_for_id(language_server_id)
9208 .map(|adapter| adapter.name()),
9209 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9210 Default::default(),
9211 ),
9212 })
9213 }
9214
9215 pub fn disk_based_diagnostics_finished(
9216 &mut self,
9217 language_server_id: LanguageServerId,
9218 cx: &mut Context<Self>,
9219 ) {
9220 if let Some(language_server_status) =
9221 self.language_server_statuses.get_mut(&language_server_id)
9222 {
9223 language_server_status.has_pending_diagnostic_updates = false;
9224 }
9225
9226 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9227 cx.emit(LspStoreEvent::LanguageServerUpdate {
9228 language_server_id,
9229 name: self
9230 .language_server_adapter_for_id(language_server_id)
9231 .map(|adapter| adapter.name()),
9232 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9233 Default::default(),
9234 ),
9235 })
9236 }
9237
9238 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9239 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9240 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9241 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9242 // the language server might take some time to publish diagnostics.
9243 fn simulate_disk_based_diagnostics_events_if_needed(
9244 &mut self,
9245 language_server_id: LanguageServerId,
9246 cx: &mut Context<Self>,
9247 ) {
9248 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9249
9250 let Some(LanguageServerState::Running {
9251 simulate_disk_based_diagnostics_completion,
9252 adapter,
9253 ..
9254 }) = self
9255 .as_local_mut()
9256 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9257 else {
9258 return;
9259 };
9260
9261 if adapter.disk_based_diagnostics_progress_token.is_some() {
9262 return;
9263 }
9264
9265 let prev_task =
9266 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9267 cx.background_executor()
9268 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9269 .await;
9270
9271 this.update(cx, |this, cx| {
9272 this.disk_based_diagnostics_finished(language_server_id, cx);
9273
9274 if let Some(LanguageServerState::Running {
9275 simulate_disk_based_diagnostics_completion,
9276 ..
9277 }) = this.as_local_mut().and_then(|local_store| {
9278 local_store.language_servers.get_mut(&language_server_id)
9279 }) {
9280 *simulate_disk_based_diagnostics_completion = None;
9281 }
9282 })
9283 .ok();
9284 }));
9285
9286 if prev_task.is_none() {
9287 self.disk_based_diagnostics_started(language_server_id, cx);
9288 }
9289 }
9290
9291 pub fn language_server_statuses(
9292 &self,
9293 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9294 self.language_server_statuses
9295 .iter()
9296 .map(|(key, value)| (*key, value))
9297 }
9298
9299 pub(super) fn did_rename_entry(
9300 &self,
9301 worktree_id: WorktreeId,
9302 old_path: &Path,
9303 new_path: &Path,
9304 is_dir: bool,
9305 ) {
9306 maybe!({
9307 let local_store = self.as_local()?;
9308
9309 let old_uri = lsp::Uri::from_file_path(old_path)
9310 .ok()
9311 .map(|uri| uri.to_string())?;
9312 let new_uri = lsp::Uri::from_file_path(new_path)
9313 .ok()
9314 .map(|uri| uri.to_string())?;
9315
9316 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9317 let Some(filter) = local_store
9318 .language_server_paths_watched_for_rename
9319 .get(&language_server.server_id())
9320 else {
9321 continue;
9322 };
9323
9324 if filter.should_send_did_rename(&old_uri, is_dir) {
9325 language_server
9326 .notify::<DidRenameFiles>(RenameFilesParams {
9327 files: vec![FileRename {
9328 old_uri: old_uri.clone(),
9329 new_uri: new_uri.clone(),
9330 }],
9331 })
9332 .ok();
9333 }
9334 }
9335 Some(())
9336 });
9337 }
9338
9339 pub(super) fn will_rename_entry(
9340 this: WeakEntity<Self>,
9341 worktree_id: WorktreeId,
9342 old_path: &Path,
9343 new_path: &Path,
9344 is_dir: bool,
9345 cx: AsyncApp,
9346 ) -> Task<ProjectTransaction> {
9347 let old_uri = lsp::Uri::from_file_path(old_path)
9348 .ok()
9349 .map(|uri| uri.to_string());
9350 let new_uri = lsp::Uri::from_file_path(new_path)
9351 .ok()
9352 .map(|uri| uri.to_string());
9353 cx.spawn(async move |cx| {
9354 let mut tasks = vec![];
9355 this.update(cx, |this, cx| {
9356 let local_store = this.as_local()?;
9357 let old_uri = old_uri?;
9358 let new_uri = new_uri?;
9359 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9360 let Some(filter) = local_store
9361 .language_server_paths_watched_for_rename
9362 .get(&language_server.server_id())
9363 else {
9364 continue;
9365 };
9366
9367 if filter.should_send_will_rename(&old_uri, is_dir) {
9368 let apply_edit = cx.spawn({
9369 let old_uri = old_uri.clone();
9370 let new_uri = new_uri.clone();
9371 let language_server = language_server.clone();
9372 async move |this, cx| {
9373 let edit = language_server
9374 .request::<WillRenameFiles>(RenameFilesParams {
9375 files: vec![FileRename { old_uri, new_uri }],
9376 })
9377 .await
9378 .into_response()
9379 .context("will rename files")
9380 .log_err()
9381 .flatten()?;
9382
9383 let transaction = LocalLspStore::deserialize_workspace_edit(
9384 this.upgrade()?,
9385 edit,
9386 false,
9387 language_server.clone(),
9388 cx,
9389 )
9390 .await
9391 .ok()?;
9392 Some(transaction)
9393 }
9394 });
9395 tasks.push(apply_edit);
9396 }
9397 }
9398 Some(())
9399 })
9400 .ok()
9401 .flatten();
9402 let mut merged_transaction = ProjectTransaction::default();
9403 for task in tasks {
9404 // Await on tasks sequentially so that the order of application of edits is deterministic
9405 // (at least with regards to the order of registration of language servers)
9406 if let Some(transaction) = task.await {
9407 for (buffer, buffer_transaction) in transaction.0 {
9408 merged_transaction.0.insert(buffer, buffer_transaction);
9409 }
9410 }
9411 }
9412 merged_transaction
9413 })
9414 }
9415
9416 fn lsp_notify_abs_paths_changed(
9417 &mut self,
9418 server_id: LanguageServerId,
9419 changes: Vec<PathEvent>,
9420 ) {
9421 maybe!({
9422 let server = self.language_server_for_id(server_id)?;
9423 let changes = changes
9424 .into_iter()
9425 .filter_map(|event| {
9426 let typ = match event.kind? {
9427 PathEventKind::Created => lsp::FileChangeType::CREATED,
9428 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9429 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9430 };
9431 Some(lsp::FileEvent {
9432 uri: file_path_to_lsp_url(&event.path).log_err()?,
9433 typ,
9434 })
9435 })
9436 .collect::<Vec<_>>();
9437 if !changes.is_empty() {
9438 server
9439 .notify::<lsp::notification::DidChangeWatchedFiles>(
9440 lsp::DidChangeWatchedFilesParams { changes },
9441 )
9442 .ok();
9443 }
9444 Some(())
9445 });
9446 }
9447
9448 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9449 self.as_local()?.language_server_for_id(id)
9450 }
9451
9452 fn on_lsp_progress(
9453 &mut self,
9454 progress_params: lsp::ProgressParams,
9455 language_server_id: LanguageServerId,
9456 disk_based_diagnostics_progress_token: Option<String>,
9457 cx: &mut Context<Self>,
9458 ) {
9459 match progress_params.value {
9460 lsp::ProgressParamsValue::WorkDone(progress) => {
9461 self.handle_work_done_progress(
9462 progress,
9463 language_server_id,
9464 disk_based_diagnostics_progress_token,
9465 ProgressToken::from_lsp(progress_params.token),
9466 cx,
9467 );
9468 }
9469 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9470 let identifier = match progress_params.token {
9471 lsp::NumberOrString::Number(_) => None,
9472 lsp::NumberOrString::String(token) => token
9473 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9474 .map(|(_, id)| id.to_owned()),
9475 };
9476 if let Some(LanguageServerState::Running {
9477 workspace_diagnostics_refresh_tasks,
9478 ..
9479 }) = self
9480 .as_local_mut()
9481 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9482 && let Some(workspace_diagnostics) =
9483 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9484 {
9485 workspace_diagnostics.progress_tx.try_send(()).ok();
9486 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9487 }
9488 }
9489 }
9490 }
9491
9492 fn handle_work_done_progress(
9493 &mut self,
9494 progress: lsp::WorkDoneProgress,
9495 language_server_id: LanguageServerId,
9496 disk_based_diagnostics_progress_token: Option<String>,
9497 token: ProgressToken,
9498 cx: &mut Context<Self>,
9499 ) {
9500 let language_server_status =
9501 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9502 status
9503 } else {
9504 return;
9505 };
9506
9507 if !language_server_status.progress_tokens.contains(&token) {
9508 return;
9509 }
9510
9511 let is_disk_based_diagnostics_progress =
9512 if let (Some(disk_based_token), ProgressToken::String(token)) =
9513 (&disk_based_diagnostics_progress_token, &token)
9514 {
9515 token.starts_with(disk_based_token)
9516 } else {
9517 false
9518 };
9519
9520 match progress {
9521 lsp::WorkDoneProgress::Begin(report) => {
9522 if is_disk_based_diagnostics_progress {
9523 self.disk_based_diagnostics_started(language_server_id, cx);
9524 }
9525 self.on_lsp_work_start(
9526 language_server_id,
9527 token.clone(),
9528 LanguageServerProgress {
9529 title: Some(report.title),
9530 is_disk_based_diagnostics_progress,
9531 is_cancellable: report.cancellable.unwrap_or(false),
9532 message: report.message.clone(),
9533 percentage: report.percentage.map(|p| p as usize),
9534 last_update_at: cx.background_executor().now(),
9535 },
9536 cx,
9537 );
9538 }
9539 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9540 language_server_id,
9541 token,
9542 LanguageServerProgress {
9543 title: None,
9544 is_disk_based_diagnostics_progress,
9545 is_cancellable: report.cancellable.unwrap_or(false),
9546 message: report.message,
9547 percentage: report.percentage.map(|p| p as usize),
9548 last_update_at: cx.background_executor().now(),
9549 },
9550 cx,
9551 ),
9552 lsp::WorkDoneProgress::End(_) => {
9553 language_server_status.progress_tokens.remove(&token);
9554 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9555 if is_disk_based_diagnostics_progress {
9556 self.disk_based_diagnostics_finished(language_server_id, cx);
9557 }
9558 }
9559 }
9560 }
9561
9562 fn on_lsp_work_start(
9563 &mut self,
9564 language_server_id: LanguageServerId,
9565 token: ProgressToken,
9566 progress: LanguageServerProgress,
9567 cx: &mut Context<Self>,
9568 ) {
9569 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9570 status.pending_work.insert(token.clone(), progress.clone());
9571 cx.notify();
9572 }
9573 cx.emit(LspStoreEvent::LanguageServerUpdate {
9574 language_server_id,
9575 name: self
9576 .language_server_adapter_for_id(language_server_id)
9577 .map(|adapter| adapter.name()),
9578 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9579 token: Some(token.to_proto()),
9580 title: progress.title,
9581 message: progress.message,
9582 percentage: progress.percentage.map(|p| p as u32),
9583 is_cancellable: Some(progress.is_cancellable),
9584 }),
9585 })
9586 }
9587
9588 fn on_lsp_work_progress(
9589 &mut self,
9590 language_server_id: LanguageServerId,
9591 token: ProgressToken,
9592 progress: LanguageServerProgress,
9593 cx: &mut Context<Self>,
9594 ) {
9595 let mut did_update = false;
9596 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9597 match status.pending_work.entry(token.clone()) {
9598 btree_map::Entry::Vacant(entry) => {
9599 entry.insert(progress.clone());
9600 did_update = true;
9601 }
9602 btree_map::Entry::Occupied(mut entry) => {
9603 let entry = entry.get_mut();
9604 if (progress.last_update_at - entry.last_update_at)
9605 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9606 {
9607 entry.last_update_at = progress.last_update_at;
9608 if progress.message.is_some() {
9609 entry.message = progress.message.clone();
9610 }
9611 if progress.percentage.is_some() {
9612 entry.percentage = progress.percentage;
9613 }
9614 if progress.is_cancellable != entry.is_cancellable {
9615 entry.is_cancellable = progress.is_cancellable;
9616 }
9617 did_update = true;
9618 }
9619 }
9620 }
9621 }
9622
9623 if did_update {
9624 cx.emit(LspStoreEvent::LanguageServerUpdate {
9625 language_server_id,
9626 name: self
9627 .language_server_adapter_for_id(language_server_id)
9628 .map(|adapter| adapter.name()),
9629 message: proto::update_language_server::Variant::WorkProgress(
9630 proto::LspWorkProgress {
9631 token: Some(token.to_proto()),
9632 message: progress.message,
9633 percentage: progress.percentage.map(|p| p as u32),
9634 is_cancellable: Some(progress.is_cancellable),
9635 },
9636 ),
9637 })
9638 }
9639 }
9640
9641 fn on_lsp_work_end(
9642 &mut self,
9643 language_server_id: LanguageServerId,
9644 token: ProgressToken,
9645 cx: &mut Context<Self>,
9646 ) {
9647 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9648 if let Some(work) = status.pending_work.remove(&token)
9649 && !work.is_disk_based_diagnostics_progress
9650 {
9651 cx.emit(LspStoreEvent::RefreshInlayHints {
9652 server_id: language_server_id,
9653 request_id: None,
9654 });
9655 }
9656 cx.notify();
9657 }
9658
9659 cx.emit(LspStoreEvent::LanguageServerUpdate {
9660 language_server_id,
9661 name: self
9662 .language_server_adapter_for_id(language_server_id)
9663 .map(|adapter| adapter.name()),
9664 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9665 token: Some(token.to_proto()),
9666 }),
9667 })
9668 }
9669
9670 pub async fn handle_resolve_completion_documentation(
9671 this: Entity<Self>,
9672 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9673 mut cx: AsyncApp,
9674 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9675 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9676
9677 let completion = this
9678 .read_with(&cx, |this, cx| {
9679 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9680 let server = this
9681 .language_server_for_id(id)
9682 .with_context(|| format!("No language server {id}"))?;
9683
9684 anyhow::Ok(cx.background_spawn(async move {
9685 let can_resolve = server
9686 .capabilities()
9687 .completion_provider
9688 .as_ref()
9689 .and_then(|options| options.resolve_provider)
9690 .unwrap_or(false);
9691 if can_resolve {
9692 server
9693 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9694 .await
9695 .into_response()
9696 .context("resolve completion item")
9697 } else {
9698 anyhow::Ok(lsp_completion)
9699 }
9700 }))
9701 })??
9702 .await?;
9703
9704 let mut documentation_is_markdown = false;
9705 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9706 let documentation = match completion.documentation {
9707 Some(lsp::Documentation::String(text)) => text,
9708
9709 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9710 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9711 value
9712 }
9713
9714 _ => String::new(),
9715 };
9716
9717 // If we have a new buffer_id, that means we're talking to a new client
9718 // and want to check for new text_edits in the completion too.
9719 let mut old_replace_start = None;
9720 let mut old_replace_end = None;
9721 let mut old_insert_start = None;
9722 let mut old_insert_end = None;
9723 let mut new_text = String::default();
9724 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9725 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9726 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9727 anyhow::Ok(buffer.read(cx).snapshot())
9728 })??;
9729
9730 if let Some(text_edit) = completion.text_edit.as_ref() {
9731 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9732
9733 if let Some(mut edit) = edit {
9734 LineEnding::normalize(&mut edit.new_text);
9735
9736 new_text = edit.new_text;
9737 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9738 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9739 if let Some(insert_range) = edit.insert_range {
9740 old_insert_start = Some(serialize_anchor(&insert_range.start));
9741 old_insert_end = Some(serialize_anchor(&insert_range.end));
9742 }
9743 }
9744 }
9745 }
9746
9747 Ok(proto::ResolveCompletionDocumentationResponse {
9748 documentation,
9749 documentation_is_markdown,
9750 old_replace_start,
9751 old_replace_end,
9752 new_text,
9753 lsp_completion,
9754 old_insert_start,
9755 old_insert_end,
9756 })
9757 }
9758
9759 async fn handle_on_type_formatting(
9760 this: Entity<Self>,
9761 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9762 mut cx: AsyncApp,
9763 ) -> Result<proto::OnTypeFormattingResponse> {
9764 let on_type_formatting = this.update(&mut cx, |this, cx| {
9765 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9766 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9767 let position = envelope
9768 .payload
9769 .position
9770 .and_then(deserialize_anchor)
9771 .context("invalid position")?;
9772 anyhow::Ok(this.apply_on_type_formatting(
9773 buffer,
9774 position,
9775 envelope.payload.trigger.clone(),
9776 cx,
9777 ))
9778 })??;
9779
9780 let transaction = on_type_formatting
9781 .await?
9782 .as_ref()
9783 .map(language::proto::serialize_transaction);
9784 Ok(proto::OnTypeFormattingResponse { transaction })
9785 }
9786
9787 async fn handle_refresh_inlay_hints(
9788 lsp_store: Entity<Self>,
9789 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9790 mut cx: AsyncApp,
9791 ) -> Result<proto::Ack> {
9792 lsp_store.update(&mut cx, |_, cx| {
9793 cx.emit(LspStoreEvent::RefreshInlayHints {
9794 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9795 request_id: envelope.payload.request_id.map(|id| id as usize),
9796 });
9797 })?;
9798 Ok(proto::Ack {})
9799 }
9800
9801 async fn handle_pull_workspace_diagnostics(
9802 lsp_store: Entity<Self>,
9803 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9804 mut cx: AsyncApp,
9805 ) -> Result<proto::Ack> {
9806 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9807 lsp_store.update(&mut cx, |lsp_store, _| {
9808 lsp_store.pull_workspace_diagnostics(server_id);
9809 })?;
9810 Ok(proto::Ack {})
9811 }
9812
9813 async fn handle_get_color_presentation(
9814 lsp_store: Entity<Self>,
9815 envelope: TypedEnvelope<proto::GetColorPresentation>,
9816 mut cx: AsyncApp,
9817 ) -> Result<proto::GetColorPresentationResponse> {
9818 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9819 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9820 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9821 })??;
9822
9823 let color = envelope
9824 .payload
9825 .color
9826 .context("invalid color resolve request")?;
9827 let start = color
9828 .lsp_range_start
9829 .context("invalid color resolve request")?;
9830 let end = color
9831 .lsp_range_end
9832 .context("invalid color resolve request")?;
9833
9834 let color = DocumentColor {
9835 lsp_range: lsp::Range {
9836 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9837 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9838 },
9839 color: lsp::Color {
9840 red: color.red,
9841 green: color.green,
9842 blue: color.blue,
9843 alpha: color.alpha,
9844 },
9845 resolved: false,
9846 color_presentations: Vec::new(),
9847 };
9848 let resolved_color = lsp_store
9849 .update(&mut cx, |lsp_store, cx| {
9850 lsp_store.resolve_color_presentation(
9851 color,
9852 buffer.clone(),
9853 LanguageServerId(envelope.payload.server_id as usize),
9854 cx,
9855 )
9856 })?
9857 .await
9858 .context("resolving color presentation")?;
9859
9860 Ok(proto::GetColorPresentationResponse {
9861 presentations: resolved_color
9862 .color_presentations
9863 .into_iter()
9864 .map(|presentation| proto::ColorPresentation {
9865 label: presentation.label.to_string(),
9866 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9867 additional_text_edits: presentation
9868 .additional_text_edits
9869 .into_iter()
9870 .map(serialize_lsp_edit)
9871 .collect(),
9872 })
9873 .collect(),
9874 })
9875 }
9876
9877 async fn handle_resolve_inlay_hint(
9878 lsp_store: Entity<Self>,
9879 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9880 mut cx: AsyncApp,
9881 ) -> Result<proto::ResolveInlayHintResponse> {
9882 let proto_hint = envelope
9883 .payload
9884 .hint
9885 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9886 let hint = InlayHints::proto_to_project_hint(proto_hint)
9887 .context("resolved proto inlay hint conversion")?;
9888 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9889 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9890 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9891 })??;
9892 let response_hint = lsp_store
9893 .update(&mut cx, |lsp_store, cx| {
9894 lsp_store.resolve_inlay_hint(
9895 hint,
9896 buffer,
9897 LanguageServerId(envelope.payload.language_server_id as usize),
9898 cx,
9899 )
9900 })?
9901 .await
9902 .context("inlay hints fetch")?;
9903 Ok(proto::ResolveInlayHintResponse {
9904 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9905 })
9906 }
9907
9908 async fn handle_refresh_code_lens(
9909 this: Entity<Self>,
9910 _: TypedEnvelope<proto::RefreshCodeLens>,
9911 mut cx: AsyncApp,
9912 ) -> Result<proto::Ack> {
9913 this.update(&mut cx, |_, cx| {
9914 cx.emit(LspStoreEvent::RefreshCodeLens);
9915 })?;
9916 Ok(proto::Ack {})
9917 }
9918
9919 async fn handle_open_buffer_for_symbol(
9920 this: Entity<Self>,
9921 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9922 mut cx: AsyncApp,
9923 ) -> Result<proto::OpenBufferForSymbolResponse> {
9924 let peer_id = envelope.original_sender_id().unwrap_or_default();
9925 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9926 let symbol = Self::deserialize_symbol(symbol)?;
9927 this.read_with(&cx, |this, _| {
9928 if let SymbolLocation::OutsideProject {
9929 abs_path,
9930 signature,
9931 } = &symbol.path
9932 {
9933 let new_signature = this.symbol_signature(&abs_path);
9934 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9935 }
9936 Ok(())
9937 })??;
9938 let buffer = this
9939 .update(&mut cx, |this, cx| {
9940 this.open_buffer_for_symbol(
9941 &Symbol {
9942 language_server_name: symbol.language_server_name,
9943 source_worktree_id: symbol.source_worktree_id,
9944 source_language_server_id: symbol.source_language_server_id,
9945 path: symbol.path,
9946 name: symbol.name,
9947 kind: symbol.kind,
9948 range: symbol.range,
9949 label: CodeLabel::default(),
9950 },
9951 cx,
9952 )
9953 })?
9954 .await?;
9955
9956 this.update(&mut cx, |this, cx| {
9957 let is_private = buffer
9958 .read(cx)
9959 .file()
9960 .map(|f| f.is_private())
9961 .unwrap_or_default();
9962 if is_private {
9963 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9964 } else {
9965 this.buffer_store
9966 .update(cx, |buffer_store, cx| {
9967 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9968 })
9969 .detach_and_log_err(cx);
9970 let buffer_id = buffer.read(cx).remote_id().to_proto();
9971 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9972 }
9973 })?
9974 }
9975
9976 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9977 let mut hasher = Sha256::new();
9978 hasher.update(abs_path.to_string_lossy().as_bytes());
9979 hasher.update(self.nonce.to_be_bytes());
9980 hasher.finalize().as_slice().try_into().unwrap()
9981 }
9982
9983 pub async fn handle_get_project_symbols(
9984 this: Entity<Self>,
9985 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9986 mut cx: AsyncApp,
9987 ) -> Result<proto::GetProjectSymbolsResponse> {
9988 let symbols = this
9989 .update(&mut cx, |this, cx| {
9990 this.symbols(&envelope.payload.query, cx)
9991 })?
9992 .await?;
9993
9994 Ok(proto::GetProjectSymbolsResponse {
9995 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9996 })
9997 }
9998
9999 pub async fn handle_restart_language_servers(
10000 this: Entity<Self>,
10001 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10002 mut cx: AsyncApp,
10003 ) -> Result<proto::Ack> {
10004 this.update(&mut cx, |lsp_store, cx| {
10005 let buffers =
10006 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10007 lsp_store.restart_language_servers_for_buffers(
10008 buffers,
10009 envelope
10010 .payload
10011 .only_servers
10012 .into_iter()
10013 .filter_map(|selector| {
10014 Some(match selector.selector? {
10015 proto::language_server_selector::Selector::ServerId(server_id) => {
10016 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10017 }
10018 proto::language_server_selector::Selector::Name(name) => {
10019 LanguageServerSelector::Name(LanguageServerName(
10020 SharedString::from(name),
10021 ))
10022 }
10023 })
10024 })
10025 .collect(),
10026 cx,
10027 );
10028 })?;
10029
10030 Ok(proto::Ack {})
10031 }
10032
10033 pub async fn handle_stop_language_servers(
10034 lsp_store: Entity<Self>,
10035 envelope: TypedEnvelope<proto::StopLanguageServers>,
10036 mut cx: AsyncApp,
10037 ) -> Result<proto::Ack> {
10038 lsp_store.update(&mut cx, |lsp_store, cx| {
10039 if envelope.payload.all
10040 && envelope.payload.also_servers.is_empty()
10041 && envelope.payload.buffer_ids.is_empty()
10042 {
10043 lsp_store.stop_all_language_servers(cx);
10044 } else {
10045 let buffers =
10046 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10047 lsp_store
10048 .stop_language_servers_for_buffers(
10049 buffers,
10050 envelope
10051 .payload
10052 .also_servers
10053 .into_iter()
10054 .filter_map(|selector| {
10055 Some(match selector.selector? {
10056 proto::language_server_selector::Selector::ServerId(
10057 server_id,
10058 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10059 server_id,
10060 )),
10061 proto::language_server_selector::Selector::Name(name) => {
10062 LanguageServerSelector::Name(LanguageServerName(
10063 SharedString::from(name),
10064 ))
10065 }
10066 })
10067 })
10068 .collect(),
10069 cx,
10070 )
10071 .detach_and_log_err(cx);
10072 }
10073 })?;
10074
10075 Ok(proto::Ack {})
10076 }
10077
10078 pub async fn handle_cancel_language_server_work(
10079 lsp_store: Entity<Self>,
10080 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10081 mut cx: AsyncApp,
10082 ) -> Result<proto::Ack> {
10083 lsp_store.update(&mut cx, |lsp_store, cx| {
10084 if let Some(work) = envelope.payload.work {
10085 match work {
10086 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10087 let buffers =
10088 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10089 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10090 }
10091 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10092 let server_id = LanguageServerId::from_proto(work.language_server_id);
10093 let token = work
10094 .token
10095 .map(|token| {
10096 ProgressToken::from_proto(token)
10097 .context("invalid work progress token")
10098 })
10099 .transpose()?;
10100 lsp_store.cancel_language_server_work(server_id, token, cx);
10101 }
10102 }
10103 }
10104 anyhow::Ok(())
10105 })??;
10106
10107 Ok(proto::Ack {})
10108 }
10109
10110 fn buffer_ids_to_buffers(
10111 &mut self,
10112 buffer_ids: impl Iterator<Item = u64>,
10113 cx: &mut Context<Self>,
10114 ) -> Vec<Entity<Buffer>> {
10115 buffer_ids
10116 .into_iter()
10117 .flat_map(|buffer_id| {
10118 self.buffer_store
10119 .read(cx)
10120 .get(BufferId::new(buffer_id).log_err()?)
10121 })
10122 .collect::<Vec<_>>()
10123 }
10124
10125 async fn handle_apply_additional_edits_for_completion(
10126 this: Entity<Self>,
10127 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10128 mut cx: AsyncApp,
10129 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10130 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10131 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10132 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10133 let completion = Self::deserialize_completion(
10134 envelope.payload.completion.context("invalid completion")?,
10135 )?;
10136 anyhow::Ok((buffer, completion))
10137 })??;
10138
10139 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10140 this.apply_additional_edits_for_completion(
10141 buffer,
10142 Rc::new(RefCell::new(Box::new([Completion {
10143 replace_range: completion.replace_range,
10144 new_text: completion.new_text,
10145 source: completion.source,
10146 documentation: None,
10147 label: CodeLabel::default(),
10148 insert_text_mode: None,
10149 icon_path: None,
10150 confirm: None,
10151 }]))),
10152 0,
10153 false,
10154 cx,
10155 )
10156 })?;
10157
10158 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10159 transaction: apply_additional_edits
10160 .await?
10161 .as_ref()
10162 .map(language::proto::serialize_transaction),
10163 })
10164 }
10165
10166 pub fn last_formatting_failure(&self) -> Option<&str> {
10167 self.last_formatting_failure.as_deref()
10168 }
10169
10170 pub fn reset_last_formatting_failure(&mut self) {
10171 self.last_formatting_failure = None;
10172 }
10173
10174 pub fn environment_for_buffer(
10175 &self,
10176 buffer: &Entity<Buffer>,
10177 cx: &mut Context<Self>,
10178 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10179 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10180 environment.update(cx, |env, cx| {
10181 env.buffer_environment(buffer, &self.worktree_store, cx)
10182 })
10183 } else {
10184 Task::ready(None).shared()
10185 }
10186 }
10187
10188 pub fn format(
10189 &mut self,
10190 buffers: HashSet<Entity<Buffer>>,
10191 target: LspFormatTarget,
10192 push_to_history: bool,
10193 trigger: FormatTrigger,
10194 cx: &mut Context<Self>,
10195 ) -> Task<anyhow::Result<ProjectTransaction>> {
10196 let logger = zlog::scoped!("format");
10197 if self.as_local().is_some() {
10198 zlog::trace!(logger => "Formatting locally");
10199 let logger = zlog::scoped!(logger => "local");
10200 let buffers = buffers
10201 .into_iter()
10202 .map(|buffer_handle| {
10203 let buffer = buffer_handle.read(cx);
10204 let buffer_abs_path = File::from_dyn(buffer.file())
10205 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10206
10207 (buffer_handle, buffer_abs_path, buffer.remote_id())
10208 })
10209 .collect::<Vec<_>>();
10210
10211 cx.spawn(async move |lsp_store, cx| {
10212 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10213
10214 for (handle, abs_path, id) in buffers {
10215 let env = lsp_store
10216 .update(cx, |lsp_store, cx| {
10217 lsp_store.environment_for_buffer(&handle, cx)
10218 })?
10219 .await;
10220
10221 let ranges = match &target {
10222 LspFormatTarget::Buffers => None,
10223 LspFormatTarget::Ranges(ranges) => {
10224 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10225 }
10226 };
10227
10228 formattable_buffers.push(FormattableBuffer {
10229 handle,
10230 abs_path,
10231 env,
10232 ranges,
10233 });
10234 }
10235 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10236
10237 let format_timer = zlog::time!(logger => "Formatting buffers");
10238 let result = LocalLspStore::format_locally(
10239 lsp_store.clone(),
10240 formattable_buffers,
10241 push_to_history,
10242 trigger,
10243 logger,
10244 cx,
10245 )
10246 .await;
10247 format_timer.end();
10248
10249 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10250
10251 lsp_store.update(cx, |lsp_store, _| {
10252 lsp_store.update_last_formatting_failure(&result);
10253 })?;
10254
10255 result
10256 })
10257 } else if let Some((client, project_id)) = self.upstream_client() {
10258 zlog::trace!(logger => "Formatting remotely");
10259 let logger = zlog::scoped!(logger => "remote");
10260 // Don't support formatting ranges via remote
10261 match target {
10262 LspFormatTarget::Buffers => {}
10263 LspFormatTarget::Ranges(_) => {
10264 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10265 return Task::ready(Ok(ProjectTransaction::default()));
10266 }
10267 }
10268
10269 let buffer_store = self.buffer_store();
10270 cx.spawn(async move |lsp_store, cx| {
10271 zlog::trace!(logger => "Sending remote format request");
10272 let request_timer = zlog::time!(logger => "remote format request");
10273 let result = client
10274 .request(proto::FormatBuffers {
10275 project_id,
10276 trigger: trigger as i32,
10277 buffer_ids: buffers
10278 .iter()
10279 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10280 .collect::<Result<_>>()?,
10281 })
10282 .await
10283 .and_then(|result| result.transaction.context("missing transaction"));
10284 request_timer.end();
10285
10286 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10287
10288 lsp_store.update(cx, |lsp_store, _| {
10289 lsp_store.update_last_formatting_failure(&result);
10290 })?;
10291
10292 let transaction_response = result?;
10293 let _timer = zlog::time!(logger => "deserializing project transaction");
10294 buffer_store
10295 .update(cx, |buffer_store, cx| {
10296 buffer_store.deserialize_project_transaction(
10297 transaction_response,
10298 push_to_history,
10299 cx,
10300 )
10301 })?
10302 .await
10303 })
10304 } else {
10305 zlog::trace!(logger => "Not formatting");
10306 Task::ready(Ok(ProjectTransaction::default()))
10307 }
10308 }
10309
10310 async fn handle_format_buffers(
10311 this: Entity<Self>,
10312 envelope: TypedEnvelope<proto::FormatBuffers>,
10313 mut cx: AsyncApp,
10314 ) -> Result<proto::FormatBuffersResponse> {
10315 let sender_id = envelope.original_sender_id().unwrap_or_default();
10316 let format = this.update(&mut cx, |this, cx| {
10317 let mut buffers = HashSet::default();
10318 for buffer_id in &envelope.payload.buffer_ids {
10319 let buffer_id = BufferId::new(*buffer_id)?;
10320 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10321 }
10322 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10323 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10324 })??;
10325
10326 let project_transaction = format.await?;
10327 let project_transaction = this.update(&mut cx, |this, cx| {
10328 this.buffer_store.update(cx, |buffer_store, cx| {
10329 buffer_store.serialize_project_transaction_for_peer(
10330 project_transaction,
10331 sender_id,
10332 cx,
10333 )
10334 })
10335 })?;
10336 Ok(proto::FormatBuffersResponse {
10337 transaction: Some(project_transaction),
10338 })
10339 }
10340
10341 async fn handle_apply_code_action_kind(
10342 this: Entity<Self>,
10343 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10344 mut cx: AsyncApp,
10345 ) -> Result<proto::ApplyCodeActionKindResponse> {
10346 let sender_id = envelope.original_sender_id().unwrap_or_default();
10347 let format = this.update(&mut cx, |this, cx| {
10348 let mut buffers = HashSet::default();
10349 for buffer_id in &envelope.payload.buffer_ids {
10350 let buffer_id = BufferId::new(*buffer_id)?;
10351 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10352 }
10353 let kind = match envelope.payload.kind.as_str() {
10354 "" => CodeActionKind::EMPTY,
10355 "quickfix" => CodeActionKind::QUICKFIX,
10356 "refactor" => CodeActionKind::REFACTOR,
10357 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10358 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10359 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10360 "source" => CodeActionKind::SOURCE,
10361 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10362 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10363 _ => anyhow::bail!(
10364 "Invalid code action kind {}",
10365 envelope.payload.kind.as_str()
10366 ),
10367 };
10368 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10369 })??;
10370
10371 let project_transaction = format.await?;
10372 let project_transaction = this.update(&mut cx, |this, cx| {
10373 this.buffer_store.update(cx, |buffer_store, cx| {
10374 buffer_store.serialize_project_transaction_for_peer(
10375 project_transaction,
10376 sender_id,
10377 cx,
10378 )
10379 })
10380 })?;
10381 Ok(proto::ApplyCodeActionKindResponse {
10382 transaction: Some(project_transaction),
10383 })
10384 }
10385
10386 async fn shutdown_language_server(
10387 server_state: Option<LanguageServerState>,
10388 name: LanguageServerName,
10389 cx: &mut AsyncApp,
10390 ) {
10391 let server = match server_state {
10392 Some(LanguageServerState::Starting { startup, .. }) => {
10393 let mut timer = cx
10394 .background_executor()
10395 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10396 .fuse();
10397
10398 select! {
10399 server = startup.fuse() => server,
10400 () = timer => {
10401 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10402 None
10403 },
10404 }
10405 }
10406
10407 Some(LanguageServerState::Running { server, .. }) => Some(server),
10408
10409 None => None,
10410 };
10411
10412 if let Some(server) = server
10413 && let Some(shutdown) = server.shutdown()
10414 {
10415 shutdown.await;
10416 }
10417 }
10418
10419 // Returns a list of all of the worktrees which no longer have a language server and the root path
10420 // for the stopped server
10421 fn stop_local_language_server(
10422 &mut self,
10423 server_id: LanguageServerId,
10424 cx: &mut Context<Self>,
10425 ) -> Task<()> {
10426 let local = match &mut self.mode {
10427 LspStoreMode::Local(local) => local,
10428 _ => {
10429 return Task::ready(());
10430 }
10431 };
10432
10433 // Remove this server ID from all entries in the given worktree.
10434 local
10435 .language_server_ids
10436 .retain(|_, state| state.id != server_id);
10437 self.buffer_store.update(cx, |buffer_store, cx| {
10438 for buffer in buffer_store.buffers() {
10439 buffer.update(cx, |buffer, cx| {
10440 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10441 buffer.set_completion_triggers(server_id, Default::default(), cx);
10442 });
10443 }
10444 });
10445
10446 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10447 summaries.retain(|path, summaries_by_server_id| {
10448 if summaries_by_server_id.remove(&server_id).is_some() {
10449 if let Some((client, project_id)) = self.downstream_client.clone() {
10450 client
10451 .send(proto::UpdateDiagnosticSummary {
10452 project_id,
10453 worktree_id: worktree_id.to_proto(),
10454 summary: Some(proto::DiagnosticSummary {
10455 path: path.as_ref().to_proto(),
10456 language_server_id: server_id.0 as u64,
10457 error_count: 0,
10458 warning_count: 0,
10459 }),
10460 more_summaries: Vec::new(),
10461 })
10462 .log_err();
10463 }
10464 !summaries_by_server_id.is_empty()
10465 } else {
10466 true
10467 }
10468 });
10469 }
10470
10471 let local = self.as_local_mut().unwrap();
10472 for diagnostics in local.diagnostics.values_mut() {
10473 diagnostics.retain(|_, diagnostics_by_server_id| {
10474 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10475 diagnostics_by_server_id.remove(ix);
10476 !diagnostics_by_server_id.is_empty()
10477 } else {
10478 true
10479 }
10480 });
10481 }
10482 local.language_server_watched_paths.remove(&server_id);
10483
10484 let server_state = local.language_servers.remove(&server_id);
10485 self.cleanup_lsp_data(server_id);
10486 let name = self
10487 .language_server_statuses
10488 .remove(&server_id)
10489 .map(|status| status.name)
10490 .or_else(|| {
10491 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10492 Some(adapter.name())
10493 } else {
10494 None
10495 }
10496 });
10497
10498 if let Some(name) = name {
10499 log::info!("stopping language server {name}");
10500 self.languages
10501 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10502 cx.notify();
10503
10504 return cx.spawn(async move |lsp_store, cx| {
10505 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10506 lsp_store
10507 .update(cx, |lsp_store, cx| {
10508 lsp_store
10509 .languages
10510 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10511 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10512 cx.notify();
10513 })
10514 .ok();
10515 });
10516 }
10517
10518 if server_state.is_some() {
10519 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10520 }
10521 Task::ready(())
10522 }
10523
10524 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10525 if let Some((client, project_id)) = self.upstream_client() {
10526 let request = client.request(proto::StopLanguageServers {
10527 project_id,
10528 buffer_ids: Vec::new(),
10529 also_servers: Vec::new(),
10530 all: true,
10531 });
10532 cx.background_spawn(request).detach_and_log_err(cx);
10533 } else {
10534 let Some(local) = self.as_local_mut() else {
10535 return;
10536 };
10537 let language_servers_to_stop = local
10538 .language_server_ids
10539 .values()
10540 .map(|state| state.id)
10541 .collect();
10542 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10543 let tasks = language_servers_to_stop
10544 .into_iter()
10545 .map(|server| self.stop_local_language_server(server, cx))
10546 .collect::<Vec<_>>();
10547 cx.background_spawn(async move {
10548 futures::future::join_all(tasks).await;
10549 })
10550 .detach();
10551 }
10552 }
10553
10554 pub fn restart_language_servers_for_buffers(
10555 &mut self,
10556 buffers: Vec<Entity<Buffer>>,
10557 only_restart_servers: HashSet<LanguageServerSelector>,
10558 cx: &mut Context<Self>,
10559 ) {
10560 if let Some((client, project_id)) = self.upstream_client() {
10561 let request = client.request(proto::RestartLanguageServers {
10562 project_id,
10563 buffer_ids: buffers
10564 .into_iter()
10565 .map(|b| b.read(cx).remote_id().to_proto())
10566 .collect(),
10567 only_servers: only_restart_servers
10568 .into_iter()
10569 .map(|selector| {
10570 let selector = match selector {
10571 LanguageServerSelector::Id(language_server_id) => {
10572 proto::language_server_selector::Selector::ServerId(
10573 language_server_id.to_proto(),
10574 )
10575 }
10576 LanguageServerSelector::Name(language_server_name) => {
10577 proto::language_server_selector::Selector::Name(
10578 language_server_name.to_string(),
10579 )
10580 }
10581 };
10582 proto::LanguageServerSelector {
10583 selector: Some(selector),
10584 }
10585 })
10586 .collect(),
10587 all: false,
10588 });
10589 cx.background_spawn(request).detach_and_log_err(cx);
10590 } else {
10591 let stop_task = if only_restart_servers.is_empty() {
10592 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10593 } else {
10594 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10595 };
10596 cx.spawn(async move |lsp_store, cx| {
10597 stop_task.await;
10598 lsp_store
10599 .update(cx, |lsp_store, cx| {
10600 for buffer in buffers {
10601 lsp_store.register_buffer_with_language_servers(
10602 &buffer,
10603 only_restart_servers.clone(),
10604 true,
10605 cx,
10606 );
10607 }
10608 })
10609 .ok()
10610 })
10611 .detach();
10612 }
10613 }
10614
10615 pub fn stop_language_servers_for_buffers(
10616 &mut self,
10617 buffers: Vec<Entity<Buffer>>,
10618 also_stop_servers: HashSet<LanguageServerSelector>,
10619 cx: &mut Context<Self>,
10620 ) -> Task<Result<()>> {
10621 if let Some((client, project_id)) = self.upstream_client() {
10622 let request = client.request(proto::StopLanguageServers {
10623 project_id,
10624 buffer_ids: buffers
10625 .into_iter()
10626 .map(|b| b.read(cx).remote_id().to_proto())
10627 .collect(),
10628 also_servers: also_stop_servers
10629 .into_iter()
10630 .map(|selector| {
10631 let selector = match selector {
10632 LanguageServerSelector::Id(language_server_id) => {
10633 proto::language_server_selector::Selector::ServerId(
10634 language_server_id.to_proto(),
10635 )
10636 }
10637 LanguageServerSelector::Name(language_server_name) => {
10638 proto::language_server_selector::Selector::Name(
10639 language_server_name.to_string(),
10640 )
10641 }
10642 };
10643 proto::LanguageServerSelector {
10644 selector: Some(selector),
10645 }
10646 })
10647 .collect(),
10648 all: false,
10649 });
10650 cx.background_spawn(async move {
10651 let _ = request.await?;
10652 Ok(())
10653 })
10654 } else {
10655 let task =
10656 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10657 cx.background_spawn(async move {
10658 task.await;
10659 Ok(())
10660 })
10661 }
10662 }
10663
10664 fn stop_local_language_servers_for_buffers(
10665 &mut self,
10666 buffers: &[Entity<Buffer>],
10667 also_stop_servers: HashSet<LanguageServerSelector>,
10668 cx: &mut Context<Self>,
10669 ) -> Task<()> {
10670 let Some(local) = self.as_local_mut() else {
10671 return Task::ready(());
10672 };
10673 let mut language_server_names_to_stop = BTreeSet::default();
10674 let mut language_servers_to_stop = also_stop_servers
10675 .into_iter()
10676 .flat_map(|selector| match selector {
10677 LanguageServerSelector::Id(id) => Some(id),
10678 LanguageServerSelector::Name(name) => {
10679 language_server_names_to_stop.insert(name);
10680 None
10681 }
10682 })
10683 .collect::<BTreeSet<_>>();
10684
10685 let mut covered_worktrees = HashSet::default();
10686 for buffer in buffers {
10687 buffer.update(cx, |buffer, cx| {
10688 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10689 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10690 && covered_worktrees.insert(worktree_id)
10691 {
10692 language_server_names_to_stop.retain(|name| {
10693 let old_ids_count = language_servers_to_stop.len();
10694 let all_language_servers_with_this_name = local
10695 .language_server_ids
10696 .iter()
10697 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10698 language_servers_to_stop.extend(all_language_servers_with_this_name);
10699 old_ids_count == language_servers_to_stop.len()
10700 });
10701 }
10702 });
10703 }
10704 for name in language_server_names_to_stop {
10705 language_servers_to_stop.extend(
10706 local
10707 .language_server_ids
10708 .iter()
10709 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10710 );
10711 }
10712
10713 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10714 let tasks = language_servers_to_stop
10715 .into_iter()
10716 .map(|server| self.stop_local_language_server(server, cx))
10717 .collect::<Vec<_>>();
10718
10719 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10720 }
10721
10722 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10723 let (worktree, relative_path) =
10724 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10725
10726 let project_path = ProjectPath {
10727 worktree_id: worktree.read(cx).id(),
10728 path: relative_path,
10729 };
10730
10731 Some(
10732 self.buffer_store()
10733 .read(cx)
10734 .get_by_path(&project_path)?
10735 .read(cx),
10736 )
10737 }
10738
10739 #[cfg(any(test, feature = "test-support"))]
10740 pub fn update_diagnostics(
10741 &mut self,
10742 server_id: LanguageServerId,
10743 diagnostics: lsp::PublishDiagnosticsParams,
10744 result_id: Option<String>,
10745 source_kind: DiagnosticSourceKind,
10746 disk_based_sources: &[String],
10747 cx: &mut Context<Self>,
10748 ) -> Result<()> {
10749 self.merge_lsp_diagnostics(
10750 source_kind,
10751 vec![DocumentDiagnosticsUpdate {
10752 diagnostics,
10753 result_id,
10754 server_id,
10755 disk_based_sources: Cow::Borrowed(disk_based_sources),
10756 }],
10757 |_, _, _| false,
10758 cx,
10759 )
10760 }
10761
10762 pub fn merge_lsp_diagnostics(
10763 &mut self,
10764 source_kind: DiagnosticSourceKind,
10765 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10766 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10767 cx: &mut Context<Self>,
10768 ) -> Result<()> {
10769 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10770 let updates = lsp_diagnostics
10771 .into_iter()
10772 .filter_map(|update| {
10773 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10774 Some(DocumentDiagnosticsUpdate {
10775 diagnostics: self.lsp_to_document_diagnostics(
10776 abs_path,
10777 source_kind,
10778 update.server_id,
10779 update.diagnostics,
10780 &update.disk_based_sources,
10781 ),
10782 result_id: update.result_id,
10783 server_id: update.server_id,
10784 disk_based_sources: update.disk_based_sources,
10785 })
10786 })
10787 .collect();
10788 self.merge_diagnostic_entries(updates, merge, cx)?;
10789 Ok(())
10790 }
10791
10792 fn lsp_to_document_diagnostics(
10793 &mut self,
10794 document_abs_path: PathBuf,
10795 source_kind: DiagnosticSourceKind,
10796 server_id: LanguageServerId,
10797 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10798 disk_based_sources: &[String],
10799 ) -> DocumentDiagnostics {
10800 let mut diagnostics = Vec::default();
10801 let mut primary_diagnostic_group_ids = HashMap::default();
10802 let mut sources_by_group_id = HashMap::default();
10803 let mut supporting_diagnostics = HashMap::default();
10804
10805 let adapter = self.language_server_adapter_for_id(server_id);
10806
10807 // Ensure that primary diagnostics are always the most severe
10808 lsp_diagnostics
10809 .diagnostics
10810 .sort_by_key(|item| item.severity);
10811
10812 for diagnostic in &lsp_diagnostics.diagnostics {
10813 let source = diagnostic.source.as_ref();
10814 let range = range_from_lsp(diagnostic.range);
10815 let is_supporting = diagnostic
10816 .related_information
10817 .as_ref()
10818 .is_some_and(|infos| {
10819 infos.iter().any(|info| {
10820 primary_diagnostic_group_ids.contains_key(&(
10821 source,
10822 diagnostic.code.clone(),
10823 range_from_lsp(info.location.range),
10824 ))
10825 })
10826 });
10827
10828 let is_unnecessary = diagnostic
10829 .tags
10830 .as_ref()
10831 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10832
10833 let underline = self
10834 .language_server_adapter_for_id(server_id)
10835 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10836
10837 if is_supporting {
10838 supporting_diagnostics.insert(
10839 (source, diagnostic.code.clone(), range),
10840 (diagnostic.severity, is_unnecessary),
10841 );
10842 } else {
10843 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10844 let is_disk_based =
10845 source.is_some_and(|source| disk_based_sources.contains(source));
10846
10847 sources_by_group_id.insert(group_id, source);
10848 primary_diagnostic_group_ids
10849 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10850
10851 diagnostics.push(DiagnosticEntry {
10852 range,
10853 diagnostic: Diagnostic {
10854 source: diagnostic.source.clone(),
10855 source_kind,
10856 code: diagnostic.code.clone(),
10857 code_description: diagnostic
10858 .code_description
10859 .as_ref()
10860 .and_then(|d| d.href.clone()),
10861 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10862 markdown: adapter.as_ref().and_then(|adapter| {
10863 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10864 }),
10865 message: diagnostic.message.trim().to_string(),
10866 group_id,
10867 is_primary: true,
10868 is_disk_based,
10869 is_unnecessary,
10870 underline,
10871 data: diagnostic.data.clone(),
10872 },
10873 });
10874 if let Some(infos) = &diagnostic.related_information {
10875 for info in infos {
10876 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10877 let range = range_from_lsp(info.location.range);
10878 diagnostics.push(DiagnosticEntry {
10879 range,
10880 diagnostic: Diagnostic {
10881 source: diagnostic.source.clone(),
10882 source_kind,
10883 code: diagnostic.code.clone(),
10884 code_description: diagnostic
10885 .code_description
10886 .as_ref()
10887 .and_then(|d| d.href.clone()),
10888 severity: DiagnosticSeverity::INFORMATION,
10889 markdown: adapter.as_ref().and_then(|adapter| {
10890 adapter.diagnostic_message_to_markdown(&info.message)
10891 }),
10892 message: info.message.trim().to_string(),
10893 group_id,
10894 is_primary: false,
10895 is_disk_based,
10896 is_unnecessary: false,
10897 underline,
10898 data: diagnostic.data.clone(),
10899 },
10900 });
10901 }
10902 }
10903 }
10904 }
10905 }
10906
10907 for entry in &mut diagnostics {
10908 let diagnostic = &mut entry.diagnostic;
10909 if !diagnostic.is_primary {
10910 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10911 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10912 source,
10913 diagnostic.code.clone(),
10914 entry.range.clone(),
10915 )) {
10916 if let Some(severity) = severity {
10917 diagnostic.severity = severity;
10918 }
10919 diagnostic.is_unnecessary = is_unnecessary;
10920 }
10921 }
10922 }
10923
10924 DocumentDiagnostics {
10925 diagnostics,
10926 document_abs_path,
10927 version: lsp_diagnostics.version,
10928 }
10929 }
10930
10931 fn insert_newly_running_language_server(
10932 &mut self,
10933 adapter: Arc<CachedLspAdapter>,
10934 language_server: Arc<LanguageServer>,
10935 server_id: LanguageServerId,
10936 key: LanguageServerSeed,
10937 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10938 cx: &mut Context<Self>,
10939 ) {
10940 let Some(local) = self.as_local_mut() else {
10941 return;
10942 };
10943 // If the language server for this key doesn't match the server id, don't store the
10944 // server. Which will cause it to be dropped, killing the process
10945 if local
10946 .language_server_ids
10947 .get(&key)
10948 .map(|state| state.id != server_id)
10949 .unwrap_or(false)
10950 {
10951 return;
10952 }
10953
10954 // Update language_servers collection with Running variant of LanguageServerState
10955 // indicating that the server is up and running and ready
10956 let workspace_folders = workspace_folders.lock().clone();
10957 language_server.set_workspace_folders(workspace_folders);
10958
10959 let workspace_diagnostics_refresh_tasks = language_server
10960 .capabilities()
10961 .diagnostic_provider
10962 .and_then(|provider| {
10963 local
10964 .language_server_dynamic_registrations
10965 .entry(server_id)
10966 .or_default()
10967 .diagnostics
10968 .entry(None)
10969 .or_insert(provider.clone());
10970 let workspace_refresher =
10971 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10972
10973 Some((None, workspace_refresher))
10974 })
10975 .into_iter()
10976 .collect();
10977 local.language_servers.insert(
10978 server_id,
10979 LanguageServerState::Running {
10980 workspace_diagnostics_refresh_tasks,
10981 adapter: adapter.clone(),
10982 server: language_server.clone(),
10983 simulate_disk_based_diagnostics_completion: None,
10984 },
10985 );
10986 local
10987 .languages
10988 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10989 if let Some(file_ops_caps) = language_server
10990 .capabilities()
10991 .workspace
10992 .as_ref()
10993 .and_then(|ws| ws.file_operations.as_ref())
10994 {
10995 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10996 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10997 if did_rename_caps.or(will_rename_caps).is_some() {
10998 let watcher = RenamePathsWatchedForServer::default()
10999 .with_did_rename_patterns(did_rename_caps)
11000 .with_will_rename_patterns(will_rename_caps);
11001 local
11002 .language_server_paths_watched_for_rename
11003 .insert(server_id, watcher);
11004 }
11005 }
11006
11007 self.language_server_statuses.insert(
11008 server_id,
11009 LanguageServerStatus {
11010 name: language_server.name(),
11011 pending_work: Default::default(),
11012 has_pending_diagnostic_updates: false,
11013 progress_tokens: Default::default(),
11014 worktree: Some(key.worktree_id),
11015 },
11016 );
11017
11018 cx.emit(LspStoreEvent::LanguageServerAdded(
11019 server_id,
11020 language_server.name(),
11021 Some(key.worktree_id),
11022 ));
11023
11024 let server_capabilities = language_server.capabilities();
11025 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11026 downstream_client
11027 .send(proto::StartLanguageServer {
11028 project_id: *project_id,
11029 server: Some(proto::LanguageServer {
11030 id: server_id.to_proto(),
11031 name: language_server.name().to_string(),
11032 worktree_id: Some(key.worktree_id.to_proto()),
11033 }),
11034 capabilities: serde_json::to_string(&server_capabilities)
11035 .expect("serializing server LSP capabilities"),
11036 })
11037 .log_err();
11038 }
11039 self.lsp_server_capabilities
11040 .insert(server_id, server_capabilities);
11041
11042 // Tell the language server about every open buffer in the worktree that matches the language.
11043 // Also check for buffers in worktrees that reused this server
11044 let mut worktrees_using_server = vec![key.worktree_id];
11045 if let Some(local) = self.as_local() {
11046 // Find all worktrees that have this server in their language server tree
11047 for (worktree_id, servers) in &local.lsp_tree.instances {
11048 if *worktree_id != key.worktree_id {
11049 for server_map in servers.roots.values() {
11050 if server_map
11051 .values()
11052 .any(|(node, _)| node.id() == Some(server_id))
11053 {
11054 worktrees_using_server.push(*worktree_id);
11055 }
11056 }
11057 }
11058 }
11059 }
11060
11061 let mut buffer_paths_registered = Vec::new();
11062 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11063 let mut lsp_adapters = HashMap::default();
11064 for buffer_handle in buffer_store.buffers() {
11065 let buffer = buffer_handle.read(cx);
11066 let file = match File::from_dyn(buffer.file()) {
11067 Some(file) => file,
11068 None => continue,
11069 };
11070 let language = match buffer.language() {
11071 Some(language) => language,
11072 None => continue,
11073 };
11074
11075 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11076 || !lsp_adapters
11077 .entry(language.name())
11078 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11079 .iter()
11080 .any(|a| a.name == key.name)
11081 {
11082 continue;
11083 }
11084 // didOpen
11085 let file = match file.as_local() {
11086 Some(file) => file,
11087 None => continue,
11088 };
11089
11090 let local = self.as_local_mut().unwrap();
11091
11092 let buffer_id = buffer.remote_id();
11093 if local.registered_buffers.contains_key(&buffer_id) {
11094 let versions = local
11095 .buffer_snapshots
11096 .entry(buffer_id)
11097 .or_default()
11098 .entry(server_id)
11099 .and_modify(|_| {
11100 assert!(
11101 false,
11102 "There should not be an existing snapshot for a newly inserted buffer"
11103 )
11104 })
11105 .or_insert_with(|| {
11106 vec![LspBufferSnapshot {
11107 version: 0,
11108 snapshot: buffer.text_snapshot(),
11109 }]
11110 });
11111
11112 let snapshot = versions.last().unwrap();
11113 let version = snapshot.version;
11114 let initial_snapshot = &snapshot.snapshot;
11115 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11116 language_server.register_buffer(
11117 uri,
11118 adapter.language_id(&language.name()),
11119 version,
11120 initial_snapshot.text(),
11121 );
11122 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11123 local
11124 .buffers_opened_in_servers
11125 .entry(buffer_id)
11126 .or_default()
11127 .insert(server_id);
11128 }
11129 buffer_handle.update(cx, |buffer, cx| {
11130 buffer.set_completion_triggers(
11131 server_id,
11132 language_server
11133 .capabilities()
11134 .completion_provider
11135 .as_ref()
11136 .and_then(|provider| {
11137 provider
11138 .trigger_characters
11139 .as_ref()
11140 .map(|characters| characters.iter().cloned().collect())
11141 })
11142 .unwrap_or_default(),
11143 cx,
11144 )
11145 });
11146 }
11147 });
11148
11149 for (buffer_id, abs_path) in buffer_paths_registered {
11150 cx.emit(LspStoreEvent::LanguageServerUpdate {
11151 language_server_id: server_id,
11152 name: Some(adapter.name()),
11153 message: proto::update_language_server::Variant::RegisteredForBuffer(
11154 proto::RegisteredForBuffer {
11155 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11156 buffer_id: buffer_id.to_proto(),
11157 },
11158 ),
11159 });
11160 }
11161
11162 cx.notify();
11163 }
11164
11165 pub fn language_servers_running_disk_based_diagnostics(
11166 &self,
11167 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11168 self.language_server_statuses
11169 .iter()
11170 .filter_map(|(id, status)| {
11171 if status.has_pending_diagnostic_updates {
11172 Some(*id)
11173 } else {
11174 None
11175 }
11176 })
11177 }
11178
11179 pub(crate) fn cancel_language_server_work_for_buffers(
11180 &mut self,
11181 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11182 cx: &mut Context<Self>,
11183 ) {
11184 if let Some((client, project_id)) = self.upstream_client() {
11185 let request = client.request(proto::CancelLanguageServerWork {
11186 project_id,
11187 work: Some(proto::cancel_language_server_work::Work::Buffers(
11188 proto::cancel_language_server_work::Buffers {
11189 buffer_ids: buffers
11190 .into_iter()
11191 .map(|b| b.read(cx).remote_id().to_proto())
11192 .collect(),
11193 },
11194 )),
11195 });
11196 cx.background_spawn(request).detach_and_log_err(cx);
11197 } else if let Some(local) = self.as_local() {
11198 let servers = buffers
11199 .into_iter()
11200 .flat_map(|buffer| {
11201 buffer.update(cx, |buffer, cx| {
11202 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11203 })
11204 })
11205 .collect::<HashSet<_>>();
11206 for server_id in servers {
11207 self.cancel_language_server_work(server_id, None, cx);
11208 }
11209 }
11210 }
11211
11212 pub(crate) fn cancel_language_server_work(
11213 &mut self,
11214 server_id: LanguageServerId,
11215 token_to_cancel: Option<ProgressToken>,
11216 cx: &mut Context<Self>,
11217 ) {
11218 if let Some(local) = self.as_local() {
11219 let status = self.language_server_statuses.get(&server_id);
11220 let server = local.language_servers.get(&server_id);
11221 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11222 {
11223 for (token, progress) in &status.pending_work {
11224 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11225 && token != token_to_cancel
11226 {
11227 continue;
11228 }
11229 if progress.is_cancellable {
11230 server
11231 .notify::<lsp::notification::WorkDoneProgressCancel>(
11232 WorkDoneProgressCancelParams {
11233 token: token.to_lsp(),
11234 },
11235 )
11236 .ok();
11237 }
11238 }
11239 }
11240 } else if let Some((client, project_id)) = self.upstream_client() {
11241 let request = client.request(proto::CancelLanguageServerWork {
11242 project_id,
11243 work: Some(
11244 proto::cancel_language_server_work::Work::LanguageServerWork(
11245 proto::cancel_language_server_work::LanguageServerWork {
11246 language_server_id: server_id.to_proto(),
11247 token: token_to_cancel.map(|token| token.to_proto()),
11248 },
11249 ),
11250 ),
11251 });
11252 cx.background_spawn(request).detach_and_log_err(cx);
11253 }
11254 }
11255
11256 fn register_supplementary_language_server(
11257 &mut self,
11258 id: LanguageServerId,
11259 name: LanguageServerName,
11260 server: Arc<LanguageServer>,
11261 cx: &mut Context<Self>,
11262 ) {
11263 if let Some(local) = self.as_local_mut() {
11264 local
11265 .supplementary_language_servers
11266 .insert(id, (name.clone(), server));
11267 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11268 }
11269 }
11270
11271 fn unregister_supplementary_language_server(
11272 &mut self,
11273 id: LanguageServerId,
11274 cx: &mut Context<Self>,
11275 ) {
11276 if let Some(local) = self.as_local_mut() {
11277 local.supplementary_language_servers.remove(&id);
11278 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11279 }
11280 }
11281
11282 pub(crate) fn supplementary_language_servers(
11283 &self,
11284 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11285 self.as_local().into_iter().flat_map(|local| {
11286 local
11287 .supplementary_language_servers
11288 .iter()
11289 .map(|(id, (name, _))| (*id, name.clone()))
11290 })
11291 }
11292
11293 pub fn language_server_adapter_for_id(
11294 &self,
11295 id: LanguageServerId,
11296 ) -> Option<Arc<CachedLspAdapter>> {
11297 self.as_local()
11298 .and_then(|local| local.language_servers.get(&id))
11299 .and_then(|language_server_state| match language_server_state {
11300 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11301 _ => None,
11302 })
11303 }
11304
11305 pub(super) fn update_local_worktree_language_servers(
11306 &mut self,
11307 worktree_handle: &Entity<Worktree>,
11308 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11309 cx: &mut Context<Self>,
11310 ) {
11311 if changes.is_empty() {
11312 return;
11313 }
11314
11315 let Some(local) = self.as_local() else { return };
11316
11317 local.prettier_store.update(cx, |prettier_store, cx| {
11318 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11319 });
11320
11321 let worktree_id = worktree_handle.read(cx).id();
11322 let mut language_server_ids = local
11323 .language_server_ids
11324 .iter()
11325 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11326 .collect::<Vec<_>>();
11327 language_server_ids.sort();
11328 language_server_ids.dedup();
11329
11330 // let abs_path = worktree_handle.read(cx).abs_path();
11331 for server_id in &language_server_ids {
11332 if let Some(LanguageServerState::Running { server, .. }) =
11333 local.language_servers.get(server_id)
11334 && let Some(watched_paths) = local
11335 .language_server_watched_paths
11336 .get(server_id)
11337 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11338 {
11339 let params = lsp::DidChangeWatchedFilesParams {
11340 changes: changes
11341 .iter()
11342 .filter_map(|(path, _, change)| {
11343 if !watched_paths.is_match(path.as_std_path()) {
11344 return None;
11345 }
11346 let typ = match change {
11347 PathChange::Loaded => return None,
11348 PathChange::Added => lsp::FileChangeType::CREATED,
11349 PathChange::Removed => lsp::FileChangeType::DELETED,
11350 PathChange::Updated => lsp::FileChangeType::CHANGED,
11351 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11352 };
11353 let uri = lsp::Uri::from_file_path(
11354 worktree_handle.read(cx).absolutize(&path),
11355 )
11356 .ok()?;
11357 Some(lsp::FileEvent { uri, typ })
11358 })
11359 .collect(),
11360 };
11361 if !params.changes.is_empty() {
11362 server
11363 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11364 .ok();
11365 }
11366 }
11367 }
11368 for (path, _, _) in changes {
11369 if let Some(file_name) = path.file_name()
11370 && local.watched_manifest_filenames.contains(file_name)
11371 {
11372 self.request_workspace_config_refresh();
11373 break;
11374 }
11375 }
11376 }
11377
11378 pub fn wait_for_remote_buffer(
11379 &mut self,
11380 id: BufferId,
11381 cx: &mut Context<Self>,
11382 ) -> Task<Result<Entity<Buffer>>> {
11383 self.buffer_store.update(cx, |buffer_store, cx| {
11384 buffer_store.wait_for_remote_buffer(id, cx)
11385 })
11386 }
11387
11388 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11389 let mut result = proto::Symbol {
11390 language_server_name: symbol.language_server_name.0.to_string(),
11391 source_worktree_id: symbol.source_worktree_id.to_proto(),
11392 language_server_id: symbol.source_language_server_id.to_proto(),
11393 name: symbol.name.clone(),
11394 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11395 start: Some(proto::PointUtf16 {
11396 row: symbol.range.start.0.row,
11397 column: symbol.range.start.0.column,
11398 }),
11399 end: Some(proto::PointUtf16 {
11400 row: symbol.range.end.0.row,
11401 column: symbol.range.end.0.column,
11402 }),
11403 worktree_id: Default::default(),
11404 path: Default::default(),
11405 signature: Default::default(),
11406 };
11407 match &symbol.path {
11408 SymbolLocation::InProject(path) => {
11409 result.worktree_id = path.worktree_id.to_proto();
11410 result.path = path.path.to_proto();
11411 }
11412 SymbolLocation::OutsideProject {
11413 abs_path,
11414 signature,
11415 } => {
11416 result.path = abs_path.to_string_lossy().into_owned();
11417 result.signature = signature.to_vec();
11418 }
11419 }
11420 result
11421 }
11422
11423 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11424 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11425 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11426 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11427
11428 let path = if serialized_symbol.signature.is_empty() {
11429 SymbolLocation::InProject(ProjectPath {
11430 worktree_id,
11431 path: RelPath::from_proto(&serialized_symbol.path)
11432 .context("invalid symbol path")?,
11433 })
11434 } else {
11435 SymbolLocation::OutsideProject {
11436 abs_path: Path::new(&serialized_symbol.path).into(),
11437 signature: serialized_symbol
11438 .signature
11439 .try_into()
11440 .map_err(|_| anyhow!("invalid signature"))?,
11441 }
11442 };
11443
11444 let start = serialized_symbol.start.context("invalid start")?;
11445 let end = serialized_symbol.end.context("invalid end")?;
11446 Ok(CoreSymbol {
11447 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11448 source_worktree_id,
11449 source_language_server_id: LanguageServerId::from_proto(
11450 serialized_symbol.language_server_id,
11451 ),
11452 path,
11453 name: serialized_symbol.name,
11454 range: Unclipped(PointUtf16::new(start.row, start.column))
11455 ..Unclipped(PointUtf16::new(end.row, end.column)),
11456 kind,
11457 })
11458 }
11459
11460 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11461 let mut serialized_completion = proto::Completion {
11462 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11463 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11464 new_text: completion.new_text.clone(),
11465 ..proto::Completion::default()
11466 };
11467 match &completion.source {
11468 CompletionSource::Lsp {
11469 insert_range,
11470 server_id,
11471 lsp_completion,
11472 lsp_defaults,
11473 resolved,
11474 } => {
11475 let (old_insert_start, old_insert_end) = insert_range
11476 .as_ref()
11477 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11478 .unzip();
11479
11480 serialized_completion.old_insert_start = old_insert_start;
11481 serialized_completion.old_insert_end = old_insert_end;
11482 serialized_completion.source = proto::completion::Source::Lsp as i32;
11483 serialized_completion.server_id = server_id.0 as u64;
11484 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11485 serialized_completion.lsp_defaults = lsp_defaults
11486 .as_deref()
11487 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11488 serialized_completion.resolved = *resolved;
11489 }
11490 CompletionSource::BufferWord {
11491 word_range,
11492 resolved,
11493 } => {
11494 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11495 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11496 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11497 serialized_completion.resolved = *resolved;
11498 }
11499 CompletionSource::Custom => {
11500 serialized_completion.source = proto::completion::Source::Custom as i32;
11501 serialized_completion.resolved = true;
11502 }
11503 CompletionSource::Dap { sort_text } => {
11504 serialized_completion.source = proto::completion::Source::Dap as i32;
11505 serialized_completion.sort_text = Some(sort_text.clone());
11506 }
11507 }
11508
11509 serialized_completion
11510 }
11511
11512 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11513 let old_replace_start = completion
11514 .old_replace_start
11515 .and_then(deserialize_anchor)
11516 .context("invalid old start")?;
11517 let old_replace_end = completion
11518 .old_replace_end
11519 .and_then(deserialize_anchor)
11520 .context("invalid old end")?;
11521 let insert_range = {
11522 match completion.old_insert_start.zip(completion.old_insert_end) {
11523 Some((start, end)) => {
11524 let start = deserialize_anchor(start).context("invalid insert old start")?;
11525 let end = deserialize_anchor(end).context("invalid insert old end")?;
11526 Some(start..end)
11527 }
11528 None => None,
11529 }
11530 };
11531 Ok(CoreCompletion {
11532 replace_range: old_replace_start..old_replace_end,
11533 new_text: completion.new_text,
11534 source: match proto::completion::Source::from_i32(completion.source) {
11535 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11536 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11537 insert_range,
11538 server_id: LanguageServerId::from_proto(completion.server_id),
11539 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11540 lsp_defaults: completion
11541 .lsp_defaults
11542 .as_deref()
11543 .map(serde_json::from_slice)
11544 .transpose()?,
11545 resolved: completion.resolved,
11546 },
11547 Some(proto::completion::Source::BufferWord) => {
11548 let word_range = completion
11549 .buffer_word_start
11550 .and_then(deserialize_anchor)
11551 .context("invalid buffer word start")?
11552 ..completion
11553 .buffer_word_end
11554 .and_then(deserialize_anchor)
11555 .context("invalid buffer word end")?;
11556 CompletionSource::BufferWord {
11557 word_range,
11558 resolved: completion.resolved,
11559 }
11560 }
11561 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11562 sort_text: completion
11563 .sort_text
11564 .context("expected sort text to exist")?,
11565 },
11566 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11567 },
11568 })
11569 }
11570
11571 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11572 let (kind, lsp_action) = match &action.lsp_action {
11573 LspAction::Action(code_action) => (
11574 proto::code_action::Kind::Action as i32,
11575 serde_json::to_vec(code_action).unwrap(),
11576 ),
11577 LspAction::Command(command) => (
11578 proto::code_action::Kind::Command as i32,
11579 serde_json::to_vec(command).unwrap(),
11580 ),
11581 LspAction::CodeLens(code_lens) => (
11582 proto::code_action::Kind::CodeLens as i32,
11583 serde_json::to_vec(code_lens).unwrap(),
11584 ),
11585 };
11586
11587 proto::CodeAction {
11588 server_id: action.server_id.0 as u64,
11589 start: Some(serialize_anchor(&action.range.start)),
11590 end: Some(serialize_anchor(&action.range.end)),
11591 lsp_action,
11592 kind,
11593 resolved: action.resolved,
11594 }
11595 }
11596
11597 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11598 let start = action
11599 .start
11600 .and_then(deserialize_anchor)
11601 .context("invalid start")?;
11602 let end = action
11603 .end
11604 .and_then(deserialize_anchor)
11605 .context("invalid end")?;
11606 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11607 Some(proto::code_action::Kind::Action) => {
11608 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11609 }
11610 Some(proto::code_action::Kind::Command) => {
11611 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11612 }
11613 Some(proto::code_action::Kind::CodeLens) => {
11614 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11615 }
11616 None => anyhow::bail!("Unknown action kind {}", action.kind),
11617 };
11618 Ok(CodeAction {
11619 server_id: LanguageServerId(action.server_id as usize),
11620 range: start..end,
11621 resolved: action.resolved,
11622 lsp_action,
11623 })
11624 }
11625
11626 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11627 match &formatting_result {
11628 Ok(_) => self.last_formatting_failure = None,
11629 Err(error) => {
11630 let error_string = format!("{error:#}");
11631 log::error!("Formatting failed: {error_string}");
11632 self.last_formatting_failure
11633 .replace(error_string.lines().join(" "));
11634 }
11635 }
11636 }
11637
11638 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11639 self.lsp_server_capabilities.remove(&for_server);
11640 for lsp_data in self.lsp_data.values_mut() {
11641 lsp_data.remove_server_data(for_server);
11642 }
11643 if let Some(local) = self.as_local_mut() {
11644 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11645 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11646 buffer_servers.remove(&for_server);
11647 }
11648 }
11649 }
11650
11651 pub fn result_id(
11652 &self,
11653 server_id: LanguageServerId,
11654 buffer_id: BufferId,
11655 cx: &App,
11656 ) -> Option<String> {
11657 let abs_path = self
11658 .buffer_store
11659 .read(cx)
11660 .get(buffer_id)
11661 .and_then(|b| File::from_dyn(b.read(cx).file()))
11662 .map(|f| f.abs_path(cx))?;
11663 self.as_local()?
11664 .buffer_pull_diagnostics_result_ids
11665 .get(&server_id)?
11666 .get(&abs_path)?
11667 .clone()
11668 }
11669
11670 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11671 let Some(local) = self.as_local() else {
11672 return HashMap::default();
11673 };
11674 local
11675 .buffer_pull_diagnostics_result_ids
11676 .get(&server_id)
11677 .into_iter()
11678 .flatten()
11679 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11680 .collect()
11681 }
11682
11683 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11684 if let Some(LanguageServerState::Running {
11685 workspace_diagnostics_refresh_tasks,
11686 ..
11687 }) = self
11688 .as_local_mut()
11689 .and_then(|local| local.language_servers.get_mut(&server_id))
11690 {
11691 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11692 diagnostics.refresh_tx.try_send(()).ok();
11693 }
11694 }
11695 }
11696
11697 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11698 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11699 return;
11700 };
11701 let Some(local) = self.as_local_mut() else {
11702 return;
11703 };
11704
11705 for server_id in buffer.update(cx, |buffer, cx| {
11706 local.language_server_ids_for_buffer(buffer, cx)
11707 }) {
11708 if let Some(LanguageServerState::Running {
11709 workspace_diagnostics_refresh_tasks,
11710 ..
11711 }) = local.language_servers.get_mut(&server_id)
11712 {
11713 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11714 diagnostics.refresh_tx.try_send(()).ok();
11715 }
11716 }
11717 }
11718 }
11719
11720 fn apply_workspace_diagnostic_report(
11721 &mut self,
11722 server_id: LanguageServerId,
11723 report: lsp::WorkspaceDiagnosticReportResult,
11724 cx: &mut Context<Self>,
11725 ) {
11726 let workspace_diagnostics =
11727 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11728 let mut unchanged_buffers = HashSet::default();
11729 let mut changed_buffers = HashSet::default();
11730 let workspace_diagnostics_updates = workspace_diagnostics
11731 .into_iter()
11732 .filter_map(
11733 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11734 LspPullDiagnostics::Response {
11735 server_id,
11736 uri,
11737 diagnostics,
11738 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11739 LspPullDiagnostics::Default => None,
11740 },
11741 )
11742 .fold(
11743 HashMap::default(),
11744 |mut acc, (server_id, uri, diagnostics, version)| {
11745 let (result_id, diagnostics) = match diagnostics {
11746 PulledDiagnostics::Unchanged { result_id } => {
11747 unchanged_buffers.insert(uri.clone());
11748 (Some(result_id), Vec::new())
11749 }
11750 PulledDiagnostics::Changed {
11751 result_id,
11752 diagnostics,
11753 } => {
11754 changed_buffers.insert(uri.clone());
11755 (result_id, diagnostics)
11756 }
11757 };
11758 let disk_based_sources = Cow::Owned(
11759 self.language_server_adapter_for_id(server_id)
11760 .as_ref()
11761 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11762 .unwrap_or(&[])
11763 .to_vec(),
11764 );
11765 acc.entry(server_id)
11766 .or_insert_with(Vec::new)
11767 .push(DocumentDiagnosticsUpdate {
11768 server_id,
11769 diagnostics: lsp::PublishDiagnosticsParams {
11770 uri,
11771 diagnostics,
11772 version,
11773 },
11774 result_id,
11775 disk_based_sources,
11776 });
11777 acc
11778 },
11779 );
11780
11781 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11782 self.merge_lsp_diagnostics(
11783 DiagnosticSourceKind::Pulled,
11784 diagnostic_updates,
11785 |buffer, old_diagnostic, cx| {
11786 File::from_dyn(buffer.file())
11787 .and_then(|file| {
11788 let abs_path = file.as_local()?.abs_path(cx);
11789 lsp::Uri::from_file_path(abs_path).ok()
11790 })
11791 .is_none_or(|buffer_uri| {
11792 unchanged_buffers.contains(&buffer_uri)
11793 || match old_diagnostic.source_kind {
11794 DiagnosticSourceKind::Pulled => {
11795 !changed_buffers.contains(&buffer_uri)
11796 }
11797 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11798 true
11799 }
11800 }
11801 })
11802 },
11803 cx,
11804 )
11805 .log_err();
11806 }
11807 }
11808
11809 fn register_server_capabilities(
11810 &mut self,
11811 server_id: LanguageServerId,
11812 params: lsp::RegistrationParams,
11813 cx: &mut Context<Self>,
11814 ) -> anyhow::Result<()> {
11815 let server = self
11816 .language_server_for_id(server_id)
11817 .with_context(|| format!("no server {server_id} found"))?;
11818 for reg in params.registrations {
11819 match reg.method.as_str() {
11820 "workspace/didChangeWatchedFiles" => {
11821 if let Some(options) = reg.register_options {
11822 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11823 let caps = serde_json::from_value(options)?;
11824 local_lsp_store
11825 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11826 true
11827 } else {
11828 false
11829 };
11830 if notify {
11831 notify_server_capabilities_updated(&server, cx);
11832 }
11833 }
11834 }
11835 "workspace/didChangeConfiguration" => {
11836 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11837 }
11838 "workspace/didChangeWorkspaceFolders" => {
11839 // In this case register options is an empty object, we can ignore it
11840 let caps = lsp::WorkspaceFoldersServerCapabilities {
11841 supported: Some(true),
11842 change_notifications: Some(OneOf::Right(reg.id)),
11843 };
11844 server.update_capabilities(|capabilities| {
11845 capabilities
11846 .workspace
11847 .get_or_insert_default()
11848 .workspace_folders = Some(caps);
11849 });
11850 notify_server_capabilities_updated(&server, cx);
11851 }
11852 "workspace/symbol" => {
11853 let options = parse_register_capabilities(reg)?;
11854 server.update_capabilities(|capabilities| {
11855 capabilities.workspace_symbol_provider = Some(options);
11856 });
11857 notify_server_capabilities_updated(&server, cx);
11858 }
11859 "workspace/fileOperations" => {
11860 if let Some(options) = reg.register_options {
11861 let caps = serde_json::from_value(options)?;
11862 server.update_capabilities(|capabilities| {
11863 capabilities
11864 .workspace
11865 .get_or_insert_default()
11866 .file_operations = Some(caps);
11867 });
11868 notify_server_capabilities_updated(&server, cx);
11869 }
11870 }
11871 "workspace/executeCommand" => {
11872 if let Some(options) = reg.register_options {
11873 let options = serde_json::from_value(options)?;
11874 server.update_capabilities(|capabilities| {
11875 capabilities.execute_command_provider = Some(options);
11876 });
11877 notify_server_capabilities_updated(&server, cx);
11878 }
11879 }
11880 "textDocument/rangeFormatting" => {
11881 let options = parse_register_capabilities(reg)?;
11882 server.update_capabilities(|capabilities| {
11883 capabilities.document_range_formatting_provider = Some(options);
11884 });
11885 notify_server_capabilities_updated(&server, cx);
11886 }
11887 "textDocument/onTypeFormatting" => {
11888 if let Some(options) = reg
11889 .register_options
11890 .map(serde_json::from_value)
11891 .transpose()?
11892 {
11893 server.update_capabilities(|capabilities| {
11894 capabilities.document_on_type_formatting_provider = Some(options);
11895 });
11896 notify_server_capabilities_updated(&server, cx);
11897 }
11898 }
11899 "textDocument/formatting" => {
11900 let options = parse_register_capabilities(reg)?;
11901 server.update_capabilities(|capabilities| {
11902 capabilities.document_formatting_provider = Some(options);
11903 });
11904 notify_server_capabilities_updated(&server, cx);
11905 }
11906 "textDocument/rename" => {
11907 let options = parse_register_capabilities(reg)?;
11908 server.update_capabilities(|capabilities| {
11909 capabilities.rename_provider = Some(options);
11910 });
11911 notify_server_capabilities_updated(&server, cx);
11912 }
11913 "textDocument/inlayHint" => {
11914 let options = parse_register_capabilities(reg)?;
11915 server.update_capabilities(|capabilities| {
11916 capabilities.inlay_hint_provider = Some(options);
11917 });
11918 notify_server_capabilities_updated(&server, cx);
11919 }
11920 "textDocument/documentSymbol" => {
11921 let options = parse_register_capabilities(reg)?;
11922 server.update_capabilities(|capabilities| {
11923 capabilities.document_symbol_provider = Some(options);
11924 });
11925 notify_server_capabilities_updated(&server, cx);
11926 }
11927 "textDocument/codeAction" => {
11928 let options = parse_register_capabilities(reg)?;
11929 let provider = match options {
11930 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11931 OneOf::Right(caps) => caps,
11932 };
11933 server.update_capabilities(|capabilities| {
11934 capabilities.code_action_provider = Some(provider);
11935 });
11936 notify_server_capabilities_updated(&server, cx);
11937 }
11938 "textDocument/definition" => {
11939 let options = parse_register_capabilities(reg)?;
11940 server.update_capabilities(|capabilities| {
11941 capabilities.definition_provider = Some(options);
11942 });
11943 notify_server_capabilities_updated(&server, cx);
11944 }
11945 "textDocument/completion" => {
11946 if let Some(caps) = reg
11947 .register_options
11948 .map(serde_json::from_value::<CompletionOptions>)
11949 .transpose()?
11950 {
11951 server.update_capabilities(|capabilities| {
11952 capabilities.completion_provider = Some(caps.clone());
11953 });
11954
11955 if let Some(local) = self.as_local() {
11956 let mut buffers_with_language_server = Vec::new();
11957 for handle in self.buffer_store.read(cx).buffers() {
11958 let buffer_id = handle.read(cx).remote_id();
11959 if local
11960 .buffers_opened_in_servers
11961 .get(&buffer_id)
11962 .filter(|s| s.contains(&server_id))
11963 .is_some()
11964 {
11965 buffers_with_language_server.push(handle);
11966 }
11967 }
11968 let triggers = caps
11969 .trigger_characters
11970 .unwrap_or_default()
11971 .into_iter()
11972 .collect::<BTreeSet<_>>();
11973 for handle in buffers_with_language_server {
11974 let triggers = triggers.clone();
11975 let _ = handle.update(cx, move |buffer, cx| {
11976 buffer.set_completion_triggers(server_id, triggers, cx);
11977 });
11978 }
11979 }
11980 notify_server_capabilities_updated(&server, cx);
11981 }
11982 }
11983 "textDocument/hover" => {
11984 let options = parse_register_capabilities(reg)?;
11985 let provider = match options {
11986 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11987 OneOf::Right(caps) => caps,
11988 };
11989 server.update_capabilities(|capabilities| {
11990 capabilities.hover_provider = Some(provider);
11991 });
11992 notify_server_capabilities_updated(&server, cx);
11993 }
11994 "textDocument/signatureHelp" => {
11995 if let Some(caps) = reg
11996 .register_options
11997 .map(serde_json::from_value)
11998 .transpose()?
11999 {
12000 server.update_capabilities(|capabilities| {
12001 capabilities.signature_help_provider = Some(caps);
12002 });
12003 notify_server_capabilities_updated(&server, cx);
12004 }
12005 }
12006 "textDocument/didChange" => {
12007 if let Some(sync_kind) = reg
12008 .register_options
12009 .and_then(|opts| opts.get("syncKind").cloned())
12010 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12011 .transpose()?
12012 {
12013 server.update_capabilities(|capabilities| {
12014 let mut sync_options =
12015 Self::take_text_document_sync_options(capabilities);
12016 sync_options.change = Some(sync_kind);
12017 capabilities.text_document_sync =
12018 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12019 });
12020 notify_server_capabilities_updated(&server, cx);
12021 }
12022 }
12023 "textDocument/didSave" => {
12024 if let Some(include_text) = reg
12025 .register_options
12026 .map(|opts| {
12027 let transpose = opts
12028 .get("includeText")
12029 .cloned()
12030 .map(serde_json::from_value::<Option<bool>>)
12031 .transpose();
12032 match transpose {
12033 Ok(value) => Ok(value.flatten()),
12034 Err(e) => Err(e),
12035 }
12036 })
12037 .transpose()?
12038 {
12039 server.update_capabilities(|capabilities| {
12040 let mut sync_options =
12041 Self::take_text_document_sync_options(capabilities);
12042 sync_options.save =
12043 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12044 include_text,
12045 }));
12046 capabilities.text_document_sync =
12047 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12048 });
12049 notify_server_capabilities_updated(&server, cx);
12050 }
12051 }
12052 "textDocument/codeLens" => {
12053 if let Some(caps) = reg
12054 .register_options
12055 .map(serde_json::from_value)
12056 .transpose()?
12057 {
12058 server.update_capabilities(|capabilities| {
12059 capabilities.code_lens_provider = Some(caps);
12060 });
12061 notify_server_capabilities_updated(&server, cx);
12062 }
12063 }
12064 "textDocument/diagnostic" => {
12065 if let Some(caps) = reg
12066 .register_options
12067 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12068 .transpose()?
12069 {
12070 let local = self
12071 .as_local_mut()
12072 .context("Expected LSP Store to be local")?;
12073 let state = local
12074 .language_servers
12075 .get_mut(&server_id)
12076 .context("Could not obtain Language Servers state")?;
12077 local
12078 .language_server_dynamic_registrations
12079 .entry(server_id)
12080 .or_default()
12081 .diagnostics
12082 .insert(Some(reg.id.clone()), caps.clone());
12083
12084 if let LanguageServerState::Running {
12085 workspace_diagnostics_refresh_tasks,
12086 ..
12087 } = state
12088 && let Some(task) = lsp_workspace_diagnostics_refresh(
12089 Some(reg.id.clone()),
12090 caps.clone(),
12091 server.clone(),
12092 cx,
12093 )
12094 {
12095 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12096 }
12097
12098 let mut did_update_caps = false;
12099 server.update_capabilities(|capabilities| {
12100 if capabilities.diagnostic_provider.as_ref().is_none_or(
12101 |current_caps| {
12102 let supports_workspace_diagnostics =
12103 |capabilities: &DiagnosticServerCapabilities| {
12104 match capabilities {
12105 DiagnosticServerCapabilities::Options(
12106 diagnostic_options,
12107 ) => diagnostic_options.workspace_diagnostics,
12108 DiagnosticServerCapabilities::RegistrationOptions(
12109 diagnostic_registration_options,
12110 ) => {
12111 diagnostic_registration_options
12112 .diagnostic_options
12113 .workspace_diagnostics
12114 }
12115 }
12116 };
12117 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12118 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12119 // as it'll think that they're not supported.
12120 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12121 !supports_workspace_diagnostics(current_caps)
12122 & supports_workspace_diagnostics(&caps)
12123 },
12124 ) {
12125 did_update_caps = true;
12126 capabilities.diagnostic_provider = Some(caps);
12127 }
12128 });
12129 if did_update_caps {
12130 notify_server_capabilities_updated(&server, cx);
12131 }
12132 }
12133 }
12134 "textDocument/documentColor" => {
12135 let options = parse_register_capabilities(reg)?;
12136 let provider = match options {
12137 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12138 OneOf::Right(caps) => caps,
12139 };
12140 server.update_capabilities(|capabilities| {
12141 capabilities.color_provider = Some(provider);
12142 });
12143 notify_server_capabilities_updated(&server, cx);
12144 }
12145 _ => log::warn!("unhandled capability registration: {reg:?}"),
12146 }
12147 }
12148
12149 Ok(())
12150 }
12151
12152 fn unregister_server_capabilities(
12153 &mut self,
12154 server_id: LanguageServerId,
12155 params: lsp::UnregistrationParams,
12156 cx: &mut Context<Self>,
12157 ) -> anyhow::Result<()> {
12158 let server = self
12159 .language_server_for_id(server_id)
12160 .with_context(|| format!("no server {server_id} found"))?;
12161 for unreg in params.unregisterations.iter() {
12162 match unreg.method.as_str() {
12163 "workspace/didChangeWatchedFiles" => {
12164 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12165 local_lsp_store
12166 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12167 true
12168 } else {
12169 false
12170 };
12171 if notify {
12172 notify_server_capabilities_updated(&server, cx);
12173 }
12174 }
12175 "workspace/didChangeConfiguration" => {
12176 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12177 }
12178 "workspace/didChangeWorkspaceFolders" => {
12179 server.update_capabilities(|capabilities| {
12180 capabilities
12181 .workspace
12182 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12183 workspace_folders: None,
12184 file_operations: None,
12185 })
12186 .workspace_folders = None;
12187 });
12188 notify_server_capabilities_updated(&server, cx);
12189 }
12190 "workspace/symbol" => {
12191 server.update_capabilities(|capabilities| {
12192 capabilities.workspace_symbol_provider = None
12193 });
12194 notify_server_capabilities_updated(&server, cx);
12195 }
12196 "workspace/fileOperations" => {
12197 server.update_capabilities(|capabilities| {
12198 capabilities
12199 .workspace
12200 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12201 workspace_folders: None,
12202 file_operations: None,
12203 })
12204 .file_operations = None;
12205 });
12206 notify_server_capabilities_updated(&server, cx);
12207 }
12208 "workspace/executeCommand" => {
12209 server.update_capabilities(|capabilities| {
12210 capabilities.execute_command_provider = None;
12211 });
12212 notify_server_capabilities_updated(&server, cx);
12213 }
12214 "textDocument/rangeFormatting" => {
12215 server.update_capabilities(|capabilities| {
12216 capabilities.document_range_formatting_provider = None
12217 });
12218 notify_server_capabilities_updated(&server, cx);
12219 }
12220 "textDocument/onTypeFormatting" => {
12221 server.update_capabilities(|capabilities| {
12222 capabilities.document_on_type_formatting_provider = None;
12223 });
12224 notify_server_capabilities_updated(&server, cx);
12225 }
12226 "textDocument/formatting" => {
12227 server.update_capabilities(|capabilities| {
12228 capabilities.document_formatting_provider = None;
12229 });
12230 notify_server_capabilities_updated(&server, cx);
12231 }
12232 "textDocument/rename" => {
12233 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12234 notify_server_capabilities_updated(&server, cx);
12235 }
12236 "textDocument/codeAction" => {
12237 server.update_capabilities(|capabilities| {
12238 capabilities.code_action_provider = None;
12239 });
12240 notify_server_capabilities_updated(&server, cx);
12241 }
12242 "textDocument/definition" => {
12243 server.update_capabilities(|capabilities| {
12244 capabilities.definition_provider = None;
12245 });
12246 notify_server_capabilities_updated(&server, cx);
12247 }
12248 "textDocument/completion" => {
12249 server.update_capabilities(|capabilities| {
12250 capabilities.completion_provider = None;
12251 });
12252 notify_server_capabilities_updated(&server, cx);
12253 }
12254 "textDocument/hover" => {
12255 server.update_capabilities(|capabilities| {
12256 capabilities.hover_provider = None;
12257 });
12258 notify_server_capabilities_updated(&server, cx);
12259 }
12260 "textDocument/signatureHelp" => {
12261 server.update_capabilities(|capabilities| {
12262 capabilities.signature_help_provider = None;
12263 });
12264 notify_server_capabilities_updated(&server, cx);
12265 }
12266 "textDocument/didChange" => {
12267 server.update_capabilities(|capabilities| {
12268 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12269 sync_options.change = None;
12270 capabilities.text_document_sync =
12271 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12272 });
12273 notify_server_capabilities_updated(&server, cx);
12274 }
12275 "textDocument/didSave" => {
12276 server.update_capabilities(|capabilities| {
12277 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12278 sync_options.save = None;
12279 capabilities.text_document_sync =
12280 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12281 });
12282 notify_server_capabilities_updated(&server, cx);
12283 }
12284 "textDocument/codeLens" => {
12285 server.update_capabilities(|capabilities| {
12286 capabilities.code_lens_provider = None;
12287 });
12288 notify_server_capabilities_updated(&server, cx);
12289 }
12290 "textDocument/diagnostic" => {
12291 let local = self
12292 .as_local_mut()
12293 .context("Expected LSP Store to be local")?;
12294
12295 let state = local
12296 .language_servers
12297 .get_mut(&server_id)
12298 .context("Could not obtain Language Servers state")?;
12299 let options = local
12300 .language_server_dynamic_registrations
12301 .get_mut(&server_id)
12302 .with_context(|| {
12303 format!("Expected dynamic registration to exist for server {server_id}")
12304 })?.diagnostics
12305 .remove(&Some(unreg.id.clone()))
12306 .with_context(|| format!(
12307 "Attempted to unregister non-existent diagnostic registration with ID {}",
12308 unreg.id)
12309 )?;
12310
12311 let mut has_any_diagnostic_providers_still = true;
12312 if let Some(identifier) = diagnostic_identifier(&options)
12313 && let LanguageServerState::Running {
12314 workspace_diagnostics_refresh_tasks,
12315 ..
12316 } = state
12317 {
12318 workspace_diagnostics_refresh_tasks.remove(&identifier);
12319 has_any_diagnostic_providers_still =
12320 !workspace_diagnostics_refresh_tasks.is_empty();
12321 }
12322
12323 if !has_any_diagnostic_providers_still {
12324 server.update_capabilities(|capabilities| {
12325 debug_assert!(capabilities.diagnostic_provider.is_some());
12326 capabilities.diagnostic_provider = None;
12327 });
12328 }
12329
12330 notify_server_capabilities_updated(&server, cx);
12331 }
12332 "textDocument/documentColor" => {
12333 server.update_capabilities(|capabilities| {
12334 capabilities.color_provider = None;
12335 });
12336 notify_server_capabilities_updated(&server, cx);
12337 }
12338 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12339 }
12340 }
12341
12342 Ok(())
12343 }
12344
12345 async fn deduplicate_range_based_lsp_requests<T>(
12346 lsp_store: &Entity<Self>,
12347 server_id: Option<LanguageServerId>,
12348 lsp_request_id: LspRequestId,
12349 proto_request: &T::ProtoRequest,
12350 range: Range<Anchor>,
12351 cx: &mut AsyncApp,
12352 ) -> Result<()>
12353 where
12354 T: LspCommand,
12355 T::ProtoRequest: proto::LspRequestMessage,
12356 {
12357 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12358 let version = deserialize_version(proto_request.buffer_version());
12359 let buffer = lsp_store.update(cx, |this, cx| {
12360 this.buffer_store.read(cx).get_existing(buffer_id)
12361 })??;
12362 buffer
12363 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12364 .await?;
12365 lsp_store.update(cx, |lsp_store, cx| {
12366 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12367 let chunks_queried_for = lsp_data
12368 .inlay_hints
12369 .applicable_chunks(&[range])
12370 .collect::<Vec<_>>();
12371 match chunks_queried_for.as_slice() {
12372 &[chunk] => {
12373 let key = LspKey {
12374 request_type: TypeId::of::<T>(),
12375 server_queried: server_id,
12376 };
12377 let previous_request = lsp_data
12378 .chunk_lsp_requests
12379 .entry(key)
12380 .or_default()
12381 .insert(chunk, lsp_request_id);
12382 if let Some((previous_request, running_requests)) =
12383 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12384 {
12385 running_requests.remove(&previous_request);
12386 }
12387 }
12388 _ambiguous_chunks => {
12389 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12390 // there, a buffer version-based check will be performed and outdated requests discarded.
12391 }
12392 }
12393 anyhow::Ok(())
12394 })??;
12395
12396 Ok(())
12397 }
12398
12399 async fn query_lsp_locally<T>(
12400 lsp_store: Entity<Self>,
12401 for_server_id: Option<LanguageServerId>,
12402 sender_id: proto::PeerId,
12403 lsp_request_id: LspRequestId,
12404 proto_request: T::ProtoRequest,
12405 position: Option<Anchor>,
12406 cx: &mut AsyncApp,
12407 ) -> Result<()>
12408 where
12409 T: LspCommand + Clone,
12410 T::ProtoRequest: proto::LspRequestMessage,
12411 <T::ProtoRequest as proto::RequestMessage>::Response:
12412 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12413 {
12414 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12415 let version = deserialize_version(proto_request.buffer_version());
12416 let buffer = lsp_store.update(cx, |this, cx| {
12417 this.buffer_store.read(cx).get_existing(buffer_id)
12418 })??;
12419 buffer
12420 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12421 .await?;
12422 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12423 let request =
12424 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12425 let key = LspKey {
12426 request_type: TypeId::of::<T>(),
12427 server_queried: for_server_id,
12428 };
12429 lsp_store.update(cx, |lsp_store, cx| {
12430 let request_task = match for_server_id {
12431 Some(server_id) => {
12432 let server_task = lsp_store.request_lsp(
12433 buffer.clone(),
12434 LanguageServerToQuery::Other(server_id),
12435 request.clone(),
12436 cx,
12437 );
12438 cx.background_spawn(async move {
12439 let mut responses = Vec::new();
12440 match server_task.await {
12441 Ok(response) => responses.push((server_id, response)),
12442 Err(e) => log::error!(
12443 "Error handling response for request {request:?}: {e:#}"
12444 ),
12445 }
12446 responses
12447 })
12448 }
12449 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12450 };
12451 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12452 if T::ProtoRequest::stop_previous_requests() {
12453 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12454 lsp_requests.clear();
12455 }
12456 }
12457 lsp_data.lsp_requests.entry(key).or_default().insert(
12458 lsp_request_id,
12459 cx.spawn(async move |lsp_store, cx| {
12460 let response = request_task.await;
12461 lsp_store
12462 .update(cx, |lsp_store, cx| {
12463 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12464 {
12465 let response = response
12466 .into_iter()
12467 .map(|(server_id, response)| {
12468 (
12469 server_id.to_proto(),
12470 T::response_to_proto(
12471 response,
12472 lsp_store,
12473 sender_id,
12474 &buffer_version,
12475 cx,
12476 )
12477 .into(),
12478 )
12479 })
12480 .collect::<HashMap<_, _>>();
12481 match client.send_lsp_response::<T::ProtoRequest>(
12482 project_id,
12483 lsp_request_id,
12484 response,
12485 ) {
12486 Ok(()) => {}
12487 Err(e) => {
12488 log::error!("Failed to send LSP response: {e:#}",)
12489 }
12490 }
12491 }
12492 })
12493 .ok();
12494 }),
12495 );
12496 })?;
12497 Ok(())
12498 }
12499
12500 fn take_text_document_sync_options(
12501 capabilities: &mut lsp::ServerCapabilities,
12502 ) -> lsp::TextDocumentSyncOptions {
12503 match capabilities.text_document_sync.take() {
12504 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12505 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12506 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12507 sync_options.change = Some(sync_kind);
12508 sync_options
12509 }
12510 None => lsp::TextDocumentSyncOptions::default(),
12511 }
12512 }
12513
12514 #[cfg(any(test, feature = "test-support"))]
12515 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12516 Some(
12517 self.lsp_data
12518 .get_mut(&buffer_id)?
12519 .code_lens
12520 .take()?
12521 .update
12522 .take()?
12523 .1,
12524 )
12525 }
12526
12527 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12528 self.downstream_client.clone()
12529 }
12530
12531 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12532 self.worktree_store.clone()
12533 }
12534
12535 /// Gets what's stored in the LSP data for the given buffer.
12536 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12537 self.lsp_data.get_mut(&buffer_id)
12538 }
12539
12540 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12541 /// new [`BufferLspData`] will be created to replace the previous state.
12542 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12543 let (buffer_id, buffer_version) =
12544 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12545 let lsp_data = self
12546 .lsp_data
12547 .entry(buffer_id)
12548 .or_insert_with(|| BufferLspData::new(buffer, cx));
12549 if buffer_version.changed_since(&lsp_data.buffer_version) {
12550 *lsp_data = BufferLspData::new(buffer, cx);
12551 }
12552 lsp_data
12553 }
12554}
12555
12556// Registration with registerOptions as null, should fallback to true.
12557// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12558fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12559 reg: lsp::Registration,
12560) -> Result<OneOf<bool, T>> {
12561 Ok(match reg.register_options {
12562 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12563 None => OneOf::Left(true),
12564 })
12565}
12566
12567fn subscribe_to_binary_statuses(
12568 languages: &Arc<LanguageRegistry>,
12569 cx: &mut Context<'_, LspStore>,
12570) -> Task<()> {
12571 let mut server_statuses = languages.language_server_binary_statuses();
12572 cx.spawn(async move |lsp_store, cx| {
12573 while let Some((server_name, binary_status)) = server_statuses.next().await {
12574 if lsp_store
12575 .update(cx, |_, cx| {
12576 let mut message = None;
12577 let binary_status = match binary_status {
12578 BinaryStatus::None => proto::ServerBinaryStatus::None,
12579 BinaryStatus::CheckingForUpdate => {
12580 proto::ServerBinaryStatus::CheckingForUpdate
12581 }
12582 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12583 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12584 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12585 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12586 BinaryStatus::Failed { error } => {
12587 message = Some(error);
12588 proto::ServerBinaryStatus::Failed
12589 }
12590 };
12591 cx.emit(LspStoreEvent::LanguageServerUpdate {
12592 // Binary updates are about the binary that might not have any language server id at that point.
12593 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12594 language_server_id: LanguageServerId(0),
12595 name: Some(server_name),
12596 message: proto::update_language_server::Variant::StatusUpdate(
12597 proto::StatusUpdate {
12598 message,
12599 status: Some(proto::status_update::Status::Binary(
12600 binary_status as i32,
12601 )),
12602 },
12603 ),
12604 });
12605 })
12606 .is_err()
12607 {
12608 break;
12609 }
12610 }
12611 })
12612}
12613
12614fn lsp_workspace_diagnostics_refresh(
12615 registration_id: Option<String>,
12616 options: DiagnosticServerCapabilities,
12617 server: Arc<LanguageServer>,
12618 cx: &mut Context<'_, LspStore>,
12619) -> Option<WorkspaceRefreshTask> {
12620 let identifier = diagnostic_identifier(&options)?;
12621
12622 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12623 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12624 refresh_tx.try_send(()).ok();
12625
12626 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12627 let mut attempts = 0;
12628 let max_attempts = 50;
12629 let mut requests = 0;
12630
12631 loop {
12632 let Some(()) = refresh_rx.recv().await else {
12633 return;
12634 };
12635
12636 'request: loop {
12637 requests += 1;
12638 if attempts > max_attempts {
12639 log::error!(
12640 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12641 );
12642 return;
12643 }
12644 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12645 cx.background_executor()
12646 .timer(Duration::from_millis(backoff_millis))
12647 .await;
12648 attempts += 1;
12649
12650 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12651 lsp_store
12652 .all_result_ids(server.server_id())
12653 .into_iter()
12654 .filter_map(|(abs_path, result_id)| {
12655 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12656 Some(lsp::PreviousResultId {
12657 uri,
12658 value: result_id,
12659 })
12660 })
12661 .collect()
12662 }) else {
12663 return;
12664 };
12665
12666 let token = if let Some(identifier) = ®istration_id {
12667 format!(
12668 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12669 server.server_id(),
12670 )
12671 } else {
12672 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12673 };
12674
12675 progress_rx.try_recv().ok();
12676 let timer =
12677 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12678 let progress = pin!(progress_rx.recv().fuse());
12679 let response_result = server
12680 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12681 lsp::WorkspaceDiagnosticParams {
12682 previous_result_ids,
12683 identifier: identifier.clone(),
12684 work_done_progress_params: Default::default(),
12685 partial_result_params: lsp::PartialResultParams {
12686 partial_result_token: Some(lsp::ProgressToken::String(token)),
12687 },
12688 },
12689 select(timer, progress).then(|either| match either {
12690 Either::Left((message, ..)) => ready(message).left_future(),
12691 Either::Right(..) => pending::<String>().right_future(),
12692 }),
12693 )
12694 .await;
12695
12696 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12697 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12698 match response_result {
12699 ConnectionResult::Timeout => {
12700 log::error!("Timeout during workspace diagnostics pull");
12701 continue 'request;
12702 }
12703 ConnectionResult::ConnectionReset => {
12704 log::error!("Server closed a workspace diagnostics pull request");
12705 continue 'request;
12706 }
12707 ConnectionResult::Result(Err(e)) => {
12708 log::error!("Error during workspace diagnostics pull: {e:#}");
12709 break 'request;
12710 }
12711 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12712 attempts = 0;
12713 if lsp_store
12714 .update(cx, |lsp_store, cx| {
12715 lsp_store.apply_workspace_diagnostic_report(
12716 server.server_id(),
12717 pulled_diagnostics,
12718 cx,
12719 )
12720 })
12721 .is_err()
12722 {
12723 return;
12724 }
12725 break 'request;
12726 }
12727 }
12728 }
12729 }
12730 });
12731
12732 Some(WorkspaceRefreshTask {
12733 refresh_tx,
12734 progress_tx,
12735 task: workspace_query_language_server,
12736 })
12737}
12738
12739fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12740 match &options {
12741 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12742 if !diagnostic_options.workspace_diagnostics {
12743 return None;
12744 }
12745 Some(diagnostic_options.identifier.clone())
12746 }
12747 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12748 let diagnostic_options = ®istration_options.diagnostic_options;
12749 if !diagnostic_options.workspace_diagnostics {
12750 return None;
12751 }
12752 Some(diagnostic_options.identifier.clone())
12753 }
12754 }
12755}
12756
12757fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12758 let CompletionSource::BufferWord {
12759 word_range,
12760 resolved,
12761 } = &mut completion.source
12762 else {
12763 return;
12764 };
12765 if *resolved {
12766 return;
12767 }
12768
12769 if completion.new_text
12770 != snapshot
12771 .text_for_range(word_range.clone())
12772 .collect::<String>()
12773 {
12774 return;
12775 }
12776
12777 let mut offset = 0;
12778 for chunk in snapshot.chunks(word_range.clone(), true) {
12779 let end_offset = offset + chunk.text.len();
12780 if let Some(highlight_id) = chunk.syntax_highlight_id {
12781 completion
12782 .label
12783 .runs
12784 .push((offset..end_offset, highlight_id));
12785 }
12786 offset = end_offset;
12787 }
12788 *resolved = true;
12789}
12790
12791impl EventEmitter<LspStoreEvent> for LspStore {}
12792
12793fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12794 hover
12795 .contents
12796 .retain(|hover_block| !hover_block.text.trim().is_empty());
12797 if hover.contents.is_empty() {
12798 None
12799 } else {
12800 Some(hover)
12801 }
12802}
12803
12804async fn populate_labels_for_completions(
12805 new_completions: Vec<CoreCompletion>,
12806 language: Option<Arc<Language>>,
12807 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12808) -> Vec<Completion> {
12809 let lsp_completions = new_completions
12810 .iter()
12811 .filter_map(|new_completion| {
12812 new_completion
12813 .source
12814 .lsp_completion(true)
12815 .map(|lsp_completion| lsp_completion.into_owned())
12816 })
12817 .collect::<Vec<_>>();
12818
12819 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12820 lsp_adapter
12821 .labels_for_completions(&lsp_completions, language)
12822 .await
12823 .log_err()
12824 .unwrap_or_default()
12825 } else {
12826 Vec::new()
12827 }
12828 .into_iter()
12829 .fuse();
12830
12831 let mut completions = Vec::new();
12832 for completion in new_completions {
12833 match completion.source.lsp_completion(true) {
12834 Some(lsp_completion) => {
12835 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12836
12837 let mut label = labels.next().flatten().unwrap_or_else(|| {
12838 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12839 });
12840 ensure_uniform_list_compatible_label(&mut label);
12841 completions.push(Completion {
12842 label,
12843 documentation,
12844 replace_range: completion.replace_range,
12845 new_text: completion.new_text,
12846 insert_text_mode: lsp_completion.insert_text_mode,
12847 source: completion.source,
12848 icon_path: None,
12849 confirm: None,
12850 });
12851 }
12852 None => {
12853 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12854 ensure_uniform_list_compatible_label(&mut label);
12855 completions.push(Completion {
12856 label,
12857 documentation: None,
12858 replace_range: completion.replace_range,
12859 new_text: completion.new_text,
12860 source: completion.source,
12861 insert_text_mode: None,
12862 icon_path: None,
12863 confirm: None,
12864 });
12865 }
12866 }
12867 }
12868 completions
12869}
12870
12871#[derive(Debug)]
12872pub enum LanguageServerToQuery {
12873 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12874 FirstCapable,
12875 /// Query a specific language server.
12876 Other(LanguageServerId),
12877}
12878
12879#[derive(Default)]
12880struct RenamePathsWatchedForServer {
12881 did_rename: Vec<RenameActionPredicate>,
12882 will_rename: Vec<RenameActionPredicate>,
12883}
12884
12885impl RenamePathsWatchedForServer {
12886 fn with_did_rename_patterns(
12887 mut self,
12888 did_rename: Option<&FileOperationRegistrationOptions>,
12889 ) -> Self {
12890 if let Some(did_rename) = did_rename {
12891 self.did_rename = did_rename
12892 .filters
12893 .iter()
12894 .filter_map(|filter| filter.try_into().log_err())
12895 .collect();
12896 }
12897 self
12898 }
12899 fn with_will_rename_patterns(
12900 mut self,
12901 will_rename: Option<&FileOperationRegistrationOptions>,
12902 ) -> Self {
12903 if let Some(will_rename) = will_rename {
12904 self.will_rename = will_rename
12905 .filters
12906 .iter()
12907 .filter_map(|filter| filter.try_into().log_err())
12908 .collect();
12909 }
12910 self
12911 }
12912
12913 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12914 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12915 }
12916 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12917 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12918 }
12919}
12920
12921impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12922 type Error = globset::Error;
12923 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12924 Ok(Self {
12925 kind: ops.pattern.matches.clone(),
12926 glob: GlobBuilder::new(&ops.pattern.glob)
12927 .case_insensitive(
12928 ops.pattern
12929 .options
12930 .as_ref()
12931 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12932 )
12933 .build()?
12934 .compile_matcher(),
12935 })
12936 }
12937}
12938struct RenameActionPredicate {
12939 glob: GlobMatcher,
12940 kind: Option<FileOperationPatternKind>,
12941}
12942
12943impl RenameActionPredicate {
12944 // Returns true if language server should be notified
12945 fn eval(&self, path: &str, is_dir: bool) -> bool {
12946 self.kind.as_ref().is_none_or(|kind| {
12947 let expected_kind = if is_dir {
12948 FileOperationPatternKind::Folder
12949 } else {
12950 FileOperationPatternKind::File
12951 };
12952 kind == &expected_kind
12953 }) && self.glob.is_match(path)
12954 }
12955}
12956
12957#[derive(Default)]
12958struct LanguageServerWatchedPaths {
12959 worktree_paths: HashMap<WorktreeId, GlobSet>,
12960 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12961}
12962
12963#[derive(Default)]
12964struct LanguageServerWatchedPathsBuilder {
12965 worktree_paths: HashMap<WorktreeId, GlobSet>,
12966 abs_paths: HashMap<Arc<Path>, GlobSet>,
12967}
12968
12969impl LanguageServerWatchedPathsBuilder {
12970 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12971 self.worktree_paths.insert(worktree_id, glob_set);
12972 }
12973 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12974 self.abs_paths.insert(path, glob_set);
12975 }
12976 fn build(
12977 self,
12978 fs: Arc<dyn Fs>,
12979 language_server_id: LanguageServerId,
12980 cx: &mut Context<LspStore>,
12981 ) -> LanguageServerWatchedPaths {
12982 let lsp_store = cx.weak_entity();
12983
12984 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12985 let abs_paths = self
12986 .abs_paths
12987 .into_iter()
12988 .map(|(abs_path, globset)| {
12989 let task = cx.spawn({
12990 let abs_path = abs_path.clone();
12991 let fs = fs.clone();
12992
12993 let lsp_store = lsp_store.clone();
12994 async move |_, cx| {
12995 maybe!(async move {
12996 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12997 while let Some(update) = push_updates.0.next().await {
12998 let action = lsp_store
12999 .update(cx, |this, _| {
13000 let Some(local) = this.as_local() else {
13001 return ControlFlow::Break(());
13002 };
13003 let Some(watcher) = local
13004 .language_server_watched_paths
13005 .get(&language_server_id)
13006 else {
13007 return ControlFlow::Break(());
13008 };
13009 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13010 "Watched abs path is not registered with a watcher",
13011 );
13012 let matching_entries = update
13013 .into_iter()
13014 .filter(|event| globs.is_match(&event.path))
13015 .collect::<Vec<_>>();
13016 this.lsp_notify_abs_paths_changed(
13017 language_server_id,
13018 matching_entries,
13019 );
13020 ControlFlow::Continue(())
13021 })
13022 .ok()?;
13023
13024 if action.is_break() {
13025 break;
13026 }
13027 }
13028 Some(())
13029 })
13030 .await;
13031 }
13032 });
13033 (abs_path, (globset, task))
13034 })
13035 .collect();
13036 LanguageServerWatchedPaths {
13037 worktree_paths: self.worktree_paths,
13038 abs_paths,
13039 }
13040 }
13041}
13042
13043struct LspBufferSnapshot {
13044 version: i32,
13045 snapshot: TextBufferSnapshot,
13046}
13047
13048/// A prompt requested by LSP server.
13049#[derive(Clone, Debug)]
13050pub struct LanguageServerPromptRequest {
13051 pub level: PromptLevel,
13052 pub message: String,
13053 pub actions: Vec<MessageActionItem>,
13054 pub lsp_name: String,
13055 pub(crate) response_channel: Sender<MessageActionItem>,
13056}
13057
13058impl LanguageServerPromptRequest {
13059 pub async fn respond(self, index: usize) -> Option<()> {
13060 if let Some(response) = self.actions.into_iter().nth(index) {
13061 self.response_channel.send(response).await.ok()
13062 } else {
13063 None
13064 }
13065 }
13066}
13067impl PartialEq for LanguageServerPromptRequest {
13068 fn eq(&self, other: &Self) -> bool {
13069 self.message == other.message && self.actions == other.actions
13070 }
13071}
13072
13073#[derive(Clone, Debug, PartialEq)]
13074pub enum LanguageServerLogType {
13075 Log(MessageType),
13076 Trace { verbose_info: Option<String> },
13077 Rpc { received: bool },
13078}
13079
13080impl LanguageServerLogType {
13081 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13082 match self {
13083 Self::Log(log_type) => {
13084 use proto::log_message::LogLevel;
13085 let level = match *log_type {
13086 MessageType::ERROR => LogLevel::Error,
13087 MessageType::WARNING => LogLevel::Warning,
13088 MessageType::INFO => LogLevel::Info,
13089 MessageType::LOG => LogLevel::Log,
13090 other => {
13091 log::warn!("Unknown lsp log message type: {other:?}");
13092 LogLevel::Log
13093 }
13094 };
13095 proto::language_server_log::LogType::Log(proto::LogMessage {
13096 level: level as i32,
13097 })
13098 }
13099 Self::Trace { verbose_info } => {
13100 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13101 verbose_info: verbose_info.to_owned(),
13102 })
13103 }
13104 Self::Rpc { received } => {
13105 let kind = if *received {
13106 proto::rpc_message::Kind::Received
13107 } else {
13108 proto::rpc_message::Kind::Sent
13109 };
13110 let kind = kind as i32;
13111 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13112 }
13113 }
13114 }
13115
13116 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13117 use proto::log_message::LogLevel;
13118 use proto::rpc_message;
13119 match log_type {
13120 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13121 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13122 LogLevel::Error => MessageType::ERROR,
13123 LogLevel::Warning => MessageType::WARNING,
13124 LogLevel::Info => MessageType::INFO,
13125 LogLevel::Log => MessageType::LOG,
13126 },
13127 ),
13128 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13129 verbose_info: trace_message.verbose_info,
13130 },
13131 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13132 received: match rpc_message::Kind::from_i32(message.kind)
13133 .unwrap_or(rpc_message::Kind::Received)
13134 {
13135 rpc_message::Kind::Received => true,
13136 rpc_message::Kind::Sent => false,
13137 },
13138 },
13139 }
13140 }
13141}
13142
13143pub struct WorkspaceRefreshTask {
13144 refresh_tx: mpsc::Sender<()>,
13145 progress_tx: mpsc::Sender<()>,
13146 #[allow(dead_code)]
13147 task: Task<()>,
13148}
13149
13150pub enum LanguageServerState {
13151 Starting {
13152 startup: Task<Option<Arc<LanguageServer>>>,
13153 /// List of language servers that will be added to the workspace once it's initialization completes.
13154 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13155 },
13156
13157 Running {
13158 adapter: Arc<CachedLspAdapter>,
13159 server: Arc<LanguageServer>,
13160 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13161 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13162 },
13163}
13164
13165impl LanguageServerState {
13166 fn add_workspace_folder(&self, uri: Uri) {
13167 match self {
13168 LanguageServerState::Starting {
13169 pending_workspace_folders,
13170 ..
13171 } => {
13172 pending_workspace_folders.lock().insert(uri);
13173 }
13174 LanguageServerState::Running { server, .. } => {
13175 server.add_workspace_folder(uri);
13176 }
13177 }
13178 }
13179 fn _remove_workspace_folder(&self, uri: Uri) {
13180 match self {
13181 LanguageServerState::Starting {
13182 pending_workspace_folders,
13183 ..
13184 } => {
13185 pending_workspace_folders.lock().remove(&uri);
13186 }
13187 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13188 }
13189 }
13190}
13191
13192impl std::fmt::Debug for LanguageServerState {
13193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13194 match self {
13195 LanguageServerState::Starting { .. } => {
13196 f.debug_struct("LanguageServerState::Starting").finish()
13197 }
13198 LanguageServerState::Running { .. } => {
13199 f.debug_struct("LanguageServerState::Running").finish()
13200 }
13201 }
13202 }
13203}
13204
13205#[derive(Clone, Debug, Serialize)]
13206pub struct LanguageServerProgress {
13207 pub is_disk_based_diagnostics_progress: bool,
13208 pub is_cancellable: bool,
13209 pub title: Option<String>,
13210 pub message: Option<String>,
13211 pub percentage: Option<usize>,
13212 #[serde(skip_serializing)]
13213 pub last_update_at: Instant,
13214}
13215
13216#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13217pub struct DiagnosticSummary {
13218 pub error_count: usize,
13219 pub warning_count: usize,
13220}
13221
13222impl DiagnosticSummary {
13223 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13224 let mut this = Self {
13225 error_count: 0,
13226 warning_count: 0,
13227 };
13228
13229 for entry in diagnostics {
13230 if entry.diagnostic.is_primary {
13231 match entry.diagnostic.severity {
13232 DiagnosticSeverity::ERROR => this.error_count += 1,
13233 DiagnosticSeverity::WARNING => this.warning_count += 1,
13234 _ => {}
13235 }
13236 }
13237 }
13238
13239 this
13240 }
13241
13242 pub fn is_empty(&self) -> bool {
13243 self.error_count == 0 && self.warning_count == 0
13244 }
13245
13246 pub fn to_proto(
13247 self,
13248 language_server_id: LanguageServerId,
13249 path: &RelPath,
13250 ) -> proto::DiagnosticSummary {
13251 proto::DiagnosticSummary {
13252 path: path.to_proto(),
13253 language_server_id: language_server_id.0 as u64,
13254 error_count: self.error_count as u32,
13255 warning_count: self.warning_count as u32,
13256 }
13257 }
13258}
13259
13260#[derive(Clone, Debug)]
13261pub enum CompletionDocumentation {
13262 /// There is no documentation for this completion.
13263 Undocumented,
13264 /// A single line of documentation.
13265 SingleLine(SharedString),
13266 /// Multiple lines of plain text documentation.
13267 MultiLinePlainText(SharedString),
13268 /// Markdown documentation.
13269 MultiLineMarkdown(SharedString),
13270 /// Both single line and multiple lines of plain text documentation.
13271 SingleLineAndMultiLinePlainText {
13272 single_line: SharedString,
13273 plain_text: Option<SharedString>,
13274 },
13275}
13276
13277impl CompletionDocumentation {
13278 #[cfg(any(test, feature = "test-support"))]
13279 pub fn text(&self) -> SharedString {
13280 match self {
13281 CompletionDocumentation::Undocumented => "".into(),
13282 CompletionDocumentation::SingleLine(s) => s.clone(),
13283 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13284 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13285 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13286 single_line.clone()
13287 }
13288 }
13289 }
13290}
13291
13292impl From<lsp::Documentation> for CompletionDocumentation {
13293 fn from(docs: lsp::Documentation) -> Self {
13294 match docs {
13295 lsp::Documentation::String(text) => {
13296 if text.lines().count() <= 1 {
13297 CompletionDocumentation::SingleLine(text.into())
13298 } else {
13299 CompletionDocumentation::MultiLinePlainText(text.into())
13300 }
13301 }
13302
13303 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13304 lsp::MarkupKind::PlainText => {
13305 if value.lines().count() <= 1 {
13306 CompletionDocumentation::SingleLine(value.into())
13307 } else {
13308 CompletionDocumentation::MultiLinePlainText(value.into())
13309 }
13310 }
13311
13312 lsp::MarkupKind::Markdown => {
13313 CompletionDocumentation::MultiLineMarkdown(value.into())
13314 }
13315 },
13316 }
13317 }
13318}
13319
13320pub enum ResolvedHint {
13321 Resolved(InlayHint),
13322 Resolving(Shared<Task<()>>),
13323}
13324
13325fn glob_literal_prefix(glob: &Path) -> PathBuf {
13326 glob.components()
13327 .take_while(|component| match component {
13328 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13329 _ => true,
13330 })
13331 .collect()
13332}
13333
13334pub struct SshLspAdapter {
13335 name: LanguageServerName,
13336 binary: LanguageServerBinary,
13337 initialization_options: Option<String>,
13338 code_action_kinds: Option<Vec<CodeActionKind>>,
13339}
13340
13341impl SshLspAdapter {
13342 pub fn new(
13343 name: LanguageServerName,
13344 binary: LanguageServerBinary,
13345 initialization_options: Option<String>,
13346 code_action_kinds: Option<String>,
13347 ) -> Self {
13348 Self {
13349 name,
13350 binary,
13351 initialization_options,
13352 code_action_kinds: code_action_kinds
13353 .as_ref()
13354 .and_then(|c| serde_json::from_str(c).ok()),
13355 }
13356 }
13357}
13358
13359impl LspInstaller for SshLspAdapter {
13360 type BinaryVersion = ();
13361 async fn check_if_user_installed(
13362 &self,
13363 _: &dyn LspAdapterDelegate,
13364 _: Option<Toolchain>,
13365 _: &AsyncApp,
13366 ) -> Option<LanguageServerBinary> {
13367 Some(self.binary.clone())
13368 }
13369
13370 async fn cached_server_binary(
13371 &self,
13372 _: PathBuf,
13373 _: &dyn LspAdapterDelegate,
13374 ) -> Option<LanguageServerBinary> {
13375 None
13376 }
13377
13378 async fn fetch_latest_server_version(
13379 &self,
13380 _: &dyn LspAdapterDelegate,
13381 _: bool,
13382 _: &mut AsyncApp,
13383 ) -> Result<()> {
13384 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13385 }
13386
13387 async fn fetch_server_binary(
13388 &self,
13389 _: (),
13390 _: PathBuf,
13391 _: &dyn LspAdapterDelegate,
13392 ) -> Result<LanguageServerBinary> {
13393 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13394 }
13395}
13396
13397#[async_trait(?Send)]
13398impl LspAdapter for SshLspAdapter {
13399 fn name(&self) -> LanguageServerName {
13400 self.name.clone()
13401 }
13402
13403 async fn initialization_options(
13404 self: Arc<Self>,
13405 _: &Arc<dyn LspAdapterDelegate>,
13406 ) -> Result<Option<serde_json::Value>> {
13407 let Some(options) = &self.initialization_options else {
13408 return Ok(None);
13409 };
13410 let result = serde_json::from_str(options)?;
13411 Ok(result)
13412 }
13413
13414 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13415 self.code_action_kinds.clone()
13416 }
13417}
13418
13419pub fn language_server_settings<'a>(
13420 delegate: &'a dyn LspAdapterDelegate,
13421 language: &LanguageServerName,
13422 cx: &'a App,
13423) -> Option<&'a LspSettings> {
13424 language_server_settings_for(
13425 SettingsLocation {
13426 worktree_id: delegate.worktree_id(),
13427 path: RelPath::empty(),
13428 },
13429 language,
13430 cx,
13431 )
13432}
13433
13434pub(crate) fn language_server_settings_for<'a>(
13435 location: SettingsLocation<'a>,
13436 language: &LanguageServerName,
13437 cx: &'a App,
13438) -> Option<&'a LspSettings> {
13439 ProjectSettings::get(Some(location), cx).lsp.get(language)
13440}
13441
13442pub struct LocalLspAdapterDelegate {
13443 lsp_store: WeakEntity<LspStore>,
13444 worktree: worktree::Snapshot,
13445 fs: Arc<dyn Fs>,
13446 http_client: Arc<dyn HttpClient>,
13447 language_registry: Arc<LanguageRegistry>,
13448 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13449}
13450
13451impl LocalLspAdapterDelegate {
13452 pub fn new(
13453 language_registry: Arc<LanguageRegistry>,
13454 environment: &Entity<ProjectEnvironment>,
13455 lsp_store: WeakEntity<LspStore>,
13456 worktree: &Entity<Worktree>,
13457 http_client: Arc<dyn HttpClient>,
13458 fs: Arc<dyn Fs>,
13459 cx: &mut App,
13460 ) -> Arc<Self> {
13461 let load_shell_env_task =
13462 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13463
13464 Arc::new(Self {
13465 lsp_store,
13466 worktree: worktree.read(cx).snapshot(),
13467 fs,
13468 http_client,
13469 language_registry,
13470 load_shell_env_task,
13471 })
13472 }
13473
13474 fn from_local_lsp(
13475 local: &LocalLspStore,
13476 worktree: &Entity<Worktree>,
13477 cx: &mut App,
13478 ) -> Arc<Self> {
13479 Self::new(
13480 local.languages.clone(),
13481 &local.environment,
13482 local.weak.clone(),
13483 worktree,
13484 local.http_client.clone(),
13485 local.fs.clone(),
13486 cx,
13487 )
13488 }
13489}
13490
13491#[async_trait]
13492impl LspAdapterDelegate for LocalLspAdapterDelegate {
13493 fn show_notification(&self, message: &str, cx: &mut App) {
13494 self.lsp_store
13495 .update(cx, |_, cx| {
13496 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13497 })
13498 .ok();
13499 }
13500
13501 fn http_client(&self) -> Arc<dyn HttpClient> {
13502 self.http_client.clone()
13503 }
13504
13505 fn worktree_id(&self) -> WorktreeId {
13506 self.worktree.id()
13507 }
13508
13509 fn worktree_root_path(&self) -> &Path {
13510 self.worktree.abs_path().as_ref()
13511 }
13512
13513 async fn shell_env(&self) -> HashMap<String, String> {
13514 let task = self.load_shell_env_task.clone();
13515 task.await.unwrap_or_default()
13516 }
13517
13518 async fn npm_package_installed_version(
13519 &self,
13520 package_name: &str,
13521 ) -> Result<Option<(PathBuf, String)>> {
13522 let local_package_directory = self.worktree_root_path();
13523 let node_modules_directory = local_package_directory.join("node_modules");
13524
13525 if let Some(version) =
13526 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13527 {
13528 return Ok(Some((node_modules_directory, version)));
13529 }
13530 let Some(npm) = self.which("npm".as_ref()).await else {
13531 log::warn!(
13532 "Failed to find npm executable for {:?}",
13533 local_package_directory
13534 );
13535 return Ok(None);
13536 };
13537
13538 let env = self.shell_env().await;
13539 let output = util::command::new_smol_command(&npm)
13540 .args(["root", "-g"])
13541 .envs(env)
13542 .current_dir(local_package_directory)
13543 .output()
13544 .await?;
13545 let global_node_modules =
13546 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13547
13548 if let Some(version) =
13549 read_package_installed_version(global_node_modules.clone(), package_name).await?
13550 {
13551 return Ok(Some((global_node_modules, version)));
13552 }
13553 return Ok(None);
13554 }
13555
13556 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13557 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13558 if self.fs.is_file(&worktree_abs_path).await {
13559 worktree_abs_path.pop();
13560 }
13561
13562 let env = self.shell_env().await;
13563
13564 let shell_path = env.get("PATH").cloned();
13565
13566 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13567 }
13568
13569 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13570 let mut working_dir = self.worktree_root_path().to_path_buf();
13571 if self.fs.is_file(&working_dir).await {
13572 working_dir.pop();
13573 }
13574 let output = util::command::new_smol_command(&command.path)
13575 .args(command.arguments)
13576 .envs(command.env.clone().unwrap_or_default())
13577 .current_dir(working_dir)
13578 .output()
13579 .await?;
13580
13581 anyhow::ensure!(
13582 output.status.success(),
13583 "{}, stdout: {:?}, stderr: {:?}",
13584 output.status,
13585 String::from_utf8_lossy(&output.stdout),
13586 String::from_utf8_lossy(&output.stderr)
13587 );
13588 Ok(())
13589 }
13590
13591 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13592 self.language_registry
13593 .update_lsp_binary_status(server_name, status);
13594 }
13595
13596 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13597 self.language_registry
13598 .all_lsp_adapters()
13599 .into_iter()
13600 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13601 .collect()
13602 }
13603
13604 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13605 let dir = self.language_registry.language_server_download_dir(name)?;
13606
13607 if !dir.exists() {
13608 smol::fs::create_dir_all(&dir)
13609 .await
13610 .context("failed to create container directory")
13611 .log_err()?;
13612 }
13613
13614 Some(dir)
13615 }
13616
13617 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13618 let entry = self
13619 .worktree
13620 .entry_for_path(path)
13621 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13622 let abs_path = self.worktree.absolutize(&entry.path);
13623 self.fs.load(&abs_path).await
13624 }
13625}
13626
13627async fn populate_labels_for_symbols(
13628 symbols: Vec<CoreSymbol>,
13629 language_registry: &Arc<LanguageRegistry>,
13630 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13631 output: &mut Vec<Symbol>,
13632) {
13633 #[allow(clippy::mutable_key_type)]
13634 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13635
13636 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13637 for symbol in symbols {
13638 let Some(file_name) = symbol.path.file_name() else {
13639 continue;
13640 };
13641 let language = language_registry
13642 .load_language_for_file_path(Path::new(file_name))
13643 .await
13644 .ok()
13645 .or_else(|| {
13646 unknown_paths.insert(file_name.into());
13647 None
13648 });
13649 symbols_by_language
13650 .entry(language)
13651 .or_default()
13652 .push(symbol);
13653 }
13654
13655 for unknown_path in unknown_paths {
13656 log::info!("no language found for symbol in file {unknown_path:?}");
13657 }
13658
13659 let mut label_params = Vec::new();
13660 for (language, mut symbols) in symbols_by_language {
13661 label_params.clear();
13662 label_params.extend(
13663 symbols
13664 .iter_mut()
13665 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13666 );
13667
13668 let mut labels = Vec::new();
13669 if let Some(language) = language {
13670 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13671 language_registry
13672 .lsp_adapters(&language.name())
13673 .first()
13674 .cloned()
13675 });
13676 if let Some(lsp_adapter) = lsp_adapter {
13677 labels = lsp_adapter
13678 .labels_for_symbols(&label_params, &language)
13679 .await
13680 .log_err()
13681 .unwrap_or_default();
13682 }
13683 }
13684
13685 for ((symbol, (name, _)), label) in symbols
13686 .into_iter()
13687 .zip(label_params.drain(..))
13688 .zip(labels.into_iter().chain(iter::repeat(None)))
13689 {
13690 output.push(Symbol {
13691 language_server_name: symbol.language_server_name,
13692 source_worktree_id: symbol.source_worktree_id,
13693 source_language_server_id: symbol.source_language_server_id,
13694 path: symbol.path,
13695 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13696 name,
13697 kind: symbol.kind,
13698 range: symbol.range,
13699 });
13700 }
13701 }
13702}
13703
13704fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13705 match server.capabilities().text_document_sync.as_ref()? {
13706 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13707 // Server wants didSave but didn't specify includeText.
13708 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13709 // Server doesn't want didSave at all.
13710 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13711 // Server provided SaveOptions.
13712 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13713 Some(save_options.include_text.unwrap_or(false))
13714 }
13715 },
13716 // We do not have any save info. Kind affects didChange only.
13717 lsp::TextDocumentSyncCapability::Kind(_) => None,
13718 }
13719}
13720
13721/// Completion items are displayed in a `UniformList`.
13722/// Usually, those items are single-line strings, but in LSP responses,
13723/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13724/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13725/// 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,
13726/// breaking the completions menu presentation.
13727///
13728/// 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.
13729fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13730 let mut new_text = String::with_capacity(label.text.len());
13731 let mut offset_map = vec![0; label.text.len() + 1];
13732 let mut last_char_was_space = false;
13733 let mut new_idx = 0;
13734 let chars = label.text.char_indices().fuse();
13735 let mut newlines_removed = false;
13736
13737 for (idx, c) in chars {
13738 offset_map[idx] = new_idx;
13739
13740 match c {
13741 '\n' if last_char_was_space => {
13742 newlines_removed = true;
13743 }
13744 '\t' | ' ' if last_char_was_space => {}
13745 '\n' if !last_char_was_space => {
13746 new_text.push(' ');
13747 new_idx += 1;
13748 last_char_was_space = true;
13749 newlines_removed = true;
13750 }
13751 ' ' | '\t' => {
13752 new_text.push(' ');
13753 new_idx += 1;
13754 last_char_was_space = true;
13755 }
13756 _ => {
13757 new_text.push(c);
13758 new_idx += c.len_utf8();
13759 last_char_was_space = false;
13760 }
13761 }
13762 }
13763 offset_map[label.text.len()] = new_idx;
13764
13765 // Only modify the label if newlines were removed.
13766 if !newlines_removed {
13767 return;
13768 }
13769
13770 let last_index = new_idx;
13771 let mut run_ranges_errors = Vec::new();
13772 label.runs.retain_mut(|(range, _)| {
13773 match offset_map.get(range.start) {
13774 Some(&start) => range.start = start,
13775 None => {
13776 run_ranges_errors.push(range.clone());
13777 return false;
13778 }
13779 }
13780
13781 match offset_map.get(range.end) {
13782 Some(&end) => range.end = end,
13783 None => {
13784 run_ranges_errors.push(range.clone());
13785 range.end = last_index;
13786 }
13787 }
13788 true
13789 });
13790 if !run_ranges_errors.is_empty() {
13791 log::error!(
13792 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13793 label.text
13794 );
13795 }
13796
13797 let mut wrong_filter_range = None;
13798 if label.filter_range == (0..label.text.len()) {
13799 label.filter_range = 0..new_text.len();
13800 } else {
13801 let mut original_filter_range = Some(label.filter_range.clone());
13802 match offset_map.get(label.filter_range.start) {
13803 Some(&start) => label.filter_range.start = start,
13804 None => {
13805 wrong_filter_range = original_filter_range.take();
13806 label.filter_range.start = last_index;
13807 }
13808 }
13809
13810 match offset_map.get(label.filter_range.end) {
13811 Some(&end) => label.filter_range.end = end,
13812 None => {
13813 wrong_filter_range = original_filter_range.take();
13814 label.filter_range.end = last_index;
13815 }
13816 }
13817 }
13818 if let Some(wrong_filter_range) = wrong_filter_range {
13819 log::error!(
13820 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13821 label.text
13822 );
13823 }
13824
13825 label.text = new_text;
13826}
13827
13828#[cfg(test)]
13829mod tests {
13830 use language::HighlightId;
13831
13832 use super::*;
13833
13834 #[test]
13835 fn test_glob_literal_prefix() {
13836 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13837 assert_eq!(
13838 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13839 Path::new("node_modules")
13840 );
13841 assert_eq!(
13842 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13843 Path::new("foo")
13844 );
13845 assert_eq!(
13846 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13847 Path::new("foo/bar/baz.js")
13848 );
13849
13850 #[cfg(target_os = "windows")]
13851 {
13852 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13853 assert_eq!(
13854 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13855 Path::new("node_modules")
13856 );
13857 assert_eq!(
13858 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13859 Path::new("foo")
13860 );
13861 assert_eq!(
13862 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13863 Path::new("foo/bar/baz.js")
13864 );
13865 }
13866 }
13867
13868 #[test]
13869 fn test_multi_len_chars_normalization() {
13870 let mut label = CodeLabel::new(
13871 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13872 0..6,
13873 vec![(0..6, HighlightId(1))],
13874 );
13875 ensure_uniform_list_compatible_label(&mut label);
13876 assert_eq!(
13877 label,
13878 CodeLabel::new(
13879 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13880 0..6,
13881 vec![(0..6, HighlightId(1))],
13882 )
13883 );
13884 }
13885}