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