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