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