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