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