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