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