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