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