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