1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17
18use crate::{
19 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
20 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction,
21 LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
22 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
23 buffer_store::{BufferStore, BufferStoreEvent},
24 environment::ProjectEnvironment,
25 lsp_command::{self, *},
26 lsp_store::{
27 self,
28 log_store::{GlobalLogStore, LanguageServerKind},
29 },
30 manifest_tree::{
31 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
32 ManifestTree,
33 },
34 prettier_store::{self, PrettierStore, PrettierStoreEvent},
35 project_settings::{LspSettings, ProjectSettings},
36 relativize_path, resolve_path,
37 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
38 worktree_store::{WorktreeStore, WorktreeStoreEvent},
39 yarn::YarnPathStore,
40};
41use anyhow::{Context as _, Result, anyhow};
42use async_trait::async_trait;
43use client::{TypedEnvelope, proto};
44use clock::Global;
45use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
46use futures::{
47 AsyncWriteExt, Future, FutureExt, StreamExt,
48 future::{Either, Shared, join_all, pending, select},
49 select, select_biased,
50 stream::FuturesUnordered,
51};
52use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
53use gpui::{
54 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
55 WeakEntity,
56};
57use http_client::HttpClient;
58use itertools::Itertools as _;
59use language::{
60 Bias, BinaryStatus, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
61 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
62 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, ManifestDelegate, ManifestName,
63 Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain, Transaction,
64 Unclipped,
65 language_settings::{
66 FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,
67 },
68 point_to_lsp,
69 proto::{
70 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
71 serialize_lsp_edit, serialize_version,
72 },
73 range_from_lsp, range_to_lsp,
74};
75use lsp::{
76 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
77 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
78 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
79 LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
80 LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture,
81 MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
82 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
83 WorkspaceFolder, notification::DidRenameFiles,
84};
85use node_runtime::read_package_installed_version;
86use parking_lot::Mutex;
87use postage::{mpsc, sink::Sink, stream::Stream, watch};
88use rand::prelude::*;
89
90use rpc::{
91 AnyProtoClient,
92 proto::{FromProto, LspRequestId, LspRequestMessage as _, ToProto},
93};
94use serde::Serialize;
95use settings::{Settings, SettingsLocation, SettingsStore};
96use sha2::{Digest, Sha256};
97use smol::channel::Sender;
98use snippet::Snippet;
99use std::{
100 any::{Any, TypeId},
101 borrow::Cow,
102 cell::RefCell,
103 cmp::{Ordering, Reverse},
104 convert::TryInto,
105 ffi::OsStr,
106 future::ready,
107 iter, mem,
108 ops::{ControlFlow, Range},
109 path::{self, Path, PathBuf},
110 pin::pin,
111 rc::Rc,
112 sync::Arc,
113 time::{Duration, Instant},
114};
115use sum_tree::Dimensions;
116use text::{Anchor, BufferId, LineEnding, OffsetRangeExt};
117
118use util::{
119 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
120 paths::{PathExt, SanitizedPath},
121 post_inc,
122};
123
124pub use fs::*;
125pub use language::Location;
126#[cfg(any(test, feature = "test-support"))]
127pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
128pub use worktree::{
129 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
130 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
131};
132
133const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
134pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub enum FormatTrigger {
138 Save,
139 Manual,
140}
141
142pub enum LspFormatTarget {
143 Buffers,
144 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
145}
146
147pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
148
149impl FormatTrigger {
150 fn from_proto(value: i32) -> FormatTrigger {
151 match value {
152 0 => FormatTrigger::Save,
153 1 => FormatTrigger::Manual,
154 _ => FormatTrigger::Save,
155 }
156 }
157}
158
159#[derive(Clone)]
160struct UnifiedLanguageServer {
161 id: LanguageServerId,
162 project_roots: HashSet<Arc<Path>>,
163}
164
165#[derive(Clone, Hash, PartialEq, Eq)]
166struct LanguageServerSeed {
167 worktree_id: WorktreeId,
168 name: LanguageServerName,
169 toolchain: Option<Toolchain>,
170 settings: Arc<LspSettings>,
171}
172
173#[derive(Debug)]
174pub struct DocumentDiagnosticsUpdate<'a, D> {
175 pub diagnostics: D,
176 pub result_id: Option<String>,
177 pub server_id: LanguageServerId,
178 pub disk_based_sources: Cow<'a, [String]>,
179}
180
181pub struct DocumentDiagnostics {
182 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
183 document_abs_path: PathBuf,
184 version: Option<i32>,
185}
186
187pub struct LocalLspStore {
188 weak: WeakEntity<LspStore>,
189 worktree_store: Entity<WorktreeStore>,
190 toolchain_store: Entity<LocalToolchainStore>,
191 http_client: Arc<dyn HttpClient>,
192 environment: Entity<ProjectEnvironment>,
193 fs: Arc<dyn Fs>,
194 languages: Arc<LanguageRegistry>,
195 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
196 yarn: Entity<YarnPathStore>,
197 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
198 buffers_being_formatted: HashSet<BufferId>,
199 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
200 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
201 watched_manifest_filenames: HashSet<ManifestName>,
202 language_server_paths_watched_for_rename:
203 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
204 language_server_watcher_registrations:
205 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
206 supplementary_language_servers:
207 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
208 prettier_store: Entity<PrettierStore>,
209 next_diagnostic_group_id: usize,
210 diagnostics: HashMap<
211 WorktreeId,
212 HashMap<
213 Arc<Path>,
214 Vec<(
215 LanguageServerId,
216 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
217 )>,
218 >,
219 >,
220 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
221 _subscription: gpui::Subscription,
222 lsp_tree: LanguageServerTree,
223 registered_buffers: HashMap<BufferId, usize>,
224 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
225 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
226}
227
228impl LocalLspStore {
229 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
230 pub fn running_language_server_for_id(
231 &self,
232 id: LanguageServerId,
233 ) -> Option<&Arc<LanguageServer>> {
234 let language_server_state = self.language_servers.get(&id)?;
235
236 match language_server_state {
237 LanguageServerState::Running { server, .. } => Some(server),
238 LanguageServerState::Starting { .. } => None,
239 }
240 }
241
242 fn get_or_insert_language_server(
243 &mut self,
244 worktree_handle: &Entity<Worktree>,
245 delegate: Arc<LocalLspAdapterDelegate>,
246 disposition: &Arc<LaunchDisposition>,
247 language_name: &LanguageName,
248 cx: &mut App,
249 ) -> LanguageServerId {
250 let key = LanguageServerSeed {
251 worktree_id: worktree_handle.read(cx).id(),
252 name: disposition.server_name.clone(),
253 settings: disposition.settings.clone(),
254 toolchain: disposition.toolchain.clone(),
255 };
256 if let Some(state) = self.language_server_ids.get_mut(&key) {
257 state.project_roots.insert(disposition.path.path.clone());
258 state.id
259 } else {
260 let adapter = self
261 .languages
262 .lsp_adapters(language_name)
263 .into_iter()
264 .find(|adapter| adapter.name() == disposition.server_name)
265 .expect("To find LSP adapter");
266 let new_language_server_id = self.start_language_server(
267 worktree_handle,
268 delegate,
269 adapter,
270 disposition.settings.clone(),
271 key.clone(),
272 cx,
273 );
274 if let Some(state) = self.language_server_ids.get_mut(&key) {
275 state.project_roots.insert(disposition.path.path.clone());
276 } else {
277 debug_assert!(
278 false,
279 "Expected `start_language_server` to ensure that `key` exists in a map"
280 );
281 }
282 new_language_server_id
283 }
284 }
285
286 fn start_language_server(
287 &mut self,
288 worktree_handle: &Entity<Worktree>,
289 delegate: Arc<LocalLspAdapterDelegate>,
290 adapter: Arc<CachedLspAdapter>,
291 settings: Arc<LspSettings>,
292 key: LanguageServerSeed,
293 cx: &mut App,
294 ) -> LanguageServerId {
295 let worktree = worktree_handle.read(cx);
296
297 let root_path = worktree.abs_path();
298 let toolchain = key.toolchain.clone();
299 let override_options = settings.initialization_options.clone();
300
301 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
302
303 let server_id = self.languages.next_language_server_id();
304 log::trace!(
305 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
306 adapter.name.0
307 );
308
309 let binary = self.get_language_server_binary(
310 adapter.clone(),
311 settings,
312 toolchain.clone(),
313 delegate.clone(),
314 true,
315 cx,
316 );
317 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
318
319 let pending_server = cx.spawn({
320 let adapter = adapter.clone();
321 let server_name = adapter.name.clone();
322 let stderr_capture = stderr_capture.clone();
323 #[cfg(any(test, feature = "test-support"))]
324 let lsp_store = self.weak.clone();
325 let pending_workspace_folders = pending_workspace_folders.clone();
326 async move |cx| {
327 let binary = binary.await?;
328 #[cfg(any(test, feature = "test-support"))]
329 if let Some(server) = lsp_store
330 .update(&mut cx.clone(), |this, cx| {
331 this.languages.create_fake_language_server(
332 server_id,
333 &server_name,
334 binary.clone(),
335 &mut cx.to_async(),
336 )
337 })
338 .ok()
339 .flatten()
340 {
341 return Ok(server);
342 }
343
344 let code_action_kinds = adapter.code_action_kinds();
345 lsp::LanguageServer::new(
346 stderr_capture,
347 server_id,
348 server_name,
349 binary,
350 &root_path,
351 code_action_kinds,
352 Some(pending_workspace_folders),
353 cx,
354 )
355 }
356 });
357
358 let startup = {
359 let server_name = adapter.name.0.clone();
360 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
361 let key = key.clone();
362 let adapter = adapter.clone();
363 let lsp_store = self.weak.clone();
364 let pending_workspace_folders = pending_workspace_folders.clone();
365 let fs = self.fs.clone();
366 let pull_diagnostics = ProjectSettings::get_global(cx)
367 .diagnostics
368 .lsp_pull_diagnostics
369 .enabled;
370 cx.spawn(async move |cx| {
371 let result = async {
372 let language_server = pending_server.await?;
373
374 let workspace_config = Self::workspace_configuration_for_adapter(
375 adapter.adapter.clone(),
376 fs.as_ref(),
377 &delegate,
378 toolchain,
379 cx,
380 )
381 .await?;
382
383 let mut initialization_options = Self::initialization_options_for_adapter(
384 adapter.adapter.clone(),
385 fs.as_ref(),
386 &delegate,
387 )
388 .await?;
389
390 match (&mut initialization_options, override_options) {
391 (Some(initialization_options), Some(override_options)) => {
392 merge_json_value_into(override_options, initialization_options);
393 }
394 (None, override_options) => initialization_options = override_options,
395 _ => {}
396 }
397
398 let initialization_params = cx.update(|cx| {
399 let mut params =
400 language_server.default_initialize_params(pull_diagnostics, cx);
401 params.initialization_options = initialization_options;
402 adapter.adapter.prepare_initialize_params(params, cx)
403 })??;
404
405 Self::setup_lsp_messages(
406 lsp_store.clone(),
407 fs,
408 &language_server,
409 delegate.clone(),
410 adapter.clone(),
411 );
412
413 let did_change_configuration_params =
414 Arc::new(lsp::DidChangeConfigurationParams {
415 settings: workspace_config,
416 });
417 let language_server = cx
418 .update(|cx| {
419 language_server.initialize(
420 initialization_params,
421 did_change_configuration_params.clone(),
422 cx,
423 )
424 })?
425 .await
426 .inspect_err(|_| {
427 if let Some(lsp_store) = lsp_store.upgrade() {
428 lsp_store
429 .update(cx, |lsp_store, cx| {
430 lsp_store.cleanup_lsp_data(server_id);
431 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
432 })
433 .ok();
434 }
435 })?;
436
437 language_server
438 .notify::<lsp::notification::DidChangeConfiguration>(
439 &did_change_configuration_params,
440 )
441 .ok();
442
443 anyhow::Ok(language_server)
444 }
445 .await;
446
447 match result {
448 Ok(server) => {
449 lsp_store
450 .update(cx, |lsp_store, cx| {
451 lsp_store.insert_newly_running_language_server(
452 adapter,
453 server.clone(),
454 server_id,
455 key,
456 pending_workspace_folders,
457 cx,
458 );
459 })
460 .ok();
461 stderr_capture.lock().take();
462 Some(server)
463 }
464
465 Err(err) => {
466 let log = stderr_capture.lock().take().unwrap_or_default();
467 delegate.update_status(
468 adapter.name(),
469 BinaryStatus::Failed {
470 error: if log.is_empty() {
471 format!("{err:#}")
472 } else {
473 format!("{err:#}\n-- stderr --\n{log}")
474 },
475 },
476 );
477 log::error!("Failed to start language server {server_name:?}: {err:?}");
478 if !log.is_empty() {
479 log::error!("server stderr: {log}");
480 }
481 None
482 }
483 }
484 })
485 };
486 let state = LanguageServerState::Starting {
487 startup,
488 pending_workspace_folders,
489 };
490
491 self.languages
492 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
493
494 self.language_servers.insert(server_id, state);
495 self.language_server_ids
496 .entry(key)
497 .or_insert(UnifiedLanguageServer {
498 id: server_id,
499 project_roots: Default::default(),
500 });
501 server_id
502 }
503
504 fn get_language_server_binary(
505 &self,
506 adapter: Arc<CachedLspAdapter>,
507 settings: Arc<LspSettings>,
508 toolchain: Option<Toolchain>,
509 delegate: Arc<dyn LspAdapterDelegate>,
510 allow_binary_download: bool,
511 cx: &mut App,
512 ) -> Task<Result<LanguageServerBinary>> {
513 if let Some(settings) = settings.binary.as_ref()
514 && settings.path.is_some()
515 {
516 let settings = settings.clone();
517
518 return cx.background_spawn(async move {
519 let mut env = delegate.shell_env().await;
520 env.extend(settings.env.unwrap_or_default());
521
522 Ok(LanguageServerBinary {
523 path: PathBuf::from(&settings.path.unwrap()),
524 env: Some(env),
525 arguments: settings
526 .arguments
527 .unwrap_or_default()
528 .iter()
529 .map(Into::into)
530 .collect(),
531 })
532 });
533 }
534 let lsp_binary_options = LanguageServerBinaryOptions {
535 allow_path_lookup: !settings
536 .binary
537 .as_ref()
538 .and_then(|b| b.ignore_system_version)
539 .unwrap_or_default(),
540 allow_binary_download,
541 };
542
543 cx.spawn(async move |cx| {
544 let binary_result = adapter
545 .clone()
546 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
547 .await;
548
549 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
550
551 let mut binary = binary_result?;
552 let mut shell_env = delegate.shell_env().await;
553
554 shell_env.extend(binary.env.unwrap_or_default());
555
556 if let Some(settings) = settings.binary.as_ref() {
557 if let Some(arguments) = &settings.arguments {
558 binary.arguments = arguments.iter().map(Into::into).collect();
559 }
560 if let Some(env) = &settings.env {
561 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
562 }
563 }
564
565 binary.env = Some(shell_env);
566 Ok(binary)
567 })
568 }
569
570 fn setup_lsp_messages(
571 this: WeakEntity<LspStore>,
572 fs: Arc<dyn Fs>,
573 language_server: &LanguageServer,
574 delegate: Arc<dyn LspAdapterDelegate>,
575 adapter: Arc<CachedLspAdapter>,
576 ) {
577 let name = language_server.name();
578 let server_id = language_server.server_id();
579 language_server
580 .on_notification::<lsp::notification::PublishDiagnostics, _>({
581 let adapter = adapter.clone();
582 let this = this.clone();
583 move |mut params, cx| {
584 let adapter = adapter.clone();
585 if let Some(this) = this.upgrade() {
586 this.update(cx, |this, cx| {
587 {
588 let buffer = params
589 .uri
590 .to_file_path()
591 .map(|file_path| this.get_buffer(&file_path, cx))
592 .ok()
593 .flatten();
594 adapter.process_diagnostics(&mut params, server_id, buffer);
595 }
596
597 this.merge_lsp_diagnostics(
598 DiagnosticSourceKind::Pushed,
599 vec![DocumentDiagnosticsUpdate {
600 server_id,
601 diagnostics: params,
602 result_id: None,
603 disk_based_sources: Cow::Borrowed(
604 &adapter.disk_based_diagnostic_sources,
605 ),
606 }],
607 |_, diagnostic, cx| match diagnostic.source_kind {
608 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
609 adapter.retain_old_diagnostic(diagnostic, cx)
610 }
611 DiagnosticSourceKind::Pulled => true,
612 },
613 cx,
614 )
615 .log_err();
616 })
617 .ok();
618 }
619 }
620 })
621 .detach();
622 language_server
623 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
624 let adapter = adapter.adapter.clone();
625 let delegate = delegate.clone();
626 let this = this.clone();
627 let fs = fs.clone();
628 move |params, cx| {
629 let adapter = adapter.clone();
630 let delegate = delegate.clone();
631 let this = this.clone();
632 let fs = fs.clone();
633 let mut cx = cx.clone();
634 async move {
635 let toolchain_for_id = this
636 .update(&mut cx, |this, _| {
637 this.as_local()?.language_server_ids.iter().find_map(
638 |(seed, value)| {
639 (value.id == server_id).then(|| seed.toolchain.clone())
640 },
641 )
642 })?
643 .context("Expected the LSP store to be in a local mode")?;
644 let workspace_config = Self::workspace_configuration_for_adapter(
645 adapter.clone(),
646 fs.as_ref(),
647 &delegate,
648 toolchain_for_id,
649 &mut cx,
650 )
651 .await?;
652
653 Ok(params
654 .items
655 .into_iter()
656 .map(|item| {
657 if let Some(section) = &item.section {
658 workspace_config
659 .get(section)
660 .cloned()
661 .unwrap_or(serde_json::Value::Null)
662 } else {
663 workspace_config.clone()
664 }
665 })
666 .collect())
667 }
668 }
669 })
670 .detach();
671
672 language_server
673 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
674 let this = this.clone();
675 move |_, cx| {
676 let this = this.clone();
677 let cx = cx.clone();
678 async move {
679 let Some(server) =
680 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
681 else {
682 return Ok(None);
683 };
684 let root = server.workspace_folders();
685 Ok(Some(
686 root.into_iter()
687 .map(|uri| WorkspaceFolder {
688 uri,
689 name: Default::default(),
690 })
691 .collect(),
692 ))
693 }
694 }
695 })
696 .detach();
697 // Even though we don't have handling for these requests, respond to them to
698 // avoid stalling any language server like `gopls` which waits for a response
699 // to these requests when initializing.
700 language_server
701 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
702 let this = this.clone();
703 move |params, cx| {
704 let this = this.clone();
705 let mut cx = cx.clone();
706 async move {
707 this.update(&mut cx, |this, _| {
708 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
709 && let lsp::NumberOrString::String(token) = params.token
710 {
711 status.progress_tokens.insert(token);
712 }
713 })?;
714
715 Ok(())
716 }
717 }
718 })
719 .detach();
720
721 language_server
722 .on_request::<lsp::request::RegisterCapability, _, _>({
723 let lsp_store = this.clone();
724 move |params, cx| {
725 let lsp_store = lsp_store.clone();
726 let mut cx = cx.clone();
727 async move {
728 lsp_store
729 .update(&mut cx, |lsp_store, cx| {
730 if lsp_store.as_local().is_some() {
731 match lsp_store
732 .register_server_capabilities(server_id, params, cx)
733 {
734 Ok(()) => {}
735 Err(e) => {
736 log::error!(
737 "Failed to register server capabilities: {e:#}"
738 );
739 }
740 };
741 }
742 })
743 .ok();
744 Ok(())
745 }
746 }
747 })
748 .detach();
749
750 language_server
751 .on_request::<lsp::request::UnregisterCapability, _, _>({
752 let lsp_store = this.clone();
753 move |params, cx| {
754 let lsp_store = lsp_store.clone();
755 let mut cx = cx.clone();
756 async move {
757 lsp_store
758 .update(&mut cx, |lsp_store, cx| {
759 if lsp_store.as_local().is_some() {
760 match lsp_store
761 .unregister_server_capabilities(server_id, params, cx)
762 {
763 Ok(()) => {}
764 Err(e) => {
765 log::error!(
766 "Failed to unregister server capabilities: {e:#}"
767 );
768 }
769 }
770 }
771 })
772 .ok();
773 Ok(())
774 }
775 }
776 })
777 .detach();
778
779 language_server
780 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
781 let this = this.clone();
782 move |params, cx| {
783 let mut cx = cx.clone();
784 let this = this.clone();
785 async move {
786 LocalLspStore::on_lsp_workspace_edit(
787 this.clone(),
788 params,
789 server_id,
790 &mut cx,
791 )
792 .await
793 }
794 }
795 })
796 .detach();
797
798 language_server
799 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
800 let this = this.clone();
801 move |(), cx| {
802 let this = this.clone();
803 let mut cx = cx.clone();
804 async move {
805 this.update(&mut cx, |this, cx| {
806 cx.emit(LspStoreEvent::RefreshInlayHints);
807 this.downstream_client.as_ref().map(|(client, project_id)| {
808 client.send(proto::RefreshInlayHints {
809 project_id: *project_id,
810 })
811 })
812 })?
813 .transpose()?;
814 Ok(())
815 }
816 }
817 })
818 .detach();
819
820 language_server
821 .on_request::<lsp::request::CodeLensRefresh, _, _>({
822 let this = this.clone();
823 move |(), cx| {
824 let this = this.clone();
825 let mut cx = cx.clone();
826 async move {
827 this.update(&mut cx, |this, cx| {
828 cx.emit(LspStoreEvent::RefreshCodeLens);
829 this.downstream_client.as_ref().map(|(client, project_id)| {
830 client.send(proto::RefreshCodeLens {
831 project_id: *project_id,
832 })
833 })
834 })?
835 .transpose()?;
836 Ok(())
837 }
838 }
839 })
840 .detach();
841
842 language_server
843 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
844 let this = this.clone();
845 move |(), cx| {
846 let this = this.clone();
847 let mut cx = cx.clone();
848 async move {
849 this.update(&mut cx, |lsp_store, _| {
850 lsp_store.pull_workspace_diagnostics(server_id);
851 lsp_store
852 .downstream_client
853 .as_ref()
854 .map(|(client, project_id)| {
855 client.send(proto::PullWorkspaceDiagnostics {
856 project_id: *project_id,
857 server_id: server_id.to_proto(),
858 })
859 })
860 })?
861 .transpose()?;
862 Ok(())
863 }
864 }
865 })
866 .detach();
867
868 language_server
869 .on_request::<lsp::request::ShowMessageRequest, _, _>({
870 let this = this.clone();
871 let name = name.to_string();
872 move |params, cx| {
873 let this = this.clone();
874 let name = name.to_string();
875 let mut cx = cx.clone();
876 async move {
877 let actions = params.actions.unwrap_or_default();
878 let (tx, rx) = smol::channel::bounded(1);
879 let request = LanguageServerPromptRequest {
880 level: match params.typ {
881 lsp::MessageType::ERROR => PromptLevel::Critical,
882 lsp::MessageType::WARNING => PromptLevel::Warning,
883 _ => PromptLevel::Info,
884 },
885 message: params.message,
886 actions,
887 response_channel: tx,
888 lsp_name: name.clone(),
889 };
890
891 let did_update = this
892 .update(&mut cx, |_, cx| {
893 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
894 })
895 .is_ok();
896 if did_update {
897 let response = rx.recv().await.ok();
898 Ok(response)
899 } else {
900 Ok(None)
901 }
902 }
903 }
904 })
905 .detach();
906 language_server
907 .on_notification::<lsp::notification::ShowMessage, _>({
908 let this = this.clone();
909 let name = name.to_string();
910 move |params, cx| {
911 let this = this.clone();
912 let name = name.to_string();
913 let mut cx = cx.clone();
914
915 let (tx, _) = smol::channel::bounded(1);
916 let request = LanguageServerPromptRequest {
917 level: match params.typ {
918 lsp::MessageType::ERROR => PromptLevel::Critical,
919 lsp::MessageType::WARNING => PromptLevel::Warning,
920 _ => PromptLevel::Info,
921 },
922 message: params.message,
923 actions: vec![],
924 response_channel: tx,
925 lsp_name: name,
926 };
927
928 let _ = this.update(&mut cx, |_, cx| {
929 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
930 });
931 }
932 })
933 .detach();
934
935 let disk_based_diagnostics_progress_token =
936 adapter.disk_based_diagnostics_progress_token.clone();
937
938 language_server
939 .on_notification::<lsp::notification::Progress, _>({
940 let this = this.clone();
941 move |params, cx| {
942 if let Some(this) = this.upgrade() {
943 this.update(cx, |this, cx| {
944 this.on_lsp_progress(
945 params,
946 server_id,
947 disk_based_diagnostics_progress_token.clone(),
948 cx,
949 );
950 })
951 .ok();
952 }
953 }
954 })
955 .detach();
956
957 language_server
958 .on_notification::<lsp::notification::LogMessage, _>({
959 let this = this.clone();
960 move |params, cx| {
961 if let Some(this) = this.upgrade() {
962 this.update(cx, |_, cx| {
963 cx.emit(LspStoreEvent::LanguageServerLog(
964 server_id,
965 LanguageServerLogType::Log(params.typ),
966 params.message,
967 ));
968 })
969 .ok();
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_notification::<lsp::notification::LogTrace, _>({
977 let this = this.clone();
978 move |params, cx| {
979 let mut cx = cx.clone();
980 if let Some(this) = this.upgrade() {
981 this.update(&mut cx, |_, cx| {
982 cx.emit(LspStoreEvent::LanguageServerLog(
983 server_id,
984 LanguageServerLogType::Trace {
985 verbose_info: params.verbose,
986 },
987 params.message,
988 ));
989 })
990 .ok();
991 }
992 }
993 })
994 .detach();
995
996 json_language_server_ext::register_requests(this.clone(), language_server);
997 rust_analyzer_ext::register_notifications(this.clone(), language_server);
998 clangd_ext::register_notifications(this, language_server, adapter);
999 }
1000
1001 fn shutdown_language_servers_on_quit(
1002 &mut self,
1003 _: &mut Context<LspStore>,
1004 ) -> impl Future<Output = ()> + use<> {
1005 let shutdown_futures = self
1006 .language_servers
1007 .drain()
1008 .map(|(_, server_state)| Self::shutdown_server(server_state))
1009 .collect::<Vec<_>>();
1010
1011 async move {
1012 join_all(shutdown_futures).await;
1013 }
1014 }
1015
1016 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1017 match server_state {
1018 LanguageServerState::Running { server, .. } => {
1019 if let Some(shutdown) = server.shutdown() {
1020 shutdown.await;
1021 }
1022 }
1023 LanguageServerState::Starting { startup, .. } => {
1024 if let Some(server) = startup.await
1025 && let Some(shutdown) = server.shutdown()
1026 {
1027 shutdown.await;
1028 }
1029 }
1030 }
1031 Ok(())
1032 }
1033
1034 fn language_servers_for_worktree(
1035 &self,
1036 worktree_id: WorktreeId,
1037 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1038 self.language_server_ids
1039 .iter()
1040 .filter_map(move |(seed, state)| {
1041 if seed.worktree_id != worktree_id {
1042 return None;
1043 }
1044
1045 if let Some(LanguageServerState::Running { server, .. }) =
1046 self.language_servers.get(&state.id)
1047 {
1048 Some(server)
1049 } else {
1050 None
1051 }
1052 })
1053 }
1054
1055 fn language_server_ids_for_project_path(
1056 &self,
1057 project_path: ProjectPath,
1058 language: &Language,
1059 cx: &mut App,
1060 ) -> Vec<LanguageServerId> {
1061 let Some(worktree) = self
1062 .worktree_store
1063 .read(cx)
1064 .worktree_for_id(project_path.worktree_id, cx)
1065 else {
1066 return Vec::new();
1067 };
1068 let delegate: Arc<dyn ManifestDelegate> =
1069 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1070
1071 self.lsp_tree
1072 .get(
1073 project_path,
1074 language.name(),
1075 language.manifest(),
1076 &delegate,
1077 cx,
1078 )
1079 .collect::<Vec<_>>()
1080 }
1081
1082 fn language_server_ids_for_buffer(
1083 &self,
1084 buffer: &Buffer,
1085 cx: &mut App,
1086 ) -> Vec<LanguageServerId> {
1087 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1088 let worktree_id = file.worktree_id(cx);
1089
1090 let path: Arc<Path> = file
1091 .path()
1092 .parent()
1093 .map(Arc::from)
1094 .unwrap_or_else(|| file.path().clone());
1095 let worktree_path = ProjectPath { worktree_id, path };
1096 self.language_server_ids_for_project_path(worktree_path, language, cx)
1097 } else {
1098 Vec::new()
1099 }
1100 }
1101
1102 fn language_servers_for_buffer<'a>(
1103 &'a self,
1104 buffer: &'a Buffer,
1105 cx: &'a mut App,
1106 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1107 self.language_server_ids_for_buffer(buffer, cx)
1108 .into_iter()
1109 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1110 LanguageServerState::Running {
1111 adapter, server, ..
1112 } => Some((adapter, server)),
1113 _ => None,
1114 })
1115 }
1116
1117 async fn execute_code_action_kind_locally(
1118 lsp_store: WeakEntity<LspStore>,
1119 mut buffers: Vec<Entity<Buffer>>,
1120 kind: CodeActionKind,
1121 push_to_history: bool,
1122 cx: &mut AsyncApp,
1123 ) -> anyhow::Result<ProjectTransaction> {
1124 // Do not allow multiple concurrent code actions requests for the
1125 // same buffer.
1126 lsp_store.update(cx, |this, cx| {
1127 let this = this.as_local_mut().unwrap();
1128 buffers.retain(|buffer| {
1129 this.buffers_being_formatted
1130 .insert(buffer.read(cx).remote_id())
1131 });
1132 })?;
1133 let _cleanup = defer({
1134 let this = lsp_store.clone();
1135 let mut cx = cx.clone();
1136 let buffers = &buffers;
1137 move || {
1138 this.update(&mut cx, |this, cx| {
1139 let this = this.as_local_mut().unwrap();
1140 for buffer in buffers {
1141 this.buffers_being_formatted
1142 .remove(&buffer.read(cx).remote_id());
1143 }
1144 })
1145 .ok();
1146 }
1147 });
1148 let mut project_transaction = ProjectTransaction::default();
1149
1150 for buffer in &buffers {
1151 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1152 buffer.update(cx, |buffer, cx| {
1153 lsp_store
1154 .as_local()
1155 .unwrap()
1156 .language_servers_for_buffer(buffer, cx)
1157 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1158 .collect::<Vec<_>>()
1159 })
1160 })?;
1161 for (_, language_server) in adapters_and_servers.iter() {
1162 let actions = Self::get_server_code_actions_from_action_kinds(
1163 &lsp_store,
1164 language_server.server_id(),
1165 vec![kind.clone()],
1166 buffer,
1167 cx,
1168 )
1169 .await?;
1170 Self::execute_code_actions_on_server(
1171 &lsp_store,
1172 language_server,
1173 actions,
1174 push_to_history,
1175 &mut project_transaction,
1176 cx,
1177 )
1178 .await?;
1179 }
1180 }
1181 Ok(project_transaction)
1182 }
1183
1184 async fn format_locally(
1185 lsp_store: WeakEntity<LspStore>,
1186 mut buffers: Vec<FormattableBuffer>,
1187 push_to_history: bool,
1188 trigger: FormatTrigger,
1189 logger: zlog::Logger,
1190 cx: &mut AsyncApp,
1191 ) -> anyhow::Result<ProjectTransaction> {
1192 // Do not allow multiple concurrent formatting requests for the
1193 // same buffer.
1194 lsp_store.update(cx, |this, cx| {
1195 let this = this.as_local_mut().unwrap();
1196 buffers.retain(|buffer| {
1197 this.buffers_being_formatted
1198 .insert(buffer.handle.read(cx).remote_id())
1199 });
1200 })?;
1201
1202 let _cleanup = defer({
1203 let this = lsp_store.clone();
1204 let mut cx = cx.clone();
1205 let buffers = &buffers;
1206 move || {
1207 this.update(&mut cx, |this, cx| {
1208 let this = this.as_local_mut().unwrap();
1209 for buffer in buffers {
1210 this.buffers_being_formatted
1211 .remove(&buffer.handle.read(cx).remote_id());
1212 }
1213 })
1214 .ok();
1215 }
1216 });
1217
1218 let mut project_transaction = ProjectTransaction::default();
1219
1220 for buffer in &buffers {
1221 zlog::debug!(
1222 logger =>
1223 "formatting buffer '{:?}'",
1224 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1225 );
1226 // Create an empty transaction to hold all of the formatting edits.
1227 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1228 // ensure no transactions created while formatting are
1229 // grouped with the previous transaction in the history
1230 // based on the transaction group interval
1231 buffer.finalize_last_transaction();
1232 buffer
1233 .start_transaction()
1234 .context("transaction already open")?;
1235 buffer.end_transaction(cx);
1236 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1237 buffer.finalize_last_transaction();
1238 anyhow::Ok(transaction_id)
1239 })??;
1240
1241 let result = Self::format_buffer_locally(
1242 lsp_store.clone(),
1243 buffer,
1244 formatting_transaction_id,
1245 trigger,
1246 logger,
1247 cx,
1248 )
1249 .await;
1250
1251 buffer.handle.update(cx, |buffer, cx| {
1252 let Some(formatting_transaction) =
1253 buffer.get_transaction(formatting_transaction_id).cloned()
1254 else {
1255 zlog::warn!(logger => "no formatting transaction");
1256 return;
1257 };
1258 if formatting_transaction.edit_ids.is_empty() {
1259 zlog::debug!(logger => "no changes made while formatting");
1260 buffer.forget_transaction(formatting_transaction_id);
1261 return;
1262 }
1263 if !push_to_history {
1264 zlog::trace!(logger => "forgetting format transaction");
1265 buffer.forget_transaction(formatting_transaction.id);
1266 }
1267 project_transaction
1268 .0
1269 .insert(cx.entity(), formatting_transaction);
1270 })?;
1271
1272 result?;
1273 }
1274
1275 Ok(project_transaction)
1276 }
1277
1278 async fn format_buffer_locally(
1279 lsp_store: WeakEntity<LspStore>,
1280 buffer: &FormattableBuffer,
1281 formatting_transaction_id: clock::Lamport,
1282 trigger: FormatTrigger,
1283 logger: zlog::Logger,
1284 cx: &mut AsyncApp,
1285 ) -> Result<()> {
1286 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1287 buffer.handle.update(cx, |buffer, cx| {
1288 let adapters_and_servers = lsp_store
1289 .as_local()
1290 .unwrap()
1291 .language_servers_for_buffer(buffer, cx)
1292 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1293 .collect::<Vec<_>>();
1294 let settings =
1295 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1296 .into_owned();
1297 (adapters_and_servers, settings)
1298 })
1299 })?;
1300
1301 /// Apply edits to the buffer that will become part of the formatting transaction.
1302 /// Fails if the buffer has been edited since the start of that transaction.
1303 fn extend_formatting_transaction(
1304 buffer: &FormattableBuffer,
1305 formatting_transaction_id: text::TransactionId,
1306 cx: &mut AsyncApp,
1307 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1308 ) -> anyhow::Result<()> {
1309 buffer.handle.update(cx, |buffer, cx| {
1310 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1311 if last_transaction_id != Some(formatting_transaction_id) {
1312 anyhow::bail!("Buffer edited while formatting. Aborting")
1313 }
1314 buffer.start_transaction();
1315 operation(buffer, cx);
1316 if let Some(transaction_id) = buffer.end_transaction(cx) {
1317 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1318 }
1319 Ok(())
1320 })?
1321 }
1322
1323 // handle whitespace formatting
1324 if settings.remove_trailing_whitespace_on_save {
1325 zlog::trace!(logger => "removing trailing whitespace");
1326 let diff = buffer
1327 .handle
1328 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1329 .await;
1330 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1331 buffer.apply_diff(diff, cx);
1332 })?;
1333 }
1334
1335 if settings.ensure_final_newline_on_save {
1336 zlog::trace!(logger => "ensuring final newline");
1337 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1338 buffer.ensure_final_newline(cx);
1339 })?;
1340 }
1341
1342 // Formatter for `code_actions_on_format` that runs before
1343 // the rest of the formatters
1344 let mut code_actions_on_format_formatter = None;
1345 let should_run_code_actions_on_format = !matches!(
1346 (trigger, &settings.format_on_save),
1347 (FormatTrigger::Save, &FormatOnSave::Off)
1348 );
1349 if should_run_code_actions_on_format {
1350 let have_code_actions_to_run_on_format = settings
1351 .code_actions_on_format
1352 .values()
1353 .any(|enabled| *enabled);
1354 if have_code_actions_to_run_on_format {
1355 zlog::trace!(logger => "going to run code actions on format");
1356 code_actions_on_format_formatter = Some(Formatter::CodeActions(
1357 settings.code_actions_on_format.clone(),
1358 ));
1359 }
1360 }
1361
1362 let formatters = match (trigger, &settings.format_on_save) {
1363 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1364 (FormatTrigger::Save, FormatOnSave::List(formatters)) => formatters.as_ref(),
1365 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1366 match &settings.formatter {
1367 SelectedFormatter::Auto => {
1368 if settings.prettier.allowed {
1369 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1370 std::slice::from_ref(&Formatter::Prettier)
1371 } else {
1372 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1373 std::slice::from_ref(&Formatter::LanguageServer { name: None })
1374 }
1375 }
1376 SelectedFormatter::List(formatter_list) => formatter_list.as_ref(),
1377 }
1378 }
1379 };
1380
1381 let formatters = code_actions_on_format_formatter.iter().chain(formatters);
1382
1383 for formatter in formatters {
1384 match formatter {
1385 Formatter::Prettier => {
1386 let logger = zlog::scoped!(logger => "prettier");
1387 zlog::trace!(logger => "formatting");
1388 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1389
1390 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1391 lsp_store.prettier_store().unwrap().downgrade()
1392 })?;
1393 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1394 .await
1395 .transpose()?;
1396 let Some(diff) = diff else {
1397 zlog::trace!(logger => "No changes");
1398 continue;
1399 };
1400
1401 extend_formatting_transaction(
1402 buffer,
1403 formatting_transaction_id,
1404 cx,
1405 |buffer, cx| {
1406 buffer.apply_diff(diff, cx);
1407 },
1408 )?;
1409 }
1410 Formatter::External { command, arguments } => {
1411 let logger = zlog::scoped!(logger => "command");
1412 zlog::trace!(logger => "formatting");
1413 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1414
1415 let diff = Self::format_via_external_command(
1416 buffer,
1417 command.as_ref(),
1418 arguments.as_deref(),
1419 cx,
1420 )
1421 .await
1422 .with_context(|| {
1423 format!("Failed to format buffer via external command: {}", command)
1424 })?;
1425 let Some(diff) = diff else {
1426 zlog::trace!(logger => "No changes");
1427 continue;
1428 };
1429
1430 extend_formatting_transaction(
1431 buffer,
1432 formatting_transaction_id,
1433 cx,
1434 |buffer, cx| {
1435 buffer.apply_diff(diff, cx);
1436 },
1437 )?;
1438 }
1439 Formatter::LanguageServer { name } => {
1440 let logger = zlog::scoped!(logger => "language-server");
1441 zlog::trace!(logger => "formatting");
1442 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1443
1444 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1445 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1446 continue;
1447 };
1448
1449 let language_server = if let Some(name) = name.as_deref() {
1450 adapters_and_servers.iter().find_map(|(adapter, server)| {
1451 if adapter.name.0.as_ref() == name {
1452 Some(server.clone())
1453 } else {
1454 None
1455 }
1456 })
1457 } else {
1458 adapters_and_servers.first().map(|e| e.1.clone())
1459 };
1460
1461 let Some(language_server) = language_server else {
1462 log::debug!(
1463 "No language server found to format buffer '{:?}'. Skipping",
1464 buffer_path_abs.as_path().to_string_lossy()
1465 );
1466 continue;
1467 };
1468
1469 zlog::trace!(
1470 logger =>
1471 "Formatting buffer '{:?}' using language server '{:?}'",
1472 buffer_path_abs.as_path().to_string_lossy(),
1473 language_server.name()
1474 );
1475
1476 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1477 zlog::trace!(logger => "formatting ranges");
1478 Self::format_ranges_via_lsp(
1479 &lsp_store,
1480 &buffer.handle,
1481 ranges,
1482 buffer_path_abs,
1483 &language_server,
1484 &settings,
1485 cx,
1486 )
1487 .await
1488 .context("Failed to format ranges via language server")?
1489 } else {
1490 zlog::trace!(logger => "formatting full");
1491 Self::format_via_lsp(
1492 &lsp_store,
1493 &buffer.handle,
1494 buffer_path_abs,
1495 &language_server,
1496 &settings,
1497 cx,
1498 )
1499 .await
1500 .context("failed to format via language server")?
1501 };
1502
1503 if edits.is_empty() {
1504 zlog::trace!(logger => "No changes");
1505 continue;
1506 }
1507 extend_formatting_transaction(
1508 buffer,
1509 formatting_transaction_id,
1510 cx,
1511 |buffer, cx| {
1512 buffer.edit(edits, None, cx);
1513 },
1514 )?;
1515 }
1516 Formatter::CodeActions(code_actions) => {
1517 let logger = zlog::scoped!(logger => "code-actions");
1518 zlog::trace!(logger => "formatting");
1519 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1520
1521 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1522 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1523 continue;
1524 };
1525 let code_action_kinds = code_actions
1526 .iter()
1527 .filter_map(|(action_kind, enabled)| {
1528 enabled.then_some(action_kind.clone().into())
1529 })
1530 .collect::<Vec<_>>();
1531 if code_action_kinds.is_empty() {
1532 zlog::trace!(logger => "No code action kinds enabled, skipping");
1533 continue;
1534 }
1535 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kinds);
1536
1537 let mut actions_and_servers = Vec::new();
1538
1539 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1540 let actions_result = Self::get_server_code_actions_from_action_kinds(
1541 &lsp_store,
1542 language_server.server_id(),
1543 code_action_kinds.clone(),
1544 &buffer.handle,
1545 cx,
1546 )
1547 .await
1548 .with_context(
1549 || format!("Failed to resolve code actions with kinds {:?} for language server {}",
1550 code_action_kinds.iter().map(|kind| kind.as_str()).join(", "),
1551 language_server.name())
1552 );
1553 let Ok(actions) = actions_result else {
1554 // note: it may be better to set result to the error and break formatters here
1555 // but for now we try to execute the actions that we can resolve and skip the rest
1556 zlog::error!(
1557 logger =>
1558 "Failed to resolve code actions with kinds {:?} with language server {}",
1559 code_action_kinds.iter().map(|kind| kind.as_str()).join(", "),
1560 language_server.name()
1561 );
1562 continue;
1563 };
1564 for action in actions {
1565 actions_and_servers.push((action, index));
1566 }
1567 }
1568
1569 if actions_and_servers.is_empty() {
1570 zlog::warn!(logger => "No code actions were resolved, continuing");
1571 continue;
1572 }
1573
1574 'actions: for (mut action, server_index) in actions_and_servers {
1575 let server = &adapters_and_servers[server_index].1;
1576
1577 let describe_code_action = |action: &CodeAction| {
1578 format!(
1579 "code action '{}' with title \"{}\" on server {}",
1580 action
1581 .lsp_action
1582 .action_kind()
1583 .unwrap_or("unknown".into())
1584 .as_str(),
1585 action.lsp_action.title(),
1586 server.name(),
1587 )
1588 };
1589
1590 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1591
1592 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1593 zlog::error!(
1594 logger =>
1595 "Failed to resolve {}. Error: {}",
1596 describe_code_action(&action),
1597 err
1598 );
1599 continue;
1600 }
1601
1602 if let Some(edit) = action.lsp_action.edit().cloned() {
1603 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1604 // but filters out and logs warnings for code actions that cause unreasonably
1605 // difficult handling on our part, such as:
1606 // - applying edits that call commands
1607 // which can result in arbitrary workspace edits being sent from the server that
1608 // have no way of being tied back to the command that initiated them (i.e. we
1609 // can't know which edits are part of the format request, or if the server is done sending
1610 // actions in response to the command)
1611 // - actions that create/delete/modify/rename files other than the one we are formatting
1612 // as we then would need to handle such changes correctly in the local history as well
1613 // as the remote history through the ProjectTransaction
1614 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1615 // Supporting these actions is not impossible, but not supported as of yet.
1616 if edit.changes.is_none() && edit.document_changes.is_none() {
1617 zlog::trace!(
1618 logger =>
1619 "No changes for code action. Skipping {}",
1620 describe_code_action(&action),
1621 );
1622 continue;
1623 }
1624
1625 let mut operations = Vec::new();
1626 if let Some(document_changes) = edit.document_changes {
1627 match document_changes {
1628 lsp::DocumentChanges::Edits(edits) => operations.extend(
1629 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1630 ),
1631 lsp::DocumentChanges::Operations(ops) => operations = ops,
1632 }
1633 } else if let Some(changes) = edit.changes {
1634 operations.extend(changes.into_iter().map(|(uri, edits)| {
1635 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1636 text_document:
1637 lsp::OptionalVersionedTextDocumentIdentifier {
1638 uri,
1639 version: None,
1640 },
1641 edits: edits.into_iter().map(Edit::Plain).collect(),
1642 })
1643 }));
1644 }
1645
1646 let mut edits = Vec::with_capacity(operations.len());
1647
1648 if operations.is_empty() {
1649 zlog::trace!(
1650 logger =>
1651 "No changes for code action. Skipping {}",
1652 describe_code_action(&action),
1653 );
1654 continue;
1655 }
1656 for operation in operations {
1657 let op = match operation {
1658 lsp::DocumentChangeOperation::Edit(op) => op,
1659 lsp::DocumentChangeOperation::Op(_) => {
1660 zlog::warn!(
1661 logger =>
1662 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1663 describe_code_action(&action),
1664 );
1665 continue 'actions;
1666 }
1667 };
1668 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1669 zlog::warn!(
1670 logger =>
1671 "Failed to convert URI '{:?}' to file path. Skipping {}",
1672 &op.text_document.uri,
1673 describe_code_action(&action),
1674 );
1675 continue 'actions;
1676 };
1677 if &file_path != buffer_path_abs {
1678 zlog::warn!(
1679 logger =>
1680 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1681 file_path,
1682 buffer_path_abs,
1683 describe_code_action(&action),
1684 );
1685 continue 'actions;
1686 }
1687
1688 let mut lsp_edits = Vec::new();
1689 for edit in op.edits {
1690 match edit {
1691 Edit::Plain(edit) => {
1692 if !lsp_edits.contains(&edit) {
1693 lsp_edits.push(edit);
1694 }
1695 }
1696 Edit::Annotated(edit) => {
1697 if !lsp_edits.contains(&edit.text_edit) {
1698 lsp_edits.push(edit.text_edit);
1699 }
1700 }
1701 Edit::Snippet(_) => {
1702 zlog::warn!(
1703 logger =>
1704 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1705 describe_code_action(&action),
1706 );
1707 continue 'actions;
1708 }
1709 }
1710 }
1711 let edits_result = lsp_store
1712 .update(cx, |lsp_store, cx| {
1713 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1714 &buffer.handle,
1715 lsp_edits,
1716 server.server_id(),
1717 op.text_document.version,
1718 cx,
1719 )
1720 })?
1721 .await;
1722 let Ok(resolved_edits) = edits_result else {
1723 zlog::warn!(
1724 logger =>
1725 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1726 buffer_path_abs.as_path(),
1727 describe_code_action(&action),
1728 );
1729 continue 'actions;
1730 };
1731 edits.extend(resolved_edits);
1732 }
1733
1734 if edits.is_empty() {
1735 zlog::warn!(logger => "No edits resolved from LSP");
1736 continue;
1737 }
1738
1739 extend_formatting_transaction(
1740 buffer,
1741 formatting_transaction_id,
1742 cx,
1743 |buffer, cx| {
1744 buffer.edit(edits, None, cx);
1745 },
1746 )?;
1747 }
1748
1749 if let Some(command) = action.lsp_action.command() {
1750 zlog::warn!(
1751 logger =>
1752 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1753 &command.command,
1754 );
1755
1756 // bail early if command is invalid
1757 let server_capabilities = server.capabilities();
1758 let available_commands = server_capabilities
1759 .execute_command_provider
1760 .as_ref()
1761 .map(|options| options.commands.as_slice())
1762 .unwrap_or_default();
1763 if !available_commands.contains(&command.command) {
1764 zlog::warn!(
1765 logger =>
1766 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1767 command.command,
1768 server.name(),
1769 );
1770 continue;
1771 }
1772
1773 // noop so we just ensure buffer hasn't been edited since resolving code actions
1774 extend_formatting_transaction(
1775 buffer,
1776 formatting_transaction_id,
1777 cx,
1778 |_, _| {},
1779 )?;
1780 zlog::info!(logger => "Executing command {}", &command.command);
1781
1782 lsp_store.update(cx, |this, _| {
1783 this.as_local_mut()
1784 .unwrap()
1785 .last_workspace_edits_by_language_server
1786 .remove(&server.server_id());
1787 })?;
1788
1789 let execute_command_result = server
1790 .request::<lsp::request::ExecuteCommand>(
1791 lsp::ExecuteCommandParams {
1792 command: command.command.clone(),
1793 arguments: command.arguments.clone().unwrap_or_default(),
1794 ..Default::default()
1795 },
1796 )
1797 .await
1798 .into_response();
1799
1800 if execute_command_result.is_err() {
1801 zlog::error!(
1802 logger =>
1803 "Failed to execute command '{}' as part of {}",
1804 &command.command,
1805 describe_code_action(&action),
1806 );
1807 continue 'actions;
1808 }
1809
1810 let mut project_transaction_command =
1811 lsp_store.update(cx, |this, _| {
1812 this.as_local_mut()
1813 .unwrap()
1814 .last_workspace_edits_by_language_server
1815 .remove(&server.server_id())
1816 .unwrap_or_default()
1817 })?;
1818
1819 if let Some(transaction) =
1820 project_transaction_command.0.remove(&buffer.handle)
1821 {
1822 zlog::trace!(
1823 logger =>
1824 "Successfully captured {} edits that resulted from command {}",
1825 transaction.edit_ids.len(),
1826 &command.command,
1827 );
1828 let transaction_id_project_transaction = transaction.id;
1829 buffer.handle.update(cx, |buffer, _| {
1830 // it may have been removed from history if push_to_history was
1831 // false in deserialize_workspace_edit. If so push it so we
1832 // can merge it with the format transaction
1833 // and pop the combined transaction off the history stack
1834 // later if push_to_history is false
1835 if buffer.get_transaction(transaction.id).is_none() {
1836 buffer.push_transaction(transaction, Instant::now());
1837 }
1838 buffer.merge_transactions(
1839 transaction_id_project_transaction,
1840 formatting_transaction_id,
1841 );
1842 })?;
1843 }
1844
1845 if !project_transaction_command.0.is_empty() {
1846 let extra_buffers = project_transaction_command
1847 .0
1848 .keys()
1849 .filter_map(|buffer_handle| {
1850 buffer_handle
1851 .read_with(cx, |b, cx| b.project_path(cx))
1852 .ok()
1853 .flatten()
1854 })
1855 .map(|p| p.path.to_sanitized_string())
1856 .join(", ");
1857 zlog::warn!(
1858 logger =>
1859 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1860 &command.command,
1861 extra_buffers,
1862 );
1863 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1864 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1865 // add it so it's included, and merge it into the format transaction when its created later
1866 }
1867 }
1868 }
1869 }
1870 }
1871 }
1872
1873 Ok(())
1874 }
1875
1876 pub async fn format_ranges_via_lsp(
1877 this: &WeakEntity<LspStore>,
1878 buffer_handle: &Entity<Buffer>,
1879 ranges: &[Range<Anchor>],
1880 abs_path: &Path,
1881 language_server: &Arc<LanguageServer>,
1882 settings: &LanguageSettings,
1883 cx: &mut AsyncApp,
1884 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1885 let capabilities = &language_server.capabilities();
1886 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1887 if range_formatting_provider == Some(&OneOf::Left(false)) {
1888 anyhow::bail!(
1889 "{} language server does not support range formatting",
1890 language_server.name()
1891 );
1892 }
1893
1894 let uri = file_path_to_lsp_url(abs_path)?;
1895 let text_document = lsp::TextDocumentIdentifier::new(uri);
1896
1897 let lsp_edits = {
1898 let mut lsp_ranges = Vec::new();
1899 this.update(cx, |_this, cx| {
1900 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1901 // not have been sent to the language server. This seems like a fairly systemic
1902 // issue, though, the resolution probably is not specific to formatting.
1903 //
1904 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1905 // LSP.
1906 let snapshot = buffer_handle.read(cx).snapshot();
1907 for range in ranges {
1908 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1909 }
1910 anyhow::Ok(())
1911 })??;
1912
1913 let mut edits = None;
1914 for range in lsp_ranges {
1915 if let Some(mut edit) = language_server
1916 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1917 text_document: text_document.clone(),
1918 range,
1919 options: lsp_command::lsp_formatting_options(settings),
1920 work_done_progress_params: Default::default(),
1921 })
1922 .await
1923 .into_response()?
1924 {
1925 edits.get_or_insert_with(Vec::new).append(&mut edit);
1926 }
1927 }
1928 edits
1929 };
1930
1931 if let Some(lsp_edits) = lsp_edits {
1932 this.update(cx, |this, cx| {
1933 this.as_local_mut().unwrap().edits_from_lsp(
1934 buffer_handle,
1935 lsp_edits,
1936 language_server.server_id(),
1937 None,
1938 cx,
1939 )
1940 })?
1941 .await
1942 } else {
1943 Ok(Vec::with_capacity(0))
1944 }
1945 }
1946
1947 async fn format_via_lsp(
1948 this: &WeakEntity<LspStore>,
1949 buffer: &Entity<Buffer>,
1950 abs_path: &Path,
1951 language_server: &Arc<LanguageServer>,
1952 settings: &LanguageSettings,
1953 cx: &mut AsyncApp,
1954 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1955 let logger = zlog::scoped!("lsp_format");
1956 zlog::info!(logger => "Formatting via LSP");
1957
1958 let uri = file_path_to_lsp_url(abs_path)?;
1959 let text_document = lsp::TextDocumentIdentifier::new(uri);
1960 let capabilities = &language_server.capabilities();
1961
1962 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1963 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1964
1965 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1966 let _timer = zlog::time!(logger => "format-full");
1967 language_server
1968 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1969 text_document,
1970 options: lsp_command::lsp_formatting_options(settings),
1971 work_done_progress_params: Default::default(),
1972 })
1973 .await
1974 .into_response()?
1975 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1976 let _timer = zlog::time!(logger => "format-range");
1977 let buffer_start = lsp::Position::new(0, 0);
1978 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1979 language_server
1980 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1981 text_document: text_document.clone(),
1982 range: lsp::Range::new(buffer_start, buffer_end),
1983 options: lsp_command::lsp_formatting_options(settings),
1984 work_done_progress_params: Default::default(),
1985 })
1986 .await
1987 .into_response()?
1988 } else {
1989 None
1990 };
1991
1992 if let Some(lsp_edits) = lsp_edits {
1993 this.update(cx, |this, cx| {
1994 this.as_local_mut().unwrap().edits_from_lsp(
1995 buffer,
1996 lsp_edits,
1997 language_server.server_id(),
1998 None,
1999 cx,
2000 )
2001 })?
2002 .await
2003 } else {
2004 Ok(Vec::with_capacity(0))
2005 }
2006 }
2007
2008 async fn format_via_external_command(
2009 buffer: &FormattableBuffer,
2010 command: &str,
2011 arguments: Option<&[String]>,
2012 cx: &mut AsyncApp,
2013 ) -> Result<Option<Diff>> {
2014 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2015 let file = File::from_dyn(buffer.file())?;
2016 let worktree = file.worktree.read(cx);
2017 let mut worktree_path = worktree.abs_path().to_path_buf();
2018 if worktree.root_entry()?.is_file() {
2019 worktree_path.pop();
2020 }
2021 Some(worktree_path)
2022 })?;
2023
2024 let mut child = util::command::new_smol_command(command);
2025
2026 if let Some(buffer_env) = buffer.env.as_ref() {
2027 child.envs(buffer_env);
2028 }
2029
2030 if let Some(working_dir_path) = working_dir_path {
2031 child.current_dir(working_dir_path);
2032 }
2033
2034 if let Some(arguments) = arguments {
2035 child.args(arguments.iter().map(|arg| {
2036 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2037 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2038 } else {
2039 arg.replace("{buffer_path}", "Untitled")
2040 }
2041 }));
2042 }
2043
2044 let mut child = child
2045 .stdin(smol::process::Stdio::piped())
2046 .stdout(smol::process::Stdio::piped())
2047 .stderr(smol::process::Stdio::piped())
2048 .spawn()?;
2049
2050 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2051 let text = buffer
2052 .handle
2053 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2054 for chunk in text.chunks() {
2055 stdin.write_all(chunk.as_bytes()).await?;
2056 }
2057 stdin.flush().await?;
2058
2059 let output = child.output().await?;
2060 anyhow::ensure!(
2061 output.status.success(),
2062 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2063 output.status.code(),
2064 String::from_utf8_lossy(&output.stdout),
2065 String::from_utf8_lossy(&output.stderr),
2066 );
2067
2068 let stdout = String::from_utf8(output.stdout)?;
2069 Ok(Some(
2070 buffer
2071 .handle
2072 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2073 .await,
2074 ))
2075 }
2076
2077 async fn try_resolve_code_action(
2078 lang_server: &LanguageServer,
2079 action: &mut CodeAction,
2080 ) -> anyhow::Result<()> {
2081 match &mut action.lsp_action {
2082 LspAction::Action(lsp_action) => {
2083 if !action.resolved
2084 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2085 && lsp_action.data.is_some()
2086 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2087 {
2088 *lsp_action = Box::new(
2089 lang_server
2090 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2091 .await
2092 .into_response()?,
2093 );
2094 }
2095 }
2096 LspAction::CodeLens(lens) => {
2097 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2098 *lens = lang_server
2099 .request::<lsp::request::CodeLensResolve>(lens.clone())
2100 .await
2101 .into_response()?;
2102 }
2103 }
2104 LspAction::Command(_) => {}
2105 }
2106
2107 action.resolved = true;
2108 anyhow::Ok(())
2109 }
2110
2111 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2112 let buffer = buffer_handle.read(cx);
2113
2114 let file = buffer.file().cloned();
2115
2116 let Some(file) = File::from_dyn(file.as_ref()) else {
2117 return;
2118 };
2119 if !file.is_local() {
2120 return;
2121 }
2122 let path = ProjectPath::from_file(file, cx);
2123 let worktree_id = file.worktree_id(cx);
2124 let language = buffer.language().cloned();
2125
2126 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2127 for (server_id, diagnostics) in
2128 diagnostics.get(file.path()).cloned().unwrap_or_default()
2129 {
2130 self.update_buffer_diagnostics(
2131 buffer_handle,
2132 server_id,
2133 None,
2134 None,
2135 diagnostics,
2136 Vec::new(),
2137 cx,
2138 )
2139 .log_err();
2140 }
2141 }
2142 let Some(language) = language else {
2143 return;
2144 };
2145 let Some(snapshot) = self
2146 .worktree_store
2147 .read(cx)
2148 .worktree_for_id(worktree_id, cx)
2149 .map(|worktree| worktree.read(cx).snapshot())
2150 else {
2151 return;
2152 };
2153 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2154
2155 for server_id in
2156 self.lsp_tree
2157 .get(path, language.name(), language.manifest(), &delegate, cx)
2158 {
2159 let server = self
2160 .language_servers
2161 .get(&server_id)
2162 .and_then(|server_state| {
2163 if let LanguageServerState::Running { server, .. } = server_state {
2164 Some(server.clone())
2165 } else {
2166 None
2167 }
2168 });
2169 let server = match server {
2170 Some(server) => server,
2171 None => continue,
2172 };
2173
2174 buffer_handle.update(cx, |buffer, cx| {
2175 buffer.set_completion_triggers(
2176 server.server_id(),
2177 server
2178 .capabilities()
2179 .completion_provider
2180 .as_ref()
2181 .and_then(|provider| {
2182 provider
2183 .trigger_characters
2184 .as_ref()
2185 .map(|characters| characters.iter().cloned().collect())
2186 })
2187 .unwrap_or_default(),
2188 cx,
2189 );
2190 });
2191 }
2192 }
2193
2194 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2195 buffer.update(cx, |buffer, cx| {
2196 let Some(language) = buffer.language() else {
2197 return;
2198 };
2199 let path = ProjectPath {
2200 worktree_id: old_file.worktree_id(cx),
2201 path: old_file.path.clone(),
2202 };
2203 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2204 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2205 buffer.set_completion_triggers(server_id, Default::default(), cx);
2206 }
2207 });
2208 }
2209
2210 fn update_buffer_diagnostics(
2211 &mut self,
2212 buffer: &Entity<Buffer>,
2213 server_id: LanguageServerId,
2214 result_id: Option<String>,
2215 version: Option<i32>,
2216 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2217 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2218 cx: &mut Context<LspStore>,
2219 ) -> Result<()> {
2220 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2221 Ordering::Equal
2222 .then_with(|| b.is_primary.cmp(&a.is_primary))
2223 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2224 .then_with(|| a.severity.cmp(&b.severity))
2225 .then_with(|| a.message.cmp(&b.message))
2226 }
2227
2228 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2229 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2230 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2231
2232 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2233 Ordering::Equal
2234 .then_with(|| a.range.start.cmp(&b.range.start))
2235 .then_with(|| b.range.end.cmp(&a.range.end))
2236 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2237 });
2238
2239 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2240
2241 let edits_since_save = std::cell::LazyCell::new(|| {
2242 let saved_version = buffer.read(cx).saved_version();
2243 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2244 });
2245
2246 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2247
2248 for (new_diagnostic, entry) in diagnostics {
2249 let start;
2250 let end;
2251 if new_diagnostic && entry.diagnostic.is_disk_based {
2252 // Some diagnostics are based on files on disk instead of buffers'
2253 // current contents. Adjust these diagnostics' ranges to reflect
2254 // any unsaved edits.
2255 // Do not alter the reused ones though, as their coordinates were stored as anchors
2256 // and were properly adjusted on reuse.
2257 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2258 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2259 } else {
2260 start = entry.range.start;
2261 end = entry.range.end;
2262 }
2263
2264 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2265 ..snapshot.clip_point_utf16(end, Bias::Right);
2266
2267 // Expand empty ranges by one codepoint
2268 if range.start == range.end {
2269 // This will be go to the next boundary when being clipped
2270 range.end.column += 1;
2271 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2272 if range.start == range.end && range.end.column > 0 {
2273 range.start.column -= 1;
2274 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2275 }
2276 }
2277
2278 sanitized_diagnostics.push(DiagnosticEntry {
2279 range,
2280 diagnostic: entry.diagnostic,
2281 });
2282 }
2283 drop(edits_since_save);
2284
2285 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2286 buffer.update(cx, |buffer, cx| {
2287 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2288 self.buffer_pull_diagnostics_result_ids
2289 .entry(server_id)
2290 .or_default()
2291 .insert(abs_path, result_id);
2292 }
2293
2294 buffer.update_diagnostics(server_id, set, cx)
2295 });
2296
2297 Ok(())
2298 }
2299
2300 fn register_language_server_for_invisible_worktree(
2301 &mut self,
2302 worktree: &Entity<Worktree>,
2303 language_server_id: LanguageServerId,
2304 cx: &mut App,
2305 ) {
2306 let worktree = worktree.read(cx);
2307 let worktree_id = worktree.id();
2308 debug_assert!(!worktree.is_visible());
2309 let Some(mut origin_seed) = self
2310 .language_server_ids
2311 .iter()
2312 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2313 else {
2314 return;
2315 };
2316 origin_seed.worktree_id = worktree_id;
2317 self.language_server_ids
2318 .entry(origin_seed)
2319 .or_insert_with(|| UnifiedLanguageServer {
2320 id: language_server_id,
2321 project_roots: Default::default(),
2322 });
2323 }
2324
2325 fn register_buffer_with_language_servers(
2326 &mut self,
2327 buffer_handle: &Entity<Buffer>,
2328 only_register_servers: HashSet<LanguageServerSelector>,
2329 cx: &mut Context<LspStore>,
2330 ) {
2331 let buffer = buffer_handle.read(cx);
2332 let buffer_id = buffer.remote_id();
2333
2334 let Some(file) = File::from_dyn(buffer.file()) else {
2335 return;
2336 };
2337 if !file.is_local() {
2338 return;
2339 }
2340
2341 let abs_path = file.abs_path(cx);
2342 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2343 return;
2344 };
2345 let initial_snapshot = buffer.text_snapshot();
2346 let worktree_id = file.worktree_id(cx);
2347
2348 let Some(language) = buffer.language().cloned() else {
2349 return;
2350 };
2351 let path: Arc<Path> = file
2352 .path()
2353 .parent()
2354 .map(Arc::from)
2355 .unwrap_or_else(|| file.path().clone());
2356 let Some(worktree) = self
2357 .worktree_store
2358 .read(cx)
2359 .worktree_for_id(worktree_id, cx)
2360 else {
2361 return;
2362 };
2363 let language_name = language.name();
2364 let (reused, delegate, servers) = self
2365 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2366 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2367 .unwrap_or_else(|| {
2368 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2369 let delegate: Arc<dyn ManifestDelegate> =
2370 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2371
2372 let servers = self
2373 .lsp_tree
2374 .walk(
2375 ProjectPath { worktree_id, path },
2376 language.name(),
2377 language.manifest(),
2378 &delegate,
2379 cx,
2380 )
2381 .collect::<Vec<_>>();
2382 (false, lsp_delegate, servers)
2383 });
2384 let servers_and_adapters = servers
2385 .into_iter()
2386 .filter_map(|server_node| {
2387 if reused && server_node.server_id().is_none() {
2388 return None;
2389 }
2390 if !only_register_servers.is_empty() {
2391 if let Some(server_id) = server_node.server_id()
2392 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2393 {
2394 return None;
2395 }
2396 if let Some(name) = server_node.name()
2397 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2398 {
2399 return None;
2400 }
2401 }
2402
2403 let server_id = server_node.server_id_or_init(|disposition| {
2404 let path = &disposition.path;
2405
2406 {
2407 let uri =
2408 Uri::from_file_path(worktree.read(cx).abs_path().join(&path.path));
2409
2410 let server_id = self.get_or_insert_language_server(
2411 &worktree,
2412 delegate.clone(),
2413 disposition,
2414 &language_name,
2415 cx,
2416 );
2417
2418 if let Some(state) = self.language_servers.get(&server_id)
2419 && let Ok(uri) = uri
2420 {
2421 state.add_workspace_folder(uri);
2422 };
2423 server_id
2424 }
2425 })?;
2426 let server_state = self.language_servers.get(&server_id)?;
2427 if let LanguageServerState::Running {
2428 server, adapter, ..
2429 } = server_state
2430 {
2431 Some((server.clone(), adapter.clone()))
2432 } else {
2433 None
2434 }
2435 })
2436 .collect::<Vec<_>>();
2437 for (server, adapter) in servers_and_adapters {
2438 buffer_handle.update(cx, |buffer, cx| {
2439 buffer.set_completion_triggers(
2440 server.server_id(),
2441 server
2442 .capabilities()
2443 .completion_provider
2444 .as_ref()
2445 .and_then(|provider| {
2446 provider
2447 .trigger_characters
2448 .as_ref()
2449 .map(|characters| characters.iter().cloned().collect())
2450 })
2451 .unwrap_or_default(),
2452 cx,
2453 );
2454 });
2455
2456 let snapshot = LspBufferSnapshot {
2457 version: 0,
2458 snapshot: initial_snapshot.clone(),
2459 };
2460
2461 let mut registered = false;
2462 self.buffer_snapshots
2463 .entry(buffer_id)
2464 .or_default()
2465 .entry(server.server_id())
2466 .or_insert_with(|| {
2467 registered = true;
2468 server.register_buffer(
2469 uri.clone(),
2470 adapter.language_id(&language.name()),
2471 0,
2472 initial_snapshot.text(),
2473 );
2474
2475 vec![snapshot]
2476 });
2477
2478 self.buffers_opened_in_servers
2479 .entry(buffer_id)
2480 .or_default()
2481 .insert(server.server_id());
2482 if registered {
2483 cx.emit(LspStoreEvent::LanguageServerUpdate {
2484 language_server_id: server.server_id(),
2485 name: None,
2486 message: proto::update_language_server::Variant::RegisteredForBuffer(
2487 proto::RegisteredForBuffer {
2488 buffer_abs_path: abs_path.to_string_lossy().to_string(),
2489 buffer_id: buffer_id.to_proto(),
2490 },
2491 ),
2492 });
2493 }
2494 }
2495 }
2496
2497 fn reuse_existing_language_server<'lang_name>(
2498 &self,
2499 server_tree: &LanguageServerTree,
2500 worktree: &Entity<Worktree>,
2501 language_name: &'lang_name LanguageName,
2502 cx: &mut App,
2503 ) -> Option<(
2504 Arc<LocalLspAdapterDelegate>,
2505 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2506 )> {
2507 if worktree.read(cx).is_visible() {
2508 return None;
2509 }
2510
2511 let worktree_store = self.worktree_store.read(cx);
2512 let servers = server_tree
2513 .instances
2514 .iter()
2515 .filter(|(worktree_id, _)| {
2516 worktree_store
2517 .worktree_for_id(**worktree_id, cx)
2518 .is_some_and(|worktree| worktree.read(cx).is_visible())
2519 })
2520 .flat_map(|(worktree_id, servers)| {
2521 servers
2522 .roots
2523 .iter()
2524 .flat_map(|(_, language_servers)| language_servers)
2525 .map(move |(_, (server_node, server_languages))| {
2526 (worktree_id, server_node, server_languages)
2527 })
2528 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2529 .map(|(worktree_id, server_node, _)| {
2530 (
2531 *worktree_id,
2532 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2533 )
2534 })
2535 })
2536 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2537 acc.entry(worktree_id)
2538 .or_insert_with(Vec::new)
2539 .push(server_node);
2540 acc
2541 })
2542 .into_values()
2543 .max_by_key(|servers| servers.len())?;
2544
2545 let worktree_id = worktree.read(cx).id();
2546 let apply = move |tree: &mut LanguageServerTree| {
2547 for server_node in &servers {
2548 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2549 }
2550 servers
2551 };
2552
2553 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2554 Some((delegate, apply))
2555 }
2556
2557 pub(crate) fn unregister_old_buffer_from_language_servers(
2558 &mut self,
2559 buffer: &Entity<Buffer>,
2560 old_file: &File,
2561 cx: &mut App,
2562 ) {
2563 let old_path = match old_file.as_local() {
2564 Some(local) => local.abs_path(cx),
2565 None => return,
2566 };
2567
2568 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2569 debug_panic!(
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 display_options: CompletionDisplayOptions::default(),
5832 is_incomplete: completion_response.is_incomplete,
5833 }])
5834 })
5835 } else if let Some(local) = self.as_local() {
5836 let snapshot = buffer.read(cx).snapshot();
5837 let offset = position.to_offset(&snapshot);
5838 let scope = snapshot.language_scope_at(offset);
5839 let language = snapshot.language().cloned();
5840 let completion_settings = language_settings(
5841 language.as_ref().map(|language| language.name()),
5842 buffer.read(cx).file(),
5843 cx,
5844 )
5845 .completions;
5846 if !completion_settings.lsp {
5847 return Task::ready(Ok(Vec::new()));
5848 }
5849
5850 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5851 local
5852 .language_servers_for_buffer(buffer, cx)
5853 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5854 .filter(|(adapter, _)| {
5855 scope
5856 .as_ref()
5857 .map(|scope| scope.language_allowed(&adapter.name))
5858 .unwrap_or(true)
5859 })
5860 .map(|(_, server)| server.server_id())
5861 .collect()
5862 });
5863
5864 let buffer = buffer.clone();
5865 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5866 let lsp_timeout = if lsp_timeout > 0 {
5867 Some(Duration::from_millis(lsp_timeout))
5868 } else {
5869 None
5870 };
5871 cx.spawn(async move |this, cx| {
5872 let mut tasks = Vec::with_capacity(server_ids.len());
5873 this.update(cx, |lsp_store, cx| {
5874 for server_id in server_ids {
5875 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5876 let lsp_timeout = lsp_timeout
5877 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5878 let mut timeout = cx.background_spawn(async move {
5879 match lsp_timeout {
5880 Some(lsp_timeout) => {
5881 lsp_timeout.await;
5882 true
5883 },
5884 None => false,
5885 }
5886 }).fuse();
5887 let mut lsp_request = lsp_store.request_lsp(
5888 buffer.clone(),
5889 LanguageServerToQuery::Other(server_id),
5890 GetCompletions {
5891 position,
5892 context: context.clone(),
5893 },
5894 cx,
5895 ).fuse();
5896 let new_task = cx.background_spawn(async move {
5897 select_biased! {
5898 response = lsp_request => anyhow::Ok(Some(response?)),
5899 timeout_happened = timeout => {
5900 if timeout_happened {
5901 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5902 Ok(None)
5903 } else {
5904 let completions = lsp_request.await?;
5905 Ok(Some(completions))
5906 }
5907 },
5908 }
5909 });
5910 tasks.push((lsp_adapter, new_task));
5911 }
5912 })?;
5913
5914 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5915 let completion_response = task.await.ok()??;
5916 let completions = populate_labels_for_completions(
5917 completion_response.completions,
5918 language.clone(),
5919 lsp_adapter,
5920 )
5921 .await;
5922 Some(CompletionResponse {
5923 completions,
5924 display_options: CompletionDisplayOptions::default(),
5925 is_incomplete: completion_response.is_incomplete,
5926 })
5927 });
5928
5929 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5930
5931 Ok(responses.into_iter().flatten().collect())
5932 })
5933 } else {
5934 Task::ready(Err(anyhow!("No upstream client or local language server")))
5935 }
5936 }
5937
5938 pub fn resolve_completions(
5939 &self,
5940 buffer: Entity<Buffer>,
5941 completion_indices: Vec<usize>,
5942 completions: Rc<RefCell<Box<[Completion]>>>,
5943 cx: &mut Context<Self>,
5944 ) -> Task<Result<bool>> {
5945 let client = self.upstream_client();
5946 let buffer_id = buffer.read(cx).remote_id();
5947 let buffer_snapshot = buffer.read(cx).snapshot();
5948
5949 if !self.check_if_capable_for_proto_request(
5950 &buffer,
5951 GetCompletions::can_resolve_completions,
5952 cx,
5953 ) {
5954 return Task::ready(Ok(false));
5955 }
5956 cx.spawn(async move |lsp_store, cx| {
5957 let mut did_resolve = false;
5958 if let Some((client, project_id)) = client {
5959 for completion_index in completion_indices {
5960 let server_id = {
5961 let completion = &completions.borrow()[completion_index];
5962 completion.source.server_id()
5963 };
5964 if let Some(server_id) = server_id {
5965 if Self::resolve_completion_remote(
5966 project_id,
5967 server_id,
5968 buffer_id,
5969 completions.clone(),
5970 completion_index,
5971 client.clone(),
5972 )
5973 .await
5974 .log_err()
5975 .is_some()
5976 {
5977 did_resolve = true;
5978 }
5979 } else {
5980 resolve_word_completion(
5981 &buffer_snapshot,
5982 &mut completions.borrow_mut()[completion_index],
5983 );
5984 }
5985 }
5986 } else {
5987 for completion_index in completion_indices {
5988 let server_id = {
5989 let completion = &completions.borrow()[completion_index];
5990 completion.source.server_id()
5991 };
5992 if let Some(server_id) = server_id {
5993 let server_and_adapter = lsp_store
5994 .read_with(cx, |lsp_store, _| {
5995 let server = lsp_store.language_server_for_id(server_id)?;
5996 let adapter =
5997 lsp_store.language_server_adapter_for_id(server.server_id())?;
5998 Some((server, adapter))
5999 })
6000 .ok()
6001 .flatten();
6002 let Some((server, adapter)) = server_and_adapter else {
6003 continue;
6004 };
6005
6006 let resolved = Self::resolve_completion_local(
6007 server,
6008 completions.clone(),
6009 completion_index,
6010 )
6011 .await
6012 .log_err()
6013 .is_some();
6014 if resolved {
6015 Self::regenerate_completion_labels(
6016 adapter,
6017 &buffer_snapshot,
6018 completions.clone(),
6019 completion_index,
6020 )
6021 .await
6022 .log_err();
6023 did_resolve = true;
6024 }
6025 } else {
6026 resolve_word_completion(
6027 &buffer_snapshot,
6028 &mut completions.borrow_mut()[completion_index],
6029 );
6030 }
6031 }
6032 }
6033
6034 Ok(did_resolve)
6035 })
6036 }
6037
6038 async fn resolve_completion_local(
6039 server: Arc<lsp::LanguageServer>,
6040 completions: Rc<RefCell<Box<[Completion]>>>,
6041 completion_index: usize,
6042 ) -> Result<()> {
6043 let server_id = server.server_id();
6044 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6045 return Ok(());
6046 }
6047
6048 let request = {
6049 let completion = &completions.borrow()[completion_index];
6050 match &completion.source {
6051 CompletionSource::Lsp {
6052 lsp_completion,
6053 resolved,
6054 server_id: completion_server_id,
6055 ..
6056 } => {
6057 if *resolved {
6058 return Ok(());
6059 }
6060 anyhow::ensure!(
6061 server_id == *completion_server_id,
6062 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6063 );
6064 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6065 }
6066 CompletionSource::BufferWord { .. }
6067 | CompletionSource::Dap { .. }
6068 | CompletionSource::Custom => {
6069 return Ok(());
6070 }
6071 }
6072 };
6073 let resolved_completion = request
6074 .await
6075 .into_response()
6076 .context("resolve completion")?;
6077
6078 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6079 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6080
6081 let mut completions = completions.borrow_mut();
6082 let completion = &mut completions[completion_index];
6083 if let CompletionSource::Lsp {
6084 lsp_completion,
6085 resolved,
6086 server_id: completion_server_id,
6087 ..
6088 } = &mut completion.source
6089 {
6090 if *resolved {
6091 return Ok(());
6092 }
6093 anyhow::ensure!(
6094 server_id == *completion_server_id,
6095 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6096 );
6097 *lsp_completion = Box::new(resolved_completion);
6098 *resolved = true;
6099 }
6100 Ok(())
6101 }
6102
6103 async fn regenerate_completion_labels(
6104 adapter: Arc<CachedLspAdapter>,
6105 snapshot: &BufferSnapshot,
6106 completions: Rc<RefCell<Box<[Completion]>>>,
6107 completion_index: usize,
6108 ) -> Result<()> {
6109 let completion_item = completions.borrow()[completion_index]
6110 .source
6111 .lsp_completion(true)
6112 .map(Cow::into_owned);
6113 if let Some(lsp_documentation) = completion_item
6114 .as_ref()
6115 .and_then(|completion_item| completion_item.documentation.clone())
6116 {
6117 let mut completions = completions.borrow_mut();
6118 let completion = &mut completions[completion_index];
6119 completion.documentation = Some(lsp_documentation.into());
6120 } else {
6121 let mut completions = completions.borrow_mut();
6122 let completion = &mut completions[completion_index];
6123 completion.documentation = Some(CompletionDocumentation::Undocumented);
6124 }
6125
6126 let mut new_label = match completion_item {
6127 Some(completion_item) => {
6128 // 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
6129 // So we have to update the label here anyway...
6130 let language = snapshot.language();
6131 match language {
6132 Some(language) => {
6133 adapter
6134 .labels_for_completions(
6135 std::slice::from_ref(&completion_item),
6136 language,
6137 )
6138 .await?
6139 }
6140 None => Vec::new(),
6141 }
6142 .pop()
6143 .flatten()
6144 .unwrap_or_else(|| {
6145 CodeLabel::fallback_for_completion(
6146 &completion_item,
6147 language.map(|language| language.as_ref()),
6148 )
6149 })
6150 }
6151 None => CodeLabel::plain(
6152 completions.borrow()[completion_index].new_text.clone(),
6153 None,
6154 ),
6155 };
6156 ensure_uniform_list_compatible_label(&mut new_label);
6157
6158 let mut completions = completions.borrow_mut();
6159 let completion = &mut completions[completion_index];
6160 if completion.label.filter_text() == new_label.filter_text() {
6161 completion.label = new_label;
6162 } else {
6163 log::error!(
6164 "Resolved completion changed display label from {} to {}. \
6165 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6166 completion.label.text(),
6167 new_label.text(),
6168 completion.label.filter_text(),
6169 new_label.filter_text()
6170 );
6171 }
6172
6173 Ok(())
6174 }
6175
6176 async fn resolve_completion_remote(
6177 project_id: u64,
6178 server_id: LanguageServerId,
6179 buffer_id: BufferId,
6180 completions: Rc<RefCell<Box<[Completion]>>>,
6181 completion_index: usize,
6182 client: AnyProtoClient,
6183 ) -> Result<()> {
6184 let lsp_completion = {
6185 let completion = &completions.borrow()[completion_index];
6186 match &completion.source {
6187 CompletionSource::Lsp {
6188 lsp_completion,
6189 resolved,
6190 server_id: completion_server_id,
6191 ..
6192 } => {
6193 anyhow::ensure!(
6194 server_id == *completion_server_id,
6195 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6196 );
6197 if *resolved {
6198 return Ok(());
6199 }
6200 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6201 }
6202 CompletionSource::Custom
6203 | CompletionSource::Dap { .. }
6204 | CompletionSource::BufferWord { .. } => {
6205 return Ok(());
6206 }
6207 }
6208 };
6209 let request = proto::ResolveCompletionDocumentation {
6210 project_id,
6211 language_server_id: server_id.0 as u64,
6212 lsp_completion,
6213 buffer_id: buffer_id.into(),
6214 };
6215
6216 let response = client
6217 .request(request)
6218 .await
6219 .context("completion documentation resolve proto request")?;
6220 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6221
6222 let documentation = if response.documentation.is_empty() {
6223 CompletionDocumentation::Undocumented
6224 } else if response.documentation_is_markdown {
6225 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6226 } else if response.documentation.lines().count() <= 1 {
6227 CompletionDocumentation::SingleLine(response.documentation.into())
6228 } else {
6229 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6230 };
6231
6232 let mut completions = completions.borrow_mut();
6233 let completion = &mut completions[completion_index];
6234 completion.documentation = Some(documentation);
6235 if let CompletionSource::Lsp {
6236 insert_range,
6237 lsp_completion,
6238 resolved,
6239 server_id: completion_server_id,
6240 lsp_defaults: _,
6241 } = &mut completion.source
6242 {
6243 let completion_insert_range = response
6244 .old_insert_start
6245 .and_then(deserialize_anchor)
6246 .zip(response.old_insert_end.and_then(deserialize_anchor));
6247 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6248
6249 if *resolved {
6250 return Ok(());
6251 }
6252 anyhow::ensure!(
6253 server_id == *completion_server_id,
6254 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6255 );
6256 *lsp_completion = Box::new(resolved_lsp_completion);
6257 *resolved = true;
6258 }
6259
6260 let replace_range = response
6261 .old_replace_start
6262 .and_then(deserialize_anchor)
6263 .zip(response.old_replace_end.and_then(deserialize_anchor));
6264 if let Some((old_replace_start, old_replace_end)) = replace_range
6265 && !response.new_text.is_empty()
6266 {
6267 completion.new_text = response.new_text;
6268 completion.replace_range = old_replace_start..old_replace_end;
6269 }
6270
6271 Ok(())
6272 }
6273
6274 pub fn apply_additional_edits_for_completion(
6275 &self,
6276 buffer_handle: Entity<Buffer>,
6277 completions: Rc<RefCell<Box<[Completion]>>>,
6278 completion_index: usize,
6279 push_to_history: bool,
6280 cx: &mut Context<Self>,
6281 ) -> Task<Result<Option<Transaction>>> {
6282 if let Some((client, project_id)) = self.upstream_client() {
6283 let buffer = buffer_handle.read(cx);
6284 let buffer_id = buffer.remote_id();
6285 cx.spawn(async move |_, cx| {
6286 let request = {
6287 let completion = completions.borrow()[completion_index].clone();
6288 proto::ApplyCompletionAdditionalEdits {
6289 project_id,
6290 buffer_id: buffer_id.into(),
6291 completion: Some(Self::serialize_completion(&CoreCompletion {
6292 replace_range: completion.replace_range,
6293 new_text: completion.new_text,
6294 source: completion.source,
6295 })),
6296 }
6297 };
6298
6299 if let Some(transaction) = client.request(request).await?.transaction {
6300 let transaction = language::proto::deserialize_transaction(transaction)?;
6301 buffer_handle
6302 .update(cx, |buffer, _| {
6303 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6304 })?
6305 .await?;
6306 if push_to_history {
6307 buffer_handle.update(cx, |buffer, _| {
6308 buffer.push_transaction(transaction.clone(), Instant::now());
6309 buffer.finalize_last_transaction();
6310 })?;
6311 }
6312 Ok(Some(transaction))
6313 } else {
6314 Ok(None)
6315 }
6316 })
6317 } else {
6318 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6319 let completion = &completions.borrow()[completion_index];
6320 let server_id = completion.source.server_id()?;
6321 Some(
6322 self.language_server_for_local_buffer(buffer, server_id, cx)?
6323 .1
6324 .clone(),
6325 )
6326 }) else {
6327 return Task::ready(Ok(None));
6328 };
6329
6330 cx.spawn(async move |this, cx| {
6331 Self::resolve_completion_local(
6332 server.clone(),
6333 completions.clone(),
6334 completion_index,
6335 )
6336 .await
6337 .context("resolving completion")?;
6338 let completion = completions.borrow()[completion_index].clone();
6339 let additional_text_edits = completion
6340 .source
6341 .lsp_completion(true)
6342 .as_ref()
6343 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6344 if let Some(edits) = additional_text_edits {
6345 let edits = this
6346 .update(cx, |this, cx| {
6347 this.as_local_mut().unwrap().edits_from_lsp(
6348 &buffer_handle,
6349 edits,
6350 server.server_id(),
6351 None,
6352 cx,
6353 )
6354 })?
6355 .await?;
6356
6357 buffer_handle.update(cx, |buffer, cx| {
6358 buffer.finalize_last_transaction();
6359 buffer.start_transaction();
6360
6361 for (range, text) in edits {
6362 let primary = &completion.replace_range;
6363 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6364 && primary.end.cmp(&range.start, buffer).is_ge();
6365 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6366 && range.end.cmp(&primary.end, buffer).is_ge();
6367
6368 //Skip additional edits which overlap with the primary completion edit
6369 //https://github.com/zed-industries/zed/pull/1871
6370 if !start_within && !end_within {
6371 buffer.edit([(range, text)], None, cx);
6372 }
6373 }
6374
6375 let transaction = if buffer.end_transaction(cx).is_some() {
6376 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6377 if !push_to_history {
6378 buffer.forget_transaction(transaction.id);
6379 }
6380 Some(transaction)
6381 } else {
6382 None
6383 };
6384 Ok(transaction)
6385 })?
6386 } else {
6387 Ok(None)
6388 }
6389 })
6390 }
6391 }
6392
6393 pub fn pull_diagnostics(
6394 &mut self,
6395 buffer: Entity<Buffer>,
6396 cx: &mut Context<Self>,
6397 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6398 let buffer_id = buffer.read(cx).remote_id();
6399
6400 if let Some((client, upstream_project_id)) = self.upstream_client() {
6401 let request = GetDocumentDiagnostics {
6402 previous_result_id: None,
6403 };
6404 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6405 return Task::ready(Ok(None));
6406 }
6407 let request_task = client.request_lsp(
6408 upstream_project_id,
6409 LSP_REQUEST_TIMEOUT,
6410 cx.background_executor().clone(),
6411 request.to_proto(upstream_project_id, buffer.read(cx)),
6412 );
6413 cx.background_spawn(async move {
6414 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6415 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6416 // Do not attempt to further process the dummy responses here.
6417 let _response = request_task.await?;
6418 Ok(None)
6419 })
6420 } else {
6421 let server_ids = buffer.update(cx, |buffer, cx| {
6422 self.language_servers_for_local_buffer(buffer, cx)
6423 .map(|(_, server)| server.server_id())
6424 .collect::<Vec<_>>()
6425 });
6426 let pull_diagnostics = server_ids
6427 .into_iter()
6428 .map(|server_id| {
6429 let result_id = self.result_id(server_id, buffer_id, cx);
6430 self.request_lsp(
6431 buffer.clone(),
6432 LanguageServerToQuery::Other(server_id),
6433 GetDocumentDiagnostics {
6434 previous_result_id: result_id,
6435 },
6436 cx,
6437 )
6438 })
6439 .collect::<Vec<_>>();
6440
6441 cx.background_spawn(async move {
6442 let mut responses = Vec::new();
6443 for diagnostics in join_all(pull_diagnostics).await {
6444 responses.extend(diagnostics?);
6445 }
6446 Ok(Some(responses))
6447 })
6448 }
6449 }
6450
6451 pub fn inlay_hints(
6452 &mut self,
6453 buffer: Entity<Buffer>,
6454 range: Range<Anchor>,
6455 cx: &mut Context<Self>,
6456 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6457 let range_start = range.start;
6458 let range_end = range.end;
6459 let buffer_id = buffer.read(cx).remote_id().into();
6460 let request = InlayHints { range };
6461
6462 if let Some((client, project_id)) = self.upstream_client() {
6463 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6464 return Task::ready(Ok(Vec::new()));
6465 }
6466 let proto_request = proto::InlayHints {
6467 project_id,
6468 buffer_id,
6469 start: Some(serialize_anchor(&range_start)),
6470 end: Some(serialize_anchor(&range_end)),
6471 version: serialize_version(&buffer.read(cx).version()),
6472 };
6473 cx.spawn(async move |project, cx| {
6474 let response = client
6475 .request(proto_request)
6476 .await
6477 .context("inlay hints proto request")?;
6478 LspCommand::response_from_proto(
6479 request,
6480 response,
6481 project.upgrade().context("No project")?,
6482 buffer.clone(),
6483 cx.clone(),
6484 )
6485 .await
6486 .context("inlay hints proto response conversion")
6487 })
6488 } else {
6489 let lsp_request_task = self.request_lsp(
6490 buffer.clone(),
6491 LanguageServerToQuery::FirstCapable,
6492 request,
6493 cx,
6494 );
6495 cx.spawn(async move |_, cx| {
6496 buffer
6497 .update(cx, |buffer, _| {
6498 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6499 })?
6500 .await
6501 .context("waiting for inlay hint request range edits")?;
6502 lsp_request_task.await.context("inlay hints LSP request")
6503 })
6504 }
6505 }
6506
6507 pub fn pull_diagnostics_for_buffer(
6508 &mut self,
6509 buffer: Entity<Buffer>,
6510 cx: &mut Context<Self>,
6511 ) -> Task<anyhow::Result<()>> {
6512 let diagnostics = self.pull_diagnostics(buffer, cx);
6513 cx.spawn(async move |lsp_store, cx| {
6514 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6515 return Ok(());
6516 };
6517 lsp_store.update(cx, |lsp_store, cx| {
6518 if lsp_store.as_local().is_none() {
6519 return;
6520 }
6521
6522 let mut unchanged_buffers = HashSet::default();
6523 let mut changed_buffers = HashSet::default();
6524 let server_diagnostics_updates = diagnostics
6525 .into_iter()
6526 .filter_map(|diagnostics_set| match diagnostics_set {
6527 LspPullDiagnostics::Response {
6528 server_id,
6529 uri,
6530 diagnostics,
6531 } => Some((server_id, uri, diagnostics)),
6532 LspPullDiagnostics::Default => None,
6533 })
6534 .fold(
6535 HashMap::default(),
6536 |mut acc, (server_id, uri, diagnostics)| {
6537 let (result_id, diagnostics) = match diagnostics {
6538 PulledDiagnostics::Unchanged { result_id } => {
6539 unchanged_buffers.insert(uri.clone());
6540 (Some(result_id), Vec::new())
6541 }
6542 PulledDiagnostics::Changed {
6543 result_id,
6544 diagnostics,
6545 } => {
6546 changed_buffers.insert(uri.clone());
6547 (result_id, diagnostics)
6548 }
6549 };
6550 let disk_based_sources = Cow::Owned(
6551 lsp_store
6552 .language_server_adapter_for_id(server_id)
6553 .as_ref()
6554 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6555 .unwrap_or(&[])
6556 .to_vec(),
6557 );
6558 acc.entry(server_id).or_insert_with(Vec::new).push(
6559 DocumentDiagnosticsUpdate {
6560 server_id,
6561 diagnostics: lsp::PublishDiagnosticsParams {
6562 uri,
6563 diagnostics,
6564 version: None,
6565 },
6566 result_id,
6567 disk_based_sources,
6568 },
6569 );
6570 acc
6571 },
6572 );
6573
6574 for diagnostic_updates in server_diagnostics_updates.into_values() {
6575 lsp_store
6576 .merge_lsp_diagnostics(
6577 DiagnosticSourceKind::Pulled,
6578 diagnostic_updates,
6579 |buffer, old_diagnostic, cx| {
6580 File::from_dyn(buffer.file())
6581 .and_then(|file| {
6582 let abs_path = file.as_local()?.abs_path(cx);
6583 lsp::Uri::from_file_path(abs_path).ok()
6584 })
6585 .is_none_or(|buffer_uri| {
6586 unchanged_buffers.contains(&buffer_uri)
6587 || match old_diagnostic.source_kind {
6588 DiagnosticSourceKind::Pulled => {
6589 !changed_buffers.contains(&buffer_uri)
6590 }
6591 DiagnosticSourceKind::Other
6592 | DiagnosticSourceKind::Pushed => true,
6593 }
6594 })
6595 },
6596 cx,
6597 )
6598 .log_err();
6599 }
6600 })
6601 })
6602 }
6603
6604 pub fn document_colors(
6605 &mut self,
6606 fetch_strategy: LspFetchStrategy,
6607 buffer: Entity<Buffer>,
6608 cx: &mut Context<Self>,
6609 ) -> Option<DocumentColorTask> {
6610 let version_queried_for = buffer.read(cx).version();
6611 let buffer_id = buffer.read(cx).remote_id();
6612
6613 match fetch_strategy {
6614 LspFetchStrategy::IgnoreCache => {}
6615 LspFetchStrategy::UseCache {
6616 known_cache_version,
6617 } => {
6618 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6619 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6620 {
6621 let has_different_servers = self.as_local().is_some_and(|local| {
6622 local
6623 .buffers_opened_in_servers
6624 .get(&buffer_id)
6625 .cloned()
6626 .unwrap_or_default()
6627 != cached_data.colors.keys().copied().collect()
6628 });
6629 if !has_different_servers {
6630 if Some(cached_data.cache_version) == known_cache_version {
6631 return None;
6632 } else {
6633 return Some(
6634 Task::ready(Ok(DocumentColors {
6635 colors: cached_data
6636 .colors
6637 .values()
6638 .flatten()
6639 .cloned()
6640 .collect(),
6641 cache_version: Some(cached_data.cache_version),
6642 }))
6643 .shared(),
6644 );
6645 }
6646 }
6647 }
6648 }
6649 }
6650
6651 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6652 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6653 && !version_queried_for.changed_since(updating_for)
6654 {
6655 return Some(running_update.clone());
6656 }
6657 let query_version_queried_for = version_queried_for.clone();
6658 let new_task = cx
6659 .spawn(async move |lsp_store, cx| {
6660 cx.background_executor()
6661 .timer(Duration::from_millis(30))
6662 .await;
6663 let fetched_colors = lsp_store
6664 .update(cx, |lsp_store, cx| {
6665 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6666 })?
6667 .await
6668 .context("fetching document colors")
6669 .map_err(Arc::new);
6670 let fetched_colors = match fetched_colors {
6671 Ok(fetched_colors) => {
6672 if fetch_strategy != LspFetchStrategy::IgnoreCache
6673 && Some(true)
6674 == buffer
6675 .update(cx, |buffer, _| {
6676 buffer.version() != query_version_queried_for
6677 })
6678 .ok()
6679 {
6680 return Ok(DocumentColors::default());
6681 }
6682 fetched_colors
6683 }
6684 Err(e) => {
6685 lsp_store
6686 .update(cx, |lsp_store, _| {
6687 lsp_store
6688 .lsp_document_colors
6689 .entry(buffer_id)
6690 .or_default()
6691 .colors_update = None;
6692 })
6693 .ok();
6694 return Err(e);
6695 }
6696 };
6697
6698 lsp_store
6699 .update(cx, |lsp_store, _| {
6700 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6701
6702 if let Some(fetched_colors) = fetched_colors {
6703 if lsp_data.colors_for_version == query_version_queried_for {
6704 lsp_data.colors.extend(fetched_colors);
6705 lsp_data.cache_version += 1;
6706 } else if !lsp_data
6707 .colors_for_version
6708 .changed_since(&query_version_queried_for)
6709 {
6710 lsp_data.colors_for_version = query_version_queried_for;
6711 lsp_data.colors = fetched_colors;
6712 lsp_data.cache_version += 1;
6713 }
6714 }
6715 lsp_data.colors_update = None;
6716 let colors = lsp_data
6717 .colors
6718 .values()
6719 .flatten()
6720 .cloned()
6721 .collect::<HashSet<_>>();
6722 DocumentColors {
6723 colors,
6724 cache_version: Some(lsp_data.cache_version),
6725 }
6726 })
6727 .map_err(Arc::new)
6728 })
6729 .shared();
6730 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6731 Some(new_task)
6732 }
6733
6734 fn fetch_document_colors_for_buffer(
6735 &mut self,
6736 buffer: &Entity<Buffer>,
6737 cx: &mut Context<Self>,
6738 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
6739 if let Some((client, project_id)) = self.upstream_client() {
6740 let request = GetDocumentColor {};
6741 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6742 return Task::ready(Ok(None));
6743 }
6744
6745 let request_task = client.request_lsp(
6746 project_id,
6747 LSP_REQUEST_TIMEOUT,
6748 cx.background_executor().clone(),
6749 request.to_proto(project_id, buffer.read(cx)),
6750 );
6751 let buffer = buffer.clone();
6752 cx.spawn(async move |lsp_store, cx| {
6753 let Some(project) = lsp_store.upgrade() else {
6754 return Ok(None);
6755 };
6756 let colors = join_all(
6757 request_task
6758 .await
6759 .log_err()
6760 .flatten()
6761 .map(|response| response.payload)
6762 .unwrap_or_default()
6763 .into_iter()
6764 .map(|color_response| {
6765 let response = request.response_from_proto(
6766 color_response.response,
6767 project.clone(),
6768 buffer.clone(),
6769 cx.clone(),
6770 );
6771 async move {
6772 (
6773 LanguageServerId::from_proto(color_response.server_id),
6774 response.await.log_err().unwrap_or_default(),
6775 )
6776 }
6777 }),
6778 )
6779 .await
6780 .into_iter()
6781 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6782 acc.entry(server_id)
6783 .or_insert_with(HashSet::default)
6784 .extend(colors);
6785 acc
6786 });
6787 Ok(Some(colors))
6788 })
6789 } else {
6790 let document_colors_task =
6791 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6792 cx.background_spawn(async move {
6793 Ok(Some(
6794 document_colors_task
6795 .await
6796 .into_iter()
6797 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6798 acc.entry(server_id)
6799 .or_insert_with(HashSet::default)
6800 .extend(colors);
6801 acc
6802 })
6803 .into_iter()
6804 .collect(),
6805 ))
6806 })
6807 }
6808 }
6809
6810 pub fn signature_help<T: ToPointUtf16>(
6811 &mut self,
6812 buffer: &Entity<Buffer>,
6813 position: T,
6814 cx: &mut Context<Self>,
6815 ) -> Task<Option<Vec<SignatureHelp>>> {
6816 let position = position.to_point_utf16(buffer.read(cx));
6817
6818 if let Some((client, upstream_project_id)) = self.upstream_client() {
6819 let request = GetSignatureHelp { position };
6820 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6821 return Task::ready(None);
6822 }
6823 let request_task = client.request_lsp(
6824 upstream_project_id,
6825 LSP_REQUEST_TIMEOUT,
6826 cx.background_executor().clone(),
6827 request.to_proto(upstream_project_id, buffer.read(cx)),
6828 );
6829 let buffer = buffer.clone();
6830 cx.spawn(async move |weak_project, cx| {
6831 let project = weak_project.upgrade()?;
6832 let signatures = join_all(
6833 request_task
6834 .await
6835 .log_err()
6836 .flatten()
6837 .map(|response| response.payload)
6838 .unwrap_or_default()
6839 .into_iter()
6840 .map(|response| {
6841 let response = GetSignatureHelp { position }.response_from_proto(
6842 response.response,
6843 project.clone(),
6844 buffer.clone(),
6845 cx.clone(),
6846 );
6847 async move { response.await.log_err().flatten() }
6848 }),
6849 )
6850 .await
6851 .into_iter()
6852 .flatten()
6853 .collect();
6854 Some(signatures)
6855 })
6856 } else {
6857 let all_actions_task = self.request_multiple_lsp_locally(
6858 buffer,
6859 Some(position),
6860 GetSignatureHelp { position },
6861 cx,
6862 );
6863 cx.background_spawn(async move {
6864 Some(
6865 all_actions_task
6866 .await
6867 .into_iter()
6868 .flat_map(|(_, actions)| actions)
6869 .collect::<Vec<_>>(),
6870 )
6871 })
6872 }
6873 }
6874
6875 pub fn hover(
6876 &mut self,
6877 buffer: &Entity<Buffer>,
6878 position: PointUtf16,
6879 cx: &mut Context<Self>,
6880 ) -> Task<Option<Vec<Hover>>> {
6881 if let Some((client, upstream_project_id)) = self.upstream_client() {
6882 let request = GetHover { position };
6883 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6884 return Task::ready(None);
6885 }
6886 let request_task = client.request_lsp(
6887 upstream_project_id,
6888 LSP_REQUEST_TIMEOUT,
6889 cx.background_executor().clone(),
6890 request.to_proto(upstream_project_id, buffer.read(cx)),
6891 );
6892 let buffer = buffer.clone();
6893 cx.spawn(async move |weak_project, cx| {
6894 let project = weak_project.upgrade()?;
6895 let hovers = join_all(
6896 request_task
6897 .await
6898 .log_err()
6899 .flatten()
6900 .map(|response| response.payload)
6901 .unwrap_or_default()
6902 .into_iter()
6903 .map(|response| {
6904 let response = GetHover { position }.response_from_proto(
6905 response.response,
6906 project.clone(),
6907 buffer.clone(),
6908 cx.clone(),
6909 );
6910 async move {
6911 response
6912 .await
6913 .log_err()
6914 .flatten()
6915 .and_then(remove_empty_hover_blocks)
6916 }
6917 }),
6918 )
6919 .await
6920 .into_iter()
6921 .flatten()
6922 .collect();
6923 Some(hovers)
6924 })
6925 } else {
6926 let all_actions_task = self.request_multiple_lsp_locally(
6927 buffer,
6928 Some(position),
6929 GetHover { position },
6930 cx,
6931 );
6932 cx.background_spawn(async move {
6933 Some(
6934 all_actions_task
6935 .await
6936 .into_iter()
6937 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
6938 .collect::<Vec<Hover>>(),
6939 )
6940 })
6941 }
6942 }
6943
6944 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
6945 let language_registry = self.languages.clone();
6946
6947 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
6948 let request = upstream_client.request(proto::GetProjectSymbols {
6949 project_id: *project_id,
6950 query: query.to_string(),
6951 });
6952 cx.foreground_executor().spawn(async move {
6953 let response = request.await?;
6954 let mut symbols = Vec::new();
6955 let core_symbols = response
6956 .symbols
6957 .into_iter()
6958 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
6959 .collect::<Vec<_>>();
6960 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
6961 .await;
6962 Ok(symbols)
6963 })
6964 } else if let Some(local) = self.as_local() {
6965 struct WorkspaceSymbolsResult {
6966 server_id: LanguageServerId,
6967 lsp_adapter: Arc<CachedLspAdapter>,
6968 worktree: WeakEntity<Worktree>,
6969 worktree_abs_path: Arc<Path>,
6970 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
6971 }
6972
6973 let mut requests = Vec::new();
6974 let mut requested_servers = BTreeSet::new();
6975 for (seed, state) in local.language_server_ids.iter() {
6976 let Some(worktree_handle) = self
6977 .worktree_store
6978 .read(cx)
6979 .worktree_for_id(seed.worktree_id, cx)
6980 else {
6981 continue;
6982 };
6983 let worktree = worktree_handle.read(cx);
6984 if !worktree.is_visible() {
6985 continue;
6986 }
6987
6988 if !requested_servers.insert(state.id) {
6989 continue;
6990 }
6991
6992 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
6993 Some(LanguageServerState::Running {
6994 adapter, server, ..
6995 }) => (adapter.clone(), server),
6996
6997 _ => continue,
6998 };
6999 let supports_workspace_symbol_request =
7000 match server.capabilities().workspace_symbol_provider {
7001 Some(OneOf::Left(supported)) => supported,
7002 Some(OneOf::Right(_)) => true,
7003 None => false,
7004 };
7005 if !supports_workspace_symbol_request {
7006 continue;
7007 }
7008 let worktree_abs_path = worktree.abs_path().clone();
7009 let worktree_handle = worktree_handle.clone();
7010 let server_id = server.server_id();
7011 requests.push(
7012 server
7013 .request::<lsp::request::WorkspaceSymbolRequest>(
7014 lsp::WorkspaceSymbolParams {
7015 query: query.to_string(),
7016 ..Default::default()
7017 },
7018 )
7019 .map(move |response| {
7020 let lsp_symbols = response.into_response()
7021 .context("workspace symbols request")
7022 .log_err()
7023 .flatten()
7024 .map(|symbol_response| match symbol_response {
7025 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7026 flat_responses.into_iter().map(|lsp_symbol| {
7027 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7028 }).collect::<Vec<_>>()
7029 }
7030 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7031 nested_responses.into_iter().filter_map(|lsp_symbol| {
7032 let location = match lsp_symbol.location {
7033 OneOf::Left(location) => location,
7034 OneOf::Right(_) => {
7035 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7036 return None
7037 }
7038 };
7039 Some((lsp_symbol.name, lsp_symbol.kind, location))
7040 }).collect::<Vec<_>>()
7041 }
7042 }).unwrap_or_default();
7043
7044 WorkspaceSymbolsResult {
7045 server_id,
7046 lsp_adapter,
7047 worktree: worktree_handle.downgrade(),
7048 worktree_abs_path,
7049 lsp_symbols,
7050 }
7051 }),
7052 );
7053 }
7054
7055 cx.spawn(async move |this, cx| {
7056 let responses = futures::future::join_all(requests).await;
7057 let this = match this.upgrade() {
7058 Some(this) => this,
7059 None => return Ok(Vec::new()),
7060 };
7061
7062 let mut symbols = Vec::new();
7063 for result in responses {
7064 let core_symbols = this.update(cx, |this, cx| {
7065 result
7066 .lsp_symbols
7067 .into_iter()
7068 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7069 let abs_path = symbol_location.uri.to_file_path().ok()?;
7070 let source_worktree = result.worktree.upgrade()?;
7071 let source_worktree_id = source_worktree.read(cx).id();
7072
7073 let path;
7074 let worktree;
7075 if let Some((tree, rel_path)) =
7076 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7077 {
7078 worktree = tree;
7079 path = rel_path;
7080 } else {
7081 worktree = source_worktree;
7082 path = relativize_path(&result.worktree_abs_path, &abs_path);
7083 }
7084
7085 let worktree_id = worktree.read(cx).id();
7086 let project_path = ProjectPath {
7087 worktree_id,
7088 path: path.into(),
7089 };
7090 let signature = this.symbol_signature(&project_path);
7091 Some(CoreSymbol {
7092 source_language_server_id: result.server_id,
7093 language_server_name: result.lsp_adapter.name.clone(),
7094 source_worktree_id,
7095 path: project_path,
7096 kind: symbol_kind,
7097 name: symbol_name,
7098 range: range_from_lsp(symbol_location.range),
7099 signature,
7100 })
7101 })
7102 .collect()
7103 })?;
7104
7105 populate_labels_for_symbols(
7106 core_symbols,
7107 &language_registry,
7108 Some(result.lsp_adapter),
7109 &mut symbols,
7110 )
7111 .await;
7112 }
7113
7114 Ok(symbols)
7115 })
7116 } else {
7117 Task::ready(Err(anyhow!("No upstream client or local language server")))
7118 }
7119 }
7120
7121 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7122 let mut summary = DiagnosticSummary::default();
7123 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7124 summary.error_count += path_summary.error_count;
7125 summary.warning_count += path_summary.warning_count;
7126 }
7127 summary
7128 }
7129
7130 pub fn diagnostic_summaries<'a>(
7131 &'a self,
7132 include_ignored: bool,
7133 cx: &'a App,
7134 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7135 self.worktree_store
7136 .read(cx)
7137 .visible_worktrees(cx)
7138 .filter_map(|worktree| {
7139 let worktree = worktree.read(cx);
7140 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7141 })
7142 .flat_map(move |(worktree, summaries)| {
7143 let worktree_id = worktree.id();
7144 summaries
7145 .iter()
7146 .filter(move |(path, _)| {
7147 include_ignored
7148 || worktree
7149 .entry_for_path(path.as_ref())
7150 .is_some_and(|entry| !entry.is_ignored)
7151 })
7152 .flat_map(move |(path, summaries)| {
7153 summaries.iter().map(move |(server_id, summary)| {
7154 (
7155 ProjectPath {
7156 worktree_id,
7157 path: path.clone(),
7158 },
7159 *server_id,
7160 *summary,
7161 )
7162 })
7163 })
7164 })
7165 }
7166
7167 pub fn on_buffer_edited(
7168 &mut self,
7169 buffer: Entity<Buffer>,
7170 cx: &mut Context<Self>,
7171 ) -> Option<()> {
7172 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7173 Some(
7174 self.as_local()?
7175 .language_servers_for_buffer(buffer, cx)
7176 .map(|i| i.1.clone())
7177 .collect(),
7178 )
7179 })?;
7180
7181 let buffer = buffer.read(cx);
7182 let file = File::from_dyn(buffer.file())?;
7183 let abs_path = file.as_local()?.abs_path(cx);
7184 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7185 let next_snapshot = buffer.text_snapshot();
7186 for language_server in language_servers {
7187 let language_server = language_server.clone();
7188
7189 let buffer_snapshots = self
7190 .as_local_mut()
7191 .unwrap()
7192 .buffer_snapshots
7193 .get_mut(&buffer.remote_id())
7194 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7195 let previous_snapshot = buffer_snapshots.last()?;
7196
7197 let build_incremental_change = || {
7198 buffer
7199 .edits_since::<Dimensions<PointUtf16, usize>>(
7200 previous_snapshot.snapshot.version(),
7201 )
7202 .map(|edit| {
7203 let edit_start = edit.new.start.0;
7204 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7205 let new_text = next_snapshot
7206 .text_for_range(edit.new.start.1..edit.new.end.1)
7207 .collect();
7208 lsp::TextDocumentContentChangeEvent {
7209 range: Some(lsp::Range::new(
7210 point_to_lsp(edit_start),
7211 point_to_lsp(edit_end),
7212 )),
7213 range_length: None,
7214 text: new_text,
7215 }
7216 })
7217 .collect()
7218 };
7219
7220 let document_sync_kind = language_server
7221 .capabilities()
7222 .text_document_sync
7223 .as_ref()
7224 .and_then(|sync| match sync {
7225 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7226 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7227 });
7228
7229 let content_changes: Vec<_> = match document_sync_kind {
7230 Some(lsp::TextDocumentSyncKind::FULL) => {
7231 vec![lsp::TextDocumentContentChangeEvent {
7232 range: None,
7233 range_length: None,
7234 text: next_snapshot.text(),
7235 }]
7236 }
7237 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7238 _ => {
7239 #[cfg(any(test, feature = "test-support"))]
7240 {
7241 build_incremental_change()
7242 }
7243
7244 #[cfg(not(any(test, feature = "test-support")))]
7245 {
7246 continue;
7247 }
7248 }
7249 };
7250
7251 let next_version = previous_snapshot.version + 1;
7252 buffer_snapshots.push(LspBufferSnapshot {
7253 version: next_version,
7254 snapshot: next_snapshot.clone(),
7255 });
7256
7257 language_server
7258 .notify::<lsp::notification::DidChangeTextDocument>(
7259 &lsp::DidChangeTextDocumentParams {
7260 text_document: lsp::VersionedTextDocumentIdentifier::new(
7261 uri.clone(),
7262 next_version,
7263 ),
7264 content_changes,
7265 },
7266 )
7267 .ok();
7268 self.pull_workspace_diagnostics(language_server.server_id());
7269 }
7270
7271 None
7272 }
7273
7274 pub fn on_buffer_saved(
7275 &mut self,
7276 buffer: Entity<Buffer>,
7277 cx: &mut Context<Self>,
7278 ) -> Option<()> {
7279 let file = File::from_dyn(buffer.read(cx).file())?;
7280 let worktree_id = file.worktree_id(cx);
7281 let abs_path = file.as_local()?.abs_path(cx);
7282 let text_document = lsp::TextDocumentIdentifier {
7283 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7284 };
7285 let local = self.as_local()?;
7286
7287 for server in local.language_servers_for_worktree(worktree_id) {
7288 if let Some(include_text) = include_text(server.as_ref()) {
7289 let text = if include_text {
7290 Some(buffer.read(cx).text())
7291 } else {
7292 None
7293 };
7294 server
7295 .notify::<lsp::notification::DidSaveTextDocument>(
7296 &lsp::DidSaveTextDocumentParams {
7297 text_document: text_document.clone(),
7298 text,
7299 },
7300 )
7301 .ok();
7302 }
7303 }
7304
7305 let language_servers = buffer.update(cx, |buffer, cx| {
7306 local.language_server_ids_for_buffer(buffer, cx)
7307 });
7308 for language_server_id in language_servers {
7309 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7310 }
7311
7312 None
7313 }
7314
7315 async fn refresh_workspace_configurations(
7316 lsp_store: &WeakEntity<Self>,
7317 fs: Arc<dyn Fs>,
7318 cx: &mut AsyncApp,
7319 ) {
7320 maybe!(async move {
7321 let mut refreshed_servers = HashSet::default();
7322 let servers = lsp_store
7323 .update(cx, |lsp_store, cx| {
7324 let local = lsp_store.as_local()?;
7325
7326 let servers = local
7327 .language_server_ids
7328 .iter()
7329 .filter_map(|(seed, state)| {
7330 let worktree = lsp_store
7331 .worktree_store
7332 .read(cx)
7333 .worktree_for_id(seed.worktree_id, cx);
7334 let delegate: Arc<dyn LspAdapterDelegate> =
7335 worktree.map(|worktree| {
7336 LocalLspAdapterDelegate::new(
7337 local.languages.clone(),
7338 &local.environment,
7339 cx.weak_entity(),
7340 &worktree,
7341 local.http_client.clone(),
7342 local.fs.clone(),
7343 cx,
7344 )
7345 })?;
7346 let server_id = state.id;
7347
7348 let states = local.language_servers.get(&server_id)?;
7349
7350 match states {
7351 LanguageServerState::Starting { .. } => None,
7352 LanguageServerState::Running {
7353 adapter, server, ..
7354 } => {
7355 let fs = fs.clone();
7356
7357 let adapter = adapter.clone();
7358 let server = server.clone();
7359 refreshed_servers.insert(server.name());
7360 let toolchain = seed.toolchain.clone();
7361 Some(cx.spawn(async move |_, cx| {
7362 let settings =
7363 LocalLspStore::workspace_configuration_for_adapter(
7364 adapter.adapter.clone(),
7365 fs.as_ref(),
7366 &delegate,
7367 toolchain,
7368 cx,
7369 )
7370 .await
7371 .ok()?;
7372 server
7373 .notify::<lsp::notification::DidChangeConfiguration>(
7374 &lsp::DidChangeConfigurationParams { settings },
7375 )
7376 .ok()?;
7377 Some(())
7378 }))
7379 }
7380 }
7381 })
7382 .collect::<Vec<_>>();
7383
7384 Some(servers)
7385 })
7386 .ok()
7387 .flatten()?;
7388
7389 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7390 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7391 // to stop and unregister its language server wrapper.
7392 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7393 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7394 let _: Vec<Option<()>> = join_all(servers).await;
7395
7396 Some(())
7397 })
7398 .await;
7399 }
7400
7401 fn maintain_workspace_config(
7402 fs: Arc<dyn Fs>,
7403 external_refresh_requests: watch::Receiver<()>,
7404 cx: &mut Context<Self>,
7405 ) -> Task<Result<()>> {
7406 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7407 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7408
7409 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7410 *settings_changed_tx.borrow_mut() = ();
7411 });
7412
7413 let mut joint_future =
7414 futures::stream::select(settings_changed_rx, external_refresh_requests);
7415 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7416 // - 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).
7417 // - 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.
7418 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7419 // - 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,
7420 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7421 cx.spawn(async move |this, cx| {
7422 while let Some(()) = joint_future.next().await {
7423 this.update(cx, |this, cx| {
7424 this.refresh_server_tree(cx);
7425 })
7426 .ok();
7427
7428 Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
7429 }
7430
7431 drop(settings_observation);
7432 anyhow::Ok(())
7433 })
7434 }
7435
7436 pub fn language_servers_for_local_buffer<'a>(
7437 &'a self,
7438 buffer: &Buffer,
7439 cx: &mut App,
7440 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7441 let local = self.as_local();
7442 let language_server_ids = local
7443 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7444 .unwrap_or_default();
7445
7446 language_server_ids
7447 .into_iter()
7448 .filter_map(
7449 move |server_id| match local?.language_servers.get(&server_id)? {
7450 LanguageServerState::Running {
7451 adapter, server, ..
7452 } => Some((adapter, server)),
7453 _ => None,
7454 },
7455 )
7456 }
7457
7458 pub fn language_server_for_local_buffer<'a>(
7459 &'a self,
7460 buffer: &'a Buffer,
7461 server_id: LanguageServerId,
7462 cx: &'a mut App,
7463 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7464 self.as_local()?
7465 .language_servers_for_buffer(buffer, cx)
7466 .find(|(_, s)| s.server_id() == server_id)
7467 }
7468
7469 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7470 self.diagnostic_summaries.remove(&id_to_remove);
7471 if let Some(local) = self.as_local_mut() {
7472 let to_remove = local.remove_worktree(id_to_remove, cx);
7473 for server in to_remove {
7474 self.language_server_statuses.remove(&server);
7475 }
7476 }
7477 }
7478
7479 pub fn shared(
7480 &mut self,
7481 project_id: u64,
7482 downstream_client: AnyProtoClient,
7483 _: &mut Context<Self>,
7484 ) {
7485 self.downstream_client = Some((downstream_client.clone(), project_id));
7486
7487 for (server_id, status) in &self.language_server_statuses {
7488 if let Some(server) = self.language_server_for_id(*server_id) {
7489 downstream_client
7490 .send(proto::StartLanguageServer {
7491 project_id,
7492 server: Some(proto::LanguageServer {
7493 id: server_id.to_proto(),
7494 name: status.name.to_string(),
7495 worktree_id: status.worktree.map(|id| id.to_proto()),
7496 }),
7497 capabilities: serde_json::to_string(&server.capabilities())
7498 .expect("serializing server LSP capabilities"),
7499 })
7500 .log_err();
7501 }
7502 }
7503 }
7504
7505 pub fn disconnected_from_host(&mut self) {
7506 self.downstream_client.take();
7507 }
7508
7509 pub fn disconnected_from_ssh_remote(&mut self) {
7510 if let LspStoreMode::Remote(RemoteLspStore {
7511 upstream_client, ..
7512 }) = &mut self.mode
7513 {
7514 upstream_client.take();
7515 }
7516 }
7517
7518 pub(crate) fn set_language_server_statuses_from_proto(
7519 &mut self,
7520 project: WeakEntity<Project>,
7521 language_servers: Vec<proto::LanguageServer>,
7522 server_capabilities: Vec<String>,
7523 cx: &mut Context<Self>,
7524 ) {
7525 let lsp_logs = cx
7526 .try_global::<GlobalLogStore>()
7527 .map(|lsp_store| lsp_store.0.clone());
7528
7529 self.language_server_statuses = language_servers
7530 .into_iter()
7531 .zip(server_capabilities)
7532 .map(|(server, server_capabilities)| {
7533 let server_id = LanguageServerId(server.id as usize);
7534 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7535 self.lsp_server_capabilities
7536 .insert(server_id, server_capabilities);
7537 }
7538
7539 let name = LanguageServerName::from_proto(server.name);
7540 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7541
7542 if let Some(lsp_logs) = &lsp_logs {
7543 lsp_logs.update(cx, |lsp_logs, cx| {
7544 lsp_logs.add_language_server(
7545 // Only remote clients get their language servers set from proto
7546 LanguageServerKind::Remote {
7547 project: project.clone(),
7548 },
7549 server_id,
7550 Some(name.clone()),
7551 worktree,
7552 None,
7553 cx,
7554 );
7555 });
7556 }
7557
7558 (
7559 server_id,
7560 LanguageServerStatus {
7561 name,
7562 pending_work: Default::default(),
7563 has_pending_diagnostic_updates: false,
7564 progress_tokens: Default::default(),
7565 worktree,
7566 },
7567 )
7568 })
7569 .collect();
7570 }
7571
7572 #[cfg(test)]
7573 pub fn update_diagnostic_entries(
7574 &mut self,
7575 server_id: LanguageServerId,
7576 abs_path: PathBuf,
7577 result_id: Option<String>,
7578 version: Option<i32>,
7579 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7580 cx: &mut Context<Self>,
7581 ) -> anyhow::Result<()> {
7582 self.merge_diagnostic_entries(
7583 vec![DocumentDiagnosticsUpdate {
7584 diagnostics: DocumentDiagnostics {
7585 diagnostics,
7586 document_abs_path: abs_path,
7587 version,
7588 },
7589 result_id,
7590 server_id,
7591 disk_based_sources: Cow::Borrowed(&[]),
7592 }],
7593 |_, _, _| false,
7594 cx,
7595 )?;
7596 Ok(())
7597 }
7598
7599 pub fn merge_diagnostic_entries<'a>(
7600 &mut self,
7601 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7602 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7603 cx: &mut Context<Self>,
7604 ) -> anyhow::Result<()> {
7605 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7606 let mut updated_diagnostics_paths = HashMap::default();
7607 for mut update in diagnostic_updates {
7608 let abs_path = &update.diagnostics.document_abs_path;
7609 let server_id = update.server_id;
7610 let Some((worktree, relative_path)) =
7611 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7612 else {
7613 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7614 return Ok(());
7615 };
7616
7617 let worktree_id = worktree.read(cx).id();
7618 let project_path = ProjectPath {
7619 worktree_id,
7620 path: relative_path.into(),
7621 };
7622
7623 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7624 let snapshot = buffer_handle.read(cx).snapshot();
7625 let buffer = buffer_handle.read(cx);
7626 let reused_diagnostics = buffer
7627 .buffer_diagnostics(Some(server_id))
7628 .iter()
7629 .filter(|v| merge(buffer, &v.diagnostic, cx))
7630 .map(|v| {
7631 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7632 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7633 DiagnosticEntry {
7634 range: start..end,
7635 diagnostic: v.diagnostic.clone(),
7636 }
7637 })
7638 .collect::<Vec<_>>();
7639
7640 self.as_local_mut()
7641 .context("cannot merge diagnostics on a remote LspStore")?
7642 .update_buffer_diagnostics(
7643 &buffer_handle,
7644 server_id,
7645 update.result_id,
7646 update.diagnostics.version,
7647 update.diagnostics.diagnostics.clone(),
7648 reused_diagnostics.clone(),
7649 cx,
7650 )?;
7651
7652 update.diagnostics.diagnostics.extend(reused_diagnostics);
7653 }
7654
7655 let updated = worktree.update(cx, |worktree, cx| {
7656 self.update_worktree_diagnostics(
7657 worktree.id(),
7658 server_id,
7659 project_path.path.clone(),
7660 update.diagnostics.diagnostics,
7661 cx,
7662 )
7663 })?;
7664 match updated {
7665 ControlFlow::Continue(new_summary) => {
7666 if let Some((project_id, new_summary)) = new_summary {
7667 match &mut diagnostics_summary {
7668 Some(diagnostics_summary) => {
7669 diagnostics_summary
7670 .more_summaries
7671 .push(proto::DiagnosticSummary {
7672 path: project_path.path.as_ref().to_proto(),
7673 language_server_id: server_id.0 as u64,
7674 error_count: new_summary.error_count,
7675 warning_count: new_summary.warning_count,
7676 })
7677 }
7678 None => {
7679 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7680 project_id,
7681 worktree_id: worktree_id.to_proto(),
7682 summary: Some(proto::DiagnosticSummary {
7683 path: project_path.path.as_ref().to_proto(),
7684 language_server_id: server_id.0 as u64,
7685 error_count: new_summary.error_count,
7686 warning_count: new_summary.warning_count,
7687 }),
7688 more_summaries: Vec::new(),
7689 })
7690 }
7691 }
7692 }
7693 updated_diagnostics_paths
7694 .entry(server_id)
7695 .or_insert_with(Vec::new)
7696 .push(project_path);
7697 }
7698 ControlFlow::Break(()) => {}
7699 }
7700 }
7701
7702 if let Some((diagnostics_summary, (downstream_client, _))) =
7703 diagnostics_summary.zip(self.downstream_client.as_ref())
7704 {
7705 downstream_client.send(diagnostics_summary).log_err();
7706 }
7707 for (server_id, paths) in updated_diagnostics_paths {
7708 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7709 }
7710 Ok(())
7711 }
7712
7713 fn update_worktree_diagnostics(
7714 &mut self,
7715 worktree_id: WorktreeId,
7716 server_id: LanguageServerId,
7717 path_in_worktree: Arc<Path>,
7718 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7719 _: &mut Context<Worktree>,
7720 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7721 let local = match &mut self.mode {
7722 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7723 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7724 };
7725
7726 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7727 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7728 let summaries_by_server_id = summaries_for_tree
7729 .entry(path_in_worktree.clone())
7730 .or_default();
7731
7732 let old_summary = summaries_by_server_id
7733 .remove(&server_id)
7734 .unwrap_or_default();
7735
7736 let new_summary = DiagnosticSummary::new(&diagnostics);
7737 if new_summary.is_empty() {
7738 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7739 {
7740 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7741 diagnostics_by_server_id.remove(ix);
7742 }
7743 if diagnostics_by_server_id.is_empty() {
7744 diagnostics_for_tree.remove(&path_in_worktree);
7745 }
7746 }
7747 } else {
7748 summaries_by_server_id.insert(server_id, new_summary);
7749 let diagnostics_by_server_id = diagnostics_for_tree
7750 .entry(path_in_worktree.clone())
7751 .or_default();
7752 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7753 Ok(ix) => {
7754 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7755 }
7756 Err(ix) => {
7757 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7758 }
7759 }
7760 }
7761
7762 if !old_summary.is_empty() || !new_summary.is_empty() {
7763 if let Some((_, project_id)) = &self.downstream_client {
7764 Ok(ControlFlow::Continue(Some((
7765 *project_id,
7766 proto::DiagnosticSummary {
7767 path: path_in_worktree.to_proto(),
7768 language_server_id: server_id.0 as u64,
7769 error_count: new_summary.error_count as u32,
7770 warning_count: new_summary.warning_count as u32,
7771 },
7772 ))))
7773 } else {
7774 Ok(ControlFlow::Continue(None))
7775 }
7776 } else {
7777 Ok(ControlFlow::Break(()))
7778 }
7779 }
7780
7781 pub fn open_buffer_for_symbol(
7782 &mut self,
7783 symbol: &Symbol,
7784 cx: &mut Context<Self>,
7785 ) -> Task<Result<Entity<Buffer>>> {
7786 if let Some((client, project_id)) = self.upstream_client() {
7787 let request = client.request(proto::OpenBufferForSymbol {
7788 project_id,
7789 symbol: Some(Self::serialize_symbol(symbol)),
7790 });
7791 cx.spawn(async move |this, cx| {
7792 let response = request.await?;
7793 let buffer_id = BufferId::new(response.buffer_id)?;
7794 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7795 .await
7796 })
7797 } else if let Some(local) = self.as_local() {
7798 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7799 seed.worktree_id == symbol.source_worktree_id
7800 && state.id == symbol.source_language_server_id
7801 && symbol.language_server_name == seed.name
7802 });
7803 if !is_valid {
7804 return Task::ready(Err(anyhow!(
7805 "language server for worktree and language not found"
7806 )));
7807 };
7808
7809 let worktree_abs_path = if let Some(worktree_abs_path) = self
7810 .worktree_store
7811 .read(cx)
7812 .worktree_for_id(symbol.path.worktree_id, cx)
7813 .map(|worktree| worktree.read(cx).abs_path())
7814 {
7815 worktree_abs_path
7816 } else {
7817 return Task::ready(Err(anyhow!("worktree not found for symbol")));
7818 };
7819
7820 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
7821 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
7822 uri
7823 } else {
7824 return Task::ready(Err(anyhow!("invalid symbol path")));
7825 };
7826
7827 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7828 } else {
7829 Task::ready(Err(anyhow!("no upstream client or local store")))
7830 }
7831 }
7832
7833 pub(crate) fn open_local_buffer_via_lsp(
7834 &mut self,
7835 abs_path: lsp::Uri,
7836 language_server_id: LanguageServerId,
7837 cx: &mut Context<Self>,
7838 ) -> Task<Result<Entity<Buffer>>> {
7839 cx.spawn(async move |lsp_store, cx| {
7840 // Escape percent-encoded string.
7841 let current_scheme = abs_path.scheme().to_owned();
7842 // Uri is immutable, so we can't modify the scheme
7843
7844 let abs_path = abs_path
7845 .to_file_path()
7846 .map_err(|()| anyhow!("can't convert URI to path"))?;
7847 let p = abs_path.clone();
7848 let yarn_worktree = lsp_store
7849 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7850 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7851 cx.spawn(async move |this, cx| {
7852 let t = this
7853 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7854 .ok()?;
7855 t.await
7856 })
7857 }),
7858 None => Task::ready(None),
7859 })?
7860 .await;
7861 let (worktree_root_target, known_relative_path) =
7862 if let Some((zip_root, relative_path)) = yarn_worktree {
7863 (zip_root, Some(relative_path))
7864 } else {
7865 (Arc::<Path>::from(abs_path.as_path()), None)
7866 };
7867 let (worktree, relative_path) = if let Some(result) =
7868 lsp_store.update(cx, |lsp_store, cx| {
7869 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7870 worktree_store.find_worktree(&worktree_root_target, cx)
7871 })
7872 })? {
7873 let relative_path =
7874 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
7875 (result.0, relative_path)
7876 } else {
7877 let worktree = lsp_store
7878 .update(cx, |lsp_store, cx| {
7879 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7880 worktree_store.create_worktree(&worktree_root_target, false, cx)
7881 })
7882 })?
7883 .await?;
7884 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
7885 lsp_store
7886 .update(cx, |lsp_store, cx| {
7887 if let Some(local) = lsp_store.as_local_mut() {
7888 local.register_language_server_for_invisible_worktree(
7889 &worktree,
7890 language_server_id,
7891 cx,
7892 )
7893 }
7894 })
7895 .ok();
7896 }
7897 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
7898 let relative_path = if let Some(known_path) = known_relative_path {
7899 known_path
7900 } else {
7901 abs_path.strip_prefix(worktree_root)?.into()
7902 };
7903 (worktree, relative_path)
7904 };
7905 let project_path = ProjectPath {
7906 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
7907 path: relative_path,
7908 };
7909 lsp_store
7910 .update(cx, |lsp_store, cx| {
7911 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
7912 buffer_store.open_buffer(project_path, cx)
7913 })
7914 })?
7915 .await
7916 })
7917 }
7918
7919 fn request_multiple_lsp_locally<P, R>(
7920 &mut self,
7921 buffer: &Entity<Buffer>,
7922 position: Option<P>,
7923 request: R,
7924 cx: &mut Context<Self>,
7925 ) -> Task<Vec<(LanguageServerId, R::Response)>>
7926 where
7927 P: ToOffset,
7928 R: LspCommand + Clone,
7929 <R::LspRequest as lsp::request::Request>::Result: Send,
7930 <R::LspRequest as lsp::request::Request>::Params: Send,
7931 {
7932 let Some(local) = self.as_local() else {
7933 return Task::ready(Vec::new());
7934 };
7935
7936 let snapshot = buffer.read(cx).snapshot();
7937 let scope = position.and_then(|position| snapshot.language_scope_at(position));
7938
7939 let server_ids = buffer.update(cx, |buffer, cx| {
7940 local
7941 .language_servers_for_buffer(buffer, cx)
7942 .filter(|(adapter, _)| {
7943 scope
7944 .as_ref()
7945 .map(|scope| scope.language_allowed(&adapter.name))
7946 .unwrap_or(true)
7947 })
7948 .map(|(_, server)| server.server_id())
7949 .filter(|server_id| {
7950 self.as_local().is_none_or(|local| {
7951 local
7952 .buffers_opened_in_servers
7953 .get(&snapshot.remote_id())
7954 .is_some_and(|servers| servers.contains(server_id))
7955 })
7956 })
7957 .collect::<Vec<_>>()
7958 });
7959
7960 let mut response_results = server_ids
7961 .into_iter()
7962 .map(|server_id| {
7963 let task = self.request_lsp(
7964 buffer.clone(),
7965 LanguageServerToQuery::Other(server_id),
7966 request.clone(),
7967 cx,
7968 );
7969 async move { (server_id, task.await) }
7970 })
7971 .collect::<FuturesUnordered<_>>();
7972
7973 cx.background_spawn(async move {
7974 let mut responses = Vec::with_capacity(response_results.len());
7975 while let Some((server_id, response_result)) = response_results.next().await {
7976 if let Some(response) = response_result.log_err() {
7977 responses.push((server_id, response));
7978 }
7979 }
7980 responses
7981 })
7982 }
7983
7984 async fn handle_lsp_command<T: LspCommand>(
7985 this: Entity<Self>,
7986 envelope: TypedEnvelope<T::ProtoRequest>,
7987 mut cx: AsyncApp,
7988 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
7989 where
7990 <T::LspRequest as lsp::request::Request>::Params: Send,
7991 <T::LspRequest as lsp::request::Request>::Result: Send,
7992 {
7993 let sender_id = envelope.original_sender_id().unwrap_or_default();
7994 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
7995 let buffer_handle = this.update(&mut cx, |this, cx| {
7996 this.buffer_store.read(cx).get_existing(buffer_id)
7997 })??;
7998 let request = T::from_proto(
7999 envelope.payload,
8000 this.clone(),
8001 buffer_handle.clone(),
8002 cx.clone(),
8003 )
8004 .await?;
8005 let response = this
8006 .update(&mut cx, |this, cx| {
8007 this.request_lsp(
8008 buffer_handle.clone(),
8009 LanguageServerToQuery::FirstCapable,
8010 request,
8011 cx,
8012 )
8013 })?
8014 .await?;
8015 this.update(&mut cx, |this, cx| {
8016 Ok(T::response_to_proto(
8017 response,
8018 this,
8019 sender_id,
8020 &buffer_handle.read(cx).version(),
8021 cx,
8022 ))
8023 })?
8024 }
8025
8026 async fn handle_lsp_query(
8027 lsp_store: Entity<Self>,
8028 envelope: TypedEnvelope<proto::LspQuery>,
8029 mut cx: AsyncApp,
8030 ) -> Result<proto::Ack> {
8031 use proto::lsp_query::Request;
8032 let sender_id = envelope.original_sender_id().unwrap_or_default();
8033 let lsp_query = envelope.payload;
8034 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8035 match lsp_query.request.context("invalid LSP query request")? {
8036 Request::GetReferences(get_references) => {
8037 let position = get_references.position.clone().and_then(deserialize_anchor);
8038 Self::query_lsp_locally::<GetReferences>(
8039 lsp_store,
8040 sender_id,
8041 lsp_request_id,
8042 get_references,
8043 position,
8044 cx.clone(),
8045 )
8046 .await?;
8047 }
8048 Request::GetDocumentColor(get_document_color) => {
8049 Self::query_lsp_locally::<GetDocumentColor>(
8050 lsp_store,
8051 sender_id,
8052 lsp_request_id,
8053 get_document_color,
8054 None,
8055 cx.clone(),
8056 )
8057 .await?;
8058 }
8059 Request::GetHover(get_hover) => {
8060 let position = get_hover.position.clone().and_then(deserialize_anchor);
8061 Self::query_lsp_locally::<GetHover>(
8062 lsp_store,
8063 sender_id,
8064 lsp_request_id,
8065 get_hover,
8066 position,
8067 cx.clone(),
8068 )
8069 .await?;
8070 }
8071 Request::GetCodeActions(get_code_actions) => {
8072 Self::query_lsp_locally::<GetCodeActions>(
8073 lsp_store,
8074 sender_id,
8075 lsp_request_id,
8076 get_code_actions,
8077 None,
8078 cx.clone(),
8079 )
8080 .await?;
8081 }
8082 Request::GetSignatureHelp(get_signature_help) => {
8083 let position = get_signature_help
8084 .position
8085 .clone()
8086 .and_then(deserialize_anchor);
8087 Self::query_lsp_locally::<GetSignatureHelp>(
8088 lsp_store,
8089 sender_id,
8090 lsp_request_id,
8091 get_signature_help,
8092 position,
8093 cx.clone(),
8094 )
8095 .await?;
8096 }
8097 Request::GetCodeLens(get_code_lens) => {
8098 Self::query_lsp_locally::<GetCodeLens>(
8099 lsp_store,
8100 sender_id,
8101 lsp_request_id,
8102 get_code_lens,
8103 None,
8104 cx.clone(),
8105 )
8106 .await?;
8107 }
8108 Request::GetDefinition(get_definition) => {
8109 let position = get_definition.position.clone().and_then(deserialize_anchor);
8110 Self::query_lsp_locally::<GetDefinitions>(
8111 lsp_store,
8112 sender_id,
8113 lsp_request_id,
8114 get_definition,
8115 position,
8116 cx.clone(),
8117 )
8118 .await?;
8119 }
8120 Request::GetDeclaration(get_declaration) => {
8121 let position = get_declaration
8122 .position
8123 .clone()
8124 .and_then(deserialize_anchor);
8125 Self::query_lsp_locally::<GetDeclarations>(
8126 lsp_store,
8127 sender_id,
8128 lsp_request_id,
8129 get_declaration,
8130 position,
8131 cx.clone(),
8132 )
8133 .await?;
8134 }
8135 Request::GetTypeDefinition(get_type_definition) => {
8136 let position = get_type_definition
8137 .position
8138 .clone()
8139 .and_then(deserialize_anchor);
8140 Self::query_lsp_locally::<GetTypeDefinitions>(
8141 lsp_store,
8142 sender_id,
8143 lsp_request_id,
8144 get_type_definition,
8145 position,
8146 cx.clone(),
8147 )
8148 .await?;
8149 }
8150 Request::GetImplementation(get_implementation) => {
8151 let position = get_implementation
8152 .position
8153 .clone()
8154 .and_then(deserialize_anchor);
8155 Self::query_lsp_locally::<GetImplementations>(
8156 lsp_store,
8157 sender_id,
8158 lsp_request_id,
8159 get_implementation,
8160 position,
8161 cx.clone(),
8162 )
8163 .await?;
8164 }
8165 // Diagnostics pull synchronizes internally via the buffer state, and cannot be handled generically as the other requests.
8166 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8167 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8168 let version = deserialize_version(get_document_diagnostics.buffer_version());
8169 let buffer = lsp_store.update(&mut cx, |this, cx| {
8170 this.buffer_store.read(cx).get_existing(buffer_id)
8171 })??;
8172 buffer
8173 .update(&mut cx, |buffer, _| {
8174 buffer.wait_for_version(version.clone())
8175 })?
8176 .await?;
8177 lsp_store.update(&mut cx, |lsp_store, cx| {
8178 let existing_queries = lsp_store
8179 .running_lsp_requests
8180 .entry(TypeId::of::<GetDocumentDiagnostics>())
8181 .or_default();
8182 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8183 ) || buffer.read(cx).version.changed_since(&existing_queries.0)
8184 {
8185 existing_queries.1.clear();
8186 }
8187 existing_queries.1.insert(
8188 lsp_request_id,
8189 cx.spawn(async move |lsp_store, cx| {
8190 let diagnostics_pull = lsp_store
8191 .update(cx, |lsp_store, cx| {
8192 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8193 })
8194 .ok();
8195 if let Some(diagnostics_pull) = diagnostics_pull {
8196 match diagnostics_pull.await {
8197 Ok(()) => {}
8198 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8199 };
8200 }
8201 }),
8202 );
8203 })?;
8204 }
8205 }
8206 Ok(proto::Ack {})
8207 }
8208
8209 async fn handle_lsp_query_response(
8210 lsp_store: Entity<Self>,
8211 envelope: TypedEnvelope<proto::LspQueryResponse>,
8212 cx: AsyncApp,
8213 ) -> Result<()> {
8214 lsp_store.read_with(&cx, |lsp_store, _| {
8215 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8216 upstream_client.handle_lsp_response(envelope.clone());
8217 }
8218 })?;
8219 Ok(())
8220 }
8221
8222 // todo(lsp) remove after Zed Stable hits v0.204.x
8223 async fn handle_multi_lsp_query(
8224 lsp_store: Entity<Self>,
8225 envelope: TypedEnvelope<proto::MultiLspQuery>,
8226 mut cx: AsyncApp,
8227 ) -> Result<proto::MultiLspQueryResponse> {
8228 let response_from_ssh = lsp_store.read_with(&cx, |this, _| {
8229 let (upstream_client, project_id) = this.upstream_client()?;
8230 let mut payload = envelope.payload.clone();
8231 payload.project_id = project_id;
8232
8233 Some(upstream_client.request(payload))
8234 })?;
8235 if let Some(response_from_ssh) = response_from_ssh {
8236 return response_from_ssh.await;
8237 }
8238
8239 let sender_id = envelope.original_sender_id().unwrap_or_default();
8240 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8241 let version = deserialize_version(&envelope.payload.version);
8242 let buffer = lsp_store.update(&mut cx, |this, cx| {
8243 this.buffer_store.read(cx).get_existing(buffer_id)
8244 })??;
8245 buffer
8246 .update(&mut cx, |buffer, _| {
8247 buffer.wait_for_version(version.clone())
8248 })?
8249 .await?;
8250 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
8251 match envelope
8252 .payload
8253 .strategy
8254 .context("invalid request without the strategy")?
8255 {
8256 proto::multi_lsp_query::Strategy::All(_) => {
8257 // currently, there's only one multiple language servers query strategy,
8258 // so just ensure it's specified correctly
8259 }
8260 }
8261 match envelope.payload.request {
8262 Some(proto::multi_lsp_query::Request::GetHover(message)) => {
8263 buffer
8264 .update(&mut cx, |buffer, _| {
8265 buffer.wait_for_version(deserialize_version(&message.version))
8266 })?
8267 .await?;
8268 let get_hover =
8269 GetHover::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8270 .await?;
8271 let all_hovers = lsp_store
8272 .update(&mut cx, |this, cx| {
8273 this.request_multiple_lsp_locally(
8274 &buffer,
8275 Some(get_hover.position),
8276 get_hover,
8277 cx,
8278 )
8279 })?
8280 .await
8281 .into_iter()
8282 .filter_map(|(server_id, hover)| {
8283 Some((server_id, remove_empty_hover_blocks(hover?)?))
8284 });
8285 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8286 responses: all_hovers
8287 .map(|(server_id, hover)| proto::LspResponse {
8288 server_id: server_id.to_proto(),
8289 response: Some(proto::lsp_response::Response::GetHoverResponse(
8290 GetHover::response_to_proto(
8291 Some(hover),
8292 project,
8293 sender_id,
8294 &buffer_version,
8295 cx,
8296 ),
8297 )),
8298 })
8299 .collect(),
8300 })
8301 }
8302 Some(proto::multi_lsp_query::Request::GetCodeActions(message)) => {
8303 buffer
8304 .update(&mut cx, |buffer, _| {
8305 buffer.wait_for_version(deserialize_version(&message.version))
8306 })?
8307 .await?;
8308 let get_code_actions = GetCodeActions::from_proto(
8309 message,
8310 lsp_store.clone(),
8311 buffer.clone(),
8312 cx.clone(),
8313 )
8314 .await?;
8315
8316 let all_actions = lsp_store
8317 .update(&mut cx, |project, cx| {
8318 project.request_multiple_lsp_locally(
8319 &buffer,
8320 Some(get_code_actions.range.start),
8321 get_code_actions,
8322 cx,
8323 )
8324 })?
8325 .await
8326 .into_iter();
8327
8328 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8329 responses: all_actions
8330 .map(|(server_id, code_actions)| proto::LspResponse {
8331 server_id: server_id.to_proto(),
8332 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
8333 GetCodeActions::response_to_proto(
8334 code_actions,
8335 project,
8336 sender_id,
8337 &buffer_version,
8338 cx,
8339 ),
8340 )),
8341 })
8342 .collect(),
8343 })
8344 }
8345 Some(proto::multi_lsp_query::Request::GetSignatureHelp(message)) => {
8346 buffer
8347 .update(&mut cx, |buffer, _| {
8348 buffer.wait_for_version(deserialize_version(&message.version))
8349 })?
8350 .await?;
8351 let get_signature_help = GetSignatureHelp::from_proto(
8352 message,
8353 lsp_store.clone(),
8354 buffer.clone(),
8355 cx.clone(),
8356 )
8357 .await?;
8358
8359 let all_signatures = lsp_store
8360 .update(&mut cx, |project, cx| {
8361 project.request_multiple_lsp_locally(
8362 &buffer,
8363 Some(get_signature_help.position),
8364 get_signature_help,
8365 cx,
8366 )
8367 })?
8368 .await
8369 .into_iter();
8370
8371 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8372 responses: all_signatures
8373 .map(|(server_id, signature_help)| proto::LspResponse {
8374 server_id: server_id.to_proto(),
8375 response: Some(
8376 proto::lsp_response::Response::GetSignatureHelpResponse(
8377 GetSignatureHelp::response_to_proto(
8378 signature_help,
8379 project,
8380 sender_id,
8381 &buffer_version,
8382 cx,
8383 ),
8384 ),
8385 ),
8386 })
8387 .collect(),
8388 })
8389 }
8390 Some(proto::multi_lsp_query::Request::GetCodeLens(message)) => {
8391 buffer
8392 .update(&mut cx, |buffer, _| {
8393 buffer.wait_for_version(deserialize_version(&message.version))
8394 })?
8395 .await?;
8396 let get_code_lens =
8397 GetCodeLens::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8398 .await?;
8399
8400 let code_lens_actions = lsp_store
8401 .update(&mut cx, |project, cx| {
8402 project.request_multiple_lsp_locally(
8403 &buffer,
8404 None::<usize>,
8405 get_code_lens,
8406 cx,
8407 )
8408 })?
8409 .await
8410 .into_iter();
8411
8412 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8413 responses: code_lens_actions
8414 .map(|(server_id, actions)| proto::LspResponse {
8415 server_id: server_id.to_proto(),
8416 response: Some(proto::lsp_response::Response::GetCodeLensResponse(
8417 GetCodeLens::response_to_proto(
8418 actions,
8419 project,
8420 sender_id,
8421 &buffer_version,
8422 cx,
8423 ),
8424 )),
8425 })
8426 .collect(),
8427 })
8428 }
8429 Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(message)) => {
8430 buffer
8431 .update(&mut cx, |buffer, _| {
8432 buffer.wait_for_version(deserialize_version(&message.version))
8433 })?
8434 .await?;
8435 lsp_store
8436 .update(&mut cx, |lsp_store, cx| {
8437 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8438 })?
8439 .await?;
8440 // `pull_diagnostics_for_buffer` will merge in the new diagnostics and send them to the client.
8441 // The client cannot merge anything into its non-local LspStore, so we do not need to return anything.
8442 Ok(proto::MultiLspQueryResponse {
8443 responses: Vec::new(),
8444 })
8445 }
8446 Some(proto::multi_lsp_query::Request::GetDocumentColor(message)) => {
8447 buffer
8448 .update(&mut cx, |buffer, _| {
8449 buffer.wait_for_version(deserialize_version(&message.version))
8450 })?
8451 .await?;
8452 let get_document_color = GetDocumentColor::from_proto(
8453 message,
8454 lsp_store.clone(),
8455 buffer.clone(),
8456 cx.clone(),
8457 )
8458 .await?;
8459
8460 let all_colors = lsp_store
8461 .update(&mut cx, |project, cx| {
8462 project.request_multiple_lsp_locally(
8463 &buffer,
8464 None::<usize>,
8465 get_document_color,
8466 cx,
8467 )
8468 })?
8469 .await
8470 .into_iter();
8471
8472 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8473 responses: all_colors
8474 .map(|(server_id, colors)| proto::LspResponse {
8475 server_id: server_id.to_proto(),
8476 response: Some(
8477 proto::lsp_response::Response::GetDocumentColorResponse(
8478 GetDocumentColor::response_to_proto(
8479 colors,
8480 project,
8481 sender_id,
8482 &buffer_version,
8483 cx,
8484 ),
8485 ),
8486 ),
8487 })
8488 .collect(),
8489 })
8490 }
8491 Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
8492 let get_definitions = GetDefinitions::from_proto(
8493 message,
8494 lsp_store.clone(),
8495 buffer.clone(),
8496 cx.clone(),
8497 )
8498 .await?;
8499
8500 let definitions = lsp_store
8501 .update(&mut cx, |project, cx| {
8502 project.request_multiple_lsp_locally(
8503 &buffer,
8504 Some(get_definitions.position),
8505 get_definitions,
8506 cx,
8507 )
8508 })?
8509 .await
8510 .into_iter();
8511
8512 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8513 responses: definitions
8514 .map(|(server_id, definitions)| proto::LspResponse {
8515 server_id: server_id.to_proto(),
8516 response: Some(proto::lsp_response::Response::GetDefinitionResponse(
8517 GetDefinitions::response_to_proto(
8518 definitions,
8519 project,
8520 sender_id,
8521 &buffer_version,
8522 cx,
8523 ),
8524 )),
8525 })
8526 .collect(),
8527 })
8528 }
8529 Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
8530 let get_declarations = GetDeclarations::from_proto(
8531 message,
8532 lsp_store.clone(),
8533 buffer.clone(),
8534 cx.clone(),
8535 )
8536 .await?;
8537
8538 let declarations = lsp_store
8539 .update(&mut cx, |project, cx| {
8540 project.request_multiple_lsp_locally(
8541 &buffer,
8542 Some(get_declarations.position),
8543 get_declarations,
8544 cx,
8545 )
8546 })?
8547 .await
8548 .into_iter();
8549
8550 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8551 responses: declarations
8552 .map(|(server_id, declarations)| proto::LspResponse {
8553 server_id: server_id.to_proto(),
8554 response: Some(proto::lsp_response::Response::GetDeclarationResponse(
8555 GetDeclarations::response_to_proto(
8556 declarations,
8557 project,
8558 sender_id,
8559 &buffer_version,
8560 cx,
8561 ),
8562 )),
8563 })
8564 .collect(),
8565 })
8566 }
8567 Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
8568 let get_type_definitions = GetTypeDefinitions::from_proto(
8569 message,
8570 lsp_store.clone(),
8571 buffer.clone(),
8572 cx.clone(),
8573 )
8574 .await?;
8575
8576 let type_definitions = lsp_store
8577 .update(&mut cx, |project, cx| {
8578 project.request_multiple_lsp_locally(
8579 &buffer,
8580 Some(get_type_definitions.position),
8581 get_type_definitions,
8582 cx,
8583 )
8584 })?
8585 .await
8586 .into_iter();
8587
8588 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8589 responses: type_definitions
8590 .map(|(server_id, type_definitions)| proto::LspResponse {
8591 server_id: server_id.to_proto(),
8592 response: Some(
8593 proto::lsp_response::Response::GetTypeDefinitionResponse(
8594 GetTypeDefinitions::response_to_proto(
8595 type_definitions,
8596 project,
8597 sender_id,
8598 &buffer_version,
8599 cx,
8600 ),
8601 ),
8602 ),
8603 })
8604 .collect(),
8605 })
8606 }
8607 Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
8608 let get_implementations = GetImplementations::from_proto(
8609 message,
8610 lsp_store.clone(),
8611 buffer.clone(),
8612 cx.clone(),
8613 )
8614 .await?;
8615
8616 let implementations = lsp_store
8617 .update(&mut cx, |project, cx| {
8618 project.request_multiple_lsp_locally(
8619 &buffer,
8620 Some(get_implementations.position),
8621 get_implementations,
8622 cx,
8623 )
8624 })?
8625 .await
8626 .into_iter();
8627
8628 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8629 responses: implementations
8630 .map(|(server_id, implementations)| proto::LspResponse {
8631 server_id: server_id.to_proto(),
8632 response: Some(
8633 proto::lsp_response::Response::GetImplementationResponse(
8634 GetImplementations::response_to_proto(
8635 implementations,
8636 project,
8637 sender_id,
8638 &buffer_version,
8639 cx,
8640 ),
8641 ),
8642 ),
8643 })
8644 .collect(),
8645 })
8646 }
8647 Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
8648 let get_references = GetReferences::from_proto(
8649 message,
8650 lsp_store.clone(),
8651 buffer.clone(),
8652 cx.clone(),
8653 )
8654 .await?;
8655
8656 let references = lsp_store
8657 .update(&mut cx, |project, cx| {
8658 project.request_multiple_lsp_locally(
8659 &buffer,
8660 Some(get_references.position),
8661 get_references,
8662 cx,
8663 )
8664 })?
8665 .await
8666 .into_iter();
8667
8668 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8669 responses: references
8670 .map(|(server_id, references)| proto::LspResponse {
8671 server_id: server_id.to_proto(),
8672 response: Some(proto::lsp_response::Response::GetReferencesResponse(
8673 GetReferences::response_to_proto(
8674 references,
8675 project,
8676 sender_id,
8677 &buffer_version,
8678 cx,
8679 ),
8680 )),
8681 })
8682 .collect(),
8683 })
8684 }
8685 None => anyhow::bail!("empty multi lsp query request"),
8686 }
8687 }
8688
8689 async fn handle_apply_code_action(
8690 this: Entity<Self>,
8691 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8692 mut cx: AsyncApp,
8693 ) -> Result<proto::ApplyCodeActionResponse> {
8694 let sender_id = envelope.original_sender_id().unwrap_or_default();
8695 let action =
8696 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8697 let apply_code_action = this.update(&mut cx, |this, cx| {
8698 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8699 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8700 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8701 })??;
8702
8703 let project_transaction = apply_code_action.await?;
8704 let project_transaction = this.update(&mut cx, |this, cx| {
8705 this.buffer_store.update(cx, |buffer_store, cx| {
8706 buffer_store.serialize_project_transaction_for_peer(
8707 project_transaction,
8708 sender_id,
8709 cx,
8710 )
8711 })
8712 })?;
8713 Ok(proto::ApplyCodeActionResponse {
8714 transaction: Some(project_transaction),
8715 })
8716 }
8717
8718 async fn handle_register_buffer_with_language_servers(
8719 this: Entity<Self>,
8720 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8721 mut cx: AsyncApp,
8722 ) -> Result<proto::Ack> {
8723 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8724 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8725 this.update(&mut cx, |this, cx| {
8726 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8727 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8728 project_id: upstream_project_id,
8729 buffer_id: buffer_id.to_proto(),
8730 only_servers: envelope.payload.only_servers,
8731 });
8732 }
8733
8734 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8735 anyhow::bail!("buffer is not open");
8736 };
8737
8738 let handle = this.register_buffer_with_language_servers(
8739 &buffer,
8740 envelope
8741 .payload
8742 .only_servers
8743 .into_iter()
8744 .filter_map(|selector| {
8745 Some(match selector.selector? {
8746 proto::language_server_selector::Selector::ServerId(server_id) => {
8747 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8748 }
8749 proto::language_server_selector::Selector::Name(name) => {
8750 LanguageServerSelector::Name(LanguageServerName(
8751 SharedString::from(name),
8752 ))
8753 }
8754 })
8755 })
8756 .collect(),
8757 false,
8758 cx,
8759 );
8760 this.buffer_store().update(cx, |buffer_store, _| {
8761 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8762 });
8763
8764 Ok(())
8765 })??;
8766 Ok(proto::Ack {})
8767 }
8768
8769 async fn handle_rename_project_entry(
8770 this: Entity<Self>,
8771 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8772 mut cx: AsyncApp,
8773 ) -> Result<proto::ProjectEntryResponse> {
8774 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8775 let (worktree_id, worktree, old_path, is_dir) = this
8776 .update(&mut cx, |this, cx| {
8777 this.worktree_store
8778 .read(cx)
8779 .worktree_and_entry_for_id(entry_id, cx)
8780 .map(|(worktree, entry)| {
8781 (
8782 worktree.read(cx).id(),
8783 worktree,
8784 entry.path.clone(),
8785 entry.is_dir(),
8786 )
8787 })
8788 })?
8789 .context("worktree not found")?;
8790 let (old_abs_path, new_abs_path) = {
8791 let root_path = worktree.read_with(&cx, |this, _| this.abs_path())?;
8792 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8793 (root_path.join(&old_path), root_path.join(&new_path))
8794 };
8795
8796 let _transaction = Self::will_rename_entry(
8797 this.downgrade(),
8798 worktree_id,
8799 &old_abs_path,
8800 &new_abs_path,
8801 is_dir,
8802 cx.clone(),
8803 )
8804 .await;
8805 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8806 this.read_with(&cx, |this, _| {
8807 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8808 })
8809 .ok();
8810 response
8811 }
8812
8813 async fn handle_update_diagnostic_summary(
8814 this: Entity<Self>,
8815 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8816 mut cx: AsyncApp,
8817 ) -> Result<()> {
8818 this.update(&mut cx, |lsp_store, cx| {
8819 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8820 let mut updated_diagnostics_paths = HashMap::default();
8821 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8822 for message_summary in envelope
8823 .payload
8824 .summary
8825 .into_iter()
8826 .chain(envelope.payload.more_summaries)
8827 {
8828 let project_path = ProjectPath {
8829 worktree_id,
8830 path: Arc::<Path>::from_proto(message_summary.path),
8831 };
8832 let path = project_path.path.clone();
8833 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8834 let summary = DiagnosticSummary {
8835 error_count: message_summary.error_count as usize,
8836 warning_count: message_summary.warning_count as usize,
8837 };
8838
8839 if summary.is_empty() {
8840 if let Some(worktree_summaries) =
8841 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8842 && let Some(summaries) = worktree_summaries.get_mut(&path)
8843 {
8844 summaries.remove(&server_id);
8845 if summaries.is_empty() {
8846 worktree_summaries.remove(&path);
8847 }
8848 }
8849 } else {
8850 lsp_store
8851 .diagnostic_summaries
8852 .entry(worktree_id)
8853 .or_default()
8854 .entry(path)
8855 .or_default()
8856 .insert(server_id, summary);
8857 }
8858
8859 if let Some((_, project_id)) = &lsp_store.downstream_client {
8860 match &mut diagnostics_summary {
8861 Some(diagnostics_summary) => {
8862 diagnostics_summary
8863 .more_summaries
8864 .push(proto::DiagnosticSummary {
8865 path: project_path.path.as_ref().to_proto(),
8866 language_server_id: server_id.0 as u64,
8867 error_count: summary.error_count as u32,
8868 warning_count: summary.warning_count as u32,
8869 })
8870 }
8871 None => {
8872 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8873 project_id: *project_id,
8874 worktree_id: worktree_id.to_proto(),
8875 summary: Some(proto::DiagnosticSummary {
8876 path: project_path.path.as_ref().to_proto(),
8877 language_server_id: server_id.0 as u64,
8878 error_count: summary.error_count as u32,
8879 warning_count: summary.warning_count as u32,
8880 }),
8881 more_summaries: Vec::new(),
8882 })
8883 }
8884 }
8885 }
8886 updated_diagnostics_paths
8887 .entry(server_id)
8888 .or_insert_with(Vec::new)
8889 .push(project_path);
8890 }
8891
8892 if let Some((diagnostics_summary, (downstream_client, _))) =
8893 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8894 {
8895 downstream_client.send(diagnostics_summary).log_err();
8896 }
8897 for (server_id, paths) in updated_diagnostics_paths {
8898 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8899 }
8900 Ok(())
8901 })?
8902 }
8903
8904 async fn handle_start_language_server(
8905 lsp_store: Entity<Self>,
8906 envelope: TypedEnvelope<proto::StartLanguageServer>,
8907 mut cx: AsyncApp,
8908 ) -> Result<()> {
8909 let server = envelope.payload.server.context("invalid server")?;
8910 let server_capabilities =
8911 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8912 .with_context(|| {
8913 format!(
8914 "incorrect server capabilities {}",
8915 envelope.payload.capabilities
8916 )
8917 })?;
8918 lsp_store.update(&mut cx, |lsp_store, cx| {
8919 let server_id = LanguageServerId(server.id as usize);
8920 let server_name = LanguageServerName::from_proto(server.name.clone());
8921 lsp_store
8922 .lsp_server_capabilities
8923 .insert(server_id, server_capabilities);
8924 lsp_store.language_server_statuses.insert(
8925 server_id,
8926 LanguageServerStatus {
8927 name: server_name.clone(),
8928 pending_work: Default::default(),
8929 has_pending_diagnostic_updates: false,
8930 progress_tokens: Default::default(),
8931 worktree: server.worktree_id.map(WorktreeId::from_proto),
8932 },
8933 );
8934 cx.emit(LspStoreEvent::LanguageServerAdded(
8935 server_id,
8936 server_name,
8937 server.worktree_id.map(WorktreeId::from_proto),
8938 ));
8939 cx.notify();
8940 })?;
8941 Ok(())
8942 }
8943
8944 async fn handle_update_language_server(
8945 lsp_store: Entity<Self>,
8946 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8947 mut cx: AsyncApp,
8948 ) -> Result<()> {
8949 lsp_store.update(&mut cx, |lsp_store, cx| {
8950 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8951
8952 match envelope.payload.variant.context("invalid variant")? {
8953 proto::update_language_server::Variant::WorkStart(payload) => {
8954 lsp_store.on_lsp_work_start(
8955 language_server_id,
8956 payload.token,
8957 LanguageServerProgress {
8958 title: payload.title,
8959 is_disk_based_diagnostics_progress: false,
8960 is_cancellable: payload.is_cancellable.unwrap_or(false),
8961 message: payload.message,
8962 percentage: payload.percentage.map(|p| p as usize),
8963 last_update_at: cx.background_executor().now(),
8964 },
8965 cx,
8966 );
8967 }
8968 proto::update_language_server::Variant::WorkProgress(payload) => {
8969 lsp_store.on_lsp_work_progress(
8970 language_server_id,
8971 payload.token,
8972 LanguageServerProgress {
8973 title: None,
8974 is_disk_based_diagnostics_progress: false,
8975 is_cancellable: payload.is_cancellable.unwrap_or(false),
8976 message: payload.message,
8977 percentage: payload.percentage.map(|p| p as usize),
8978 last_update_at: cx.background_executor().now(),
8979 },
8980 cx,
8981 );
8982 }
8983
8984 proto::update_language_server::Variant::WorkEnd(payload) => {
8985 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8986 }
8987
8988 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8989 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8990 }
8991
8992 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8993 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8994 }
8995
8996 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8997 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8998 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8999 cx.emit(LspStoreEvent::LanguageServerUpdate {
9000 language_server_id,
9001 name: envelope
9002 .payload
9003 .server_name
9004 .map(SharedString::new)
9005 .map(LanguageServerName),
9006 message: non_lsp,
9007 });
9008 }
9009 }
9010
9011 Ok(())
9012 })?
9013 }
9014
9015 async fn handle_language_server_log(
9016 this: Entity<Self>,
9017 envelope: TypedEnvelope<proto::LanguageServerLog>,
9018 mut cx: AsyncApp,
9019 ) -> Result<()> {
9020 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9021 let log_type = envelope
9022 .payload
9023 .log_type
9024 .map(LanguageServerLogType::from_proto)
9025 .context("invalid language server log type")?;
9026
9027 let message = envelope.payload.message;
9028
9029 this.update(&mut cx, |_, cx| {
9030 cx.emit(LspStoreEvent::LanguageServerLog(
9031 language_server_id,
9032 log_type,
9033 message,
9034 ));
9035 })
9036 }
9037
9038 async fn handle_lsp_ext_cancel_flycheck(
9039 lsp_store: Entity<Self>,
9040 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9041 cx: AsyncApp,
9042 ) -> Result<proto::Ack> {
9043 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9044 lsp_store.read_with(&cx, |lsp_store, _| {
9045 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9046 server
9047 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
9048 .context("handling lsp ext cancel flycheck")
9049 } else {
9050 anyhow::Ok(())
9051 }
9052 })??;
9053
9054 Ok(proto::Ack {})
9055 }
9056
9057 async fn handle_lsp_ext_run_flycheck(
9058 lsp_store: Entity<Self>,
9059 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9060 mut cx: AsyncApp,
9061 ) -> Result<proto::Ack> {
9062 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9063 lsp_store.update(&mut cx, |lsp_store, cx| {
9064 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9065 let text_document = if envelope.payload.current_file_only {
9066 let buffer_id = envelope
9067 .payload
9068 .buffer_id
9069 .map(|id| BufferId::new(id))
9070 .transpose()?;
9071 buffer_id
9072 .and_then(|buffer_id| {
9073 lsp_store
9074 .buffer_store()
9075 .read(cx)
9076 .get(buffer_id)
9077 .and_then(|buffer| {
9078 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9079 })
9080 .map(|path| make_text_document_identifier(&path))
9081 })
9082 .transpose()?
9083 } else {
9084 None
9085 };
9086 server
9087 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9088 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9089 )
9090 .context("handling lsp ext run flycheck")
9091 } else {
9092 anyhow::Ok(())
9093 }
9094 })??;
9095
9096 Ok(proto::Ack {})
9097 }
9098
9099 async fn handle_lsp_ext_clear_flycheck(
9100 lsp_store: Entity<Self>,
9101 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9102 cx: AsyncApp,
9103 ) -> Result<proto::Ack> {
9104 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9105 lsp_store.read_with(&cx, |lsp_store, _| {
9106 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9107 server
9108 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
9109 .context("handling lsp ext clear flycheck")
9110 } else {
9111 anyhow::Ok(())
9112 }
9113 })??;
9114
9115 Ok(proto::Ack {})
9116 }
9117
9118 pub fn disk_based_diagnostics_started(
9119 &mut self,
9120 language_server_id: LanguageServerId,
9121 cx: &mut Context<Self>,
9122 ) {
9123 if let Some(language_server_status) =
9124 self.language_server_statuses.get_mut(&language_server_id)
9125 {
9126 language_server_status.has_pending_diagnostic_updates = true;
9127 }
9128
9129 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9130 cx.emit(LspStoreEvent::LanguageServerUpdate {
9131 language_server_id,
9132 name: self
9133 .language_server_adapter_for_id(language_server_id)
9134 .map(|adapter| adapter.name()),
9135 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9136 Default::default(),
9137 ),
9138 })
9139 }
9140
9141 pub fn disk_based_diagnostics_finished(
9142 &mut self,
9143 language_server_id: LanguageServerId,
9144 cx: &mut Context<Self>,
9145 ) {
9146 if let Some(language_server_status) =
9147 self.language_server_statuses.get_mut(&language_server_id)
9148 {
9149 language_server_status.has_pending_diagnostic_updates = false;
9150 }
9151
9152 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9153 cx.emit(LspStoreEvent::LanguageServerUpdate {
9154 language_server_id,
9155 name: self
9156 .language_server_adapter_for_id(language_server_id)
9157 .map(|adapter| adapter.name()),
9158 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9159 Default::default(),
9160 ),
9161 })
9162 }
9163
9164 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9165 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9166 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9167 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9168 // the language server might take some time to publish diagnostics.
9169 fn simulate_disk_based_diagnostics_events_if_needed(
9170 &mut self,
9171 language_server_id: LanguageServerId,
9172 cx: &mut Context<Self>,
9173 ) {
9174 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9175
9176 let Some(LanguageServerState::Running {
9177 simulate_disk_based_diagnostics_completion,
9178 adapter,
9179 ..
9180 }) = self
9181 .as_local_mut()
9182 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9183 else {
9184 return;
9185 };
9186
9187 if adapter.disk_based_diagnostics_progress_token.is_some() {
9188 return;
9189 }
9190
9191 let prev_task =
9192 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9193 cx.background_executor()
9194 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9195 .await;
9196
9197 this.update(cx, |this, cx| {
9198 this.disk_based_diagnostics_finished(language_server_id, cx);
9199
9200 if let Some(LanguageServerState::Running {
9201 simulate_disk_based_diagnostics_completion,
9202 ..
9203 }) = this.as_local_mut().and_then(|local_store| {
9204 local_store.language_servers.get_mut(&language_server_id)
9205 }) {
9206 *simulate_disk_based_diagnostics_completion = None;
9207 }
9208 })
9209 .ok();
9210 }));
9211
9212 if prev_task.is_none() {
9213 self.disk_based_diagnostics_started(language_server_id, cx);
9214 }
9215 }
9216
9217 pub fn language_server_statuses(
9218 &self,
9219 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9220 self.language_server_statuses
9221 .iter()
9222 .map(|(key, value)| (*key, value))
9223 }
9224
9225 pub(super) fn did_rename_entry(
9226 &self,
9227 worktree_id: WorktreeId,
9228 old_path: &Path,
9229 new_path: &Path,
9230 is_dir: bool,
9231 ) {
9232 maybe!({
9233 let local_store = self.as_local()?;
9234
9235 let old_uri = lsp::Uri::from_file_path(old_path)
9236 .ok()
9237 .map(|uri| uri.to_string())?;
9238 let new_uri = lsp::Uri::from_file_path(new_path)
9239 .ok()
9240 .map(|uri| uri.to_string())?;
9241
9242 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9243 let Some(filter) = local_store
9244 .language_server_paths_watched_for_rename
9245 .get(&language_server.server_id())
9246 else {
9247 continue;
9248 };
9249
9250 if filter.should_send_did_rename(&old_uri, is_dir) {
9251 language_server
9252 .notify::<DidRenameFiles>(&RenameFilesParams {
9253 files: vec![FileRename {
9254 old_uri: old_uri.clone(),
9255 new_uri: new_uri.clone(),
9256 }],
9257 })
9258 .ok();
9259 }
9260 }
9261 Some(())
9262 });
9263 }
9264
9265 pub(super) fn will_rename_entry(
9266 this: WeakEntity<Self>,
9267 worktree_id: WorktreeId,
9268 old_path: &Path,
9269 new_path: &Path,
9270 is_dir: bool,
9271 cx: AsyncApp,
9272 ) -> Task<ProjectTransaction> {
9273 let old_uri = lsp::Uri::from_file_path(old_path)
9274 .ok()
9275 .map(|uri| uri.to_string());
9276 let new_uri = lsp::Uri::from_file_path(new_path)
9277 .ok()
9278 .map(|uri| uri.to_string());
9279 cx.spawn(async move |cx| {
9280 let mut tasks = vec![];
9281 this.update(cx, |this, cx| {
9282 let local_store = this.as_local()?;
9283 let old_uri = old_uri?;
9284 let new_uri = new_uri?;
9285 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9286 let Some(filter) = local_store
9287 .language_server_paths_watched_for_rename
9288 .get(&language_server.server_id())
9289 else {
9290 continue;
9291 };
9292
9293 if filter.should_send_will_rename(&old_uri, is_dir) {
9294 let apply_edit = cx.spawn({
9295 let old_uri = old_uri.clone();
9296 let new_uri = new_uri.clone();
9297 let language_server = language_server.clone();
9298 async move |this, cx| {
9299 let edit = language_server
9300 .request::<WillRenameFiles>(RenameFilesParams {
9301 files: vec![FileRename { old_uri, new_uri }],
9302 })
9303 .await
9304 .into_response()
9305 .context("will rename files")
9306 .log_err()
9307 .flatten()?;
9308
9309 let transaction = LocalLspStore::deserialize_workspace_edit(
9310 this.upgrade()?,
9311 edit,
9312 false,
9313 language_server.clone(),
9314 cx,
9315 )
9316 .await
9317 .ok()?;
9318 Some(transaction)
9319 }
9320 });
9321 tasks.push(apply_edit);
9322 }
9323 }
9324 Some(())
9325 })
9326 .ok()
9327 .flatten();
9328 let mut merged_transaction = ProjectTransaction::default();
9329 for task in tasks {
9330 // Await on tasks sequentially so that the order of application of edits is deterministic
9331 // (at least with regards to the order of registration of language servers)
9332 if let Some(transaction) = task.await {
9333 for (buffer, buffer_transaction) in transaction.0 {
9334 merged_transaction.0.insert(buffer, buffer_transaction);
9335 }
9336 }
9337 }
9338 merged_transaction
9339 })
9340 }
9341
9342 fn lsp_notify_abs_paths_changed(
9343 &mut self,
9344 server_id: LanguageServerId,
9345 changes: Vec<PathEvent>,
9346 ) {
9347 maybe!({
9348 let server = self.language_server_for_id(server_id)?;
9349 let changes = changes
9350 .into_iter()
9351 .filter_map(|event| {
9352 let typ = match event.kind? {
9353 PathEventKind::Created => lsp::FileChangeType::CREATED,
9354 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9355 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9356 };
9357 Some(lsp::FileEvent {
9358 uri: file_path_to_lsp_url(&event.path).log_err()?,
9359 typ,
9360 })
9361 })
9362 .collect::<Vec<_>>();
9363 if !changes.is_empty() {
9364 server
9365 .notify::<lsp::notification::DidChangeWatchedFiles>(
9366 &lsp::DidChangeWatchedFilesParams { changes },
9367 )
9368 .ok();
9369 }
9370 Some(())
9371 });
9372 }
9373
9374 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9375 self.as_local()?.language_server_for_id(id)
9376 }
9377
9378 fn on_lsp_progress(
9379 &mut self,
9380 progress: lsp::ProgressParams,
9381 language_server_id: LanguageServerId,
9382 disk_based_diagnostics_progress_token: Option<String>,
9383 cx: &mut Context<Self>,
9384 ) {
9385 let token = match progress.token {
9386 lsp::NumberOrString::String(token) => token,
9387 lsp::NumberOrString::Number(token) => {
9388 log::info!("skipping numeric progress token {}", token);
9389 return;
9390 }
9391 };
9392
9393 match progress.value {
9394 lsp::ProgressParamsValue::WorkDone(progress) => {
9395 self.handle_work_done_progress(
9396 progress,
9397 language_server_id,
9398 disk_based_diagnostics_progress_token,
9399 token,
9400 cx,
9401 );
9402 }
9403 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9404 if let Some(LanguageServerState::Running {
9405 workspace_refresh_task: Some(workspace_refresh_task),
9406 ..
9407 }) = self
9408 .as_local_mut()
9409 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9410 {
9411 workspace_refresh_task.progress_tx.try_send(()).ok();
9412 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9413 }
9414 }
9415 }
9416 }
9417
9418 fn handle_work_done_progress(
9419 &mut self,
9420 progress: lsp::WorkDoneProgress,
9421 language_server_id: LanguageServerId,
9422 disk_based_diagnostics_progress_token: Option<String>,
9423 token: String,
9424 cx: &mut Context<Self>,
9425 ) {
9426 let language_server_status =
9427 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9428 status
9429 } else {
9430 return;
9431 };
9432
9433 if !language_server_status.progress_tokens.contains(&token) {
9434 return;
9435 }
9436
9437 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9438 .as_ref()
9439 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9440
9441 match progress {
9442 lsp::WorkDoneProgress::Begin(report) => {
9443 if is_disk_based_diagnostics_progress {
9444 self.disk_based_diagnostics_started(language_server_id, cx);
9445 }
9446 self.on_lsp_work_start(
9447 language_server_id,
9448 token.clone(),
9449 LanguageServerProgress {
9450 title: Some(report.title),
9451 is_disk_based_diagnostics_progress,
9452 is_cancellable: report.cancellable.unwrap_or(false),
9453 message: report.message.clone(),
9454 percentage: report.percentage.map(|p| p as usize),
9455 last_update_at: cx.background_executor().now(),
9456 },
9457 cx,
9458 );
9459 }
9460 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9461 language_server_id,
9462 token,
9463 LanguageServerProgress {
9464 title: None,
9465 is_disk_based_diagnostics_progress,
9466 is_cancellable: report.cancellable.unwrap_or(false),
9467 message: report.message,
9468 percentage: report.percentage.map(|p| p as usize),
9469 last_update_at: cx.background_executor().now(),
9470 },
9471 cx,
9472 ),
9473 lsp::WorkDoneProgress::End(_) => {
9474 language_server_status.progress_tokens.remove(&token);
9475 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9476 if is_disk_based_diagnostics_progress {
9477 self.disk_based_diagnostics_finished(language_server_id, cx);
9478 }
9479 }
9480 }
9481 }
9482
9483 fn on_lsp_work_start(
9484 &mut self,
9485 language_server_id: LanguageServerId,
9486 token: String,
9487 progress: LanguageServerProgress,
9488 cx: &mut Context<Self>,
9489 ) {
9490 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9491 status.pending_work.insert(token.clone(), progress.clone());
9492 cx.notify();
9493 }
9494 cx.emit(LspStoreEvent::LanguageServerUpdate {
9495 language_server_id,
9496 name: self
9497 .language_server_adapter_for_id(language_server_id)
9498 .map(|adapter| adapter.name()),
9499 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9500 token,
9501 title: progress.title,
9502 message: progress.message,
9503 percentage: progress.percentage.map(|p| p as u32),
9504 is_cancellable: Some(progress.is_cancellable),
9505 }),
9506 })
9507 }
9508
9509 fn on_lsp_work_progress(
9510 &mut self,
9511 language_server_id: LanguageServerId,
9512 token: String,
9513 progress: LanguageServerProgress,
9514 cx: &mut Context<Self>,
9515 ) {
9516 let mut did_update = false;
9517 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9518 match status.pending_work.entry(token.clone()) {
9519 btree_map::Entry::Vacant(entry) => {
9520 entry.insert(progress.clone());
9521 did_update = true;
9522 }
9523 btree_map::Entry::Occupied(mut entry) => {
9524 let entry = entry.get_mut();
9525 if (progress.last_update_at - entry.last_update_at)
9526 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9527 {
9528 entry.last_update_at = progress.last_update_at;
9529 if progress.message.is_some() {
9530 entry.message = progress.message.clone();
9531 }
9532 if progress.percentage.is_some() {
9533 entry.percentage = progress.percentage;
9534 }
9535 if progress.is_cancellable != entry.is_cancellable {
9536 entry.is_cancellable = progress.is_cancellable;
9537 }
9538 did_update = true;
9539 }
9540 }
9541 }
9542 }
9543
9544 if did_update {
9545 cx.emit(LspStoreEvent::LanguageServerUpdate {
9546 language_server_id,
9547 name: self
9548 .language_server_adapter_for_id(language_server_id)
9549 .map(|adapter| adapter.name()),
9550 message: proto::update_language_server::Variant::WorkProgress(
9551 proto::LspWorkProgress {
9552 token,
9553 message: progress.message,
9554 percentage: progress.percentage.map(|p| p as u32),
9555 is_cancellable: Some(progress.is_cancellable),
9556 },
9557 ),
9558 })
9559 }
9560 }
9561
9562 fn on_lsp_work_end(
9563 &mut self,
9564 language_server_id: LanguageServerId,
9565 token: String,
9566 cx: &mut Context<Self>,
9567 ) {
9568 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9569 if let Some(work) = status.pending_work.remove(&token)
9570 && !work.is_disk_based_diagnostics_progress
9571 {
9572 cx.emit(LspStoreEvent::RefreshInlayHints);
9573 }
9574 cx.notify();
9575 }
9576
9577 cx.emit(LspStoreEvent::LanguageServerUpdate {
9578 language_server_id,
9579 name: self
9580 .language_server_adapter_for_id(language_server_id)
9581 .map(|adapter| adapter.name()),
9582 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9583 })
9584 }
9585
9586 pub async fn handle_resolve_completion_documentation(
9587 this: Entity<Self>,
9588 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9589 mut cx: AsyncApp,
9590 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9591 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9592
9593 let completion = this
9594 .read_with(&cx, |this, cx| {
9595 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9596 let server = this
9597 .language_server_for_id(id)
9598 .with_context(|| format!("No language server {id}"))?;
9599
9600 anyhow::Ok(cx.background_spawn(async move {
9601 let can_resolve = server
9602 .capabilities()
9603 .completion_provider
9604 .as_ref()
9605 .and_then(|options| options.resolve_provider)
9606 .unwrap_or(false);
9607 if can_resolve {
9608 server
9609 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9610 .await
9611 .into_response()
9612 .context("resolve completion item")
9613 } else {
9614 anyhow::Ok(lsp_completion)
9615 }
9616 }))
9617 })??
9618 .await?;
9619
9620 let mut documentation_is_markdown = false;
9621 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9622 let documentation = match completion.documentation {
9623 Some(lsp::Documentation::String(text)) => text,
9624
9625 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9626 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9627 value
9628 }
9629
9630 _ => String::new(),
9631 };
9632
9633 // If we have a new buffer_id, that means we're talking to a new client
9634 // and want to check for new text_edits in the completion too.
9635 let mut old_replace_start = None;
9636 let mut old_replace_end = None;
9637 let mut old_insert_start = None;
9638 let mut old_insert_end = None;
9639 let mut new_text = String::default();
9640 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9641 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9642 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9643 anyhow::Ok(buffer.read(cx).snapshot())
9644 })??;
9645
9646 if let Some(text_edit) = completion.text_edit.as_ref() {
9647 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9648
9649 if let Some(mut edit) = edit {
9650 LineEnding::normalize(&mut edit.new_text);
9651
9652 new_text = edit.new_text;
9653 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9654 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9655 if let Some(insert_range) = edit.insert_range {
9656 old_insert_start = Some(serialize_anchor(&insert_range.start));
9657 old_insert_end = Some(serialize_anchor(&insert_range.end));
9658 }
9659 }
9660 }
9661 }
9662
9663 Ok(proto::ResolveCompletionDocumentationResponse {
9664 documentation,
9665 documentation_is_markdown,
9666 old_replace_start,
9667 old_replace_end,
9668 new_text,
9669 lsp_completion,
9670 old_insert_start,
9671 old_insert_end,
9672 })
9673 }
9674
9675 async fn handle_on_type_formatting(
9676 this: Entity<Self>,
9677 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9678 mut cx: AsyncApp,
9679 ) -> Result<proto::OnTypeFormattingResponse> {
9680 let on_type_formatting = this.update(&mut cx, |this, cx| {
9681 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9682 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9683 let position = envelope
9684 .payload
9685 .position
9686 .and_then(deserialize_anchor)
9687 .context("invalid position")?;
9688 anyhow::Ok(this.apply_on_type_formatting(
9689 buffer,
9690 position,
9691 envelope.payload.trigger.clone(),
9692 cx,
9693 ))
9694 })??;
9695
9696 let transaction = on_type_formatting
9697 .await?
9698 .as_ref()
9699 .map(language::proto::serialize_transaction);
9700 Ok(proto::OnTypeFormattingResponse { transaction })
9701 }
9702
9703 async fn handle_refresh_inlay_hints(
9704 this: Entity<Self>,
9705 _: TypedEnvelope<proto::RefreshInlayHints>,
9706 mut cx: AsyncApp,
9707 ) -> Result<proto::Ack> {
9708 this.update(&mut cx, |_, cx| {
9709 cx.emit(LspStoreEvent::RefreshInlayHints);
9710 })?;
9711 Ok(proto::Ack {})
9712 }
9713
9714 async fn handle_pull_workspace_diagnostics(
9715 lsp_store: Entity<Self>,
9716 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9717 mut cx: AsyncApp,
9718 ) -> Result<proto::Ack> {
9719 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9720 lsp_store.update(&mut cx, |lsp_store, _| {
9721 lsp_store.pull_workspace_diagnostics(server_id);
9722 })?;
9723 Ok(proto::Ack {})
9724 }
9725
9726 async fn handle_inlay_hints(
9727 this: Entity<Self>,
9728 envelope: TypedEnvelope<proto::InlayHints>,
9729 mut cx: AsyncApp,
9730 ) -> Result<proto::InlayHintsResponse> {
9731 let sender_id = envelope.original_sender_id().unwrap_or_default();
9732 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9733 let buffer = this.update(&mut cx, |this, cx| {
9734 this.buffer_store.read(cx).get_existing(buffer_id)
9735 })??;
9736 buffer
9737 .update(&mut cx, |buffer, _| {
9738 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9739 })?
9740 .await
9741 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9742
9743 let start = envelope
9744 .payload
9745 .start
9746 .and_then(deserialize_anchor)
9747 .context("missing range start")?;
9748 let end = envelope
9749 .payload
9750 .end
9751 .and_then(deserialize_anchor)
9752 .context("missing range end")?;
9753 let buffer_hints = this
9754 .update(&mut cx, |lsp_store, cx| {
9755 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9756 })?
9757 .await
9758 .context("inlay hints fetch")?;
9759
9760 this.update(&mut cx, |project, cx| {
9761 InlayHints::response_to_proto(
9762 buffer_hints,
9763 project,
9764 sender_id,
9765 &buffer.read(cx).version(),
9766 cx,
9767 )
9768 })
9769 }
9770
9771 async fn handle_get_color_presentation(
9772 lsp_store: Entity<Self>,
9773 envelope: TypedEnvelope<proto::GetColorPresentation>,
9774 mut cx: AsyncApp,
9775 ) -> Result<proto::GetColorPresentationResponse> {
9776 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9777 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9778 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9779 })??;
9780
9781 let color = envelope
9782 .payload
9783 .color
9784 .context("invalid color resolve request")?;
9785 let start = color
9786 .lsp_range_start
9787 .context("invalid color resolve request")?;
9788 let end = color
9789 .lsp_range_end
9790 .context("invalid color resolve request")?;
9791
9792 let color = DocumentColor {
9793 lsp_range: lsp::Range {
9794 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9795 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9796 },
9797 color: lsp::Color {
9798 red: color.red,
9799 green: color.green,
9800 blue: color.blue,
9801 alpha: color.alpha,
9802 },
9803 resolved: false,
9804 color_presentations: Vec::new(),
9805 };
9806 let resolved_color = lsp_store
9807 .update(&mut cx, |lsp_store, cx| {
9808 lsp_store.resolve_color_presentation(
9809 color,
9810 buffer.clone(),
9811 LanguageServerId(envelope.payload.server_id as usize),
9812 cx,
9813 )
9814 })?
9815 .await
9816 .context("resolving color presentation")?;
9817
9818 Ok(proto::GetColorPresentationResponse {
9819 presentations: resolved_color
9820 .color_presentations
9821 .into_iter()
9822 .map(|presentation| proto::ColorPresentation {
9823 label: presentation.label.to_string(),
9824 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9825 additional_text_edits: presentation
9826 .additional_text_edits
9827 .into_iter()
9828 .map(serialize_lsp_edit)
9829 .collect(),
9830 })
9831 .collect(),
9832 })
9833 }
9834
9835 async fn handle_resolve_inlay_hint(
9836 this: Entity<Self>,
9837 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9838 mut cx: AsyncApp,
9839 ) -> Result<proto::ResolveInlayHintResponse> {
9840 let proto_hint = envelope
9841 .payload
9842 .hint
9843 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9844 let hint = InlayHints::proto_to_project_hint(proto_hint)
9845 .context("resolved proto inlay hint conversion")?;
9846 let buffer = this.update(&mut cx, |this, cx| {
9847 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9848 this.buffer_store.read(cx).get_existing(buffer_id)
9849 })??;
9850 let response_hint = this
9851 .update(&mut cx, |this, cx| {
9852 this.resolve_inlay_hint(
9853 hint,
9854 buffer,
9855 LanguageServerId(envelope.payload.language_server_id as usize),
9856 cx,
9857 )
9858 })?
9859 .await
9860 .context("inlay hints fetch")?;
9861 Ok(proto::ResolveInlayHintResponse {
9862 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9863 })
9864 }
9865
9866 async fn handle_refresh_code_lens(
9867 this: Entity<Self>,
9868 _: TypedEnvelope<proto::RefreshCodeLens>,
9869 mut cx: AsyncApp,
9870 ) -> Result<proto::Ack> {
9871 this.update(&mut cx, |_, cx| {
9872 cx.emit(LspStoreEvent::RefreshCodeLens);
9873 })?;
9874 Ok(proto::Ack {})
9875 }
9876
9877 async fn handle_open_buffer_for_symbol(
9878 this: Entity<Self>,
9879 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9880 mut cx: AsyncApp,
9881 ) -> Result<proto::OpenBufferForSymbolResponse> {
9882 let peer_id = envelope.original_sender_id().unwrap_or_default();
9883 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9884 let symbol = Self::deserialize_symbol(symbol)?;
9885 let symbol = this.read_with(&cx, |this, _| {
9886 let signature = this.symbol_signature(&symbol.path);
9887 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9888 Ok(symbol)
9889 })??;
9890 let buffer = this
9891 .update(&mut cx, |this, cx| {
9892 this.open_buffer_for_symbol(
9893 &Symbol {
9894 language_server_name: symbol.language_server_name,
9895 source_worktree_id: symbol.source_worktree_id,
9896 source_language_server_id: symbol.source_language_server_id,
9897 path: symbol.path,
9898 name: symbol.name,
9899 kind: symbol.kind,
9900 range: symbol.range,
9901 signature: symbol.signature,
9902 label: CodeLabel {
9903 text: Default::default(),
9904 runs: Default::default(),
9905 filter_range: Default::default(),
9906 },
9907 },
9908 cx,
9909 )
9910 })?
9911 .await?;
9912
9913 this.update(&mut cx, |this, cx| {
9914 let is_private = buffer
9915 .read(cx)
9916 .file()
9917 .map(|f| f.is_private())
9918 .unwrap_or_default();
9919 if is_private {
9920 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9921 } else {
9922 this.buffer_store
9923 .update(cx, |buffer_store, cx| {
9924 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9925 })
9926 .detach_and_log_err(cx);
9927 let buffer_id = buffer.read(cx).remote_id().to_proto();
9928 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9929 }
9930 })?
9931 }
9932
9933 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
9934 let mut hasher = Sha256::new();
9935 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
9936 hasher.update(project_path.path.to_string_lossy().as_bytes());
9937 hasher.update(self.nonce.to_be_bytes());
9938 hasher.finalize().as_slice().try_into().unwrap()
9939 }
9940
9941 pub async fn handle_get_project_symbols(
9942 this: Entity<Self>,
9943 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9944 mut cx: AsyncApp,
9945 ) -> Result<proto::GetProjectSymbolsResponse> {
9946 let symbols = this
9947 .update(&mut cx, |this, cx| {
9948 this.symbols(&envelope.payload.query, cx)
9949 })?
9950 .await?;
9951
9952 Ok(proto::GetProjectSymbolsResponse {
9953 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9954 })
9955 }
9956
9957 pub async fn handle_restart_language_servers(
9958 this: Entity<Self>,
9959 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9960 mut cx: AsyncApp,
9961 ) -> Result<proto::Ack> {
9962 this.update(&mut cx, |lsp_store, cx| {
9963 let buffers =
9964 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9965 lsp_store.restart_language_servers_for_buffers(
9966 buffers,
9967 envelope
9968 .payload
9969 .only_servers
9970 .into_iter()
9971 .filter_map(|selector| {
9972 Some(match selector.selector? {
9973 proto::language_server_selector::Selector::ServerId(server_id) => {
9974 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9975 }
9976 proto::language_server_selector::Selector::Name(name) => {
9977 LanguageServerSelector::Name(LanguageServerName(
9978 SharedString::from(name),
9979 ))
9980 }
9981 })
9982 })
9983 .collect(),
9984 cx,
9985 );
9986 })?;
9987
9988 Ok(proto::Ack {})
9989 }
9990
9991 pub async fn handle_stop_language_servers(
9992 lsp_store: Entity<Self>,
9993 envelope: TypedEnvelope<proto::StopLanguageServers>,
9994 mut cx: AsyncApp,
9995 ) -> Result<proto::Ack> {
9996 lsp_store.update(&mut cx, |lsp_store, cx| {
9997 if envelope.payload.all
9998 && envelope.payload.also_servers.is_empty()
9999 && envelope.payload.buffer_ids.is_empty()
10000 {
10001 lsp_store.stop_all_language_servers(cx);
10002 } else {
10003 let buffers =
10004 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10005 lsp_store
10006 .stop_language_servers_for_buffers(
10007 buffers,
10008 envelope
10009 .payload
10010 .also_servers
10011 .into_iter()
10012 .filter_map(|selector| {
10013 Some(match selector.selector? {
10014 proto::language_server_selector::Selector::ServerId(
10015 server_id,
10016 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10017 server_id,
10018 )),
10019 proto::language_server_selector::Selector::Name(name) => {
10020 LanguageServerSelector::Name(LanguageServerName(
10021 SharedString::from(name),
10022 ))
10023 }
10024 })
10025 })
10026 .collect(),
10027 cx,
10028 )
10029 .detach_and_log_err(cx);
10030 }
10031 })?;
10032
10033 Ok(proto::Ack {})
10034 }
10035
10036 pub async fn handle_cancel_language_server_work(
10037 this: Entity<Self>,
10038 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10039 mut cx: AsyncApp,
10040 ) -> Result<proto::Ack> {
10041 this.update(&mut cx, |this, cx| {
10042 if let Some(work) = envelope.payload.work {
10043 match work {
10044 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10045 let buffers =
10046 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10047 this.cancel_language_server_work_for_buffers(buffers, cx);
10048 }
10049 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10050 let server_id = LanguageServerId::from_proto(work.language_server_id);
10051 this.cancel_language_server_work(server_id, work.token, cx);
10052 }
10053 }
10054 }
10055 })?;
10056
10057 Ok(proto::Ack {})
10058 }
10059
10060 fn buffer_ids_to_buffers(
10061 &mut self,
10062 buffer_ids: impl Iterator<Item = u64>,
10063 cx: &mut Context<Self>,
10064 ) -> Vec<Entity<Buffer>> {
10065 buffer_ids
10066 .into_iter()
10067 .flat_map(|buffer_id| {
10068 self.buffer_store
10069 .read(cx)
10070 .get(BufferId::new(buffer_id).log_err()?)
10071 })
10072 .collect::<Vec<_>>()
10073 }
10074
10075 async fn handle_apply_additional_edits_for_completion(
10076 this: Entity<Self>,
10077 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10078 mut cx: AsyncApp,
10079 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10080 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10081 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10082 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10083 let completion = Self::deserialize_completion(
10084 envelope.payload.completion.context("invalid completion")?,
10085 )?;
10086 anyhow::Ok((buffer, completion))
10087 })??;
10088
10089 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10090 this.apply_additional_edits_for_completion(
10091 buffer,
10092 Rc::new(RefCell::new(Box::new([Completion {
10093 replace_range: completion.replace_range,
10094 new_text: completion.new_text,
10095 source: completion.source,
10096 documentation: None,
10097 label: CodeLabel {
10098 text: Default::default(),
10099 runs: Default::default(),
10100 filter_range: Default::default(),
10101 },
10102 insert_text_mode: None,
10103 icon_path: None,
10104 confirm: None,
10105 }]))),
10106 0,
10107 false,
10108 cx,
10109 )
10110 })?;
10111
10112 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10113 transaction: apply_additional_edits
10114 .await?
10115 .as_ref()
10116 .map(language::proto::serialize_transaction),
10117 })
10118 }
10119
10120 pub fn last_formatting_failure(&self) -> Option<&str> {
10121 self.last_formatting_failure.as_deref()
10122 }
10123
10124 pub fn reset_last_formatting_failure(&mut self) {
10125 self.last_formatting_failure = None;
10126 }
10127
10128 pub fn environment_for_buffer(
10129 &self,
10130 buffer: &Entity<Buffer>,
10131 cx: &mut Context<Self>,
10132 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10133 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10134 environment.update(cx, |env, cx| {
10135 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10136 })
10137 } else {
10138 Task::ready(None).shared()
10139 }
10140 }
10141
10142 pub fn format(
10143 &mut self,
10144 buffers: HashSet<Entity<Buffer>>,
10145 target: LspFormatTarget,
10146 push_to_history: bool,
10147 trigger: FormatTrigger,
10148 cx: &mut Context<Self>,
10149 ) -> Task<anyhow::Result<ProjectTransaction>> {
10150 let logger = zlog::scoped!("format");
10151 if self.as_local().is_some() {
10152 zlog::trace!(logger => "Formatting locally");
10153 let logger = zlog::scoped!(logger => "local");
10154 let buffers = buffers
10155 .into_iter()
10156 .map(|buffer_handle| {
10157 let buffer = buffer_handle.read(cx);
10158 let buffer_abs_path = File::from_dyn(buffer.file())
10159 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10160
10161 (buffer_handle, buffer_abs_path, buffer.remote_id())
10162 })
10163 .collect::<Vec<_>>();
10164
10165 cx.spawn(async move |lsp_store, cx| {
10166 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10167
10168 for (handle, abs_path, id) in buffers {
10169 let env = lsp_store
10170 .update(cx, |lsp_store, cx| {
10171 lsp_store.environment_for_buffer(&handle, cx)
10172 })?
10173 .await;
10174
10175 let ranges = match &target {
10176 LspFormatTarget::Buffers => None,
10177 LspFormatTarget::Ranges(ranges) => {
10178 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10179 }
10180 };
10181
10182 formattable_buffers.push(FormattableBuffer {
10183 handle,
10184 abs_path,
10185 env,
10186 ranges,
10187 });
10188 }
10189 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10190
10191 let format_timer = zlog::time!(logger => "Formatting buffers");
10192 let result = LocalLspStore::format_locally(
10193 lsp_store.clone(),
10194 formattable_buffers,
10195 push_to_history,
10196 trigger,
10197 logger,
10198 cx,
10199 )
10200 .await;
10201 format_timer.end();
10202
10203 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10204
10205 lsp_store.update(cx, |lsp_store, _| {
10206 lsp_store.update_last_formatting_failure(&result);
10207 })?;
10208
10209 result
10210 })
10211 } else if let Some((client, project_id)) = self.upstream_client() {
10212 zlog::trace!(logger => "Formatting remotely");
10213 let logger = zlog::scoped!(logger => "remote");
10214 // Don't support formatting ranges via remote
10215 match target {
10216 LspFormatTarget::Buffers => {}
10217 LspFormatTarget::Ranges(_) => {
10218 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10219 return Task::ready(Ok(ProjectTransaction::default()));
10220 }
10221 }
10222
10223 let buffer_store = self.buffer_store();
10224 cx.spawn(async move |lsp_store, cx| {
10225 zlog::trace!(logger => "Sending remote format request");
10226 let request_timer = zlog::time!(logger => "remote format request");
10227 let result = client
10228 .request(proto::FormatBuffers {
10229 project_id,
10230 trigger: trigger as i32,
10231 buffer_ids: buffers
10232 .iter()
10233 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10234 .collect::<Result<_>>()?,
10235 })
10236 .await
10237 .and_then(|result| result.transaction.context("missing transaction"));
10238 request_timer.end();
10239
10240 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10241
10242 lsp_store.update(cx, |lsp_store, _| {
10243 lsp_store.update_last_formatting_failure(&result);
10244 })?;
10245
10246 let transaction_response = result?;
10247 let _timer = zlog::time!(logger => "deserializing project transaction");
10248 buffer_store
10249 .update(cx, |buffer_store, cx| {
10250 buffer_store.deserialize_project_transaction(
10251 transaction_response,
10252 push_to_history,
10253 cx,
10254 )
10255 })?
10256 .await
10257 })
10258 } else {
10259 zlog::trace!(logger => "Not formatting");
10260 Task::ready(Ok(ProjectTransaction::default()))
10261 }
10262 }
10263
10264 async fn handle_format_buffers(
10265 this: Entity<Self>,
10266 envelope: TypedEnvelope<proto::FormatBuffers>,
10267 mut cx: AsyncApp,
10268 ) -> Result<proto::FormatBuffersResponse> {
10269 let sender_id = envelope.original_sender_id().unwrap_or_default();
10270 let format = this.update(&mut cx, |this, cx| {
10271 let mut buffers = HashSet::default();
10272 for buffer_id in &envelope.payload.buffer_ids {
10273 let buffer_id = BufferId::new(*buffer_id)?;
10274 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10275 }
10276 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10277 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10278 })??;
10279
10280 let project_transaction = format.await?;
10281 let project_transaction = this.update(&mut cx, |this, cx| {
10282 this.buffer_store.update(cx, |buffer_store, cx| {
10283 buffer_store.serialize_project_transaction_for_peer(
10284 project_transaction,
10285 sender_id,
10286 cx,
10287 )
10288 })
10289 })?;
10290 Ok(proto::FormatBuffersResponse {
10291 transaction: Some(project_transaction),
10292 })
10293 }
10294
10295 async fn handle_apply_code_action_kind(
10296 this: Entity<Self>,
10297 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10298 mut cx: AsyncApp,
10299 ) -> Result<proto::ApplyCodeActionKindResponse> {
10300 let sender_id = envelope.original_sender_id().unwrap_or_default();
10301 let format = this.update(&mut cx, |this, cx| {
10302 let mut buffers = HashSet::default();
10303 for buffer_id in &envelope.payload.buffer_ids {
10304 let buffer_id = BufferId::new(*buffer_id)?;
10305 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10306 }
10307 let kind = match envelope.payload.kind.as_str() {
10308 "" => CodeActionKind::EMPTY,
10309 "quickfix" => CodeActionKind::QUICKFIX,
10310 "refactor" => CodeActionKind::REFACTOR,
10311 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10312 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10313 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10314 "source" => CodeActionKind::SOURCE,
10315 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10316 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10317 _ => anyhow::bail!(
10318 "Invalid code action kind {}",
10319 envelope.payload.kind.as_str()
10320 ),
10321 };
10322 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10323 })??;
10324
10325 let project_transaction = format.await?;
10326 let project_transaction = this.update(&mut cx, |this, cx| {
10327 this.buffer_store.update(cx, |buffer_store, cx| {
10328 buffer_store.serialize_project_transaction_for_peer(
10329 project_transaction,
10330 sender_id,
10331 cx,
10332 )
10333 })
10334 })?;
10335 Ok(proto::ApplyCodeActionKindResponse {
10336 transaction: Some(project_transaction),
10337 })
10338 }
10339
10340 async fn shutdown_language_server(
10341 server_state: Option<LanguageServerState>,
10342 name: LanguageServerName,
10343 cx: &mut AsyncApp,
10344 ) {
10345 let server = match server_state {
10346 Some(LanguageServerState::Starting { startup, .. }) => {
10347 let mut timer = cx
10348 .background_executor()
10349 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10350 .fuse();
10351
10352 select! {
10353 server = startup.fuse() => server,
10354 () = timer => {
10355 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10356 None
10357 },
10358 }
10359 }
10360
10361 Some(LanguageServerState::Running { server, .. }) => Some(server),
10362
10363 None => None,
10364 };
10365
10366 if let Some(server) = server
10367 && let Some(shutdown) = server.shutdown()
10368 {
10369 shutdown.await;
10370 }
10371 }
10372
10373 // Returns a list of all of the worktrees which no longer have a language server and the root path
10374 // for the stopped server
10375 fn stop_local_language_server(
10376 &mut self,
10377 server_id: LanguageServerId,
10378 cx: &mut Context<Self>,
10379 ) -> Task<()> {
10380 let local = match &mut self.mode {
10381 LspStoreMode::Local(local) => local,
10382 _ => {
10383 return Task::ready(());
10384 }
10385 };
10386
10387 // Remove this server ID from all entries in the given worktree.
10388 local
10389 .language_server_ids
10390 .retain(|_, state| state.id != server_id);
10391 self.buffer_store.update(cx, |buffer_store, cx| {
10392 for buffer in buffer_store.buffers() {
10393 buffer.update(cx, |buffer, cx| {
10394 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10395 buffer.set_completion_triggers(server_id, Default::default(), cx);
10396 });
10397 }
10398 });
10399
10400 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10401 summaries.retain(|path, summaries_by_server_id| {
10402 if summaries_by_server_id.remove(&server_id).is_some() {
10403 if let Some((client, project_id)) = self.downstream_client.clone() {
10404 client
10405 .send(proto::UpdateDiagnosticSummary {
10406 project_id,
10407 worktree_id: worktree_id.to_proto(),
10408 summary: Some(proto::DiagnosticSummary {
10409 path: path.as_ref().to_proto(),
10410 language_server_id: server_id.0 as u64,
10411 error_count: 0,
10412 warning_count: 0,
10413 }),
10414 more_summaries: Vec::new(),
10415 })
10416 .log_err();
10417 }
10418 !summaries_by_server_id.is_empty()
10419 } else {
10420 true
10421 }
10422 });
10423 }
10424
10425 let local = self.as_local_mut().unwrap();
10426 for diagnostics in local.diagnostics.values_mut() {
10427 diagnostics.retain(|_, diagnostics_by_server_id| {
10428 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10429 diagnostics_by_server_id.remove(ix);
10430 !diagnostics_by_server_id.is_empty()
10431 } else {
10432 true
10433 }
10434 });
10435 }
10436 local.language_server_watched_paths.remove(&server_id);
10437
10438 let server_state = local.language_servers.remove(&server_id);
10439 self.cleanup_lsp_data(server_id);
10440 let name = self
10441 .language_server_statuses
10442 .remove(&server_id)
10443 .map(|status| status.name)
10444 .or_else(|| {
10445 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10446 Some(adapter.name())
10447 } else {
10448 None
10449 }
10450 });
10451
10452 if let Some(name) = name {
10453 log::info!("stopping language server {name}");
10454 self.languages
10455 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10456 cx.notify();
10457
10458 return cx.spawn(async move |lsp_store, cx| {
10459 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10460 lsp_store
10461 .update(cx, |lsp_store, cx| {
10462 lsp_store
10463 .languages
10464 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10465 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10466 cx.notify();
10467 })
10468 .ok();
10469 });
10470 }
10471
10472 if server_state.is_some() {
10473 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10474 }
10475 Task::ready(())
10476 }
10477
10478 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10479 if let Some((client, project_id)) = self.upstream_client() {
10480 let request = client.request(proto::StopLanguageServers {
10481 project_id,
10482 buffer_ids: Vec::new(),
10483 also_servers: Vec::new(),
10484 all: true,
10485 });
10486 cx.background_spawn(request).detach_and_log_err(cx);
10487 } else {
10488 let Some(local) = self.as_local_mut() else {
10489 return;
10490 };
10491 let language_servers_to_stop = local
10492 .language_server_ids
10493 .values()
10494 .map(|state| state.id)
10495 .collect();
10496 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10497 let tasks = language_servers_to_stop
10498 .into_iter()
10499 .map(|server| self.stop_local_language_server(server, cx))
10500 .collect::<Vec<_>>();
10501 cx.background_spawn(async move {
10502 futures::future::join_all(tasks).await;
10503 })
10504 .detach();
10505 }
10506 }
10507
10508 pub fn restart_language_servers_for_buffers(
10509 &mut self,
10510 buffers: Vec<Entity<Buffer>>,
10511 only_restart_servers: HashSet<LanguageServerSelector>,
10512 cx: &mut Context<Self>,
10513 ) {
10514 if let Some((client, project_id)) = self.upstream_client() {
10515 let request = client.request(proto::RestartLanguageServers {
10516 project_id,
10517 buffer_ids: buffers
10518 .into_iter()
10519 .map(|b| b.read(cx).remote_id().to_proto())
10520 .collect(),
10521 only_servers: only_restart_servers
10522 .into_iter()
10523 .map(|selector| {
10524 let selector = match selector {
10525 LanguageServerSelector::Id(language_server_id) => {
10526 proto::language_server_selector::Selector::ServerId(
10527 language_server_id.to_proto(),
10528 )
10529 }
10530 LanguageServerSelector::Name(language_server_name) => {
10531 proto::language_server_selector::Selector::Name(
10532 language_server_name.to_string(),
10533 )
10534 }
10535 };
10536 proto::LanguageServerSelector {
10537 selector: Some(selector),
10538 }
10539 })
10540 .collect(),
10541 all: false,
10542 });
10543 cx.background_spawn(request).detach_and_log_err(cx);
10544 } else {
10545 let stop_task = if only_restart_servers.is_empty() {
10546 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10547 } else {
10548 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10549 };
10550 cx.spawn(async move |lsp_store, cx| {
10551 stop_task.await;
10552 lsp_store
10553 .update(cx, |lsp_store, cx| {
10554 for buffer in buffers {
10555 lsp_store.register_buffer_with_language_servers(
10556 &buffer,
10557 only_restart_servers.clone(),
10558 true,
10559 cx,
10560 );
10561 }
10562 })
10563 .ok()
10564 })
10565 .detach();
10566 }
10567 }
10568
10569 pub fn stop_language_servers_for_buffers(
10570 &mut self,
10571 buffers: Vec<Entity<Buffer>>,
10572 also_stop_servers: HashSet<LanguageServerSelector>,
10573 cx: &mut Context<Self>,
10574 ) -> Task<Result<()>> {
10575 if let Some((client, project_id)) = self.upstream_client() {
10576 let request = client.request(proto::StopLanguageServers {
10577 project_id,
10578 buffer_ids: buffers
10579 .into_iter()
10580 .map(|b| b.read(cx).remote_id().to_proto())
10581 .collect(),
10582 also_servers: also_stop_servers
10583 .into_iter()
10584 .map(|selector| {
10585 let selector = match selector {
10586 LanguageServerSelector::Id(language_server_id) => {
10587 proto::language_server_selector::Selector::ServerId(
10588 language_server_id.to_proto(),
10589 )
10590 }
10591 LanguageServerSelector::Name(language_server_name) => {
10592 proto::language_server_selector::Selector::Name(
10593 language_server_name.to_string(),
10594 )
10595 }
10596 };
10597 proto::LanguageServerSelector {
10598 selector: Some(selector),
10599 }
10600 })
10601 .collect(),
10602 all: false,
10603 });
10604 cx.background_spawn(async move {
10605 let _ = request.await?;
10606 Ok(())
10607 })
10608 } else {
10609 let task =
10610 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10611 cx.background_spawn(async move {
10612 task.await;
10613 Ok(())
10614 })
10615 }
10616 }
10617
10618 fn stop_local_language_servers_for_buffers(
10619 &mut self,
10620 buffers: &[Entity<Buffer>],
10621 also_stop_servers: HashSet<LanguageServerSelector>,
10622 cx: &mut Context<Self>,
10623 ) -> Task<()> {
10624 let Some(local) = self.as_local_mut() else {
10625 return Task::ready(());
10626 };
10627 let mut language_server_names_to_stop = BTreeSet::default();
10628 let mut language_servers_to_stop = also_stop_servers
10629 .into_iter()
10630 .flat_map(|selector| match selector {
10631 LanguageServerSelector::Id(id) => Some(id),
10632 LanguageServerSelector::Name(name) => {
10633 language_server_names_to_stop.insert(name);
10634 None
10635 }
10636 })
10637 .collect::<BTreeSet<_>>();
10638
10639 let mut covered_worktrees = HashSet::default();
10640 for buffer in buffers {
10641 buffer.update(cx, |buffer, cx| {
10642 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10643 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10644 && covered_worktrees.insert(worktree_id)
10645 {
10646 language_server_names_to_stop.retain(|name| {
10647 let old_ids_count = language_servers_to_stop.len();
10648 let all_language_servers_with_this_name = local
10649 .language_server_ids
10650 .iter()
10651 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10652 language_servers_to_stop.extend(all_language_servers_with_this_name);
10653 old_ids_count == language_servers_to_stop.len()
10654 });
10655 }
10656 });
10657 }
10658 for name in language_server_names_to_stop {
10659 language_servers_to_stop.extend(
10660 local
10661 .language_server_ids
10662 .iter()
10663 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10664 );
10665 }
10666
10667 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10668 let tasks = language_servers_to_stop
10669 .into_iter()
10670 .map(|server| self.stop_local_language_server(server, cx))
10671 .collect::<Vec<_>>();
10672
10673 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10674 }
10675
10676 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10677 let (worktree, relative_path) =
10678 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10679
10680 let project_path = ProjectPath {
10681 worktree_id: worktree.read(cx).id(),
10682 path: relative_path.into(),
10683 };
10684
10685 Some(
10686 self.buffer_store()
10687 .read(cx)
10688 .get_by_path(&project_path)?
10689 .read(cx),
10690 )
10691 }
10692
10693 #[cfg(any(test, feature = "test-support"))]
10694 pub fn update_diagnostics(
10695 &mut self,
10696 server_id: LanguageServerId,
10697 diagnostics: lsp::PublishDiagnosticsParams,
10698 result_id: Option<String>,
10699 source_kind: DiagnosticSourceKind,
10700 disk_based_sources: &[String],
10701 cx: &mut Context<Self>,
10702 ) -> Result<()> {
10703 self.merge_lsp_diagnostics(
10704 source_kind,
10705 vec![DocumentDiagnosticsUpdate {
10706 diagnostics,
10707 result_id,
10708 server_id,
10709 disk_based_sources: Cow::Borrowed(disk_based_sources),
10710 }],
10711 |_, _, _| false,
10712 cx,
10713 )
10714 }
10715
10716 pub fn merge_lsp_diagnostics(
10717 &mut self,
10718 source_kind: DiagnosticSourceKind,
10719 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10720 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10721 cx: &mut Context<Self>,
10722 ) -> Result<()> {
10723 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10724 let updates = lsp_diagnostics
10725 .into_iter()
10726 .filter_map(|update| {
10727 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10728 Some(DocumentDiagnosticsUpdate {
10729 diagnostics: self.lsp_to_document_diagnostics(
10730 abs_path,
10731 source_kind,
10732 update.server_id,
10733 update.diagnostics,
10734 &update.disk_based_sources,
10735 ),
10736 result_id: update.result_id,
10737 server_id: update.server_id,
10738 disk_based_sources: update.disk_based_sources,
10739 })
10740 })
10741 .collect();
10742 self.merge_diagnostic_entries(updates, merge, cx)?;
10743 Ok(())
10744 }
10745
10746 fn lsp_to_document_diagnostics(
10747 &mut self,
10748 document_abs_path: PathBuf,
10749 source_kind: DiagnosticSourceKind,
10750 server_id: LanguageServerId,
10751 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10752 disk_based_sources: &[String],
10753 ) -> DocumentDiagnostics {
10754 let mut diagnostics = Vec::default();
10755 let mut primary_diagnostic_group_ids = HashMap::default();
10756 let mut sources_by_group_id = HashMap::default();
10757 let mut supporting_diagnostics = HashMap::default();
10758
10759 let adapter = self.language_server_adapter_for_id(server_id);
10760
10761 // Ensure that primary diagnostics are always the most severe
10762 lsp_diagnostics
10763 .diagnostics
10764 .sort_by_key(|item| item.severity);
10765
10766 for diagnostic in &lsp_diagnostics.diagnostics {
10767 let source = diagnostic.source.as_ref();
10768 let range = range_from_lsp(diagnostic.range);
10769 let is_supporting = diagnostic
10770 .related_information
10771 .as_ref()
10772 .is_some_and(|infos| {
10773 infos.iter().any(|info| {
10774 primary_diagnostic_group_ids.contains_key(&(
10775 source,
10776 diagnostic.code.clone(),
10777 range_from_lsp(info.location.range),
10778 ))
10779 })
10780 });
10781
10782 let is_unnecessary = diagnostic
10783 .tags
10784 .as_ref()
10785 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10786
10787 let underline = self
10788 .language_server_adapter_for_id(server_id)
10789 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10790
10791 if is_supporting {
10792 supporting_diagnostics.insert(
10793 (source, diagnostic.code.clone(), range),
10794 (diagnostic.severity, is_unnecessary),
10795 );
10796 } else {
10797 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10798 let is_disk_based =
10799 source.is_some_and(|source| disk_based_sources.contains(source));
10800
10801 sources_by_group_id.insert(group_id, source);
10802 primary_diagnostic_group_ids
10803 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10804
10805 diagnostics.push(DiagnosticEntry {
10806 range,
10807 diagnostic: Diagnostic {
10808 source: diagnostic.source.clone(),
10809 source_kind,
10810 code: diagnostic.code.clone(),
10811 code_description: diagnostic
10812 .code_description
10813 .as_ref()
10814 .and_then(|d| d.href.clone()),
10815 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10816 markdown: adapter.as_ref().and_then(|adapter| {
10817 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10818 }),
10819 message: diagnostic.message.trim().to_string(),
10820 group_id,
10821 is_primary: true,
10822 is_disk_based,
10823 is_unnecessary,
10824 underline,
10825 data: diagnostic.data.clone(),
10826 },
10827 });
10828 if let Some(infos) = &diagnostic.related_information {
10829 for info in infos {
10830 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10831 let range = range_from_lsp(info.location.range);
10832 diagnostics.push(DiagnosticEntry {
10833 range,
10834 diagnostic: Diagnostic {
10835 source: diagnostic.source.clone(),
10836 source_kind,
10837 code: diagnostic.code.clone(),
10838 code_description: diagnostic
10839 .code_description
10840 .as_ref()
10841 .and_then(|d| d.href.clone()),
10842 severity: DiagnosticSeverity::INFORMATION,
10843 markdown: adapter.as_ref().and_then(|adapter| {
10844 adapter.diagnostic_message_to_markdown(&info.message)
10845 }),
10846 message: info.message.trim().to_string(),
10847 group_id,
10848 is_primary: false,
10849 is_disk_based,
10850 is_unnecessary: false,
10851 underline,
10852 data: diagnostic.data.clone(),
10853 },
10854 });
10855 }
10856 }
10857 }
10858 }
10859 }
10860
10861 for entry in &mut diagnostics {
10862 let diagnostic = &mut entry.diagnostic;
10863 if !diagnostic.is_primary {
10864 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10865 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10866 source,
10867 diagnostic.code.clone(),
10868 entry.range.clone(),
10869 )) {
10870 if let Some(severity) = severity {
10871 diagnostic.severity = severity;
10872 }
10873 diagnostic.is_unnecessary = is_unnecessary;
10874 }
10875 }
10876 }
10877
10878 DocumentDiagnostics {
10879 diagnostics,
10880 document_abs_path,
10881 version: lsp_diagnostics.version,
10882 }
10883 }
10884
10885 fn insert_newly_running_language_server(
10886 &mut self,
10887 adapter: Arc<CachedLspAdapter>,
10888 language_server: Arc<LanguageServer>,
10889 server_id: LanguageServerId,
10890 key: LanguageServerSeed,
10891 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10892 cx: &mut Context<Self>,
10893 ) {
10894 let Some(local) = self.as_local_mut() else {
10895 return;
10896 };
10897 // If the language server for this key doesn't match the server id, don't store the
10898 // server. Which will cause it to be dropped, killing the process
10899 if local
10900 .language_server_ids
10901 .get(&key)
10902 .map(|state| state.id != server_id)
10903 .unwrap_or(false)
10904 {
10905 return;
10906 }
10907
10908 // Update language_servers collection with Running variant of LanguageServerState
10909 // indicating that the server is up and running and ready
10910 let workspace_folders = workspace_folders.lock().clone();
10911 language_server.set_workspace_folders(workspace_folders);
10912
10913 local.language_servers.insert(
10914 server_id,
10915 LanguageServerState::Running {
10916 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10917 language_server.clone(),
10918 cx,
10919 ),
10920 adapter: adapter.clone(),
10921 server: language_server.clone(),
10922 simulate_disk_based_diagnostics_completion: None,
10923 },
10924 );
10925 local
10926 .languages
10927 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10928 if let Some(file_ops_caps) = language_server
10929 .capabilities()
10930 .workspace
10931 .as_ref()
10932 .and_then(|ws| ws.file_operations.as_ref())
10933 {
10934 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10935 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10936 if did_rename_caps.or(will_rename_caps).is_some() {
10937 let watcher = RenamePathsWatchedForServer::default()
10938 .with_did_rename_patterns(did_rename_caps)
10939 .with_will_rename_patterns(will_rename_caps);
10940 local
10941 .language_server_paths_watched_for_rename
10942 .insert(server_id, watcher);
10943 }
10944 }
10945
10946 self.language_server_statuses.insert(
10947 server_id,
10948 LanguageServerStatus {
10949 name: language_server.name(),
10950 pending_work: Default::default(),
10951 has_pending_diagnostic_updates: false,
10952 progress_tokens: Default::default(),
10953 worktree: Some(key.worktree_id),
10954 },
10955 );
10956
10957 cx.emit(LspStoreEvent::LanguageServerAdded(
10958 server_id,
10959 language_server.name(),
10960 Some(key.worktree_id),
10961 ));
10962 cx.emit(LspStoreEvent::RefreshInlayHints);
10963
10964 let server_capabilities = language_server.capabilities();
10965 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10966 downstream_client
10967 .send(proto::StartLanguageServer {
10968 project_id: *project_id,
10969 server: Some(proto::LanguageServer {
10970 id: server_id.to_proto(),
10971 name: language_server.name().to_string(),
10972 worktree_id: Some(key.worktree_id.to_proto()),
10973 }),
10974 capabilities: serde_json::to_string(&server_capabilities)
10975 .expect("serializing server LSP capabilities"),
10976 })
10977 .log_err();
10978 }
10979 self.lsp_server_capabilities
10980 .insert(server_id, server_capabilities);
10981
10982 // Tell the language server about every open buffer in the worktree that matches the language.
10983 // Also check for buffers in worktrees that reused this server
10984 let mut worktrees_using_server = vec![key.worktree_id];
10985 if let Some(local) = self.as_local() {
10986 // Find all worktrees that have this server in their language server tree
10987 for (worktree_id, servers) in &local.lsp_tree.instances {
10988 if *worktree_id != key.worktree_id {
10989 for server_map in servers.roots.values() {
10990 if server_map.contains_key(&key.name) {
10991 worktrees_using_server.push(*worktree_id);
10992 }
10993 }
10994 }
10995 }
10996 }
10997
10998 let mut buffer_paths_registered = Vec::new();
10999 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11000 for buffer_handle in buffer_store.buffers() {
11001 let buffer = buffer_handle.read(cx);
11002 let file = match File::from_dyn(buffer.file()) {
11003 Some(file) => file,
11004 None => continue,
11005 };
11006 let language = match buffer.language() {
11007 Some(language) => language,
11008 None => continue,
11009 };
11010
11011 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11012 || !self
11013 .languages
11014 .lsp_adapters(&language.name())
11015 .iter()
11016 .any(|a| a.name == key.name)
11017 {
11018 continue;
11019 }
11020 // didOpen
11021 let file = match file.as_local() {
11022 Some(file) => file,
11023 None => continue,
11024 };
11025
11026 let local = self.as_local_mut().unwrap();
11027
11028 let buffer_id = buffer.remote_id();
11029 if local.registered_buffers.contains_key(&buffer_id) {
11030 let versions = local
11031 .buffer_snapshots
11032 .entry(buffer_id)
11033 .or_default()
11034 .entry(server_id)
11035 .and_modify(|_| {
11036 assert!(
11037 false,
11038 "There should not be an existing snapshot for a newly inserted buffer"
11039 )
11040 })
11041 .or_insert_with(|| {
11042 vec![LspBufferSnapshot {
11043 version: 0,
11044 snapshot: buffer.text_snapshot(),
11045 }]
11046 });
11047
11048 let snapshot = versions.last().unwrap();
11049 let version = snapshot.version;
11050 let initial_snapshot = &snapshot.snapshot;
11051 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11052 language_server.register_buffer(
11053 uri,
11054 adapter.language_id(&language.name()),
11055 version,
11056 initial_snapshot.text(),
11057 );
11058 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11059 local
11060 .buffers_opened_in_servers
11061 .entry(buffer_id)
11062 .or_default()
11063 .insert(server_id);
11064 }
11065 buffer_handle.update(cx, |buffer, cx| {
11066 buffer.set_completion_triggers(
11067 server_id,
11068 language_server
11069 .capabilities()
11070 .completion_provider
11071 .as_ref()
11072 .and_then(|provider| {
11073 provider
11074 .trigger_characters
11075 .as_ref()
11076 .map(|characters| characters.iter().cloned().collect())
11077 })
11078 .unwrap_or_default(),
11079 cx,
11080 )
11081 });
11082 }
11083 });
11084
11085 for (buffer_id, abs_path) in buffer_paths_registered {
11086 cx.emit(LspStoreEvent::LanguageServerUpdate {
11087 language_server_id: server_id,
11088 name: Some(adapter.name()),
11089 message: proto::update_language_server::Variant::RegisteredForBuffer(
11090 proto::RegisteredForBuffer {
11091 buffer_abs_path: abs_path.to_string_lossy().to_string(),
11092 buffer_id: buffer_id.to_proto(),
11093 },
11094 ),
11095 });
11096 }
11097
11098 cx.notify();
11099 }
11100
11101 pub fn language_servers_running_disk_based_diagnostics(
11102 &self,
11103 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11104 self.language_server_statuses
11105 .iter()
11106 .filter_map(|(id, status)| {
11107 if status.has_pending_diagnostic_updates {
11108 Some(*id)
11109 } else {
11110 None
11111 }
11112 })
11113 }
11114
11115 pub(crate) fn cancel_language_server_work_for_buffers(
11116 &mut self,
11117 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11118 cx: &mut Context<Self>,
11119 ) {
11120 if let Some((client, project_id)) = self.upstream_client() {
11121 let request = client.request(proto::CancelLanguageServerWork {
11122 project_id,
11123 work: Some(proto::cancel_language_server_work::Work::Buffers(
11124 proto::cancel_language_server_work::Buffers {
11125 buffer_ids: buffers
11126 .into_iter()
11127 .map(|b| b.read(cx).remote_id().to_proto())
11128 .collect(),
11129 },
11130 )),
11131 });
11132 cx.background_spawn(request).detach_and_log_err(cx);
11133 } else if let Some(local) = self.as_local() {
11134 let servers = buffers
11135 .into_iter()
11136 .flat_map(|buffer| {
11137 buffer.update(cx, |buffer, cx| {
11138 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11139 })
11140 })
11141 .collect::<HashSet<_>>();
11142 for server_id in servers {
11143 self.cancel_language_server_work(server_id, None, cx);
11144 }
11145 }
11146 }
11147
11148 pub(crate) fn cancel_language_server_work(
11149 &mut self,
11150 server_id: LanguageServerId,
11151 token_to_cancel: Option<String>,
11152 cx: &mut Context<Self>,
11153 ) {
11154 if let Some(local) = self.as_local() {
11155 let status = self.language_server_statuses.get(&server_id);
11156 let server = local.language_servers.get(&server_id);
11157 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11158 {
11159 for (token, progress) in &status.pending_work {
11160 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11161 && token != token_to_cancel
11162 {
11163 continue;
11164 }
11165 if progress.is_cancellable {
11166 server
11167 .notify::<lsp::notification::WorkDoneProgressCancel>(
11168 &WorkDoneProgressCancelParams {
11169 token: lsp::NumberOrString::String(token.clone()),
11170 },
11171 )
11172 .ok();
11173 }
11174 }
11175 }
11176 } else if let Some((client, project_id)) = self.upstream_client() {
11177 let request = client.request(proto::CancelLanguageServerWork {
11178 project_id,
11179 work: Some(
11180 proto::cancel_language_server_work::Work::LanguageServerWork(
11181 proto::cancel_language_server_work::LanguageServerWork {
11182 language_server_id: server_id.to_proto(),
11183 token: token_to_cancel,
11184 },
11185 ),
11186 ),
11187 });
11188 cx.background_spawn(request).detach_and_log_err(cx);
11189 }
11190 }
11191
11192 fn register_supplementary_language_server(
11193 &mut self,
11194 id: LanguageServerId,
11195 name: LanguageServerName,
11196 server: Arc<LanguageServer>,
11197 cx: &mut Context<Self>,
11198 ) {
11199 if let Some(local) = self.as_local_mut() {
11200 local
11201 .supplementary_language_servers
11202 .insert(id, (name.clone(), server));
11203 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11204 }
11205 }
11206
11207 fn unregister_supplementary_language_server(
11208 &mut self,
11209 id: LanguageServerId,
11210 cx: &mut Context<Self>,
11211 ) {
11212 if let Some(local) = self.as_local_mut() {
11213 local.supplementary_language_servers.remove(&id);
11214 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11215 }
11216 }
11217
11218 pub(crate) fn supplementary_language_servers(
11219 &self,
11220 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11221 self.as_local().into_iter().flat_map(|local| {
11222 local
11223 .supplementary_language_servers
11224 .iter()
11225 .map(|(id, (name, _))| (*id, name.clone()))
11226 })
11227 }
11228
11229 pub fn language_server_adapter_for_id(
11230 &self,
11231 id: LanguageServerId,
11232 ) -> Option<Arc<CachedLspAdapter>> {
11233 self.as_local()
11234 .and_then(|local| local.language_servers.get(&id))
11235 .and_then(|language_server_state| match language_server_state {
11236 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11237 _ => None,
11238 })
11239 }
11240
11241 pub(super) fn update_local_worktree_language_servers(
11242 &mut self,
11243 worktree_handle: &Entity<Worktree>,
11244 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
11245 cx: &mut Context<Self>,
11246 ) {
11247 if changes.is_empty() {
11248 return;
11249 }
11250
11251 let Some(local) = self.as_local() else { return };
11252
11253 local.prettier_store.update(cx, |prettier_store, cx| {
11254 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11255 });
11256
11257 let worktree_id = worktree_handle.read(cx).id();
11258 let mut language_server_ids = local
11259 .language_server_ids
11260 .iter()
11261 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11262 .collect::<Vec<_>>();
11263 language_server_ids.sort();
11264 language_server_ids.dedup();
11265
11266 let abs_path = worktree_handle.read(cx).abs_path();
11267 for server_id in &language_server_ids {
11268 if let Some(LanguageServerState::Running { server, .. }) =
11269 local.language_servers.get(server_id)
11270 && let Some(watched_paths) = local
11271 .language_server_watched_paths
11272 .get(server_id)
11273 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11274 {
11275 let params = lsp::DidChangeWatchedFilesParams {
11276 changes: changes
11277 .iter()
11278 .filter_map(|(path, _, change)| {
11279 if !watched_paths.is_match(path) {
11280 return None;
11281 }
11282 let typ = match change {
11283 PathChange::Loaded => return None,
11284 PathChange::Added => lsp::FileChangeType::CREATED,
11285 PathChange::Removed => lsp::FileChangeType::DELETED,
11286 PathChange::Updated => lsp::FileChangeType::CHANGED,
11287 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11288 };
11289 Some(lsp::FileEvent {
11290 uri: lsp::Uri::from_file_path(abs_path.join(path)).unwrap(),
11291 typ,
11292 })
11293 })
11294 .collect(),
11295 };
11296 if !params.changes.is_empty() {
11297 server
11298 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
11299 .ok();
11300 }
11301 }
11302 }
11303 for (path, _, _) in changes {
11304 if let Some(file_name) = path.file_name().and_then(|file_name| file_name.to_str())
11305 && local.watched_manifest_filenames.contains(file_name)
11306 {
11307 self.request_workspace_config_refresh();
11308 break;
11309 }
11310 }
11311 }
11312
11313 pub fn wait_for_remote_buffer(
11314 &mut self,
11315 id: BufferId,
11316 cx: &mut Context<Self>,
11317 ) -> Task<Result<Entity<Buffer>>> {
11318 self.buffer_store.update(cx, |buffer_store, cx| {
11319 buffer_store.wait_for_remote_buffer(id, cx)
11320 })
11321 }
11322
11323 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11324 proto::Symbol {
11325 language_server_name: symbol.language_server_name.0.to_string(),
11326 source_worktree_id: symbol.source_worktree_id.to_proto(),
11327 language_server_id: symbol.source_language_server_id.to_proto(),
11328 worktree_id: symbol.path.worktree_id.to_proto(),
11329 path: symbol.path.path.as_ref().to_proto(),
11330 name: symbol.name.clone(),
11331 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11332 start: Some(proto::PointUtf16 {
11333 row: symbol.range.start.0.row,
11334 column: symbol.range.start.0.column,
11335 }),
11336 end: Some(proto::PointUtf16 {
11337 row: symbol.range.end.0.row,
11338 column: symbol.range.end.0.column,
11339 }),
11340 signature: symbol.signature.to_vec(),
11341 }
11342 }
11343
11344 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11345 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11346 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11347 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11348 let path = ProjectPath {
11349 worktree_id,
11350 path: Arc::<Path>::from_proto(serialized_symbol.path),
11351 };
11352
11353 let start = serialized_symbol.start.context("invalid start")?;
11354 let end = serialized_symbol.end.context("invalid end")?;
11355 Ok(CoreSymbol {
11356 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11357 source_worktree_id,
11358 source_language_server_id: LanguageServerId::from_proto(
11359 serialized_symbol.language_server_id,
11360 ),
11361 path,
11362 name: serialized_symbol.name,
11363 range: Unclipped(PointUtf16::new(start.row, start.column))
11364 ..Unclipped(PointUtf16::new(end.row, end.column)),
11365 kind,
11366 signature: serialized_symbol
11367 .signature
11368 .try_into()
11369 .map_err(|_| anyhow!("invalid signature"))?,
11370 })
11371 }
11372
11373 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11374 let mut serialized_completion = proto::Completion {
11375 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11376 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11377 new_text: completion.new_text.clone(),
11378 ..proto::Completion::default()
11379 };
11380 match &completion.source {
11381 CompletionSource::Lsp {
11382 insert_range,
11383 server_id,
11384 lsp_completion,
11385 lsp_defaults,
11386 resolved,
11387 } => {
11388 let (old_insert_start, old_insert_end) = insert_range
11389 .as_ref()
11390 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11391 .unzip();
11392
11393 serialized_completion.old_insert_start = old_insert_start;
11394 serialized_completion.old_insert_end = old_insert_end;
11395 serialized_completion.source = proto::completion::Source::Lsp as i32;
11396 serialized_completion.server_id = server_id.0 as u64;
11397 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11398 serialized_completion.lsp_defaults = lsp_defaults
11399 .as_deref()
11400 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11401 serialized_completion.resolved = *resolved;
11402 }
11403 CompletionSource::BufferWord {
11404 word_range,
11405 resolved,
11406 } => {
11407 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11408 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11409 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11410 serialized_completion.resolved = *resolved;
11411 }
11412 CompletionSource::Custom => {
11413 serialized_completion.source = proto::completion::Source::Custom as i32;
11414 serialized_completion.resolved = true;
11415 }
11416 CompletionSource::Dap { sort_text } => {
11417 serialized_completion.source = proto::completion::Source::Dap as i32;
11418 serialized_completion.sort_text = Some(sort_text.clone());
11419 }
11420 }
11421
11422 serialized_completion
11423 }
11424
11425 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11426 let old_replace_start = completion
11427 .old_replace_start
11428 .and_then(deserialize_anchor)
11429 .context("invalid old start")?;
11430 let old_replace_end = completion
11431 .old_replace_end
11432 .and_then(deserialize_anchor)
11433 .context("invalid old end")?;
11434 let insert_range = {
11435 match completion.old_insert_start.zip(completion.old_insert_end) {
11436 Some((start, end)) => {
11437 let start = deserialize_anchor(start).context("invalid insert old start")?;
11438 let end = deserialize_anchor(end).context("invalid insert old end")?;
11439 Some(start..end)
11440 }
11441 None => None,
11442 }
11443 };
11444 Ok(CoreCompletion {
11445 replace_range: old_replace_start..old_replace_end,
11446 new_text: completion.new_text,
11447 source: match proto::completion::Source::from_i32(completion.source) {
11448 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11449 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11450 insert_range,
11451 server_id: LanguageServerId::from_proto(completion.server_id),
11452 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11453 lsp_defaults: completion
11454 .lsp_defaults
11455 .as_deref()
11456 .map(serde_json::from_slice)
11457 .transpose()?,
11458 resolved: completion.resolved,
11459 },
11460 Some(proto::completion::Source::BufferWord) => {
11461 let word_range = completion
11462 .buffer_word_start
11463 .and_then(deserialize_anchor)
11464 .context("invalid buffer word start")?
11465 ..completion
11466 .buffer_word_end
11467 .and_then(deserialize_anchor)
11468 .context("invalid buffer word end")?;
11469 CompletionSource::BufferWord {
11470 word_range,
11471 resolved: completion.resolved,
11472 }
11473 }
11474 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11475 sort_text: completion
11476 .sort_text
11477 .context("expected sort text to exist")?,
11478 },
11479 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11480 },
11481 })
11482 }
11483
11484 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11485 let (kind, lsp_action) = match &action.lsp_action {
11486 LspAction::Action(code_action) => (
11487 proto::code_action::Kind::Action as i32,
11488 serde_json::to_vec(code_action).unwrap(),
11489 ),
11490 LspAction::Command(command) => (
11491 proto::code_action::Kind::Command as i32,
11492 serde_json::to_vec(command).unwrap(),
11493 ),
11494 LspAction::CodeLens(code_lens) => (
11495 proto::code_action::Kind::CodeLens as i32,
11496 serde_json::to_vec(code_lens).unwrap(),
11497 ),
11498 };
11499
11500 proto::CodeAction {
11501 server_id: action.server_id.0 as u64,
11502 start: Some(serialize_anchor(&action.range.start)),
11503 end: Some(serialize_anchor(&action.range.end)),
11504 lsp_action,
11505 kind,
11506 resolved: action.resolved,
11507 }
11508 }
11509
11510 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11511 let start = action
11512 .start
11513 .and_then(deserialize_anchor)
11514 .context("invalid start")?;
11515 let end = action
11516 .end
11517 .and_then(deserialize_anchor)
11518 .context("invalid end")?;
11519 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11520 Some(proto::code_action::Kind::Action) => {
11521 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11522 }
11523 Some(proto::code_action::Kind::Command) => {
11524 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11525 }
11526 Some(proto::code_action::Kind::CodeLens) => {
11527 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11528 }
11529 None => anyhow::bail!("Unknown action kind {}", action.kind),
11530 };
11531 Ok(CodeAction {
11532 server_id: LanguageServerId(action.server_id as usize),
11533 range: start..end,
11534 resolved: action.resolved,
11535 lsp_action,
11536 })
11537 }
11538
11539 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11540 match &formatting_result {
11541 Ok(_) => self.last_formatting_failure = None,
11542 Err(error) => {
11543 let error_string = format!("{error:#}");
11544 log::error!("Formatting failed: {error_string}");
11545 self.last_formatting_failure
11546 .replace(error_string.lines().join(" "));
11547 }
11548 }
11549 }
11550
11551 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11552 self.lsp_server_capabilities.remove(&for_server);
11553 for buffer_colors in self.lsp_document_colors.values_mut() {
11554 buffer_colors.colors.remove(&for_server);
11555 buffer_colors.cache_version += 1;
11556 }
11557 for buffer_lens in self.lsp_code_lens.values_mut() {
11558 buffer_lens.lens.remove(&for_server);
11559 }
11560 if let Some(local) = self.as_local_mut() {
11561 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11562 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11563 buffer_servers.remove(&for_server);
11564 }
11565 }
11566 }
11567
11568 pub fn result_id(
11569 &self,
11570 server_id: LanguageServerId,
11571 buffer_id: BufferId,
11572 cx: &App,
11573 ) -> Option<String> {
11574 let abs_path = self
11575 .buffer_store
11576 .read(cx)
11577 .get(buffer_id)
11578 .and_then(|b| File::from_dyn(b.read(cx).file()))
11579 .map(|f| f.abs_path(cx))?;
11580 self.as_local()?
11581 .buffer_pull_diagnostics_result_ids
11582 .get(&server_id)?
11583 .get(&abs_path)?
11584 .clone()
11585 }
11586
11587 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11588 let Some(local) = self.as_local() else {
11589 return HashMap::default();
11590 };
11591 local
11592 .buffer_pull_diagnostics_result_ids
11593 .get(&server_id)
11594 .into_iter()
11595 .flatten()
11596 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11597 .collect()
11598 }
11599
11600 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11601 if let Some(LanguageServerState::Running {
11602 workspace_refresh_task: Some(workspace_refresh_task),
11603 ..
11604 }) = self
11605 .as_local_mut()
11606 .and_then(|local| local.language_servers.get_mut(&server_id))
11607 {
11608 workspace_refresh_task.refresh_tx.try_send(()).ok();
11609 }
11610 }
11611
11612 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11613 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11614 return;
11615 };
11616 let Some(local) = self.as_local_mut() else {
11617 return;
11618 };
11619
11620 for server_id in buffer.update(cx, |buffer, cx| {
11621 local.language_server_ids_for_buffer(buffer, cx)
11622 }) {
11623 if let Some(LanguageServerState::Running {
11624 workspace_refresh_task: Some(workspace_refresh_task),
11625 ..
11626 }) = local.language_servers.get_mut(&server_id)
11627 {
11628 workspace_refresh_task.refresh_tx.try_send(()).ok();
11629 }
11630 }
11631 }
11632
11633 fn apply_workspace_diagnostic_report(
11634 &mut self,
11635 server_id: LanguageServerId,
11636 report: lsp::WorkspaceDiagnosticReportResult,
11637 cx: &mut Context<Self>,
11638 ) {
11639 let workspace_diagnostics =
11640 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11641 let mut unchanged_buffers = HashSet::default();
11642 let mut changed_buffers = HashSet::default();
11643 let workspace_diagnostics_updates = workspace_diagnostics
11644 .into_iter()
11645 .filter_map(
11646 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11647 LspPullDiagnostics::Response {
11648 server_id,
11649 uri,
11650 diagnostics,
11651 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11652 LspPullDiagnostics::Default => None,
11653 },
11654 )
11655 .fold(
11656 HashMap::default(),
11657 |mut acc, (server_id, uri, diagnostics, version)| {
11658 let (result_id, diagnostics) = match diagnostics {
11659 PulledDiagnostics::Unchanged { result_id } => {
11660 unchanged_buffers.insert(uri.clone());
11661 (Some(result_id), Vec::new())
11662 }
11663 PulledDiagnostics::Changed {
11664 result_id,
11665 diagnostics,
11666 } => {
11667 changed_buffers.insert(uri.clone());
11668 (result_id, diagnostics)
11669 }
11670 };
11671 let disk_based_sources = Cow::Owned(
11672 self.language_server_adapter_for_id(server_id)
11673 .as_ref()
11674 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11675 .unwrap_or(&[])
11676 .to_vec(),
11677 );
11678 acc.entry(server_id)
11679 .or_insert_with(Vec::new)
11680 .push(DocumentDiagnosticsUpdate {
11681 server_id,
11682 diagnostics: lsp::PublishDiagnosticsParams {
11683 uri,
11684 diagnostics,
11685 version,
11686 },
11687 result_id,
11688 disk_based_sources,
11689 });
11690 acc
11691 },
11692 );
11693
11694 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11695 self.merge_lsp_diagnostics(
11696 DiagnosticSourceKind::Pulled,
11697 diagnostic_updates,
11698 |buffer, old_diagnostic, cx| {
11699 File::from_dyn(buffer.file())
11700 .and_then(|file| {
11701 let abs_path = file.as_local()?.abs_path(cx);
11702 lsp::Uri::from_file_path(abs_path).ok()
11703 })
11704 .is_none_or(|buffer_uri| {
11705 unchanged_buffers.contains(&buffer_uri)
11706 || match old_diagnostic.source_kind {
11707 DiagnosticSourceKind::Pulled => {
11708 !changed_buffers.contains(&buffer_uri)
11709 }
11710 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11711 true
11712 }
11713 }
11714 })
11715 },
11716 cx,
11717 )
11718 .log_err();
11719 }
11720 }
11721
11722 fn register_server_capabilities(
11723 &mut self,
11724 server_id: LanguageServerId,
11725 params: lsp::RegistrationParams,
11726 cx: &mut Context<Self>,
11727 ) -> anyhow::Result<()> {
11728 let server = self
11729 .language_server_for_id(server_id)
11730 .with_context(|| format!("no server {server_id} found"))?;
11731 for reg in params.registrations {
11732 match reg.method.as_str() {
11733 "workspace/didChangeWatchedFiles" => {
11734 if let Some(options) = reg.register_options {
11735 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11736 let caps = serde_json::from_value(options)?;
11737 local_lsp_store
11738 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11739 true
11740 } else {
11741 false
11742 };
11743 if notify {
11744 notify_server_capabilities_updated(&server, cx);
11745 }
11746 }
11747 }
11748 "workspace/didChangeConfiguration" => {
11749 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11750 }
11751 "workspace/didChangeWorkspaceFolders" => {
11752 // In this case register options is an empty object, we can ignore it
11753 let caps = lsp::WorkspaceFoldersServerCapabilities {
11754 supported: Some(true),
11755 change_notifications: Some(OneOf::Right(reg.id)),
11756 };
11757 server.update_capabilities(|capabilities| {
11758 capabilities
11759 .workspace
11760 .get_or_insert_default()
11761 .workspace_folders = Some(caps);
11762 });
11763 notify_server_capabilities_updated(&server, cx);
11764 }
11765 "workspace/symbol" => {
11766 let options = parse_register_capabilities(reg)?;
11767 server.update_capabilities(|capabilities| {
11768 capabilities.workspace_symbol_provider = Some(options);
11769 });
11770 notify_server_capabilities_updated(&server, cx);
11771 }
11772 "workspace/fileOperations" => {
11773 if let Some(options) = reg.register_options {
11774 let caps = serde_json::from_value(options)?;
11775 server.update_capabilities(|capabilities| {
11776 capabilities
11777 .workspace
11778 .get_or_insert_default()
11779 .file_operations = Some(caps);
11780 });
11781 notify_server_capabilities_updated(&server, cx);
11782 }
11783 }
11784 "workspace/executeCommand" => {
11785 if let Some(options) = reg.register_options {
11786 let options = serde_json::from_value(options)?;
11787 server.update_capabilities(|capabilities| {
11788 capabilities.execute_command_provider = Some(options);
11789 });
11790 notify_server_capabilities_updated(&server, cx);
11791 }
11792 }
11793 "textDocument/rangeFormatting" => {
11794 let options = parse_register_capabilities(reg)?;
11795 server.update_capabilities(|capabilities| {
11796 capabilities.document_range_formatting_provider = Some(options);
11797 });
11798 notify_server_capabilities_updated(&server, cx);
11799 }
11800 "textDocument/onTypeFormatting" => {
11801 if let Some(options) = reg
11802 .register_options
11803 .map(serde_json::from_value)
11804 .transpose()?
11805 {
11806 server.update_capabilities(|capabilities| {
11807 capabilities.document_on_type_formatting_provider = Some(options);
11808 });
11809 notify_server_capabilities_updated(&server, cx);
11810 }
11811 }
11812 "textDocument/formatting" => {
11813 let options = parse_register_capabilities(reg)?;
11814 server.update_capabilities(|capabilities| {
11815 capabilities.document_formatting_provider = Some(options);
11816 });
11817 notify_server_capabilities_updated(&server, cx);
11818 }
11819 "textDocument/rename" => {
11820 let options = parse_register_capabilities(reg)?;
11821 server.update_capabilities(|capabilities| {
11822 capabilities.rename_provider = Some(options);
11823 });
11824 notify_server_capabilities_updated(&server, cx);
11825 }
11826 "textDocument/inlayHint" => {
11827 let options = parse_register_capabilities(reg)?;
11828 server.update_capabilities(|capabilities| {
11829 capabilities.inlay_hint_provider = Some(options);
11830 });
11831 notify_server_capabilities_updated(&server, cx);
11832 }
11833 "textDocument/documentSymbol" => {
11834 let options = parse_register_capabilities(reg)?;
11835 server.update_capabilities(|capabilities| {
11836 capabilities.document_symbol_provider = Some(options);
11837 });
11838 notify_server_capabilities_updated(&server, cx);
11839 }
11840 "textDocument/codeAction" => {
11841 let options = parse_register_capabilities(reg)?;
11842 let provider = match options {
11843 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11844 OneOf::Right(caps) => caps,
11845 };
11846 server.update_capabilities(|capabilities| {
11847 capabilities.code_action_provider = Some(provider);
11848 });
11849 notify_server_capabilities_updated(&server, cx);
11850 }
11851 "textDocument/definition" => {
11852 let options = parse_register_capabilities(reg)?;
11853 server.update_capabilities(|capabilities| {
11854 capabilities.definition_provider = Some(options);
11855 });
11856 notify_server_capabilities_updated(&server, cx);
11857 }
11858 "textDocument/completion" => {
11859 if let Some(caps) = reg
11860 .register_options
11861 .map(serde_json::from_value)
11862 .transpose()?
11863 {
11864 server.update_capabilities(|capabilities| {
11865 capabilities.completion_provider = Some(caps);
11866 });
11867 notify_server_capabilities_updated(&server, cx);
11868 }
11869 }
11870 "textDocument/hover" => {
11871 let options = parse_register_capabilities(reg)?;
11872 let provider = match options {
11873 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11874 OneOf::Right(caps) => caps,
11875 };
11876 server.update_capabilities(|capabilities| {
11877 capabilities.hover_provider = Some(provider);
11878 });
11879 notify_server_capabilities_updated(&server, cx);
11880 }
11881 "textDocument/signatureHelp" => {
11882 if let Some(caps) = reg
11883 .register_options
11884 .map(serde_json::from_value)
11885 .transpose()?
11886 {
11887 server.update_capabilities(|capabilities| {
11888 capabilities.signature_help_provider = Some(caps);
11889 });
11890 notify_server_capabilities_updated(&server, cx);
11891 }
11892 }
11893 "textDocument/didChange" => {
11894 if let Some(sync_kind) = reg
11895 .register_options
11896 .and_then(|opts| opts.get("syncKind").cloned())
11897 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11898 .transpose()?
11899 {
11900 server.update_capabilities(|capabilities| {
11901 let mut sync_options =
11902 Self::take_text_document_sync_options(capabilities);
11903 sync_options.change = Some(sync_kind);
11904 capabilities.text_document_sync =
11905 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11906 });
11907 notify_server_capabilities_updated(&server, cx);
11908 }
11909 }
11910 "textDocument/didSave" => {
11911 if let Some(include_text) = reg
11912 .register_options
11913 .map(|opts| {
11914 let transpose = opts
11915 .get("includeText")
11916 .cloned()
11917 .map(serde_json::from_value::<Option<bool>>)
11918 .transpose();
11919 match transpose {
11920 Ok(value) => Ok(value.flatten()),
11921 Err(e) => Err(e),
11922 }
11923 })
11924 .transpose()?
11925 {
11926 server.update_capabilities(|capabilities| {
11927 let mut sync_options =
11928 Self::take_text_document_sync_options(capabilities);
11929 sync_options.save =
11930 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11931 include_text,
11932 }));
11933 capabilities.text_document_sync =
11934 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11935 });
11936 notify_server_capabilities_updated(&server, cx);
11937 }
11938 }
11939 "textDocument/codeLens" => {
11940 if let Some(caps) = reg
11941 .register_options
11942 .map(serde_json::from_value)
11943 .transpose()?
11944 {
11945 server.update_capabilities(|capabilities| {
11946 capabilities.code_lens_provider = Some(caps);
11947 });
11948 notify_server_capabilities_updated(&server, cx);
11949 }
11950 }
11951 "textDocument/diagnostic" => {
11952 if let Some(caps) = reg
11953 .register_options
11954 .map(serde_json::from_value)
11955 .transpose()?
11956 {
11957 server.update_capabilities(|capabilities| {
11958 capabilities.diagnostic_provider = Some(caps);
11959 });
11960 notify_server_capabilities_updated(&server, cx);
11961 }
11962 }
11963 "textDocument/documentColor" => {
11964 let options = parse_register_capabilities(reg)?;
11965 let provider = match options {
11966 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11967 OneOf::Right(caps) => caps,
11968 };
11969 server.update_capabilities(|capabilities| {
11970 capabilities.color_provider = Some(provider);
11971 });
11972 notify_server_capabilities_updated(&server, cx);
11973 }
11974 _ => log::warn!("unhandled capability registration: {reg:?}"),
11975 }
11976 }
11977
11978 Ok(())
11979 }
11980
11981 fn unregister_server_capabilities(
11982 &mut self,
11983 server_id: LanguageServerId,
11984 params: lsp::UnregistrationParams,
11985 cx: &mut Context<Self>,
11986 ) -> anyhow::Result<()> {
11987 let server = self
11988 .language_server_for_id(server_id)
11989 .with_context(|| format!("no server {server_id} found"))?;
11990 for unreg in params.unregisterations.iter() {
11991 match unreg.method.as_str() {
11992 "workspace/didChangeWatchedFiles" => {
11993 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11994 local_lsp_store
11995 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11996 true
11997 } else {
11998 false
11999 };
12000 if notify {
12001 notify_server_capabilities_updated(&server, cx);
12002 }
12003 }
12004 "workspace/didChangeConfiguration" => {
12005 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12006 }
12007 "workspace/didChangeWorkspaceFolders" => {
12008 server.update_capabilities(|capabilities| {
12009 capabilities
12010 .workspace
12011 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12012 workspace_folders: None,
12013 file_operations: None,
12014 })
12015 .workspace_folders = None;
12016 });
12017 notify_server_capabilities_updated(&server, cx);
12018 }
12019 "workspace/symbol" => {
12020 server.update_capabilities(|capabilities| {
12021 capabilities.workspace_symbol_provider = None
12022 });
12023 notify_server_capabilities_updated(&server, cx);
12024 }
12025 "workspace/fileOperations" => {
12026 server.update_capabilities(|capabilities| {
12027 capabilities
12028 .workspace
12029 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12030 workspace_folders: None,
12031 file_operations: None,
12032 })
12033 .file_operations = None;
12034 });
12035 notify_server_capabilities_updated(&server, cx);
12036 }
12037 "workspace/executeCommand" => {
12038 server.update_capabilities(|capabilities| {
12039 capabilities.execute_command_provider = None;
12040 });
12041 notify_server_capabilities_updated(&server, cx);
12042 }
12043 "textDocument/rangeFormatting" => {
12044 server.update_capabilities(|capabilities| {
12045 capabilities.document_range_formatting_provider = None
12046 });
12047 notify_server_capabilities_updated(&server, cx);
12048 }
12049 "textDocument/onTypeFormatting" => {
12050 server.update_capabilities(|capabilities| {
12051 capabilities.document_on_type_formatting_provider = None;
12052 });
12053 notify_server_capabilities_updated(&server, cx);
12054 }
12055 "textDocument/formatting" => {
12056 server.update_capabilities(|capabilities| {
12057 capabilities.document_formatting_provider = None;
12058 });
12059 notify_server_capabilities_updated(&server, cx);
12060 }
12061 "textDocument/rename" => {
12062 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12063 notify_server_capabilities_updated(&server, cx);
12064 }
12065 "textDocument/codeAction" => {
12066 server.update_capabilities(|capabilities| {
12067 capabilities.code_action_provider = None;
12068 });
12069 notify_server_capabilities_updated(&server, cx);
12070 }
12071 "textDocument/definition" => {
12072 server.update_capabilities(|capabilities| {
12073 capabilities.definition_provider = None;
12074 });
12075 notify_server_capabilities_updated(&server, cx);
12076 }
12077 "textDocument/completion" => {
12078 server.update_capabilities(|capabilities| {
12079 capabilities.completion_provider = None;
12080 });
12081 notify_server_capabilities_updated(&server, cx);
12082 }
12083 "textDocument/hover" => {
12084 server.update_capabilities(|capabilities| {
12085 capabilities.hover_provider = None;
12086 });
12087 notify_server_capabilities_updated(&server, cx);
12088 }
12089 "textDocument/signatureHelp" => {
12090 server.update_capabilities(|capabilities| {
12091 capabilities.signature_help_provider = None;
12092 });
12093 notify_server_capabilities_updated(&server, cx);
12094 }
12095 "textDocument/didChange" => {
12096 server.update_capabilities(|capabilities| {
12097 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12098 sync_options.change = None;
12099 capabilities.text_document_sync =
12100 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12101 });
12102 notify_server_capabilities_updated(&server, cx);
12103 }
12104 "textDocument/didSave" => {
12105 server.update_capabilities(|capabilities| {
12106 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12107 sync_options.save = None;
12108 capabilities.text_document_sync =
12109 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12110 });
12111 notify_server_capabilities_updated(&server, cx);
12112 }
12113 "textDocument/codeLens" => {
12114 server.update_capabilities(|capabilities| {
12115 capabilities.code_lens_provider = None;
12116 });
12117 notify_server_capabilities_updated(&server, cx);
12118 }
12119 "textDocument/diagnostic" => {
12120 server.update_capabilities(|capabilities| {
12121 capabilities.diagnostic_provider = None;
12122 });
12123 notify_server_capabilities_updated(&server, cx);
12124 }
12125 "textDocument/documentColor" => {
12126 server.update_capabilities(|capabilities| {
12127 capabilities.color_provider = None;
12128 });
12129 notify_server_capabilities_updated(&server, cx);
12130 }
12131 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12132 }
12133 }
12134
12135 Ok(())
12136 }
12137
12138 async fn query_lsp_locally<T>(
12139 lsp_store: Entity<Self>,
12140 sender_id: proto::PeerId,
12141 lsp_request_id: LspRequestId,
12142 proto_request: T::ProtoRequest,
12143 position: Option<Anchor>,
12144 mut cx: AsyncApp,
12145 ) -> Result<()>
12146 where
12147 T: LspCommand + Clone,
12148 T::ProtoRequest: proto::LspRequestMessage,
12149 <T::ProtoRequest as proto::RequestMessage>::Response:
12150 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12151 {
12152 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12153 let version = deserialize_version(proto_request.buffer_version());
12154 let buffer = lsp_store.update(&mut cx, |this, cx| {
12155 this.buffer_store.read(cx).get_existing(buffer_id)
12156 })??;
12157 buffer
12158 .update(&mut cx, |buffer, _| {
12159 buffer.wait_for_version(version.clone())
12160 })?
12161 .await?;
12162 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
12163 let request =
12164 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12165 lsp_store.update(&mut cx, |lsp_store, cx| {
12166 let request_task =
12167 lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx);
12168 let existing_queries = lsp_store
12169 .running_lsp_requests
12170 .entry(TypeId::of::<T>())
12171 .or_default();
12172 if T::ProtoRequest::stop_previous_requests()
12173 || buffer_version.changed_since(&existing_queries.0)
12174 {
12175 existing_queries.1.clear();
12176 }
12177 existing_queries.1.insert(
12178 lsp_request_id,
12179 cx.spawn(async move |lsp_store, cx| {
12180 let response = request_task.await;
12181 lsp_store
12182 .update(cx, |lsp_store, cx| {
12183 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12184 {
12185 let response = response
12186 .into_iter()
12187 .map(|(server_id, response)| {
12188 (
12189 server_id.to_proto(),
12190 T::response_to_proto(
12191 response,
12192 lsp_store,
12193 sender_id,
12194 &buffer_version,
12195 cx,
12196 )
12197 .into(),
12198 )
12199 })
12200 .collect::<HashMap<_, _>>();
12201 match client.send_lsp_response::<T::ProtoRequest>(
12202 project_id,
12203 lsp_request_id,
12204 response,
12205 ) {
12206 Ok(()) => {}
12207 Err(e) => {
12208 log::error!("Failed to send LSP response: {e:#}",)
12209 }
12210 }
12211 }
12212 })
12213 .ok();
12214 }),
12215 );
12216 })?;
12217 Ok(())
12218 }
12219
12220 fn take_text_document_sync_options(
12221 capabilities: &mut lsp::ServerCapabilities,
12222 ) -> lsp::TextDocumentSyncOptions {
12223 match capabilities.text_document_sync.take() {
12224 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12225 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12226 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12227 sync_options.change = Some(sync_kind);
12228 sync_options
12229 }
12230 None => lsp::TextDocumentSyncOptions::default(),
12231 }
12232 }
12233
12234 #[cfg(any(test, feature = "test-support"))]
12235 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12236 let data = self.lsp_code_lens.get_mut(&buffer_id)?;
12237 Some(data.update.take()?.1)
12238 }
12239
12240 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12241 self.downstream_client.clone()
12242 }
12243
12244 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12245 self.worktree_store.clone()
12246 }
12247}
12248
12249// Registration with registerOptions as null, should fallback to true.
12250// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12251fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12252 reg: lsp::Registration,
12253) -> Result<OneOf<bool, T>> {
12254 Ok(match reg.register_options {
12255 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12256 None => OneOf::Left(true),
12257 })
12258}
12259
12260fn subscribe_to_binary_statuses(
12261 languages: &Arc<LanguageRegistry>,
12262 cx: &mut Context<'_, LspStore>,
12263) -> Task<()> {
12264 let mut server_statuses = languages.language_server_binary_statuses();
12265 cx.spawn(async move |lsp_store, cx| {
12266 while let Some((server_name, binary_status)) = server_statuses.next().await {
12267 if lsp_store
12268 .update(cx, |_, cx| {
12269 let mut message = None;
12270 let binary_status = match binary_status {
12271 BinaryStatus::None => proto::ServerBinaryStatus::None,
12272 BinaryStatus::CheckingForUpdate => {
12273 proto::ServerBinaryStatus::CheckingForUpdate
12274 }
12275 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12276 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12277 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12278 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12279 BinaryStatus::Failed { error } => {
12280 message = Some(error);
12281 proto::ServerBinaryStatus::Failed
12282 }
12283 };
12284 cx.emit(LspStoreEvent::LanguageServerUpdate {
12285 // Binary updates are about the binary that might not have any language server id at that point.
12286 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12287 language_server_id: LanguageServerId(0),
12288 name: Some(server_name),
12289 message: proto::update_language_server::Variant::StatusUpdate(
12290 proto::StatusUpdate {
12291 message,
12292 status: Some(proto::status_update::Status::Binary(
12293 binary_status as i32,
12294 )),
12295 },
12296 ),
12297 });
12298 })
12299 .is_err()
12300 {
12301 break;
12302 }
12303 }
12304 })
12305}
12306
12307fn lsp_workspace_diagnostics_refresh(
12308 server: Arc<LanguageServer>,
12309 cx: &mut Context<'_, LspStore>,
12310) -> Option<WorkspaceRefreshTask> {
12311 let identifier = match server.capabilities().diagnostic_provider? {
12312 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12313 if !diagnostic_options.workspace_diagnostics {
12314 return None;
12315 }
12316 diagnostic_options.identifier
12317 }
12318 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12319 let diagnostic_options = registration_options.diagnostic_options;
12320 if !diagnostic_options.workspace_diagnostics {
12321 return None;
12322 }
12323 diagnostic_options.identifier
12324 }
12325 };
12326
12327 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12328 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12329 refresh_tx.try_send(()).ok();
12330
12331 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12332 let mut attempts = 0;
12333 let max_attempts = 50;
12334 let mut requests = 0;
12335
12336 loop {
12337 let Some(()) = refresh_rx.recv().await else {
12338 return;
12339 };
12340
12341 'request: loop {
12342 requests += 1;
12343 if attempts > max_attempts {
12344 log::error!(
12345 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12346 );
12347 return;
12348 }
12349 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12350 cx.background_executor()
12351 .timer(Duration::from_millis(backoff_millis))
12352 .await;
12353 attempts += 1;
12354
12355 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12356 lsp_store
12357 .all_result_ids(server.server_id())
12358 .into_iter()
12359 .filter_map(|(abs_path, result_id)| {
12360 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12361 Some(lsp::PreviousResultId {
12362 uri,
12363 value: result_id,
12364 })
12365 })
12366 .collect()
12367 }) else {
12368 return;
12369 };
12370
12371 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12372
12373 progress_rx.try_recv().ok();
12374 let timer =
12375 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12376 let progress = pin!(progress_rx.recv().fuse());
12377 let response_result = server
12378 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12379 lsp::WorkspaceDiagnosticParams {
12380 previous_result_ids,
12381 identifier: identifier.clone(),
12382 work_done_progress_params: Default::default(),
12383 partial_result_params: lsp::PartialResultParams {
12384 partial_result_token: Some(lsp::ProgressToken::String(token)),
12385 },
12386 },
12387 select(timer, progress).then(|either| match either {
12388 Either::Left((message, ..)) => ready(message).left_future(),
12389 Either::Right(..) => pending::<String>().right_future(),
12390 }),
12391 )
12392 .await;
12393
12394 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12395 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12396 match response_result {
12397 ConnectionResult::Timeout => {
12398 log::error!("Timeout during workspace diagnostics pull");
12399 continue 'request;
12400 }
12401 ConnectionResult::ConnectionReset => {
12402 log::error!("Server closed a workspace diagnostics pull request");
12403 continue 'request;
12404 }
12405 ConnectionResult::Result(Err(e)) => {
12406 log::error!("Error during workspace diagnostics pull: {e:#}");
12407 break 'request;
12408 }
12409 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12410 attempts = 0;
12411 if lsp_store
12412 .update(cx, |lsp_store, cx| {
12413 lsp_store.apply_workspace_diagnostic_report(
12414 server.server_id(),
12415 pulled_diagnostics,
12416 cx,
12417 )
12418 })
12419 .is_err()
12420 {
12421 return;
12422 }
12423 break 'request;
12424 }
12425 }
12426 }
12427 }
12428 });
12429
12430 Some(WorkspaceRefreshTask {
12431 refresh_tx,
12432 progress_tx,
12433 task: workspace_query_language_server,
12434 })
12435}
12436
12437fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12438 let CompletionSource::BufferWord {
12439 word_range,
12440 resolved,
12441 } = &mut completion.source
12442 else {
12443 return;
12444 };
12445 if *resolved {
12446 return;
12447 }
12448
12449 if completion.new_text
12450 != snapshot
12451 .text_for_range(word_range.clone())
12452 .collect::<String>()
12453 {
12454 return;
12455 }
12456
12457 let mut offset = 0;
12458 for chunk in snapshot.chunks(word_range.clone(), true) {
12459 let end_offset = offset + chunk.text.len();
12460 if let Some(highlight_id) = chunk.syntax_highlight_id {
12461 completion
12462 .label
12463 .runs
12464 .push((offset..end_offset, highlight_id));
12465 }
12466 offset = end_offset;
12467 }
12468 *resolved = true;
12469}
12470
12471impl EventEmitter<LspStoreEvent> for LspStore {}
12472
12473fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12474 hover
12475 .contents
12476 .retain(|hover_block| !hover_block.text.trim().is_empty());
12477 if hover.contents.is_empty() {
12478 None
12479 } else {
12480 Some(hover)
12481 }
12482}
12483
12484async fn populate_labels_for_completions(
12485 new_completions: Vec<CoreCompletion>,
12486 language: Option<Arc<Language>>,
12487 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12488) -> Vec<Completion> {
12489 let lsp_completions = new_completions
12490 .iter()
12491 .filter_map(|new_completion| {
12492 new_completion
12493 .source
12494 .lsp_completion(true)
12495 .map(|lsp_completion| lsp_completion.into_owned())
12496 })
12497 .collect::<Vec<_>>();
12498
12499 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12500 lsp_adapter
12501 .labels_for_completions(&lsp_completions, language)
12502 .await
12503 .log_err()
12504 .unwrap_or_default()
12505 } else {
12506 Vec::new()
12507 }
12508 .into_iter()
12509 .fuse();
12510
12511 let mut completions = Vec::new();
12512 for completion in new_completions {
12513 match completion.source.lsp_completion(true) {
12514 Some(lsp_completion) => {
12515 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12516
12517 let mut label = labels.next().flatten().unwrap_or_else(|| {
12518 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12519 });
12520 ensure_uniform_list_compatible_label(&mut label);
12521 completions.push(Completion {
12522 label,
12523 documentation,
12524 replace_range: completion.replace_range,
12525 new_text: completion.new_text,
12526 insert_text_mode: lsp_completion.insert_text_mode,
12527 source: completion.source,
12528 icon_path: None,
12529 confirm: None,
12530 });
12531 }
12532 None => {
12533 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12534 ensure_uniform_list_compatible_label(&mut label);
12535 completions.push(Completion {
12536 label,
12537 documentation: None,
12538 replace_range: completion.replace_range,
12539 new_text: completion.new_text,
12540 source: completion.source,
12541 insert_text_mode: None,
12542 icon_path: None,
12543 confirm: None,
12544 });
12545 }
12546 }
12547 }
12548 completions
12549}
12550
12551#[derive(Debug)]
12552pub enum LanguageServerToQuery {
12553 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12554 FirstCapable,
12555 /// Query a specific language server.
12556 Other(LanguageServerId),
12557}
12558
12559#[derive(Default)]
12560struct RenamePathsWatchedForServer {
12561 did_rename: Vec<RenameActionPredicate>,
12562 will_rename: Vec<RenameActionPredicate>,
12563}
12564
12565impl RenamePathsWatchedForServer {
12566 fn with_did_rename_patterns(
12567 mut self,
12568 did_rename: Option<&FileOperationRegistrationOptions>,
12569 ) -> Self {
12570 if let Some(did_rename) = did_rename {
12571 self.did_rename = did_rename
12572 .filters
12573 .iter()
12574 .filter_map(|filter| filter.try_into().log_err())
12575 .collect();
12576 }
12577 self
12578 }
12579 fn with_will_rename_patterns(
12580 mut self,
12581 will_rename: Option<&FileOperationRegistrationOptions>,
12582 ) -> Self {
12583 if let Some(will_rename) = will_rename {
12584 self.will_rename = will_rename
12585 .filters
12586 .iter()
12587 .filter_map(|filter| filter.try_into().log_err())
12588 .collect();
12589 }
12590 self
12591 }
12592
12593 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12594 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12595 }
12596 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12597 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12598 }
12599}
12600
12601impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12602 type Error = globset::Error;
12603 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12604 Ok(Self {
12605 kind: ops.pattern.matches.clone(),
12606 glob: GlobBuilder::new(&ops.pattern.glob)
12607 .case_insensitive(
12608 ops.pattern
12609 .options
12610 .as_ref()
12611 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12612 )
12613 .build()?
12614 .compile_matcher(),
12615 })
12616 }
12617}
12618struct RenameActionPredicate {
12619 glob: GlobMatcher,
12620 kind: Option<FileOperationPatternKind>,
12621}
12622
12623impl RenameActionPredicate {
12624 // Returns true if language server should be notified
12625 fn eval(&self, path: &str, is_dir: bool) -> bool {
12626 self.kind.as_ref().is_none_or(|kind| {
12627 let expected_kind = if is_dir {
12628 FileOperationPatternKind::Folder
12629 } else {
12630 FileOperationPatternKind::File
12631 };
12632 kind == &expected_kind
12633 }) && self.glob.is_match(path)
12634 }
12635}
12636
12637#[derive(Default)]
12638struct LanguageServerWatchedPaths {
12639 worktree_paths: HashMap<WorktreeId, GlobSet>,
12640 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12641}
12642
12643#[derive(Default)]
12644struct LanguageServerWatchedPathsBuilder {
12645 worktree_paths: HashMap<WorktreeId, GlobSet>,
12646 abs_paths: HashMap<Arc<Path>, GlobSet>,
12647}
12648
12649impl LanguageServerWatchedPathsBuilder {
12650 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12651 self.worktree_paths.insert(worktree_id, glob_set);
12652 }
12653 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12654 self.abs_paths.insert(path, glob_set);
12655 }
12656 fn build(
12657 self,
12658 fs: Arc<dyn Fs>,
12659 language_server_id: LanguageServerId,
12660 cx: &mut Context<LspStore>,
12661 ) -> LanguageServerWatchedPaths {
12662 let project = cx.weak_entity();
12663
12664 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12665 let abs_paths = self
12666 .abs_paths
12667 .into_iter()
12668 .map(|(abs_path, globset)| {
12669 let task = cx.spawn({
12670 let abs_path = abs_path.clone();
12671 let fs = fs.clone();
12672
12673 let lsp_store = project.clone();
12674 async move |_, cx| {
12675 maybe!(async move {
12676 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12677 while let Some(update) = push_updates.0.next().await {
12678 let action = lsp_store
12679 .update(cx, |this, _| {
12680 let Some(local) = this.as_local() else {
12681 return ControlFlow::Break(());
12682 };
12683 let Some(watcher) = local
12684 .language_server_watched_paths
12685 .get(&language_server_id)
12686 else {
12687 return ControlFlow::Break(());
12688 };
12689 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12690 "Watched abs path is not registered with a watcher",
12691 );
12692 let matching_entries = update
12693 .into_iter()
12694 .filter(|event| globs.is_match(&event.path))
12695 .collect::<Vec<_>>();
12696 this.lsp_notify_abs_paths_changed(
12697 language_server_id,
12698 matching_entries,
12699 );
12700 ControlFlow::Continue(())
12701 })
12702 .ok()?;
12703
12704 if action.is_break() {
12705 break;
12706 }
12707 }
12708 Some(())
12709 })
12710 .await;
12711 }
12712 });
12713 (abs_path, (globset, task))
12714 })
12715 .collect();
12716 LanguageServerWatchedPaths {
12717 worktree_paths: self.worktree_paths,
12718 abs_paths,
12719 }
12720 }
12721}
12722
12723struct LspBufferSnapshot {
12724 version: i32,
12725 snapshot: TextBufferSnapshot,
12726}
12727
12728/// A prompt requested by LSP server.
12729#[derive(Clone, Debug)]
12730pub struct LanguageServerPromptRequest {
12731 pub level: PromptLevel,
12732 pub message: String,
12733 pub actions: Vec<MessageActionItem>,
12734 pub lsp_name: String,
12735 pub(crate) response_channel: Sender<MessageActionItem>,
12736}
12737
12738impl LanguageServerPromptRequest {
12739 pub async fn respond(self, index: usize) -> Option<()> {
12740 if let Some(response) = self.actions.into_iter().nth(index) {
12741 self.response_channel.send(response).await.ok()
12742 } else {
12743 None
12744 }
12745 }
12746}
12747impl PartialEq for LanguageServerPromptRequest {
12748 fn eq(&self, other: &Self) -> bool {
12749 self.message == other.message && self.actions == other.actions
12750 }
12751}
12752
12753#[derive(Clone, Debug, PartialEq)]
12754pub enum LanguageServerLogType {
12755 Log(MessageType),
12756 Trace { verbose_info: Option<String> },
12757 Rpc { received: bool },
12758}
12759
12760impl LanguageServerLogType {
12761 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12762 match self {
12763 Self::Log(log_type) => {
12764 use proto::log_message::LogLevel;
12765 let level = match *log_type {
12766 MessageType::ERROR => LogLevel::Error,
12767 MessageType::WARNING => LogLevel::Warning,
12768 MessageType::INFO => LogLevel::Info,
12769 MessageType::LOG => LogLevel::Log,
12770 other => {
12771 log::warn!("Unknown lsp log message type: {other:?}");
12772 LogLevel::Log
12773 }
12774 };
12775 proto::language_server_log::LogType::Log(proto::LogMessage {
12776 level: level as i32,
12777 })
12778 }
12779 Self::Trace { verbose_info } => {
12780 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12781 verbose_info: verbose_info.to_owned(),
12782 })
12783 }
12784 Self::Rpc { received } => {
12785 let kind = if *received {
12786 proto::rpc_message::Kind::Received
12787 } else {
12788 proto::rpc_message::Kind::Sent
12789 };
12790 let kind = kind as i32;
12791 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12792 }
12793 }
12794 }
12795
12796 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12797 use proto::log_message::LogLevel;
12798 use proto::rpc_message;
12799 match log_type {
12800 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12801 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12802 LogLevel::Error => MessageType::ERROR,
12803 LogLevel::Warning => MessageType::WARNING,
12804 LogLevel::Info => MessageType::INFO,
12805 LogLevel::Log => MessageType::LOG,
12806 },
12807 ),
12808 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12809 verbose_info: trace_message.verbose_info,
12810 },
12811 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12812 received: match rpc_message::Kind::from_i32(message.kind)
12813 .unwrap_or(rpc_message::Kind::Received)
12814 {
12815 rpc_message::Kind::Received => true,
12816 rpc_message::Kind::Sent => false,
12817 },
12818 },
12819 }
12820 }
12821}
12822
12823pub struct WorkspaceRefreshTask {
12824 refresh_tx: mpsc::Sender<()>,
12825 progress_tx: mpsc::Sender<()>,
12826 #[allow(dead_code)]
12827 task: Task<()>,
12828}
12829
12830pub enum LanguageServerState {
12831 Starting {
12832 startup: Task<Option<Arc<LanguageServer>>>,
12833 /// List of language servers that will be added to the workspace once it's initialization completes.
12834 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12835 },
12836
12837 Running {
12838 adapter: Arc<CachedLspAdapter>,
12839 server: Arc<LanguageServer>,
12840 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12841 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12842 },
12843}
12844
12845impl LanguageServerState {
12846 fn add_workspace_folder(&self, uri: Uri) {
12847 match self {
12848 LanguageServerState::Starting {
12849 pending_workspace_folders,
12850 ..
12851 } => {
12852 pending_workspace_folders.lock().insert(uri);
12853 }
12854 LanguageServerState::Running { server, .. } => {
12855 server.add_workspace_folder(uri);
12856 }
12857 }
12858 }
12859 fn _remove_workspace_folder(&self, uri: Uri) {
12860 match self {
12861 LanguageServerState::Starting {
12862 pending_workspace_folders,
12863 ..
12864 } => {
12865 pending_workspace_folders.lock().remove(&uri);
12866 }
12867 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12868 }
12869 }
12870}
12871
12872impl std::fmt::Debug for LanguageServerState {
12873 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12874 match self {
12875 LanguageServerState::Starting { .. } => {
12876 f.debug_struct("LanguageServerState::Starting").finish()
12877 }
12878 LanguageServerState::Running { .. } => {
12879 f.debug_struct("LanguageServerState::Running").finish()
12880 }
12881 }
12882 }
12883}
12884
12885#[derive(Clone, Debug, Serialize)]
12886pub struct LanguageServerProgress {
12887 pub is_disk_based_diagnostics_progress: bool,
12888 pub is_cancellable: bool,
12889 pub title: Option<String>,
12890 pub message: Option<String>,
12891 pub percentage: Option<usize>,
12892 #[serde(skip_serializing)]
12893 pub last_update_at: Instant,
12894}
12895
12896#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12897pub struct DiagnosticSummary {
12898 pub error_count: usize,
12899 pub warning_count: usize,
12900}
12901
12902impl DiagnosticSummary {
12903 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12904 let mut this = Self {
12905 error_count: 0,
12906 warning_count: 0,
12907 };
12908
12909 for entry in diagnostics {
12910 if entry.diagnostic.is_primary {
12911 match entry.diagnostic.severity {
12912 DiagnosticSeverity::ERROR => this.error_count += 1,
12913 DiagnosticSeverity::WARNING => this.warning_count += 1,
12914 _ => {}
12915 }
12916 }
12917 }
12918
12919 this
12920 }
12921
12922 pub fn is_empty(&self) -> bool {
12923 self.error_count == 0 && self.warning_count == 0
12924 }
12925
12926 pub fn to_proto(
12927 self,
12928 language_server_id: LanguageServerId,
12929 path: &Path,
12930 ) -> proto::DiagnosticSummary {
12931 proto::DiagnosticSummary {
12932 path: path.to_proto(),
12933 language_server_id: language_server_id.0 as u64,
12934 error_count: self.error_count as u32,
12935 warning_count: self.warning_count as u32,
12936 }
12937 }
12938}
12939
12940#[derive(Clone, Debug)]
12941pub enum CompletionDocumentation {
12942 /// There is no documentation for this completion.
12943 Undocumented,
12944 /// A single line of documentation.
12945 SingleLine(SharedString),
12946 /// Multiple lines of plain text documentation.
12947 MultiLinePlainText(SharedString),
12948 /// Markdown documentation.
12949 MultiLineMarkdown(SharedString),
12950 /// Both single line and multiple lines of plain text documentation.
12951 SingleLineAndMultiLinePlainText {
12952 single_line: SharedString,
12953 plain_text: Option<SharedString>,
12954 },
12955}
12956
12957impl CompletionDocumentation {
12958 #[cfg(any(test, feature = "test-support"))]
12959 pub fn text(&self) -> SharedString {
12960 match self {
12961 CompletionDocumentation::Undocumented => "".into(),
12962 CompletionDocumentation::SingleLine(s) => s.clone(),
12963 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
12964 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
12965 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
12966 single_line.clone()
12967 }
12968 }
12969 }
12970}
12971
12972impl From<lsp::Documentation> for CompletionDocumentation {
12973 fn from(docs: lsp::Documentation) -> Self {
12974 match docs {
12975 lsp::Documentation::String(text) => {
12976 if text.lines().count() <= 1 {
12977 CompletionDocumentation::SingleLine(text.into())
12978 } else {
12979 CompletionDocumentation::MultiLinePlainText(text.into())
12980 }
12981 }
12982
12983 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12984 lsp::MarkupKind::PlainText => {
12985 if value.lines().count() <= 1 {
12986 CompletionDocumentation::SingleLine(value.into())
12987 } else {
12988 CompletionDocumentation::MultiLinePlainText(value.into())
12989 }
12990 }
12991
12992 lsp::MarkupKind::Markdown => {
12993 CompletionDocumentation::MultiLineMarkdown(value.into())
12994 }
12995 },
12996 }
12997 }
12998}
12999
13000fn glob_literal_prefix(glob: &Path) -> PathBuf {
13001 glob.components()
13002 .take_while(|component| match component {
13003 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13004 _ => true,
13005 })
13006 .collect()
13007}
13008
13009pub struct SshLspAdapter {
13010 name: LanguageServerName,
13011 binary: LanguageServerBinary,
13012 initialization_options: Option<String>,
13013 code_action_kinds: Option<Vec<CodeActionKind>>,
13014}
13015
13016impl SshLspAdapter {
13017 pub fn new(
13018 name: LanguageServerName,
13019 binary: LanguageServerBinary,
13020 initialization_options: Option<String>,
13021 code_action_kinds: Option<String>,
13022 ) -> Self {
13023 Self {
13024 name,
13025 binary,
13026 initialization_options,
13027 code_action_kinds: code_action_kinds
13028 .as_ref()
13029 .and_then(|c| serde_json::from_str(c).ok()),
13030 }
13031 }
13032}
13033
13034#[async_trait(?Send)]
13035impl LspAdapter for SshLspAdapter {
13036 fn name(&self) -> LanguageServerName {
13037 self.name.clone()
13038 }
13039
13040 async fn initialization_options(
13041 self: Arc<Self>,
13042 _: &dyn Fs,
13043 _: &Arc<dyn LspAdapterDelegate>,
13044 ) -> Result<Option<serde_json::Value>> {
13045 let Some(options) = &self.initialization_options else {
13046 return Ok(None);
13047 };
13048 let result = serde_json::from_str(options)?;
13049 Ok(result)
13050 }
13051
13052 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13053 self.code_action_kinds.clone()
13054 }
13055
13056 async fn check_if_user_installed(
13057 &self,
13058 _: &dyn LspAdapterDelegate,
13059 _: Option<Toolchain>,
13060 _: &AsyncApp,
13061 ) -> Option<LanguageServerBinary> {
13062 Some(self.binary.clone())
13063 }
13064
13065 async fn cached_server_binary(
13066 &self,
13067 _: PathBuf,
13068 _: &dyn LspAdapterDelegate,
13069 ) -> Option<LanguageServerBinary> {
13070 None
13071 }
13072
13073 async fn fetch_latest_server_version(
13074 &self,
13075 _: &dyn LspAdapterDelegate,
13076 ) -> Result<Box<dyn 'static + Send + Any>> {
13077 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13078 }
13079
13080 async fn fetch_server_binary(
13081 &self,
13082 _: Box<dyn 'static + Send + Any>,
13083 _: PathBuf,
13084 _: &dyn LspAdapterDelegate,
13085 ) -> Result<LanguageServerBinary> {
13086 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13087 }
13088}
13089
13090pub fn language_server_settings<'a>(
13091 delegate: &'a dyn LspAdapterDelegate,
13092 language: &LanguageServerName,
13093 cx: &'a App,
13094) -> Option<&'a LspSettings> {
13095 language_server_settings_for(
13096 SettingsLocation {
13097 worktree_id: delegate.worktree_id(),
13098 path: delegate.worktree_root_path(),
13099 },
13100 language,
13101 cx,
13102 )
13103}
13104
13105pub(crate) fn language_server_settings_for<'a>(
13106 location: SettingsLocation<'a>,
13107 language: &LanguageServerName,
13108 cx: &'a App,
13109) -> Option<&'a LspSettings> {
13110 ProjectSettings::get(Some(location), cx).lsp.get(language)
13111}
13112
13113pub struct LocalLspAdapterDelegate {
13114 lsp_store: WeakEntity<LspStore>,
13115 worktree: worktree::Snapshot,
13116 fs: Arc<dyn Fs>,
13117 http_client: Arc<dyn HttpClient>,
13118 language_registry: Arc<LanguageRegistry>,
13119 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13120}
13121
13122impl LocalLspAdapterDelegate {
13123 pub fn new(
13124 language_registry: Arc<LanguageRegistry>,
13125 environment: &Entity<ProjectEnvironment>,
13126 lsp_store: WeakEntity<LspStore>,
13127 worktree: &Entity<Worktree>,
13128 http_client: Arc<dyn HttpClient>,
13129 fs: Arc<dyn Fs>,
13130 cx: &mut App,
13131 ) -> Arc<Self> {
13132 let load_shell_env_task = environment.update(cx, |env, cx| {
13133 env.get_worktree_environment(worktree.clone(), cx)
13134 });
13135
13136 Arc::new(Self {
13137 lsp_store,
13138 worktree: worktree.read(cx).snapshot(),
13139 fs,
13140 http_client,
13141 language_registry,
13142 load_shell_env_task,
13143 })
13144 }
13145
13146 fn from_local_lsp(
13147 local: &LocalLspStore,
13148 worktree: &Entity<Worktree>,
13149 cx: &mut App,
13150 ) -> Arc<Self> {
13151 Self::new(
13152 local.languages.clone(),
13153 &local.environment,
13154 local.weak.clone(),
13155 worktree,
13156 local.http_client.clone(),
13157 local.fs.clone(),
13158 cx,
13159 )
13160 }
13161}
13162
13163#[async_trait]
13164impl LspAdapterDelegate for LocalLspAdapterDelegate {
13165 fn show_notification(&self, message: &str, cx: &mut App) {
13166 self.lsp_store
13167 .update(cx, |_, cx| {
13168 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13169 })
13170 .ok();
13171 }
13172
13173 fn http_client(&self) -> Arc<dyn HttpClient> {
13174 self.http_client.clone()
13175 }
13176
13177 fn worktree_id(&self) -> WorktreeId {
13178 self.worktree.id()
13179 }
13180
13181 fn worktree_root_path(&self) -> &Path {
13182 self.worktree.abs_path().as_ref()
13183 }
13184
13185 async fn shell_env(&self) -> HashMap<String, String> {
13186 let task = self.load_shell_env_task.clone();
13187 task.await.unwrap_or_default()
13188 }
13189
13190 async fn npm_package_installed_version(
13191 &self,
13192 package_name: &str,
13193 ) -> Result<Option<(PathBuf, String)>> {
13194 let local_package_directory = self.worktree_root_path();
13195 let node_modules_directory = local_package_directory.join("node_modules");
13196
13197 if let Some(version) =
13198 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13199 {
13200 return Ok(Some((node_modules_directory, version)));
13201 }
13202 let Some(npm) = self.which("npm".as_ref()).await else {
13203 log::warn!(
13204 "Failed to find npm executable for {:?}",
13205 local_package_directory
13206 );
13207 return Ok(None);
13208 };
13209
13210 let env = self.shell_env().await;
13211 let output = util::command::new_smol_command(&npm)
13212 .args(["root", "-g"])
13213 .envs(env)
13214 .current_dir(local_package_directory)
13215 .output()
13216 .await?;
13217 let global_node_modules =
13218 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13219
13220 if let Some(version) =
13221 read_package_installed_version(global_node_modules.clone(), package_name).await?
13222 {
13223 return Ok(Some((global_node_modules, version)));
13224 }
13225 return Ok(None);
13226 }
13227
13228 #[cfg(not(target_os = "windows"))]
13229 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13230 let worktree_abs_path = self.worktree.abs_path();
13231 let shell_path = self.shell_env().await.get("PATH").cloned();
13232 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13233 }
13234
13235 #[cfg(target_os = "windows")]
13236 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13237 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
13238 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
13239 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
13240 which::which(command).ok()
13241 }
13242
13243 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13244 let working_dir = self.worktree_root_path();
13245 let output = util::command::new_smol_command(&command.path)
13246 .args(command.arguments)
13247 .envs(command.env.clone().unwrap_or_default())
13248 .current_dir(working_dir)
13249 .output()
13250 .await?;
13251
13252 anyhow::ensure!(
13253 output.status.success(),
13254 "{}, stdout: {:?}, stderr: {:?}",
13255 output.status,
13256 String::from_utf8_lossy(&output.stdout),
13257 String::from_utf8_lossy(&output.stderr)
13258 );
13259 Ok(())
13260 }
13261
13262 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13263 self.language_registry
13264 .update_lsp_binary_status(server_name, status);
13265 }
13266
13267 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13268 self.language_registry
13269 .all_lsp_adapters()
13270 .into_iter()
13271 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13272 .collect()
13273 }
13274
13275 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13276 let dir = self.language_registry.language_server_download_dir(name)?;
13277
13278 if !dir.exists() {
13279 smol::fs::create_dir_all(&dir)
13280 .await
13281 .context("failed to create container directory")
13282 .log_err()?;
13283 }
13284
13285 Some(dir)
13286 }
13287
13288 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
13289 let entry = self
13290 .worktree
13291 .entry_for_path(&path)
13292 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13293 let abs_path = self
13294 .worktree
13295 .absolutize(&entry.path)
13296 .with_context(|| format!("cannot absolutize path {path:?}"))?;
13297
13298 self.fs.load(&abs_path).await
13299 }
13300}
13301
13302async fn populate_labels_for_symbols(
13303 symbols: Vec<CoreSymbol>,
13304 language_registry: &Arc<LanguageRegistry>,
13305 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13306 output: &mut Vec<Symbol>,
13307) {
13308 #[allow(clippy::mutable_key_type)]
13309 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13310
13311 let mut unknown_paths = BTreeSet::new();
13312 for symbol in symbols {
13313 let language = language_registry
13314 .language_for_file_path(&symbol.path.path)
13315 .await
13316 .ok()
13317 .or_else(|| {
13318 unknown_paths.insert(symbol.path.path.clone());
13319 None
13320 });
13321 symbols_by_language
13322 .entry(language)
13323 .or_default()
13324 .push(symbol);
13325 }
13326
13327 for unknown_path in unknown_paths {
13328 log::info!(
13329 "no language found for symbol path {}",
13330 unknown_path.display()
13331 );
13332 }
13333
13334 let mut label_params = Vec::new();
13335 for (language, mut symbols) in symbols_by_language {
13336 label_params.clear();
13337 label_params.extend(
13338 symbols
13339 .iter_mut()
13340 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13341 );
13342
13343 let mut labels = Vec::new();
13344 if let Some(language) = language {
13345 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13346 language_registry
13347 .lsp_adapters(&language.name())
13348 .first()
13349 .cloned()
13350 });
13351 if let Some(lsp_adapter) = lsp_adapter {
13352 labels = lsp_adapter
13353 .labels_for_symbols(&label_params, &language)
13354 .await
13355 .log_err()
13356 .unwrap_or_default();
13357 }
13358 }
13359
13360 for ((symbol, (name, _)), label) in symbols
13361 .into_iter()
13362 .zip(label_params.drain(..))
13363 .zip(labels.into_iter().chain(iter::repeat(None)))
13364 {
13365 output.push(Symbol {
13366 language_server_name: symbol.language_server_name,
13367 source_worktree_id: symbol.source_worktree_id,
13368 source_language_server_id: symbol.source_language_server_id,
13369 path: symbol.path,
13370 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13371 name,
13372 kind: symbol.kind,
13373 range: symbol.range,
13374 signature: symbol.signature,
13375 });
13376 }
13377 }
13378}
13379
13380fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13381 match server.capabilities().text_document_sync.as_ref()? {
13382 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13383 // Server wants didSave but didn't specify includeText.
13384 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13385 // Server doesn't want didSave at all.
13386 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13387 // Server provided SaveOptions.
13388 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13389 Some(save_options.include_text.unwrap_or(false))
13390 }
13391 },
13392 // We do not have any save info. Kind affects didChange only.
13393 lsp::TextDocumentSyncCapability::Kind(_) => None,
13394 }
13395}
13396
13397/// Completion items are displayed in a `UniformList`.
13398/// Usually, those items are single-line strings, but in LSP responses,
13399/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13400/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13401/// 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,
13402/// breaking the completions menu presentation.
13403///
13404/// 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.
13405fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13406 let mut new_text = String::with_capacity(label.text.len());
13407 let mut offset_map = vec![0; label.text.len() + 1];
13408 let mut last_char_was_space = false;
13409 let mut new_idx = 0;
13410 let chars = label.text.char_indices().fuse();
13411 let mut newlines_removed = false;
13412
13413 for (idx, c) in chars {
13414 offset_map[idx] = new_idx;
13415
13416 match c {
13417 '\n' if last_char_was_space => {
13418 newlines_removed = true;
13419 }
13420 '\t' | ' ' if last_char_was_space => {}
13421 '\n' if !last_char_was_space => {
13422 new_text.push(' ');
13423 new_idx += 1;
13424 last_char_was_space = true;
13425 newlines_removed = true;
13426 }
13427 ' ' | '\t' => {
13428 new_text.push(' ');
13429 new_idx += 1;
13430 last_char_was_space = true;
13431 }
13432 _ => {
13433 new_text.push(c);
13434 new_idx += c.len_utf8();
13435 last_char_was_space = false;
13436 }
13437 }
13438 }
13439 offset_map[label.text.len()] = new_idx;
13440
13441 // Only modify the label if newlines were removed.
13442 if !newlines_removed {
13443 return;
13444 }
13445
13446 let last_index = new_idx;
13447 let mut run_ranges_errors = Vec::new();
13448 label.runs.retain_mut(|(range, _)| {
13449 match offset_map.get(range.start) {
13450 Some(&start) => range.start = start,
13451 None => {
13452 run_ranges_errors.push(range.clone());
13453 return false;
13454 }
13455 }
13456
13457 match offset_map.get(range.end) {
13458 Some(&end) => range.end = end,
13459 None => {
13460 run_ranges_errors.push(range.clone());
13461 range.end = last_index;
13462 }
13463 }
13464 true
13465 });
13466 if !run_ranges_errors.is_empty() {
13467 log::error!(
13468 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13469 label.text
13470 );
13471 }
13472
13473 let mut wrong_filter_range = None;
13474 if label.filter_range == (0..label.text.len()) {
13475 label.filter_range = 0..new_text.len();
13476 } else {
13477 let mut original_filter_range = Some(label.filter_range.clone());
13478 match offset_map.get(label.filter_range.start) {
13479 Some(&start) => label.filter_range.start = start,
13480 None => {
13481 wrong_filter_range = original_filter_range.take();
13482 label.filter_range.start = last_index;
13483 }
13484 }
13485
13486 match offset_map.get(label.filter_range.end) {
13487 Some(&end) => label.filter_range.end = end,
13488 None => {
13489 wrong_filter_range = original_filter_range.take();
13490 label.filter_range.end = last_index;
13491 }
13492 }
13493 }
13494 if let Some(wrong_filter_range) = wrong_filter_range {
13495 log::error!(
13496 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13497 label.text
13498 );
13499 }
13500
13501 label.text = new_text;
13502}
13503
13504#[cfg(test)]
13505mod tests {
13506 use language::HighlightId;
13507
13508 use super::*;
13509
13510 #[test]
13511 fn test_glob_literal_prefix() {
13512 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13513 assert_eq!(
13514 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13515 Path::new("node_modules")
13516 );
13517 assert_eq!(
13518 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13519 Path::new("foo")
13520 );
13521 assert_eq!(
13522 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13523 Path::new("foo/bar/baz.js")
13524 );
13525
13526 #[cfg(target_os = "windows")]
13527 {
13528 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13529 assert_eq!(
13530 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13531 Path::new("node_modules")
13532 );
13533 assert_eq!(
13534 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13535 Path::new("foo")
13536 );
13537 assert_eq!(
13538 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13539 Path::new("foo/bar/baz.js")
13540 );
13541 }
13542 }
13543
13544 #[test]
13545 fn test_multi_len_chars_normalization() {
13546 let mut label = CodeLabel {
13547 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13548 runs: vec![(0..6, HighlightId(1))],
13549 filter_range: 0..6,
13550 };
13551 ensure_uniform_list_compatible_label(&mut label);
13552 assert_eq!(
13553 label,
13554 CodeLabel {
13555 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13556 runs: vec![(0..6, HighlightId(1))],
13557 filter_range: 0..6,
13558 }
13559 );
13560 }
13561}