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