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