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