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