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