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