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