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