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