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