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