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