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