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