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