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