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