1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = settings.binary.as_ref()
567 && settings.path.is_some()
568 {
569 let settings = settings.clone();
570
571 return cx.background_spawn(async move {
572 let mut env = delegate.shell_env().await;
573 env.extend(settings.env.unwrap_or_default());
574
575 Ok(LanguageServerBinary {
576 path: PathBuf::from(&settings.path.unwrap()),
577 env: Some(env),
578 arguments: settings
579 .arguments
580 .unwrap_or_default()
581 .iter()
582 .map(Into::into)
583 .collect(),
584 })
585 });
586 }
587 let lsp_binary_options = LanguageServerBinaryOptions {
588 allow_path_lookup: !settings
589 .binary
590 .as_ref()
591 .and_then(|b| b.ignore_system_version)
592 .unwrap_or_default(),
593 allow_binary_download,
594 pre_release: settings
595 .fetch
596 .as_ref()
597 .and_then(|f| f.pre_release)
598 .unwrap_or(false),
599 };
600
601 cx.spawn(async move |cx| {
602 let binary_result = adapter
603 .clone()
604 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
605 .await;
606
607 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
608
609 let mut binary = binary_result?;
610 let mut shell_env = delegate.shell_env().await;
611
612 shell_env.extend(binary.env.unwrap_or_default());
613
614 if let Some(settings) = settings.binary.as_ref() {
615 if let Some(arguments) = &settings.arguments {
616 binary.arguments = arguments.iter().map(Into::into).collect();
617 }
618 if let Some(env) = &settings.env {
619 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
620 }
621 }
622
623 binary.env = Some(shell_env);
624 Ok(binary)
625 })
626 }
627
628 fn setup_lsp_messages(
629 lsp_store: WeakEntity<LspStore>,
630 language_server: &LanguageServer,
631 delegate: Arc<dyn LspAdapterDelegate>,
632 adapter: Arc<CachedLspAdapter>,
633 ) {
634 let name = language_server.name();
635 let server_id = language_server.server_id();
636 language_server
637 .on_notification::<lsp::notification::PublishDiagnostics, _>({
638 let adapter = adapter.clone();
639 let this = lsp_store.clone();
640 move |mut params, cx| {
641 let adapter = adapter.clone();
642 if let Some(this) = this.upgrade() {
643 this.update(cx, |this, cx| {
644 {
645 let buffer = params
646 .uri
647 .to_file_path()
648 .map(|file_path| this.get_buffer(&file_path, cx))
649 .ok()
650 .flatten();
651 adapter.process_diagnostics(&mut params, server_id, buffer);
652 }
653
654 this.merge_lsp_diagnostics(
655 DiagnosticSourceKind::Pushed,
656 vec![DocumentDiagnosticsUpdate {
657 server_id,
658 diagnostics: params,
659 result_id: None,
660 disk_based_sources: Cow::Borrowed(
661 &adapter.disk_based_diagnostic_sources,
662 ),
663 }],
664 |_, diagnostic, cx| match diagnostic.source_kind {
665 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
666 adapter.retain_old_diagnostic(diagnostic, cx)
667 }
668 DiagnosticSourceKind::Pulled => true,
669 },
670 cx,
671 )
672 .log_err();
673 })
674 .ok();
675 }
676 }
677 })
678 .detach();
679 language_server
680 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
681 let adapter = adapter.adapter.clone();
682 let delegate = delegate.clone();
683 let this = lsp_store.clone();
684 move |params, cx| {
685 let adapter = adapter.clone();
686 let delegate = delegate.clone();
687 let this = this.clone();
688 let mut cx = cx.clone();
689 async move {
690 let toolchain_for_id = this
691 .update(&mut cx, |this, _| {
692 this.as_local()?.language_server_ids.iter().find_map(
693 |(seed, value)| {
694 (value.id == server_id).then(|| seed.toolchain.clone())
695 },
696 )
697 })?
698 .context("Expected the LSP store to be in a local mode")?;
699 let workspace_config = Self::workspace_configuration_for_adapter(
700 adapter.clone(),
701 &delegate,
702 toolchain_for_id,
703 &mut cx,
704 )
705 .await?;
706
707 Ok(params
708 .items
709 .into_iter()
710 .map(|item| {
711 if let Some(section) = &item.section {
712 workspace_config
713 .get(section)
714 .cloned()
715 .unwrap_or(serde_json::Value::Null)
716 } else {
717 workspace_config.clone()
718 }
719 })
720 .collect())
721 }
722 }
723 })
724 .detach();
725
726 language_server
727 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
728 let this = lsp_store.clone();
729 move |_, cx| {
730 let this = this.clone();
731 let cx = cx.clone();
732 async move {
733 let Some(server) =
734 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
735 else {
736 return Ok(None);
737 };
738 let root = server.workspace_folders();
739 Ok(Some(
740 root.into_iter()
741 .map(|uri| WorkspaceFolder {
742 uri,
743 name: Default::default(),
744 })
745 .collect(),
746 ))
747 }
748 }
749 })
750 .detach();
751 // Even though we don't have handling for these requests, respond to them to
752 // avoid stalling any language server like `gopls` which waits for a response
753 // to these requests when initializing.
754 language_server
755 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
756 let this = lsp_store.clone();
757 move |params, cx| {
758 let this = this.clone();
759 let mut cx = cx.clone();
760 async move {
761 this.update(&mut cx, |this, _| {
762 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
763 {
764 status
765 .progress_tokens
766 .insert(ProgressToken::from_lsp(params.token));
767 }
768 })?;
769
770 Ok(())
771 }
772 }
773 })
774 .detach();
775
776 language_server
777 .on_request::<lsp::request::RegisterCapability, _, _>({
778 let lsp_store = lsp_store.clone();
779 move |params, cx| {
780 let lsp_store = lsp_store.clone();
781 let mut cx = cx.clone();
782 async move {
783 lsp_store
784 .update(&mut cx, |lsp_store, cx| {
785 if lsp_store.as_local().is_some() {
786 match lsp_store
787 .register_server_capabilities(server_id, params, cx)
788 {
789 Ok(()) => {}
790 Err(e) => {
791 log::error!(
792 "Failed to register server capabilities: {e:#}"
793 );
794 }
795 };
796 }
797 })
798 .ok();
799 Ok(())
800 }
801 }
802 })
803 .detach();
804
805 language_server
806 .on_request::<lsp::request::UnregisterCapability, _, _>({
807 let lsp_store = lsp_store.clone();
808 move |params, cx| {
809 let lsp_store = lsp_store.clone();
810 let mut cx = cx.clone();
811 async move {
812 lsp_store
813 .update(&mut cx, |lsp_store, cx| {
814 if lsp_store.as_local().is_some() {
815 match lsp_store
816 .unregister_server_capabilities(server_id, params, cx)
817 {
818 Ok(()) => {}
819 Err(e) => {
820 log::error!(
821 "Failed to unregister server capabilities: {e:#}"
822 );
823 }
824 }
825 }
826 })
827 .ok();
828 Ok(())
829 }
830 }
831 })
832 .detach();
833
834 language_server
835 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
836 let this = lsp_store.clone();
837 move |params, cx| {
838 let mut cx = cx.clone();
839 let this = this.clone();
840 async move {
841 LocalLspStore::on_lsp_workspace_edit(
842 this.clone(),
843 params,
844 server_id,
845 &mut cx,
846 )
847 .await
848 }
849 }
850 })
851 .detach();
852
853 language_server
854 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
855 let lsp_store = lsp_store.clone();
856 let request_id = Arc::new(AtomicUsize::new(0));
857 move |(), cx| {
858 let lsp_store = lsp_store.clone();
859 let request_id = request_id.clone();
860 let mut cx = cx.clone();
861 async move {
862 lsp_store
863 .update(&mut cx, |lsp_store, cx| {
864 let request_id =
865 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
866 cx.emit(LspStoreEvent::RefreshInlayHints {
867 server_id,
868 request_id,
869 });
870 lsp_store
871 .downstream_client
872 .as_ref()
873 .map(|(client, project_id)| {
874 client.send(proto::RefreshInlayHints {
875 project_id: *project_id,
876 server_id: server_id.to_proto(),
877 request_id: request_id.map(|id| id as u64),
878 })
879 })
880 })?
881 .transpose()?;
882 Ok(())
883 }
884 }
885 })
886 .detach();
887
888 language_server
889 .on_request::<lsp::request::CodeLensRefresh, _, _>({
890 let this = lsp_store.clone();
891 move |(), cx| {
892 let this = this.clone();
893 let mut cx = cx.clone();
894 async move {
895 this.update(&mut cx, |this, cx| {
896 cx.emit(LspStoreEvent::RefreshCodeLens);
897 this.downstream_client.as_ref().map(|(client, project_id)| {
898 client.send(proto::RefreshCodeLens {
899 project_id: *project_id,
900 })
901 })
902 })?
903 .transpose()?;
904 Ok(())
905 }
906 }
907 })
908 .detach();
909
910 language_server
911 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
912 let this = lsp_store.clone();
913 move |(), cx| {
914 let this = this.clone();
915 let mut cx = cx.clone();
916 async move {
917 this.update(&mut cx, |lsp_store, _| {
918 lsp_store.pull_workspace_diagnostics(server_id);
919 lsp_store
920 .downstream_client
921 .as_ref()
922 .map(|(client, project_id)| {
923 client.send(proto::PullWorkspaceDiagnostics {
924 project_id: *project_id,
925 server_id: server_id.to_proto(),
926 })
927 })
928 })?
929 .transpose()?;
930 Ok(())
931 }
932 }
933 })
934 .detach();
935
936 language_server
937 .on_request::<lsp::request::ShowMessageRequest, _, _>({
938 let this = lsp_store.clone();
939 let name = name.to_string();
940 move |params, cx| {
941 let this = this.clone();
942 let name = name.to_string();
943 let mut cx = cx.clone();
944 async move {
945 let actions = params.actions.unwrap_or_default();
946 let (tx, rx) = smol::channel::bounded(1);
947 let request = LanguageServerPromptRequest {
948 level: match params.typ {
949 lsp::MessageType::ERROR => PromptLevel::Critical,
950 lsp::MessageType::WARNING => PromptLevel::Warning,
951 _ => PromptLevel::Info,
952 },
953 message: params.message,
954 actions,
955 response_channel: tx,
956 lsp_name: name.clone(),
957 };
958
959 let did_update = this
960 .update(&mut cx, |_, cx| {
961 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
962 })
963 .is_ok();
964 if did_update {
965 let response = rx.recv().await.ok();
966 Ok(response)
967 } else {
968 Ok(None)
969 }
970 }
971 }
972 })
973 .detach();
974 language_server
975 .on_notification::<lsp::notification::ShowMessage, _>({
976 let this = lsp_store.clone();
977 let name = name.to_string();
978 move |params, cx| {
979 let this = this.clone();
980 let name = name.to_string();
981 let mut cx = cx.clone();
982
983 let (tx, _) = smol::channel::bounded(1);
984 let request = LanguageServerPromptRequest {
985 level: match params.typ {
986 lsp::MessageType::ERROR => PromptLevel::Critical,
987 lsp::MessageType::WARNING => PromptLevel::Warning,
988 _ => PromptLevel::Info,
989 },
990 message: params.message,
991 actions: vec![],
992 response_channel: tx,
993 lsp_name: name,
994 };
995
996 let _ = this.update(&mut cx, |_, cx| {
997 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
998 });
999 }
1000 })
1001 .detach();
1002
1003 let disk_based_diagnostics_progress_token =
1004 adapter.disk_based_diagnostics_progress_token.clone();
1005
1006 language_server
1007 .on_notification::<lsp::notification::Progress, _>({
1008 let this = lsp_store.clone();
1009 move |params, cx| {
1010 if let Some(this) = this.upgrade() {
1011 this.update(cx, |this, cx| {
1012 this.on_lsp_progress(
1013 params,
1014 server_id,
1015 disk_based_diagnostics_progress_token.clone(),
1016 cx,
1017 );
1018 })
1019 .ok();
1020 }
1021 }
1022 })
1023 .detach();
1024
1025 language_server
1026 .on_notification::<lsp::notification::LogMessage, _>({
1027 let this = lsp_store.clone();
1028 move |params, cx| {
1029 if let Some(this) = this.upgrade() {
1030 this.update(cx, |_, cx| {
1031 cx.emit(LspStoreEvent::LanguageServerLog(
1032 server_id,
1033 LanguageServerLogType::Log(params.typ),
1034 params.message,
1035 ));
1036 })
1037 .ok();
1038 }
1039 }
1040 })
1041 .detach();
1042
1043 language_server
1044 .on_notification::<lsp::notification::LogTrace, _>({
1045 let this = lsp_store.clone();
1046 move |params, cx| {
1047 let mut cx = cx.clone();
1048 if let Some(this) = this.upgrade() {
1049 this.update(&mut cx, |_, cx| {
1050 cx.emit(LspStoreEvent::LanguageServerLog(
1051 server_id,
1052 LanguageServerLogType::Trace {
1053 verbose_info: params.verbose,
1054 },
1055 params.message,
1056 ));
1057 })
1058 .ok();
1059 }
1060 }
1061 })
1062 .detach();
1063
1064 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1065 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1066 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1067 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1068 }
1069
1070 fn shutdown_language_servers_on_quit(
1071 &mut self,
1072 _: &mut Context<LspStore>,
1073 ) -> impl Future<Output = ()> + use<> {
1074 let shutdown_futures = self
1075 .language_servers
1076 .drain()
1077 .map(|(_, server_state)| Self::shutdown_server(server_state))
1078 .collect::<Vec<_>>();
1079
1080 async move {
1081 join_all(shutdown_futures).await;
1082 }
1083 }
1084
1085 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1086 match server_state {
1087 LanguageServerState::Running { server, .. } => {
1088 if let Some(shutdown) = server.shutdown() {
1089 shutdown.await;
1090 }
1091 }
1092 LanguageServerState::Starting { startup, .. } => {
1093 if let Some(server) = startup.await
1094 && let Some(shutdown) = server.shutdown()
1095 {
1096 shutdown.await;
1097 }
1098 }
1099 }
1100 Ok(())
1101 }
1102
1103 fn language_servers_for_worktree(
1104 &self,
1105 worktree_id: WorktreeId,
1106 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1107 self.language_server_ids
1108 .iter()
1109 .filter_map(move |(seed, state)| {
1110 if seed.worktree_id != worktree_id {
1111 return None;
1112 }
1113
1114 if let Some(LanguageServerState::Running { server, .. }) =
1115 self.language_servers.get(&state.id)
1116 {
1117 Some(server)
1118 } else {
1119 None
1120 }
1121 })
1122 }
1123
1124 fn language_server_ids_for_project_path(
1125 &self,
1126 project_path: ProjectPath,
1127 language: &Language,
1128 cx: &mut App,
1129 ) -> Vec<LanguageServerId> {
1130 let Some(worktree) = self
1131 .worktree_store
1132 .read(cx)
1133 .worktree_for_id(project_path.worktree_id, cx)
1134 else {
1135 return Vec::new();
1136 };
1137 let delegate: Arc<dyn ManifestDelegate> =
1138 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1139
1140 self.lsp_tree
1141 .get(
1142 project_path,
1143 language.name(),
1144 language.manifest(),
1145 &delegate,
1146 cx,
1147 )
1148 .collect::<Vec<_>>()
1149 }
1150
1151 fn language_server_ids_for_buffer(
1152 &self,
1153 buffer: &Buffer,
1154 cx: &mut App,
1155 ) -> Vec<LanguageServerId> {
1156 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1157 let worktree_id = file.worktree_id(cx);
1158
1159 let path: Arc<RelPath> = file
1160 .path()
1161 .parent()
1162 .map(Arc::from)
1163 .unwrap_or_else(|| file.path().clone());
1164 let worktree_path = ProjectPath { worktree_id, path };
1165 self.language_server_ids_for_project_path(worktree_path, language, cx)
1166 } else {
1167 Vec::new()
1168 }
1169 }
1170
1171 fn language_servers_for_buffer<'a>(
1172 &'a self,
1173 buffer: &'a Buffer,
1174 cx: &'a mut App,
1175 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1176 self.language_server_ids_for_buffer(buffer, cx)
1177 .into_iter()
1178 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1179 LanguageServerState::Running {
1180 adapter, server, ..
1181 } => Some((adapter, server)),
1182 _ => None,
1183 })
1184 }
1185
1186 async fn execute_code_action_kind_locally(
1187 lsp_store: WeakEntity<LspStore>,
1188 mut buffers: Vec<Entity<Buffer>>,
1189 kind: CodeActionKind,
1190 push_to_history: bool,
1191 cx: &mut AsyncApp,
1192 ) -> anyhow::Result<ProjectTransaction> {
1193 // Do not allow multiple concurrent code actions requests for the
1194 // same buffer.
1195 lsp_store.update(cx, |this, cx| {
1196 let this = this.as_local_mut().unwrap();
1197 buffers.retain(|buffer| {
1198 this.buffers_being_formatted
1199 .insert(buffer.read(cx).remote_id())
1200 });
1201 })?;
1202 let _cleanup = defer({
1203 let this = lsp_store.clone();
1204 let mut cx = cx.clone();
1205 let buffers = &buffers;
1206 move || {
1207 this.update(&mut cx, |this, cx| {
1208 let this = this.as_local_mut().unwrap();
1209 for buffer in buffers {
1210 this.buffers_being_formatted
1211 .remove(&buffer.read(cx).remote_id());
1212 }
1213 })
1214 .ok();
1215 }
1216 });
1217 let mut project_transaction = ProjectTransaction::default();
1218
1219 for buffer in &buffers {
1220 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1221 buffer.update(cx, |buffer, cx| {
1222 lsp_store
1223 .as_local()
1224 .unwrap()
1225 .language_servers_for_buffer(buffer, cx)
1226 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1227 .collect::<Vec<_>>()
1228 })
1229 })?;
1230 for (_, language_server) in adapters_and_servers.iter() {
1231 let actions = Self::get_server_code_actions_from_action_kinds(
1232 &lsp_store,
1233 language_server.server_id(),
1234 vec![kind.clone()],
1235 buffer,
1236 cx,
1237 )
1238 .await?;
1239 Self::execute_code_actions_on_server(
1240 &lsp_store,
1241 language_server,
1242 actions,
1243 push_to_history,
1244 &mut project_transaction,
1245 cx,
1246 )
1247 .await?;
1248 }
1249 }
1250 Ok(project_transaction)
1251 }
1252
1253 async fn format_locally(
1254 lsp_store: WeakEntity<LspStore>,
1255 mut buffers: Vec<FormattableBuffer>,
1256 push_to_history: bool,
1257 trigger: FormatTrigger,
1258 logger: zlog::Logger,
1259 cx: &mut AsyncApp,
1260 ) -> anyhow::Result<ProjectTransaction> {
1261 // Do not allow multiple concurrent formatting requests for the
1262 // same buffer.
1263 lsp_store.update(cx, |this, cx| {
1264 let this = this.as_local_mut().unwrap();
1265 buffers.retain(|buffer| {
1266 this.buffers_being_formatted
1267 .insert(buffer.handle.read(cx).remote_id())
1268 });
1269 })?;
1270
1271 let _cleanup = defer({
1272 let this = lsp_store.clone();
1273 let mut cx = cx.clone();
1274 let buffers = &buffers;
1275 move || {
1276 this.update(&mut cx, |this, cx| {
1277 let this = this.as_local_mut().unwrap();
1278 for buffer in buffers {
1279 this.buffers_being_formatted
1280 .remove(&buffer.handle.read(cx).remote_id());
1281 }
1282 })
1283 .ok();
1284 }
1285 });
1286
1287 let mut project_transaction = ProjectTransaction::default();
1288
1289 for buffer in &buffers {
1290 zlog::debug!(
1291 logger =>
1292 "formatting buffer '{:?}'",
1293 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1294 );
1295 // Create an empty transaction to hold all of the formatting edits.
1296 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1297 // ensure no transactions created while formatting are
1298 // grouped with the previous transaction in the history
1299 // based on the transaction group interval
1300 buffer.finalize_last_transaction();
1301 buffer
1302 .start_transaction()
1303 .context("transaction already open")?;
1304 buffer.end_transaction(cx);
1305 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1306 buffer.finalize_last_transaction();
1307 anyhow::Ok(transaction_id)
1308 })??;
1309
1310 let result = Self::format_buffer_locally(
1311 lsp_store.clone(),
1312 buffer,
1313 formatting_transaction_id,
1314 trigger,
1315 logger,
1316 cx,
1317 )
1318 .await;
1319
1320 buffer.handle.update(cx, |buffer, cx| {
1321 let Some(formatting_transaction) =
1322 buffer.get_transaction(formatting_transaction_id).cloned()
1323 else {
1324 zlog::warn!(logger => "no formatting transaction");
1325 return;
1326 };
1327 if formatting_transaction.edit_ids.is_empty() {
1328 zlog::debug!(logger => "no changes made while formatting");
1329 buffer.forget_transaction(formatting_transaction_id);
1330 return;
1331 }
1332 if !push_to_history {
1333 zlog::trace!(logger => "forgetting format transaction");
1334 buffer.forget_transaction(formatting_transaction.id);
1335 }
1336 project_transaction
1337 .0
1338 .insert(cx.entity(), formatting_transaction);
1339 })?;
1340
1341 result?;
1342 }
1343
1344 Ok(project_transaction)
1345 }
1346
1347 async fn format_buffer_locally(
1348 lsp_store: WeakEntity<LspStore>,
1349 buffer: &FormattableBuffer,
1350 formatting_transaction_id: clock::Lamport,
1351 trigger: FormatTrigger,
1352 logger: zlog::Logger,
1353 cx: &mut AsyncApp,
1354 ) -> Result<()> {
1355 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1356 buffer.handle.update(cx, |buffer, cx| {
1357 let adapters_and_servers = lsp_store
1358 .as_local()
1359 .unwrap()
1360 .language_servers_for_buffer(buffer, cx)
1361 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1362 .collect::<Vec<_>>();
1363 let settings =
1364 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1365 .into_owned();
1366 (adapters_and_servers, settings)
1367 })
1368 })?;
1369
1370 /// Apply edits to the buffer that will become part of the formatting transaction.
1371 /// Fails if the buffer has been edited since the start of that transaction.
1372 fn extend_formatting_transaction(
1373 buffer: &FormattableBuffer,
1374 formatting_transaction_id: text::TransactionId,
1375 cx: &mut AsyncApp,
1376 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1377 ) -> anyhow::Result<()> {
1378 buffer.handle.update(cx, |buffer, cx| {
1379 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1380 if last_transaction_id != Some(formatting_transaction_id) {
1381 anyhow::bail!("Buffer edited while formatting. Aborting")
1382 }
1383 buffer.start_transaction();
1384 operation(buffer, cx);
1385 if let Some(transaction_id) = buffer.end_transaction(cx) {
1386 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1387 }
1388 Ok(())
1389 })?
1390 }
1391
1392 // handle whitespace formatting
1393 if settings.remove_trailing_whitespace_on_save {
1394 zlog::trace!(logger => "removing trailing whitespace");
1395 let diff = buffer
1396 .handle
1397 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1398 .await;
1399 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1400 buffer.apply_diff(diff, cx);
1401 })?;
1402 }
1403
1404 if settings.ensure_final_newline_on_save {
1405 zlog::trace!(logger => "ensuring final newline");
1406 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1407 buffer.ensure_final_newline(cx);
1408 })?;
1409 }
1410
1411 // Formatter for `code_actions_on_format` that runs before
1412 // the rest of the formatters
1413 let mut code_actions_on_format_formatters = None;
1414 let should_run_code_actions_on_format = !matches!(
1415 (trigger, &settings.format_on_save),
1416 (FormatTrigger::Save, &FormatOnSave::Off)
1417 );
1418 if should_run_code_actions_on_format {
1419 let have_code_actions_to_run_on_format = settings
1420 .code_actions_on_format
1421 .values()
1422 .any(|enabled| *enabled);
1423 if have_code_actions_to_run_on_format {
1424 zlog::trace!(logger => "going to run code actions on format");
1425 code_actions_on_format_formatters = Some(
1426 settings
1427 .code_actions_on_format
1428 .iter()
1429 .filter_map(|(action, enabled)| enabled.then_some(action))
1430 .cloned()
1431 .map(Formatter::CodeAction)
1432 .collect::<Vec<_>>(),
1433 );
1434 }
1435 }
1436
1437 let formatters = match (trigger, &settings.format_on_save) {
1438 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1439 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1440 settings.formatter.as_ref()
1441 }
1442 };
1443
1444 let formatters = code_actions_on_format_formatters
1445 .iter()
1446 .flatten()
1447 .chain(formatters);
1448
1449 for formatter in formatters {
1450 let formatter = if formatter == &Formatter::Auto {
1451 if settings.prettier.allowed {
1452 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1453 &Formatter::Prettier
1454 } else {
1455 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1456 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1457 }
1458 } else {
1459 formatter
1460 };
1461 match formatter {
1462 Formatter::Auto => unreachable!("Auto resolved above"),
1463 Formatter::Prettier => {
1464 let logger = zlog::scoped!(logger => "prettier");
1465 zlog::trace!(logger => "formatting");
1466 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1467
1468 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1469 lsp_store.prettier_store().unwrap().downgrade()
1470 })?;
1471 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1472 .await
1473 .transpose()?;
1474 let Some(diff) = diff else {
1475 zlog::trace!(logger => "No changes");
1476 continue;
1477 };
1478
1479 extend_formatting_transaction(
1480 buffer,
1481 formatting_transaction_id,
1482 cx,
1483 |buffer, cx| {
1484 buffer.apply_diff(diff, cx);
1485 },
1486 )?;
1487 }
1488 Formatter::External { command, arguments } => {
1489 let logger = zlog::scoped!(logger => "command");
1490 zlog::trace!(logger => "formatting");
1491 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1492
1493 let diff = Self::format_via_external_command(
1494 buffer,
1495 command.as_ref(),
1496 arguments.as_deref(),
1497 cx,
1498 )
1499 .await
1500 .with_context(|| {
1501 format!("Failed to format buffer via external command: {}", command)
1502 })?;
1503 let Some(diff) = diff else {
1504 zlog::trace!(logger => "No changes");
1505 continue;
1506 };
1507
1508 extend_formatting_transaction(
1509 buffer,
1510 formatting_transaction_id,
1511 cx,
1512 |buffer, cx| {
1513 buffer.apply_diff(diff, cx);
1514 },
1515 )?;
1516 }
1517 Formatter::LanguageServer(specifier) => {
1518 let logger = zlog::scoped!(logger => "language-server");
1519 zlog::trace!(logger => "formatting");
1520 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1521
1522 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1523 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1524 continue;
1525 };
1526
1527 let language_server = match specifier {
1528 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1529 adapters_and_servers.iter().find_map(|(adapter, server)| {
1530 if adapter.name.0.as_ref() == name {
1531 Some(server.clone())
1532 } else {
1533 None
1534 }
1535 })
1536 }
1537 settings::LanguageServerFormatterSpecifier::Current => {
1538 adapters_and_servers.first().map(|e| e.1.clone())
1539 }
1540 };
1541
1542 let Some(language_server) = language_server else {
1543 log::debug!(
1544 "No language server found to format buffer '{:?}'. Skipping",
1545 buffer_path_abs.as_path().to_string_lossy()
1546 );
1547 continue;
1548 };
1549
1550 zlog::trace!(
1551 logger =>
1552 "Formatting buffer '{:?}' using language server '{:?}'",
1553 buffer_path_abs.as_path().to_string_lossy(),
1554 language_server.name()
1555 );
1556
1557 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1558 zlog::trace!(logger => "formatting ranges");
1559 Self::format_ranges_via_lsp(
1560 &lsp_store,
1561 &buffer.handle,
1562 ranges,
1563 buffer_path_abs,
1564 &language_server,
1565 &settings,
1566 cx,
1567 )
1568 .await
1569 .context("Failed to format ranges via language server")?
1570 } else {
1571 zlog::trace!(logger => "formatting full");
1572 Self::format_via_lsp(
1573 &lsp_store,
1574 &buffer.handle,
1575 buffer_path_abs,
1576 &language_server,
1577 &settings,
1578 cx,
1579 )
1580 .await
1581 .context("failed to format via language server")?
1582 };
1583
1584 if edits.is_empty() {
1585 zlog::trace!(logger => "No changes");
1586 continue;
1587 }
1588 extend_formatting_transaction(
1589 buffer,
1590 formatting_transaction_id,
1591 cx,
1592 |buffer, cx| {
1593 buffer.edit(edits, None, cx);
1594 },
1595 )?;
1596 }
1597 Formatter::CodeAction(code_action_name) => {
1598 let logger = zlog::scoped!(logger => "code-actions");
1599 zlog::trace!(logger => "formatting");
1600 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1601
1602 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1603 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1604 continue;
1605 };
1606
1607 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1608 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1609
1610 let mut actions_and_servers = Vec::new();
1611
1612 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1613 let actions_result = Self::get_server_code_actions_from_action_kinds(
1614 &lsp_store,
1615 language_server.server_id(),
1616 vec![code_action_kind.clone()],
1617 &buffer.handle,
1618 cx,
1619 )
1620 .await
1621 .with_context(|| {
1622 format!(
1623 "Failed to resolve code action {:?} with language server {}",
1624 code_action_kind,
1625 language_server.name()
1626 )
1627 });
1628 let Ok(actions) = actions_result else {
1629 // note: it may be better to set result to the error and break formatters here
1630 // but for now we try to execute the actions that we can resolve and skip the rest
1631 zlog::error!(
1632 logger =>
1633 "Failed to resolve code action {:?} with language server {}",
1634 code_action_kind,
1635 language_server.name()
1636 );
1637 continue;
1638 };
1639 for action in actions {
1640 actions_and_servers.push((action, index));
1641 }
1642 }
1643
1644 if actions_and_servers.is_empty() {
1645 zlog::warn!(logger => "No code actions were resolved, continuing");
1646 continue;
1647 }
1648
1649 'actions: for (mut action, server_index) in actions_and_servers {
1650 let server = &adapters_and_servers[server_index].1;
1651
1652 let describe_code_action = |action: &CodeAction| {
1653 format!(
1654 "code action '{}' with title \"{}\" on server {}",
1655 action
1656 .lsp_action
1657 .action_kind()
1658 .unwrap_or("unknown".into())
1659 .as_str(),
1660 action.lsp_action.title(),
1661 server.name(),
1662 )
1663 };
1664
1665 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1666
1667 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1668 zlog::error!(
1669 logger =>
1670 "Failed to resolve {}. Error: {}",
1671 describe_code_action(&action),
1672 err
1673 );
1674 continue;
1675 }
1676
1677 if let Some(edit) = action.lsp_action.edit().cloned() {
1678 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1679 // but filters out and logs warnings for code actions that require unreasonably
1680 // difficult handling on our part, such as:
1681 // - applying edits that call commands
1682 // which can result in arbitrary workspace edits being sent from the server that
1683 // have no way of being tied back to the command that initiated them (i.e. we
1684 // can't know which edits are part of the format request, or if the server is done sending
1685 // actions in response to the command)
1686 // - actions that create/delete/modify/rename files other than the one we are formatting
1687 // as we then would need to handle such changes correctly in the local history as well
1688 // as the remote history through the ProjectTransaction
1689 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1690 // Supporting these actions is not impossible, but not supported as of yet.
1691 if edit.changes.is_none() && edit.document_changes.is_none() {
1692 zlog::trace!(
1693 logger =>
1694 "No changes for code action. Skipping {}",
1695 describe_code_action(&action),
1696 );
1697 continue;
1698 }
1699
1700 let mut operations = Vec::new();
1701 if let Some(document_changes) = edit.document_changes {
1702 match document_changes {
1703 lsp::DocumentChanges::Edits(edits) => operations.extend(
1704 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1705 ),
1706 lsp::DocumentChanges::Operations(ops) => operations = ops,
1707 }
1708 } else if let Some(changes) = edit.changes {
1709 operations.extend(changes.into_iter().map(|(uri, edits)| {
1710 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1711 text_document:
1712 lsp::OptionalVersionedTextDocumentIdentifier {
1713 uri,
1714 version: None,
1715 },
1716 edits: edits.into_iter().map(Edit::Plain).collect(),
1717 })
1718 }));
1719 }
1720
1721 let mut edits = Vec::with_capacity(operations.len());
1722
1723 if operations.is_empty() {
1724 zlog::trace!(
1725 logger =>
1726 "No changes for code action. Skipping {}",
1727 describe_code_action(&action),
1728 );
1729 continue;
1730 }
1731 for operation in operations {
1732 let op = match operation {
1733 lsp::DocumentChangeOperation::Edit(op) => op,
1734 lsp::DocumentChangeOperation::Op(_) => {
1735 zlog::warn!(
1736 logger =>
1737 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1738 describe_code_action(&action),
1739 );
1740 continue 'actions;
1741 }
1742 };
1743 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1744 zlog::warn!(
1745 logger =>
1746 "Failed to convert URI '{:?}' to file path. Skipping {}",
1747 &op.text_document.uri,
1748 describe_code_action(&action),
1749 );
1750 continue 'actions;
1751 };
1752 if &file_path != buffer_path_abs {
1753 zlog::warn!(
1754 logger =>
1755 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1756 file_path,
1757 buffer_path_abs,
1758 describe_code_action(&action),
1759 );
1760 continue 'actions;
1761 }
1762
1763 let mut lsp_edits = Vec::new();
1764 for edit in op.edits {
1765 match edit {
1766 Edit::Plain(edit) => {
1767 if !lsp_edits.contains(&edit) {
1768 lsp_edits.push(edit);
1769 }
1770 }
1771 Edit::Annotated(edit) => {
1772 if !lsp_edits.contains(&edit.text_edit) {
1773 lsp_edits.push(edit.text_edit);
1774 }
1775 }
1776 Edit::Snippet(_) => {
1777 zlog::warn!(
1778 logger =>
1779 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1780 describe_code_action(&action),
1781 );
1782 continue 'actions;
1783 }
1784 }
1785 }
1786 let edits_result = lsp_store
1787 .update(cx, |lsp_store, cx| {
1788 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1789 &buffer.handle,
1790 lsp_edits,
1791 server.server_id(),
1792 op.text_document.version,
1793 cx,
1794 )
1795 })?
1796 .await;
1797 let Ok(resolved_edits) = edits_result else {
1798 zlog::warn!(
1799 logger =>
1800 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1801 buffer_path_abs.as_path(),
1802 describe_code_action(&action),
1803 );
1804 continue 'actions;
1805 };
1806 edits.extend(resolved_edits);
1807 }
1808
1809 if edits.is_empty() {
1810 zlog::warn!(logger => "No edits resolved from LSP");
1811 continue;
1812 }
1813
1814 extend_formatting_transaction(
1815 buffer,
1816 formatting_transaction_id,
1817 cx,
1818 |buffer, cx| {
1819 zlog::info!(
1820 "Applying edits {edits:?}. Content: {:?}",
1821 buffer.text()
1822 );
1823 buffer.edit(edits, None, cx);
1824 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1825 },
1826 )?;
1827 }
1828
1829 if let Some(command) = action.lsp_action.command() {
1830 zlog::warn!(
1831 logger =>
1832 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1833 &command.command,
1834 );
1835
1836 // bail early if command is invalid
1837 let server_capabilities = server.capabilities();
1838 let available_commands = server_capabilities
1839 .execute_command_provider
1840 .as_ref()
1841 .map(|options| options.commands.as_slice())
1842 .unwrap_or_default();
1843 if !available_commands.contains(&command.command) {
1844 zlog::warn!(
1845 logger =>
1846 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1847 command.command,
1848 server.name(),
1849 );
1850 continue;
1851 }
1852
1853 // noop so we just ensure buffer hasn't been edited since resolving code actions
1854 extend_formatting_transaction(
1855 buffer,
1856 formatting_transaction_id,
1857 cx,
1858 |_, _| {},
1859 )?;
1860 zlog::info!(logger => "Executing command {}", &command.command);
1861
1862 lsp_store.update(cx, |this, _| {
1863 this.as_local_mut()
1864 .unwrap()
1865 .last_workspace_edits_by_language_server
1866 .remove(&server.server_id());
1867 })?;
1868
1869 let execute_command_result = server
1870 .request::<lsp::request::ExecuteCommand>(
1871 lsp::ExecuteCommandParams {
1872 command: command.command.clone(),
1873 arguments: command.arguments.clone().unwrap_or_default(),
1874 ..Default::default()
1875 },
1876 )
1877 .await
1878 .into_response();
1879
1880 if execute_command_result.is_err() {
1881 zlog::error!(
1882 logger =>
1883 "Failed to execute command '{}' as part of {}",
1884 &command.command,
1885 describe_code_action(&action),
1886 );
1887 continue 'actions;
1888 }
1889
1890 let mut project_transaction_command =
1891 lsp_store.update(cx, |this, _| {
1892 this.as_local_mut()
1893 .unwrap()
1894 .last_workspace_edits_by_language_server
1895 .remove(&server.server_id())
1896 .unwrap_or_default()
1897 })?;
1898
1899 if let Some(transaction) =
1900 project_transaction_command.0.remove(&buffer.handle)
1901 {
1902 zlog::trace!(
1903 logger =>
1904 "Successfully captured {} edits that resulted from command {}",
1905 transaction.edit_ids.len(),
1906 &command.command,
1907 );
1908 let transaction_id_project_transaction = transaction.id;
1909 buffer.handle.update(cx, |buffer, _| {
1910 // it may have been removed from history if push_to_history was
1911 // false in deserialize_workspace_edit. If so push it so we
1912 // can merge it with the format transaction
1913 // and pop the combined transaction off the history stack
1914 // later if push_to_history is false
1915 if buffer.get_transaction(transaction.id).is_none() {
1916 buffer.push_transaction(transaction, Instant::now());
1917 }
1918 buffer.merge_transactions(
1919 transaction_id_project_transaction,
1920 formatting_transaction_id,
1921 );
1922 })?;
1923 }
1924
1925 if !project_transaction_command.0.is_empty() {
1926 let mut extra_buffers = String::new();
1927 for buffer in project_transaction_command.0.keys() {
1928 buffer
1929 .read_with(cx, |b, cx| {
1930 if let Some(path) = b.project_path(cx) {
1931 if !extra_buffers.is_empty() {
1932 extra_buffers.push_str(", ");
1933 }
1934 extra_buffers.push_str(path.path.as_unix_str());
1935 }
1936 })
1937 .ok();
1938 }
1939 zlog::warn!(
1940 logger =>
1941 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1942 &command.command,
1943 extra_buffers,
1944 );
1945 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1946 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1947 // add it so it's included, and merge it into the format transaction when its created later
1948 }
1949 }
1950 }
1951 }
1952 }
1953 }
1954
1955 Ok(())
1956 }
1957
1958 pub async fn format_ranges_via_lsp(
1959 this: &WeakEntity<LspStore>,
1960 buffer_handle: &Entity<Buffer>,
1961 ranges: &[Range<Anchor>],
1962 abs_path: &Path,
1963 language_server: &Arc<LanguageServer>,
1964 settings: &LanguageSettings,
1965 cx: &mut AsyncApp,
1966 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1967 let capabilities = &language_server.capabilities();
1968 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1969 if range_formatting_provider == Some(&OneOf::Left(false)) {
1970 anyhow::bail!(
1971 "{} language server does not support range formatting",
1972 language_server.name()
1973 );
1974 }
1975
1976 let uri = file_path_to_lsp_url(abs_path)?;
1977 let text_document = lsp::TextDocumentIdentifier::new(uri);
1978
1979 let lsp_edits = {
1980 let mut lsp_ranges = Vec::new();
1981 this.update(cx, |_this, cx| {
1982 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1983 // not have been sent to the language server. This seems like a fairly systemic
1984 // issue, though, the resolution probably is not specific to formatting.
1985 //
1986 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1987 // LSP.
1988 let snapshot = buffer_handle.read(cx).snapshot();
1989 for range in ranges {
1990 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1991 }
1992 anyhow::Ok(())
1993 })??;
1994
1995 let mut edits = None;
1996 for range in lsp_ranges {
1997 if let Some(mut edit) = language_server
1998 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1999 text_document: text_document.clone(),
2000 range,
2001 options: lsp_command::lsp_formatting_options(settings),
2002 work_done_progress_params: Default::default(),
2003 })
2004 .await
2005 .into_response()?
2006 {
2007 edits.get_or_insert_with(Vec::new).append(&mut edit);
2008 }
2009 }
2010 edits
2011 };
2012
2013 if let Some(lsp_edits) = lsp_edits {
2014 this.update(cx, |this, cx| {
2015 this.as_local_mut().unwrap().edits_from_lsp(
2016 buffer_handle,
2017 lsp_edits,
2018 language_server.server_id(),
2019 None,
2020 cx,
2021 )
2022 })?
2023 .await
2024 } else {
2025 Ok(Vec::with_capacity(0))
2026 }
2027 }
2028
2029 async fn format_via_lsp(
2030 this: &WeakEntity<LspStore>,
2031 buffer: &Entity<Buffer>,
2032 abs_path: &Path,
2033 language_server: &Arc<LanguageServer>,
2034 settings: &LanguageSettings,
2035 cx: &mut AsyncApp,
2036 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2037 let logger = zlog::scoped!("lsp_format");
2038 zlog::info!(logger => "Formatting via LSP");
2039
2040 let uri = file_path_to_lsp_url(abs_path)?;
2041 let text_document = lsp::TextDocumentIdentifier::new(uri);
2042 let capabilities = &language_server.capabilities();
2043
2044 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2045 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2046
2047 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2048 let _timer = zlog::time!(logger => "format-full");
2049 language_server
2050 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2051 text_document,
2052 options: lsp_command::lsp_formatting_options(settings),
2053 work_done_progress_params: Default::default(),
2054 })
2055 .await
2056 .into_response()?
2057 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2058 let _timer = zlog::time!(logger => "format-range");
2059 let buffer_start = lsp::Position::new(0, 0);
2060 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2061 language_server
2062 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2063 text_document: text_document.clone(),
2064 range: lsp::Range::new(buffer_start, buffer_end),
2065 options: lsp_command::lsp_formatting_options(settings),
2066 work_done_progress_params: Default::default(),
2067 })
2068 .await
2069 .into_response()?
2070 } else {
2071 None
2072 };
2073
2074 if let Some(lsp_edits) = lsp_edits {
2075 this.update(cx, |this, cx| {
2076 this.as_local_mut().unwrap().edits_from_lsp(
2077 buffer,
2078 lsp_edits,
2079 language_server.server_id(),
2080 None,
2081 cx,
2082 )
2083 })?
2084 .await
2085 } else {
2086 Ok(Vec::with_capacity(0))
2087 }
2088 }
2089
2090 async fn format_via_external_command(
2091 buffer: &FormattableBuffer,
2092 command: &str,
2093 arguments: Option<&[String]>,
2094 cx: &mut AsyncApp,
2095 ) -> Result<Option<Diff>> {
2096 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2097 let file = File::from_dyn(buffer.file())?;
2098 let worktree = file.worktree.read(cx);
2099 let mut worktree_path = worktree.abs_path().to_path_buf();
2100 if worktree.root_entry()?.is_file() {
2101 worktree_path.pop();
2102 }
2103 Some(worktree_path)
2104 })?;
2105
2106 let mut child = util::command::new_smol_command(command);
2107
2108 if let Some(buffer_env) = buffer.env.as_ref() {
2109 child.envs(buffer_env);
2110 }
2111
2112 if let Some(working_dir_path) = working_dir_path {
2113 child.current_dir(working_dir_path);
2114 }
2115
2116 if let Some(arguments) = arguments {
2117 child.args(arguments.iter().map(|arg| {
2118 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2119 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2120 } else {
2121 arg.replace("{buffer_path}", "Untitled")
2122 }
2123 }));
2124 }
2125
2126 let mut child = child
2127 .stdin(smol::process::Stdio::piped())
2128 .stdout(smol::process::Stdio::piped())
2129 .stderr(smol::process::Stdio::piped())
2130 .spawn()?;
2131
2132 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2133 let text = buffer
2134 .handle
2135 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2136 for chunk in text.chunks() {
2137 stdin.write_all(chunk.as_bytes()).await?;
2138 }
2139 stdin.flush().await?;
2140
2141 let output = child.output().await?;
2142 anyhow::ensure!(
2143 output.status.success(),
2144 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2145 output.status.code(),
2146 String::from_utf8_lossy(&output.stdout),
2147 String::from_utf8_lossy(&output.stderr),
2148 );
2149
2150 let stdout = String::from_utf8(output.stdout)?;
2151 Ok(Some(
2152 buffer
2153 .handle
2154 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2155 .await,
2156 ))
2157 }
2158
2159 async fn try_resolve_code_action(
2160 lang_server: &LanguageServer,
2161 action: &mut CodeAction,
2162 ) -> anyhow::Result<()> {
2163 match &mut action.lsp_action {
2164 LspAction::Action(lsp_action) => {
2165 if !action.resolved
2166 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2167 && lsp_action.data.is_some()
2168 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2169 {
2170 *lsp_action = Box::new(
2171 lang_server
2172 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2173 .await
2174 .into_response()?,
2175 );
2176 }
2177 }
2178 LspAction::CodeLens(lens) => {
2179 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2180 *lens = lang_server
2181 .request::<lsp::request::CodeLensResolve>(lens.clone())
2182 .await
2183 .into_response()?;
2184 }
2185 }
2186 LspAction::Command(_) => {}
2187 }
2188
2189 action.resolved = true;
2190 anyhow::Ok(())
2191 }
2192
2193 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2194 let buffer = buffer_handle.read(cx);
2195
2196 let file = buffer.file().cloned();
2197
2198 let Some(file) = File::from_dyn(file.as_ref()) else {
2199 return;
2200 };
2201 if !file.is_local() {
2202 return;
2203 }
2204 let path = ProjectPath::from_file(file, cx);
2205 let worktree_id = file.worktree_id(cx);
2206 let language = buffer.language().cloned();
2207
2208 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2209 for (server_id, diagnostics) in
2210 diagnostics.get(file.path()).cloned().unwrap_or_default()
2211 {
2212 self.update_buffer_diagnostics(
2213 buffer_handle,
2214 server_id,
2215 None,
2216 None,
2217 diagnostics,
2218 Vec::new(),
2219 cx,
2220 )
2221 .log_err();
2222 }
2223 }
2224 let Some(language) = language else {
2225 return;
2226 };
2227 let Some(snapshot) = self
2228 .worktree_store
2229 .read(cx)
2230 .worktree_for_id(worktree_id, cx)
2231 .map(|worktree| worktree.read(cx).snapshot())
2232 else {
2233 return;
2234 };
2235 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2236
2237 for server_id in
2238 self.lsp_tree
2239 .get(path, language.name(), language.manifest(), &delegate, cx)
2240 {
2241 let server = self
2242 .language_servers
2243 .get(&server_id)
2244 .and_then(|server_state| {
2245 if let LanguageServerState::Running { server, .. } = server_state {
2246 Some(server.clone())
2247 } else {
2248 None
2249 }
2250 });
2251 let server = match server {
2252 Some(server) => server,
2253 None => continue,
2254 };
2255
2256 buffer_handle.update(cx, |buffer, cx| {
2257 buffer.set_completion_triggers(
2258 server.server_id(),
2259 server
2260 .capabilities()
2261 .completion_provider
2262 .as_ref()
2263 .and_then(|provider| {
2264 provider
2265 .trigger_characters
2266 .as_ref()
2267 .map(|characters| characters.iter().cloned().collect())
2268 })
2269 .unwrap_or_default(),
2270 cx,
2271 );
2272 });
2273 }
2274 }
2275
2276 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2277 buffer.update(cx, |buffer, cx| {
2278 let Some(language) = buffer.language() else {
2279 return;
2280 };
2281 let path = ProjectPath {
2282 worktree_id: old_file.worktree_id(cx),
2283 path: old_file.path.clone(),
2284 };
2285 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2286 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2287 buffer.set_completion_triggers(server_id, Default::default(), cx);
2288 }
2289 });
2290 }
2291
2292 fn update_buffer_diagnostics(
2293 &mut self,
2294 buffer: &Entity<Buffer>,
2295 server_id: LanguageServerId,
2296 result_id: Option<String>,
2297 version: Option<i32>,
2298 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2299 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2300 cx: &mut Context<LspStore>,
2301 ) -> Result<()> {
2302 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2303 Ordering::Equal
2304 .then_with(|| b.is_primary.cmp(&a.is_primary))
2305 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2306 .then_with(|| a.severity.cmp(&b.severity))
2307 .then_with(|| a.message.cmp(&b.message))
2308 }
2309
2310 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2311 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2312 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2313
2314 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2315 Ordering::Equal
2316 .then_with(|| a.range.start.cmp(&b.range.start))
2317 .then_with(|| b.range.end.cmp(&a.range.end))
2318 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2319 });
2320
2321 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2322
2323 let edits_since_save = std::cell::LazyCell::new(|| {
2324 let saved_version = buffer.read(cx).saved_version();
2325 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2326 });
2327
2328 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2329
2330 for (new_diagnostic, entry) in diagnostics {
2331 let start;
2332 let end;
2333 if new_diagnostic && entry.diagnostic.is_disk_based {
2334 // Some diagnostics are based on files on disk instead of buffers'
2335 // current contents. Adjust these diagnostics' ranges to reflect
2336 // any unsaved edits.
2337 // Do not alter the reused ones though, as their coordinates were stored as anchors
2338 // and were properly adjusted on reuse.
2339 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2340 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2341 } else {
2342 start = entry.range.start;
2343 end = entry.range.end;
2344 }
2345
2346 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2347 ..snapshot.clip_point_utf16(end, Bias::Right);
2348
2349 // Expand empty ranges by one codepoint
2350 if range.start == range.end {
2351 // This will be go to the next boundary when being clipped
2352 range.end.column += 1;
2353 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2354 if range.start == range.end && range.end.column > 0 {
2355 range.start.column -= 1;
2356 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2357 }
2358 }
2359
2360 sanitized_diagnostics.push(DiagnosticEntry {
2361 range,
2362 diagnostic: entry.diagnostic,
2363 });
2364 }
2365 drop(edits_since_save);
2366
2367 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2368 buffer.update(cx, |buffer, cx| {
2369 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2370 self.buffer_pull_diagnostics_result_ids
2371 .entry(server_id)
2372 .or_default()
2373 .insert(abs_path, result_id);
2374 }
2375
2376 buffer.update_diagnostics(server_id, set, cx)
2377 });
2378
2379 Ok(())
2380 }
2381
2382 fn register_language_server_for_invisible_worktree(
2383 &mut self,
2384 worktree: &Entity<Worktree>,
2385 language_server_id: LanguageServerId,
2386 cx: &mut App,
2387 ) {
2388 let worktree = worktree.read(cx);
2389 let worktree_id = worktree.id();
2390 debug_assert!(!worktree.is_visible());
2391 let Some(mut origin_seed) = self
2392 .language_server_ids
2393 .iter()
2394 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2395 else {
2396 return;
2397 };
2398 origin_seed.worktree_id = worktree_id;
2399 self.language_server_ids
2400 .entry(origin_seed)
2401 .or_insert_with(|| UnifiedLanguageServer {
2402 id: language_server_id,
2403 project_roots: Default::default(),
2404 });
2405 }
2406
2407 fn register_buffer_with_language_servers(
2408 &mut self,
2409 buffer_handle: &Entity<Buffer>,
2410 only_register_servers: HashSet<LanguageServerSelector>,
2411 cx: &mut Context<LspStore>,
2412 ) {
2413 let buffer = buffer_handle.read(cx);
2414 let buffer_id = buffer.remote_id();
2415
2416 let Some(file) = File::from_dyn(buffer.file()) else {
2417 return;
2418 };
2419 if !file.is_local() {
2420 return;
2421 }
2422
2423 let abs_path = file.abs_path(cx);
2424 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2425 return;
2426 };
2427 let initial_snapshot = buffer.text_snapshot();
2428 let worktree_id = file.worktree_id(cx);
2429
2430 let Some(language) = buffer.language().cloned() else {
2431 return;
2432 };
2433 let path: Arc<RelPath> = file
2434 .path()
2435 .parent()
2436 .map(Arc::from)
2437 .unwrap_or_else(|| file.path().clone());
2438 let Some(worktree) = self
2439 .worktree_store
2440 .read(cx)
2441 .worktree_for_id(worktree_id, cx)
2442 else {
2443 return;
2444 };
2445 let language_name = language.name();
2446 let (reused, delegate, servers) = self
2447 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2448 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2449 .unwrap_or_else(|| {
2450 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2451 let delegate: Arc<dyn ManifestDelegate> =
2452 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2453
2454 let servers = self
2455 .lsp_tree
2456 .walk(
2457 ProjectPath { worktree_id, path },
2458 language.name(),
2459 language.manifest(),
2460 &delegate,
2461 cx,
2462 )
2463 .collect::<Vec<_>>();
2464 (false, lsp_delegate, servers)
2465 });
2466 let servers_and_adapters = servers
2467 .into_iter()
2468 .filter_map(|server_node| {
2469 if reused && server_node.server_id().is_none() {
2470 return None;
2471 }
2472 if !only_register_servers.is_empty() {
2473 if let Some(server_id) = server_node.server_id()
2474 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2475 {
2476 return None;
2477 }
2478 if let Some(name) = server_node.name()
2479 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2480 {
2481 return None;
2482 }
2483 }
2484
2485 let server_id = server_node.server_id_or_init(|disposition| {
2486 let path = &disposition.path;
2487
2488 {
2489 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2490
2491 let server_id = self.get_or_insert_language_server(
2492 &worktree,
2493 delegate.clone(),
2494 disposition,
2495 &language_name,
2496 cx,
2497 );
2498
2499 if let Some(state) = self.language_servers.get(&server_id)
2500 && let Ok(uri) = uri
2501 {
2502 state.add_workspace_folder(uri);
2503 };
2504 server_id
2505 }
2506 })?;
2507 let server_state = self.language_servers.get(&server_id)?;
2508 if let LanguageServerState::Running {
2509 server, adapter, ..
2510 } = server_state
2511 {
2512 Some((server.clone(), adapter.clone()))
2513 } else {
2514 None
2515 }
2516 })
2517 .collect::<Vec<_>>();
2518 for (server, adapter) in servers_and_adapters {
2519 buffer_handle.update(cx, |buffer, cx| {
2520 buffer.set_completion_triggers(
2521 server.server_id(),
2522 server
2523 .capabilities()
2524 .completion_provider
2525 .as_ref()
2526 .and_then(|provider| {
2527 provider
2528 .trigger_characters
2529 .as_ref()
2530 .map(|characters| characters.iter().cloned().collect())
2531 })
2532 .unwrap_or_default(),
2533 cx,
2534 );
2535 });
2536
2537 let snapshot = LspBufferSnapshot {
2538 version: 0,
2539 snapshot: initial_snapshot.clone(),
2540 };
2541
2542 let mut registered = false;
2543 self.buffer_snapshots
2544 .entry(buffer_id)
2545 .or_default()
2546 .entry(server.server_id())
2547 .or_insert_with(|| {
2548 registered = true;
2549 server.register_buffer(
2550 uri.clone(),
2551 adapter.language_id(&language.name()),
2552 0,
2553 initial_snapshot.text(),
2554 );
2555
2556 vec![snapshot]
2557 });
2558
2559 self.buffers_opened_in_servers
2560 .entry(buffer_id)
2561 .or_default()
2562 .insert(server.server_id());
2563 if registered {
2564 cx.emit(LspStoreEvent::LanguageServerUpdate {
2565 language_server_id: server.server_id(),
2566 name: None,
2567 message: proto::update_language_server::Variant::RegisteredForBuffer(
2568 proto::RegisteredForBuffer {
2569 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2570 buffer_id: buffer_id.to_proto(),
2571 },
2572 ),
2573 });
2574 }
2575 }
2576 }
2577
2578 fn reuse_existing_language_server<'lang_name>(
2579 &self,
2580 server_tree: &LanguageServerTree,
2581 worktree: &Entity<Worktree>,
2582 language_name: &'lang_name LanguageName,
2583 cx: &mut App,
2584 ) -> Option<(
2585 Arc<LocalLspAdapterDelegate>,
2586 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2587 )> {
2588 if worktree.read(cx).is_visible() {
2589 return None;
2590 }
2591
2592 let worktree_store = self.worktree_store.read(cx);
2593 let servers = server_tree
2594 .instances
2595 .iter()
2596 .filter(|(worktree_id, _)| {
2597 worktree_store
2598 .worktree_for_id(**worktree_id, cx)
2599 .is_some_and(|worktree| worktree.read(cx).is_visible())
2600 })
2601 .flat_map(|(worktree_id, servers)| {
2602 servers
2603 .roots
2604 .iter()
2605 .flat_map(|(_, language_servers)| language_servers)
2606 .map(move |(_, (server_node, server_languages))| {
2607 (worktree_id, server_node, server_languages)
2608 })
2609 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2610 .map(|(worktree_id, server_node, _)| {
2611 (
2612 *worktree_id,
2613 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2614 )
2615 })
2616 })
2617 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2618 acc.entry(worktree_id)
2619 .or_insert_with(Vec::new)
2620 .push(server_node);
2621 acc
2622 })
2623 .into_values()
2624 .max_by_key(|servers| servers.len())?;
2625
2626 let worktree_id = worktree.read(cx).id();
2627 let apply = move |tree: &mut LanguageServerTree| {
2628 for server_node in &servers {
2629 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2630 }
2631 servers
2632 };
2633
2634 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2635 Some((delegate, apply))
2636 }
2637
2638 pub(crate) fn unregister_old_buffer_from_language_servers(
2639 &mut self,
2640 buffer: &Entity<Buffer>,
2641 old_file: &File,
2642 cx: &mut App,
2643 ) {
2644 let old_path = match old_file.as_local() {
2645 Some(local) => local.abs_path(cx),
2646 None => return,
2647 };
2648
2649 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2650 debug_panic!("{old_path:?} is not parseable as an URI");
2651 return;
2652 };
2653 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2654 }
2655
2656 pub(crate) fn unregister_buffer_from_language_servers(
2657 &mut self,
2658 buffer: &Entity<Buffer>,
2659 file_url: &lsp::Uri,
2660 cx: &mut App,
2661 ) {
2662 buffer.update(cx, |buffer, cx| {
2663 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2664
2665 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2666 language_server.unregister_buffer(file_url.clone());
2667 }
2668 });
2669 }
2670
2671 fn buffer_snapshot_for_lsp_version(
2672 &mut self,
2673 buffer: &Entity<Buffer>,
2674 server_id: LanguageServerId,
2675 version: Option<i32>,
2676 cx: &App,
2677 ) -> Result<TextBufferSnapshot> {
2678 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2679
2680 if let Some(version) = version {
2681 let buffer_id = buffer.read(cx).remote_id();
2682 let snapshots = if let Some(snapshots) = self
2683 .buffer_snapshots
2684 .get_mut(&buffer_id)
2685 .and_then(|m| m.get_mut(&server_id))
2686 {
2687 snapshots
2688 } else if version == 0 {
2689 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2690 // We detect this case and treat it as if the version was `None`.
2691 return Ok(buffer.read(cx).text_snapshot());
2692 } else {
2693 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2694 };
2695
2696 let found_snapshot = snapshots
2697 .binary_search_by_key(&version, |e| e.version)
2698 .map(|ix| snapshots[ix].snapshot.clone())
2699 .map_err(|_| {
2700 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2701 })?;
2702
2703 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2704 Ok(found_snapshot)
2705 } else {
2706 Ok((buffer.read(cx)).text_snapshot())
2707 }
2708 }
2709
2710 async fn get_server_code_actions_from_action_kinds(
2711 lsp_store: &WeakEntity<LspStore>,
2712 language_server_id: LanguageServerId,
2713 code_action_kinds: Vec<lsp::CodeActionKind>,
2714 buffer: &Entity<Buffer>,
2715 cx: &mut AsyncApp,
2716 ) -> Result<Vec<CodeAction>> {
2717 let actions = lsp_store
2718 .update(cx, move |this, cx| {
2719 let request = GetCodeActions {
2720 range: text::Anchor::MIN..text::Anchor::MAX,
2721 kinds: Some(code_action_kinds),
2722 };
2723 let server = LanguageServerToQuery::Other(language_server_id);
2724 this.request_lsp(buffer.clone(), server, request, cx)
2725 })?
2726 .await?;
2727 Ok(actions)
2728 }
2729
2730 pub async fn execute_code_actions_on_server(
2731 lsp_store: &WeakEntity<LspStore>,
2732 language_server: &Arc<LanguageServer>,
2733
2734 actions: Vec<CodeAction>,
2735 push_to_history: bool,
2736 project_transaction: &mut ProjectTransaction,
2737 cx: &mut AsyncApp,
2738 ) -> anyhow::Result<()> {
2739 for mut action in actions {
2740 Self::try_resolve_code_action(language_server, &mut action)
2741 .await
2742 .context("resolving a formatting code action")?;
2743
2744 if let Some(edit) = action.lsp_action.edit() {
2745 if edit.changes.is_none() && edit.document_changes.is_none() {
2746 continue;
2747 }
2748
2749 let new = Self::deserialize_workspace_edit(
2750 lsp_store.upgrade().context("project dropped")?,
2751 edit.clone(),
2752 push_to_history,
2753 language_server.clone(),
2754 cx,
2755 )
2756 .await?;
2757 project_transaction.0.extend(new.0);
2758 }
2759
2760 if let Some(command) = action.lsp_action.command() {
2761 let server_capabilities = language_server.capabilities();
2762 let available_commands = server_capabilities
2763 .execute_command_provider
2764 .as_ref()
2765 .map(|options| options.commands.as_slice())
2766 .unwrap_or_default();
2767 if available_commands.contains(&command.command) {
2768 lsp_store.update(cx, |lsp_store, _| {
2769 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2770 mode.last_workspace_edits_by_language_server
2771 .remove(&language_server.server_id());
2772 }
2773 })?;
2774
2775 language_server
2776 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2777 command: command.command.clone(),
2778 arguments: command.arguments.clone().unwrap_or_default(),
2779 ..Default::default()
2780 })
2781 .await
2782 .into_response()
2783 .context("execute command")?;
2784
2785 lsp_store.update(cx, |this, _| {
2786 if let LspStoreMode::Local(mode) = &mut this.mode {
2787 project_transaction.0.extend(
2788 mode.last_workspace_edits_by_language_server
2789 .remove(&language_server.server_id())
2790 .unwrap_or_default()
2791 .0,
2792 )
2793 }
2794 })?;
2795 } else {
2796 log::warn!(
2797 "Cannot execute a command {} not listed in the language server capabilities",
2798 command.command
2799 )
2800 }
2801 }
2802 }
2803 Ok(())
2804 }
2805
2806 pub async fn deserialize_text_edits(
2807 this: Entity<LspStore>,
2808 buffer_to_edit: Entity<Buffer>,
2809 edits: Vec<lsp::TextEdit>,
2810 push_to_history: bool,
2811 _: Arc<CachedLspAdapter>,
2812 language_server: Arc<LanguageServer>,
2813 cx: &mut AsyncApp,
2814 ) -> Result<Option<Transaction>> {
2815 let edits = this
2816 .update(cx, |this, cx| {
2817 this.as_local_mut().unwrap().edits_from_lsp(
2818 &buffer_to_edit,
2819 edits,
2820 language_server.server_id(),
2821 None,
2822 cx,
2823 )
2824 })?
2825 .await?;
2826
2827 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2828 buffer.finalize_last_transaction();
2829 buffer.start_transaction();
2830 for (range, text) in edits {
2831 buffer.edit([(range, text)], None, cx);
2832 }
2833
2834 if buffer.end_transaction(cx).is_some() {
2835 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2836 if !push_to_history {
2837 buffer.forget_transaction(transaction.id);
2838 }
2839 Some(transaction)
2840 } else {
2841 None
2842 }
2843 })?;
2844
2845 Ok(transaction)
2846 }
2847
2848 #[allow(clippy::type_complexity)]
2849 pub(crate) fn edits_from_lsp(
2850 &mut self,
2851 buffer: &Entity<Buffer>,
2852 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2853 server_id: LanguageServerId,
2854 version: Option<i32>,
2855 cx: &mut Context<LspStore>,
2856 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2857 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2858 cx.background_spawn(async move {
2859 let snapshot = snapshot?;
2860 let mut lsp_edits = lsp_edits
2861 .into_iter()
2862 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2863 .collect::<Vec<_>>();
2864
2865 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2866
2867 let mut lsp_edits = lsp_edits.into_iter().peekable();
2868 let mut edits = Vec::new();
2869 while let Some((range, mut new_text)) = lsp_edits.next() {
2870 // Clip invalid ranges provided by the language server.
2871 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2872 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2873
2874 // Combine any LSP edits that are adjacent.
2875 //
2876 // Also, combine LSP edits that are separated from each other by only
2877 // a newline. This is important because for some code actions,
2878 // Rust-analyzer rewrites the entire buffer via a series of edits that
2879 // are separated by unchanged newline characters.
2880 //
2881 // In order for the diffing logic below to work properly, any edits that
2882 // cancel each other out must be combined into one.
2883 while let Some((next_range, next_text)) = lsp_edits.peek() {
2884 if next_range.start.0 > range.end {
2885 if next_range.start.0.row > range.end.row + 1
2886 || next_range.start.0.column > 0
2887 || snapshot.clip_point_utf16(
2888 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2889 Bias::Left,
2890 ) > range.end
2891 {
2892 break;
2893 }
2894 new_text.push('\n');
2895 }
2896 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2897 new_text.push_str(next_text);
2898 lsp_edits.next();
2899 }
2900
2901 // For multiline edits, perform a diff of the old and new text so that
2902 // we can identify the changes more precisely, preserving the locations
2903 // of any anchors positioned in the unchanged regions.
2904 if range.end.row > range.start.row {
2905 let offset = range.start.to_offset(&snapshot);
2906 let old_text = snapshot.text_for_range(range).collect::<String>();
2907 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2908 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2909 (
2910 snapshot.anchor_after(offset + range.start)
2911 ..snapshot.anchor_before(offset + range.end),
2912 replacement,
2913 )
2914 }));
2915 } else if range.end == range.start {
2916 let anchor = snapshot.anchor_after(range.start);
2917 edits.push((anchor..anchor, new_text.into()));
2918 } else {
2919 let edit_start = snapshot.anchor_after(range.start);
2920 let edit_end = snapshot.anchor_before(range.end);
2921 edits.push((edit_start..edit_end, new_text.into()));
2922 }
2923 }
2924
2925 Ok(edits)
2926 })
2927 }
2928
2929 pub(crate) async fn deserialize_workspace_edit(
2930 this: Entity<LspStore>,
2931 edit: lsp::WorkspaceEdit,
2932 push_to_history: bool,
2933 language_server: Arc<LanguageServer>,
2934 cx: &mut AsyncApp,
2935 ) -> Result<ProjectTransaction> {
2936 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2937
2938 let mut operations = Vec::new();
2939 if let Some(document_changes) = edit.document_changes {
2940 match document_changes {
2941 lsp::DocumentChanges::Edits(edits) => {
2942 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2943 }
2944 lsp::DocumentChanges::Operations(ops) => operations = ops,
2945 }
2946 } else if let Some(changes) = edit.changes {
2947 operations.extend(changes.into_iter().map(|(uri, edits)| {
2948 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2949 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2950 uri,
2951 version: None,
2952 },
2953 edits: edits.into_iter().map(Edit::Plain).collect(),
2954 })
2955 }));
2956 }
2957
2958 let mut project_transaction = ProjectTransaction::default();
2959 for operation in operations {
2960 match operation {
2961 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2962 let abs_path = op
2963 .uri
2964 .to_file_path()
2965 .map_err(|()| anyhow!("can't convert URI to path"))?;
2966
2967 if let Some(parent_path) = abs_path.parent() {
2968 fs.create_dir(parent_path).await?;
2969 }
2970 if abs_path.ends_with("/") {
2971 fs.create_dir(&abs_path).await?;
2972 } else {
2973 fs.create_file(
2974 &abs_path,
2975 op.options
2976 .map(|options| fs::CreateOptions {
2977 overwrite: options.overwrite.unwrap_or(false),
2978 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2979 })
2980 .unwrap_or_default(),
2981 )
2982 .await?;
2983 }
2984 }
2985
2986 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2987 let source_abs_path = op
2988 .old_uri
2989 .to_file_path()
2990 .map_err(|()| anyhow!("can't convert URI to path"))?;
2991 let target_abs_path = op
2992 .new_uri
2993 .to_file_path()
2994 .map_err(|()| anyhow!("can't convert URI to path"))?;
2995 fs.rename(
2996 &source_abs_path,
2997 &target_abs_path,
2998 op.options
2999 .map(|options| fs::RenameOptions {
3000 overwrite: options.overwrite.unwrap_or(false),
3001 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3002 })
3003 .unwrap_or_default(),
3004 )
3005 .await?;
3006 }
3007
3008 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3009 let abs_path = op
3010 .uri
3011 .to_file_path()
3012 .map_err(|()| anyhow!("can't convert URI to path"))?;
3013 let options = op
3014 .options
3015 .map(|options| fs::RemoveOptions {
3016 recursive: options.recursive.unwrap_or(false),
3017 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3018 })
3019 .unwrap_or_default();
3020 if abs_path.ends_with("/") {
3021 fs.remove_dir(&abs_path, options).await?;
3022 } else {
3023 fs.remove_file(&abs_path, options).await?;
3024 }
3025 }
3026
3027 lsp::DocumentChangeOperation::Edit(op) => {
3028 let buffer_to_edit = this
3029 .update(cx, |this, cx| {
3030 this.open_local_buffer_via_lsp(
3031 op.text_document.uri.clone(),
3032 language_server.server_id(),
3033 cx,
3034 )
3035 })?
3036 .await?;
3037
3038 let edits = this
3039 .update(cx, |this, cx| {
3040 let path = buffer_to_edit.read(cx).project_path(cx);
3041 let active_entry = this.active_entry;
3042 let is_active_entry = path.is_some_and(|project_path| {
3043 this.worktree_store
3044 .read(cx)
3045 .entry_for_path(&project_path, cx)
3046 .is_some_and(|entry| Some(entry.id) == active_entry)
3047 });
3048 let local = this.as_local_mut().unwrap();
3049
3050 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3051 for edit in op.edits {
3052 match edit {
3053 Edit::Plain(edit) => {
3054 if !edits.contains(&edit) {
3055 edits.push(edit)
3056 }
3057 }
3058 Edit::Annotated(edit) => {
3059 if !edits.contains(&edit.text_edit) {
3060 edits.push(edit.text_edit)
3061 }
3062 }
3063 Edit::Snippet(edit) => {
3064 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3065 else {
3066 continue;
3067 };
3068
3069 if is_active_entry {
3070 snippet_edits.push((edit.range, snippet));
3071 } else {
3072 // Since this buffer is not focused, apply a normal edit.
3073 let new_edit = TextEdit {
3074 range: edit.range,
3075 new_text: snippet.text,
3076 };
3077 if !edits.contains(&new_edit) {
3078 edits.push(new_edit);
3079 }
3080 }
3081 }
3082 }
3083 }
3084 if !snippet_edits.is_empty() {
3085 let buffer_id = buffer_to_edit.read(cx).remote_id();
3086 let version = if let Some(buffer_version) = op.text_document.version
3087 {
3088 local
3089 .buffer_snapshot_for_lsp_version(
3090 &buffer_to_edit,
3091 language_server.server_id(),
3092 Some(buffer_version),
3093 cx,
3094 )
3095 .ok()
3096 .map(|snapshot| snapshot.version)
3097 } else {
3098 Some(buffer_to_edit.read(cx).saved_version().clone())
3099 };
3100
3101 let most_recent_edit =
3102 version.and_then(|version| version.most_recent());
3103 // Check if the edit that triggered that edit has been made by this participant.
3104
3105 if let Some(most_recent_edit) = most_recent_edit {
3106 cx.emit(LspStoreEvent::SnippetEdit {
3107 buffer_id,
3108 edits: snippet_edits,
3109 most_recent_edit,
3110 });
3111 }
3112 }
3113
3114 local.edits_from_lsp(
3115 &buffer_to_edit,
3116 edits,
3117 language_server.server_id(),
3118 op.text_document.version,
3119 cx,
3120 )
3121 })?
3122 .await?;
3123
3124 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3125 buffer.finalize_last_transaction();
3126 buffer.start_transaction();
3127 for (range, text) in edits {
3128 buffer.edit([(range, text)], None, cx);
3129 }
3130
3131 buffer.end_transaction(cx).and_then(|transaction_id| {
3132 if push_to_history {
3133 buffer.finalize_last_transaction();
3134 buffer.get_transaction(transaction_id).cloned()
3135 } else {
3136 buffer.forget_transaction(transaction_id)
3137 }
3138 })
3139 })?;
3140 if let Some(transaction) = transaction {
3141 project_transaction.0.insert(buffer_to_edit, transaction);
3142 }
3143 }
3144 }
3145 }
3146
3147 Ok(project_transaction)
3148 }
3149
3150 async fn on_lsp_workspace_edit(
3151 this: WeakEntity<LspStore>,
3152 params: lsp::ApplyWorkspaceEditParams,
3153 server_id: LanguageServerId,
3154 cx: &mut AsyncApp,
3155 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3156 let this = this.upgrade().context("project project closed")?;
3157 let language_server = this
3158 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3159 .context("language server not found")?;
3160 let transaction = Self::deserialize_workspace_edit(
3161 this.clone(),
3162 params.edit,
3163 true,
3164 language_server.clone(),
3165 cx,
3166 )
3167 .await
3168 .log_err();
3169 this.update(cx, |this, _| {
3170 if let Some(transaction) = transaction {
3171 this.as_local_mut()
3172 .unwrap()
3173 .last_workspace_edits_by_language_server
3174 .insert(server_id, transaction);
3175 }
3176 })?;
3177 Ok(lsp::ApplyWorkspaceEditResponse {
3178 applied: true,
3179 failed_change: None,
3180 failure_reason: None,
3181 })
3182 }
3183
3184 fn remove_worktree(
3185 &mut self,
3186 id_to_remove: WorktreeId,
3187 cx: &mut Context<LspStore>,
3188 ) -> Vec<LanguageServerId> {
3189 self.diagnostics.remove(&id_to_remove);
3190 self.prettier_store.update(cx, |prettier_store, cx| {
3191 prettier_store.remove_worktree(id_to_remove, cx);
3192 });
3193
3194 let mut servers_to_remove = BTreeSet::default();
3195 let mut servers_to_preserve = HashSet::default();
3196 for (seed, state) in &self.language_server_ids {
3197 if seed.worktree_id == id_to_remove {
3198 servers_to_remove.insert(state.id);
3199 } else {
3200 servers_to_preserve.insert(state.id);
3201 }
3202 }
3203 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3204 self.language_server_ids
3205 .retain(|_, state| !servers_to_remove.contains(&state.id));
3206 for server_id_to_remove in &servers_to_remove {
3207 self.language_server_watched_paths
3208 .remove(server_id_to_remove);
3209 self.language_server_paths_watched_for_rename
3210 .remove(server_id_to_remove);
3211 self.last_workspace_edits_by_language_server
3212 .remove(server_id_to_remove);
3213 self.language_servers.remove(server_id_to_remove);
3214 self.buffer_pull_diagnostics_result_ids
3215 .remove(server_id_to_remove);
3216 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3217 buffer_servers.remove(server_id_to_remove);
3218 }
3219 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3220 }
3221 servers_to_remove.into_iter().collect()
3222 }
3223
3224 fn rebuild_watched_paths_inner<'a>(
3225 &'a self,
3226 language_server_id: LanguageServerId,
3227 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3228 cx: &mut Context<LspStore>,
3229 ) -> LanguageServerWatchedPathsBuilder {
3230 let worktrees = self
3231 .worktree_store
3232 .read(cx)
3233 .worktrees()
3234 .filter_map(|worktree| {
3235 self.language_servers_for_worktree(worktree.read(cx).id())
3236 .find(|server| server.server_id() == language_server_id)
3237 .map(|_| worktree)
3238 })
3239 .collect::<Vec<_>>();
3240
3241 let mut worktree_globs = HashMap::default();
3242 let mut abs_globs = HashMap::default();
3243 log::trace!(
3244 "Processing new watcher paths for language server with id {}",
3245 language_server_id
3246 );
3247
3248 for watcher in watchers {
3249 if let Some((worktree, literal_prefix, pattern)) =
3250 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3251 {
3252 worktree.update(cx, |worktree, _| {
3253 if let Some((tree, glob)) =
3254 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3255 {
3256 tree.add_path_prefix_to_scan(literal_prefix);
3257 worktree_globs
3258 .entry(tree.id())
3259 .or_insert_with(GlobSetBuilder::new)
3260 .add(glob);
3261 }
3262 });
3263 } else {
3264 let (path, pattern) = match &watcher.glob_pattern {
3265 lsp::GlobPattern::String(s) => {
3266 let watcher_path = SanitizedPath::new(s);
3267 let path = glob_literal_prefix(watcher_path.as_path());
3268 let pattern = watcher_path
3269 .as_path()
3270 .strip_prefix(&path)
3271 .map(|p| p.to_string_lossy().into_owned())
3272 .unwrap_or_else(|e| {
3273 debug_panic!(
3274 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3275 s,
3276 path.display(),
3277 e
3278 );
3279 watcher_path.as_path().to_string_lossy().into_owned()
3280 });
3281 (path, pattern)
3282 }
3283 lsp::GlobPattern::Relative(rp) => {
3284 let Ok(mut base_uri) = match &rp.base_uri {
3285 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3286 lsp::OneOf::Right(base_uri) => base_uri,
3287 }
3288 .to_file_path() else {
3289 continue;
3290 };
3291
3292 let path = glob_literal_prefix(Path::new(&rp.pattern));
3293 let pattern = Path::new(&rp.pattern)
3294 .strip_prefix(&path)
3295 .map(|p| p.to_string_lossy().into_owned())
3296 .unwrap_or_else(|e| {
3297 debug_panic!(
3298 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3299 rp.pattern,
3300 path.display(),
3301 e
3302 );
3303 rp.pattern.clone()
3304 });
3305 base_uri.push(path);
3306 (base_uri, pattern)
3307 }
3308 };
3309
3310 if let Some(glob) = Glob::new(&pattern).log_err() {
3311 if !path
3312 .components()
3313 .any(|c| matches!(c, path::Component::Normal(_)))
3314 {
3315 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3316 // rather than adding a new watcher for `/`.
3317 for worktree in &worktrees {
3318 worktree_globs
3319 .entry(worktree.read(cx).id())
3320 .or_insert_with(GlobSetBuilder::new)
3321 .add(glob.clone());
3322 }
3323 } else {
3324 abs_globs
3325 .entry(path.into())
3326 .or_insert_with(GlobSetBuilder::new)
3327 .add(glob);
3328 }
3329 }
3330 }
3331 }
3332
3333 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3334 for (worktree_id, builder) in worktree_globs {
3335 if let Ok(globset) = builder.build() {
3336 watch_builder.watch_worktree(worktree_id, globset);
3337 }
3338 }
3339 for (abs_path, builder) in abs_globs {
3340 if let Ok(globset) = builder.build() {
3341 watch_builder.watch_abs_path(abs_path, globset);
3342 }
3343 }
3344 watch_builder
3345 }
3346
3347 fn worktree_and_path_for_file_watcher(
3348 worktrees: &[Entity<Worktree>],
3349 watcher: &FileSystemWatcher,
3350 cx: &App,
3351 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3352 worktrees.iter().find_map(|worktree| {
3353 let tree = worktree.read(cx);
3354 let worktree_root_path = tree.abs_path();
3355 let path_style = tree.path_style();
3356 match &watcher.glob_pattern {
3357 lsp::GlobPattern::String(s) => {
3358 let watcher_path = SanitizedPath::new(s);
3359 let relative = watcher_path
3360 .as_path()
3361 .strip_prefix(&worktree_root_path)
3362 .ok()?;
3363 let literal_prefix = glob_literal_prefix(relative);
3364 Some((
3365 worktree.clone(),
3366 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3367 relative.to_string_lossy().into_owned(),
3368 ))
3369 }
3370 lsp::GlobPattern::Relative(rp) => {
3371 let base_uri = match &rp.base_uri {
3372 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3373 lsp::OneOf::Right(base_uri) => base_uri,
3374 }
3375 .to_file_path()
3376 .ok()?;
3377 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3378 let mut literal_prefix = relative.to_owned();
3379 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3380 Some((
3381 worktree.clone(),
3382 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3383 rp.pattern.clone(),
3384 ))
3385 }
3386 }
3387 })
3388 }
3389
3390 fn rebuild_watched_paths(
3391 &mut self,
3392 language_server_id: LanguageServerId,
3393 cx: &mut Context<LspStore>,
3394 ) {
3395 let Some(registrations) = self
3396 .language_server_dynamic_registrations
3397 .get(&language_server_id)
3398 else {
3399 return;
3400 };
3401
3402 let watch_builder = self.rebuild_watched_paths_inner(
3403 language_server_id,
3404 registrations.did_change_watched_files.values().flatten(),
3405 cx,
3406 );
3407 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3408 self.language_server_watched_paths
3409 .insert(language_server_id, watcher);
3410
3411 cx.notify();
3412 }
3413
3414 fn on_lsp_did_change_watched_files(
3415 &mut self,
3416 language_server_id: LanguageServerId,
3417 registration_id: &str,
3418 params: DidChangeWatchedFilesRegistrationOptions,
3419 cx: &mut Context<LspStore>,
3420 ) {
3421 let registrations = self
3422 .language_server_dynamic_registrations
3423 .entry(language_server_id)
3424 .or_default();
3425
3426 registrations
3427 .did_change_watched_files
3428 .insert(registration_id.to_string(), params.watchers);
3429
3430 self.rebuild_watched_paths(language_server_id, cx);
3431 }
3432
3433 fn on_lsp_unregister_did_change_watched_files(
3434 &mut self,
3435 language_server_id: LanguageServerId,
3436 registration_id: &str,
3437 cx: &mut Context<LspStore>,
3438 ) {
3439 let registrations = self
3440 .language_server_dynamic_registrations
3441 .entry(language_server_id)
3442 .or_default();
3443
3444 if registrations
3445 .did_change_watched_files
3446 .remove(registration_id)
3447 .is_some()
3448 {
3449 log::info!(
3450 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3451 language_server_id,
3452 registration_id
3453 );
3454 } else {
3455 log::warn!(
3456 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3457 language_server_id,
3458 registration_id
3459 );
3460 }
3461
3462 self.rebuild_watched_paths(language_server_id, cx);
3463 }
3464
3465 async fn initialization_options_for_adapter(
3466 adapter: Arc<dyn LspAdapter>,
3467 delegate: &Arc<dyn LspAdapterDelegate>,
3468 ) -> Result<Option<serde_json::Value>> {
3469 let Some(mut initialization_config) =
3470 adapter.clone().initialization_options(delegate).await?
3471 else {
3472 return Ok(None);
3473 };
3474
3475 for other_adapter in delegate.registered_lsp_adapters() {
3476 if other_adapter.name() == adapter.name() {
3477 continue;
3478 }
3479 if let Ok(Some(target_config)) = other_adapter
3480 .clone()
3481 .additional_initialization_options(adapter.name(), delegate)
3482 .await
3483 {
3484 merge_json_value_into(target_config.clone(), &mut initialization_config);
3485 }
3486 }
3487
3488 Ok(Some(initialization_config))
3489 }
3490
3491 async fn workspace_configuration_for_adapter(
3492 adapter: Arc<dyn LspAdapter>,
3493 delegate: &Arc<dyn LspAdapterDelegate>,
3494 toolchain: Option<Toolchain>,
3495 cx: &mut AsyncApp,
3496 ) -> Result<serde_json::Value> {
3497 let mut workspace_config = adapter
3498 .clone()
3499 .workspace_configuration(delegate, toolchain, cx)
3500 .await?;
3501
3502 for other_adapter in delegate.registered_lsp_adapters() {
3503 if other_adapter.name() == adapter.name() {
3504 continue;
3505 }
3506 if let Ok(Some(target_config)) = other_adapter
3507 .clone()
3508 .additional_workspace_configuration(adapter.name(), delegate, cx)
3509 .await
3510 {
3511 merge_json_value_into(target_config.clone(), &mut workspace_config);
3512 }
3513 }
3514
3515 Ok(workspace_config)
3516 }
3517
3518 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3519 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3520 Some(server.clone())
3521 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3522 Some(Arc::clone(server))
3523 } else {
3524 None
3525 }
3526 }
3527}
3528
3529fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3530 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3531 cx.emit(LspStoreEvent::LanguageServerUpdate {
3532 language_server_id: server.server_id(),
3533 name: Some(server.name()),
3534 message: proto::update_language_server::Variant::MetadataUpdated(
3535 proto::ServerMetadataUpdated {
3536 capabilities: Some(capabilities),
3537 },
3538 ),
3539 });
3540 }
3541}
3542
3543#[derive(Debug)]
3544pub struct FormattableBuffer {
3545 handle: Entity<Buffer>,
3546 abs_path: Option<PathBuf>,
3547 env: Option<HashMap<String, String>>,
3548 ranges: Option<Vec<Range<Anchor>>>,
3549}
3550
3551pub struct RemoteLspStore {
3552 upstream_client: Option<AnyProtoClient>,
3553 upstream_project_id: u64,
3554}
3555
3556pub(crate) enum LspStoreMode {
3557 Local(LocalLspStore), // ssh host and collab host
3558 Remote(RemoteLspStore), // collab guest
3559}
3560
3561impl LspStoreMode {
3562 fn is_local(&self) -> bool {
3563 matches!(self, LspStoreMode::Local(_))
3564 }
3565}
3566
3567pub struct LspStore {
3568 mode: LspStoreMode,
3569 last_formatting_failure: Option<String>,
3570 downstream_client: Option<(AnyProtoClient, u64)>,
3571 nonce: u128,
3572 buffer_store: Entity<BufferStore>,
3573 worktree_store: Entity<WorktreeStore>,
3574 pub languages: Arc<LanguageRegistry>,
3575 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3576 active_entry: Option<ProjectEntryId>,
3577 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3578 _maintain_buffer_languages: Task<()>,
3579 diagnostic_summaries:
3580 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3581 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3582 lsp_data: HashMap<BufferId, BufferLspData>,
3583 next_hint_id: Arc<AtomicUsize>,
3584}
3585
3586#[derive(Debug)]
3587pub struct BufferLspData {
3588 buffer_version: Global,
3589 document_colors: Option<DocumentColorData>,
3590 code_lens: Option<CodeLensData>,
3591 inlay_hints: BufferInlayHints,
3592 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3593 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3594}
3595
3596#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3597struct LspKey {
3598 request_type: TypeId,
3599 server_queried: Option<LanguageServerId>,
3600}
3601
3602impl BufferLspData {
3603 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3604 Self {
3605 buffer_version: buffer.read(cx).version(),
3606 document_colors: None,
3607 code_lens: None,
3608 inlay_hints: BufferInlayHints::new(buffer, cx),
3609 lsp_requests: HashMap::default(),
3610 chunk_lsp_requests: HashMap::default(),
3611 }
3612 }
3613
3614 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3615 if let Some(document_colors) = &mut self.document_colors {
3616 document_colors.colors.remove(&for_server);
3617 document_colors.cache_version += 1;
3618 }
3619
3620 if let Some(code_lens) = &mut self.code_lens {
3621 code_lens.lens.remove(&for_server);
3622 }
3623
3624 self.inlay_hints.remove_server_data(for_server);
3625 }
3626
3627 #[cfg(any(test, feature = "test-support"))]
3628 pub fn inlay_hints(&self) -> &BufferInlayHints {
3629 &self.inlay_hints
3630 }
3631}
3632
3633#[derive(Debug, Default, Clone)]
3634pub struct DocumentColors {
3635 pub colors: HashSet<DocumentColor>,
3636 pub cache_version: Option<usize>,
3637}
3638
3639type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3640type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3641
3642#[derive(Debug, Default)]
3643struct DocumentColorData {
3644 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3645 cache_version: usize,
3646 colors_update: Option<(Global, DocumentColorTask)>,
3647}
3648
3649#[derive(Debug, Default)]
3650struct CodeLensData {
3651 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3652 update: Option<(Global, CodeLensTask)>,
3653}
3654
3655#[derive(Debug)]
3656pub enum LspStoreEvent {
3657 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3658 LanguageServerRemoved(LanguageServerId),
3659 LanguageServerUpdate {
3660 language_server_id: LanguageServerId,
3661 name: Option<LanguageServerName>,
3662 message: proto::update_language_server::Variant,
3663 },
3664 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3665 LanguageServerPrompt(LanguageServerPromptRequest),
3666 LanguageDetected {
3667 buffer: Entity<Buffer>,
3668 new_language: Option<Arc<Language>>,
3669 },
3670 Notification(String),
3671 RefreshInlayHints {
3672 server_id: LanguageServerId,
3673 request_id: Option<usize>,
3674 },
3675 RefreshCodeLens,
3676 DiagnosticsUpdated {
3677 server_id: LanguageServerId,
3678 paths: Vec<ProjectPath>,
3679 },
3680 DiskBasedDiagnosticsStarted {
3681 language_server_id: LanguageServerId,
3682 },
3683 DiskBasedDiagnosticsFinished {
3684 language_server_id: LanguageServerId,
3685 },
3686 SnippetEdit {
3687 buffer_id: BufferId,
3688 edits: Vec<(lsp::Range, Snippet)>,
3689 most_recent_edit: clock::Lamport,
3690 },
3691}
3692
3693#[derive(Clone, Debug, Serialize)]
3694pub struct LanguageServerStatus {
3695 pub name: LanguageServerName,
3696 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3697 pub has_pending_diagnostic_updates: bool,
3698 progress_tokens: HashSet<ProgressToken>,
3699 pub worktree: Option<WorktreeId>,
3700}
3701
3702#[derive(Clone, Debug)]
3703struct CoreSymbol {
3704 pub language_server_name: LanguageServerName,
3705 pub source_worktree_id: WorktreeId,
3706 pub source_language_server_id: LanguageServerId,
3707 pub path: SymbolLocation,
3708 pub name: String,
3709 pub kind: lsp::SymbolKind,
3710 pub range: Range<Unclipped<PointUtf16>>,
3711}
3712
3713#[derive(Clone, Debug, PartialEq, Eq)]
3714pub enum SymbolLocation {
3715 InProject(ProjectPath),
3716 OutsideProject {
3717 abs_path: Arc<Path>,
3718 signature: [u8; 32],
3719 },
3720}
3721
3722impl SymbolLocation {
3723 fn file_name(&self) -> Option<&str> {
3724 match self {
3725 Self::InProject(path) => path.path.file_name(),
3726 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3727 }
3728 }
3729}
3730
3731impl LspStore {
3732 pub fn init(client: &AnyProtoClient) {
3733 client.add_entity_request_handler(Self::handle_lsp_query);
3734 client.add_entity_message_handler(Self::handle_lsp_query_response);
3735 client.add_entity_request_handler(Self::handle_restart_language_servers);
3736 client.add_entity_request_handler(Self::handle_stop_language_servers);
3737 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3738 client.add_entity_message_handler(Self::handle_start_language_server);
3739 client.add_entity_message_handler(Self::handle_update_language_server);
3740 client.add_entity_message_handler(Self::handle_language_server_log);
3741 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3742 client.add_entity_request_handler(Self::handle_format_buffers);
3743 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3744 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3745 client.add_entity_request_handler(Self::handle_apply_code_action);
3746 client.add_entity_request_handler(Self::handle_get_project_symbols);
3747 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3748 client.add_entity_request_handler(Self::handle_get_color_presentation);
3749 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3750 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3751 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3752 client.add_entity_request_handler(Self::handle_on_type_formatting);
3753 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3754 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3755 client.add_entity_request_handler(Self::handle_rename_project_entry);
3756 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3757 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3758 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3759 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3760 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3761 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3762 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3763
3764 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3765 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3766 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3767 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3768 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3769 client.add_entity_request_handler(
3770 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3771 );
3772 client.add_entity_request_handler(
3773 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3774 );
3775 client.add_entity_request_handler(
3776 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3777 );
3778 }
3779
3780 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3781 match &self.mode {
3782 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3783 _ => None,
3784 }
3785 }
3786
3787 pub fn as_local(&self) -> Option<&LocalLspStore> {
3788 match &self.mode {
3789 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3790 _ => None,
3791 }
3792 }
3793
3794 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3795 match &mut self.mode {
3796 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3797 _ => None,
3798 }
3799 }
3800
3801 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3802 match &self.mode {
3803 LspStoreMode::Remote(RemoteLspStore {
3804 upstream_client: Some(upstream_client),
3805 upstream_project_id,
3806 ..
3807 }) => Some((upstream_client.clone(), *upstream_project_id)),
3808
3809 LspStoreMode::Remote(RemoteLspStore {
3810 upstream_client: None,
3811 ..
3812 }) => None,
3813 LspStoreMode::Local(_) => None,
3814 }
3815 }
3816
3817 pub fn new_local(
3818 buffer_store: Entity<BufferStore>,
3819 worktree_store: Entity<WorktreeStore>,
3820 prettier_store: Entity<PrettierStore>,
3821 toolchain_store: Entity<LocalToolchainStore>,
3822 environment: Entity<ProjectEnvironment>,
3823 manifest_tree: Entity<ManifestTree>,
3824 languages: Arc<LanguageRegistry>,
3825 http_client: Arc<dyn HttpClient>,
3826 fs: Arc<dyn Fs>,
3827 cx: &mut Context<Self>,
3828 ) -> Self {
3829 let yarn = YarnPathStore::new(fs.clone(), cx);
3830 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3831 .detach();
3832 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3833 .detach();
3834 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3835 .detach();
3836 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3837 .detach();
3838 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3839 .detach();
3840 subscribe_to_binary_statuses(&languages, cx).detach();
3841
3842 let _maintain_workspace_config = {
3843 let (sender, receiver) = watch::channel();
3844 (Self::maintain_workspace_config(receiver, cx), sender)
3845 };
3846
3847 Self {
3848 mode: LspStoreMode::Local(LocalLspStore {
3849 weak: cx.weak_entity(),
3850 worktree_store: worktree_store.clone(),
3851
3852 supplementary_language_servers: Default::default(),
3853 languages: languages.clone(),
3854 language_server_ids: Default::default(),
3855 language_servers: Default::default(),
3856 last_workspace_edits_by_language_server: Default::default(),
3857 language_server_watched_paths: Default::default(),
3858 language_server_paths_watched_for_rename: Default::default(),
3859 language_server_dynamic_registrations: Default::default(),
3860 buffers_being_formatted: Default::default(),
3861 buffer_snapshots: Default::default(),
3862 prettier_store,
3863 environment,
3864 http_client,
3865 fs,
3866 yarn,
3867 next_diagnostic_group_id: Default::default(),
3868 diagnostics: Default::default(),
3869 _subscription: cx.on_app_quit(|this, cx| {
3870 this.as_local_mut()
3871 .unwrap()
3872 .shutdown_language_servers_on_quit(cx)
3873 }),
3874 lsp_tree: LanguageServerTree::new(
3875 manifest_tree,
3876 languages.clone(),
3877 toolchain_store.clone(),
3878 ),
3879 toolchain_store,
3880 registered_buffers: HashMap::default(),
3881 buffers_opened_in_servers: HashMap::default(),
3882 buffer_pull_diagnostics_result_ids: HashMap::default(),
3883 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3884 .manifest_file_names(),
3885 }),
3886 last_formatting_failure: None,
3887 downstream_client: None,
3888 buffer_store,
3889 worktree_store,
3890 languages: languages.clone(),
3891 language_server_statuses: Default::default(),
3892 nonce: StdRng::from_os_rng().random(),
3893 diagnostic_summaries: HashMap::default(),
3894 lsp_server_capabilities: HashMap::default(),
3895 lsp_data: HashMap::default(),
3896 next_hint_id: Arc::default(),
3897 active_entry: None,
3898 _maintain_workspace_config,
3899 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3900 }
3901 }
3902
3903 fn send_lsp_proto_request<R: LspCommand>(
3904 &self,
3905 buffer: Entity<Buffer>,
3906 client: AnyProtoClient,
3907 upstream_project_id: u64,
3908 request: R,
3909 cx: &mut Context<LspStore>,
3910 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3911 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3912 return Task::ready(Ok(R::Response::default()));
3913 }
3914 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3915 cx.spawn(async move |this, cx| {
3916 let response = client.request(message).await?;
3917 let this = this.upgrade().context("project dropped")?;
3918 request
3919 .response_from_proto(response, this, buffer, cx.clone())
3920 .await
3921 })
3922 }
3923
3924 pub(super) fn new_remote(
3925 buffer_store: Entity<BufferStore>,
3926 worktree_store: Entity<WorktreeStore>,
3927 languages: Arc<LanguageRegistry>,
3928 upstream_client: AnyProtoClient,
3929 project_id: u64,
3930 cx: &mut Context<Self>,
3931 ) -> Self {
3932 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3933 .detach();
3934 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3935 .detach();
3936 subscribe_to_binary_statuses(&languages, cx).detach();
3937 let _maintain_workspace_config = {
3938 let (sender, receiver) = watch::channel();
3939 (Self::maintain_workspace_config(receiver, cx), sender)
3940 };
3941 Self {
3942 mode: LspStoreMode::Remote(RemoteLspStore {
3943 upstream_client: Some(upstream_client),
3944 upstream_project_id: project_id,
3945 }),
3946 downstream_client: None,
3947 last_formatting_failure: None,
3948 buffer_store,
3949 worktree_store,
3950 languages: languages.clone(),
3951 language_server_statuses: Default::default(),
3952 nonce: StdRng::from_os_rng().random(),
3953 diagnostic_summaries: HashMap::default(),
3954 lsp_server_capabilities: HashMap::default(),
3955 next_hint_id: Arc::default(),
3956 lsp_data: HashMap::default(),
3957 active_entry: None,
3958
3959 _maintain_workspace_config,
3960 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3961 }
3962 }
3963
3964 fn on_buffer_store_event(
3965 &mut self,
3966 _: Entity<BufferStore>,
3967 event: &BufferStoreEvent,
3968 cx: &mut Context<Self>,
3969 ) {
3970 match event {
3971 BufferStoreEvent::BufferAdded(buffer) => {
3972 self.on_buffer_added(buffer, cx).log_err();
3973 }
3974 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3975 let buffer_id = buffer.read(cx).remote_id();
3976 if let Some(local) = self.as_local_mut()
3977 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3978 {
3979 local.reset_buffer(buffer, old_file, cx);
3980
3981 if local.registered_buffers.contains_key(&buffer_id) {
3982 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3983 }
3984 }
3985
3986 self.detect_language_for_buffer(buffer, cx);
3987 if let Some(local) = self.as_local_mut() {
3988 local.initialize_buffer(buffer, cx);
3989 if local.registered_buffers.contains_key(&buffer_id) {
3990 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3991 }
3992 }
3993 }
3994 _ => {}
3995 }
3996 }
3997
3998 fn on_worktree_store_event(
3999 &mut self,
4000 _: Entity<WorktreeStore>,
4001 event: &WorktreeStoreEvent,
4002 cx: &mut Context<Self>,
4003 ) {
4004 match event {
4005 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4006 if !worktree.read(cx).is_local() {
4007 return;
4008 }
4009 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4010 worktree::Event::UpdatedEntries(changes) => {
4011 this.update_local_worktree_language_servers(&worktree, changes, cx);
4012 }
4013 worktree::Event::UpdatedGitRepositories(_)
4014 | worktree::Event::DeletedEntry(_) => {}
4015 })
4016 .detach()
4017 }
4018 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4019 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4020 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4021 }
4022 WorktreeStoreEvent::WorktreeReleased(..)
4023 | WorktreeStoreEvent::WorktreeOrderChanged
4024 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4025 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4026 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4027 }
4028 }
4029
4030 fn on_prettier_store_event(
4031 &mut self,
4032 _: Entity<PrettierStore>,
4033 event: &PrettierStoreEvent,
4034 cx: &mut Context<Self>,
4035 ) {
4036 match event {
4037 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4038 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4039 }
4040 PrettierStoreEvent::LanguageServerAdded {
4041 new_server_id,
4042 name,
4043 prettier_server,
4044 } => {
4045 self.register_supplementary_language_server(
4046 *new_server_id,
4047 name.clone(),
4048 prettier_server.clone(),
4049 cx,
4050 );
4051 }
4052 }
4053 }
4054
4055 fn on_toolchain_store_event(
4056 &mut self,
4057 _: Entity<LocalToolchainStore>,
4058 event: &ToolchainStoreEvent,
4059 _: &mut Context<Self>,
4060 ) {
4061 if let ToolchainStoreEvent::ToolchainActivated = event {
4062 self.request_workspace_config_refresh()
4063 }
4064 }
4065
4066 fn request_workspace_config_refresh(&mut self) {
4067 *self._maintain_workspace_config.1.borrow_mut() = ();
4068 }
4069
4070 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4071 self.as_local().map(|local| local.prettier_store.clone())
4072 }
4073
4074 fn on_buffer_event(
4075 &mut self,
4076 buffer: Entity<Buffer>,
4077 event: &language::BufferEvent,
4078 cx: &mut Context<Self>,
4079 ) {
4080 match event {
4081 language::BufferEvent::Edited => {
4082 self.on_buffer_edited(buffer, cx);
4083 }
4084
4085 language::BufferEvent::Saved => {
4086 self.on_buffer_saved(buffer, cx);
4087 }
4088
4089 _ => {}
4090 }
4091 }
4092
4093 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4094 buffer
4095 .read(cx)
4096 .set_language_registry(self.languages.clone());
4097
4098 cx.subscribe(buffer, |this, buffer, event, cx| {
4099 this.on_buffer_event(buffer, event, cx);
4100 })
4101 .detach();
4102
4103 self.detect_language_for_buffer(buffer, cx);
4104 if let Some(local) = self.as_local_mut() {
4105 local.initialize_buffer(buffer, cx);
4106 }
4107
4108 Ok(())
4109 }
4110
4111 pub(crate) fn register_buffer_with_language_servers(
4112 &mut self,
4113 buffer: &Entity<Buffer>,
4114 only_register_servers: HashSet<LanguageServerSelector>,
4115 ignore_refcounts: bool,
4116 cx: &mut Context<Self>,
4117 ) -> OpenLspBufferHandle {
4118 let buffer_id = buffer.read(cx).remote_id();
4119 let handle = cx.new(|_| buffer.clone());
4120 if let Some(local) = self.as_local_mut() {
4121 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4122 if !ignore_refcounts {
4123 *refcount += 1;
4124 }
4125
4126 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4127 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4128 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4129 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4130 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4131 return handle;
4132 };
4133 if !file.is_local() {
4134 return handle;
4135 }
4136
4137 if ignore_refcounts || *refcount == 1 {
4138 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4139 }
4140 if !ignore_refcounts {
4141 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4142 let refcount = {
4143 let local = lsp_store.as_local_mut().unwrap();
4144 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4145 debug_panic!("bad refcounting");
4146 return;
4147 };
4148
4149 *refcount -= 1;
4150 *refcount
4151 };
4152 if refcount == 0 {
4153 lsp_store.lsp_data.remove(&buffer_id);
4154 let local = lsp_store.as_local_mut().unwrap();
4155 local.registered_buffers.remove(&buffer_id);
4156 local.buffers_opened_in_servers.remove(&buffer_id);
4157 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4158 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4159 }
4160 }
4161 })
4162 .detach();
4163 }
4164 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4165 let buffer_id = buffer.read(cx).remote_id().to_proto();
4166 cx.background_spawn(async move {
4167 upstream_client
4168 .request(proto::RegisterBufferWithLanguageServers {
4169 project_id: upstream_project_id,
4170 buffer_id,
4171 only_servers: only_register_servers
4172 .into_iter()
4173 .map(|selector| {
4174 let selector = match selector {
4175 LanguageServerSelector::Id(language_server_id) => {
4176 proto::language_server_selector::Selector::ServerId(
4177 language_server_id.to_proto(),
4178 )
4179 }
4180 LanguageServerSelector::Name(language_server_name) => {
4181 proto::language_server_selector::Selector::Name(
4182 language_server_name.to_string(),
4183 )
4184 }
4185 };
4186 proto::LanguageServerSelector {
4187 selector: Some(selector),
4188 }
4189 })
4190 .collect(),
4191 })
4192 .await
4193 })
4194 .detach();
4195 } else {
4196 panic!("oops!");
4197 }
4198 handle
4199 }
4200
4201 fn maintain_buffer_languages(
4202 languages: Arc<LanguageRegistry>,
4203 cx: &mut Context<Self>,
4204 ) -> Task<()> {
4205 let mut subscription = languages.subscribe();
4206 let mut prev_reload_count = languages.reload_count();
4207 cx.spawn(async move |this, cx| {
4208 while let Some(()) = subscription.next().await {
4209 if let Some(this) = this.upgrade() {
4210 // If the language registry has been reloaded, then remove and
4211 // re-assign the languages on all open buffers.
4212 let reload_count = languages.reload_count();
4213 if reload_count > prev_reload_count {
4214 prev_reload_count = reload_count;
4215 this.update(cx, |this, cx| {
4216 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4217 for buffer in buffer_store.buffers() {
4218 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4219 {
4220 buffer
4221 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4222 if let Some(local) = this.as_local_mut() {
4223 local.reset_buffer(&buffer, &f, cx);
4224
4225 if local
4226 .registered_buffers
4227 .contains_key(&buffer.read(cx).remote_id())
4228 && let Some(file_url) =
4229 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4230 {
4231 local.unregister_buffer_from_language_servers(
4232 &buffer, &file_url, cx,
4233 );
4234 }
4235 }
4236 }
4237 }
4238 });
4239 })
4240 .ok();
4241 }
4242
4243 this.update(cx, |this, cx| {
4244 let mut plain_text_buffers = Vec::new();
4245 let mut buffers_with_unknown_injections = Vec::new();
4246 for handle in this.buffer_store.read(cx).buffers() {
4247 let buffer = handle.read(cx);
4248 if buffer.language().is_none()
4249 || buffer.language() == Some(&*language::PLAIN_TEXT)
4250 {
4251 plain_text_buffers.push(handle);
4252 } else if buffer.contains_unknown_injections() {
4253 buffers_with_unknown_injections.push(handle);
4254 }
4255 }
4256
4257 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4258 // and reused later in the invisible worktrees.
4259 plain_text_buffers.sort_by_key(|buffer| {
4260 Reverse(
4261 File::from_dyn(buffer.read(cx).file())
4262 .map(|file| file.worktree.read(cx).is_visible()),
4263 )
4264 });
4265
4266 for buffer in plain_text_buffers {
4267 this.detect_language_for_buffer(&buffer, cx);
4268 if let Some(local) = this.as_local_mut() {
4269 local.initialize_buffer(&buffer, cx);
4270 if local
4271 .registered_buffers
4272 .contains_key(&buffer.read(cx).remote_id())
4273 {
4274 local.register_buffer_with_language_servers(
4275 &buffer,
4276 HashSet::default(),
4277 cx,
4278 );
4279 }
4280 }
4281 }
4282
4283 for buffer in buffers_with_unknown_injections {
4284 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4285 }
4286 })
4287 .ok();
4288 }
4289 }
4290 })
4291 }
4292
4293 fn detect_language_for_buffer(
4294 &mut self,
4295 buffer_handle: &Entity<Buffer>,
4296 cx: &mut Context<Self>,
4297 ) -> Option<language::AvailableLanguage> {
4298 // If the buffer has a language, set it and start the language server if we haven't already.
4299 let buffer = buffer_handle.read(cx);
4300 let file = buffer.file()?;
4301
4302 let content = buffer.as_rope();
4303 let available_language = self.languages.language_for_file(file, Some(content), cx);
4304 if let Some(available_language) = &available_language {
4305 if let Some(Ok(Ok(new_language))) = self
4306 .languages
4307 .load_language(available_language)
4308 .now_or_never()
4309 {
4310 self.set_language_for_buffer(buffer_handle, new_language, cx);
4311 }
4312 } else {
4313 cx.emit(LspStoreEvent::LanguageDetected {
4314 buffer: buffer_handle.clone(),
4315 new_language: None,
4316 });
4317 }
4318
4319 available_language
4320 }
4321
4322 pub(crate) fn set_language_for_buffer(
4323 &mut self,
4324 buffer_entity: &Entity<Buffer>,
4325 new_language: Arc<Language>,
4326 cx: &mut Context<Self>,
4327 ) {
4328 let buffer = buffer_entity.read(cx);
4329 let buffer_file = buffer.file().cloned();
4330 let buffer_id = buffer.remote_id();
4331 if let Some(local_store) = self.as_local_mut()
4332 && local_store.registered_buffers.contains_key(&buffer_id)
4333 && let Some(abs_path) =
4334 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4335 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4336 {
4337 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4338 }
4339 buffer_entity.update(cx, |buffer, cx| {
4340 if buffer
4341 .language()
4342 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4343 {
4344 buffer.set_language(Some(new_language.clone()), cx);
4345 }
4346 });
4347
4348 let settings =
4349 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4350 let buffer_file = File::from_dyn(buffer_file.as_ref());
4351
4352 let worktree_id = if let Some(file) = buffer_file {
4353 let worktree = file.worktree.clone();
4354
4355 if let Some(local) = self.as_local_mut()
4356 && local.registered_buffers.contains_key(&buffer_id)
4357 {
4358 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4359 }
4360 Some(worktree.read(cx).id())
4361 } else {
4362 None
4363 };
4364
4365 if settings.prettier.allowed
4366 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4367 {
4368 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4369 if let Some(prettier_store) = prettier_store {
4370 prettier_store.update(cx, |prettier_store, cx| {
4371 prettier_store.install_default_prettier(
4372 worktree_id,
4373 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4374 cx,
4375 )
4376 })
4377 }
4378 }
4379
4380 cx.emit(LspStoreEvent::LanguageDetected {
4381 buffer: buffer_entity.clone(),
4382 new_language: Some(new_language),
4383 })
4384 }
4385
4386 pub fn buffer_store(&self) -> Entity<BufferStore> {
4387 self.buffer_store.clone()
4388 }
4389
4390 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4391 self.active_entry = active_entry;
4392 }
4393
4394 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4395 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4396 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4397 {
4398 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4399 summaries
4400 .iter()
4401 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4402 });
4403 if let Some(summary) = summaries.next() {
4404 client
4405 .send(proto::UpdateDiagnosticSummary {
4406 project_id: downstream_project_id,
4407 worktree_id: worktree.id().to_proto(),
4408 summary: Some(summary),
4409 more_summaries: summaries.collect(),
4410 })
4411 .log_err();
4412 }
4413 }
4414 }
4415
4416 fn is_capable_for_proto_request<R>(
4417 &self,
4418 buffer: &Entity<Buffer>,
4419 request: &R,
4420 cx: &App,
4421 ) -> bool
4422 where
4423 R: LspCommand,
4424 {
4425 self.check_if_capable_for_proto_request(
4426 buffer,
4427 |capabilities| {
4428 request.check_capabilities(AdapterServerCapabilities {
4429 server_capabilities: capabilities.clone(),
4430 code_action_kinds: None,
4431 })
4432 },
4433 cx,
4434 )
4435 }
4436
4437 fn check_if_capable_for_proto_request<F>(
4438 &self,
4439 buffer: &Entity<Buffer>,
4440 check: F,
4441 cx: &App,
4442 ) -> bool
4443 where
4444 F: FnMut(&lsp::ServerCapabilities) -> bool,
4445 {
4446 let Some(language) = buffer.read(cx).language().cloned() else {
4447 return false;
4448 };
4449 let relevant_language_servers = self
4450 .languages
4451 .lsp_adapters(&language.name())
4452 .into_iter()
4453 .map(|lsp_adapter| lsp_adapter.name())
4454 .collect::<HashSet<_>>();
4455 self.language_server_statuses
4456 .iter()
4457 .filter_map(|(server_id, server_status)| {
4458 relevant_language_servers
4459 .contains(&server_status.name)
4460 .then_some(server_id)
4461 })
4462 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4463 .any(check)
4464 }
4465
4466 pub fn request_lsp<R>(
4467 &mut self,
4468 buffer: Entity<Buffer>,
4469 server: LanguageServerToQuery,
4470 request: R,
4471 cx: &mut Context<Self>,
4472 ) -> Task<Result<R::Response>>
4473 where
4474 R: LspCommand,
4475 <R::LspRequest as lsp::request::Request>::Result: Send,
4476 <R::LspRequest as lsp::request::Request>::Params: Send,
4477 {
4478 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4479 return self.send_lsp_proto_request(
4480 buffer,
4481 upstream_client,
4482 upstream_project_id,
4483 request,
4484 cx,
4485 );
4486 }
4487
4488 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4489 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4490 local
4491 .language_servers_for_buffer(buffer, cx)
4492 .find(|(_, server)| {
4493 request.check_capabilities(server.adapter_server_capabilities())
4494 })
4495 .map(|(_, server)| server.clone())
4496 }),
4497 LanguageServerToQuery::Other(id) => self
4498 .language_server_for_local_buffer(buffer, id, cx)
4499 .and_then(|(_, server)| {
4500 request
4501 .check_capabilities(server.adapter_server_capabilities())
4502 .then(|| Arc::clone(server))
4503 }),
4504 }) else {
4505 return Task::ready(Ok(Default::default()));
4506 };
4507
4508 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4509
4510 let Some(file) = file else {
4511 return Task::ready(Ok(Default::default()));
4512 };
4513
4514 let lsp_params = match request.to_lsp_params_or_response(
4515 &file.abs_path(cx),
4516 buffer.read(cx),
4517 &language_server,
4518 cx,
4519 ) {
4520 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4521 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4522
4523 Err(err) => {
4524 let message = format!(
4525 "{} via {} failed: {}",
4526 request.display_name(),
4527 language_server.name(),
4528 err
4529 );
4530 log::warn!("{message}");
4531 return Task::ready(Err(anyhow!(message)));
4532 }
4533 };
4534
4535 let status = request.status();
4536 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4537 return Task::ready(Ok(Default::default()));
4538 }
4539 cx.spawn(async move |this, cx| {
4540 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4541
4542 let id = lsp_request.id();
4543 let _cleanup = if status.is_some() {
4544 cx.update(|cx| {
4545 this.update(cx, |this, cx| {
4546 this.on_lsp_work_start(
4547 language_server.server_id(),
4548 ProgressToken::Number(id),
4549 LanguageServerProgress {
4550 is_disk_based_diagnostics_progress: false,
4551 is_cancellable: false,
4552 title: None,
4553 message: status.clone(),
4554 percentage: None,
4555 last_update_at: cx.background_executor().now(),
4556 },
4557 cx,
4558 );
4559 })
4560 })
4561 .log_err();
4562
4563 Some(defer(|| {
4564 cx.update(|cx| {
4565 this.update(cx, |this, cx| {
4566 this.on_lsp_work_end(
4567 language_server.server_id(),
4568 ProgressToken::Number(id),
4569 cx,
4570 );
4571 })
4572 })
4573 .log_err();
4574 }))
4575 } else {
4576 None
4577 };
4578
4579 let result = lsp_request.await.into_response();
4580
4581 let response = result.map_err(|err| {
4582 let message = format!(
4583 "{} via {} failed: {}",
4584 request.display_name(),
4585 language_server.name(),
4586 err
4587 );
4588 log::warn!("{message}");
4589 anyhow::anyhow!(message)
4590 })?;
4591
4592 request
4593 .response_from_lsp(
4594 response,
4595 this.upgrade().context("no app context")?,
4596 buffer,
4597 language_server.server_id(),
4598 cx.clone(),
4599 )
4600 .await
4601 })
4602 }
4603
4604 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4605 let mut language_formatters_to_check = Vec::new();
4606 for buffer in self.buffer_store.read(cx).buffers() {
4607 let buffer = buffer.read(cx);
4608 let buffer_file = File::from_dyn(buffer.file());
4609 let buffer_language = buffer.language();
4610 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4611 if buffer_language.is_some() {
4612 language_formatters_to_check.push((
4613 buffer_file.map(|f| f.worktree_id(cx)),
4614 settings.into_owned(),
4615 ));
4616 }
4617 }
4618
4619 self.request_workspace_config_refresh();
4620
4621 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4622 prettier_store.update(cx, |prettier_store, cx| {
4623 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4624 })
4625 }
4626
4627 cx.notify();
4628 }
4629
4630 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4631 let buffer_store = self.buffer_store.clone();
4632 let Some(local) = self.as_local_mut() else {
4633 return;
4634 };
4635 let mut adapters = BTreeMap::default();
4636 let get_adapter = {
4637 let languages = local.languages.clone();
4638 let environment = local.environment.clone();
4639 let weak = local.weak.clone();
4640 let worktree_store = local.worktree_store.clone();
4641 let http_client = local.http_client.clone();
4642 let fs = local.fs.clone();
4643 move |worktree_id, cx: &mut App| {
4644 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4645 Some(LocalLspAdapterDelegate::new(
4646 languages.clone(),
4647 &environment,
4648 weak.clone(),
4649 &worktree,
4650 http_client.clone(),
4651 fs.clone(),
4652 cx,
4653 ))
4654 }
4655 };
4656
4657 let mut messages_to_report = Vec::new();
4658 let (new_tree, to_stop) = {
4659 let mut rebase = local.lsp_tree.rebase();
4660 let buffers = buffer_store
4661 .read(cx)
4662 .buffers()
4663 .filter_map(|buffer| {
4664 let raw_buffer = buffer.read(cx);
4665 if !local
4666 .registered_buffers
4667 .contains_key(&raw_buffer.remote_id())
4668 {
4669 return None;
4670 }
4671 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4672 let language = raw_buffer.language().cloned()?;
4673 Some((file, language, raw_buffer.remote_id()))
4674 })
4675 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4676 for (file, language, buffer_id) in buffers {
4677 let worktree_id = file.worktree_id(cx);
4678 let Some(worktree) = local
4679 .worktree_store
4680 .read(cx)
4681 .worktree_for_id(worktree_id, cx)
4682 else {
4683 continue;
4684 };
4685
4686 if let Some((_, apply)) = local.reuse_existing_language_server(
4687 rebase.server_tree(),
4688 &worktree,
4689 &language.name(),
4690 cx,
4691 ) {
4692 (apply)(rebase.server_tree());
4693 } else if let Some(lsp_delegate) = adapters
4694 .entry(worktree_id)
4695 .or_insert_with(|| get_adapter(worktree_id, cx))
4696 .clone()
4697 {
4698 let delegate =
4699 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4700 let path = file
4701 .path()
4702 .parent()
4703 .map(Arc::from)
4704 .unwrap_or_else(|| file.path().clone());
4705 let worktree_path = ProjectPath { worktree_id, path };
4706 let abs_path = file.abs_path(cx);
4707 let nodes = rebase
4708 .walk(
4709 worktree_path,
4710 language.name(),
4711 language.manifest(),
4712 delegate.clone(),
4713 cx,
4714 )
4715 .collect::<Vec<_>>();
4716 for node in nodes {
4717 let server_id = node.server_id_or_init(|disposition| {
4718 let path = &disposition.path;
4719 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4720 let key = LanguageServerSeed {
4721 worktree_id,
4722 name: disposition.server_name.clone(),
4723 settings: disposition.settings.clone(),
4724 toolchain: local.toolchain_store.read(cx).active_toolchain(
4725 path.worktree_id,
4726 &path.path,
4727 language.name(),
4728 ),
4729 };
4730 local.language_server_ids.remove(&key);
4731
4732 let server_id = local.get_or_insert_language_server(
4733 &worktree,
4734 lsp_delegate.clone(),
4735 disposition,
4736 &language.name(),
4737 cx,
4738 );
4739 if let Some(state) = local.language_servers.get(&server_id)
4740 && let Ok(uri) = uri
4741 {
4742 state.add_workspace_folder(uri);
4743 };
4744 server_id
4745 });
4746
4747 if let Some(language_server_id) = server_id {
4748 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4749 language_server_id,
4750 name: node.name(),
4751 message:
4752 proto::update_language_server::Variant::RegisteredForBuffer(
4753 proto::RegisteredForBuffer {
4754 buffer_abs_path: abs_path
4755 .to_string_lossy()
4756 .into_owned(),
4757 buffer_id: buffer_id.to_proto(),
4758 },
4759 ),
4760 });
4761 }
4762 }
4763 } else {
4764 continue;
4765 }
4766 }
4767 rebase.finish()
4768 };
4769 for message in messages_to_report {
4770 cx.emit(message);
4771 }
4772 local.lsp_tree = new_tree;
4773 for (id, _) in to_stop {
4774 self.stop_local_language_server(id, cx).detach();
4775 }
4776 }
4777
4778 pub fn apply_code_action(
4779 &self,
4780 buffer_handle: Entity<Buffer>,
4781 mut action: CodeAction,
4782 push_to_history: bool,
4783 cx: &mut Context<Self>,
4784 ) -> Task<Result<ProjectTransaction>> {
4785 if let Some((upstream_client, project_id)) = self.upstream_client() {
4786 let request = proto::ApplyCodeAction {
4787 project_id,
4788 buffer_id: buffer_handle.read(cx).remote_id().into(),
4789 action: Some(Self::serialize_code_action(&action)),
4790 };
4791 let buffer_store = self.buffer_store();
4792 cx.spawn(async move |_, cx| {
4793 let response = upstream_client
4794 .request(request)
4795 .await?
4796 .transaction
4797 .context("missing transaction")?;
4798
4799 buffer_store
4800 .update(cx, |buffer_store, cx| {
4801 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4802 })?
4803 .await
4804 })
4805 } else if self.mode.is_local() {
4806 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4807 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4808 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4809 }) else {
4810 return Task::ready(Ok(ProjectTransaction::default()));
4811 };
4812 cx.spawn(async move |this, cx| {
4813 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4814 .await
4815 .context("resolving a code action")?;
4816 if let Some(edit) = action.lsp_action.edit()
4817 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4818 return LocalLspStore::deserialize_workspace_edit(
4819 this.upgrade().context("no app present")?,
4820 edit.clone(),
4821 push_to_history,
4822
4823 lang_server.clone(),
4824 cx,
4825 )
4826 .await;
4827 }
4828
4829 if let Some(command) = action.lsp_action.command() {
4830 let server_capabilities = lang_server.capabilities();
4831 let available_commands = server_capabilities
4832 .execute_command_provider
4833 .as_ref()
4834 .map(|options| options.commands.as_slice())
4835 .unwrap_or_default();
4836 if available_commands.contains(&command.command) {
4837 this.update(cx, |this, _| {
4838 this.as_local_mut()
4839 .unwrap()
4840 .last_workspace_edits_by_language_server
4841 .remove(&lang_server.server_id());
4842 })?;
4843
4844 let _result = lang_server
4845 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4846 command: command.command.clone(),
4847 arguments: command.arguments.clone().unwrap_or_default(),
4848 ..lsp::ExecuteCommandParams::default()
4849 })
4850 .await.into_response()
4851 .context("execute command")?;
4852
4853 return this.update(cx, |this, _| {
4854 this.as_local_mut()
4855 .unwrap()
4856 .last_workspace_edits_by_language_server
4857 .remove(&lang_server.server_id())
4858 .unwrap_or_default()
4859 });
4860 } else {
4861 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4862 }
4863 }
4864
4865 Ok(ProjectTransaction::default())
4866 })
4867 } else {
4868 Task::ready(Err(anyhow!("no upstream client and not local")))
4869 }
4870 }
4871
4872 pub fn apply_code_action_kind(
4873 &mut self,
4874 buffers: HashSet<Entity<Buffer>>,
4875 kind: CodeActionKind,
4876 push_to_history: bool,
4877 cx: &mut Context<Self>,
4878 ) -> Task<anyhow::Result<ProjectTransaction>> {
4879 if self.as_local().is_some() {
4880 cx.spawn(async move |lsp_store, cx| {
4881 let buffers = buffers.into_iter().collect::<Vec<_>>();
4882 let result = LocalLspStore::execute_code_action_kind_locally(
4883 lsp_store.clone(),
4884 buffers,
4885 kind,
4886 push_to_history,
4887 cx,
4888 )
4889 .await;
4890 lsp_store.update(cx, |lsp_store, _| {
4891 lsp_store.update_last_formatting_failure(&result);
4892 })?;
4893 result
4894 })
4895 } else if let Some((client, project_id)) = self.upstream_client() {
4896 let buffer_store = self.buffer_store();
4897 cx.spawn(async move |lsp_store, cx| {
4898 let result = client
4899 .request(proto::ApplyCodeActionKind {
4900 project_id,
4901 kind: kind.as_str().to_owned(),
4902 buffer_ids: buffers
4903 .iter()
4904 .map(|buffer| {
4905 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4906 })
4907 .collect::<Result<_>>()?,
4908 })
4909 .await
4910 .and_then(|result| result.transaction.context("missing transaction"));
4911 lsp_store.update(cx, |lsp_store, _| {
4912 lsp_store.update_last_formatting_failure(&result);
4913 })?;
4914
4915 let transaction_response = result?;
4916 buffer_store
4917 .update(cx, |buffer_store, cx| {
4918 buffer_store.deserialize_project_transaction(
4919 transaction_response,
4920 push_to_history,
4921 cx,
4922 )
4923 })?
4924 .await
4925 })
4926 } else {
4927 Task::ready(Ok(ProjectTransaction::default()))
4928 }
4929 }
4930
4931 pub fn resolved_hint(
4932 &mut self,
4933 buffer_id: BufferId,
4934 id: InlayId,
4935 cx: &mut Context<Self>,
4936 ) -> Option<ResolvedHint> {
4937 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4938
4939 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4940 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4941 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4942 let (server_id, resolve_data) = match &hint.resolve_state {
4943 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4944 ResolveState::Resolving => {
4945 return Some(ResolvedHint::Resolving(
4946 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4947 ));
4948 }
4949 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4950 };
4951
4952 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4953 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4954 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4955 id,
4956 cx.spawn(async move |lsp_store, cx| {
4957 let resolved_hint = resolve_task.await;
4958 lsp_store
4959 .update(cx, |lsp_store, _| {
4960 if let Some(old_inlay_hint) = lsp_store
4961 .lsp_data
4962 .get_mut(&buffer_id)
4963 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4964 {
4965 match resolved_hint {
4966 Ok(resolved_hint) => {
4967 *old_inlay_hint = resolved_hint;
4968 }
4969 Err(e) => {
4970 old_inlay_hint.resolve_state =
4971 ResolveState::CanResolve(server_id, resolve_data);
4972 log::error!("Inlay hint resolve failed: {e:#}");
4973 }
4974 }
4975 }
4976 })
4977 .ok();
4978 })
4979 .shared(),
4980 );
4981 debug_assert!(
4982 previous_task.is_none(),
4983 "Did not change hint's resolve state after spawning its resolve"
4984 );
4985 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4986 None
4987 }
4988
4989 fn resolve_inlay_hint(
4990 &self,
4991 mut hint: InlayHint,
4992 buffer: Entity<Buffer>,
4993 server_id: LanguageServerId,
4994 cx: &mut Context<Self>,
4995 ) -> Task<anyhow::Result<InlayHint>> {
4996 if let Some((upstream_client, project_id)) = self.upstream_client() {
4997 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4998 {
4999 hint.resolve_state = ResolveState::Resolved;
5000 return Task::ready(Ok(hint));
5001 }
5002 let request = proto::ResolveInlayHint {
5003 project_id,
5004 buffer_id: buffer.read(cx).remote_id().into(),
5005 language_server_id: server_id.0 as u64,
5006 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5007 };
5008 cx.background_spawn(async move {
5009 let response = upstream_client
5010 .request(request)
5011 .await
5012 .context("inlay hints proto request")?;
5013 match response.hint {
5014 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5015 .context("inlay hints proto resolve response conversion"),
5016 None => Ok(hint),
5017 }
5018 })
5019 } else {
5020 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5021 self.language_server_for_local_buffer(buffer, server_id, cx)
5022 .map(|(_, server)| server.clone())
5023 }) else {
5024 return Task::ready(Ok(hint));
5025 };
5026 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5027 return Task::ready(Ok(hint));
5028 }
5029 let buffer_snapshot = buffer.read(cx).snapshot();
5030 cx.spawn(async move |_, cx| {
5031 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5032 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5033 );
5034 let resolved_hint = resolve_task
5035 .await
5036 .into_response()
5037 .context("inlay hint resolve LSP request")?;
5038 let resolved_hint = InlayHints::lsp_to_project_hint(
5039 resolved_hint,
5040 &buffer,
5041 server_id,
5042 ResolveState::Resolved,
5043 false,
5044 cx,
5045 )
5046 .await?;
5047 Ok(resolved_hint)
5048 })
5049 }
5050 }
5051
5052 pub fn resolve_color_presentation(
5053 &mut self,
5054 mut color: DocumentColor,
5055 buffer: Entity<Buffer>,
5056 server_id: LanguageServerId,
5057 cx: &mut Context<Self>,
5058 ) -> Task<Result<DocumentColor>> {
5059 if color.resolved {
5060 return Task::ready(Ok(color));
5061 }
5062
5063 if let Some((upstream_client, project_id)) = self.upstream_client() {
5064 let start = color.lsp_range.start;
5065 let end = color.lsp_range.end;
5066 let request = proto::GetColorPresentation {
5067 project_id,
5068 server_id: server_id.to_proto(),
5069 buffer_id: buffer.read(cx).remote_id().into(),
5070 color: Some(proto::ColorInformation {
5071 red: color.color.red,
5072 green: color.color.green,
5073 blue: color.color.blue,
5074 alpha: color.color.alpha,
5075 lsp_range_start: Some(proto::PointUtf16 {
5076 row: start.line,
5077 column: start.character,
5078 }),
5079 lsp_range_end: Some(proto::PointUtf16 {
5080 row: end.line,
5081 column: end.character,
5082 }),
5083 }),
5084 };
5085 cx.background_spawn(async move {
5086 let response = upstream_client
5087 .request(request)
5088 .await
5089 .context("color presentation proto request")?;
5090 color.resolved = true;
5091 color.color_presentations = response
5092 .presentations
5093 .into_iter()
5094 .map(|presentation| ColorPresentation {
5095 label: SharedString::from(presentation.label),
5096 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5097 additional_text_edits: presentation
5098 .additional_text_edits
5099 .into_iter()
5100 .filter_map(deserialize_lsp_edit)
5101 .collect(),
5102 })
5103 .collect();
5104 Ok(color)
5105 })
5106 } else {
5107 let path = match buffer
5108 .update(cx, |buffer, cx| {
5109 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5110 })
5111 .context("buffer with the missing path")
5112 {
5113 Ok(path) => path,
5114 Err(e) => return Task::ready(Err(e)),
5115 };
5116 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5117 self.language_server_for_local_buffer(buffer, server_id, cx)
5118 .map(|(_, server)| server.clone())
5119 }) else {
5120 return Task::ready(Ok(color));
5121 };
5122 cx.background_spawn(async move {
5123 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5124 lsp::ColorPresentationParams {
5125 text_document: make_text_document_identifier(&path)?,
5126 color: color.color,
5127 range: color.lsp_range,
5128 work_done_progress_params: Default::default(),
5129 partial_result_params: Default::default(),
5130 },
5131 );
5132 color.color_presentations = resolve_task
5133 .await
5134 .into_response()
5135 .context("color presentation resolve LSP request")?
5136 .into_iter()
5137 .map(|presentation| ColorPresentation {
5138 label: SharedString::from(presentation.label),
5139 text_edit: presentation.text_edit,
5140 additional_text_edits: presentation
5141 .additional_text_edits
5142 .unwrap_or_default(),
5143 })
5144 .collect();
5145 color.resolved = true;
5146 Ok(color)
5147 })
5148 }
5149 }
5150
5151 pub(crate) fn linked_edits(
5152 &mut self,
5153 buffer: &Entity<Buffer>,
5154 position: Anchor,
5155 cx: &mut Context<Self>,
5156 ) -> Task<Result<Vec<Range<Anchor>>>> {
5157 let snapshot = buffer.read(cx).snapshot();
5158 let scope = snapshot.language_scope_at(position);
5159 let Some(server_id) = self
5160 .as_local()
5161 .and_then(|local| {
5162 buffer.update(cx, |buffer, cx| {
5163 local
5164 .language_servers_for_buffer(buffer, cx)
5165 .filter(|(_, server)| {
5166 LinkedEditingRange::check_server_capabilities(server.capabilities())
5167 })
5168 .filter(|(adapter, _)| {
5169 scope
5170 .as_ref()
5171 .map(|scope| scope.language_allowed(&adapter.name))
5172 .unwrap_or(true)
5173 })
5174 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5175 .next()
5176 })
5177 })
5178 .or_else(|| {
5179 self.upstream_client()
5180 .is_some()
5181 .then_some(LanguageServerToQuery::FirstCapable)
5182 })
5183 .filter(|_| {
5184 maybe!({
5185 let language = buffer.read(cx).language_at(position)?;
5186 Some(
5187 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5188 .linked_edits,
5189 )
5190 }) == Some(true)
5191 })
5192 else {
5193 return Task::ready(Ok(Vec::new()));
5194 };
5195
5196 self.request_lsp(
5197 buffer.clone(),
5198 server_id,
5199 LinkedEditingRange { position },
5200 cx,
5201 )
5202 }
5203
5204 fn apply_on_type_formatting(
5205 &mut self,
5206 buffer: Entity<Buffer>,
5207 position: Anchor,
5208 trigger: String,
5209 cx: &mut Context<Self>,
5210 ) -> Task<Result<Option<Transaction>>> {
5211 if let Some((client, project_id)) = self.upstream_client() {
5212 if !self.check_if_capable_for_proto_request(
5213 &buffer,
5214 |capabilities| {
5215 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5216 },
5217 cx,
5218 ) {
5219 return Task::ready(Ok(None));
5220 }
5221 let request = proto::OnTypeFormatting {
5222 project_id,
5223 buffer_id: buffer.read(cx).remote_id().into(),
5224 position: Some(serialize_anchor(&position)),
5225 trigger,
5226 version: serialize_version(&buffer.read(cx).version()),
5227 };
5228 cx.background_spawn(async move {
5229 client
5230 .request(request)
5231 .await?
5232 .transaction
5233 .map(language::proto::deserialize_transaction)
5234 .transpose()
5235 })
5236 } else if let Some(local) = self.as_local_mut() {
5237 let buffer_id = buffer.read(cx).remote_id();
5238 local.buffers_being_formatted.insert(buffer_id);
5239 cx.spawn(async move |this, cx| {
5240 let _cleanup = defer({
5241 let this = this.clone();
5242 let mut cx = cx.clone();
5243 move || {
5244 this.update(&mut cx, |this, _| {
5245 if let Some(local) = this.as_local_mut() {
5246 local.buffers_being_formatted.remove(&buffer_id);
5247 }
5248 })
5249 .ok();
5250 }
5251 });
5252
5253 buffer
5254 .update(cx, |buffer, _| {
5255 buffer.wait_for_edits(Some(position.timestamp))
5256 })?
5257 .await?;
5258 this.update(cx, |this, cx| {
5259 let position = position.to_point_utf16(buffer.read(cx));
5260 this.on_type_format(buffer, position, trigger, false, cx)
5261 })?
5262 .await
5263 })
5264 } else {
5265 Task::ready(Err(anyhow!("No upstream client or local language server")))
5266 }
5267 }
5268
5269 pub fn on_type_format<T: ToPointUtf16>(
5270 &mut self,
5271 buffer: Entity<Buffer>,
5272 position: T,
5273 trigger: String,
5274 push_to_history: bool,
5275 cx: &mut Context<Self>,
5276 ) -> Task<Result<Option<Transaction>>> {
5277 let position = position.to_point_utf16(buffer.read(cx));
5278 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5279 }
5280
5281 fn on_type_format_impl(
5282 &mut self,
5283 buffer: Entity<Buffer>,
5284 position: PointUtf16,
5285 trigger: String,
5286 push_to_history: bool,
5287 cx: &mut Context<Self>,
5288 ) -> Task<Result<Option<Transaction>>> {
5289 let options = buffer.update(cx, |buffer, cx| {
5290 lsp_command::lsp_formatting_options(
5291 language_settings(
5292 buffer.language_at(position).map(|l| l.name()),
5293 buffer.file(),
5294 cx,
5295 )
5296 .as_ref(),
5297 )
5298 });
5299
5300 cx.spawn(async move |this, cx| {
5301 if let Some(waiter) =
5302 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5303 {
5304 waiter.await?;
5305 }
5306 cx.update(|cx| {
5307 this.update(cx, |this, cx| {
5308 this.request_lsp(
5309 buffer.clone(),
5310 LanguageServerToQuery::FirstCapable,
5311 OnTypeFormatting {
5312 position,
5313 trigger,
5314 options,
5315 push_to_history,
5316 },
5317 cx,
5318 )
5319 })
5320 })??
5321 .await
5322 })
5323 }
5324
5325 pub fn definitions(
5326 &mut self,
5327 buffer: &Entity<Buffer>,
5328 position: PointUtf16,
5329 cx: &mut Context<Self>,
5330 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5331 if let Some((upstream_client, project_id)) = self.upstream_client() {
5332 let request = GetDefinitions { position };
5333 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5334 return Task::ready(Ok(None));
5335 }
5336 let request_task = upstream_client.request_lsp(
5337 project_id,
5338 None,
5339 LSP_REQUEST_TIMEOUT,
5340 cx.background_executor().clone(),
5341 request.to_proto(project_id, buffer.read(cx)),
5342 );
5343 let buffer = buffer.clone();
5344 cx.spawn(async move |weak_lsp_store, cx| {
5345 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5346 return Ok(None);
5347 };
5348 let Some(responses) = request_task.await? else {
5349 return Ok(None);
5350 };
5351 let actions = join_all(responses.payload.into_iter().map(|response| {
5352 GetDefinitions { position }.response_from_proto(
5353 response.response,
5354 lsp_store.clone(),
5355 buffer.clone(),
5356 cx.clone(),
5357 )
5358 }))
5359 .await;
5360
5361 Ok(Some(
5362 actions
5363 .into_iter()
5364 .collect::<Result<Vec<Vec<_>>>>()?
5365 .into_iter()
5366 .flatten()
5367 .dedup()
5368 .collect(),
5369 ))
5370 })
5371 } else {
5372 let definitions_task = self.request_multiple_lsp_locally(
5373 buffer,
5374 Some(position),
5375 GetDefinitions { position },
5376 cx,
5377 );
5378 cx.background_spawn(async move {
5379 Ok(Some(
5380 definitions_task
5381 .await
5382 .into_iter()
5383 .flat_map(|(_, definitions)| definitions)
5384 .dedup()
5385 .collect(),
5386 ))
5387 })
5388 }
5389 }
5390
5391 pub fn declarations(
5392 &mut self,
5393 buffer: &Entity<Buffer>,
5394 position: PointUtf16,
5395 cx: &mut Context<Self>,
5396 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5397 if let Some((upstream_client, project_id)) = self.upstream_client() {
5398 let request = GetDeclarations { position };
5399 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5400 return Task::ready(Ok(None));
5401 }
5402 let request_task = upstream_client.request_lsp(
5403 project_id,
5404 None,
5405 LSP_REQUEST_TIMEOUT,
5406 cx.background_executor().clone(),
5407 request.to_proto(project_id, buffer.read(cx)),
5408 );
5409 let buffer = buffer.clone();
5410 cx.spawn(async move |weak_lsp_store, cx| {
5411 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5412 return Ok(None);
5413 };
5414 let Some(responses) = request_task.await? else {
5415 return Ok(None);
5416 };
5417 let actions = join_all(responses.payload.into_iter().map(|response| {
5418 GetDeclarations { position }.response_from_proto(
5419 response.response,
5420 lsp_store.clone(),
5421 buffer.clone(),
5422 cx.clone(),
5423 )
5424 }))
5425 .await;
5426
5427 Ok(Some(
5428 actions
5429 .into_iter()
5430 .collect::<Result<Vec<Vec<_>>>>()?
5431 .into_iter()
5432 .flatten()
5433 .dedup()
5434 .collect(),
5435 ))
5436 })
5437 } else {
5438 let declarations_task = self.request_multiple_lsp_locally(
5439 buffer,
5440 Some(position),
5441 GetDeclarations { position },
5442 cx,
5443 );
5444 cx.background_spawn(async move {
5445 Ok(Some(
5446 declarations_task
5447 .await
5448 .into_iter()
5449 .flat_map(|(_, declarations)| declarations)
5450 .dedup()
5451 .collect(),
5452 ))
5453 })
5454 }
5455 }
5456
5457 pub fn type_definitions(
5458 &mut self,
5459 buffer: &Entity<Buffer>,
5460 position: PointUtf16,
5461 cx: &mut Context<Self>,
5462 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5463 if let Some((upstream_client, project_id)) = self.upstream_client() {
5464 let request = GetTypeDefinitions { position };
5465 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5466 return Task::ready(Ok(None));
5467 }
5468 let request_task = upstream_client.request_lsp(
5469 project_id,
5470 None,
5471 LSP_REQUEST_TIMEOUT,
5472 cx.background_executor().clone(),
5473 request.to_proto(project_id, buffer.read(cx)),
5474 );
5475 let buffer = buffer.clone();
5476 cx.spawn(async move |weak_lsp_store, cx| {
5477 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5478 return Ok(None);
5479 };
5480 let Some(responses) = request_task.await? else {
5481 return Ok(None);
5482 };
5483 let actions = join_all(responses.payload.into_iter().map(|response| {
5484 GetTypeDefinitions { position }.response_from_proto(
5485 response.response,
5486 lsp_store.clone(),
5487 buffer.clone(),
5488 cx.clone(),
5489 )
5490 }))
5491 .await;
5492
5493 Ok(Some(
5494 actions
5495 .into_iter()
5496 .collect::<Result<Vec<Vec<_>>>>()?
5497 .into_iter()
5498 .flatten()
5499 .dedup()
5500 .collect(),
5501 ))
5502 })
5503 } else {
5504 let type_definitions_task = self.request_multiple_lsp_locally(
5505 buffer,
5506 Some(position),
5507 GetTypeDefinitions { position },
5508 cx,
5509 );
5510 cx.background_spawn(async move {
5511 Ok(Some(
5512 type_definitions_task
5513 .await
5514 .into_iter()
5515 .flat_map(|(_, type_definitions)| type_definitions)
5516 .dedup()
5517 .collect(),
5518 ))
5519 })
5520 }
5521 }
5522
5523 pub fn implementations(
5524 &mut self,
5525 buffer: &Entity<Buffer>,
5526 position: PointUtf16,
5527 cx: &mut Context<Self>,
5528 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5529 if let Some((upstream_client, project_id)) = self.upstream_client() {
5530 let request = GetImplementations { position };
5531 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5532 return Task::ready(Ok(None));
5533 }
5534 let request_task = upstream_client.request_lsp(
5535 project_id,
5536 None,
5537 LSP_REQUEST_TIMEOUT,
5538 cx.background_executor().clone(),
5539 request.to_proto(project_id, buffer.read(cx)),
5540 );
5541 let buffer = buffer.clone();
5542 cx.spawn(async move |weak_lsp_store, cx| {
5543 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5544 return Ok(None);
5545 };
5546 let Some(responses) = request_task.await? else {
5547 return Ok(None);
5548 };
5549 let actions = join_all(responses.payload.into_iter().map(|response| {
5550 GetImplementations { position }.response_from_proto(
5551 response.response,
5552 lsp_store.clone(),
5553 buffer.clone(),
5554 cx.clone(),
5555 )
5556 }))
5557 .await;
5558
5559 Ok(Some(
5560 actions
5561 .into_iter()
5562 .collect::<Result<Vec<Vec<_>>>>()?
5563 .into_iter()
5564 .flatten()
5565 .dedup()
5566 .collect(),
5567 ))
5568 })
5569 } else {
5570 let implementations_task = self.request_multiple_lsp_locally(
5571 buffer,
5572 Some(position),
5573 GetImplementations { position },
5574 cx,
5575 );
5576 cx.background_spawn(async move {
5577 Ok(Some(
5578 implementations_task
5579 .await
5580 .into_iter()
5581 .flat_map(|(_, implementations)| implementations)
5582 .dedup()
5583 .collect(),
5584 ))
5585 })
5586 }
5587 }
5588
5589 pub fn references(
5590 &mut self,
5591 buffer: &Entity<Buffer>,
5592 position: PointUtf16,
5593 cx: &mut Context<Self>,
5594 ) -> Task<Result<Option<Vec<Location>>>> {
5595 if let Some((upstream_client, project_id)) = self.upstream_client() {
5596 let request = GetReferences { position };
5597 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5598 return Task::ready(Ok(None));
5599 }
5600
5601 let request_task = upstream_client.request_lsp(
5602 project_id,
5603 None,
5604 LSP_REQUEST_TIMEOUT,
5605 cx.background_executor().clone(),
5606 request.to_proto(project_id, buffer.read(cx)),
5607 );
5608 let buffer = buffer.clone();
5609 cx.spawn(async move |weak_lsp_store, cx| {
5610 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5611 return Ok(None);
5612 };
5613 let Some(responses) = request_task.await? else {
5614 return Ok(None);
5615 };
5616
5617 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5618 GetReferences { position }.response_from_proto(
5619 lsp_response.response,
5620 lsp_store.clone(),
5621 buffer.clone(),
5622 cx.clone(),
5623 )
5624 }))
5625 .await
5626 .into_iter()
5627 .collect::<Result<Vec<Vec<_>>>>()?
5628 .into_iter()
5629 .flatten()
5630 .dedup()
5631 .collect();
5632 Ok(Some(locations))
5633 })
5634 } else {
5635 let references_task = self.request_multiple_lsp_locally(
5636 buffer,
5637 Some(position),
5638 GetReferences { position },
5639 cx,
5640 );
5641 cx.background_spawn(async move {
5642 Ok(Some(
5643 references_task
5644 .await
5645 .into_iter()
5646 .flat_map(|(_, references)| references)
5647 .dedup()
5648 .collect(),
5649 ))
5650 })
5651 }
5652 }
5653
5654 pub fn code_actions(
5655 &mut self,
5656 buffer: &Entity<Buffer>,
5657 range: Range<Anchor>,
5658 kinds: Option<Vec<CodeActionKind>>,
5659 cx: &mut Context<Self>,
5660 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5661 if let Some((upstream_client, project_id)) = self.upstream_client() {
5662 let request = GetCodeActions {
5663 range: range.clone(),
5664 kinds: kinds.clone(),
5665 };
5666 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5667 return Task::ready(Ok(None));
5668 }
5669 let request_task = upstream_client.request_lsp(
5670 project_id,
5671 None,
5672 LSP_REQUEST_TIMEOUT,
5673 cx.background_executor().clone(),
5674 request.to_proto(project_id, buffer.read(cx)),
5675 );
5676 let buffer = buffer.clone();
5677 cx.spawn(async move |weak_lsp_store, cx| {
5678 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5679 return Ok(None);
5680 };
5681 let Some(responses) = request_task.await? else {
5682 return Ok(None);
5683 };
5684 let actions = join_all(responses.payload.into_iter().map(|response| {
5685 GetCodeActions {
5686 range: range.clone(),
5687 kinds: kinds.clone(),
5688 }
5689 .response_from_proto(
5690 response.response,
5691 lsp_store.clone(),
5692 buffer.clone(),
5693 cx.clone(),
5694 )
5695 }))
5696 .await;
5697
5698 Ok(Some(
5699 actions
5700 .into_iter()
5701 .collect::<Result<Vec<Vec<_>>>>()?
5702 .into_iter()
5703 .flatten()
5704 .collect(),
5705 ))
5706 })
5707 } else {
5708 let all_actions_task = self.request_multiple_lsp_locally(
5709 buffer,
5710 Some(range.start),
5711 GetCodeActions { range, kinds },
5712 cx,
5713 );
5714 cx.background_spawn(async move {
5715 Ok(Some(
5716 all_actions_task
5717 .await
5718 .into_iter()
5719 .flat_map(|(_, actions)| actions)
5720 .collect(),
5721 ))
5722 })
5723 }
5724 }
5725
5726 pub fn code_lens_actions(
5727 &mut self,
5728 buffer: &Entity<Buffer>,
5729 cx: &mut Context<Self>,
5730 ) -> CodeLensTask {
5731 let version_queried_for = buffer.read(cx).version();
5732 let buffer_id = buffer.read(cx).remote_id();
5733 let existing_servers = self.as_local().map(|local| {
5734 local
5735 .buffers_opened_in_servers
5736 .get(&buffer_id)
5737 .cloned()
5738 .unwrap_or_default()
5739 });
5740
5741 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5742 if let Some(cached_lens) = &lsp_data.code_lens {
5743 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5744 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5745 existing_servers != cached_lens.lens.keys().copied().collect()
5746 });
5747 if !has_different_servers {
5748 return Task::ready(Ok(Some(
5749 cached_lens.lens.values().flatten().cloned().collect(),
5750 )))
5751 .shared();
5752 }
5753 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5754 if !version_queried_for.changed_since(updating_for) {
5755 return running_update.clone();
5756 }
5757 }
5758 }
5759 }
5760
5761 let lens_lsp_data = self
5762 .latest_lsp_data(buffer, cx)
5763 .code_lens
5764 .get_or_insert_default();
5765 let buffer = buffer.clone();
5766 let query_version_queried_for = version_queried_for.clone();
5767 let new_task = cx
5768 .spawn(async move |lsp_store, cx| {
5769 cx.background_executor()
5770 .timer(Duration::from_millis(30))
5771 .await;
5772 let fetched_lens = lsp_store
5773 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5774 .map_err(Arc::new)?
5775 .await
5776 .context("fetching code lens")
5777 .map_err(Arc::new);
5778 let fetched_lens = match fetched_lens {
5779 Ok(fetched_lens) => fetched_lens,
5780 Err(e) => {
5781 lsp_store
5782 .update(cx, |lsp_store, _| {
5783 if let Some(lens_lsp_data) = lsp_store
5784 .lsp_data
5785 .get_mut(&buffer_id)
5786 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5787 {
5788 lens_lsp_data.update = None;
5789 }
5790 })
5791 .ok();
5792 return Err(e);
5793 }
5794 };
5795
5796 lsp_store
5797 .update(cx, |lsp_store, _| {
5798 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5799 let code_lens = lsp_data.code_lens.as_mut()?;
5800 if let Some(fetched_lens) = fetched_lens {
5801 if lsp_data.buffer_version == query_version_queried_for {
5802 code_lens.lens.extend(fetched_lens);
5803 } else if !lsp_data
5804 .buffer_version
5805 .changed_since(&query_version_queried_for)
5806 {
5807 lsp_data.buffer_version = query_version_queried_for;
5808 code_lens.lens = fetched_lens;
5809 }
5810 }
5811 code_lens.update = None;
5812 Some(code_lens.lens.values().flatten().cloned().collect())
5813 })
5814 .map_err(Arc::new)
5815 })
5816 .shared();
5817 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5818 new_task
5819 }
5820
5821 fn fetch_code_lens(
5822 &mut self,
5823 buffer: &Entity<Buffer>,
5824 cx: &mut Context<Self>,
5825 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5826 if let Some((upstream_client, project_id)) = self.upstream_client() {
5827 let request = GetCodeLens;
5828 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5829 return Task::ready(Ok(None));
5830 }
5831 let request_task = upstream_client.request_lsp(
5832 project_id,
5833 None,
5834 LSP_REQUEST_TIMEOUT,
5835 cx.background_executor().clone(),
5836 request.to_proto(project_id, buffer.read(cx)),
5837 );
5838 let buffer = buffer.clone();
5839 cx.spawn(async move |weak_lsp_store, cx| {
5840 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5841 return Ok(None);
5842 };
5843 let Some(responses) = request_task.await? else {
5844 return Ok(None);
5845 };
5846
5847 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5848 let lsp_store = lsp_store.clone();
5849 let buffer = buffer.clone();
5850 let cx = cx.clone();
5851 async move {
5852 (
5853 LanguageServerId::from_proto(response.server_id),
5854 GetCodeLens
5855 .response_from_proto(response.response, lsp_store, buffer, cx)
5856 .await,
5857 )
5858 }
5859 }))
5860 .await;
5861
5862 let mut has_errors = false;
5863 let code_lens_actions = code_lens_actions
5864 .into_iter()
5865 .filter_map(|(server_id, code_lens)| match code_lens {
5866 Ok(code_lens) => Some((server_id, code_lens)),
5867 Err(e) => {
5868 has_errors = true;
5869 log::error!("{e:#}");
5870 None
5871 }
5872 })
5873 .collect::<HashMap<_, _>>();
5874 anyhow::ensure!(
5875 !has_errors || !code_lens_actions.is_empty(),
5876 "Failed to fetch code lens"
5877 );
5878 Ok(Some(code_lens_actions))
5879 })
5880 } else {
5881 let code_lens_actions_task =
5882 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5883 cx.background_spawn(async move {
5884 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5885 })
5886 }
5887 }
5888
5889 #[inline(never)]
5890 pub fn completions(
5891 &self,
5892 buffer: &Entity<Buffer>,
5893 position: PointUtf16,
5894 context: CompletionContext,
5895 cx: &mut Context<Self>,
5896 ) -> Task<Result<Vec<CompletionResponse>>> {
5897 let language_registry = self.languages.clone();
5898
5899 if let Some((upstream_client, project_id)) = self.upstream_client() {
5900 let request = GetCompletions { position, context };
5901 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5902 return Task::ready(Ok(Vec::new()));
5903 }
5904 let task = self.send_lsp_proto_request(
5905 buffer.clone(),
5906 upstream_client,
5907 project_id,
5908 request,
5909 cx,
5910 );
5911 let language = buffer.read(cx).language().cloned();
5912
5913 // In the future, we should provide project guests with the names of LSP adapters,
5914 // so that they can use the correct LSP adapter when computing labels. For now,
5915 // guests just use the first LSP adapter associated with the buffer's language.
5916 let lsp_adapter = language.as_ref().and_then(|language| {
5917 language_registry
5918 .lsp_adapters(&language.name())
5919 .first()
5920 .cloned()
5921 });
5922
5923 cx.foreground_executor().spawn(async move {
5924 let completion_response = task.await?;
5925 let completions = populate_labels_for_completions(
5926 completion_response.completions,
5927 language,
5928 lsp_adapter,
5929 )
5930 .await;
5931 Ok(vec![CompletionResponse {
5932 completions,
5933 display_options: CompletionDisplayOptions::default(),
5934 is_incomplete: completion_response.is_incomplete,
5935 }])
5936 })
5937 } else if let Some(local) = self.as_local() {
5938 let snapshot = buffer.read(cx).snapshot();
5939 let offset = position.to_offset(&snapshot);
5940 let scope = snapshot.language_scope_at(offset);
5941 let language = snapshot.language().cloned();
5942 let completion_settings = language_settings(
5943 language.as_ref().map(|language| language.name()),
5944 buffer.read(cx).file(),
5945 cx,
5946 )
5947 .completions
5948 .clone();
5949 if !completion_settings.lsp {
5950 return Task::ready(Ok(Vec::new()));
5951 }
5952
5953 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5954 local
5955 .language_servers_for_buffer(buffer, cx)
5956 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5957 .filter(|(adapter, _)| {
5958 scope
5959 .as_ref()
5960 .map(|scope| scope.language_allowed(&adapter.name))
5961 .unwrap_or(true)
5962 })
5963 .map(|(_, server)| server.server_id())
5964 .collect()
5965 });
5966
5967 let buffer = buffer.clone();
5968 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5969 let lsp_timeout = if lsp_timeout > 0 {
5970 Some(Duration::from_millis(lsp_timeout))
5971 } else {
5972 None
5973 };
5974 cx.spawn(async move |this, cx| {
5975 let mut tasks = Vec::with_capacity(server_ids.len());
5976 this.update(cx, |lsp_store, cx| {
5977 for server_id in server_ids {
5978 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5979 let lsp_timeout = lsp_timeout
5980 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5981 let mut timeout = cx.background_spawn(async move {
5982 match lsp_timeout {
5983 Some(lsp_timeout) => {
5984 lsp_timeout.await;
5985 true
5986 },
5987 None => false,
5988 }
5989 }).fuse();
5990 let mut lsp_request = lsp_store.request_lsp(
5991 buffer.clone(),
5992 LanguageServerToQuery::Other(server_id),
5993 GetCompletions {
5994 position,
5995 context: context.clone(),
5996 },
5997 cx,
5998 ).fuse();
5999 let new_task = cx.background_spawn(async move {
6000 select_biased! {
6001 response = lsp_request => anyhow::Ok(Some(response?)),
6002 timeout_happened = timeout => {
6003 if timeout_happened {
6004 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6005 Ok(None)
6006 } else {
6007 let completions = lsp_request.await?;
6008 Ok(Some(completions))
6009 }
6010 },
6011 }
6012 });
6013 tasks.push((lsp_adapter, new_task));
6014 }
6015 })?;
6016
6017 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6018 let completion_response = task.await.ok()??;
6019 let completions = populate_labels_for_completions(
6020 completion_response.completions,
6021 language.clone(),
6022 lsp_adapter,
6023 )
6024 .await;
6025 Some(CompletionResponse {
6026 completions,
6027 display_options: CompletionDisplayOptions::default(),
6028 is_incomplete: completion_response.is_incomplete,
6029 })
6030 });
6031
6032 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6033
6034 Ok(responses.into_iter().flatten().collect())
6035 })
6036 } else {
6037 Task::ready(Err(anyhow!("No upstream client or local language server")))
6038 }
6039 }
6040
6041 pub fn resolve_completions(
6042 &self,
6043 buffer: Entity<Buffer>,
6044 completion_indices: Vec<usize>,
6045 completions: Rc<RefCell<Box<[Completion]>>>,
6046 cx: &mut Context<Self>,
6047 ) -> Task<Result<bool>> {
6048 let client = self.upstream_client();
6049 let buffer_id = buffer.read(cx).remote_id();
6050 let buffer_snapshot = buffer.read(cx).snapshot();
6051
6052 if !self.check_if_capable_for_proto_request(
6053 &buffer,
6054 GetCompletions::can_resolve_completions,
6055 cx,
6056 ) {
6057 return Task::ready(Ok(false));
6058 }
6059 cx.spawn(async move |lsp_store, cx| {
6060 let mut did_resolve = false;
6061 if let Some((client, project_id)) = client {
6062 for completion_index in completion_indices {
6063 let server_id = {
6064 let completion = &completions.borrow()[completion_index];
6065 completion.source.server_id()
6066 };
6067 if let Some(server_id) = server_id {
6068 if Self::resolve_completion_remote(
6069 project_id,
6070 server_id,
6071 buffer_id,
6072 completions.clone(),
6073 completion_index,
6074 client.clone(),
6075 )
6076 .await
6077 .log_err()
6078 .is_some()
6079 {
6080 did_resolve = true;
6081 }
6082 } else {
6083 resolve_word_completion(
6084 &buffer_snapshot,
6085 &mut completions.borrow_mut()[completion_index],
6086 );
6087 }
6088 }
6089 } else {
6090 for completion_index in completion_indices {
6091 let server_id = {
6092 let completion = &completions.borrow()[completion_index];
6093 completion.source.server_id()
6094 };
6095 if let Some(server_id) = server_id {
6096 let server_and_adapter = lsp_store
6097 .read_with(cx, |lsp_store, _| {
6098 let server = lsp_store.language_server_for_id(server_id)?;
6099 let adapter =
6100 lsp_store.language_server_adapter_for_id(server.server_id())?;
6101 Some((server, adapter))
6102 })
6103 .ok()
6104 .flatten();
6105 let Some((server, adapter)) = server_and_adapter else {
6106 continue;
6107 };
6108
6109 let resolved = Self::resolve_completion_local(
6110 server,
6111 completions.clone(),
6112 completion_index,
6113 )
6114 .await
6115 .log_err()
6116 .is_some();
6117 if resolved {
6118 Self::regenerate_completion_labels(
6119 adapter,
6120 &buffer_snapshot,
6121 completions.clone(),
6122 completion_index,
6123 )
6124 .await
6125 .log_err();
6126 did_resolve = true;
6127 }
6128 } else {
6129 resolve_word_completion(
6130 &buffer_snapshot,
6131 &mut completions.borrow_mut()[completion_index],
6132 );
6133 }
6134 }
6135 }
6136
6137 Ok(did_resolve)
6138 })
6139 }
6140
6141 async fn resolve_completion_local(
6142 server: Arc<lsp::LanguageServer>,
6143 completions: Rc<RefCell<Box<[Completion]>>>,
6144 completion_index: usize,
6145 ) -> Result<()> {
6146 let server_id = server.server_id();
6147 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6148 return Ok(());
6149 }
6150
6151 let request = {
6152 let completion = &completions.borrow()[completion_index];
6153 match &completion.source {
6154 CompletionSource::Lsp {
6155 lsp_completion,
6156 resolved,
6157 server_id: completion_server_id,
6158 ..
6159 } => {
6160 if *resolved {
6161 return Ok(());
6162 }
6163 anyhow::ensure!(
6164 server_id == *completion_server_id,
6165 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6166 );
6167 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6168 }
6169 CompletionSource::BufferWord { .. }
6170 | CompletionSource::Dap { .. }
6171 | CompletionSource::Custom => {
6172 return Ok(());
6173 }
6174 }
6175 };
6176 let resolved_completion = request
6177 .await
6178 .into_response()
6179 .context("resolve completion")?;
6180
6181 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6182 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6183
6184 let mut completions = completions.borrow_mut();
6185 let completion = &mut completions[completion_index];
6186 if let CompletionSource::Lsp {
6187 lsp_completion,
6188 resolved,
6189 server_id: completion_server_id,
6190 ..
6191 } = &mut completion.source
6192 {
6193 if *resolved {
6194 return Ok(());
6195 }
6196 anyhow::ensure!(
6197 server_id == *completion_server_id,
6198 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6199 );
6200 *lsp_completion = Box::new(resolved_completion);
6201 *resolved = true;
6202 }
6203 Ok(())
6204 }
6205
6206 async fn regenerate_completion_labels(
6207 adapter: Arc<CachedLspAdapter>,
6208 snapshot: &BufferSnapshot,
6209 completions: Rc<RefCell<Box<[Completion]>>>,
6210 completion_index: usize,
6211 ) -> Result<()> {
6212 let completion_item = completions.borrow()[completion_index]
6213 .source
6214 .lsp_completion(true)
6215 .map(Cow::into_owned);
6216 if let Some(lsp_documentation) = completion_item
6217 .as_ref()
6218 .and_then(|completion_item| completion_item.documentation.clone())
6219 {
6220 let mut completions = completions.borrow_mut();
6221 let completion = &mut completions[completion_index];
6222 completion.documentation = Some(lsp_documentation.into());
6223 } else {
6224 let mut completions = completions.borrow_mut();
6225 let completion = &mut completions[completion_index];
6226 completion.documentation = Some(CompletionDocumentation::Undocumented);
6227 }
6228
6229 let mut new_label = match completion_item {
6230 Some(completion_item) => {
6231 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6232 // So we have to update the label here anyway...
6233 let language = snapshot.language();
6234 match language {
6235 Some(language) => {
6236 adapter
6237 .labels_for_completions(
6238 std::slice::from_ref(&completion_item),
6239 language,
6240 )
6241 .await?
6242 }
6243 None => Vec::new(),
6244 }
6245 .pop()
6246 .flatten()
6247 .unwrap_or_else(|| {
6248 CodeLabel::fallback_for_completion(
6249 &completion_item,
6250 language.map(|language| language.as_ref()),
6251 )
6252 })
6253 }
6254 None => CodeLabel::plain(
6255 completions.borrow()[completion_index].new_text.clone(),
6256 None,
6257 ),
6258 };
6259 ensure_uniform_list_compatible_label(&mut new_label);
6260
6261 let mut completions = completions.borrow_mut();
6262 let completion = &mut completions[completion_index];
6263 if completion.label.filter_text() == new_label.filter_text() {
6264 completion.label = new_label;
6265 } else {
6266 log::error!(
6267 "Resolved completion changed display label from {} to {}. \
6268 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6269 completion.label.text(),
6270 new_label.text(),
6271 completion.label.filter_text(),
6272 new_label.filter_text()
6273 );
6274 }
6275
6276 Ok(())
6277 }
6278
6279 async fn resolve_completion_remote(
6280 project_id: u64,
6281 server_id: LanguageServerId,
6282 buffer_id: BufferId,
6283 completions: Rc<RefCell<Box<[Completion]>>>,
6284 completion_index: usize,
6285 client: AnyProtoClient,
6286 ) -> Result<()> {
6287 let lsp_completion = {
6288 let completion = &completions.borrow()[completion_index];
6289 match &completion.source {
6290 CompletionSource::Lsp {
6291 lsp_completion,
6292 resolved,
6293 server_id: completion_server_id,
6294 ..
6295 } => {
6296 anyhow::ensure!(
6297 server_id == *completion_server_id,
6298 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6299 );
6300 if *resolved {
6301 return Ok(());
6302 }
6303 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6304 }
6305 CompletionSource::Custom
6306 | CompletionSource::Dap { .. }
6307 | CompletionSource::BufferWord { .. } => {
6308 return Ok(());
6309 }
6310 }
6311 };
6312 let request = proto::ResolveCompletionDocumentation {
6313 project_id,
6314 language_server_id: server_id.0 as u64,
6315 lsp_completion,
6316 buffer_id: buffer_id.into(),
6317 };
6318
6319 let response = client
6320 .request(request)
6321 .await
6322 .context("completion documentation resolve proto request")?;
6323 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6324
6325 let documentation = if response.documentation.is_empty() {
6326 CompletionDocumentation::Undocumented
6327 } else if response.documentation_is_markdown {
6328 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6329 } else if response.documentation.lines().count() <= 1 {
6330 CompletionDocumentation::SingleLine(response.documentation.into())
6331 } else {
6332 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6333 };
6334
6335 let mut completions = completions.borrow_mut();
6336 let completion = &mut completions[completion_index];
6337 completion.documentation = Some(documentation);
6338 if let CompletionSource::Lsp {
6339 insert_range,
6340 lsp_completion,
6341 resolved,
6342 server_id: completion_server_id,
6343 lsp_defaults: _,
6344 } = &mut completion.source
6345 {
6346 let completion_insert_range = response
6347 .old_insert_start
6348 .and_then(deserialize_anchor)
6349 .zip(response.old_insert_end.and_then(deserialize_anchor));
6350 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6351
6352 if *resolved {
6353 return Ok(());
6354 }
6355 anyhow::ensure!(
6356 server_id == *completion_server_id,
6357 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6358 );
6359 *lsp_completion = Box::new(resolved_lsp_completion);
6360 *resolved = true;
6361 }
6362
6363 let replace_range = response
6364 .old_replace_start
6365 .and_then(deserialize_anchor)
6366 .zip(response.old_replace_end.and_then(deserialize_anchor));
6367 if let Some((old_replace_start, old_replace_end)) = replace_range
6368 && !response.new_text.is_empty()
6369 {
6370 completion.new_text = response.new_text;
6371 completion.replace_range = old_replace_start..old_replace_end;
6372 }
6373
6374 Ok(())
6375 }
6376
6377 pub fn apply_additional_edits_for_completion(
6378 &self,
6379 buffer_handle: Entity<Buffer>,
6380 completions: Rc<RefCell<Box<[Completion]>>>,
6381 completion_index: usize,
6382 push_to_history: bool,
6383 cx: &mut Context<Self>,
6384 ) -> Task<Result<Option<Transaction>>> {
6385 if let Some((client, project_id)) = self.upstream_client() {
6386 let buffer = buffer_handle.read(cx);
6387 let buffer_id = buffer.remote_id();
6388 cx.spawn(async move |_, cx| {
6389 let request = {
6390 let completion = completions.borrow()[completion_index].clone();
6391 proto::ApplyCompletionAdditionalEdits {
6392 project_id,
6393 buffer_id: buffer_id.into(),
6394 completion: Some(Self::serialize_completion(&CoreCompletion {
6395 replace_range: completion.replace_range,
6396 new_text: completion.new_text,
6397 source: completion.source,
6398 })),
6399 }
6400 };
6401
6402 if let Some(transaction) = client.request(request).await?.transaction {
6403 let transaction = language::proto::deserialize_transaction(transaction)?;
6404 buffer_handle
6405 .update(cx, |buffer, _| {
6406 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6407 })?
6408 .await?;
6409 if push_to_history {
6410 buffer_handle.update(cx, |buffer, _| {
6411 buffer.push_transaction(transaction.clone(), Instant::now());
6412 buffer.finalize_last_transaction();
6413 })?;
6414 }
6415 Ok(Some(transaction))
6416 } else {
6417 Ok(None)
6418 }
6419 })
6420 } else {
6421 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6422 let completion = &completions.borrow()[completion_index];
6423 let server_id = completion.source.server_id()?;
6424 Some(
6425 self.language_server_for_local_buffer(buffer, server_id, cx)?
6426 .1
6427 .clone(),
6428 )
6429 }) else {
6430 return Task::ready(Ok(None));
6431 };
6432
6433 cx.spawn(async move |this, cx| {
6434 Self::resolve_completion_local(
6435 server.clone(),
6436 completions.clone(),
6437 completion_index,
6438 )
6439 .await
6440 .context("resolving completion")?;
6441 let completion = completions.borrow()[completion_index].clone();
6442 let additional_text_edits = completion
6443 .source
6444 .lsp_completion(true)
6445 .as_ref()
6446 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6447 if let Some(edits) = additional_text_edits {
6448 let edits = this
6449 .update(cx, |this, cx| {
6450 this.as_local_mut().unwrap().edits_from_lsp(
6451 &buffer_handle,
6452 edits,
6453 server.server_id(),
6454 None,
6455 cx,
6456 )
6457 })?
6458 .await?;
6459
6460 buffer_handle.update(cx, |buffer, cx| {
6461 buffer.finalize_last_transaction();
6462 buffer.start_transaction();
6463
6464 for (range, text) in edits {
6465 let primary = &completion.replace_range;
6466
6467 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6468 // and the primary completion is just an insertion (empty range), then this is likely
6469 // an auto-import scenario and should not be considered overlapping
6470 // https://github.com/zed-industries/zed/issues/26136
6471 let is_file_start_auto_import = {
6472 let snapshot = buffer.snapshot();
6473 let primary_start_point = primary.start.to_point(&snapshot);
6474 let range_start_point = range.start.to_point(&snapshot);
6475
6476 let result = primary_start_point.row == 0
6477 && primary_start_point.column == 0
6478 && range_start_point.row == 0
6479 && range_start_point.column == 0;
6480
6481 result
6482 };
6483
6484 let has_overlap = if is_file_start_auto_import {
6485 false
6486 } else {
6487 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6488 && primary.end.cmp(&range.start, buffer).is_ge();
6489 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6490 && range.end.cmp(&primary.end, buffer).is_ge();
6491 let result = start_within || end_within;
6492 result
6493 };
6494
6495 //Skip additional edits which overlap with the primary completion edit
6496 //https://github.com/zed-industries/zed/pull/1871
6497 if !has_overlap {
6498 buffer.edit([(range, text)], None, cx);
6499 }
6500 }
6501
6502 let transaction = if buffer.end_transaction(cx).is_some() {
6503 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6504 if !push_to_history {
6505 buffer.forget_transaction(transaction.id);
6506 }
6507 Some(transaction)
6508 } else {
6509 None
6510 };
6511 Ok(transaction)
6512 })?
6513 } else {
6514 Ok(None)
6515 }
6516 })
6517 }
6518 }
6519
6520 pub fn pull_diagnostics(
6521 &mut self,
6522 buffer: Entity<Buffer>,
6523 cx: &mut Context<Self>,
6524 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6525 let buffer_id = buffer.read(cx).remote_id();
6526
6527 if let Some((client, upstream_project_id)) = self.upstream_client() {
6528 let mut suitable_capabilities = None;
6529 // Are we capable for proto request?
6530 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6531 &buffer,
6532 |capabilities| {
6533 if let Some(caps) = &capabilities.diagnostic_provider {
6534 suitable_capabilities = Some(caps.clone());
6535 true
6536 } else {
6537 false
6538 }
6539 },
6540 cx,
6541 );
6542 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6543 let Some(dynamic_caps) = suitable_capabilities else {
6544 return Task::ready(Ok(None));
6545 };
6546 assert!(any_server_has_diagnostics_provider);
6547
6548 let request = GetDocumentDiagnostics {
6549 previous_result_id: None,
6550 dynamic_caps,
6551 };
6552 let request_task = client.request_lsp(
6553 upstream_project_id,
6554 None,
6555 LSP_REQUEST_TIMEOUT,
6556 cx.background_executor().clone(),
6557 request.to_proto(upstream_project_id, buffer.read(cx)),
6558 );
6559 cx.background_spawn(async move {
6560 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6561 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6562 // Do not attempt to further process the dummy responses here.
6563 let _response = request_task.await?;
6564 Ok(None)
6565 })
6566 } else {
6567 let servers = buffer.update(cx, |buffer, cx| {
6568 self.language_servers_for_local_buffer(buffer, cx)
6569 .map(|(_, server)| server.clone())
6570 .collect::<Vec<_>>()
6571 });
6572
6573 let pull_diagnostics = servers
6574 .into_iter()
6575 .flat_map(|server| {
6576 let result = maybe!({
6577 let local = self.as_local()?;
6578 let server_id = server.server_id();
6579 let providers_with_identifiers = local
6580 .language_server_dynamic_registrations
6581 .get(&server_id)
6582 .into_iter()
6583 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6584 .collect::<Vec<_>>();
6585 Some(
6586 providers_with_identifiers
6587 .into_iter()
6588 .map(|dynamic_caps| {
6589 let result_id = self.result_id(server_id, buffer_id, cx);
6590 self.request_lsp(
6591 buffer.clone(),
6592 LanguageServerToQuery::Other(server_id),
6593 GetDocumentDiagnostics {
6594 previous_result_id: result_id,
6595 dynamic_caps,
6596 },
6597 cx,
6598 )
6599 })
6600 .collect::<Vec<_>>(),
6601 )
6602 });
6603
6604 result.unwrap_or_default()
6605 })
6606 .collect::<Vec<_>>();
6607
6608 cx.background_spawn(async move {
6609 let mut responses = Vec::new();
6610 for diagnostics in join_all(pull_diagnostics).await {
6611 responses.extend(diagnostics?);
6612 }
6613 Ok(Some(responses))
6614 })
6615 }
6616 }
6617
6618 pub fn applicable_inlay_chunks(
6619 &mut self,
6620 buffer: &Entity<Buffer>,
6621 ranges: &[Range<text::Anchor>],
6622 cx: &mut Context<Self>,
6623 ) -> Vec<Range<BufferRow>> {
6624 self.latest_lsp_data(buffer, cx)
6625 .inlay_hints
6626 .applicable_chunks(ranges)
6627 .map(|chunk| chunk.start..chunk.end)
6628 .collect()
6629 }
6630
6631 pub fn invalidate_inlay_hints<'a>(
6632 &'a mut self,
6633 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6634 ) {
6635 for buffer_id in for_buffers {
6636 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6637 lsp_data.inlay_hints.clear();
6638 }
6639 }
6640 }
6641
6642 pub fn inlay_hints(
6643 &mut self,
6644 invalidate: InvalidationStrategy,
6645 buffer: Entity<Buffer>,
6646 ranges: Vec<Range<text::Anchor>>,
6647 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6648 cx: &mut Context<Self>,
6649 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6650 let buffer_snapshot = buffer.read(cx).snapshot();
6651 let next_hint_id = self.next_hint_id.clone();
6652 let lsp_data = self.latest_lsp_data(&buffer, cx);
6653 let mut lsp_refresh_requested = false;
6654 let for_server = if let InvalidationStrategy::RefreshRequested {
6655 server_id,
6656 request_id,
6657 } = invalidate
6658 {
6659 let invalidated = lsp_data
6660 .inlay_hints
6661 .invalidate_for_server_refresh(server_id, request_id);
6662 lsp_refresh_requested = invalidated;
6663 Some(server_id)
6664 } else {
6665 None
6666 };
6667 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6668 let known_chunks = known_chunks
6669 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6670 .map(|(_, known_chunks)| known_chunks)
6671 .unwrap_or_default();
6672
6673 let mut hint_fetch_tasks = Vec::new();
6674 let mut cached_inlay_hints = None;
6675 let mut ranges_to_query = None;
6676 let applicable_chunks = existing_inlay_hints
6677 .applicable_chunks(ranges.as_slice())
6678 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6679 .collect::<Vec<_>>();
6680 if applicable_chunks.is_empty() {
6681 return HashMap::default();
6682 }
6683
6684 let last_chunk_number = existing_inlay_hints.buffer_chunks_len() - 1;
6685
6686 for row_chunk in applicable_chunks {
6687 match (
6688 existing_inlay_hints
6689 .cached_hints(&row_chunk)
6690 .filter(|_| !lsp_refresh_requested)
6691 .cloned(),
6692 existing_inlay_hints
6693 .fetched_hints(&row_chunk)
6694 .as_ref()
6695 .filter(|_| !lsp_refresh_requested)
6696 .cloned(),
6697 ) {
6698 (None, None) => {
6699 let end = if last_chunk_number == row_chunk.id {
6700 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6701 } else {
6702 Point::new(row_chunk.end, 0)
6703 };
6704 ranges_to_query.get_or_insert_with(Vec::new).push((
6705 row_chunk,
6706 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6707 ..buffer_snapshot.anchor_after(end),
6708 ));
6709 }
6710 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6711 (Some(cached_hints), None) => {
6712 for (server_id, cached_hints) in cached_hints {
6713 if for_server.is_none_or(|for_server| for_server == server_id) {
6714 cached_inlay_hints
6715 .get_or_insert_with(HashMap::default)
6716 .entry(row_chunk.start..row_chunk.end)
6717 .or_insert_with(HashMap::default)
6718 .entry(server_id)
6719 .or_insert_with(Vec::new)
6720 .extend(cached_hints);
6721 }
6722 }
6723 }
6724 (Some(cached_hints), Some(fetched_hints)) => {
6725 hint_fetch_tasks.push((row_chunk, fetched_hints));
6726 for (server_id, cached_hints) in cached_hints {
6727 if for_server.is_none_or(|for_server| for_server == server_id) {
6728 cached_inlay_hints
6729 .get_or_insert_with(HashMap::default)
6730 .entry(row_chunk.start..row_chunk.end)
6731 .or_insert_with(HashMap::default)
6732 .entry(server_id)
6733 .or_insert_with(Vec::new)
6734 .extend(cached_hints);
6735 }
6736 }
6737 }
6738 }
6739 }
6740
6741 if hint_fetch_tasks.is_empty()
6742 && ranges_to_query
6743 .as_ref()
6744 .is_none_or(|ranges| ranges.is_empty())
6745 && let Some(cached_inlay_hints) = cached_inlay_hints
6746 {
6747 cached_inlay_hints
6748 .into_iter()
6749 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6750 .collect()
6751 } else {
6752 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6753 let next_hint_id = next_hint_id.clone();
6754 let buffer = buffer.clone();
6755 let new_inlay_hints = cx
6756 .spawn(async move |lsp_store, cx| {
6757 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6758 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6759 })?;
6760 new_fetch_task
6761 .await
6762 .and_then(|new_hints_by_server| {
6763 lsp_store.update(cx, |lsp_store, cx| {
6764 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6765 let update_cache = !lsp_data
6766 .buffer_version
6767 .changed_since(&buffer.read(cx).version());
6768 if new_hints_by_server.is_empty() {
6769 if update_cache {
6770 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6771 }
6772 HashMap::default()
6773 } else {
6774 new_hints_by_server
6775 .into_iter()
6776 .map(|(server_id, new_hints)| {
6777 let new_hints = new_hints
6778 .into_iter()
6779 .map(|new_hint| {
6780 (
6781 InlayId::Hint(next_hint_id.fetch_add(
6782 1,
6783 atomic::Ordering::AcqRel,
6784 )),
6785 new_hint,
6786 )
6787 })
6788 .collect::<Vec<_>>();
6789 if update_cache {
6790 lsp_data.inlay_hints.insert_new_hints(
6791 chunk,
6792 server_id,
6793 new_hints.clone(),
6794 );
6795 }
6796 (server_id, new_hints)
6797 })
6798 .collect()
6799 }
6800 })
6801 })
6802 .map_err(Arc::new)
6803 })
6804 .shared();
6805
6806 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6807 *fetch_task = Some(new_inlay_hints.clone());
6808 hint_fetch_tasks.push((chunk, new_inlay_hints));
6809 }
6810
6811 cached_inlay_hints
6812 .unwrap_or_default()
6813 .into_iter()
6814 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6815 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6816 (
6817 chunk.start..chunk.end,
6818 cx.spawn(async move |_, _| {
6819 hints_fetch.await.map_err(|e| {
6820 if e.error_code() != ErrorCode::Internal {
6821 anyhow!(e.error_code())
6822 } else {
6823 anyhow!("{e:#}")
6824 }
6825 })
6826 }),
6827 )
6828 }))
6829 .collect()
6830 }
6831 }
6832
6833 fn fetch_inlay_hints(
6834 &mut self,
6835 for_server: Option<LanguageServerId>,
6836 buffer: &Entity<Buffer>,
6837 range: Range<Anchor>,
6838 cx: &mut Context<Self>,
6839 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6840 let request = InlayHints {
6841 range: range.clone(),
6842 };
6843 if let Some((upstream_client, project_id)) = self.upstream_client() {
6844 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6845 return Task::ready(Ok(HashMap::default()));
6846 }
6847 let request_task = upstream_client.request_lsp(
6848 project_id,
6849 for_server.map(|id| id.to_proto()),
6850 LSP_REQUEST_TIMEOUT,
6851 cx.background_executor().clone(),
6852 request.to_proto(project_id, buffer.read(cx)),
6853 );
6854 let buffer = buffer.clone();
6855 cx.spawn(async move |weak_lsp_store, cx| {
6856 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6857 return Ok(HashMap::default());
6858 };
6859 let Some(responses) = request_task.await? else {
6860 return Ok(HashMap::default());
6861 };
6862
6863 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6864 let lsp_store = lsp_store.clone();
6865 let buffer = buffer.clone();
6866 let cx = cx.clone();
6867 let request = request.clone();
6868 async move {
6869 (
6870 LanguageServerId::from_proto(response.server_id),
6871 request
6872 .response_from_proto(response.response, lsp_store, buffer, cx)
6873 .await,
6874 )
6875 }
6876 }))
6877 .await;
6878
6879 let mut has_errors = false;
6880 let inlay_hints = inlay_hints
6881 .into_iter()
6882 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6883 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6884 Err(e) => {
6885 has_errors = true;
6886 log::error!("{e:#}");
6887 None
6888 }
6889 })
6890 .collect::<HashMap<_, _>>();
6891 anyhow::ensure!(
6892 !has_errors || !inlay_hints.is_empty(),
6893 "Failed to fetch inlay hints"
6894 );
6895 Ok(inlay_hints)
6896 })
6897 } else {
6898 let inlay_hints_task = match for_server {
6899 Some(server_id) => {
6900 let server_task = self.request_lsp(
6901 buffer.clone(),
6902 LanguageServerToQuery::Other(server_id),
6903 request,
6904 cx,
6905 );
6906 cx.background_spawn(async move {
6907 let mut responses = Vec::new();
6908 match server_task.await {
6909 Ok(response) => responses.push((server_id, response)),
6910 Err(e) => log::error!(
6911 "Error handling response for inlay hints request: {e:#}"
6912 ),
6913 }
6914 responses
6915 })
6916 }
6917 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6918 };
6919 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6920 cx.background_spawn(async move {
6921 Ok(inlay_hints_task
6922 .await
6923 .into_iter()
6924 .map(|(server_id, mut new_hints)| {
6925 new_hints.retain(|hint| {
6926 hint.position.is_valid(&buffer_snapshot)
6927 && range.start.is_valid(&buffer_snapshot)
6928 && range.end.is_valid(&buffer_snapshot)
6929 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6930 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6931 });
6932 (server_id, new_hints)
6933 })
6934 .collect())
6935 })
6936 }
6937 }
6938
6939 pub fn pull_diagnostics_for_buffer(
6940 &mut self,
6941 buffer: Entity<Buffer>,
6942 cx: &mut Context<Self>,
6943 ) -> Task<anyhow::Result<()>> {
6944 let diagnostics = self.pull_diagnostics(buffer, cx);
6945 cx.spawn(async move |lsp_store, cx| {
6946 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6947 return Ok(());
6948 };
6949 lsp_store.update(cx, |lsp_store, cx| {
6950 if lsp_store.as_local().is_none() {
6951 return;
6952 }
6953
6954 let mut unchanged_buffers = HashSet::default();
6955 let mut changed_buffers = HashSet::default();
6956 let server_diagnostics_updates = diagnostics
6957 .into_iter()
6958 .filter_map(|diagnostics_set| match diagnostics_set {
6959 LspPullDiagnostics::Response {
6960 server_id,
6961 uri,
6962 diagnostics,
6963 } => Some((server_id, uri, diagnostics)),
6964 LspPullDiagnostics::Default => None,
6965 })
6966 .fold(
6967 HashMap::default(),
6968 |mut acc, (server_id, uri, diagnostics)| {
6969 let (result_id, diagnostics) = match diagnostics {
6970 PulledDiagnostics::Unchanged { result_id } => {
6971 unchanged_buffers.insert(uri.clone());
6972 (Some(result_id), Vec::new())
6973 }
6974 PulledDiagnostics::Changed {
6975 result_id,
6976 diagnostics,
6977 } => {
6978 changed_buffers.insert(uri.clone());
6979 (result_id, diagnostics)
6980 }
6981 };
6982 let disk_based_sources = Cow::Owned(
6983 lsp_store
6984 .language_server_adapter_for_id(server_id)
6985 .as_ref()
6986 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6987 .unwrap_or(&[])
6988 .to_vec(),
6989 );
6990 acc.entry(server_id).or_insert_with(Vec::new).push(
6991 DocumentDiagnosticsUpdate {
6992 server_id,
6993 diagnostics: lsp::PublishDiagnosticsParams {
6994 uri,
6995 diagnostics,
6996 version: None,
6997 },
6998 result_id,
6999 disk_based_sources,
7000 },
7001 );
7002 acc
7003 },
7004 );
7005
7006 for diagnostic_updates in server_diagnostics_updates.into_values() {
7007 lsp_store
7008 .merge_lsp_diagnostics(
7009 DiagnosticSourceKind::Pulled,
7010 diagnostic_updates,
7011 |buffer, old_diagnostic, cx| {
7012 File::from_dyn(buffer.file())
7013 .and_then(|file| {
7014 let abs_path = file.as_local()?.abs_path(cx);
7015 lsp::Uri::from_file_path(abs_path).ok()
7016 })
7017 .is_none_or(|buffer_uri| {
7018 unchanged_buffers.contains(&buffer_uri)
7019 || match old_diagnostic.source_kind {
7020 DiagnosticSourceKind::Pulled => {
7021 !changed_buffers.contains(&buffer_uri)
7022 }
7023 DiagnosticSourceKind::Other
7024 | DiagnosticSourceKind::Pushed => true,
7025 }
7026 })
7027 },
7028 cx,
7029 )
7030 .log_err();
7031 }
7032 })
7033 })
7034 }
7035
7036 pub fn document_colors(
7037 &mut self,
7038 known_cache_version: Option<usize>,
7039 buffer: Entity<Buffer>,
7040 cx: &mut Context<Self>,
7041 ) -> Option<DocumentColorTask> {
7042 let version_queried_for = buffer.read(cx).version();
7043 let buffer_id = buffer.read(cx).remote_id();
7044
7045 let current_language_servers = self.as_local().map(|local| {
7046 local
7047 .buffers_opened_in_servers
7048 .get(&buffer_id)
7049 .cloned()
7050 .unwrap_or_default()
7051 });
7052
7053 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7054 if let Some(cached_colors) = &lsp_data.document_colors {
7055 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7056 let has_different_servers =
7057 current_language_servers.is_some_and(|current_language_servers| {
7058 current_language_servers
7059 != cached_colors.colors.keys().copied().collect()
7060 });
7061 if !has_different_servers {
7062 let cache_version = cached_colors.cache_version;
7063 if Some(cache_version) == known_cache_version {
7064 return None;
7065 } else {
7066 return Some(
7067 Task::ready(Ok(DocumentColors {
7068 colors: cached_colors
7069 .colors
7070 .values()
7071 .flatten()
7072 .cloned()
7073 .collect(),
7074 cache_version: Some(cache_version),
7075 }))
7076 .shared(),
7077 );
7078 }
7079 }
7080 }
7081 }
7082 }
7083
7084 let color_lsp_data = self
7085 .latest_lsp_data(&buffer, cx)
7086 .document_colors
7087 .get_or_insert_default();
7088 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7089 && !version_queried_for.changed_since(updating_for)
7090 {
7091 return Some(running_update.clone());
7092 }
7093 let buffer_version_queried_for = version_queried_for.clone();
7094 let new_task = cx
7095 .spawn(async move |lsp_store, cx| {
7096 cx.background_executor()
7097 .timer(Duration::from_millis(30))
7098 .await;
7099 let fetched_colors = lsp_store
7100 .update(cx, |lsp_store, cx| {
7101 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7102 })?
7103 .await
7104 .context("fetching document colors")
7105 .map_err(Arc::new);
7106 let fetched_colors = match fetched_colors {
7107 Ok(fetched_colors) => {
7108 if Some(true)
7109 == buffer
7110 .update(cx, |buffer, _| {
7111 buffer.version() != buffer_version_queried_for
7112 })
7113 .ok()
7114 {
7115 return Ok(DocumentColors::default());
7116 }
7117 fetched_colors
7118 }
7119 Err(e) => {
7120 lsp_store
7121 .update(cx, |lsp_store, _| {
7122 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7123 if let Some(document_colors) = &mut lsp_data.document_colors {
7124 document_colors.colors_update = None;
7125 }
7126 }
7127 })
7128 .ok();
7129 return Err(e);
7130 }
7131 };
7132
7133 lsp_store
7134 .update(cx, |lsp_store, cx| {
7135 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7136 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7137
7138 if let Some(fetched_colors) = fetched_colors {
7139 if lsp_data.buffer_version == buffer_version_queried_for {
7140 lsp_colors.colors.extend(fetched_colors);
7141 lsp_colors.cache_version += 1;
7142 } else if !lsp_data
7143 .buffer_version
7144 .changed_since(&buffer_version_queried_for)
7145 {
7146 lsp_data.buffer_version = buffer_version_queried_for;
7147 lsp_colors.colors = fetched_colors;
7148 lsp_colors.cache_version += 1;
7149 }
7150 }
7151 lsp_colors.colors_update = None;
7152 let colors = lsp_colors
7153 .colors
7154 .values()
7155 .flatten()
7156 .cloned()
7157 .collect::<HashSet<_>>();
7158 DocumentColors {
7159 colors,
7160 cache_version: Some(lsp_colors.cache_version),
7161 }
7162 })
7163 .map_err(Arc::new)
7164 })
7165 .shared();
7166 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7167 Some(new_task)
7168 }
7169
7170 fn fetch_document_colors_for_buffer(
7171 &mut self,
7172 buffer: &Entity<Buffer>,
7173 cx: &mut Context<Self>,
7174 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7175 if let Some((client, project_id)) = self.upstream_client() {
7176 let request = GetDocumentColor {};
7177 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7178 return Task::ready(Ok(None));
7179 }
7180
7181 let request_task = client.request_lsp(
7182 project_id,
7183 None,
7184 LSP_REQUEST_TIMEOUT,
7185 cx.background_executor().clone(),
7186 request.to_proto(project_id, buffer.read(cx)),
7187 );
7188 let buffer = buffer.clone();
7189 cx.spawn(async move |lsp_store, cx| {
7190 let Some(lsp_store) = lsp_store.upgrade() else {
7191 return Ok(None);
7192 };
7193 let colors = join_all(
7194 request_task
7195 .await
7196 .log_err()
7197 .flatten()
7198 .map(|response| response.payload)
7199 .unwrap_or_default()
7200 .into_iter()
7201 .map(|color_response| {
7202 let response = request.response_from_proto(
7203 color_response.response,
7204 lsp_store.clone(),
7205 buffer.clone(),
7206 cx.clone(),
7207 );
7208 async move {
7209 (
7210 LanguageServerId::from_proto(color_response.server_id),
7211 response.await.log_err().unwrap_or_default(),
7212 )
7213 }
7214 }),
7215 )
7216 .await
7217 .into_iter()
7218 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7219 acc.entry(server_id)
7220 .or_insert_with(HashSet::default)
7221 .extend(colors);
7222 acc
7223 });
7224 Ok(Some(colors))
7225 })
7226 } else {
7227 let document_colors_task =
7228 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7229 cx.background_spawn(async move {
7230 Ok(Some(
7231 document_colors_task
7232 .await
7233 .into_iter()
7234 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7235 acc.entry(server_id)
7236 .or_insert_with(HashSet::default)
7237 .extend(colors);
7238 acc
7239 })
7240 .into_iter()
7241 .collect(),
7242 ))
7243 })
7244 }
7245 }
7246
7247 pub fn signature_help<T: ToPointUtf16>(
7248 &mut self,
7249 buffer: &Entity<Buffer>,
7250 position: T,
7251 cx: &mut Context<Self>,
7252 ) -> Task<Option<Vec<SignatureHelp>>> {
7253 let position = position.to_point_utf16(buffer.read(cx));
7254
7255 if let Some((client, upstream_project_id)) = self.upstream_client() {
7256 let request = GetSignatureHelp { position };
7257 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7258 return Task::ready(None);
7259 }
7260 let request_task = client.request_lsp(
7261 upstream_project_id,
7262 None,
7263 LSP_REQUEST_TIMEOUT,
7264 cx.background_executor().clone(),
7265 request.to_proto(upstream_project_id, buffer.read(cx)),
7266 );
7267 let buffer = buffer.clone();
7268 cx.spawn(async move |weak_lsp_store, cx| {
7269 let lsp_store = weak_lsp_store.upgrade()?;
7270 let signatures = join_all(
7271 request_task
7272 .await
7273 .log_err()
7274 .flatten()
7275 .map(|response| response.payload)
7276 .unwrap_or_default()
7277 .into_iter()
7278 .map(|response| {
7279 let response = GetSignatureHelp { position }.response_from_proto(
7280 response.response,
7281 lsp_store.clone(),
7282 buffer.clone(),
7283 cx.clone(),
7284 );
7285 async move { response.await.log_err().flatten() }
7286 }),
7287 )
7288 .await
7289 .into_iter()
7290 .flatten()
7291 .collect();
7292 Some(signatures)
7293 })
7294 } else {
7295 let all_actions_task = self.request_multiple_lsp_locally(
7296 buffer,
7297 Some(position),
7298 GetSignatureHelp { position },
7299 cx,
7300 );
7301 cx.background_spawn(async move {
7302 Some(
7303 all_actions_task
7304 .await
7305 .into_iter()
7306 .flat_map(|(_, actions)| actions)
7307 .collect::<Vec<_>>(),
7308 )
7309 })
7310 }
7311 }
7312
7313 pub fn hover(
7314 &mut self,
7315 buffer: &Entity<Buffer>,
7316 position: PointUtf16,
7317 cx: &mut Context<Self>,
7318 ) -> Task<Option<Vec<Hover>>> {
7319 if let Some((client, upstream_project_id)) = self.upstream_client() {
7320 let request = GetHover { position };
7321 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7322 return Task::ready(None);
7323 }
7324 let request_task = client.request_lsp(
7325 upstream_project_id,
7326 None,
7327 LSP_REQUEST_TIMEOUT,
7328 cx.background_executor().clone(),
7329 request.to_proto(upstream_project_id, buffer.read(cx)),
7330 );
7331 let buffer = buffer.clone();
7332 cx.spawn(async move |weak_lsp_store, cx| {
7333 let lsp_store = weak_lsp_store.upgrade()?;
7334 let hovers = join_all(
7335 request_task
7336 .await
7337 .log_err()
7338 .flatten()
7339 .map(|response| response.payload)
7340 .unwrap_or_default()
7341 .into_iter()
7342 .map(|response| {
7343 let response = GetHover { position }.response_from_proto(
7344 response.response,
7345 lsp_store.clone(),
7346 buffer.clone(),
7347 cx.clone(),
7348 );
7349 async move {
7350 response
7351 .await
7352 .log_err()
7353 .flatten()
7354 .and_then(remove_empty_hover_blocks)
7355 }
7356 }),
7357 )
7358 .await
7359 .into_iter()
7360 .flatten()
7361 .collect();
7362 Some(hovers)
7363 })
7364 } else {
7365 let all_actions_task = self.request_multiple_lsp_locally(
7366 buffer,
7367 Some(position),
7368 GetHover { position },
7369 cx,
7370 );
7371 cx.background_spawn(async move {
7372 Some(
7373 all_actions_task
7374 .await
7375 .into_iter()
7376 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7377 .collect::<Vec<Hover>>(),
7378 )
7379 })
7380 }
7381 }
7382
7383 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7384 let language_registry = self.languages.clone();
7385
7386 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7387 let request = upstream_client.request(proto::GetProjectSymbols {
7388 project_id: *project_id,
7389 query: query.to_string(),
7390 });
7391 cx.foreground_executor().spawn(async move {
7392 let response = request.await?;
7393 let mut symbols = Vec::new();
7394 let core_symbols = response
7395 .symbols
7396 .into_iter()
7397 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7398 .collect::<Vec<_>>();
7399 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7400 .await;
7401 Ok(symbols)
7402 })
7403 } else if let Some(local) = self.as_local() {
7404 struct WorkspaceSymbolsResult {
7405 server_id: LanguageServerId,
7406 lsp_adapter: Arc<CachedLspAdapter>,
7407 worktree: WeakEntity<Worktree>,
7408 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7409 }
7410
7411 let mut requests = Vec::new();
7412 let mut requested_servers = BTreeSet::new();
7413 for (seed, state) in local.language_server_ids.iter() {
7414 let Some(worktree_handle) = self
7415 .worktree_store
7416 .read(cx)
7417 .worktree_for_id(seed.worktree_id, cx)
7418 else {
7419 continue;
7420 };
7421 let worktree = worktree_handle.read(cx);
7422 if !worktree.is_visible() {
7423 continue;
7424 }
7425
7426 if !requested_servers.insert(state.id) {
7427 continue;
7428 }
7429
7430 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7431 Some(LanguageServerState::Running {
7432 adapter, server, ..
7433 }) => (adapter.clone(), server),
7434
7435 _ => continue,
7436 };
7437 let supports_workspace_symbol_request =
7438 match server.capabilities().workspace_symbol_provider {
7439 Some(OneOf::Left(supported)) => supported,
7440 Some(OneOf::Right(_)) => true,
7441 None => false,
7442 };
7443 if !supports_workspace_symbol_request {
7444 continue;
7445 }
7446 let worktree_handle = worktree_handle.clone();
7447 let server_id = server.server_id();
7448 requests.push(
7449 server
7450 .request::<lsp::request::WorkspaceSymbolRequest>(
7451 lsp::WorkspaceSymbolParams {
7452 query: query.to_string(),
7453 ..Default::default()
7454 },
7455 )
7456 .map(move |response| {
7457 let lsp_symbols = response.into_response()
7458 .context("workspace symbols request")
7459 .log_err()
7460 .flatten()
7461 .map(|symbol_response| match symbol_response {
7462 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7463 flat_responses.into_iter().map(|lsp_symbol| {
7464 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7465 }).collect::<Vec<_>>()
7466 }
7467 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7468 nested_responses.into_iter().filter_map(|lsp_symbol| {
7469 let location = match lsp_symbol.location {
7470 OneOf::Left(location) => location,
7471 OneOf::Right(_) => {
7472 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7473 return None
7474 }
7475 };
7476 Some((lsp_symbol.name, lsp_symbol.kind, location))
7477 }).collect::<Vec<_>>()
7478 }
7479 }).unwrap_or_default();
7480
7481 WorkspaceSymbolsResult {
7482 server_id,
7483 lsp_adapter,
7484 worktree: worktree_handle.downgrade(),
7485 lsp_symbols,
7486 }
7487 }),
7488 );
7489 }
7490
7491 cx.spawn(async move |this, cx| {
7492 let responses = futures::future::join_all(requests).await;
7493 let this = match this.upgrade() {
7494 Some(this) => this,
7495 None => return Ok(Vec::new()),
7496 };
7497
7498 let mut symbols = Vec::new();
7499 for result in responses {
7500 let core_symbols = this.update(cx, |this, cx| {
7501 result
7502 .lsp_symbols
7503 .into_iter()
7504 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7505 let abs_path = symbol_location.uri.to_file_path().ok()?;
7506 let source_worktree = result.worktree.upgrade()?;
7507 let source_worktree_id = source_worktree.read(cx).id();
7508
7509 let path = if let Some((tree, rel_path)) =
7510 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7511 {
7512 let worktree_id = tree.read(cx).id();
7513 SymbolLocation::InProject(ProjectPath {
7514 worktree_id,
7515 path: rel_path,
7516 })
7517 } else {
7518 SymbolLocation::OutsideProject {
7519 signature: this.symbol_signature(&abs_path),
7520 abs_path: abs_path.into(),
7521 }
7522 };
7523
7524 Some(CoreSymbol {
7525 source_language_server_id: result.server_id,
7526 language_server_name: result.lsp_adapter.name.clone(),
7527 source_worktree_id,
7528 path,
7529 kind: symbol_kind,
7530 name: symbol_name,
7531 range: range_from_lsp(symbol_location.range),
7532 })
7533 })
7534 .collect()
7535 })?;
7536
7537 populate_labels_for_symbols(
7538 core_symbols,
7539 &language_registry,
7540 Some(result.lsp_adapter),
7541 &mut symbols,
7542 )
7543 .await;
7544 }
7545
7546 Ok(symbols)
7547 })
7548 } else {
7549 Task::ready(Err(anyhow!("No upstream client or local language server")))
7550 }
7551 }
7552
7553 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7554 let mut summary = DiagnosticSummary::default();
7555 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7556 summary.error_count += path_summary.error_count;
7557 summary.warning_count += path_summary.warning_count;
7558 }
7559 summary
7560 }
7561
7562 /// Returns the diagnostic summary for a specific project path.
7563 pub fn diagnostic_summary_for_path(
7564 &self,
7565 project_path: &ProjectPath,
7566 _: &App,
7567 ) -> DiagnosticSummary {
7568 if let Some(summaries) = self
7569 .diagnostic_summaries
7570 .get(&project_path.worktree_id)
7571 .and_then(|map| map.get(&project_path.path))
7572 {
7573 let (error_count, warning_count) = summaries.iter().fold(
7574 (0, 0),
7575 |(error_count, warning_count), (_language_server_id, summary)| {
7576 (
7577 error_count + summary.error_count,
7578 warning_count + summary.warning_count,
7579 )
7580 },
7581 );
7582
7583 DiagnosticSummary {
7584 error_count,
7585 warning_count,
7586 }
7587 } else {
7588 DiagnosticSummary::default()
7589 }
7590 }
7591
7592 pub fn diagnostic_summaries<'a>(
7593 &'a self,
7594 include_ignored: bool,
7595 cx: &'a App,
7596 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7597 self.worktree_store
7598 .read(cx)
7599 .visible_worktrees(cx)
7600 .filter_map(|worktree| {
7601 let worktree = worktree.read(cx);
7602 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7603 })
7604 .flat_map(move |(worktree, summaries)| {
7605 let worktree_id = worktree.id();
7606 summaries
7607 .iter()
7608 .filter(move |(path, _)| {
7609 include_ignored
7610 || worktree
7611 .entry_for_path(path.as_ref())
7612 .is_some_and(|entry| !entry.is_ignored)
7613 })
7614 .flat_map(move |(path, summaries)| {
7615 summaries.iter().map(move |(server_id, summary)| {
7616 (
7617 ProjectPath {
7618 worktree_id,
7619 path: path.clone(),
7620 },
7621 *server_id,
7622 *summary,
7623 )
7624 })
7625 })
7626 })
7627 }
7628
7629 pub fn on_buffer_edited(
7630 &mut self,
7631 buffer: Entity<Buffer>,
7632 cx: &mut Context<Self>,
7633 ) -> Option<()> {
7634 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7635 Some(
7636 self.as_local()?
7637 .language_servers_for_buffer(buffer, cx)
7638 .map(|i| i.1.clone())
7639 .collect(),
7640 )
7641 })?;
7642
7643 let buffer = buffer.read(cx);
7644 let file = File::from_dyn(buffer.file())?;
7645 let abs_path = file.as_local()?.abs_path(cx);
7646 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7647 let next_snapshot = buffer.text_snapshot();
7648 for language_server in language_servers {
7649 let language_server = language_server.clone();
7650
7651 let buffer_snapshots = self
7652 .as_local_mut()
7653 .unwrap()
7654 .buffer_snapshots
7655 .get_mut(&buffer.remote_id())
7656 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7657 let previous_snapshot = buffer_snapshots.last()?;
7658
7659 let build_incremental_change = || {
7660 buffer
7661 .edits_since::<Dimensions<PointUtf16, usize>>(
7662 previous_snapshot.snapshot.version(),
7663 )
7664 .map(|edit| {
7665 let edit_start = edit.new.start.0;
7666 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7667 let new_text = next_snapshot
7668 .text_for_range(edit.new.start.1..edit.new.end.1)
7669 .collect();
7670 lsp::TextDocumentContentChangeEvent {
7671 range: Some(lsp::Range::new(
7672 point_to_lsp(edit_start),
7673 point_to_lsp(edit_end),
7674 )),
7675 range_length: None,
7676 text: new_text,
7677 }
7678 })
7679 .collect()
7680 };
7681
7682 let document_sync_kind = language_server
7683 .capabilities()
7684 .text_document_sync
7685 .as_ref()
7686 .and_then(|sync| match sync {
7687 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7688 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7689 });
7690
7691 let content_changes: Vec<_> = match document_sync_kind {
7692 Some(lsp::TextDocumentSyncKind::FULL) => {
7693 vec![lsp::TextDocumentContentChangeEvent {
7694 range: None,
7695 range_length: None,
7696 text: next_snapshot.text(),
7697 }]
7698 }
7699 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7700 _ => {
7701 #[cfg(any(test, feature = "test-support"))]
7702 {
7703 build_incremental_change()
7704 }
7705
7706 #[cfg(not(any(test, feature = "test-support")))]
7707 {
7708 continue;
7709 }
7710 }
7711 };
7712
7713 let next_version = previous_snapshot.version + 1;
7714 buffer_snapshots.push(LspBufferSnapshot {
7715 version: next_version,
7716 snapshot: next_snapshot.clone(),
7717 });
7718
7719 language_server
7720 .notify::<lsp::notification::DidChangeTextDocument>(
7721 lsp::DidChangeTextDocumentParams {
7722 text_document: lsp::VersionedTextDocumentIdentifier::new(
7723 uri.clone(),
7724 next_version,
7725 ),
7726 content_changes,
7727 },
7728 )
7729 .ok();
7730 self.pull_workspace_diagnostics(language_server.server_id());
7731 }
7732
7733 None
7734 }
7735
7736 pub fn on_buffer_saved(
7737 &mut self,
7738 buffer: Entity<Buffer>,
7739 cx: &mut Context<Self>,
7740 ) -> Option<()> {
7741 let file = File::from_dyn(buffer.read(cx).file())?;
7742 let worktree_id = file.worktree_id(cx);
7743 let abs_path = file.as_local()?.abs_path(cx);
7744 let text_document = lsp::TextDocumentIdentifier {
7745 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7746 };
7747 let local = self.as_local()?;
7748
7749 for server in local.language_servers_for_worktree(worktree_id) {
7750 if let Some(include_text) = include_text(server.as_ref()) {
7751 let text = if include_text {
7752 Some(buffer.read(cx).text())
7753 } else {
7754 None
7755 };
7756 server
7757 .notify::<lsp::notification::DidSaveTextDocument>(
7758 lsp::DidSaveTextDocumentParams {
7759 text_document: text_document.clone(),
7760 text,
7761 },
7762 )
7763 .ok();
7764 }
7765 }
7766
7767 let language_servers = buffer.update(cx, |buffer, cx| {
7768 local.language_server_ids_for_buffer(buffer, cx)
7769 });
7770 for language_server_id in language_servers {
7771 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7772 }
7773
7774 None
7775 }
7776
7777 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7778 maybe!(async move {
7779 let mut refreshed_servers = HashSet::default();
7780 let servers = lsp_store
7781 .update(cx, |lsp_store, cx| {
7782 let local = lsp_store.as_local()?;
7783
7784 let servers = local
7785 .language_server_ids
7786 .iter()
7787 .filter_map(|(seed, state)| {
7788 let worktree = lsp_store
7789 .worktree_store
7790 .read(cx)
7791 .worktree_for_id(seed.worktree_id, cx);
7792 let delegate: Arc<dyn LspAdapterDelegate> =
7793 worktree.map(|worktree| {
7794 LocalLspAdapterDelegate::new(
7795 local.languages.clone(),
7796 &local.environment,
7797 cx.weak_entity(),
7798 &worktree,
7799 local.http_client.clone(),
7800 local.fs.clone(),
7801 cx,
7802 )
7803 })?;
7804 let server_id = state.id;
7805
7806 let states = local.language_servers.get(&server_id)?;
7807
7808 match states {
7809 LanguageServerState::Starting { .. } => None,
7810 LanguageServerState::Running {
7811 adapter, server, ..
7812 } => {
7813 let adapter = adapter.clone();
7814 let server = server.clone();
7815 refreshed_servers.insert(server.name());
7816 let toolchain = seed.toolchain.clone();
7817 Some(cx.spawn(async move |_, cx| {
7818 let settings =
7819 LocalLspStore::workspace_configuration_for_adapter(
7820 adapter.adapter.clone(),
7821 &delegate,
7822 toolchain,
7823 cx,
7824 )
7825 .await
7826 .ok()?;
7827 server
7828 .notify::<lsp::notification::DidChangeConfiguration>(
7829 lsp::DidChangeConfigurationParams { settings },
7830 )
7831 .ok()?;
7832 Some(())
7833 }))
7834 }
7835 }
7836 })
7837 .collect::<Vec<_>>();
7838
7839 Some(servers)
7840 })
7841 .ok()
7842 .flatten()?;
7843
7844 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7845 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7846 // to stop and unregister its language server wrapper.
7847 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7848 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7849 let _: Vec<Option<()>> = join_all(servers).await;
7850
7851 Some(())
7852 })
7853 .await;
7854 }
7855
7856 fn maintain_workspace_config(
7857 external_refresh_requests: watch::Receiver<()>,
7858 cx: &mut Context<Self>,
7859 ) -> Task<Result<()>> {
7860 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7861 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7862
7863 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7864 *settings_changed_tx.borrow_mut() = ();
7865 });
7866
7867 let mut joint_future =
7868 futures::stream::select(settings_changed_rx, external_refresh_requests);
7869 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7870 // - 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).
7871 // - 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.
7872 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7873 // - 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,
7874 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7875 cx.spawn(async move |this, cx| {
7876 while let Some(()) = joint_future.next().await {
7877 this.update(cx, |this, cx| {
7878 this.refresh_server_tree(cx);
7879 })
7880 .ok();
7881
7882 Self::refresh_workspace_configurations(&this, cx).await;
7883 }
7884
7885 drop(settings_observation);
7886 anyhow::Ok(())
7887 })
7888 }
7889
7890 pub fn language_servers_for_local_buffer<'a>(
7891 &'a self,
7892 buffer: &Buffer,
7893 cx: &mut App,
7894 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7895 let local = self.as_local();
7896 let language_server_ids = local
7897 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7898 .unwrap_or_default();
7899
7900 language_server_ids
7901 .into_iter()
7902 .filter_map(
7903 move |server_id| match local?.language_servers.get(&server_id)? {
7904 LanguageServerState::Running {
7905 adapter, server, ..
7906 } => Some((adapter, server)),
7907 _ => None,
7908 },
7909 )
7910 }
7911
7912 pub fn language_server_for_local_buffer<'a>(
7913 &'a self,
7914 buffer: &'a Buffer,
7915 server_id: LanguageServerId,
7916 cx: &'a mut App,
7917 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7918 self.as_local()?
7919 .language_servers_for_buffer(buffer, cx)
7920 .find(|(_, s)| s.server_id() == server_id)
7921 }
7922
7923 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7924 self.diagnostic_summaries.remove(&id_to_remove);
7925 if let Some(local) = self.as_local_mut() {
7926 let to_remove = local.remove_worktree(id_to_remove, cx);
7927 for server in to_remove {
7928 self.language_server_statuses.remove(&server);
7929 }
7930 }
7931 }
7932
7933 pub fn shared(
7934 &mut self,
7935 project_id: u64,
7936 downstream_client: AnyProtoClient,
7937 _: &mut Context<Self>,
7938 ) {
7939 self.downstream_client = Some((downstream_client.clone(), project_id));
7940
7941 for (server_id, status) in &self.language_server_statuses {
7942 if let Some(server) = self.language_server_for_id(*server_id) {
7943 downstream_client
7944 .send(proto::StartLanguageServer {
7945 project_id,
7946 server: Some(proto::LanguageServer {
7947 id: server_id.to_proto(),
7948 name: status.name.to_string(),
7949 worktree_id: status.worktree.map(|id| id.to_proto()),
7950 }),
7951 capabilities: serde_json::to_string(&server.capabilities())
7952 .expect("serializing server LSP capabilities"),
7953 })
7954 .log_err();
7955 }
7956 }
7957 }
7958
7959 pub fn disconnected_from_host(&mut self) {
7960 self.downstream_client.take();
7961 }
7962
7963 pub fn disconnected_from_ssh_remote(&mut self) {
7964 if let LspStoreMode::Remote(RemoteLspStore {
7965 upstream_client, ..
7966 }) = &mut self.mode
7967 {
7968 upstream_client.take();
7969 }
7970 }
7971
7972 pub(crate) fn set_language_server_statuses_from_proto(
7973 &mut self,
7974 project: WeakEntity<Project>,
7975 language_servers: Vec<proto::LanguageServer>,
7976 server_capabilities: Vec<String>,
7977 cx: &mut Context<Self>,
7978 ) {
7979 let lsp_logs = cx
7980 .try_global::<GlobalLogStore>()
7981 .map(|lsp_store| lsp_store.0.clone());
7982
7983 self.language_server_statuses = language_servers
7984 .into_iter()
7985 .zip(server_capabilities)
7986 .map(|(server, server_capabilities)| {
7987 let server_id = LanguageServerId(server.id as usize);
7988 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7989 self.lsp_server_capabilities
7990 .insert(server_id, server_capabilities);
7991 }
7992
7993 let name = LanguageServerName::from_proto(server.name);
7994 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7995
7996 if let Some(lsp_logs) = &lsp_logs {
7997 lsp_logs.update(cx, |lsp_logs, cx| {
7998 lsp_logs.add_language_server(
7999 // Only remote clients get their language servers set from proto
8000 LanguageServerKind::Remote {
8001 project: project.clone(),
8002 },
8003 server_id,
8004 Some(name.clone()),
8005 worktree,
8006 None,
8007 cx,
8008 );
8009 });
8010 }
8011
8012 (
8013 server_id,
8014 LanguageServerStatus {
8015 name,
8016 pending_work: Default::default(),
8017 has_pending_diagnostic_updates: false,
8018 progress_tokens: Default::default(),
8019 worktree,
8020 },
8021 )
8022 })
8023 .collect();
8024 }
8025
8026 #[cfg(test)]
8027 pub fn update_diagnostic_entries(
8028 &mut self,
8029 server_id: LanguageServerId,
8030 abs_path: PathBuf,
8031 result_id: Option<String>,
8032 version: Option<i32>,
8033 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8034 cx: &mut Context<Self>,
8035 ) -> anyhow::Result<()> {
8036 self.merge_diagnostic_entries(
8037 vec![DocumentDiagnosticsUpdate {
8038 diagnostics: DocumentDiagnostics {
8039 diagnostics,
8040 document_abs_path: abs_path,
8041 version,
8042 },
8043 result_id,
8044 server_id,
8045 disk_based_sources: Cow::Borrowed(&[]),
8046 }],
8047 |_, _, _| false,
8048 cx,
8049 )?;
8050 Ok(())
8051 }
8052
8053 pub fn merge_diagnostic_entries<'a>(
8054 &mut self,
8055 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8056 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8057 cx: &mut Context<Self>,
8058 ) -> anyhow::Result<()> {
8059 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8060 let mut updated_diagnostics_paths = HashMap::default();
8061 for mut update in diagnostic_updates {
8062 let abs_path = &update.diagnostics.document_abs_path;
8063 let server_id = update.server_id;
8064 let Some((worktree, relative_path)) =
8065 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8066 else {
8067 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8068 return Ok(());
8069 };
8070
8071 let worktree_id = worktree.read(cx).id();
8072 let project_path = ProjectPath {
8073 worktree_id,
8074 path: relative_path,
8075 };
8076
8077 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8078 let snapshot = buffer_handle.read(cx).snapshot();
8079 let buffer = buffer_handle.read(cx);
8080 let reused_diagnostics = buffer
8081 .buffer_diagnostics(Some(server_id))
8082 .iter()
8083 .filter(|v| merge(buffer, &v.diagnostic, cx))
8084 .map(|v| {
8085 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8086 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8087 DiagnosticEntry {
8088 range: start..end,
8089 diagnostic: v.diagnostic.clone(),
8090 }
8091 })
8092 .collect::<Vec<_>>();
8093
8094 self.as_local_mut()
8095 .context("cannot merge diagnostics on a remote LspStore")?
8096 .update_buffer_diagnostics(
8097 &buffer_handle,
8098 server_id,
8099 update.result_id,
8100 update.diagnostics.version,
8101 update.diagnostics.diagnostics.clone(),
8102 reused_diagnostics.clone(),
8103 cx,
8104 )?;
8105
8106 update.diagnostics.diagnostics.extend(reused_diagnostics);
8107 }
8108
8109 let updated = worktree.update(cx, |worktree, cx| {
8110 self.update_worktree_diagnostics(
8111 worktree.id(),
8112 server_id,
8113 project_path.path.clone(),
8114 update.diagnostics.diagnostics,
8115 cx,
8116 )
8117 })?;
8118 match updated {
8119 ControlFlow::Continue(new_summary) => {
8120 if let Some((project_id, new_summary)) = new_summary {
8121 match &mut diagnostics_summary {
8122 Some(diagnostics_summary) => {
8123 diagnostics_summary
8124 .more_summaries
8125 .push(proto::DiagnosticSummary {
8126 path: project_path.path.as_ref().to_proto(),
8127 language_server_id: server_id.0 as u64,
8128 error_count: new_summary.error_count,
8129 warning_count: new_summary.warning_count,
8130 })
8131 }
8132 None => {
8133 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8134 project_id,
8135 worktree_id: worktree_id.to_proto(),
8136 summary: Some(proto::DiagnosticSummary {
8137 path: project_path.path.as_ref().to_proto(),
8138 language_server_id: server_id.0 as u64,
8139 error_count: new_summary.error_count,
8140 warning_count: new_summary.warning_count,
8141 }),
8142 more_summaries: Vec::new(),
8143 })
8144 }
8145 }
8146 }
8147 updated_diagnostics_paths
8148 .entry(server_id)
8149 .or_insert_with(Vec::new)
8150 .push(project_path);
8151 }
8152 ControlFlow::Break(()) => {}
8153 }
8154 }
8155
8156 if let Some((diagnostics_summary, (downstream_client, _))) =
8157 diagnostics_summary.zip(self.downstream_client.as_ref())
8158 {
8159 downstream_client.send(diagnostics_summary).log_err();
8160 }
8161 for (server_id, paths) in updated_diagnostics_paths {
8162 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8163 }
8164 Ok(())
8165 }
8166
8167 fn update_worktree_diagnostics(
8168 &mut self,
8169 worktree_id: WorktreeId,
8170 server_id: LanguageServerId,
8171 path_in_worktree: Arc<RelPath>,
8172 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8173 _: &mut Context<Worktree>,
8174 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8175 let local = match &mut self.mode {
8176 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8177 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8178 };
8179
8180 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8181 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8182 let summaries_by_server_id = summaries_for_tree
8183 .entry(path_in_worktree.clone())
8184 .or_default();
8185
8186 let old_summary = summaries_by_server_id
8187 .remove(&server_id)
8188 .unwrap_or_default();
8189
8190 let new_summary = DiagnosticSummary::new(&diagnostics);
8191 if new_summary.is_empty() {
8192 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8193 {
8194 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8195 diagnostics_by_server_id.remove(ix);
8196 }
8197 if diagnostics_by_server_id.is_empty() {
8198 diagnostics_for_tree.remove(&path_in_worktree);
8199 }
8200 }
8201 } else {
8202 summaries_by_server_id.insert(server_id, new_summary);
8203 let diagnostics_by_server_id = diagnostics_for_tree
8204 .entry(path_in_worktree.clone())
8205 .or_default();
8206 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8207 Ok(ix) => {
8208 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8209 }
8210 Err(ix) => {
8211 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8212 }
8213 }
8214 }
8215
8216 if !old_summary.is_empty() || !new_summary.is_empty() {
8217 if let Some((_, project_id)) = &self.downstream_client {
8218 Ok(ControlFlow::Continue(Some((
8219 *project_id,
8220 proto::DiagnosticSummary {
8221 path: path_in_worktree.to_proto(),
8222 language_server_id: server_id.0 as u64,
8223 error_count: new_summary.error_count as u32,
8224 warning_count: new_summary.warning_count as u32,
8225 },
8226 ))))
8227 } else {
8228 Ok(ControlFlow::Continue(None))
8229 }
8230 } else {
8231 Ok(ControlFlow::Break(()))
8232 }
8233 }
8234
8235 pub fn open_buffer_for_symbol(
8236 &mut self,
8237 symbol: &Symbol,
8238 cx: &mut Context<Self>,
8239 ) -> Task<Result<Entity<Buffer>>> {
8240 if let Some((client, project_id)) = self.upstream_client() {
8241 let request = client.request(proto::OpenBufferForSymbol {
8242 project_id,
8243 symbol: Some(Self::serialize_symbol(symbol)),
8244 });
8245 cx.spawn(async move |this, cx| {
8246 let response = request.await?;
8247 let buffer_id = BufferId::new(response.buffer_id)?;
8248 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8249 .await
8250 })
8251 } else if let Some(local) = self.as_local() {
8252 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8253 seed.worktree_id == symbol.source_worktree_id
8254 && state.id == symbol.source_language_server_id
8255 && symbol.language_server_name == seed.name
8256 });
8257 if !is_valid {
8258 return Task::ready(Err(anyhow!(
8259 "language server for worktree and language not found"
8260 )));
8261 };
8262
8263 let symbol_abs_path = match &symbol.path {
8264 SymbolLocation::InProject(project_path) => self
8265 .worktree_store
8266 .read(cx)
8267 .absolutize(&project_path, cx)
8268 .context("no such worktree"),
8269 SymbolLocation::OutsideProject {
8270 abs_path,
8271 signature: _,
8272 } => Ok(abs_path.to_path_buf()),
8273 };
8274 let symbol_abs_path = match symbol_abs_path {
8275 Ok(abs_path) => abs_path,
8276 Err(err) => return Task::ready(Err(err)),
8277 };
8278 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8279 uri
8280 } else {
8281 return Task::ready(Err(anyhow!("invalid symbol path")));
8282 };
8283
8284 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8285 } else {
8286 Task::ready(Err(anyhow!("no upstream client or local store")))
8287 }
8288 }
8289
8290 pub(crate) fn open_local_buffer_via_lsp(
8291 &mut self,
8292 abs_path: lsp::Uri,
8293 language_server_id: LanguageServerId,
8294 cx: &mut Context<Self>,
8295 ) -> Task<Result<Entity<Buffer>>> {
8296 cx.spawn(async move |lsp_store, cx| {
8297 // Escape percent-encoded string.
8298 let current_scheme = abs_path.scheme().to_owned();
8299 // Uri is immutable, so we can't modify the scheme
8300
8301 let abs_path = abs_path
8302 .to_file_path()
8303 .map_err(|()| anyhow!("can't convert URI to path"))?;
8304 let p = abs_path.clone();
8305 let yarn_worktree = lsp_store
8306 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8307 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8308 cx.spawn(async move |this, cx| {
8309 let t = this
8310 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8311 .ok()?;
8312 t.await
8313 })
8314 }),
8315 None => Task::ready(None),
8316 })?
8317 .await;
8318 let (worktree_root_target, known_relative_path) =
8319 if let Some((zip_root, relative_path)) = yarn_worktree {
8320 (zip_root, Some(relative_path))
8321 } else {
8322 (Arc::<Path>::from(abs_path.as_path()), None)
8323 };
8324 let (worktree, relative_path) = if let Some(result) =
8325 lsp_store.update(cx, |lsp_store, cx| {
8326 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8327 worktree_store.find_worktree(&worktree_root_target, cx)
8328 })
8329 })? {
8330 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8331 (result.0, relative_path)
8332 } else {
8333 let worktree = lsp_store
8334 .update(cx, |lsp_store, cx| {
8335 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8336 worktree_store.create_worktree(&worktree_root_target, false, cx)
8337 })
8338 })?
8339 .await?;
8340 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8341 lsp_store
8342 .update(cx, |lsp_store, cx| {
8343 if let Some(local) = lsp_store.as_local_mut() {
8344 local.register_language_server_for_invisible_worktree(
8345 &worktree,
8346 language_server_id,
8347 cx,
8348 )
8349 }
8350 })
8351 .ok();
8352 }
8353 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8354 let relative_path = if let Some(known_path) = known_relative_path {
8355 known_path
8356 } else {
8357 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8358 .into_arc()
8359 };
8360 (worktree, relative_path)
8361 };
8362 let project_path = ProjectPath {
8363 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8364 path: relative_path,
8365 };
8366 lsp_store
8367 .update(cx, |lsp_store, cx| {
8368 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8369 buffer_store.open_buffer(project_path, cx)
8370 })
8371 })?
8372 .await
8373 })
8374 }
8375
8376 fn request_multiple_lsp_locally<P, R>(
8377 &mut self,
8378 buffer: &Entity<Buffer>,
8379 position: Option<P>,
8380 request: R,
8381 cx: &mut Context<Self>,
8382 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8383 where
8384 P: ToOffset,
8385 R: LspCommand + Clone,
8386 <R::LspRequest as lsp::request::Request>::Result: Send,
8387 <R::LspRequest as lsp::request::Request>::Params: Send,
8388 {
8389 let Some(local) = self.as_local() else {
8390 return Task::ready(Vec::new());
8391 };
8392
8393 let snapshot = buffer.read(cx).snapshot();
8394 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8395
8396 let server_ids = buffer.update(cx, |buffer, cx| {
8397 local
8398 .language_servers_for_buffer(buffer, cx)
8399 .filter(|(adapter, _)| {
8400 scope
8401 .as_ref()
8402 .map(|scope| scope.language_allowed(&adapter.name))
8403 .unwrap_or(true)
8404 })
8405 .map(|(_, server)| server.server_id())
8406 .filter(|server_id| {
8407 self.as_local().is_none_or(|local| {
8408 local
8409 .buffers_opened_in_servers
8410 .get(&snapshot.remote_id())
8411 .is_some_and(|servers| servers.contains(server_id))
8412 })
8413 })
8414 .collect::<Vec<_>>()
8415 });
8416
8417 let mut response_results = server_ids
8418 .into_iter()
8419 .map(|server_id| {
8420 let task = self.request_lsp(
8421 buffer.clone(),
8422 LanguageServerToQuery::Other(server_id),
8423 request.clone(),
8424 cx,
8425 );
8426 async move { (server_id, task.await) }
8427 })
8428 .collect::<FuturesUnordered<_>>();
8429
8430 cx.background_spawn(async move {
8431 let mut responses = Vec::with_capacity(response_results.len());
8432 while let Some((server_id, response_result)) = response_results.next().await {
8433 match response_result {
8434 Ok(response) => responses.push((server_id, response)),
8435 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8436 }
8437 }
8438 responses
8439 })
8440 }
8441
8442 async fn handle_lsp_command<T: LspCommand>(
8443 this: Entity<Self>,
8444 envelope: TypedEnvelope<T::ProtoRequest>,
8445 mut cx: AsyncApp,
8446 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8447 where
8448 <T::LspRequest as lsp::request::Request>::Params: Send,
8449 <T::LspRequest as lsp::request::Request>::Result: Send,
8450 {
8451 let sender_id = envelope.original_sender_id().unwrap_or_default();
8452 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8453 let buffer_handle = this.update(&mut cx, |this, cx| {
8454 this.buffer_store.read(cx).get_existing(buffer_id)
8455 })??;
8456 let request = T::from_proto(
8457 envelope.payload,
8458 this.clone(),
8459 buffer_handle.clone(),
8460 cx.clone(),
8461 )
8462 .await?;
8463 let response = this
8464 .update(&mut cx, |this, cx| {
8465 this.request_lsp(
8466 buffer_handle.clone(),
8467 LanguageServerToQuery::FirstCapable,
8468 request,
8469 cx,
8470 )
8471 })?
8472 .await?;
8473 this.update(&mut cx, |this, cx| {
8474 Ok(T::response_to_proto(
8475 response,
8476 this,
8477 sender_id,
8478 &buffer_handle.read(cx).version(),
8479 cx,
8480 ))
8481 })?
8482 }
8483
8484 async fn handle_lsp_query(
8485 lsp_store: Entity<Self>,
8486 envelope: TypedEnvelope<proto::LspQuery>,
8487 mut cx: AsyncApp,
8488 ) -> Result<proto::Ack> {
8489 use proto::lsp_query::Request;
8490 let sender_id = envelope.original_sender_id().unwrap_or_default();
8491 let lsp_query = envelope.payload;
8492 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8493 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8494 match lsp_query.request.context("invalid LSP query request")? {
8495 Request::GetReferences(get_references) => {
8496 let position = get_references.position.clone().and_then(deserialize_anchor);
8497 Self::query_lsp_locally::<GetReferences>(
8498 lsp_store,
8499 server_id,
8500 sender_id,
8501 lsp_request_id,
8502 get_references,
8503 position,
8504 &mut cx,
8505 )
8506 .await?;
8507 }
8508 Request::GetDocumentColor(get_document_color) => {
8509 Self::query_lsp_locally::<GetDocumentColor>(
8510 lsp_store,
8511 server_id,
8512 sender_id,
8513 lsp_request_id,
8514 get_document_color,
8515 None,
8516 &mut cx,
8517 )
8518 .await?;
8519 }
8520 Request::GetHover(get_hover) => {
8521 let position = get_hover.position.clone().and_then(deserialize_anchor);
8522 Self::query_lsp_locally::<GetHover>(
8523 lsp_store,
8524 server_id,
8525 sender_id,
8526 lsp_request_id,
8527 get_hover,
8528 position,
8529 &mut cx,
8530 )
8531 .await?;
8532 }
8533 Request::GetCodeActions(get_code_actions) => {
8534 Self::query_lsp_locally::<GetCodeActions>(
8535 lsp_store,
8536 server_id,
8537 sender_id,
8538 lsp_request_id,
8539 get_code_actions,
8540 None,
8541 &mut cx,
8542 )
8543 .await?;
8544 }
8545 Request::GetSignatureHelp(get_signature_help) => {
8546 let position = get_signature_help
8547 .position
8548 .clone()
8549 .and_then(deserialize_anchor);
8550 Self::query_lsp_locally::<GetSignatureHelp>(
8551 lsp_store,
8552 server_id,
8553 sender_id,
8554 lsp_request_id,
8555 get_signature_help,
8556 position,
8557 &mut cx,
8558 )
8559 .await?;
8560 }
8561 Request::GetCodeLens(get_code_lens) => {
8562 Self::query_lsp_locally::<GetCodeLens>(
8563 lsp_store,
8564 server_id,
8565 sender_id,
8566 lsp_request_id,
8567 get_code_lens,
8568 None,
8569 &mut cx,
8570 )
8571 .await?;
8572 }
8573 Request::GetDefinition(get_definition) => {
8574 let position = get_definition.position.clone().and_then(deserialize_anchor);
8575 Self::query_lsp_locally::<GetDefinitions>(
8576 lsp_store,
8577 server_id,
8578 sender_id,
8579 lsp_request_id,
8580 get_definition,
8581 position,
8582 &mut cx,
8583 )
8584 .await?;
8585 }
8586 Request::GetDeclaration(get_declaration) => {
8587 let position = get_declaration
8588 .position
8589 .clone()
8590 .and_then(deserialize_anchor);
8591 Self::query_lsp_locally::<GetDeclarations>(
8592 lsp_store,
8593 server_id,
8594 sender_id,
8595 lsp_request_id,
8596 get_declaration,
8597 position,
8598 &mut cx,
8599 )
8600 .await?;
8601 }
8602 Request::GetTypeDefinition(get_type_definition) => {
8603 let position = get_type_definition
8604 .position
8605 .clone()
8606 .and_then(deserialize_anchor);
8607 Self::query_lsp_locally::<GetTypeDefinitions>(
8608 lsp_store,
8609 server_id,
8610 sender_id,
8611 lsp_request_id,
8612 get_type_definition,
8613 position,
8614 &mut cx,
8615 )
8616 .await?;
8617 }
8618 Request::GetImplementation(get_implementation) => {
8619 let position = get_implementation
8620 .position
8621 .clone()
8622 .and_then(deserialize_anchor);
8623 Self::query_lsp_locally::<GetImplementations>(
8624 lsp_store,
8625 server_id,
8626 sender_id,
8627 lsp_request_id,
8628 get_implementation,
8629 position,
8630 &mut cx,
8631 )
8632 .await?;
8633 }
8634 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8635 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8636 let version = deserialize_version(get_document_diagnostics.buffer_version());
8637 let buffer = lsp_store.update(&mut cx, |this, cx| {
8638 this.buffer_store.read(cx).get_existing(buffer_id)
8639 })??;
8640 buffer
8641 .update(&mut cx, |buffer, _| {
8642 buffer.wait_for_version(version.clone())
8643 })?
8644 .await?;
8645 lsp_store.update(&mut cx, |lsp_store, cx| {
8646 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8647 let key = LspKey {
8648 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8649 server_queried: server_id,
8650 };
8651 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8652 ) {
8653 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8654 lsp_requests.clear();
8655 };
8656 }
8657
8658 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8659 existing_queries.insert(
8660 lsp_request_id,
8661 cx.spawn(async move |lsp_store, cx| {
8662 let diagnostics_pull = lsp_store
8663 .update(cx, |lsp_store, cx| {
8664 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8665 })
8666 .ok();
8667 if let Some(diagnostics_pull) = diagnostics_pull {
8668 match diagnostics_pull.await {
8669 Ok(()) => {}
8670 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8671 };
8672 }
8673 }),
8674 );
8675 })?;
8676 }
8677 Request::InlayHints(inlay_hints) => {
8678 let query_start = inlay_hints
8679 .start
8680 .clone()
8681 .and_then(deserialize_anchor)
8682 .context("invalid inlay hints range start")?;
8683 let query_end = inlay_hints
8684 .end
8685 .clone()
8686 .and_then(deserialize_anchor)
8687 .context("invalid inlay hints range end")?;
8688 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8689 &lsp_store,
8690 server_id,
8691 lsp_request_id,
8692 &inlay_hints,
8693 query_start..query_end,
8694 &mut cx,
8695 )
8696 .await
8697 .context("preparing inlay hints request")?;
8698 Self::query_lsp_locally::<InlayHints>(
8699 lsp_store,
8700 server_id,
8701 sender_id,
8702 lsp_request_id,
8703 inlay_hints,
8704 None,
8705 &mut cx,
8706 )
8707 .await
8708 .context("querying for inlay hints")?
8709 }
8710 }
8711 Ok(proto::Ack {})
8712 }
8713
8714 async fn handle_lsp_query_response(
8715 lsp_store: Entity<Self>,
8716 envelope: TypedEnvelope<proto::LspQueryResponse>,
8717 cx: AsyncApp,
8718 ) -> Result<()> {
8719 lsp_store.read_with(&cx, |lsp_store, _| {
8720 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8721 upstream_client.handle_lsp_response(envelope.clone());
8722 }
8723 })?;
8724 Ok(())
8725 }
8726
8727 async fn handle_apply_code_action(
8728 this: Entity<Self>,
8729 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8730 mut cx: AsyncApp,
8731 ) -> Result<proto::ApplyCodeActionResponse> {
8732 let sender_id = envelope.original_sender_id().unwrap_or_default();
8733 let action =
8734 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8735 let apply_code_action = this.update(&mut cx, |this, cx| {
8736 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8737 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8738 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8739 })??;
8740
8741 let project_transaction = apply_code_action.await?;
8742 let project_transaction = this.update(&mut cx, |this, cx| {
8743 this.buffer_store.update(cx, |buffer_store, cx| {
8744 buffer_store.serialize_project_transaction_for_peer(
8745 project_transaction,
8746 sender_id,
8747 cx,
8748 )
8749 })
8750 })?;
8751 Ok(proto::ApplyCodeActionResponse {
8752 transaction: Some(project_transaction),
8753 })
8754 }
8755
8756 async fn handle_register_buffer_with_language_servers(
8757 this: Entity<Self>,
8758 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8759 mut cx: AsyncApp,
8760 ) -> Result<proto::Ack> {
8761 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8762 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8763 this.update(&mut cx, |this, cx| {
8764 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8765 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8766 project_id: upstream_project_id,
8767 buffer_id: buffer_id.to_proto(),
8768 only_servers: envelope.payload.only_servers,
8769 });
8770 }
8771
8772 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8773 anyhow::bail!("buffer is not open");
8774 };
8775
8776 let handle = this.register_buffer_with_language_servers(
8777 &buffer,
8778 envelope
8779 .payload
8780 .only_servers
8781 .into_iter()
8782 .filter_map(|selector| {
8783 Some(match selector.selector? {
8784 proto::language_server_selector::Selector::ServerId(server_id) => {
8785 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8786 }
8787 proto::language_server_selector::Selector::Name(name) => {
8788 LanguageServerSelector::Name(LanguageServerName(
8789 SharedString::from(name),
8790 ))
8791 }
8792 })
8793 })
8794 .collect(),
8795 false,
8796 cx,
8797 );
8798 this.buffer_store().update(cx, |buffer_store, _| {
8799 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8800 });
8801
8802 Ok(())
8803 })??;
8804 Ok(proto::Ack {})
8805 }
8806
8807 async fn handle_rename_project_entry(
8808 this: Entity<Self>,
8809 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8810 mut cx: AsyncApp,
8811 ) -> Result<proto::ProjectEntryResponse> {
8812 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8813 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8814 let new_path =
8815 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8816
8817 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8818 .update(&mut cx, |this, cx| {
8819 let (worktree, entry) = this
8820 .worktree_store
8821 .read(cx)
8822 .worktree_and_entry_for_id(entry_id, cx)?;
8823 let new_worktree = this
8824 .worktree_store
8825 .read(cx)
8826 .worktree_for_id(new_worktree_id, cx)?;
8827 Some((
8828 this.worktree_store.clone(),
8829 worktree,
8830 new_worktree,
8831 entry.clone(),
8832 ))
8833 })?
8834 .context("worktree not found")?;
8835 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8836 (worktree.absolutize(&old_entry.path), worktree.id())
8837 })?;
8838 let new_abs_path =
8839 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8840
8841 let _transaction = Self::will_rename_entry(
8842 this.downgrade(),
8843 old_worktree_id,
8844 &old_abs_path,
8845 &new_abs_path,
8846 old_entry.is_dir(),
8847 cx.clone(),
8848 )
8849 .await;
8850 let response = WorktreeStore::handle_rename_project_entry(
8851 worktree_store,
8852 envelope.payload,
8853 cx.clone(),
8854 )
8855 .await;
8856 this.read_with(&cx, |this, _| {
8857 this.did_rename_entry(
8858 old_worktree_id,
8859 &old_abs_path,
8860 &new_abs_path,
8861 old_entry.is_dir(),
8862 );
8863 })
8864 .ok();
8865 response
8866 }
8867
8868 async fn handle_update_diagnostic_summary(
8869 this: Entity<Self>,
8870 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8871 mut cx: AsyncApp,
8872 ) -> Result<()> {
8873 this.update(&mut cx, |lsp_store, cx| {
8874 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8875 let mut updated_diagnostics_paths = HashMap::default();
8876 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8877 for message_summary in envelope
8878 .payload
8879 .summary
8880 .into_iter()
8881 .chain(envelope.payload.more_summaries)
8882 {
8883 let project_path = ProjectPath {
8884 worktree_id,
8885 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8886 };
8887 let path = project_path.path.clone();
8888 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8889 let summary = DiagnosticSummary {
8890 error_count: message_summary.error_count as usize,
8891 warning_count: message_summary.warning_count as usize,
8892 };
8893
8894 if summary.is_empty() {
8895 if let Some(worktree_summaries) =
8896 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8897 && let Some(summaries) = worktree_summaries.get_mut(&path)
8898 {
8899 summaries.remove(&server_id);
8900 if summaries.is_empty() {
8901 worktree_summaries.remove(&path);
8902 }
8903 }
8904 } else {
8905 lsp_store
8906 .diagnostic_summaries
8907 .entry(worktree_id)
8908 .or_default()
8909 .entry(path)
8910 .or_default()
8911 .insert(server_id, summary);
8912 }
8913
8914 if let Some((_, project_id)) = &lsp_store.downstream_client {
8915 match &mut diagnostics_summary {
8916 Some(diagnostics_summary) => {
8917 diagnostics_summary
8918 .more_summaries
8919 .push(proto::DiagnosticSummary {
8920 path: project_path.path.as_ref().to_proto(),
8921 language_server_id: server_id.0 as u64,
8922 error_count: summary.error_count as u32,
8923 warning_count: summary.warning_count as u32,
8924 })
8925 }
8926 None => {
8927 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8928 project_id: *project_id,
8929 worktree_id: worktree_id.to_proto(),
8930 summary: Some(proto::DiagnosticSummary {
8931 path: project_path.path.as_ref().to_proto(),
8932 language_server_id: server_id.0 as u64,
8933 error_count: summary.error_count as u32,
8934 warning_count: summary.warning_count as u32,
8935 }),
8936 more_summaries: Vec::new(),
8937 })
8938 }
8939 }
8940 }
8941 updated_diagnostics_paths
8942 .entry(server_id)
8943 .or_insert_with(Vec::new)
8944 .push(project_path);
8945 }
8946
8947 if let Some((diagnostics_summary, (downstream_client, _))) =
8948 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8949 {
8950 downstream_client.send(diagnostics_summary).log_err();
8951 }
8952 for (server_id, paths) in updated_diagnostics_paths {
8953 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8954 }
8955 Ok(())
8956 })?
8957 }
8958
8959 async fn handle_start_language_server(
8960 lsp_store: Entity<Self>,
8961 envelope: TypedEnvelope<proto::StartLanguageServer>,
8962 mut cx: AsyncApp,
8963 ) -> Result<()> {
8964 let server = envelope.payload.server.context("invalid server")?;
8965 let server_capabilities =
8966 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8967 .with_context(|| {
8968 format!(
8969 "incorrect server capabilities {}",
8970 envelope.payload.capabilities
8971 )
8972 })?;
8973 lsp_store.update(&mut cx, |lsp_store, cx| {
8974 let server_id = LanguageServerId(server.id as usize);
8975 let server_name = LanguageServerName::from_proto(server.name.clone());
8976 lsp_store
8977 .lsp_server_capabilities
8978 .insert(server_id, server_capabilities);
8979 lsp_store.language_server_statuses.insert(
8980 server_id,
8981 LanguageServerStatus {
8982 name: server_name.clone(),
8983 pending_work: Default::default(),
8984 has_pending_diagnostic_updates: false,
8985 progress_tokens: Default::default(),
8986 worktree: server.worktree_id.map(WorktreeId::from_proto),
8987 },
8988 );
8989 cx.emit(LspStoreEvent::LanguageServerAdded(
8990 server_id,
8991 server_name,
8992 server.worktree_id.map(WorktreeId::from_proto),
8993 ));
8994 cx.notify();
8995 })?;
8996 Ok(())
8997 }
8998
8999 async fn handle_update_language_server(
9000 lsp_store: Entity<Self>,
9001 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9002 mut cx: AsyncApp,
9003 ) -> Result<()> {
9004 lsp_store.update(&mut cx, |lsp_store, cx| {
9005 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9006
9007 match envelope.payload.variant.context("invalid variant")? {
9008 proto::update_language_server::Variant::WorkStart(payload) => {
9009 lsp_store.on_lsp_work_start(
9010 language_server_id,
9011 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9012 .context("invalid progress token value")?,
9013 LanguageServerProgress {
9014 title: payload.title,
9015 is_disk_based_diagnostics_progress: false,
9016 is_cancellable: payload.is_cancellable.unwrap_or(false),
9017 message: payload.message,
9018 percentage: payload.percentage.map(|p| p as usize),
9019 last_update_at: cx.background_executor().now(),
9020 },
9021 cx,
9022 );
9023 }
9024 proto::update_language_server::Variant::WorkProgress(payload) => {
9025 lsp_store.on_lsp_work_progress(
9026 language_server_id,
9027 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9028 .context("invalid progress token value")?,
9029 LanguageServerProgress {
9030 title: None,
9031 is_disk_based_diagnostics_progress: false,
9032 is_cancellable: payload.is_cancellable.unwrap_or(false),
9033 message: payload.message,
9034 percentage: payload.percentage.map(|p| p as usize),
9035 last_update_at: cx.background_executor().now(),
9036 },
9037 cx,
9038 );
9039 }
9040
9041 proto::update_language_server::Variant::WorkEnd(payload) => {
9042 lsp_store.on_lsp_work_end(
9043 language_server_id,
9044 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9045 .context("invalid progress token value")?,
9046 cx,
9047 );
9048 }
9049
9050 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9051 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9052 }
9053
9054 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9055 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9056 }
9057
9058 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9059 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9060 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9061 cx.emit(LspStoreEvent::LanguageServerUpdate {
9062 language_server_id,
9063 name: envelope
9064 .payload
9065 .server_name
9066 .map(SharedString::new)
9067 .map(LanguageServerName),
9068 message: non_lsp,
9069 });
9070 }
9071 }
9072
9073 Ok(())
9074 })?
9075 }
9076
9077 async fn handle_language_server_log(
9078 this: Entity<Self>,
9079 envelope: TypedEnvelope<proto::LanguageServerLog>,
9080 mut cx: AsyncApp,
9081 ) -> Result<()> {
9082 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9083 let log_type = envelope
9084 .payload
9085 .log_type
9086 .map(LanguageServerLogType::from_proto)
9087 .context("invalid language server log type")?;
9088
9089 let message = envelope.payload.message;
9090
9091 this.update(&mut cx, |_, cx| {
9092 cx.emit(LspStoreEvent::LanguageServerLog(
9093 language_server_id,
9094 log_type,
9095 message,
9096 ));
9097 })
9098 }
9099
9100 async fn handle_lsp_ext_cancel_flycheck(
9101 lsp_store: Entity<Self>,
9102 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9103 cx: AsyncApp,
9104 ) -> Result<proto::Ack> {
9105 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9106 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9107 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9108 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9109 } else {
9110 None
9111 }
9112 })?;
9113 if let Some(task) = task {
9114 task.context("handling lsp ext cancel flycheck")?;
9115 }
9116
9117 Ok(proto::Ack {})
9118 }
9119
9120 async fn handle_lsp_ext_run_flycheck(
9121 lsp_store: Entity<Self>,
9122 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9123 mut cx: AsyncApp,
9124 ) -> Result<proto::Ack> {
9125 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9126 lsp_store.update(&mut cx, |lsp_store, cx| {
9127 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9128 let text_document = if envelope.payload.current_file_only {
9129 let buffer_id = envelope
9130 .payload
9131 .buffer_id
9132 .map(|id| BufferId::new(id))
9133 .transpose()?;
9134 buffer_id
9135 .and_then(|buffer_id| {
9136 lsp_store
9137 .buffer_store()
9138 .read(cx)
9139 .get(buffer_id)
9140 .and_then(|buffer| {
9141 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9142 })
9143 .map(|path| make_text_document_identifier(&path))
9144 })
9145 .transpose()?
9146 } else {
9147 None
9148 };
9149 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9150 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9151 )?;
9152 }
9153 anyhow::Ok(())
9154 })??;
9155
9156 Ok(proto::Ack {})
9157 }
9158
9159 async fn handle_lsp_ext_clear_flycheck(
9160 lsp_store: Entity<Self>,
9161 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9162 cx: AsyncApp,
9163 ) -> Result<proto::Ack> {
9164 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9165 lsp_store
9166 .read_with(&cx, |lsp_store, _| {
9167 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9168 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9169 } else {
9170 None
9171 }
9172 })
9173 .context("handling lsp ext clear flycheck")?;
9174
9175 Ok(proto::Ack {})
9176 }
9177
9178 pub fn disk_based_diagnostics_started(
9179 &mut self,
9180 language_server_id: LanguageServerId,
9181 cx: &mut Context<Self>,
9182 ) {
9183 if let Some(language_server_status) =
9184 self.language_server_statuses.get_mut(&language_server_id)
9185 {
9186 language_server_status.has_pending_diagnostic_updates = true;
9187 }
9188
9189 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9190 cx.emit(LspStoreEvent::LanguageServerUpdate {
9191 language_server_id,
9192 name: self
9193 .language_server_adapter_for_id(language_server_id)
9194 .map(|adapter| adapter.name()),
9195 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9196 Default::default(),
9197 ),
9198 })
9199 }
9200
9201 pub fn disk_based_diagnostics_finished(
9202 &mut self,
9203 language_server_id: LanguageServerId,
9204 cx: &mut Context<Self>,
9205 ) {
9206 if let Some(language_server_status) =
9207 self.language_server_statuses.get_mut(&language_server_id)
9208 {
9209 language_server_status.has_pending_diagnostic_updates = false;
9210 }
9211
9212 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9213 cx.emit(LspStoreEvent::LanguageServerUpdate {
9214 language_server_id,
9215 name: self
9216 .language_server_adapter_for_id(language_server_id)
9217 .map(|adapter| adapter.name()),
9218 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9219 Default::default(),
9220 ),
9221 })
9222 }
9223
9224 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9225 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9226 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9227 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9228 // the language server might take some time to publish diagnostics.
9229 fn simulate_disk_based_diagnostics_events_if_needed(
9230 &mut self,
9231 language_server_id: LanguageServerId,
9232 cx: &mut Context<Self>,
9233 ) {
9234 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9235
9236 let Some(LanguageServerState::Running {
9237 simulate_disk_based_diagnostics_completion,
9238 adapter,
9239 ..
9240 }) = self
9241 .as_local_mut()
9242 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9243 else {
9244 return;
9245 };
9246
9247 if adapter.disk_based_diagnostics_progress_token.is_some() {
9248 return;
9249 }
9250
9251 let prev_task =
9252 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9253 cx.background_executor()
9254 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9255 .await;
9256
9257 this.update(cx, |this, cx| {
9258 this.disk_based_diagnostics_finished(language_server_id, cx);
9259
9260 if let Some(LanguageServerState::Running {
9261 simulate_disk_based_diagnostics_completion,
9262 ..
9263 }) = this.as_local_mut().and_then(|local_store| {
9264 local_store.language_servers.get_mut(&language_server_id)
9265 }) {
9266 *simulate_disk_based_diagnostics_completion = None;
9267 }
9268 })
9269 .ok();
9270 }));
9271
9272 if prev_task.is_none() {
9273 self.disk_based_diagnostics_started(language_server_id, cx);
9274 }
9275 }
9276
9277 pub fn language_server_statuses(
9278 &self,
9279 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9280 self.language_server_statuses
9281 .iter()
9282 .map(|(key, value)| (*key, value))
9283 }
9284
9285 pub(super) fn did_rename_entry(
9286 &self,
9287 worktree_id: WorktreeId,
9288 old_path: &Path,
9289 new_path: &Path,
9290 is_dir: bool,
9291 ) {
9292 maybe!({
9293 let local_store = self.as_local()?;
9294
9295 let old_uri = lsp::Uri::from_file_path(old_path)
9296 .ok()
9297 .map(|uri| uri.to_string())?;
9298 let new_uri = lsp::Uri::from_file_path(new_path)
9299 .ok()
9300 .map(|uri| uri.to_string())?;
9301
9302 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9303 let Some(filter) = local_store
9304 .language_server_paths_watched_for_rename
9305 .get(&language_server.server_id())
9306 else {
9307 continue;
9308 };
9309
9310 if filter.should_send_did_rename(&old_uri, is_dir) {
9311 language_server
9312 .notify::<DidRenameFiles>(RenameFilesParams {
9313 files: vec![FileRename {
9314 old_uri: old_uri.clone(),
9315 new_uri: new_uri.clone(),
9316 }],
9317 })
9318 .ok();
9319 }
9320 }
9321 Some(())
9322 });
9323 }
9324
9325 pub(super) fn will_rename_entry(
9326 this: WeakEntity<Self>,
9327 worktree_id: WorktreeId,
9328 old_path: &Path,
9329 new_path: &Path,
9330 is_dir: bool,
9331 cx: AsyncApp,
9332 ) -> Task<ProjectTransaction> {
9333 let old_uri = lsp::Uri::from_file_path(old_path)
9334 .ok()
9335 .map(|uri| uri.to_string());
9336 let new_uri = lsp::Uri::from_file_path(new_path)
9337 .ok()
9338 .map(|uri| uri.to_string());
9339 cx.spawn(async move |cx| {
9340 let mut tasks = vec![];
9341 this.update(cx, |this, cx| {
9342 let local_store = this.as_local()?;
9343 let old_uri = old_uri?;
9344 let new_uri = new_uri?;
9345 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9346 let Some(filter) = local_store
9347 .language_server_paths_watched_for_rename
9348 .get(&language_server.server_id())
9349 else {
9350 continue;
9351 };
9352
9353 if filter.should_send_will_rename(&old_uri, is_dir) {
9354 let apply_edit = cx.spawn({
9355 let old_uri = old_uri.clone();
9356 let new_uri = new_uri.clone();
9357 let language_server = language_server.clone();
9358 async move |this, cx| {
9359 let edit = language_server
9360 .request::<WillRenameFiles>(RenameFilesParams {
9361 files: vec![FileRename { old_uri, new_uri }],
9362 })
9363 .await
9364 .into_response()
9365 .context("will rename files")
9366 .log_err()
9367 .flatten()?;
9368
9369 let transaction = LocalLspStore::deserialize_workspace_edit(
9370 this.upgrade()?,
9371 edit,
9372 false,
9373 language_server.clone(),
9374 cx,
9375 )
9376 .await
9377 .ok()?;
9378 Some(transaction)
9379 }
9380 });
9381 tasks.push(apply_edit);
9382 }
9383 }
9384 Some(())
9385 })
9386 .ok()
9387 .flatten();
9388 let mut merged_transaction = ProjectTransaction::default();
9389 for task in tasks {
9390 // Await on tasks sequentially so that the order of application of edits is deterministic
9391 // (at least with regards to the order of registration of language servers)
9392 if let Some(transaction) = task.await {
9393 for (buffer, buffer_transaction) in transaction.0 {
9394 merged_transaction.0.insert(buffer, buffer_transaction);
9395 }
9396 }
9397 }
9398 merged_transaction
9399 })
9400 }
9401
9402 fn lsp_notify_abs_paths_changed(
9403 &mut self,
9404 server_id: LanguageServerId,
9405 changes: Vec<PathEvent>,
9406 ) {
9407 maybe!({
9408 let server = self.language_server_for_id(server_id)?;
9409 let changes = changes
9410 .into_iter()
9411 .filter_map(|event| {
9412 let typ = match event.kind? {
9413 PathEventKind::Created => lsp::FileChangeType::CREATED,
9414 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9415 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9416 };
9417 Some(lsp::FileEvent {
9418 uri: file_path_to_lsp_url(&event.path).log_err()?,
9419 typ,
9420 })
9421 })
9422 .collect::<Vec<_>>();
9423 if !changes.is_empty() {
9424 server
9425 .notify::<lsp::notification::DidChangeWatchedFiles>(
9426 lsp::DidChangeWatchedFilesParams { changes },
9427 )
9428 .ok();
9429 }
9430 Some(())
9431 });
9432 }
9433
9434 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9435 self.as_local()?.language_server_for_id(id)
9436 }
9437
9438 fn on_lsp_progress(
9439 &mut self,
9440 progress_params: lsp::ProgressParams,
9441 language_server_id: LanguageServerId,
9442 disk_based_diagnostics_progress_token: Option<String>,
9443 cx: &mut Context<Self>,
9444 ) {
9445 match progress_params.value {
9446 lsp::ProgressParamsValue::WorkDone(progress) => {
9447 self.handle_work_done_progress(
9448 progress,
9449 language_server_id,
9450 disk_based_diagnostics_progress_token,
9451 ProgressToken::from_lsp(progress_params.token),
9452 cx,
9453 );
9454 }
9455 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9456 let identifier = match progress_params.token {
9457 lsp::NumberOrString::Number(_) => None,
9458 lsp::NumberOrString::String(token) => token
9459 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9460 .map(|(_, id)| id.to_owned()),
9461 };
9462 if let Some(LanguageServerState::Running {
9463 workspace_diagnostics_refresh_tasks,
9464 ..
9465 }) = self
9466 .as_local_mut()
9467 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9468 && let Some(workspace_diagnostics) =
9469 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9470 {
9471 workspace_diagnostics.progress_tx.try_send(()).ok();
9472 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9473 }
9474 }
9475 }
9476 }
9477
9478 fn handle_work_done_progress(
9479 &mut self,
9480 progress: lsp::WorkDoneProgress,
9481 language_server_id: LanguageServerId,
9482 disk_based_diagnostics_progress_token: Option<String>,
9483 token: ProgressToken,
9484 cx: &mut Context<Self>,
9485 ) {
9486 let language_server_status =
9487 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9488 status
9489 } else {
9490 return;
9491 };
9492
9493 if !language_server_status.progress_tokens.contains(&token) {
9494 return;
9495 }
9496
9497 let is_disk_based_diagnostics_progress =
9498 if let (Some(disk_based_token), ProgressToken::String(token)) =
9499 (&disk_based_diagnostics_progress_token, &token)
9500 {
9501 token.starts_with(disk_based_token)
9502 } else {
9503 false
9504 };
9505
9506 match progress {
9507 lsp::WorkDoneProgress::Begin(report) => {
9508 if is_disk_based_diagnostics_progress {
9509 self.disk_based_diagnostics_started(language_server_id, cx);
9510 }
9511 self.on_lsp_work_start(
9512 language_server_id,
9513 token.clone(),
9514 LanguageServerProgress {
9515 title: Some(report.title),
9516 is_disk_based_diagnostics_progress,
9517 is_cancellable: report.cancellable.unwrap_or(false),
9518 message: report.message.clone(),
9519 percentage: report.percentage.map(|p| p as usize),
9520 last_update_at: cx.background_executor().now(),
9521 },
9522 cx,
9523 );
9524 }
9525 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9526 language_server_id,
9527 token,
9528 LanguageServerProgress {
9529 title: None,
9530 is_disk_based_diagnostics_progress,
9531 is_cancellable: report.cancellable.unwrap_or(false),
9532 message: report.message,
9533 percentage: report.percentage.map(|p| p as usize),
9534 last_update_at: cx.background_executor().now(),
9535 },
9536 cx,
9537 ),
9538 lsp::WorkDoneProgress::End(_) => {
9539 language_server_status.progress_tokens.remove(&token);
9540 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9541 if is_disk_based_diagnostics_progress {
9542 self.disk_based_diagnostics_finished(language_server_id, cx);
9543 }
9544 }
9545 }
9546 }
9547
9548 fn on_lsp_work_start(
9549 &mut self,
9550 language_server_id: LanguageServerId,
9551 token: ProgressToken,
9552 progress: LanguageServerProgress,
9553 cx: &mut Context<Self>,
9554 ) {
9555 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9556 status.pending_work.insert(token.clone(), progress.clone());
9557 cx.notify();
9558 }
9559 cx.emit(LspStoreEvent::LanguageServerUpdate {
9560 language_server_id,
9561 name: self
9562 .language_server_adapter_for_id(language_server_id)
9563 .map(|adapter| adapter.name()),
9564 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9565 token: Some(token.to_proto()),
9566 title: progress.title,
9567 message: progress.message,
9568 percentage: progress.percentage.map(|p| p as u32),
9569 is_cancellable: Some(progress.is_cancellable),
9570 }),
9571 })
9572 }
9573
9574 fn on_lsp_work_progress(
9575 &mut self,
9576 language_server_id: LanguageServerId,
9577 token: ProgressToken,
9578 progress: LanguageServerProgress,
9579 cx: &mut Context<Self>,
9580 ) {
9581 let mut did_update = false;
9582 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9583 match status.pending_work.entry(token.clone()) {
9584 btree_map::Entry::Vacant(entry) => {
9585 entry.insert(progress.clone());
9586 did_update = true;
9587 }
9588 btree_map::Entry::Occupied(mut entry) => {
9589 let entry = entry.get_mut();
9590 if (progress.last_update_at - entry.last_update_at)
9591 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9592 {
9593 entry.last_update_at = progress.last_update_at;
9594 if progress.message.is_some() {
9595 entry.message = progress.message.clone();
9596 }
9597 if progress.percentage.is_some() {
9598 entry.percentage = progress.percentage;
9599 }
9600 if progress.is_cancellable != entry.is_cancellable {
9601 entry.is_cancellable = progress.is_cancellable;
9602 }
9603 did_update = true;
9604 }
9605 }
9606 }
9607 }
9608
9609 if did_update {
9610 cx.emit(LspStoreEvent::LanguageServerUpdate {
9611 language_server_id,
9612 name: self
9613 .language_server_adapter_for_id(language_server_id)
9614 .map(|adapter| adapter.name()),
9615 message: proto::update_language_server::Variant::WorkProgress(
9616 proto::LspWorkProgress {
9617 token: Some(token.to_proto()),
9618 message: progress.message,
9619 percentage: progress.percentage.map(|p| p as u32),
9620 is_cancellable: Some(progress.is_cancellable),
9621 },
9622 ),
9623 })
9624 }
9625 }
9626
9627 fn on_lsp_work_end(
9628 &mut self,
9629 language_server_id: LanguageServerId,
9630 token: ProgressToken,
9631 cx: &mut Context<Self>,
9632 ) {
9633 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9634 if let Some(work) = status.pending_work.remove(&token)
9635 && !work.is_disk_based_diagnostics_progress
9636 {
9637 cx.emit(LspStoreEvent::RefreshInlayHints {
9638 server_id: language_server_id,
9639 request_id: None,
9640 });
9641 }
9642 cx.notify();
9643 }
9644
9645 cx.emit(LspStoreEvent::LanguageServerUpdate {
9646 language_server_id,
9647 name: self
9648 .language_server_adapter_for_id(language_server_id)
9649 .map(|adapter| adapter.name()),
9650 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9651 token: Some(token.to_proto()),
9652 }),
9653 })
9654 }
9655
9656 pub async fn handle_resolve_completion_documentation(
9657 this: Entity<Self>,
9658 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9659 mut cx: AsyncApp,
9660 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9661 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9662
9663 let completion = this
9664 .read_with(&cx, |this, cx| {
9665 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9666 let server = this
9667 .language_server_for_id(id)
9668 .with_context(|| format!("No language server {id}"))?;
9669
9670 anyhow::Ok(cx.background_spawn(async move {
9671 let can_resolve = server
9672 .capabilities()
9673 .completion_provider
9674 .as_ref()
9675 .and_then(|options| options.resolve_provider)
9676 .unwrap_or(false);
9677 if can_resolve {
9678 server
9679 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9680 .await
9681 .into_response()
9682 .context("resolve completion item")
9683 } else {
9684 anyhow::Ok(lsp_completion)
9685 }
9686 }))
9687 })??
9688 .await?;
9689
9690 let mut documentation_is_markdown = false;
9691 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9692 let documentation = match completion.documentation {
9693 Some(lsp::Documentation::String(text)) => text,
9694
9695 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9696 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9697 value
9698 }
9699
9700 _ => String::new(),
9701 };
9702
9703 // If we have a new buffer_id, that means we're talking to a new client
9704 // and want to check for new text_edits in the completion too.
9705 let mut old_replace_start = None;
9706 let mut old_replace_end = None;
9707 let mut old_insert_start = None;
9708 let mut old_insert_end = None;
9709 let mut new_text = String::default();
9710 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9711 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9712 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9713 anyhow::Ok(buffer.read(cx).snapshot())
9714 })??;
9715
9716 if let Some(text_edit) = completion.text_edit.as_ref() {
9717 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9718
9719 if let Some(mut edit) = edit {
9720 LineEnding::normalize(&mut edit.new_text);
9721
9722 new_text = edit.new_text;
9723 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9724 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9725 if let Some(insert_range) = edit.insert_range {
9726 old_insert_start = Some(serialize_anchor(&insert_range.start));
9727 old_insert_end = Some(serialize_anchor(&insert_range.end));
9728 }
9729 }
9730 }
9731 }
9732
9733 Ok(proto::ResolveCompletionDocumentationResponse {
9734 documentation,
9735 documentation_is_markdown,
9736 old_replace_start,
9737 old_replace_end,
9738 new_text,
9739 lsp_completion,
9740 old_insert_start,
9741 old_insert_end,
9742 })
9743 }
9744
9745 async fn handle_on_type_formatting(
9746 this: Entity<Self>,
9747 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9748 mut cx: AsyncApp,
9749 ) -> Result<proto::OnTypeFormattingResponse> {
9750 let on_type_formatting = this.update(&mut cx, |this, cx| {
9751 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9752 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9753 let position = envelope
9754 .payload
9755 .position
9756 .and_then(deserialize_anchor)
9757 .context("invalid position")?;
9758 anyhow::Ok(this.apply_on_type_formatting(
9759 buffer,
9760 position,
9761 envelope.payload.trigger.clone(),
9762 cx,
9763 ))
9764 })??;
9765
9766 let transaction = on_type_formatting
9767 .await?
9768 .as_ref()
9769 .map(language::proto::serialize_transaction);
9770 Ok(proto::OnTypeFormattingResponse { transaction })
9771 }
9772
9773 async fn handle_refresh_inlay_hints(
9774 lsp_store: Entity<Self>,
9775 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9776 mut cx: AsyncApp,
9777 ) -> Result<proto::Ack> {
9778 lsp_store.update(&mut cx, |_, cx| {
9779 cx.emit(LspStoreEvent::RefreshInlayHints {
9780 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9781 request_id: envelope.payload.request_id.map(|id| id as usize),
9782 });
9783 })?;
9784 Ok(proto::Ack {})
9785 }
9786
9787 async fn handle_pull_workspace_diagnostics(
9788 lsp_store: Entity<Self>,
9789 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9790 mut cx: AsyncApp,
9791 ) -> Result<proto::Ack> {
9792 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9793 lsp_store.update(&mut cx, |lsp_store, _| {
9794 lsp_store.pull_workspace_diagnostics(server_id);
9795 })?;
9796 Ok(proto::Ack {})
9797 }
9798
9799 async fn handle_get_color_presentation(
9800 lsp_store: Entity<Self>,
9801 envelope: TypedEnvelope<proto::GetColorPresentation>,
9802 mut cx: AsyncApp,
9803 ) -> Result<proto::GetColorPresentationResponse> {
9804 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9805 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9806 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9807 })??;
9808
9809 let color = envelope
9810 .payload
9811 .color
9812 .context("invalid color resolve request")?;
9813 let start = color
9814 .lsp_range_start
9815 .context("invalid color resolve request")?;
9816 let end = color
9817 .lsp_range_end
9818 .context("invalid color resolve request")?;
9819
9820 let color = DocumentColor {
9821 lsp_range: lsp::Range {
9822 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9823 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9824 },
9825 color: lsp::Color {
9826 red: color.red,
9827 green: color.green,
9828 blue: color.blue,
9829 alpha: color.alpha,
9830 },
9831 resolved: false,
9832 color_presentations: Vec::new(),
9833 };
9834 let resolved_color = lsp_store
9835 .update(&mut cx, |lsp_store, cx| {
9836 lsp_store.resolve_color_presentation(
9837 color,
9838 buffer.clone(),
9839 LanguageServerId(envelope.payload.server_id as usize),
9840 cx,
9841 )
9842 })?
9843 .await
9844 .context("resolving color presentation")?;
9845
9846 Ok(proto::GetColorPresentationResponse {
9847 presentations: resolved_color
9848 .color_presentations
9849 .into_iter()
9850 .map(|presentation| proto::ColorPresentation {
9851 label: presentation.label.to_string(),
9852 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9853 additional_text_edits: presentation
9854 .additional_text_edits
9855 .into_iter()
9856 .map(serialize_lsp_edit)
9857 .collect(),
9858 })
9859 .collect(),
9860 })
9861 }
9862
9863 async fn handle_resolve_inlay_hint(
9864 lsp_store: Entity<Self>,
9865 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9866 mut cx: AsyncApp,
9867 ) -> Result<proto::ResolveInlayHintResponse> {
9868 let proto_hint = envelope
9869 .payload
9870 .hint
9871 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9872 let hint = InlayHints::proto_to_project_hint(proto_hint)
9873 .context("resolved proto inlay hint conversion")?;
9874 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9875 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9876 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9877 })??;
9878 let response_hint = lsp_store
9879 .update(&mut cx, |lsp_store, cx| {
9880 lsp_store.resolve_inlay_hint(
9881 hint,
9882 buffer,
9883 LanguageServerId(envelope.payload.language_server_id as usize),
9884 cx,
9885 )
9886 })?
9887 .await
9888 .context("inlay hints fetch")?;
9889 Ok(proto::ResolveInlayHintResponse {
9890 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9891 })
9892 }
9893
9894 async fn handle_refresh_code_lens(
9895 this: Entity<Self>,
9896 _: TypedEnvelope<proto::RefreshCodeLens>,
9897 mut cx: AsyncApp,
9898 ) -> Result<proto::Ack> {
9899 this.update(&mut cx, |_, cx| {
9900 cx.emit(LspStoreEvent::RefreshCodeLens);
9901 })?;
9902 Ok(proto::Ack {})
9903 }
9904
9905 async fn handle_open_buffer_for_symbol(
9906 this: Entity<Self>,
9907 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9908 mut cx: AsyncApp,
9909 ) -> Result<proto::OpenBufferForSymbolResponse> {
9910 let peer_id = envelope.original_sender_id().unwrap_or_default();
9911 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9912 let symbol = Self::deserialize_symbol(symbol)?;
9913 this.read_with(&cx, |this, _| {
9914 if let SymbolLocation::OutsideProject {
9915 abs_path,
9916 signature,
9917 } = &symbol.path
9918 {
9919 let new_signature = this.symbol_signature(&abs_path);
9920 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9921 }
9922 Ok(())
9923 })??;
9924 let buffer = this
9925 .update(&mut cx, |this, cx| {
9926 this.open_buffer_for_symbol(
9927 &Symbol {
9928 language_server_name: symbol.language_server_name,
9929 source_worktree_id: symbol.source_worktree_id,
9930 source_language_server_id: symbol.source_language_server_id,
9931 path: symbol.path,
9932 name: symbol.name,
9933 kind: symbol.kind,
9934 range: symbol.range,
9935 label: CodeLabel::default(),
9936 },
9937 cx,
9938 )
9939 })?
9940 .await?;
9941
9942 this.update(&mut cx, |this, cx| {
9943 let is_private = buffer
9944 .read(cx)
9945 .file()
9946 .map(|f| f.is_private())
9947 .unwrap_or_default();
9948 if is_private {
9949 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9950 } else {
9951 this.buffer_store
9952 .update(cx, |buffer_store, cx| {
9953 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9954 })
9955 .detach_and_log_err(cx);
9956 let buffer_id = buffer.read(cx).remote_id().to_proto();
9957 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9958 }
9959 })?
9960 }
9961
9962 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9963 let mut hasher = Sha256::new();
9964 hasher.update(abs_path.to_string_lossy().as_bytes());
9965 hasher.update(self.nonce.to_be_bytes());
9966 hasher.finalize().as_slice().try_into().unwrap()
9967 }
9968
9969 pub async fn handle_get_project_symbols(
9970 this: Entity<Self>,
9971 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9972 mut cx: AsyncApp,
9973 ) -> Result<proto::GetProjectSymbolsResponse> {
9974 let symbols = this
9975 .update(&mut cx, |this, cx| {
9976 this.symbols(&envelope.payload.query, cx)
9977 })?
9978 .await?;
9979
9980 Ok(proto::GetProjectSymbolsResponse {
9981 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9982 })
9983 }
9984
9985 pub async fn handle_restart_language_servers(
9986 this: Entity<Self>,
9987 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9988 mut cx: AsyncApp,
9989 ) -> Result<proto::Ack> {
9990 this.update(&mut cx, |lsp_store, cx| {
9991 let buffers =
9992 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9993 lsp_store.restart_language_servers_for_buffers(
9994 buffers,
9995 envelope
9996 .payload
9997 .only_servers
9998 .into_iter()
9999 .filter_map(|selector| {
10000 Some(match selector.selector? {
10001 proto::language_server_selector::Selector::ServerId(server_id) => {
10002 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10003 }
10004 proto::language_server_selector::Selector::Name(name) => {
10005 LanguageServerSelector::Name(LanguageServerName(
10006 SharedString::from(name),
10007 ))
10008 }
10009 })
10010 })
10011 .collect(),
10012 cx,
10013 );
10014 })?;
10015
10016 Ok(proto::Ack {})
10017 }
10018
10019 pub async fn handle_stop_language_servers(
10020 lsp_store: Entity<Self>,
10021 envelope: TypedEnvelope<proto::StopLanguageServers>,
10022 mut cx: AsyncApp,
10023 ) -> Result<proto::Ack> {
10024 lsp_store.update(&mut cx, |lsp_store, cx| {
10025 if envelope.payload.all
10026 && envelope.payload.also_servers.is_empty()
10027 && envelope.payload.buffer_ids.is_empty()
10028 {
10029 lsp_store.stop_all_language_servers(cx);
10030 } else {
10031 let buffers =
10032 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10033 lsp_store
10034 .stop_language_servers_for_buffers(
10035 buffers,
10036 envelope
10037 .payload
10038 .also_servers
10039 .into_iter()
10040 .filter_map(|selector| {
10041 Some(match selector.selector? {
10042 proto::language_server_selector::Selector::ServerId(
10043 server_id,
10044 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10045 server_id,
10046 )),
10047 proto::language_server_selector::Selector::Name(name) => {
10048 LanguageServerSelector::Name(LanguageServerName(
10049 SharedString::from(name),
10050 ))
10051 }
10052 })
10053 })
10054 .collect(),
10055 cx,
10056 )
10057 .detach_and_log_err(cx);
10058 }
10059 })?;
10060
10061 Ok(proto::Ack {})
10062 }
10063
10064 pub async fn handle_cancel_language_server_work(
10065 lsp_store: Entity<Self>,
10066 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10067 mut cx: AsyncApp,
10068 ) -> Result<proto::Ack> {
10069 lsp_store.update(&mut cx, |lsp_store, cx| {
10070 if let Some(work) = envelope.payload.work {
10071 match work {
10072 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10073 let buffers =
10074 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10075 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10076 }
10077 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10078 let server_id = LanguageServerId::from_proto(work.language_server_id);
10079 let token = work
10080 .token
10081 .map(|token| {
10082 ProgressToken::from_proto(token)
10083 .context("invalid work progress token")
10084 })
10085 .transpose()?;
10086 lsp_store.cancel_language_server_work(server_id, token, cx);
10087 }
10088 }
10089 }
10090 anyhow::Ok(())
10091 })??;
10092
10093 Ok(proto::Ack {})
10094 }
10095
10096 fn buffer_ids_to_buffers(
10097 &mut self,
10098 buffer_ids: impl Iterator<Item = u64>,
10099 cx: &mut Context<Self>,
10100 ) -> Vec<Entity<Buffer>> {
10101 buffer_ids
10102 .into_iter()
10103 .flat_map(|buffer_id| {
10104 self.buffer_store
10105 .read(cx)
10106 .get(BufferId::new(buffer_id).log_err()?)
10107 })
10108 .collect::<Vec<_>>()
10109 }
10110
10111 async fn handle_apply_additional_edits_for_completion(
10112 this: Entity<Self>,
10113 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10114 mut cx: AsyncApp,
10115 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10116 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10117 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10118 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10119 let completion = Self::deserialize_completion(
10120 envelope.payload.completion.context("invalid completion")?,
10121 )?;
10122 anyhow::Ok((buffer, completion))
10123 })??;
10124
10125 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10126 this.apply_additional_edits_for_completion(
10127 buffer,
10128 Rc::new(RefCell::new(Box::new([Completion {
10129 replace_range: completion.replace_range,
10130 new_text: completion.new_text,
10131 source: completion.source,
10132 documentation: None,
10133 label: CodeLabel::default(),
10134 insert_text_mode: None,
10135 icon_path: None,
10136 confirm: None,
10137 }]))),
10138 0,
10139 false,
10140 cx,
10141 )
10142 })?;
10143
10144 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10145 transaction: apply_additional_edits
10146 .await?
10147 .as_ref()
10148 .map(language::proto::serialize_transaction),
10149 })
10150 }
10151
10152 pub fn last_formatting_failure(&self) -> Option<&str> {
10153 self.last_formatting_failure.as_deref()
10154 }
10155
10156 pub fn reset_last_formatting_failure(&mut self) {
10157 self.last_formatting_failure = None;
10158 }
10159
10160 pub fn environment_for_buffer(
10161 &self,
10162 buffer: &Entity<Buffer>,
10163 cx: &mut Context<Self>,
10164 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10165 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10166 environment.update(cx, |env, cx| {
10167 env.buffer_environment(buffer, &self.worktree_store, cx)
10168 })
10169 } else {
10170 Task::ready(None).shared()
10171 }
10172 }
10173
10174 pub fn format(
10175 &mut self,
10176 buffers: HashSet<Entity<Buffer>>,
10177 target: LspFormatTarget,
10178 push_to_history: bool,
10179 trigger: FormatTrigger,
10180 cx: &mut Context<Self>,
10181 ) -> Task<anyhow::Result<ProjectTransaction>> {
10182 let logger = zlog::scoped!("format");
10183 if self.as_local().is_some() {
10184 zlog::trace!(logger => "Formatting locally");
10185 let logger = zlog::scoped!(logger => "local");
10186 let buffers = buffers
10187 .into_iter()
10188 .map(|buffer_handle| {
10189 let buffer = buffer_handle.read(cx);
10190 let buffer_abs_path = File::from_dyn(buffer.file())
10191 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10192
10193 (buffer_handle, buffer_abs_path, buffer.remote_id())
10194 })
10195 .collect::<Vec<_>>();
10196
10197 cx.spawn(async move |lsp_store, cx| {
10198 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10199
10200 for (handle, abs_path, id) in buffers {
10201 let env = lsp_store
10202 .update(cx, |lsp_store, cx| {
10203 lsp_store.environment_for_buffer(&handle, cx)
10204 })?
10205 .await;
10206
10207 let ranges = match &target {
10208 LspFormatTarget::Buffers => None,
10209 LspFormatTarget::Ranges(ranges) => {
10210 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10211 }
10212 };
10213
10214 formattable_buffers.push(FormattableBuffer {
10215 handle,
10216 abs_path,
10217 env,
10218 ranges,
10219 });
10220 }
10221 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10222
10223 let format_timer = zlog::time!(logger => "Formatting buffers");
10224 let result = LocalLspStore::format_locally(
10225 lsp_store.clone(),
10226 formattable_buffers,
10227 push_to_history,
10228 trigger,
10229 logger,
10230 cx,
10231 )
10232 .await;
10233 format_timer.end();
10234
10235 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10236
10237 lsp_store.update(cx, |lsp_store, _| {
10238 lsp_store.update_last_formatting_failure(&result);
10239 })?;
10240
10241 result
10242 })
10243 } else if let Some((client, project_id)) = self.upstream_client() {
10244 zlog::trace!(logger => "Formatting remotely");
10245 let logger = zlog::scoped!(logger => "remote");
10246 // Don't support formatting ranges via remote
10247 match target {
10248 LspFormatTarget::Buffers => {}
10249 LspFormatTarget::Ranges(_) => {
10250 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10251 return Task::ready(Ok(ProjectTransaction::default()));
10252 }
10253 }
10254
10255 let buffer_store = self.buffer_store();
10256 cx.spawn(async move |lsp_store, cx| {
10257 zlog::trace!(logger => "Sending remote format request");
10258 let request_timer = zlog::time!(logger => "remote format request");
10259 let result = client
10260 .request(proto::FormatBuffers {
10261 project_id,
10262 trigger: trigger as i32,
10263 buffer_ids: buffers
10264 .iter()
10265 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10266 .collect::<Result<_>>()?,
10267 })
10268 .await
10269 .and_then(|result| result.transaction.context("missing transaction"));
10270 request_timer.end();
10271
10272 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10273
10274 lsp_store.update(cx, |lsp_store, _| {
10275 lsp_store.update_last_formatting_failure(&result);
10276 })?;
10277
10278 let transaction_response = result?;
10279 let _timer = zlog::time!(logger => "deserializing project transaction");
10280 buffer_store
10281 .update(cx, |buffer_store, cx| {
10282 buffer_store.deserialize_project_transaction(
10283 transaction_response,
10284 push_to_history,
10285 cx,
10286 )
10287 })?
10288 .await
10289 })
10290 } else {
10291 zlog::trace!(logger => "Not formatting");
10292 Task::ready(Ok(ProjectTransaction::default()))
10293 }
10294 }
10295
10296 async fn handle_format_buffers(
10297 this: Entity<Self>,
10298 envelope: TypedEnvelope<proto::FormatBuffers>,
10299 mut cx: AsyncApp,
10300 ) -> Result<proto::FormatBuffersResponse> {
10301 let sender_id = envelope.original_sender_id().unwrap_or_default();
10302 let format = this.update(&mut cx, |this, cx| {
10303 let mut buffers = HashSet::default();
10304 for buffer_id in &envelope.payload.buffer_ids {
10305 let buffer_id = BufferId::new(*buffer_id)?;
10306 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10307 }
10308 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10309 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10310 })??;
10311
10312 let project_transaction = format.await?;
10313 let project_transaction = this.update(&mut cx, |this, cx| {
10314 this.buffer_store.update(cx, |buffer_store, cx| {
10315 buffer_store.serialize_project_transaction_for_peer(
10316 project_transaction,
10317 sender_id,
10318 cx,
10319 )
10320 })
10321 })?;
10322 Ok(proto::FormatBuffersResponse {
10323 transaction: Some(project_transaction),
10324 })
10325 }
10326
10327 async fn handle_apply_code_action_kind(
10328 this: Entity<Self>,
10329 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10330 mut cx: AsyncApp,
10331 ) -> Result<proto::ApplyCodeActionKindResponse> {
10332 let sender_id = envelope.original_sender_id().unwrap_or_default();
10333 let format = this.update(&mut cx, |this, cx| {
10334 let mut buffers = HashSet::default();
10335 for buffer_id in &envelope.payload.buffer_ids {
10336 let buffer_id = BufferId::new(*buffer_id)?;
10337 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10338 }
10339 let kind = match envelope.payload.kind.as_str() {
10340 "" => CodeActionKind::EMPTY,
10341 "quickfix" => CodeActionKind::QUICKFIX,
10342 "refactor" => CodeActionKind::REFACTOR,
10343 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10344 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10345 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10346 "source" => CodeActionKind::SOURCE,
10347 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10348 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10349 _ => anyhow::bail!(
10350 "Invalid code action kind {}",
10351 envelope.payload.kind.as_str()
10352 ),
10353 };
10354 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10355 })??;
10356
10357 let project_transaction = format.await?;
10358 let project_transaction = this.update(&mut cx, |this, cx| {
10359 this.buffer_store.update(cx, |buffer_store, cx| {
10360 buffer_store.serialize_project_transaction_for_peer(
10361 project_transaction,
10362 sender_id,
10363 cx,
10364 )
10365 })
10366 })?;
10367 Ok(proto::ApplyCodeActionKindResponse {
10368 transaction: Some(project_transaction),
10369 })
10370 }
10371
10372 async fn shutdown_language_server(
10373 server_state: Option<LanguageServerState>,
10374 name: LanguageServerName,
10375 cx: &mut AsyncApp,
10376 ) {
10377 let server = match server_state {
10378 Some(LanguageServerState::Starting { startup, .. }) => {
10379 let mut timer = cx
10380 .background_executor()
10381 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10382 .fuse();
10383
10384 select! {
10385 server = startup.fuse() => server,
10386 () = timer => {
10387 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10388 None
10389 },
10390 }
10391 }
10392
10393 Some(LanguageServerState::Running { server, .. }) => Some(server),
10394
10395 None => None,
10396 };
10397
10398 if let Some(server) = server
10399 && let Some(shutdown) = server.shutdown()
10400 {
10401 shutdown.await;
10402 }
10403 }
10404
10405 // Returns a list of all of the worktrees which no longer have a language server and the root path
10406 // for the stopped server
10407 fn stop_local_language_server(
10408 &mut self,
10409 server_id: LanguageServerId,
10410 cx: &mut Context<Self>,
10411 ) -> Task<()> {
10412 let local = match &mut self.mode {
10413 LspStoreMode::Local(local) => local,
10414 _ => {
10415 return Task::ready(());
10416 }
10417 };
10418
10419 // Remove this server ID from all entries in the given worktree.
10420 local
10421 .language_server_ids
10422 .retain(|_, state| state.id != server_id);
10423 self.buffer_store.update(cx, |buffer_store, cx| {
10424 for buffer in buffer_store.buffers() {
10425 buffer.update(cx, |buffer, cx| {
10426 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10427 buffer.set_completion_triggers(server_id, Default::default(), cx);
10428 });
10429 }
10430 });
10431
10432 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10433 summaries.retain(|path, summaries_by_server_id| {
10434 if summaries_by_server_id.remove(&server_id).is_some() {
10435 if let Some((client, project_id)) = self.downstream_client.clone() {
10436 client
10437 .send(proto::UpdateDiagnosticSummary {
10438 project_id,
10439 worktree_id: worktree_id.to_proto(),
10440 summary: Some(proto::DiagnosticSummary {
10441 path: path.as_ref().to_proto(),
10442 language_server_id: server_id.0 as u64,
10443 error_count: 0,
10444 warning_count: 0,
10445 }),
10446 more_summaries: Vec::new(),
10447 })
10448 .log_err();
10449 }
10450 !summaries_by_server_id.is_empty()
10451 } else {
10452 true
10453 }
10454 });
10455 }
10456
10457 let local = self.as_local_mut().unwrap();
10458 for diagnostics in local.diagnostics.values_mut() {
10459 diagnostics.retain(|_, diagnostics_by_server_id| {
10460 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10461 diagnostics_by_server_id.remove(ix);
10462 !diagnostics_by_server_id.is_empty()
10463 } else {
10464 true
10465 }
10466 });
10467 }
10468 local.language_server_watched_paths.remove(&server_id);
10469
10470 let server_state = local.language_servers.remove(&server_id);
10471 self.cleanup_lsp_data(server_id);
10472 let name = self
10473 .language_server_statuses
10474 .remove(&server_id)
10475 .map(|status| status.name)
10476 .or_else(|| {
10477 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10478 Some(adapter.name())
10479 } else {
10480 None
10481 }
10482 });
10483
10484 if let Some(name) = name {
10485 log::info!("stopping language server {name}");
10486 self.languages
10487 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10488 cx.notify();
10489
10490 return cx.spawn(async move |lsp_store, cx| {
10491 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10492 lsp_store
10493 .update(cx, |lsp_store, cx| {
10494 lsp_store
10495 .languages
10496 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10497 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10498 cx.notify();
10499 })
10500 .ok();
10501 });
10502 }
10503
10504 if server_state.is_some() {
10505 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10506 }
10507 Task::ready(())
10508 }
10509
10510 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10511 if let Some((client, project_id)) = self.upstream_client() {
10512 let request = client.request(proto::StopLanguageServers {
10513 project_id,
10514 buffer_ids: Vec::new(),
10515 also_servers: Vec::new(),
10516 all: true,
10517 });
10518 cx.background_spawn(request).detach_and_log_err(cx);
10519 } else {
10520 let Some(local) = self.as_local_mut() else {
10521 return;
10522 };
10523 let language_servers_to_stop = local
10524 .language_server_ids
10525 .values()
10526 .map(|state| state.id)
10527 .collect();
10528 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10529 let tasks = language_servers_to_stop
10530 .into_iter()
10531 .map(|server| self.stop_local_language_server(server, cx))
10532 .collect::<Vec<_>>();
10533 cx.background_spawn(async move {
10534 futures::future::join_all(tasks).await;
10535 })
10536 .detach();
10537 }
10538 }
10539
10540 pub fn restart_language_servers_for_buffers(
10541 &mut self,
10542 buffers: Vec<Entity<Buffer>>,
10543 only_restart_servers: HashSet<LanguageServerSelector>,
10544 cx: &mut Context<Self>,
10545 ) {
10546 if let Some((client, project_id)) = self.upstream_client() {
10547 let request = client.request(proto::RestartLanguageServers {
10548 project_id,
10549 buffer_ids: buffers
10550 .into_iter()
10551 .map(|b| b.read(cx).remote_id().to_proto())
10552 .collect(),
10553 only_servers: only_restart_servers
10554 .into_iter()
10555 .map(|selector| {
10556 let selector = match selector {
10557 LanguageServerSelector::Id(language_server_id) => {
10558 proto::language_server_selector::Selector::ServerId(
10559 language_server_id.to_proto(),
10560 )
10561 }
10562 LanguageServerSelector::Name(language_server_name) => {
10563 proto::language_server_selector::Selector::Name(
10564 language_server_name.to_string(),
10565 )
10566 }
10567 };
10568 proto::LanguageServerSelector {
10569 selector: Some(selector),
10570 }
10571 })
10572 .collect(),
10573 all: false,
10574 });
10575 cx.background_spawn(request).detach_and_log_err(cx);
10576 } else {
10577 let stop_task = if only_restart_servers.is_empty() {
10578 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10579 } else {
10580 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10581 };
10582 cx.spawn(async move |lsp_store, cx| {
10583 stop_task.await;
10584 lsp_store
10585 .update(cx, |lsp_store, cx| {
10586 for buffer in buffers {
10587 lsp_store.register_buffer_with_language_servers(
10588 &buffer,
10589 only_restart_servers.clone(),
10590 true,
10591 cx,
10592 );
10593 }
10594 })
10595 .ok()
10596 })
10597 .detach();
10598 }
10599 }
10600
10601 pub fn stop_language_servers_for_buffers(
10602 &mut self,
10603 buffers: Vec<Entity<Buffer>>,
10604 also_stop_servers: HashSet<LanguageServerSelector>,
10605 cx: &mut Context<Self>,
10606 ) -> Task<Result<()>> {
10607 if let Some((client, project_id)) = self.upstream_client() {
10608 let request = client.request(proto::StopLanguageServers {
10609 project_id,
10610 buffer_ids: buffers
10611 .into_iter()
10612 .map(|b| b.read(cx).remote_id().to_proto())
10613 .collect(),
10614 also_servers: also_stop_servers
10615 .into_iter()
10616 .map(|selector| {
10617 let selector = match selector {
10618 LanguageServerSelector::Id(language_server_id) => {
10619 proto::language_server_selector::Selector::ServerId(
10620 language_server_id.to_proto(),
10621 )
10622 }
10623 LanguageServerSelector::Name(language_server_name) => {
10624 proto::language_server_selector::Selector::Name(
10625 language_server_name.to_string(),
10626 )
10627 }
10628 };
10629 proto::LanguageServerSelector {
10630 selector: Some(selector),
10631 }
10632 })
10633 .collect(),
10634 all: false,
10635 });
10636 cx.background_spawn(async move {
10637 let _ = request.await?;
10638 Ok(())
10639 })
10640 } else {
10641 let task =
10642 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10643 cx.background_spawn(async move {
10644 task.await;
10645 Ok(())
10646 })
10647 }
10648 }
10649
10650 fn stop_local_language_servers_for_buffers(
10651 &mut self,
10652 buffers: &[Entity<Buffer>],
10653 also_stop_servers: HashSet<LanguageServerSelector>,
10654 cx: &mut Context<Self>,
10655 ) -> Task<()> {
10656 let Some(local) = self.as_local_mut() else {
10657 return Task::ready(());
10658 };
10659 let mut language_server_names_to_stop = BTreeSet::default();
10660 let mut language_servers_to_stop = also_stop_servers
10661 .into_iter()
10662 .flat_map(|selector| match selector {
10663 LanguageServerSelector::Id(id) => Some(id),
10664 LanguageServerSelector::Name(name) => {
10665 language_server_names_to_stop.insert(name);
10666 None
10667 }
10668 })
10669 .collect::<BTreeSet<_>>();
10670
10671 let mut covered_worktrees = HashSet::default();
10672 for buffer in buffers {
10673 buffer.update(cx, |buffer, cx| {
10674 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10675 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10676 && covered_worktrees.insert(worktree_id)
10677 {
10678 language_server_names_to_stop.retain(|name| {
10679 let old_ids_count = language_servers_to_stop.len();
10680 let all_language_servers_with_this_name = local
10681 .language_server_ids
10682 .iter()
10683 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10684 language_servers_to_stop.extend(all_language_servers_with_this_name);
10685 old_ids_count == language_servers_to_stop.len()
10686 });
10687 }
10688 });
10689 }
10690 for name in language_server_names_to_stop {
10691 language_servers_to_stop.extend(
10692 local
10693 .language_server_ids
10694 .iter()
10695 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10696 );
10697 }
10698
10699 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10700 let tasks = language_servers_to_stop
10701 .into_iter()
10702 .map(|server| self.stop_local_language_server(server, cx))
10703 .collect::<Vec<_>>();
10704
10705 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10706 }
10707
10708 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10709 let (worktree, relative_path) =
10710 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10711
10712 let project_path = ProjectPath {
10713 worktree_id: worktree.read(cx).id(),
10714 path: relative_path,
10715 };
10716
10717 Some(
10718 self.buffer_store()
10719 .read(cx)
10720 .get_by_path(&project_path)?
10721 .read(cx),
10722 )
10723 }
10724
10725 #[cfg(any(test, feature = "test-support"))]
10726 pub fn update_diagnostics(
10727 &mut self,
10728 server_id: LanguageServerId,
10729 diagnostics: lsp::PublishDiagnosticsParams,
10730 result_id: Option<String>,
10731 source_kind: DiagnosticSourceKind,
10732 disk_based_sources: &[String],
10733 cx: &mut Context<Self>,
10734 ) -> Result<()> {
10735 self.merge_lsp_diagnostics(
10736 source_kind,
10737 vec![DocumentDiagnosticsUpdate {
10738 diagnostics,
10739 result_id,
10740 server_id,
10741 disk_based_sources: Cow::Borrowed(disk_based_sources),
10742 }],
10743 |_, _, _| false,
10744 cx,
10745 )
10746 }
10747
10748 pub fn merge_lsp_diagnostics(
10749 &mut self,
10750 source_kind: DiagnosticSourceKind,
10751 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10752 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10753 cx: &mut Context<Self>,
10754 ) -> Result<()> {
10755 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10756 let updates = lsp_diagnostics
10757 .into_iter()
10758 .filter_map(|update| {
10759 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10760 Some(DocumentDiagnosticsUpdate {
10761 diagnostics: self.lsp_to_document_diagnostics(
10762 abs_path,
10763 source_kind,
10764 update.server_id,
10765 update.diagnostics,
10766 &update.disk_based_sources,
10767 ),
10768 result_id: update.result_id,
10769 server_id: update.server_id,
10770 disk_based_sources: update.disk_based_sources,
10771 })
10772 })
10773 .collect();
10774 self.merge_diagnostic_entries(updates, merge, cx)?;
10775 Ok(())
10776 }
10777
10778 fn lsp_to_document_diagnostics(
10779 &mut self,
10780 document_abs_path: PathBuf,
10781 source_kind: DiagnosticSourceKind,
10782 server_id: LanguageServerId,
10783 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10784 disk_based_sources: &[String],
10785 ) -> DocumentDiagnostics {
10786 let mut diagnostics = Vec::default();
10787 let mut primary_diagnostic_group_ids = HashMap::default();
10788 let mut sources_by_group_id = HashMap::default();
10789 let mut supporting_diagnostics = HashMap::default();
10790
10791 let adapter = self.language_server_adapter_for_id(server_id);
10792
10793 // Ensure that primary diagnostics are always the most severe
10794 lsp_diagnostics
10795 .diagnostics
10796 .sort_by_key(|item| item.severity);
10797
10798 for diagnostic in &lsp_diagnostics.diagnostics {
10799 let source = diagnostic.source.as_ref();
10800 let range = range_from_lsp(diagnostic.range);
10801 let is_supporting = diagnostic
10802 .related_information
10803 .as_ref()
10804 .is_some_and(|infos| {
10805 infos.iter().any(|info| {
10806 primary_diagnostic_group_ids.contains_key(&(
10807 source,
10808 diagnostic.code.clone(),
10809 range_from_lsp(info.location.range),
10810 ))
10811 })
10812 });
10813
10814 let is_unnecessary = diagnostic
10815 .tags
10816 .as_ref()
10817 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10818
10819 let underline = self
10820 .language_server_adapter_for_id(server_id)
10821 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10822
10823 if is_supporting {
10824 supporting_diagnostics.insert(
10825 (source, diagnostic.code.clone(), range),
10826 (diagnostic.severity, is_unnecessary),
10827 );
10828 } else {
10829 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10830 let is_disk_based =
10831 source.is_some_and(|source| disk_based_sources.contains(source));
10832
10833 sources_by_group_id.insert(group_id, source);
10834 primary_diagnostic_group_ids
10835 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10836
10837 diagnostics.push(DiagnosticEntry {
10838 range,
10839 diagnostic: Diagnostic {
10840 source: diagnostic.source.clone(),
10841 source_kind,
10842 code: diagnostic.code.clone(),
10843 code_description: diagnostic
10844 .code_description
10845 .as_ref()
10846 .and_then(|d| d.href.clone()),
10847 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10848 markdown: adapter.as_ref().and_then(|adapter| {
10849 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10850 }),
10851 message: diagnostic.message.trim().to_string(),
10852 group_id,
10853 is_primary: true,
10854 is_disk_based,
10855 is_unnecessary,
10856 underline,
10857 data: diagnostic.data.clone(),
10858 },
10859 });
10860 if let Some(infos) = &diagnostic.related_information {
10861 for info in infos {
10862 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10863 let range = range_from_lsp(info.location.range);
10864 diagnostics.push(DiagnosticEntry {
10865 range,
10866 diagnostic: Diagnostic {
10867 source: diagnostic.source.clone(),
10868 source_kind,
10869 code: diagnostic.code.clone(),
10870 code_description: diagnostic
10871 .code_description
10872 .as_ref()
10873 .and_then(|d| d.href.clone()),
10874 severity: DiagnosticSeverity::INFORMATION,
10875 markdown: adapter.as_ref().and_then(|adapter| {
10876 adapter.diagnostic_message_to_markdown(&info.message)
10877 }),
10878 message: info.message.trim().to_string(),
10879 group_id,
10880 is_primary: false,
10881 is_disk_based,
10882 is_unnecessary: false,
10883 underline,
10884 data: diagnostic.data.clone(),
10885 },
10886 });
10887 }
10888 }
10889 }
10890 }
10891 }
10892
10893 for entry in &mut diagnostics {
10894 let diagnostic = &mut entry.diagnostic;
10895 if !diagnostic.is_primary {
10896 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10897 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10898 source,
10899 diagnostic.code.clone(),
10900 entry.range.clone(),
10901 )) {
10902 if let Some(severity) = severity {
10903 diagnostic.severity = severity;
10904 }
10905 diagnostic.is_unnecessary = is_unnecessary;
10906 }
10907 }
10908 }
10909
10910 DocumentDiagnostics {
10911 diagnostics,
10912 document_abs_path,
10913 version: lsp_diagnostics.version,
10914 }
10915 }
10916
10917 fn insert_newly_running_language_server(
10918 &mut self,
10919 adapter: Arc<CachedLspAdapter>,
10920 language_server: Arc<LanguageServer>,
10921 server_id: LanguageServerId,
10922 key: LanguageServerSeed,
10923 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10924 cx: &mut Context<Self>,
10925 ) {
10926 let Some(local) = self.as_local_mut() else {
10927 return;
10928 };
10929 // If the language server for this key doesn't match the server id, don't store the
10930 // server. Which will cause it to be dropped, killing the process
10931 if local
10932 .language_server_ids
10933 .get(&key)
10934 .map(|state| state.id != server_id)
10935 .unwrap_or(false)
10936 {
10937 return;
10938 }
10939
10940 // Update language_servers collection with Running variant of LanguageServerState
10941 // indicating that the server is up and running and ready
10942 let workspace_folders = workspace_folders.lock().clone();
10943 language_server.set_workspace_folders(workspace_folders);
10944
10945 let workspace_diagnostics_refresh_tasks = language_server
10946 .capabilities()
10947 .diagnostic_provider
10948 .and_then(|provider| {
10949 local
10950 .language_server_dynamic_registrations
10951 .entry(server_id)
10952 .or_default()
10953 .diagnostics
10954 .entry(None)
10955 .or_insert(provider.clone());
10956 let workspace_refresher =
10957 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10958
10959 Some((None, workspace_refresher))
10960 })
10961 .into_iter()
10962 .collect();
10963 local.language_servers.insert(
10964 server_id,
10965 LanguageServerState::Running {
10966 workspace_diagnostics_refresh_tasks,
10967 adapter: adapter.clone(),
10968 server: language_server.clone(),
10969 simulate_disk_based_diagnostics_completion: None,
10970 },
10971 );
10972 local
10973 .languages
10974 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10975 if let Some(file_ops_caps) = language_server
10976 .capabilities()
10977 .workspace
10978 .as_ref()
10979 .and_then(|ws| ws.file_operations.as_ref())
10980 {
10981 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10982 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10983 if did_rename_caps.or(will_rename_caps).is_some() {
10984 let watcher = RenamePathsWatchedForServer::default()
10985 .with_did_rename_patterns(did_rename_caps)
10986 .with_will_rename_patterns(will_rename_caps);
10987 local
10988 .language_server_paths_watched_for_rename
10989 .insert(server_id, watcher);
10990 }
10991 }
10992
10993 self.language_server_statuses.insert(
10994 server_id,
10995 LanguageServerStatus {
10996 name: language_server.name(),
10997 pending_work: Default::default(),
10998 has_pending_diagnostic_updates: false,
10999 progress_tokens: Default::default(),
11000 worktree: Some(key.worktree_id),
11001 },
11002 );
11003
11004 cx.emit(LspStoreEvent::LanguageServerAdded(
11005 server_id,
11006 language_server.name(),
11007 Some(key.worktree_id),
11008 ));
11009
11010 let server_capabilities = language_server.capabilities();
11011 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11012 downstream_client
11013 .send(proto::StartLanguageServer {
11014 project_id: *project_id,
11015 server: Some(proto::LanguageServer {
11016 id: server_id.to_proto(),
11017 name: language_server.name().to_string(),
11018 worktree_id: Some(key.worktree_id.to_proto()),
11019 }),
11020 capabilities: serde_json::to_string(&server_capabilities)
11021 .expect("serializing server LSP capabilities"),
11022 })
11023 .log_err();
11024 }
11025 self.lsp_server_capabilities
11026 .insert(server_id, server_capabilities);
11027
11028 // Tell the language server about every open buffer in the worktree that matches the language.
11029 // Also check for buffers in worktrees that reused this server
11030 let mut worktrees_using_server = vec![key.worktree_id];
11031 if let Some(local) = self.as_local() {
11032 // Find all worktrees that have this server in their language server tree
11033 for (worktree_id, servers) in &local.lsp_tree.instances {
11034 if *worktree_id != key.worktree_id {
11035 for server_map in servers.roots.values() {
11036 if server_map
11037 .values()
11038 .any(|(node, _)| node.id() == Some(server_id))
11039 {
11040 worktrees_using_server.push(*worktree_id);
11041 }
11042 }
11043 }
11044 }
11045 }
11046
11047 let mut buffer_paths_registered = Vec::new();
11048 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11049 let mut lsp_adapters = HashMap::default();
11050 for buffer_handle in buffer_store.buffers() {
11051 let buffer = buffer_handle.read(cx);
11052 let file = match File::from_dyn(buffer.file()) {
11053 Some(file) => file,
11054 None => continue,
11055 };
11056 let language = match buffer.language() {
11057 Some(language) => language,
11058 None => continue,
11059 };
11060
11061 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11062 || !lsp_adapters
11063 .entry(language.name())
11064 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11065 .iter()
11066 .any(|a| a.name == key.name)
11067 {
11068 continue;
11069 }
11070 // didOpen
11071 let file = match file.as_local() {
11072 Some(file) => file,
11073 None => continue,
11074 };
11075
11076 let local = self.as_local_mut().unwrap();
11077
11078 let buffer_id = buffer.remote_id();
11079 if local.registered_buffers.contains_key(&buffer_id) {
11080 let versions = local
11081 .buffer_snapshots
11082 .entry(buffer_id)
11083 .or_default()
11084 .entry(server_id)
11085 .and_modify(|_| {
11086 assert!(
11087 false,
11088 "There should not be an existing snapshot for a newly inserted buffer"
11089 )
11090 })
11091 .or_insert_with(|| {
11092 vec![LspBufferSnapshot {
11093 version: 0,
11094 snapshot: buffer.text_snapshot(),
11095 }]
11096 });
11097
11098 let snapshot = versions.last().unwrap();
11099 let version = snapshot.version;
11100 let initial_snapshot = &snapshot.snapshot;
11101 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11102 language_server.register_buffer(
11103 uri,
11104 adapter.language_id(&language.name()),
11105 version,
11106 initial_snapshot.text(),
11107 );
11108 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11109 local
11110 .buffers_opened_in_servers
11111 .entry(buffer_id)
11112 .or_default()
11113 .insert(server_id);
11114 }
11115 buffer_handle.update(cx, |buffer, cx| {
11116 buffer.set_completion_triggers(
11117 server_id,
11118 language_server
11119 .capabilities()
11120 .completion_provider
11121 .as_ref()
11122 .and_then(|provider| {
11123 provider
11124 .trigger_characters
11125 .as_ref()
11126 .map(|characters| characters.iter().cloned().collect())
11127 })
11128 .unwrap_or_default(),
11129 cx,
11130 )
11131 });
11132 }
11133 });
11134
11135 for (buffer_id, abs_path) in buffer_paths_registered {
11136 cx.emit(LspStoreEvent::LanguageServerUpdate {
11137 language_server_id: server_id,
11138 name: Some(adapter.name()),
11139 message: proto::update_language_server::Variant::RegisteredForBuffer(
11140 proto::RegisteredForBuffer {
11141 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11142 buffer_id: buffer_id.to_proto(),
11143 },
11144 ),
11145 });
11146 }
11147
11148 cx.notify();
11149 }
11150
11151 pub fn language_servers_running_disk_based_diagnostics(
11152 &self,
11153 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11154 self.language_server_statuses
11155 .iter()
11156 .filter_map(|(id, status)| {
11157 if status.has_pending_diagnostic_updates {
11158 Some(*id)
11159 } else {
11160 None
11161 }
11162 })
11163 }
11164
11165 pub(crate) fn cancel_language_server_work_for_buffers(
11166 &mut self,
11167 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11168 cx: &mut Context<Self>,
11169 ) {
11170 if let Some((client, project_id)) = self.upstream_client() {
11171 let request = client.request(proto::CancelLanguageServerWork {
11172 project_id,
11173 work: Some(proto::cancel_language_server_work::Work::Buffers(
11174 proto::cancel_language_server_work::Buffers {
11175 buffer_ids: buffers
11176 .into_iter()
11177 .map(|b| b.read(cx).remote_id().to_proto())
11178 .collect(),
11179 },
11180 )),
11181 });
11182 cx.background_spawn(request).detach_and_log_err(cx);
11183 } else if let Some(local) = self.as_local() {
11184 let servers = buffers
11185 .into_iter()
11186 .flat_map(|buffer| {
11187 buffer.update(cx, |buffer, cx| {
11188 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11189 })
11190 })
11191 .collect::<HashSet<_>>();
11192 for server_id in servers {
11193 self.cancel_language_server_work(server_id, None, cx);
11194 }
11195 }
11196 }
11197
11198 pub(crate) fn cancel_language_server_work(
11199 &mut self,
11200 server_id: LanguageServerId,
11201 token_to_cancel: Option<ProgressToken>,
11202 cx: &mut Context<Self>,
11203 ) {
11204 if let Some(local) = self.as_local() {
11205 let status = self.language_server_statuses.get(&server_id);
11206 let server = local.language_servers.get(&server_id);
11207 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11208 {
11209 for (token, progress) in &status.pending_work {
11210 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11211 && token != token_to_cancel
11212 {
11213 continue;
11214 }
11215 if progress.is_cancellable {
11216 server
11217 .notify::<lsp::notification::WorkDoneProgressCancel>(
11218 WorkDoneProgressCancelParams {
11219 token: token.to_lsp(),
11220 },
11221 )
11222 .ok();
11223 }
11224 }
11225 }
11226 } else if let Some((client, project_id)) = self.upstream_client() {
11227 let request = client.request(proto::CancelLanguageServerWork {
11228 project_id,
11229 work: Some(
11230 proto::cancel_language_server_work::Work::LanguageServerWork(
11231 proto::cancel_language_server_work::LanguageServerWork {
11232 language_server_id: server_id.to_proto(),
11233 token: token_to_cancel.map(|token| token.to_proto()),
11234 },
11235 ),
11236 ),
11237 });
11238 cx.background_spawn(request).detach_and_log_err(cx);
11239 }
11240 }
11241
11242 fn register_supplementary_language_server(
11243 &mut self,
11244 id: LanguageServerId,
11245 name: LanguageServerName,
11246 server: Arc<LanguageServer>,
11247 cx: &mut Context<Self>,
11248 ) {
11249 if let Some(local) = self.as_local_mut() {
11250 local
11251 .supplementary_language_servers
11252 .insert(id, (name.clone(), server));
11253 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11254 }
11255 }
11256
11257 fn unregister_supplementary_language_server(
11258 &mut self,
11259 id: LanguageServerId,
11260 cx: &mut Context<Self>,
11261 ) {
11262 if let Some(local) = self.as_local_mut() {
11263 local.supplementary_language_servers.remove(&id);
11264 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11265 }
11266 }
11267
11268 pub(crate) fn supplementary_language_servers(
11269 &self,
11270 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11271 self.as_local().into_iter().flat_map(|local| {
11272 local
11273 .supplementary_language_servers
11274 .iter()
11275 .map(|(id, (name, _))| (*id, name.clone()))
11276 })
11277 }
11278
11279 pub fn language_server_adapter_for_id(
11280 &self,
11281 id: LanguageServerId,
11282 ) -> Option<Arc<CachedLspAdapter>> {
11283 self.as_local()
11284 .and_then(|local| local.language_servers.get(&id))
11285 .and_then(|language_server_state| match language_server_state {
11286 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11287 _ => None,
11288 })
11289 }
11290
11291 pub(super) fn update_local_worktree_language_servers(
11292 &mut self,
11293 worktree_handle: &Entity<Worktree>,
11294 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11295 cx: &mut Context<Self>,
11296 ) {
11297 if changes.is_empty() {
11298 return;
11299 }
11300
11301 let Some(local) = self.as_local() else { return };
11302
11303 local.prettier_store.update(cx, |prettier_store, cx| {
11304 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11305 });
11306
11307 let worktree_id = worktree_handle.read(cx).id();
11308 let mut language_server_ids = local
11309 .language_server_ids
11310 .iter()
11311 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11312 .collect::<Vec<_>>();
11313 language_server_ids.sort();
11314 language_server_ids.dedup();
11315
11316 // let abs_path = worktree_handle.read(cx).abs_path();
11317 for server_id in &language_server_ids {
11318 if let Some(LanguageServerState::Running { server, .. }) =
11319 local.language_servers.get(server_id)
11320 && let Some(watched_paths) = local
11321 .language_server_watched_paths
11322 .get(server_id)
11323 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11324 {
11325 let params = lsp::DidChangeWatchedFilesParams {
11326 changes: changes
11327 .iter()
11328 .filter_map(|(path, _, change)| {
11329 if !watched_paths.is_match(path.as_std_path()) {
11330 return None;
11331 }
11332 let typ = match change {
11333 PathChange::Loaded => return None,
11334 PathChange::Added => lsp::FileChangeType::CREATED,
11335 PathChange::Removed => lsp::FileChangeType::DELETED,
11336 PathChange::Updated => lsp::FileChangeType::CHANGED,
11337 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11338 };
11339 let uri = lsp::Uri::from_file_path(
11340 worktree_handle.read(cx).absolutize(&path),
11341 )
11342 .ok()?;
11343 Some(lsp::FileEvent { uri, typ })
11344 })
11345 .collect(),
11346 };
11347 if !params.changes.is_empty() {
11348 server
11349 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11350 .ok();
11351 }
11352 }
11353 }
11354 for (path, _, _) in changes {
11355 if let Some(file_name) = path.file_name()
11356 && local.watched_manifest_filenames.contains(file_name)
11357 {
11358 self.request_workspace_config_refresh();
11359 break;
11360 }
11361 }
11362 }
11363
11364 pub fn wait_for_remote_buffer(
11365 &mut self,
11366 id: BufferId,
11367 cx: &mut Context<Self>,
11368 ) -> Task<Result<Entity<Buffer>>> {
11369 self.buffer_store.update(cx, |buffer_store, cx| {
11370 buffer_store.wait_for_remote_buffer(id, cx)
11371 })
11372 }
11373
11374 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11375 let mut result = proto::Symbol {
11376 language_server_name: symbol.language_server_name.0.to_string(),
11377 source_worktree_id: symbol.source_worktree_id.to_proto(),
11378 language_server_id: symbol.source_language_server_id.to_proto(),
11379 name: symbol.name.clone(),
11380 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11381 start: Some(proto::PointUtf16 {
11382 row: symbol.range.start.0.row,
11383 column: symbol.range.start.0.column,
11384 }),
11385 end: Some(proto::PointUtf16 {
11386 row: symbol.range.end.0.row,
11387 column: symbol.range.end.0.column,
11388 }),
11389 worktree_id: Default::default(),
11390 path: Default::default(),
11391 signature: Default::default(),
11392 };
11393 match &symbol.path {
11394 SymbolLocation::InProject(path) => {
11395 result.worktree_id = path.worktree_id.to_proto();
11396 result.path = path.path.to_proto();
11397 }
11398 SymbolLocation::OutsideProject {
11399 abs_path,
11400 signature,
11401 } => {
11402 result.path = abs_path.to_string_lossy().into_owned();
11403 result.signature = signature.to_vec();
11404 }
11405 }
11406 result
11407 }
11408
11409 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11410 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11411 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11412 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11413
11414 let path = if serialized_symbol.signature.is_empty() {
11415 SymbolLocation::InProject(ProjectPath {
11416 worktree_id,
11417 path: RelPath::from_proto(&serialized_symbol.path)
11418 .context("invalid symbol path")?,
11419 })
11420 } else {
11421 SymbolLocation::OutsideProject {
11422 abs_path: Path::new(&serialized_symbol.path).into(),
11423 signature: serialized_symbol
11424 .signature
11425 .try_into()
11426 .map_err(|_| anyhow!("invalid signature"))?,
11427 }
11428 };
11429
11430 let start = serialized_symbol.start.context("invalid start")?;
11431 let end = serialized_symbol.end.context("invalid end")?;
11432 Ok(CoreSymbol {
11433 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11434 source_worktree_id,
11435 source_language_server_id: LanguageServerId::from_proto(
11436 serialized_symbol.language_server_id,
11437 ),
11438 path,
11439 name: serialized_symbol.name,
11440 range: Unclipped(PointUtf16::new(start.row, start.column))
11441 ..Unclipped(PointUtf16::new(end.row, end.column)),
11442 kind,
11443 })
11444 }
11445
11446 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11447 let mut serialized_completion = proto::Completion {
11448 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11449 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11450 new_text: completion.new_text.clone(),
11451 ..proto::Completion::default()
11452 };
11453 match &completion.source {
11454 CompletionSource::Lsp {
11455 insert_range,
11456 server_id,
11457 lsp_completion,
11458 lsp_defaults,
11459 resolved,
11460 } => {
11461 let (old_insert_start, old_insert_end) = insert_range
11462 .as_ref()
11463 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11464 .unzip();
11465
11466 serialized_completion.old_insert_start = old_insert_start;
11467 serialized_completion.old_insert_end = old_insert_end;
11468 serialized_completion.source = proto::completion::Source::Lsp as i32;
11469 serialized_completion.server_id = server_id.0 as u64;
11470 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11471 serialized_completion.lsp_defaults = lsp_defaults
11472 .as_deref()
11473 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11474 serialized_completion.resolved = *resolved;
11475 }
11476 CompletionSource::BufferWord {
11477 word_range,
11478 resolved,
11479 } => {
11480 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11481 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11482 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11483 serialized_completion.resolved = *resolved;
11484 }
11485 CompletionSource::Custom => {
11486 serialized_completion.source = proto::completion::Source::Custom as i32;
11487 serialized_completion.resolved = true;
11488 }
11489 CompletionSource::Dap { sort_text } => {
11490 serialized_completion.source = proto::completion::Source::Dap as i32;
11491 serialized_completion.sort_text = Some(sort_text.clone());
11492 }
11493 }
11494
11495 serialized_completion
11496 }
11497
11498 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11499 let old_replace_start = completion
11500 .old_replace_start
11501 .and_then(deserialize_anchor)
11502 .context("invalid old start")?;
11503 let old_replace_end = completion
11504 .old_replace_end
11505 .and_then(deserialize_anchor)
11506 .context("invalid old end")?;
11507 let insert_range = {
11508 match completion.old_insert_start.zip(completion.old_insert_end) {
11509 Some((start, end)) => {
11510 let start = deserialize_anchor(start).context("invalid insert old start")?;
11511 let end = deserialize_anchor(end).context("invalid insert old end")?;
11512 Some(start..end)
11513 }
11514 None => None,
11515 }
11516 };
11517 Ok(CoreCompletion {
11518 replace_range: old_replace_start..old_replace_end,
11519 new_text: completion.new_text,
11520 source: match proto::completion::Source::from_i32(completion.source) {
11521 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11522 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11523 insert_range,
11524 server_id: LanguageServerId::from_proto(completion.server_id),
11525 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11526 lsp_defaults: completion
11527 .lsp_defaults
11528 .as_deref()
11529 .map(serde_json::from_slice)
11530 .transpose()?,
11531 resolved: completion.resolved,
11532 },
11533 Some(proto::completion::Source::BufferWord) => {
11534 let word_range = completion
11535 .buffer_word_start
11536 .and_then(deserialize_anchor)
11537 .context("invalid buffer word start")?
11538 ..completion
11539 .buffer_word_end
11540 .and_then(deserialize_anchor)
11541 .context("invalid buffer word end")?;
11542 CompletionSource::BufferWord {
11543 word_range,
11544 resolved: completion.resolved,
11545 }
11546 }
11547 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11548 sort_text: completion
11549 .sort_text
11550 .context("expected sort text to exist")?,
11551 },
11552 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11553 },
11554 })
11555 }
11556
11557 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11558 let (kind, lsp_action) = match &action.lsp_action {
11559 LspAction::Action(code_action) => (
11560 proto::code_action::Kind::Action as i32,
11561 serde_json::to_vec(code_action).unwrap(),
11562 ),
11563 LspAction::Command(command) => (
11564 proto::code_action::Kind::Command as i32,
11565 serde_json::to_vec(command).unwrap(),
11566 ),
11567 LspAction::CodeLens(code_lens) => (
11568 proto::code_action::Kind::CodeLens as i32,
11569 serde_json::to_vec(code_lens).unwrap(),
11570 ),
11571 };
11572
11573 proto::CodeAction {
11574 server_id: action.server_id.0 as u64,
11575 start: Some(serialize_anchor(&action.range.start)),
11576 end: Some(serialize_anchor(&action.range.end)),
11577 lsp_action,
11578 kind,
11579 resolved: action.resolved,
11580 }
11581 }
11582
11583 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11584 let start = action
11585 .start
11586 .and_then(deserialize_anchor)
11587 .context("invalid start")?;
11588 let end = action
11589 .end
11590 .and_then(deserialize_anchor)
11591 .context("invalid end")?;
11592 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11593 Some(proto::code_action::Kind::Action) => {
11594 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11595 }
11596 Some(proto::code_action::Kind::Command) => {
11597 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11598 }
11599 Some(proto::code_action::Kind::CodeLens) => {
11600 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11601 }
11602 None => anyhow::bail!("Unknown action kind {}", action.kind),
11603 };
11604 Ok(CodeAction {
11605 server_id: LanguageServerId(action.server_id as usize),
11606 range: start..end,
11607 resolved: action.resolved,
11608 lsp_action,
11609 })
11610 }
11611
11612 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11613 match &formatting_result {
11614 Ok(_) => self.last_formatting_failure = None,
11615 Err(error) => {
11616 let error_string = format!("{error:#}");
11617 log::error!("Formatting failed: {error_string}");
11618 self.last_formatting_failure
11619 .replace(error_string.lines().join(" "));
11620 }
11621 }
11622 }
11623
11624 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11625 self.lsp_server_capabilities.remove(&for_server);
11626 for lsp_data in self.lsp_data.values_mut() {
11627 lsp_data.remove_server_data(for_server);
11628 }
11629 if let Some(local) = self.as_local_mut() {
11630 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11631 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11632 buffer_servers.remove(&for_server);
11633 }
11634 }
11635 }
11636
11637 pub fn result_id(
11638 &self,
11639 server_id: LanguageServerId,
11640 buffer_id: BufferId,
11641 cx: &App,
11642 ) -> Option<String> {
11643 let abs_path = self
11644 .buffer_store
11645 .read(cx)
11646 .get(buffer_id)
11647 .and_then(|b| File::from_dyn(b.read(cx).file()))
11648 .map(|f| f.abs_path(cx))?;
11649 self.as_local()?
11650 .buffer_pull_diagnostics_result_ids
11651 .get(&server_id)?
11652 .get(&abs_path)?
11653 .clone()
11654 }
11655
11656 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11657 let Some(local) = self.as_local() else {
11658 return HashMap::default();
11659 };
11660 local
11661 .buffer_pull_diagnostics_result_ids
11662 .get(&server_id)
11663 .into_iter()
11664 .flatten()
11665 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11666 .collect()
11667 }
11668
11669 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11670 if let Some(LanguageServerState::Running {
11671 workspace_diagnostics_refresh_tasks,
11672 ..
11673 }) = self
11674 .as_local_mut()
11675 .and_then(|local| local.language_servers.get_mut(&server_id))
11676 {
11677 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11678 diagnostics.refresh_tx.try_send(()).ok();
11679 }
11680 }
11681 }
11682
11683 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11684 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11685 return;
11686 };
11687 let Some(local) = self.as_local_mut() else {
11688 return;
11689 };
11690
11691 for server_id in buffer.update(cx, |buffer, cx| {
11692 local.language_server_ids_for_buffer(buffer, cx)
11693 }) {
11694 if let Some(LanguageServerState::Running {
11695 workspace_diagnostics_refresh_tasks,
11696 ..
11697 }) = local.language_servers.get_mut(&server_id)
11698 {
11699 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11700 diagnostics.refresh_tx.try_send(()).ok();
11701 }
11702 }
11703 }
11704 }
11705
11706 fn apply_workspace_diagnostic_report(
11707 &mut self,
11708 server_id: LanguageServerId,
11709 report: lsp::WorkspaceDiagnosticReportResult,
11710 cx: &mut Context<Self>,
11711 ) {
11712 let workspace_diagnostics =
11713 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11714 let mut unchanged_buffers = HashSet::default();
11715 let mut changed_buffers = HashSet::default();
11716 let workspace_diagnostics_updates = workspace_diagnostics
11717 .into_iter()
11718 .filter_map(
11719 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11720 LspPullDiagnostics::Response {
11721 server_id,
11722 uri,
11723 diagnostics,
11724 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11725 LspPullDiagnostics::Default => None,
11726 },
11727 )
11728 .fold(
11729 HashMap::default(),
11730 |mut acc, (server_id, uri, diagnostics, version)| {
11731 let (result_id, diagnostics) = match diagnostics {
11732 PulledDiagnostics::Unchanged { result_id } => {
11733 unchanged_buffers.insert(uri.clone());
11734 (Some(result_id), Vec::new())
11735 }
11736 PulledDiagnostics::Changed {
11737 result_id,
11738 diagnostics,
11739 } => {
11740 changed_buffers.insert(uri.clone());
11741 (result_id, diagnostics)
11742 }
11743 };
11744 let disk_based_sources = Cow::Owned(
11745 self.language_server_adapter_for_id(server_id)
11746 .as_ref()
11747 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11748 .unwrap_or(&[])
11749 .to_vec(),
11750 );
11751 acc.entry(server_id)
11752 .or_insert_with(Vec::new)
11753 .push(DocumentDiagnosticsUpdate {
11754 server_id,
11755 diagnostics: lsp::PublishDiagnosticsParams {
11756 uri,
11757 diagnostics,
11758 version,
11759 },
11760 result_id,
11761 disk_based_sources,
11762 });
11763 acc
11764 },
11765 );
11766
11767 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11768 self.merge_lsp_diagnostics(
11769 DiagnosticSourceKind::Pulled,
11770 diagnostic_updates,
11771 |buffer, old_diagnostic, cx| {
11772 File::from_dyn(buffer.file())
11773 .and_then(|file| {
11774 let abs_path = file.as_local()?.abs_path(cx);
11775 lsp::Uri::from_file_path(abs_path).ok()
11776 })
11777 .is_none_or(|buffer_uri| {
11778 unchanged_buffers.contains(&buffer_uri)
11779 || match old_diagnostic.source_kind {
11780 DiagnosticSourceKind::Pulled => {
11781 !changed_buffers.contains(&buffer_uri)
11782 }
11783 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11784 true
11785 }
11786 }
11787 })
11788 },
11789 cx,
11790 )
11791 .log_err();
11792 }
11793 }
11794
11795 fn register_server_capabilities(
11796 &mut self,
11797 server_id: LanguageServerId,
11798 params: lsp::RegistrationParams,
11799 cx: &mut Context<Self>,
11800 ) -> anyhow::Result<()> {
11801 let server = self
11802 .language_server_for_id(server_id)
11803 .with_context(|| format!("no server {server_id} found"))?;
11804 for reg in params.registrations {
11805 match reg.method.as_str() {
11806 "workspace/didChangeWatchedFiles" => {
11807 if let Some(options) = reg.register_options {
11808 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11809 let caps = serde_json::from_value(options)?;
11810 local_lsp_store
11811 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11812 true
11813 } else {
11814 false
11815 };
11816 if notify {
11817 notify_server_capabilities_updated(&server, cx);
11818 }
11819 }
11820 }
11821 "workspace/didChangeConfiguration" => {
11822 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11823 }
11824 "workspace/didChangeWorkspaceFolders" => {
11825 // In this case register options is an empty object, we can ignore it
11826 let caps = lsp::WorkspaceFoldersServerCapabilities {
11827 supported: Some(true),
11828 change_notifications: Some(OneOf::Right(reg.id)),
11829 };
11830 server.update_capabilities(|capabilities| {
11831 capabilities
11832 .workspace
11833 .get_or_insert_default()
11834 .workspace_folders = Some(caps);
11835 });
11836 notify_server_capabilities_updated(&server, cx);
11837 }
11838 "workspace/symbol" => {
11839 let options = parse_register_capabilities(reg)?;
11840 server.update_capabilities(|capabilities| {
11841 capabilities.workspace_symbol_provider = Some(options);
11842 });
11843 notify_server_capabilities_updated(&server, cx);
11844 }
11845 "workspace/fileOperations" => {
11846 if let Some(options) = reg.register_options {
11847 let caps = serde_json::from_value(options)?;
11848 server.update_capabilities(|capabilities| {
11849 capabilities
11850 .workspace
11851 .get_or_insert_default()
11852 .file_operations = Some(caps);
11853 });
11854 notify_server_capabilities_updated(&server, cx);
11855 }
11856 }
11857 "workspace/executeCommand" => {
11858 if let Some(options) = reg.register_options {
11859 let options = serde_json::from_value(options)?;
11860 server.update_capabilities(|capabilities| {
11861 capabilities.execute_command_provider = Some(options);
11862 });
11863 notify_server_capabilities_updated(&server, cx);
11864 }
11865 }
11866 "textDocument/rangeFormatting" => {
11867 let options = parse_register_capabilities(reg)?;
11868 server.update_capabilities(|capabilities| {
11869 capabilities.document_range_formatting_provider = Some(options);
11870 });
11871 notify_server_capabilities_updated(&server, cx);
11872 }
11873 "textDocument/onTypeFormatting" => {
11874 if let Some(options) = reg
11875 .register_options
11876 .map(serde_json::from_value)
11877 .transpose()?
11878 {
11879 server.update_capabilities(|capabilities| {
11880 capabilities.document_on_type_formatting_provider = Some(options);
11881 });
11882 notify_server_capabilities_updated(&server, cx);
11883 }
11884 }
11885 "textDocument/formatting" => {
11886 let options = parse_register_capabilities(reg)?;
11887 server.update_capabilities(|capabilities| {
11888 capabilities.document_formatting_provider = Some(options);
11889 });
11890 notify_server_capabilities_updated(&server, cx);
11891 }
11892 "textDocument/rename" => {
11893 let options = parse_register_capabilities(reg)?;
11894 server.update_capabilities(|capabilities| {
11895 capabilities.rename_provider = Some(options);
11896 });
11897 notify_server_capabilities_updated(&server, cx);
11898 }
11899 "textDocument/inlayHint" => {
11900 let options = parse_register_capabilities(reg)?;
11901 server.update_capabilities(|capabilities| {
11902 capabilities.inlay_hint_provider = Some(options);
11903 });
11904 notify_server_capabilities_updated(&server, cx);
11905 }
11906 "textDocument/documentSymbol" => {
11907 let options = parse_register_capabilities(reg)?;
11908 server.update_capabilities(|capabilities| {
11909 capabilities.document_symbol_provider = Some(options);
11910 });
11911 notify_server_capabilities_updated(&server, cx);
11912 }
11913 "textDocument/codeAction" => {
11914 let options = parse_register_capabilities(reg)?;
11915 let provider = match options {
11916 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11917 OneOf::Right(caps) => caps,
11918 };
11919 server.update_capabilities(|capabilities| {
11920 capabilities.code_action_provider = Some(provider);
11921 });
11922 notify_server_capabilities_updated(&server, cx);
11923 }
11924 "textDocument/definition" => {
11925 let options = parse_register_capabilities(reg)?;
11926 server.update_capabilities(|capabilities| {
11927 capabilities.definition_provider = Some(options);
11928 });
11929 notify_server_capabilities_updated(&server, cx);
11930 }
11931 "textDocument/completion" => {
11932 if let Some(caps) = reg
11933 .register_options
11934 .map(serde_json::from_value::<CompletionOptions>)
11935 .transpose()?
11936 {
11937 server.update_capabilities(|capabilities| {
11938 capabilities.completion_provider = Some(caps.clone());
11939 });
11940
11941 if let Some(local) = self.as_local() {
11942 let mut buffers_with_language_server = Vec::new();
11943 for handle in self.buffer_store.read(cx).buffers() {
11944 let buffer_id = handle.read(cx).remote_id();
11945 if local
11946 .buffers_opened_in_servers
11947 .get(&buffer_id)
11948 .filter(|s| s.contains(&server_id))
11949 .is_some()
11950 {
11951 buffers_with_language_server.push(handle);
11952 }
11953 }
11954 let triggers = caps
11955 .trigger_characters
11956 .unwrap_or_default()
11957 .into_iter()
11958 .collect::<BTreeSet<_>>();
11959 for handle in buffers_with_language_server {
11960 let triggers = triggers.clone();
11961 let _ = handle.update(cx, move |buffer, cx| {
11962 buffer.set_completion_triggers(server_id, triggers, cx);
11963 });
11964 }
11965 }
11966 notify_server_capabilities_updated(&server, cx);
11967 }
11968 }
11969 "textDocument/hover" => {
11970 let options = parse_register_capabilities(reg)?;
11971 let provider = match options {
11972 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11973 OneOf::Right(caps) => caps,
11974 };
11975 server.update_capabilities(|capabilities| {
11976 capabilities.hover_provider = Some(provider);
11977 });
11978 notify_server_capabilities_updated(&server, cx);
11979 }
11980 "textDocument/signatureHelp" => {
11981 if let Some(caps) = reg
11982 .register_options
11983 .map(serde_json::from_value)
11984 .transpose()?
11985 {
11986 server.update_capabilities(|capabilities| {
11987 capabilities.signature_help_provider = Some(caps);
11988 });
11989 notify_server_capabilities_updated(&server, cx);
11990 }
11991 }
11992 "textDocument/didChange" => {
11993 if let Some(sync_kind) = reg
11994 .register_options
11995 .and_then(|opts| opts.get("syncKind").cloned())
11996 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11997 .transpose()?
11998 {
11999 server.update_capabilities(|capabilities| {
12000 let mut sync_options =
12001 Self::take_text_document_sync_options(capabilities);
12002 sync_options.change = Some(sync_kind);
12003 capabilities.text_document_sync =
12004 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12005 });
12006 notify_server_capabilities_updated(&server, cx);
12007 }
12008 }
12009 "textDocument/didSave" => {
12010 if let Some(include_text) = reg
12011 .register_options
12012 .map(|opts| {
12013 let transpose = opts
12014 .get("includeText")
12015 .cloned()
12016 .map(serde_json::from_value::<Option<bool>>)
12017 .transpose();
12018 match transpose {
12019 Ok(value) => Ok(value.flatten()),
12020 Err(e) => Err(e),
12021 }
12022 })
12023 .transpose()?
12024 {
12025 server.update_capabilities(|capabilities| {
12026 let mut sync_options =
12027 Self::take_text_document_sync_options(capabilities);
12028 sync_options.save =
12029 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12030 include_text,
12031 }));
12032 capabilities.text_document_sync =
12033 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12034 });
12035 notify_server_capabilities_updated(&server, cx);
12036 }
12037 }
12038 "textDocument/codeLens" => {
12039 if let Some(caps) = reg
12040 .register_options
12041 .map(serde_json::from_value)
12042 .transpose()?
12043 {
12044 server.update_capabilities(|capabilities| {
12045 capabilities.code_lens_provider = Some(caps);
12046 });
12047 notify_server_capabilities_updated(&server, cx);
12048 }
12049 }
12050 "textDocument/diagnostic" => {
12051 if let Some(caps) = reg
12052 .register_options
12053 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12054 .transpose()?
12055 {
12056 let local = self
12057 .as_local_mut()
12058 .context("Expected LSP Store to be local")?;
12059 let state = local
12060 .language_servers
12061 .get_mut(&server_id)
12062 .context("Could not obtain Language Servers state")?;
12063 local
12064 .language_server_dynamic_registrations
12065 .get_mut(&server_id)
12066 .and_then(|registrations| {
12067 registrations
12068 .diagnostics
12069 .insert(Some(reg.id.clone()), caps.clone())
12070 });
12071
12072 let mut can_now_provide_diagnostics = false;
12073 if let LanguageServerState::Running {
12074 workspace_diagnostics_refresh_tasks,
12075 ..
12076 } = state
12077 && let Some(task) = lsp_workspace_diagnostics_refresh(
12078 Some(reg.id.clone()),
12079 caps.clone(),
12080 server.clone(),
12081 cx,
12082 )
12083 {
12084 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12085 can_now_provide_diagnostics = true;
12086 }
12087
12088 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12089 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12090 // as it'll think that they're not supported.
12091 if can_now_provide_diagnostics {
12092 server.update_capabilities(|capabilities| {
12093 debug_assert!(capabilities.diagnostic_provider.is_none());
12094 capabilities.diagnostic_provider = Some(caps);
12095 });
12096 }
12097
12098 notify_server_capabilities_updated(&server, cx);
12099 }
12100 }
12101 "textDocument/documentColor" => {
12102 let options = parse_register_capabilities(reg)?;
12103 let provider = match options {
12104 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12105 OneOf::Right(caps) => caps,
12106 };
12107 server.update_capabilities(|capabilities| {
12108 capabilities.color_provider = Some(provider);
12109 });
12110 notify_server_capabilities_updated(&server, cx);
12111 }
12112 _ => log::warn!("unhandled capability registration: {reg:?}"),
12113 }
12114 }
12115
12116 Ok(())
12117 }
12118
12119 fn unregister_server_capabilities(
12120 &mut self,
12121 server_id: LanguageServerId,
12122 params: lsp::UnregistrationParams,
12123 cx: &mut Context<Self>,
12124 ) -> anyhow::Result<()> {
12125 let server = self
12126 .language_server_for_id(server_id)
12127 .with_context(|| format!("no server {server_id} found"))?;
12128 for unreg in params.unregisterations.iter() {
12129 match unreg.method.as_str() {
12130 "workspace/didChangeWatchedFiles" => {
12131 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12132 local_lsp_store
12133 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12134 true
12135 } else {
12136 false
12137 };
12138 if notify {
12139 notify_server_capabilities_updated(&server, cx);
12140 }
12141 }
12142 "workspace/didChangeConfiguration" => {
12143 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12144 }
12145 "workspace/didChangeWorkspaceFolders" => {
12146 server.update_capabilities(|capabilities| {
12147 capabilities
12148 .workspace
12149 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12150 workspace_folders: None,
12151 file_operations: None,
12152 })
12153 .workspace_folders = None;
12154 });
12155 notify_server_capabilities_updated(&server, cx);
12156 }
12157 "workspace/symbol" => {
12158 server.update_capabilities(|capabilities| {
12159 capabilities.workspace_symbol_provider = None
12160 });
12161 notify_server_capabilities_updated(&server, cx);
12162 }
12163 "workspace/fileOperations" => {
12164 server.update_capabilities(|capabilities| {
12165 capabilities
12166 .workspace
12167 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12168 workspace_folders: None,
12169 file_operations: None,
12170 })
12171 .file_operations = None;
12172 });
12173 notify_server_capabilities_updated(&server, cx);
12174 }
12175 "workspace/executeCommand" => {
12176 server.update_capabilities(|capabilities| {
12177 capabilities.execute_command_provider = None;
12178 });
12179 notify_server_capabilities_updated(&server, cx);
12180 }
12181 "textDocument/rangeFormatting" => {
12182 server.update_capabilities(|capabilities| {
12183 capabilities.document_range_formatting_provider = None
12184 });
12185 notify_server_capabilities_updated(&server, cx);
12186 }
12187 "textDocument/onTypeFormatting" => {
12188 server.update_capabilities(|capabilities| {
12189 capabilities.document_on_type_formatting_provider = None;
12190 });
12191 notify_server_capabilities_updated(&server, cx);
12192 }
12193 "textDocument/formatting" => {
12194 server.update_capabilities(|capabilities| {
12195 capabilities.document_formatting_provider = None;
12196 });
12197 notify_server_capabilities_updated(&server, cx);
12198 }
12199 "textDocument/rename" => {
12200 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12201 notify_server_capabilities_updated(&server, cx);
12202 }
12203 "textDocument/codeAction" => {
12204 server.update_capabilities(|capabilities| {
12205 capabilities.code_action_provider = None;
12206 });
12207 notify_server_capabilities_updated(&server, cx);
12208 }
12209 "textDocument/definition" => {
12210 server.update_capabilities(|capabilities| {
12211 capabilities.definition_provider = None;
12212 });
12213 notify_server_capabilities_updated(&server, cx);
12214 }
12215 "textDocument/completion" => {
12216 server.update_capabilities(|capabilities| {
12217 capabilities.completion_provider = None;
12218 });
12219 notify_server_capabilities_updated(&server, cx);
12220 }
12221 "textDocument/hover" => {
12222 server.update_capabilities(|capabilities| {
12223 capabilities.hover_provider = None;
12224 });
12225 notify_server_capabilities_updated(&server, cx);
12226 }
12227 "textDocument/signatureHelp" => {
12228 server.update_capabilities(|capabilities| {
12229 capabilities.signature_help_provider = None;
12230 });
12231 notify_server_capabilities_updated(&server, cx);
12232 }
12233 "textDocument/didChange" => {
12234 server.update_capabilities(|capabilities| {
12235 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12236 sync_options.change = None;
12237 capabilities.text_document_sync =
12238 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12239 });
12240 notify_server_capabilities_updated(&server, cx);
12241 }
12242 "textDocument/didSave" => {
12243 server.update_capabilities(|capabilities| {
12244 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12245 sync_options.save = None;
12246 capabilities.text_document_sync =
12247 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12248 });
12249 notify_server_capabilities_updated(&server, cx);
12250 }
12251 "textDocument/codeLens" => {
12252 server.update_capabilities(|capabilities| {
12253 capabilities.code_lens_provider = None;
12254 });
12255 notify_server_capabilities_updated(&server, cx);
12256 }
12257 "textDocument/diagnostic" => {
12258 let local = self
12259 .as_local_mut()
12260 .context("Expected LSP Store to be local")?;
12261
12262 let state = local
12263 .language_servers
12264 .get_mut(&server_id)
12265 .context("Could not obtain Language Servers state")?;
12266 let options = local
12267 .language_server_dynamic_registrations
12268 .get_mut(&server_id)
12269 .with_context(|| {
12270 format!("Expected dynamic registration to exist for server {server_id}")
12271 })?.diagnostics
12272 .remove(&Some(unreg.id.clone()))
12273 .with_context(|| format!(
12274 "Attempted to unregister non-existent diagnostic registration with ID {}",
12275 unreg.id)
12276 )?;
12277
12278 let mut has_any_diagnostic_providers_still = true;
12279 if let Some(identifier) = diagnostic_identifier(&options)
12280 && let LanguageServerState::Running {
12281 workspace_diagnostics_refresh_tasks,
12282 ..
12283 } = state
12284 {
12285 workspace_diagnostics_refresh_tasks.remove(&identifier);
12286 has_any_diagnostic_providers_still =
12287 !workspace_diagnostics_refresh_tasks.is_empty();
12288 }
12289
12290 if !has_any_diagnostic_providers_still {
12291 server.update_capabilities(|capabilities| {
12292 debug_assert!(capabilities.diagnostic_provider.is_some());
12293 capabilities.diagnostic_provider = None;
12294 });
12295 }
12296
12297 notify_server_capabilities_updated(&server, cx);
12298 }
12299 "textDocument/documentColor" => {
12300 server.update_capabilities(|capabilities| {
12301 capabilities.color_provider = None;
12302 });
12303 notify_server_capabilities_updated(&server, cx);
12304 }
12305 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12306 }
12307 }
12308
12309 Ok(())
12310 }
12311
12312 async fn deduplicate_range_based_lsp_requests<T>(
12313 lsp_store: &Entity<Self>,
12314 server_id: Option<LanguageServerId>,
12315 lsp_request_id: LspRequestId,
12316 proto_request: &T::ProtoRequest,
12317 range: Range<Anchor>,
12318 cx: &mut AsyncApp,
12319 ) -> Result<()>
12320 where
12321 T: LspCommand,
12322 T::ProtoRequest: proto::LspRequestMessage,
12323 {
12324 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12325 let version = deserialize_version(proto_request.buffer_version());
12326 let buffer = lsp_store.update(cx, |this, cx| {
12327 this.buffer_store.read(cx).get_existing(buffer_id)
12328 })??;
12329 buffer
12330 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12331 .await?;
12332 lsp_store.update(cx, |lsp_store, cx| {
12333 let lsp_data = lsp_store
12334 .lsp_data
12335 .entry(buffer_id)
12336 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12337 let chunks_queried_for = lsp_data
12338 .inlay_hints
12339 .applicable_chunks(&[range])
12340 .collect::<Vec<_>>();
12341 match chunks_queried_for.as_slice() {
12342 &[chunk] => {
12343 let key = LspKey {
12344 request_type: TypeId::of::<T>(),
12345 server_queried: server_id,
12346 };
12347 let previous_request = lsp_data
12348 .chunk_lsp_requests
12349 .entry(key)
12350 .or_default()
12351 .insert(chunk, lsp_request_id);
12352 if let Some((previous_request, running_requests)) =
12353 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12354 {
12355 running_requests.remove(&previous_request);
12356 }
12357 }
12358 _ambiguous_chunks => {
12359 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12360 // there, a buffer version-based check will be performed and outdated requests discarded.
12361 }
12362 }
12363 anyhow::Ok(())
12364 })??;
12365
12366 Ok(())
12367 }
12368
12369 async fn query_lsp_locally<T>(
12370 lsp_store: Entity<Self>,
12371 for_server_id: Option<LanguageServerId>,
12372 sender_id: proto::PeerId,
12373 lsp_request_id: LspRequestId,
12374 proto_request: T::ProtoRequest,
12375 position: Option<Anchor>,
12376 cx: &mut AsyncApp,
12377 ) -> Result<()>
12378 where
12379 T: LspCommand + Clone,
12380 T::ProtoRequest: proto::LspRequestMessage,
12381 <T::ProtoRequest as proto::RequestMessage>::Response:
12382 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12383 {
12384 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12385 let version = deserialize_version(proto_request.buffer_version());
12386 let buffer = lsp_store.update(cx, |this, cx| {
12387 this.buffer_store.read(cx).get_existing(buffer_id)
12388 })??;
12389 buffer
12390 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12391 .await?;
12392 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12393 let request =
12394 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12395 let key = LspKey {
12396 request_type: TypeId::of::<T>(),
12397 server_queried: for_server_id,
12398 };
12399 lsp_store.update(cx, |lsp_store, cx| {
12400 let request_task = match for_server_id {
12401 Some(server_id) => {
12402 let server_task = lsp_store.request_lsp(
12403 buffer.clone(),
12404 LanguageServerToQuery::Other(server_id),
12405 request.clone(),
12406 cx,
12407 );
12408 cx.background_spawn(async move {
12409 let mut responses = Vec::new();
12410 match server_task.await {
12411 Ok(response) => responses.push((server_id, response)),
12412 Err(e) => log::error!(
12413 "Error handling response for request {request:?}: {e:#}"
12414 ),
12415 }
12416 responses
12417 })
12418 }
12419 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12420 };
12421 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12422 if T::ProtoRequest::stop_previous_requests() {
12423 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12424 lsp_requests.clear();
12425 }
12426 }
12427 lsp_data.lsp_requests.entry(key).or_default().insert(
12428 lsp_request_id,
12429 cx.spawn(async move |lsp_store, cx| {
12430 let response = request_task.await;
12431 lsp_store
12432 .update(cx, |lsp_store, cx| {
12433 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12434 {
12435 let response = response
12436 .into_iter()
12437 .map(|(server_id, response)| {
12438 (
12439 server_id.to_proto(),
12440 T::response_to_proto(
12441 response,
12442 lsp_store,
12443 sender_id,
12444 &buffer_version,
12445 cx,
12446 )
12447 .into(),
12448 )
12449 })
12450 .collect::<HashMap<_, _>>();
12451 match client.send_lsp_response::<T::ProtoRequest>(
12452 project_id,
12453 lsp_request_id,
12454 response,
12455 ) {
12456 Ok(()) => {}
12457 Err(e) => {
12458 log::error!("Failed to send LSP response: {e:#}",)
12459 }
12460 }
12461 }
12462 })
12463 .ok();
12464 }),
12465 );
12466 })?;
12467 Ok(())
12468 }
12469
12470 fn take_text_document_sync_options(
12471 capabilities: &mut lsp::ServerCapabilities,
12472 ) -> lsp::TextDocumentSyncOptions {
12473 match capabilities.text_document_sync.take() {
12474 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12475 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12476 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12477 sync_options.change = Some(sync_kind);
12478 sync_options
12479 }
12480 None => lsp::TextDocumentSyncOptions::default(),
12481 }
12482 }
12483
12484 #[cfg(any(test, feature = "test-support"))]
12485 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12486 Some(
12487 self.lsp_data
12488 .get_mut(&buffer_id)?
12489 .code_lens
12490 .take()?
12491 .update
12492 .take()?
12493 .1,
12494 )
12495 }
12496
12497 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12498 self.downstream_client.clone()
12499 }
12500
12501 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12502 self.worktree_store.clone()
12503 }
12504
12505 /// Gets what's stored in the LSP data for the given buffer.
12506 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12507 self.lsp_data.get_mut(&buffer_id)
12508 }
12509
12510 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12511 /// new [`BufferLspData`] will be created to replace the previous state.
12512 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12513 let (buffer_id, buffer_version) =
12514 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12515 let lsp_data = self
12516 .lsp_data
12517 .entry(buffer_id)
12518 .or_insert_with(|| BufferLspData::new(buffer, cx));
12519 if buffer_version.changed_since(&lsp_data.buffer_version) {
12520 *lsp_data = BufferLspData::new(buffer, cx);
12521 }
12522 lsp_data
12523 }
12524}
12525
12526// Registration with registerOptions as null, should fallback to true.
12527// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12528fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12529 reg: lsp::Registration,
12530) -> Result<OneOf<bool, T>> {
12531 Ok(match reg.register_options {
12532 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12533 None => OneOf::Left(true),
12534 })
12535}
12536
12537fn subscribe_to_binary_statuses(
12538 languages: &Arc<LanguageRegistry>,
12539 cx: &mut Context<'_, LspStore>,
12540) -> Task<()> {
12541 let mut server_statuses = languages.language_server_binary_statuses();
12542 cx.spawn(async move |lsp_store, cx| {
12543 while let Some((server_name, binary_status)) = server_statuses.next().await {
12544 if lsp_store
12545 .update(cx, |_, cx| {
12546 let mut message = None;
12547 let binary_status = match binary_status {
12548 BinaryStatus::None => proto::ServerBinaryStatus::None,
12549 BinaryStatus::CheckingForUpdate => {
12550 proto::ServerBinaryStatus::CheckingForUpdate
12551 }
12552 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12553 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12554 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12555 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12556 BinaryStatus::Failed { error } => {
12557 message = Some(error);
12558 proto::ServerBinaryStatus::Failed
12559 }
12560 };
12561 cx.emit(LspStoreEvent::LanguageServerUpdate {
12562 // Binary updates are about the binary that might not have any language server id at that point.
12563 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12564 language_server_id: LanguageServerId(0),
12565 name: Some(server_name),
12566 message: proto::update_language_server::Variant::StatusUpdate(
12567 proto::StatusUpdate {
12568 message,
12569 status: Some(proto::status_update::Status::Binary(
12570 binary_status as i32,
12571 )),
12572 },
12573 ),
12574 });
12575 })
12576 .is_err()
12577 {
12578 break;
12579 }
12580 }
12581 })
12582}
12583
12584fn lsp_workspace_diagnostics_refresh(
12585 registration_id: Option<String>,
12586 options: DiagnosticServerCapabilities,
12587 server: Arc<LanguageServer>,
12588 cx: &mut Context<'_, LspStore>,
12589) -> Option<WorkspaceRefreshTask> {
12590 let identifier = diagnostic_identifier(&options)?;
12591
12592 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12593 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12594 refresh_tx.try_send(()).ok();
12595
12596 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12597 let mut attempts = 0;
12598 let max_attempts = 50;
12599 let mut requests = 0;
12600
12601 loop {
12602 let Some(()) = refresh_rx.recv().await else {
12603 return;
12604 };
12605
12606 'request: loop {
12607 requests += 1;
12608 if attempts > max_attempts {
12609 log::error!(
12610 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12611 );
12612 return;
12613 }
12614 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12615 cx.background_executor()
12616 .timer(Duration::from_millis(backoff_millis))
12617 .await;
12618 attempts += 1;
12619
12620 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12621 lsp_store
12622 .all_result_ids(server.server_id())
12623 .into_iter()
12624 .filter_map(|(abs_path, result_id)| {
12625 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12626 Some(lsp::PreviousResultId {
12627 uri,
12628 value: result_id,
12629 })
12630 })
12631 .collect()
12632 }) else {
12633 return;
12634 };
12635
12636 let token = if let Some(identifier) = ®istration_id {
12637 format!(
12638 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12639 server.server_id(),
12640 )
12641 } else {
12642 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12643 };
12644
12645 progress_rx.try_recv().ok();
12646 let timer =
12647 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12648 let progress = pin!(progress_rx.recv().fuse());
12649 let response_result = server
12650 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12651 lsp::WorkspaceDiagnosticParams {
12652 previous_result_ids,
12653 identifier: identifier.clone(),
12654 work_done_progress_params: Default::default(),
12655 partial_result_params: lsp::PartialResultParams {
12656 partial_result_token: Some(lsp::ProgressToken::String(token)),
12657 },
12658 },
12659 select(timer, progress).then(|either| match either {
12660 Either::Left((message, ..)) => ready(message).left_future(),
12661 Either::Right(..) => pending::<String>().right_future(),
12662 }),
12663 )
12664 .await;
12665
12666 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12667 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12668 match response_result {
12669 ConnectionResult::Timeout => {
12670 log::error!("Timeout during workspace diagnostics pull");
12671 continue 'request;
12672 }
12673 ConnectionResult::ConnectionReset => {
12674 log::error!("Server closed a workspace diagnostics pull request");
12675 continue 'request;
12676 }
12677 ConnectionResult::Result(Err(e)) => {
12678 log::error!("Error during workspace diagnostics pull: {e:#}");
12679 break 'request;
12680 }
12681 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12682 attempts = 0;
12683 if lsp_store
12684 .update(cx, |lsp_store, cx| {
12685 lsp_store.apply_workspace_diagnostic_report(
12686 server.server_id(),
12687 pulled_diagnostics,
12688 cx,
12689 )
12690 })
12691 .is_err()
12692 {
12693 return;
12694 }
12695 break 'request;
12696 }
12697 }
12698 }
12699 }
12700 });
12701
12702 Some(WorkspaceRefreshTask {
12703 refresh_tx,
12704 progress_tx,
12705 task: workspace_query_language_server,
12706 })
12707}
12708
12709fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12710 match &options {
12711 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12712 if !diagnostic_options.workspace_diagnostics {
12713 return None;
12714 }
12715 Some(diagnostic_options.identifier.clone())
12716 }
12717 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12718 let diagnostic_options = ®istration_options.diagnostic_options;
12719 if !diagnostic_options.workspace_diagnostics {
12720 return None;
12721 }
12722 Some(diagnostic_options.identifier.clone())
12723 }
12724 }
12725}
12726
12727fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12728 let CompletionSource::BufferWord {
12729 word_range,
12730 resolved,
12731 } = &mut completion.source
12732 else {
12733 return;
12734 };
12735 if *resolved {
12736 return;
12737 }
12738
12739 if completion.new_text
12740 != snapshot
12741 .text_for_range(word_range.clone())
12742 .collect::<String>()
12743 {
12744 return;
12745 }
12746
12747 let mut offset = 0;
12748 for chunk in snapshot.chunks(word_range.clone(), true) {
12749 let end_offset = offset + chunk.text.len();
12750 if let Some(highlight_id) = chunk.syntax_highlight_id {
12751 completion
12752 .label
12753 .runs
12754 .push((offset..end_offset, highlight_id));
12755 }
12756 offset = end_offset;
12757 }
12758 *resolved = true;
12759}
12760
12761impl EventEmitter<LspStoreEvent> for LspStore {}
12762
12763fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12764 hover
12765 .contents
12766 .retain(|hover_block| !hover_block.text.trim().is_empty());
12767 if hover.contents.is_empty() {
12768 None
12769 } else {
12770 Some(hover)
12771 }
12772}
12773
12774async fn populate_labels_for_completions(
12775 new_completions: Vec<CoreCompletion>,
12776 language: Option<Arc<Language>>,
12777 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12778) -> Vec<Completion> {
12779 let lsp_completions = new_completions
12780 .iter()
12781 .filter_map(|new_completion| {
12782 new_completion
12783 .source
12784 .lsp_completion(true)
12785 .map(|lsp_completion| lsp_completion.into_owned())
12786 })
12787 .collect::<Vec<_>>();
12788
12789 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12790 lsp_adapter
12791 .labels_for_completions(&lsp_completions, language)
12792 .await
12793 .log_err()
12794 .unwrap_or_default()
12795 } else {
12796 Vec::new()
12797 }
12798 .into_iter()
12799 .fuse();
12800
12801 let mut completions = Vec::new();
12802 for completion in new_completions {
12803 match completion.source.lsp_completion(true) {
12804 Some(lsp_completion) => {
12805 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12806
12807 let mut label = labels.next().flatten().unwrap_or_else(|| {
12808 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12809 });
12810 ensure_uniform_list_compatible_label(&mut label);
12811 completions.push(Completion {
12812 label,
12813 documentation,
12814 replace_range: completion.replace_range,
12815 new_text: completion.new_text,
12816 insert_text_mode: lsp_completion.insert_text_mode,
12817 source: completion.source,
12818 icon_path: None,
12819 confirm: None,
12820 });
12821 }
12822 None => {
12823 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12824 ensure_uniform_list_compatible_label(&mut label);
12825 completions.push(Completion {
12826 label,
12827 documentation: None,
12828 replace_range: completion.replace_range,
12829 new_text: completion.new_text,
12830 source: completion.source,
12831 insert_text_mode: None,
12832 icon_path: None,
12833 confirm: None,
12834 });
12835 }
12836 }
12837 }
12838 completions
12839}
12840
12841#[derive(Debug)]
12842pub enum LanguageServerToQuery {
12843 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12844 FirstCapable,
12845 /// Query a specific language server.
12846 Other(LanguageServerId),
12847}
12848
12849#[derive(Default)]
12850struct RenamePathsWatchedForServer {
12851 did_rename: Vec<RenameActionPredicate>,
12852 will_rename: Vec<RenameActionPredicate>,
12853}
12854
12855impl RenamePathsWatchedForServer {
12856 fn with_did_rename_patterns(
12857 mut self,
12858 did_rename: Option<&FileOperationRegistrationOptions>,
12859 ) -> Self {
12860 if let Some(did_rename) = did_rename {
12861 self.did_rename = did_rename
12862 .filters
12863 .iter()
12864 .filter_map(|filter| filter.try_into().log_err())
12865 .collect();
12866 }
12867 self
12868 }
12869 fn with_will_rename_patterns(
12870 mut self,
12871 will_rename: Option<&FileOperationRegistrationOptions>,
12872 ) -> Self {
12873 if let Some(will_rename) = will_rename {
12874 self.will_rename = will_rename
12875 .filters
12876 .iter()
12877 .filter_map(|filter| filter.try_into().log_err())
12878 .collect();
12879 }
12880 self
12881 }
12882
12883 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12884 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12885 }
12886 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12887 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12888 }
12889}
12890
12891impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12892 type Error = globset::Error;
12893 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12894 Ok(Self {
12895 kind: ops.pattern.matches.clone(),
12896 glob: GlobBuilder::new(&ops.pattern.glob)
12897 .case_insensitive(
12898 ops.pattern
12899 .options
12900 .as_ref()
12901 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12902 )
12903 .build()?
12904 .compile_matcher(),
12905 })
12906 }
12907}
12908struct RenameActionPredicate {
12909 glob: GlobMatcher,
12910 kind: Option<FileOperationPatternKind>,
12911}
12912
12913impl RenameActionPredicate {
12914 // Returns true if language server should be notified
12915 fn eval(&self, path: &str, is_dir: bool) -> bool {
12916 self.kind.as_ref().is_none_or(|kind| {
12917 let expected_kind = if is_dir {
12918 FileOperationPatternKind::Folder
12919 } else {
12920 FileOperationPatternKind::File
12921 };
12922 kind == &expected_kind
12923 }) && self.glob.is_match(path)
12924 }
12925}
12926
12927#[derive(Default)]
12928struct LanguageServerWatchedPaths {
12929 worktree_paths: HashMap<WorktreeId, GlobSet>,
12930 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12931}
12932
12933#[derive(Default)]
12934struct LanguageServerWatchedPathsBuilder {
12935 worktree_paths: HashMap<WorktreeId, GlobSet>,
12936 abs_paths: HashMap<Arc<Path>, GlobSet>,
12937}
12938
12939impl LanguageServerWatchedPathsBuilder {
12940 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12941 self.worktree_paths.insert(worktree_id, glob_set);
12942 }
12943 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12944 self.abs_paths.insert(path, glob_set);
12945 }
12946 fn build(
12947 self,
12948 fs: Arc<dyn Fs>,
12949 language_server_id: LanguageServerId,
12950 cx: &mut Context<LspStore>,
12951 ) -> LanguageServerWatchedPaths {
12952 let lsp_store = cx.weak_entity();
12953
12954 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12955 let abs_paths = self
12956 .abs_paths
12957 .into_iter()
12958 .map(|(abs_path, globset)| {
12959 let task = cx.spawn({
12960 let abs_path = abs_path.clone();
12961 let fs = fs.clone();
12962
12963 let lsp_store = lsp_store.clone();
12964 async move |_, cx| {
12965 maybe!(async move {
12966 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12967 while let Some(update) = push_updates.0.next().await {
12968 let action = lsp_store
12969 .update(cx, |this, _| {
12970 let Some(local) = this.as_local() else {
12971 return ControlFlow::Break(());
12972 };
12973 let Some(watcher) = local
12974 .language_server_watched_paths
12975 .get(&language_server_id)
12976 else {
12977 return ControlFlow::Break(());
12978 };
12979 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12980 "Watched abs path is not registered with a watcher",
12981 );
12982 let matching_entries = update
12983 .into_iter()
12984 .filter(|event| globs.is_match(&event.path))
12985 .collect::<Vec<_>>();
12986 this.lsp_notify_abs_paths_changed(
12987 language_server_id,
12988 matching_entries,
12989 );
12990 ControlFlow::Continue(())
12991 })
12992 .ok()?;
12993
12994 if action.is_break() {
12995 break;
12996 }
12997 }
12998 Some(())
12999 })
13000 .await;
13001 }
13002 });
13003 (abs_path, (globset, task))
13004 })
13005 .collect();
13006 LanguageServerWatchedPaths {
13007 worktree_paths: self.worktree_paths,
13008 abs_paths,
13009 }
13010 }
13011}
13012
13013struct LspBufferSnapshot {
13014 version: i32,
13015 snapshot: TextBufferSnapshot,
13016}
13017
13018/// A prompt requested by LSP server.
13019#[derive(Clone, Debug)]
13020pub struct LanguageServerPromptRequest {
13021 pub level: PromptLevel,
13022 pub message: String,
13023 pub actions: Vec<MessageActionItem>,
13024 pub lsp_name: String,
13025 pub(crate) response_channel: Sender<MessageActionItem>,
13026}
13027
13028impl LanguageServerPromptRequest {
13029 pub async fn respond(self, index: usize) -> Option<()> {
13030 if let Some(response) = self.actions.into_iter().nth(index) {
13031 self.response_channel.send(response).await.ok()
13032 } else {
13033 None
13034 }
13035 }
13036}
13037impl PartialEq for LanguageServerPromptRequest {
13038 fn eq(&self, other: &Self) -> bool {
13039 self.message == other.message && self.actions == other.actions
13040 }
13041}
13042
13043#[derive(Clone, Debug, PartialEq)]
13044pub enum LanguageServerLogType {
13045 Log(MessageType),
13046 Trace { verbose_info: Option<String> },
13047 Rpc { received: bool },
13048}
13049
13050impl LanguageServerLogType {
13051 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13052 match self {
13053 Self::Log(log_type) => {
13054 use proto::log_message::LogLevel;
13055 let level = match *log_type {
13056 MessageType::ERROR => LogLevel::Error,
13057 MessageType::WARNING => LogLevel::Warning,
13058 MessageType::INFO => LogLevel::Info,
13059 MessageType::LOG => LogLevel::Log,
13060 other => {
13061 log::warn!("Unknown lsp log message type: {other:?}");
13062 LogLevel::Log
13063 }
13064 };
13065 proto::language_server_log::LogType::Log(proto::LogMessage {
13066 level: level as i32,
13067 })
13068 }
13069 Self::Trace { verbose_info } => {
13070 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13071 verbose_info: verbose_info.to_owned(),
13072 })
13073 }
13074 Self::Rpc { received } => {
13075 let kind = if *received {
13076 proto::rpc_message::Kind::Received
13077 } else {
13078 proto::rpc_message::Kind::Sent
13079 };
13080 let kind = kind as i32;
13081 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13082 }
13083 }
13084 }
13085
13086 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13087 use proto::log_message::LogLevel;
13088 use proto::rpc_message;
13089 match log_type {
13090 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13091 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13092 LogLevel::Error => MessageType::ERROR,
13093 LogLevel::Warning => MessageType::WARNING,
13094 LogLevel::Info => MessageType::INFO,
13095 LogLevel::Log => MessageType::LOG,
13096 },
13097 ),
13098 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13099 verbose_info: trace_message.verbose_info,
13100 },
13101 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13102 received: match rpc_message::Kind::from_i32(message.kind)
13103 .unwrap_or(rpc_message::Kind::Received)
13104 {
13105 rpc_message::Kind::Received => true,
13106 rpc_message::Kind::Sent => false,
13107 },
13108 },
13109 }
13110 }
13111}
13112
13113pub struct WorkspaceRefreshTask {
13114 refresh_tx: mpsc::Sender<()>,
13115 progress_tx: mpsc::Sender<()>,
13116 #[allow(dead_code)]
13117 task: Task<()>,
13118}
13119
13120pub enum LanguageServerState {
13121 Starting {
13122 startup: Task<Option<Arc<LanguageServer>>>,
13123 /// List of language servers that will be added to the workspace once it's initialization completes.
13124 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13125 },
13126
13127 Running {
13128 adapter: Arc<CachedLspAdapter>,
13129 server: Arc<LanguageServer>,
13130 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13131 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13132 },
13133}
13134
13135impl LanguageServerState {
13136 fn add_workspace_folder(&self, uri: Uri) {
13137 match self {
13138 LanguageServerState::Starting {
13139 pending_workspace_folders,
13140 ..
13141 } => {
13142 pending_workspace_folders.lock().insert(uri);
13143 }
13144 LanguageServerState::Running { server, .. } => {
13145 server.add_workspace_folder(uri);
13146 }
13147 }
13148 }
13149 fn _remove_workspace_folder(&self, uri: Uri) {
13150 match self {
13151 LanguageServerState::Starting {
13152 pending_workspace_folders,
13153 ..
13154 } => {
13155 pending_workspace_folders.lock().remove(&uri);
13156 }
13157 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13158 }
13159 }
13160}
13161
13162impl std::fmt::Debug for LanguageServerState {
13163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13164 match self {
13165 LanguageServerState::Starting { .. } => {
13166 f.debug_struct("LanguageServerState::Starting").finish()
13167 }
13168 LanguageServerState::Running { .. } => {
13169 f.debug_struct("LanguageServerState::Running").finish()
13170 }
13171 }
13172 }
13173}
13174
13175#[derive(Clone, Debug, Serialize)]
13176pub struct LanguageServerProgress {
13177 pub is_disk_based_diagnostics_progress: bool,
13178 pub is_cancellable: bool,
13179 pub title: Option<String>,
13180 pub message: Option<String>,
13181 pub percentage: Option<usize>,
13182 #[serde(skip_serializing)]
13183 pub last_update_at: Instant,
13184}
13185
13186#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13187pub struct DiagnosticSummary {
13188 pub error_count: usize,
13189 pub warning_count: usize,
13190}
13191
13192impl DiagnosticSummary {
13193 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13194 let mut this = Self {
13195 error_count: 0,
13196 warning_count: 0,
13197 };
13198
13199 for entry in diagnostics {
13200 if entry.diagnostic.is_primary {
13201 match entry.diagnostic.severity {
13202 DiagnosticSeverity::ERROR => this.error_count += 1,
13203 DiagnosticSeverity::WARNING => this.warning_count += 1,
13204 _ => {}
13205 }
13206 }
13207 }
13208
13209 this
13210 }
13211
13212 pub fn is_empty(&self) -> bool {
13213 self.error_count == 0 && self.warning_count == 0
13214 }
13215
13216 pub fn to_proto(
13217 self,
13218 language_server_id: LanguageServerId,
13219 path: &RelPath,
13220 ) -> proto::DiagnosticSummary {
13221 proto::DiagnosticSummary {
13222 path: path.to_proto(),
13223 language_server_id: language_server_id.0 as u64,
13224 error_count: self.error_count as u32,
13225 warning_count: self.warning_count as u32,
13226 }
13227 }
13228}
13229
13230#[derive(Clone, Debug)]
13231pub enum CompletionDocumentation {
13232 /// There is no documentation for this completion.
13233 Undocumented,
13234 /// A single line of documentation.
13235 SingleLine(SharedString),
13236 /// Multiple lines of plain text documentation.
13237 MultiLinePlainText(SharedString),
13238 /// Markdown documentation.
13239 MultiLineMarkdown(SharedString),
13240 /// Both single line and multiple lines of plain text documentation.
13241 SingleLineAndMultiLinePlainText {
13242 single_line: SharedString,
13243 plain_text: Option<SharedString>,
13244 },
13245}
13246
13247impl CompletionDocumentation {
13248 #[cfg(any(test, feature = "test-support"))]
13249 pub fn text(&self) -> SharedString {
13250 match self {
13251 CompletionDocumentation::Undocumented => "".into(),
13252 CompletionDocumentation::SingleLine(s) => s.clone(),
13253 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13254 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13255 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13256 single_line.clone()
13257 }
13258 }
13259 }
13260}
13261
13262impl From<lsp::Documentation> for CompletionDocumentation {
13263 fn from(docs: lsp::Documentation) -> Self {
13264 match docs {
13265 lsp::Documentation::String(text) => {
13266 if text.lines().count() <= 1 {
13267 CompletionDocumentation::SingleLine(text.into())
13268 } else {
13269 CompletionDocumentation::MultiLinePlainText(text.into())
13270 }
13271 }
13272
13273 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13274 lsp::MarkupKind::PlainText => {
13275 if value.lines().count() <= 1 {
13276 CompletionDocumentation::SingleLine(value.into())
13277 } else {
13278 CompletionDocumentation::MultiLinePlainText(value.into())
13279 }
13280 }
13281
13282 lsp::MarkupKind::Markdown => {
13283 CompletionDocumentation::MultiLineMarkdown(value.into())
13284 }
13285 },
13286 }
13287 }
13288}
13289
13290pub enum ResolvedHint {
13291 Resolved(InlayHint),
13292 Resolving(Shared<Task<()>>),
13293}
13294
13295fn glob_literal_prefix(glob: &Path) -> PathBuf {
13296 glob.components()
13297 .take_while(|component| match component {
13298 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13299 _ => true,
13300 })
13301 .collect()
13302}
13303
13304pub struct SshLspAdapter {
13305 name: LanguageServerName,
13306 binary: LanguageServerBinary,
13307 initialization_options: Option<String>,
13308 code_action_kinds: Option<Vec<CodeActionKind>>,
13309}
13310
13311impl SshLspAdapter {
13312 pub fn new(
13313 name: LanguageServerName,
13314 binary: LanguageServerBinary,
13315 initialization_options: Option<String>,
13316 code_action_kinds: Option<String>,
13317 ) -> Self {
13318 Self {
13319 name,
13320 binary,
13321 initialization_options,
13322 code_action_kinds: code_action_kinds
13323 .as_ref()
13324 .and_then(|c| serde_json::from_str(c).ok()),
13325 }
13326 }
13327}
13328
13329impl LspInstaller for SshLspAdapter {
13330 type BinaryVersion = ();
13331 async fn check_if_user_installed(
13332 &self,
13333 _: &dyn LspAdapterDelegate,
13334 _: Option<Toolchain>,
13335 _: &AsyncApp,
13336 ) -> Option<LanguageServerBinary> {
13337 Some(self.binary.clone())
13338 }
13339
13340 async fn cached_server_binary(
13341 &self,
13342 _: PathBuf,
13343 _: &dyn LspAdapterDelegate,
13344 ) -> Option<LanguageServerBinary> {
13345 None
13346 }
13347
13348 async fn fetch_latest_server_version(
13349 &self,
13350 _: &dyn LspAdapterDelegate,
13351 _: bool,
13352 _: &mut AsyncApp,
13353 ) -> Result<()> {
13354 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13355 }
13356
13357 async fn fetch_server_binary(
13358 &self,
13359 _: (),
13360 _: PathBuf,
13361 _: &dyn LspAdapterDelegate,
13362 ) -> Result<LanguageServerBinary> {
13363 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13364 }
13365}
13366
13367#[async_trait(?Send)]
13368impl LspAdapter for SshLspAdapter {
13369 fn name(&self) -> LanguageServerName {
13370 self.name.clone()
13371 }
13372
13373 async fn initialization_options(
13374 self: Arc<Self>,
13375 _: &Arc<dyn LspAdapterDelegate>,
13376 ) -> Result<Option<serde_json::Value>> {
13377 let Some(options) = &self.initialization_options else {
13378 return Ok(None);
13379 };
13380 let result = serde_json::from_str(options)?;
13381 Ok(result)
13382 }
13383
13384 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13385 self.code_action_kinds.clone()
13386 }
13387}
13388
13389pub fn language_server_settings<'a>(
13390 delegate: &'a dyn LspAdapterDelegate,
13391 language: &LanguageServerName,
13392 cx: &'a App,
13393) -> Option<&'a LspSettings> {
13394 language_server_settings_for(
13395 SettingsLocation {
13396 worktree_id: delegate.worktree_id(),
13397 path: RelPath::empty(),
13398 },
13399 language,
13400 cx,
13401 )
13402}
13403
13404pub(crate) fn language_server_settings_for<'a>(
13405 location: SettingsLocation<'a>,
13406 language: &LanguageServerName,
13407 cx: &'a App,
13408) -> Option<&'a LspSettings> {
13409 ProjectSettings::get(Some(location), cx).lsp.get(language)
13410}
13411
13412pub struct LocalLspAdapterDelegate {
13413 lsp_store: WeakEntity<LspStore>,
13414 worktree: worktree::Snapshot,
13415 fs: Arc<dyn Fs>,
13416 http_client: Arc<dyn HttpClient>,
13417 language_registry: Arc<LanguageRegistry>,
13418 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13419}
13420
13421impl LocalLspAdapterDelegate {
13422 pub fn new(
13423 language_registry: Arc<LanguageRegistry>,
13424 environment: &Entity<ProjectEnvironment>,
13425 lsp_store: WeakEntity<LspStore>,
13426 worktree: &Entity<Worktree>,
13427 http_client: Arc<dyn HttpClient>,
13428 fs: Arc<dyn Fs>,
13429 cx: &mut App,
13430 ) -> Arc<Self> {
13431 let load_shell_env_task =
13432 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13433
13434 Arc::new(Self {
13435 lsp_store,
13436 worktree: worktree.read(cx).snapshot(),
13437 fs,
13438 http_client,
13439 language_registry,
13440 load_shell_env_task,
13441 })
13442 }
13443
13444 fn from_local_lsp(
13445 local: &LocalLspStore,
13446 worktree: &Entity<Worktree>,
13447 cx: &mut App,
13448 ) -> Arc<Self> {
13449 Self::new(
13450 local.languages.clone(),
13451 &local.environment,
13452 local.weak.clone(),
13453 worktree,
13454 local.http_client.clone(),
13455 local.fs.clone(),
13456 cx,
13457 )
13458 }
13459}
13460
13461#[async_trait]
13462impl LspAdapterDelegate for LocalLspAdapterDelegate {
13463 fn show_notification(&self, message: &str, cx: &mut App) {
13464 self.lsp_store
13465 .update(cx, |_, cx| {
13466 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13467 })
13468 .ok();
13469 }
13470
13471 fn http_client(&self) -> Arc<dyn HttpClient> {
13472 self.http_client.clone()
13473 }
13474
13475 fn worktree_id(&self) -> WorktreeId {
13476 self.worktree.id()
13477 }
13478
13479 fn worktree_root_path(&self) -> &Path {
13480 self.worktree.abs_path().as_ref()
13481 }
13482
13483 async fn shell_env(&self) -> HashMap<String, String> {
13484 let task = self.load_shell_env_task.clone();
13485 task.await.unwrap_or_default()
13486 }
13487
13488 async fn npm_package_installed_version(
13489 &self,
13490 package_name: &str,
13491 ) -> Result<Option<(PathBuf, String)>> {
13492 let local_package_directory = self.worktree_root_path();
13493 let node_modules_directory = local_package_directory.join("node_modules");
13494
13495 if let Some(version) =
13496 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13497 {
13498 return Ok(Some((node_modules_directory, version)));
13499 }
13500 let Some(npm) = self.which("npm".as_ref()).await else {
13501 log::warn!(
13502 "Failed to find npm executable for {:?}",
13503 local_package_directory
13504 );
13505 return Ok(None);
13506 };
13507
13508 let env = self.shell_env().await;
13509 let output = util::command::new_smol_command(&npm)
13510 .args(["root", "-g"])
13511 .envs(env)
13512 .current_dir(local_package_directory)
13513 .output()
13514 .await?;
13515 let global_node_modules =
13516 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13517
13518 if let Some(version) =
13519 read_package_installed_version(global_node_modules.clone(), package_name).await?
13520 {
13521 return Ok(Some((global_node_modules, version)));
13522 }
13523 return Ok(None);
13524 }
13525
13526 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13527 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13528 if self.fs.is_file(&worktree_abs_path).await {
13529 worktree_abs_path.pop();
13530 }
13531
13532 let env = self.shell_env().await;
13533
13534 let shell_path = env.get("PATH").cloned();
13535
13536 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13537 }
13538
13539 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13540 let mut working_dir = self.worktree_root_path().to_path_buf();
13541 if self.fs.is_file(&working_dir).await {
13542 working_dir.pop();
13543 }
13544 let output = util::command::new_smol_command(&command.path)
13545 .args(command.arguments)
13546 .envs(command.env.clone().unwrap_or_default())
13547 .current_dir(working_dir)
13548 .output()
13549 .await?;
13550
13551 anyhow::ensure!(
13552 output.status.success(),
13553 "{}, stdout: {:?}, stderr: {:?}",
13554 output.status,
13555 String::from_utf8_lossy(&output.stdout),
13556 String::from_utf8_lossy(&output.stderr)
13557 );
13558 Ok(())
13559 }
13560
13561 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13562 self.language_registry
13563 .update_lsp_binary_status(server_name, status);
13564 }
13565
13566 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13567 self.language_registry
13568 .all_lsp_adapters()
13569 .into_iter()
13570 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13571 .collect()
13572 }
13573
13574 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13575 let dir = self.language_registry.language_server_download_dir(name)?;
13576
13577 if !dir.exists() {
13578 smol::fs::create_dir_all(&dir)
13579 .await
13580 .context("failed to create container directory")
13581 .log_err()?;
13582 }
13583
13584 Some(dir)
13585 }
13586
13587 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13588 let entry = self
13589 .worktree
13590 .entry_for_path(path)
13591 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13592 let abs_path = self.worktree.absolutize(&entry.path);
13593 self.fs.load(&abs_path).await
13594 }
13595}
13596
13597async fn populate_labels_for_symbols(
13598 symbols: Vec<CoreSymbol>,
13599 language_registry: &Arc<LanguageRegistry>,
13600 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13601 output: &mut Vec<Symbol>,
13602) {
13603 #[allow(clippy::mutable_key_type)]
13604 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13605
13606 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13607 for symbol in symbols {
13608 let Some(file_name) = symbol.path.file_name() else {
13609 continue;
13610 };
13611 let language = language_registry
13612 .load_language_for_file_path(Path::new(file_name))
13613 .await
13614 .ok()
13615 .or_else(|| {
13616 unknown_paths.insert(file_name.into());
13617 None
13618 });
13619 symbols_by_language
13620 .entry(language)
13621 .or_default()
13622 .push(symbol);
13623 }
13624
13625 for unknown_path in unknown_paths {
13626 log::info!("no language found for symbol in file {unknown_path:?}");
13627 }
13628
13629 let mut label_params = Vec::new();
13630 for (language, mut symbols) in symbols_by_language {
13631 label_params.clear();
13632 label_params.extend(
13633 symbols
13634 .iter_mut()
13635 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13636 );
13637
13638 let mut labels = Vec::new();
13639 if let Some(language) = language {
13640 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13641 language_registry
13642 .lsp_adapters(&language.name())
13643 .first()
13644 .cloned()
13645 });
13646 if let Some(lsp_adapter) = lsp_adapter {
13647 labels = lsp_adapter
13648 .labels_for_symbols(&label_params, &language)
13649 .await
13650 .log_err()
13651 .unwrap_or_default();
13652 }
13653 }
13654
13655 for ((symbol, (name, _)), label) in symbols
13656 .into_iter()
13657 .zip(label_params.drain(..))
13658 .zip(labels.into_iter().chain(iter::repeat(None)))
13659 {
13660 output.push(Symbol {
13661 language_server_name: symbol.language_server_name,
13662 source_worktree_id: symbol.source_worktree_id,
13663 source_language_server_id: symbol.source_language_server_id,
13664 path: symbol.path,
13665 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13666 name,
13667 kind: symbol.kind,
13668 range: symbol.range,
13669 });
13670 }
13671 }
13672}
13673
13674fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13675 match server.capabilities().text_document_sync.as_ref()? {
13676 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13677 // Server wants didSave but didn't specify includeText.
13678 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13679 // Server doesn't want didSave at all.
13680 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13681 // Server provided SaveOptions.
13682 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13683 Some(save_options.include_text.unwrap_or(false))
13684 }
13685 },
13686 // We do not have any save info. Kind affects didChange only.
13687 lsp::TextDocumentSyncCapability::Kind(_) => None,
13688 }
13689}
13690
13691/// Completion items are displayed in a `UniformList`.
13692/// Usually, those items are single-line strings, but in LSP responses,
13693/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13694/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13695/// 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,
13696/// breaking the completions menu presentation.
13697///
13698/// 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.
13699fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13700 let mut new_text = String::with_capacity(label.text.len());
13701 let mut offset_map = vec![0; label.text.len() + 1];
13702 let mut last_char_was_space = false;
13703 let mut new_idx = 0;
13704 let chars = label.text.char_indices().fuse();
13705 let mut newlines_removed = false;
13706
13707 for (idx, c) in chars {
13708 offset_map[idx] = new_idx;
13709
13710 match c {
13711 '\n' if last_char_was_space => {
13712 newlines_removed = true;
13713 }
13714 '\t' | ' ' if last_char_was_space => {}
13715 '\n' if !last_char_was_space => {
13716 new_text.push(' ');
13717 new_idx += 1;
13718 last_char_was_space = true;
13719 newlines_removed = true;
13720 }
13721 ' ' | '\t' => {
13722 new_text.push(' ');
13723 new_idx += 1;
13724 last_char_was_space = true;
13725 }
13726 _ => {
13727 new_text.push(c);
13728 new_idx += c.len_utf8();
13729 last_char_was_space = false;
13730 }
13731 }
13732 }
13733 offset_map[label.text.len()] = new_idx;
13734
13735 // Only modify the label if newlines were removed.
13736 if !newlines_removed {
13737 return;
13738 }
13739
13740 let last_index = new_idx;
13741 let mut run_ranges_errors = Vec::new();
13742 label.runs.retain_mut(|(range, _)| {
13743 match offset_map.get(range.start) {
13744 Some(&start) => range.start = start,
13745 None => {
13746 run_ranges_errors.push(range.clone());
13747 return false;
13748 }
13749 }
13750
13751 match offset_map.get(range.end) {
13752 Some(&end) => range.end = end,
13753 None => {
13754 run_ranges_errors.push(range.clone());
13755 range.end = last_index;
13756 }
13757 }
13758 true
13759 });
13760 if !run_ranges_errors.is_empty() {
13761 log::error!(
13762 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13763 label.text
13764 );
13765 }
13766
13767 let mut wrong_filter_range = None;
13768 if label.filter_range == (0..label.text.len()) {
13769 label.filter_range = 0..new_text.len();
13770 } else {
13771 let mut original_filter_range = Some(label.filter_range.clone());
13772 match offset_map.get(label.filter_range.start) {
13773 Some(&start) => label.filter_range.start = start,
13774 None => {
13775 wrong_filter_range = original_filter_range.take();
13776 label.filter_range.start = last_index;
13777 }
13778 }
13779
13780 match offset_map.get(label.filter_range.end) {
13781 Some(&end) => label.filter_range.end = end,
13782 None => {
13783 wrong_filter_range = original_filter_range.take();
13784 label.filter_range.end = last_index;
13785 }
13786 }
13787 }
13788 if let Some(wrong_filter_range) = wrong_filter_range {
13789 log::error!(
13790 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13791 label.text
13792 );
13793 }
13794
13795 label.text = new_text;
13796}
13797
13798#[cfg(test)]
13799mod tests {
13800 use language::HighlightId;
13801
13802 use super::*;
13803
13804 #[test]
13805 fn test_glob_literal_prefix() {
13806 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13807 assert_eq!(
13808 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13809 Path::new("node_modules")
13810 );
13811 assert_eq!(
13812 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13813 Path::new("foo")
13814 );
13815 assert_eq!(
13816 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13817 Path::new("foo/bar/baz.js")
13818 );
13819
13820 #[cfg(target_os = "windows")]
13821 {
13822 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13823 assert_eq!(
13824 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13825 Path::new("node_modules")
13826 );
13827 assert_eq!(
13828 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13829 Path::new("foo")
13830 );
13831 assert_eq!(
13832 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13833 Path::new("foo/bar/baz.js")
13834 );
13835 }
13836 }
13837
13838 #[test]
13839 fn test_multi_len_chars_normalization() {
13840 let mut label = CodeLabel::new(
13841 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13842 0..6,
13843 vec![(0..6, HighlightId(1))],
13844 );
13845 ensure_uniform_list_compatible_label(&mut label);
13846 assert_eq!(
13847 label,
13848 CodeLabel::new(
13849 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13850 0..6,
13851 vec![(0..6, HighlightId(1))],
13852 )
13853 );
13854 }
13855}