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 UnsavedBufferEdit(Entity<Buffer>),
3559}
3560
3561#[derive(Clone, Debug, Serialize)]
3562pub struct LanguageServerStatus {
3563 pub name: LanguageServerName,
3564 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3565 pub has_pending_diagnostic_updates: bool,
3566 progress_tokens: HashSet<String>,
3567}
3568
3569#[derive(Clone, Debug)]
3570struct CoreSymbol {
3571 pub language_server_name: LanguageServerName,
3572 pub source_worktree_id: WorktreeId,
3573 pub source_language_server_id: LanguageServerId,
3574 pub path: ProjectPath,
3575 pub name: String,
3576 pub kind: lsp::SymbolKind,
3577 pub range: Range<Unclipped<PointUtf16>>,
3578 pub signature: [u8; 32],
3579}
3580
3581impl LspStore {
3582 pub fn init(client: &AnyProtoClient) {
3583 client.add_entity_request_handler(Self::handle_multi_lsp_query);
3584 client.add_entity_request_handler(Self::handle_restart_language_servers);
3585 client.add_entity_request_handler(Self::handle_stop_language_servers);
3586 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3587 client.add_entity_message_handler(Self::handle_start_language_server);
3588 client.add_entity_message_handler(Self::handle_update_language_server);
3589 client.add_entity_message_handler(Self::handle_language_server_log);
3590 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3591 client.add_entity_request_handler(Self::handle_format_buffers);
3592 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3593 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3594 client.add_entity_request_handler(Self::handle_apply_code_action);
3595 client.add_entity_request_handler(Self::handle_inlay_hints);
3596 client.add_entity_request_handler(Self::handle_get_project_symbols);
3597 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3598 client.add_entity_request_handler(Self::handle_get_color_presentation);
3599 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3600 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3601 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3602 client.add_entity_request_handler(Self::handle_on_type_formatting);
3603 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3604 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3605 client.add_entity_request_handler(Self::handle_rename_project_entry);
3606 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3607 client.add_entity_request_handler(Self::handle_lsp_command::<GetCodeActions>);
3608 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3609 client.add_entity_request_handler(Self::handle_lsp_command::<GetHover>);
3610 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3611 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3612 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3613 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3614 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3615
3616 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3617 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3618 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3619 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3620 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3621 client.add_entity_request_handler(
3622 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3623 );
3624 client.add_entity_request_handler(
3625 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3626 );
3627 client.add_entity_request_handler(
3628 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3629 );
3630 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentDiagnostics>);
3631 }
3632
3633 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3634 match &self.mode {
3635 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3636 _ => None,
3637 }
3638 }
3639
3640 pub fn as_local(&self) -> Option<&LocalLspStore> {
3641 match &self.mode {
3642 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3643 _ => None,
3644 }
3645 }
3646
3647 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3648 match &mut self.mode {
3649 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3650 _ => None,
3651 }
3652 }
3653
3654 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3655 match &self.mode {
3656 LspStoreMode::Remote(RemoteLspStore {
3657 upstream_client: Some(upstream_client),
3658 upstream_project_id,
3659 ..
3660 }) => Some((upstream_client.clone(), *upstream_project_id)),
3661
3662 LspStoreMode::Remote(RemoteLspStore {
3663 upstream_client: None,
3664 ..
3665 }) => None,
3666 LspStoreMode::Local(_) => None,
3667 }
3668 }
3669
3670 pub fn new_local(
3671 buffer_store: Entity<BufferStore>,
3672 worktree_store: Entity<WorktreeStore>,
3673 prettier_store: Entity<PrettierStore>,
3674 toolchain_store: Entity<LocalToolchainStore>,
3675 environment: Entity<ProjectEnvironment>,
3676 manifest_tree: Entity<ManifestTree>,
3677 languages: Arc<LanguageRegistry>,
3678 http_client: Arc<dyn HttpClient>,
3679 fs: Arc<dyn Fs>,
3680 cx: &mut Context<Self>,
3681 ) -> Self {
3682 let yarn = YarnPathStore::new(fs.clone(), cx);
3683 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3684 .detach();
3685 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3686 .detach();
3687 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3688 .detach();
3689 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3690 .detach();
3691 if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
3692 cx.subscribe(
3693 extension_events,
3694 Self::reload_zed_json_schemas_on_extensions_changed,
3695 )
3696 .detach();
3697 } else {
3698 log::debug!("No extension events global found. Skipping JSON schema auto-reload setup");
3699 }
3700 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3701 .detach();
3702 subscribe_to_binary_statuses(&languages, cx).detach();
3703
3704 let _maintain_workspace_config = {
3705 let (sender, receiver) = watch::channel();
3706 (
3707 Self::maintain_workspace_config(fs.clone(), receiver, cx),
3708 sender,
3709 )
3710 };
3711
3712 Self {
3713 mode: LspStoreMode::Local(LocalLspStore {
3714 weak: cx.weak_entity(),
3715 worktree_store: worktree_store.clone(),
3716
3717 supplementary_language_servers: Default::default(),
3718 languages: languages.clone(),
3719 language_server_ids: Default::default(),
3720 language_servers: Default::default(),
3721 last_workspace_edits_by_language_server: Default::default(),
3722 language_server_watched_paths: Default::default(),
3723 language_server_paths_watched_for_rename: Default::default(),
3724 language_server_watcher_registrations: Default::default(),
3725 buffers_being_formatted: Default::default(),
3726 buffer_snapshots: Default::default(),
3727 prettier_store,
3728 environment,
3729 http_client,
3730 fs,
3731 yarn,
3732 next_diagnostic_group_id: Default::default(),
3733 diagnostics: Default::default(),
3734 _subscription: cx.on_app_quit(|this, cx| {
3735 this.as_local_mut()
3736 .unwrap()
3737 .shutdown_language_servers_on_quit(cx)
3738 }),
3739 lsp_tree: LanguageServerTree::new(
3740 manifest_tree,
3741 languages.clone(),
3742 toolchain_store.clone(),
3743 ),
3744 toolchain_store,
3745 registered_buffers: HashMap::default(),
3746 buffers_opened_in_servers: HashMap::default(),
3747 buffer_pull_diagnostics_result_ids: HashMap::default(),
3748 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3749 .manifest_file_names(),
3750 }),
3751 last_formatting_failure: None,
3752 downstream_client: None,
3753 buffer_store,
3754 worktree_store,
3755 languages: languages.clone(),
3756 language_server_statuses: Default::default(),
3757 nonce: StdRng::from_entropy().r#gen(),
3758 diagnostic_summaries: HashMap::default(),
3759 lsp_server_capabilities: HashMap::default(),
3760 lsp_document_colors: HashMap::default(),
3761 lsp_code_lens: HashMap::default(),
3762 active_entry: None,
3763 _maintain_workspace_config,
3764 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3765 }
3766 }
3767
3768 fn send_lsp_proto_request<R: LspCommand>(
3769 &self,
3770 buffer: Entity<Buffer>,
3771 client: AnyProtoClient,
3772 upstream_project_id: u64,
3773 request: R,
3774 cx: &mut Context<LspStore>,
3775 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3776 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3777 return Task::ready(Ok(R::Response::default()));
3778 }
3779 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3780 cx.spawn(async move |this, cx| {
3781 let response = client.request(message).await?;
3782 let this = this.upgrade().context("project dropped")?;
3783 request
3784 .response_from_proto(response, this, buffer, cx.clone())
3785 .await
3786 })
3787 }
3788
3789 pub(super) fn new_remote(
3790 buffer_store: Entity<BufferStore>,
3791 worktree_store: Entity<WorktreeStore>,
3792 languages: Arc<LanguageRegistry>,
3793 upstream_client: AnyProtoClient,
3794 project_id: u64,
3795 fs: Arc<dyn Fs>,
3796 cx: &mut Context<Self>,
3797 ) -> Self {
3798 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3799 .detach();
3800 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3801 .detach();
3802 subscribe_to_binary_statuses(&languages, cx).detach();
3803 let _maintain_workspace_config = {
3804 let (sender, receiver) = watch::channel();
3805 (Self::maintain_workspace_config(fs, receiver, cx), sender)
3806 };
3807 Self {
3808 mode: LspStoreMode::Remote(RemoteLspStore {
3809 upstream_client: Some(upstream_client),
3810 upstream_project_id: project_id,
3811 }),
3812 downstream_client: None,
3813 last_formatting_failure: None,
3814 buffer_store,
3815 worktree_store,
3816 languages: languages.clone(),
3817 language_server_statuses: Default::default(),
3818 nonce: StdRng::from_entropy().r#gen(),
3819 diagnostic_summaries: HashMap::default(),
3820 lsp_server_capabilities: HashMap::default(),
3821 lsp_document_colors: HashMap::default(),
3822 lsp_code_lens: HashMap::default(),
3823 active_entry: None,
3824
3825 _maintain_workspace_config,
3826 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3827 }
3828 }
3829
3830 fn on_buffer_store_event(
3831 &mut self,
3832 _: Entity<BufferStore>,
3833 event: &BufferStoreEvent,
3834 cx: &mut Context<Self>,
3835 ) {
3836 match event {
3837 BufferStoreEvent::BufferAdded(buffer) => {
3838 self.on_buffer_added(buffer, cx).log_err();
3839 }
3840 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3841 let buffer_id = buffer.read(cx).remote_id();
3842 if let Some(local) = self.as_local_mut()
3843 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3844 {
3845 local.reset_buffer(buffer, old_file, cx);
3846
3847 if local.registered_buffers.contains_key(&buffer_id) {
3848 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3849 }
3850 }
3851
3852 self.detect_language_for_buffer(buffer, cx);
3853 if let Some(local) = self.as_local_mut() {
3854 local.initialize_buffer(buffer, cx);
3855 if local.registered_buffers.contains_key(&buffer_id) {
3856 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3857 }
3858 }
3859 }
3860 _ => {}
3861 }
3862 }
3863
3864 fn on_worktree_store_event(
3865 &mut self,
3866 _: Entity<WorktreeStore>,
3867 event: &WorktreeStoreEvent,
3868 cx: &mut Context<Self>,
3869 ) {
3870 match event {
3871 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3872 if !worktree.read(cx).is_local() {
3873 return;
3874 }
3875 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3876 worktree::Event::UpdatedEntries(changes) => {
3877 this.update_local_worktree_language_servers(&worktree, changes, cx);
3878 }
3879 worktree::Event::UpdatedGitRepositories(_)
3880 | worktree::Event::DeletedEntry(_) => {}
3881 })
3882 .detach()
3883 }
3884 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3885 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3886 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3887 }
3888 WorktreeStoreEvent::WorktreeReleased(..)
3889 | WorktreeStoreEvent::WorktreeOrderChanged
3890 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3891 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3892 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3893 }
3894 }
3895
3896 fn on_prettier_store_event(
3897 &mut self,
3898 _: Entity<PrettierStore>,
3899 event: &PrettierStoreEvent,
3900 cx: &mut Context<Self>,
3901 ) {
3902 match event {
3903 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3904 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3905 }
3906 PrettierStoreEvent::LanguageServerAdded {
3907 new_server_id,
3908 name,
3909 prettier_server,
3910 } => {
3911 self.register_supplementary_language_server(
3912 *new_server_id,
3913 name.clone(),
3914 prettier_server.clone(),
3915 cx,
3916 );
3917 }
3918 }
3919 }
3920
3921 fn on_toolchain_store_event(
3922 &mut self,
3923 _: Entity<LocalToolchainStore>,
3924 event: &ToolchainStoreEvent,
3925 _: &mut Context<Self>,
3926 ) {
3927 match event {
3928 ToolchainStoreEvent::ToolchainActivated { .. } => {
3929 self.request_workspace_config_refresh()
3930 }
3931 }
3932 }
3933
3934 fn request_workspace_config_refresh(&mut self) {
3935 *self._maintain_workspace_config.1.borrow_mut() = ();
3936 }
3937
3938 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
3939 self.as_local().map(|local| local.prettier_store.clone())
3940 }
3941
3942 fn on_buffer_event(
3943 &mut self,
3944 buffer: Entity<Buffer>,
3945 event: &language::BufferEvent,
3946 cx: &mut Context<Self>,
3947 ) {
3948 match event {
3949 language::BufferEvent::Edited => {
3950 self.on_buffer_edited(buffer, cx);
3951 }
3952
3953 language::BufferEvent::Saved => {
3954 self.on_buffer_saved(buffer, cx);
3955 }
3956
3957 _ => {}
3958 }
3959 }
3960
3961 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
3962 buffer
3963 .read(cx)
3964 .set_language_registry(self.languages.clone());
3965
3966 cx.subscribe(buffer, |this, buffer, event, cx| {
3967 this.on_buffer_event(buffer, event, cx);
3968 })
3969 .detach();
3970
3971 self.detect_language_for_buffer(buffer, cx);
3972 if let Some(local) = self.as_local_mut() {
3973 local.initialize_buffer(buffer, cx);
3974 }
3975
3976 Ok(())
3977 }
3978
3979 pub fn reload_zed_json_schemas_on_extensions_changed(
3980 &mut self,
3981 _: Entity<extension::ExtensionEvents>,
3982 evt: &extension::Event,
3983 cx: &mut Context<Self>,
3984 ) {
3985 match evt {
3986 extension::Event::ExtensionInstalled(_)
3987 | extension::Event::ExtensionUninstalled(_)
3988 | extension::Event::ConfigureExtensionRequested(_) => return,
3989 extension::Event::ExtensionsInstalledChanged => {}
3990 }
3991 if self.as_local().is_none() {
3992 return;
3993 }
3994 cx.spawn(async move |this, cx| {
3995 let weak_ref = this.clone();
3996
3997 let servers = this
3998 .update(cx, |this, cx| {
3999 let local = this.as_local()?;
4000
4001 let mut servers = Vec::new();
4002 for (seed, state) in &local.language_server_ids {
4003
4004 let Some(states) = local.language_servers.get(&state.id) else {
4005 continue;
4006 };
4007 let (json_adapter, json_server) = match states {
4008 LanguageServerState::Running {
4009 adapter, server, ..
4010 } if adapter.adapter.is_primary_zed_json_schema_adapter() => {
4011 (adapter.adapter.clone(), server.clone())
4012 }
4013 _ => continue,
4014 };
4015
4016 let Some(worktree) = this
4017 .worktree_store
4018 .read(cx)
4019 .worktree_for_id(seed.worktree_id, cx)
4020 else {
4021 continue;
4022 };
4023 let json_delegate: Arc<dyn LspAdapterDelegate> =
4024 LocalLspAdapterDelegate::new(
4025 local.languages.clone(),
4026 &local.environment,
4027 weak_ref.clone(),
4028 &worktree,
4029 local.http_client.clone(),
4030 local.fs.clone(),
4031 cx,
4032 );
4033
4034 servers.push((json_adapter, json_server, json_delegate));
4035
4036 }
4037 Some(servers)
4038 })
4039 .ok()
4040 .flatten();
4041
4042 let Some(servers) = servers else {
4043 return;
4044 };
4045
4046 let Ok(Some((fs, _))) = this.read_with(cx, |this, _| {
4047 let local = this.as_local()?;
4048 let toolchain_store = local.toolchain_store().clone();
4049 Some((local.fs.clone(), toolchain_store))
4050 }) else {
4051 return;
4052 };
4053 for (adapter, server, delegate) in servers {
4054 adapter.clear_zed_json_schema_cache().await;
4055
4056 let Some(json_workspace_config) = LocalLspStore::workspace_configuration_for_adapter(
4057 adapter,
4058 fs.as_ref(),
4059 &delegate,
4060 None,
4061 cx,
4062 )
4063 .await
4064 .context("generate new workspace configuration for JSON language server while trying to refresh JSON Schemas")
4065 .ok()
4066 else {
4067 continue;
4068 };
4069 server
4070 .notify::<lsp::notification::DidChangeConfiguration>(
4071 &lsp::DidChangeConfigurationParams {
4072 settings: json_workspace_config,
4073 },
4074 )
4075 .ok();
4076 }
4077 })
4078 .detach();
4079 }
4080
4081 pub(crate) fn register_buffer_with_language_servers(
4082 &mut self,
4083 buffer: &Entity<Buffer>,
4084 only_register_servers: HashSet<LanguageServerSelector>,
4085 ignore_refcounts: bool,
4086 cx: &mut Context<Self>,
4087 ) -> OpenLspBufferHandle {
4088 let buffer_id = buffer.read(cx).remote_id();
4089 let handle = cx.new(|_| buffer.clone());
4090 if let Some(local) = self.as_local_mut() {
4091 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4092 if !ignore_refcounts {
4093 *refcount += 1;
4094 }
4095
4096 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4097 // 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
4098 // 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
4099 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4100 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4101 return handle;
4102 };
4103 if !file.is_local() {
4104 return handle;
4105 }
4106
4107 if ignore_refcounts || *refcount == 1 {
4108 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4109 }
4110 if !ignore_refcounts {
4111 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4112 let refcount = {
4113 let local = lsp_store.as_local_mut().unwrap();
4114 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4115 debug_panic!("bad refcounting");
4116 return;
4117 };
4118
4119 *refcount -= 1;
4120 *refcount
4121 };
4122 if refcount == 0 {
4123 lsp_store.lsp_document_colors.remove(&buffer_id);
4124 lsp_store.lsp_code_lens.remove(&buffer_id);
4125 let local = lsp_store.as_local_mut().unwrap();
4126 local.registered_buffers.remove(&buffer_id);
4127 local.buffers_opened_in_servers.remove(&buffer_id);
4128 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4129 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4130 }
4131 }
4132 })
4133 .detach();
4134 }
4135 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4136 let buffer_id = buffer.read(cx).remote_id().to_proto();
4137 cx.background_spawn(async move {
4138 upstream_client
4139 .request(proto::RegisterBufferWithLanguageServers {
4140 project_id: upstream_project_id,
4141 buffer_id,
4142 only_servers: only_register_servers
4143 .into_iter()
4144 .map(|selector| {
4145 let selector = match selector {
4146 LanguageServerSelector::Id(language_server_id) => {
4147 proto::language_server_selector::Selector::ServerId(
4148 language_server_id.to_proto(),
4149 )
4150 }
4151 LanguageServerSelector::Name(language_server_name) => {
4152 proto::language_server_selector::Selector::Name(
4153 language_server_name.to_string(),
4154 )
4155 }
4156 };
4157 proto::LanguageServerSelector {
4158 selector: Some(selector),
4159 }
4160 })
4161 .collect(),
4162 })
4163 .await
4164 })
4165 .detach();
4166 } else {
4167 panic!("oops!");
4168 }
4169 handle
4170 }
4171
4172 fn maintain_buffer_languages(
4173 languages: Arc<LanguageRegistry>,
4174 cx: &mut Context<Self>,
4175 ) -> Task<()> {
4176 let mut subscription = languages.subscribe();
4177 let mut prev_reload_count = languages.reload_count();
4178 cx.spawn(async move |this, cx| {
4179 while let Some(()) = subscription.next().await {
4180 if let Some(this) = this.upgrade() {
4181 // If the language registry has been reloaded, then remove and
4182 // re-assign the languages on all open buffers.
4183 let reload_count = languages.reload_count();
4184 if reload_count > prev_reload_count {
4185 prev_reload_count = reload_count;
4186 this.update(cx, |this, cx| {
4187 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4188 for buffer in buffer_store.buffers() {
4189 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4190 {
4191 buffer
4192 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4193 if let Some(local) = this.as_local_mut() {
4194 local.reset_buffer(&buffer, &f, cx);
4195
4196 if local
4197 .registered_buffers
4198 .contains_key(&buffer.read(cx).remote_id())
4199 && let Some(file_url) =
4200 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4201 {
4202 local.unregister_buffer_from_language_servers(
4203 &buffer, &file_url, cx,
4204 );
4205 }
4206 }
4207 }
4208 }
4209 });
4210 })
4211 .ok();
4212 }
4213
4214 this.update(cx, |this, cx| {
4215 let mut plain_text_buffers = Vec::new();
4216 let mut buffers_with_unknown_injections = Vec::new();
4217 for handle in this.buffer_store.read(cx).buffers() {
4218 let buffer = handle.read(cx);
4219 if buffer.language().is_none()
4220 || buffer.language() == Some(&*language::PLAIN_TEXT)
4221 {
4222 plain_text_buffers.push(handle);
4223 } else if buffer.contains_unknown_injections() {
4224 buffers_with_unknown_injections.push(handle);
4225 }
4226 }
4227
4228 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4229 // and reused later in the invisible worktrees.
4230 plain_text_buffers.sort_by_key(|buffer| {
4231 Reverse(
4232 File::from_dyn(buffer.read(cx).file())
4233 .map(|file| file.worktree.read(cx).is_visible()),
4234 )
4235 });
4236
4237 for buffer in plain_text_buffers {
4238 this.detect_language_for_buffer(&buffer, cx);
4239 if let Some(local) = this.as_local_mut() {
4240 local.initialize_buffer(&buffer, cx);
4241 if local
4242 .registered_buffers
4243 .contains_key(&buffer.read(cx).remote_id())
4244 {
4245 local.register_buffer_with_language_servers(
4246 &buffer,
4247 HashSet::default(),
4248 cx,
4249 );
4250 }
4251 }
4252 }
4253
4254 for buffer in buffers_with_unknown_injections {
4255 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4256 }
4257 })
4258 .ok();
4259 }
4260 }
4261 })
4262 }
4263
4264 fn detect_language_for_buffer(
4265 &mut self,
4266 buffer_handle: &Entity<Buffer>,
4267 cx: &mut Context<Self>,
4268 ) -> Option<language::AvailableLanguage> {
4269 // If the buffer has a language, set it and start the language server if we haven't already.
4270 let buffer = buffer_handle.read(cx);
4271 let file = buffer.file()?;
4272
4273 let content = buffer.as_rope();
4274 let available_language = self.languages.language_for_file(file, Some(content), cx);
4275 if let Some(available_language) = &available_language {
4276 if let Some(Ok(Ok(new_language))) = self
4277 .languages
4278 .load_language(available_language)
4279 .now_or_never()
4280 {
4281 self.set_language_for_buffer(buffer_handle, new_language, cx);
4282 }
4283 } else {
4284 cx.emit(LspStoreEvent::LanguageDetected {
4285 buffer: buffer_handle.clone(),
4286 new_language: None,
4287 });
4288 }
4289
4290 available_language
4291 }
4292
4293 pub(crate) fn set_language_for_buffer(
4294 &mut self,
4295 buffer_entity: &Entity<Buffer>,
4296 new_language: Arc<Language>,
4297 cx: &mut Context<Self>,
4298 ) {
4299 let buffer = buffer_entity.read(cx);
4300 let buffer_file = buffer.file().cloned();
4301 let buffer_id = buffer.remote_id();
4302 if let Some(local_store) = self.as_local_mut()
4303 && local_store.registered_buffers.contains_key(&buffer_id)
4304 && let Some(abs_path) =
4305 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4306 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4307 {
4308 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4309 }
4310 buffer_entity.update(cx, |buffer, cx| {
4311 if buffer
4312 .language()
4313 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4314 {
4315 buffer.set_language(Some(new_language.clone()), cx);
4316 }
4317 });
4318
4319 let settings =
4320 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4321 let buffer_file = File::from_dyn(buffer_file.as_ref());
4322
4323 let worktree_id = if let Some(file) = buffer_file {
4324 let worktree = file.worktree.clone();
4325
4326 if let Some(local) = self.as_local_mut()
4327 && local.registered_buffers.contains_key(&buffer_id)
4328 {
4329 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4330 }
4331 Some(worktree.read(cx).id())
4332 } else {
4333 None
4334 };
4335
4336 if settings.prettier.allowed
4337 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4338 {
4339 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4340 if let Some(prettier_store) = prettier_store {
4341 prettier_store.update(cx, |prettier_store, cx| {
4342 prettier_store.install_default_prettier(
4343 worktree_id,
4344 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4345 cx,
4346 )
4347 })
4348 }
4349 }
4350
4351 cx.emit(LspStoreEvent::LanguageDetected {
4352 buffer: buffer_entity.clone(),
4353 new_language: Some(new_language),
4354 })
4355 }
4356
4357 pub fn buffer_store(&self) -> Entity<BufferStore> {
4358 self.buffer_store.clone()
4359 }
4360
4361 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4362 self.active_entry = active_entry;
4363 }
4364
4365 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4366 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4367 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4368 {
4369 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4370 summaries
4371 .iter()
4372 .map(|(server_id, summary)| summary.to_proto(*server_id, path))
4373 });
4374 if let Some(summary) = summaries.next() {
4375 client
4376 .send(proto::UpdateDiagnosticSummary {
4377 project_id: downstream_project_id,
4378 worktree_id: worktree.id().to_proto(),
4379 summary: Some(summary),
4380 more_summaries: summaries.collect(),
4381 })
4382 .log_err();
4383 }
4384 }
4385 }
4386
4387 // TODO: remove MultiLspQuery: instead, the proto handler should pick appropriate server(s)
4388 // Then, use `send_lsp_proto_request` or analogue for most of the LSP proto requests and inline this check inside
4389 fn is_capable_for_proto_request<R>(
4390 &self,
4391 buffer: &Entity<Buffer>,
4392 request: &R,
4393 cx: &Context<Self>,
4394 ) -> bool
4395 where
4396 R: LspCommand,
4397 {
4398 self.check_if_capable_for_proto_request(
4399 buffer,
4400 |capabilities| {
4401 request.check_capabilities(AdapterServerCapabilities {
4402 server_capabilities: capabilities.clone(),
4403 code_action_kinds: None,
4404 })
4405 },
4406 cx,
4407 )
4408 }
4409
4410 fn check_if_capable_for_proto_request<F>(
4411 &self,
4412 buffer: &Entity<Buffer>,
4413 check: F,
4414 cx: &Context<Self>,
4415 ) -> bool
4416 where
4417 F: Fn(&lsp::ServerCapabilities) -> bool,
4418 {
4419 let Some(language) = buffer.read(cx).language().cloned() else {
4420 return false;
4421 };
4422 let relevant_language_servers = self
4423 .languages
4424 .lsp_adapters(&language.name())
4425 .into_iter()
4426 .map(|lsp_adapter| lsp_adapter.name())
4427 .collect::<HashSet<_>>();
4428 self.language_server_statuses
4429 .iter()
4430 .filter_map(|(server_id, server_status)| {
4431 relevant_language_servers
4432 .contains(&server_status.name)
4433 .then_some(server_id)
4434 })
4435 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4436 .any(check)
4437 }
4438
4439 pub fn request_lsp<R>(
4440 &mut self,
4441 buffer: Entity<Buffer>,
4442 server: LanguageServerToQuery,
4443 request: R,
4444 cx: &mut Context<Self>,
4445 ) -> Task<Result<R::Response>>
4446 where
4447 R: LspCommand,
4448 <R::LspRequest as lsp::request::Request>::Result: Send,
4449 <R::LspRequest as lsp::request::Request>::Params: Send,
4450 {
4451 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4452 return self.send_lsp_proto_request(
4453 buffer,
4454 upstream_client,
4455 upstream_project_id,
4456 request,
4457 cx,
4458 );
4459 }
4460
4461 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4462 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4463 local
4464 .language_servers_for_buffer(buffer, cx)
4465 .find(|(_, server)| {
4466 request.check_capabilities(server.adapter_server_capabilities())
4467 })
4468 .map(|(_, server)| server.clone())
4469 }),
4470 LanguageServerToQuery::Other(id) => self
4471 .language_server_for_local_buffer(buffer, id, cx)
4472 .and_then(|(_, server)| {
4473 request
4474 .check_capabilities(server.adapter_server_capabilities())
4475 .then(|| Arc::clone(server))
4476 }),
4477 }) else {
4478 return Task::ready(Ok(Default::default()));
4479 };
4480
4481 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4482
4483 let Some(file) = file else {
4484 return Task::ready(Ok(Default::default()));
4485 };
4486
4487 let lsp_params = match request.to_lsp_params_or_response(
4488 &file.abs_path(cx),
4489 buffer.read(cx),
4490 &language_server,
4491 cx,
4492 ) {
4493 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4494 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4495
4496 Err(err) => {
4497 let message = format!(
4498 "{} via {} failed: {}",
4499 request.display_name(),
4500 language_server.name(),
4501 err
4502 );
4503 log::warn!("{message}");
4504 return Task::ready(Err(anyhow!(message)));
4505 }
4506 };
4507
4508 let status = request.status();
4509 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4510 return Task::ready(Ok(Default::default()));
4511 }
4512 cx.spawn(async move |this, cx| {
4513 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4514
4515 let id = lsp_request.id();
4516 let _cleanup = if status.is_some() {
4517 cx.update(|cx| {
4518 this.update(cx, |this, cx| {
4519 this.on_lsp_work_start(
4520 language_server.server_id(),
4521 id.to_string(),
4522 LanguageServerProgress {
4523 is_disk_based_diagnostics_progress: false,
4524 is_cancellable: false,
4525 title: None,
4526 message: status.clone(),
4527 percentage: None,
4528 last_update_at: cx.background_executor().now(),
4529 },
4530 cx,
4531 );
4532 })
4533 })
4534 .log_err();
4535
4536 Some(defer(|| {
4537 cx.update(|cx| {
4538 this.update(cx, |this, cx| {
4539 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4540 })
4541 })
4542 .log_err();
4543 }))
4544 } else {
4545 None
4546 };
4547
4548 let result = lsp_request.await.into_response();
4549
4550 let response = result.map_err(|err| {
4551 let message = format!(
4552 "{} via {} failed: {}",
4553 request.display_name(),
4554 language_server.name(),
4555 err
4556 );
4557 log::warn!("{message}");
4558 anyhow::anyhow!(message)
4559 })?;
4560
4561 request
4562 .response_from_lsp(
4563 response,
4564 this.upgrade().context("no app context")?,
4565 buffer,
4566 language_server.server_id(),
4567 cx.clone(),
4568 )
4569 .await
4570 })
4571 }
4572
4573 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4574 let mut language_formatters_to_check = Vec::new();
4575 for buffer in self.buffer_store.read(cx).buffers() {
4576 let buffer = buffer.read(cx);
4577 let buffer_file = File::from_dyn(buffer.file());
4578 let buffer_language = buffer.language();
4579 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4580 if buffer_language.is_some() {
4581 language_formatters_to_check.push((
4582 buffer_file.map(|f| f.worktree_id(cx)),
4583 settings.into_owned(),
4584 ));
4585 }
4586 }
4587
4588 self.request_workspace_config_refresh();
4589
4590 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4591 prettier_store.update(cx, |prettier_store, cx| {
4592 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4593 })
4594 }
4595
4596 cx.notify();
4597 }
4598
4599 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4600 let buffer_store = self.buffer_store.clone();
4601 let Some(local) = self.as_local_mut() else {
4602 return;
4603 };
4604 let mut adapters = BTreeMap::default();
4605 let get_adapter = {
4606 let languages = local.languages.clone();
4607 let environment = local.environment.clone();
4608 let weak = local.weak.clone();
4609 let worktree_store = local.worktree_store.clone();
4610 let http_client = local.http_client.clone();
4611 let fs = local.fs.clone();
4612 move |worktree_id, cx: &mut App| {
4613 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4614 Some(LocalLspAdapterDelegate::new(
4615 languages.clone(),
4616 &environment,
4617 weak.clone(),
4618 &worktree,
4619 http_client.clone(),
4620 fs.clone(),
4621 cx,
4622 ))
4623 }
4624 };
4625
4626 let mut messages_to_report = Vec::new();
4627 let (new_tree, to_stop) = {
4628 let mut rebase = local.lsp_tree.rebase();
4629 let buffers = buffer_store
4630 .read(cx)
4631 .buffers()
4632 .filter_map(|buffer| {
4633 let raw_buffer = buffer.read(cx);
4634 if !local
4635 .registered_buffers
4636 .contains_key(&raw_buffer.remote_id())
4637 {
4638 return None;
4639 }
4640 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4641 let language = raw_buffer.language().cloned()?;
4642 Some((file, language, raw_buffer.remote_id()))
4643 })
4644 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4645
4646 for (file, language, buffer_id) in buffers {
4647 let worktree_id = file.worktree_id(cx);
4648 let Some(worktree) = local
4649 .worktree_store
4650 .read(cx)
4651 .worktree_for_id(worktree_id, cx)
4652 else {
4653 continue;
4654 };
4655
4656 if let Some((_, apply)) = local.reuse_existing_language_server(
4657 rebase.server_tree(),
4658 &worktree,
4659 &language.name(),
4660 cx,
4661 ) {
4662 (apply)(rebase.server_tree());
4663 } else if let Some(lsp_delegate) = adapters
4664 .entry(worktree_id)
4665 .or_insert_with(|| get_adapter(worktree_id, cx))
4666 .clone()
4667 {
4668 let delegate =
4669 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4670 let path = file
4671 .path()
4672 .parent()
4673 .map(Arc::from)
4674 .unwrap_or_else(|| file.path().clone());
4675 let worktree_path = ProjectPath { worktree_id, path };
4676 let abs_path = file.abs_path(cx);
4677 let worktree_root = worktree.read(cx).abs_path();
4678 let nodes = rebase
4679 .walk(
4680 worktree_path,
4681 language.name(),
4682 language.manifest(),
4683 delegate.clone(),
4684 cx,
4685 )
4686 .collect::<Vec<_>>();
4687
4688 for node in nodes {
4689 let server_id = node.server_id_or_init(|disposition| {
4690 let path = &disposition.path;
4691 let uri = Url::from_file_path(worktree_root.join(&path.path));
4692 let key = LanguageServerSeed {
4693 worktree_id,
4694 name: disposition.server_name.clone(),
4695 settings: disposition.settings.clone(),
4696 toolchain: local.toolchain_store.read(cx).active_toolchain(
4697 path.worktree_id,
4698 &path.path,
4699 language.name(),
4700 ),
4701 };
4702 local.language_server_ids.remove(&key);
4703
4704 let server_id = local.get_or_insert_language_server(
4705 &worktree,
4706 lsp_delegate.clone(),
4707 disposition,
4708 &language.name(),
4709 cx,
4710 );
4711 if let Some(state) = local.language_servers.get(&server_id)
4712 && let Ok(uri) = uri
4713 {
4714 state.add_workspace_folder(uri);
4715 };
4716 server_id
4717 });
4718
4719 if let Some(language_server_id) = server_id {
4720 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4721 language_server_id,
4722 name: node.name(),
4723 message:
4724 proto::update_language_server::Variant::RegisteredForBuffer(
4725 proto::RegisteredForBuffer {
4726 buffer_abs_path: abs_path.to_string_lossy().to_string(),
4727 buffer_id: buffer_id.to_proto(),
4728 },
4729 ),
4730 });
4731 }
4732 }
4733 } else {
4734 continue;
4735 }
4736 }
4737 rebase.finish()
4738 };
4739 for message in messages_to_report {
4740 cx.emit(message);
4741 }
4742 local.lsp_tree = new_tree;
4743 for (id, _) in to_stop {
4744 self.stop_local_language_server(id, cx).detach();
4745 }
4746 }
4747
4748 pub fn apply_code_action(
4749 &self,
4750 buffer_handle: Entity<Buffer>,
4751 mut action: CodeAction,
4752 push_to_history: bool,
4753 cx: &mut Context<Self>,
4754 ) -> Task<Result<ProjectTransaction>> {
4755 if let Some((upstream_client, project_id)) = self.upstream_client() {
4756 let request = proto::ApplyCodeAction {
4757 project_id,
4758 buffer_id: buffer_handle.read(cx).remote_id().into(),
4759 action: Some(Self::serialize_code_action(&action)),
4760 };
4761 let buffer_store = self.buffer_store();
4762 cx.spawn(async move |_, cx| {
4763 let response = upstream_client
4764 .request(request)
4765 .await?
4766 .transaction
4767 .context("missing transaction")?;
4768
4769 buffer_store
4770 .update(cx, |buffer_store, cx| {
4771 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4772 })?
4773 .await
4774 })
4775 } else if self.mode.is_local() {
4776 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4777 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4778 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4779 }) else {
4780 return Task::ready(Ok(ProjectTransaction::default()));
4781 };
4782 cx.spawn(async move |this, cx| {
4783 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4784 .await
4785 .context("resolving a code action")?;
4786 if let Some(edit) = action.lsp_action.edit()
4787 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4788 return LocalLspStore::deserialize_workspace_edit(
4789 this.upgrade().context("no app present")?,
4790 edit.clone(),
4791 push_to_history,
4792
4793 lang_server.clone(),
4794 cx,
4795 )
4796 .await;
4797 }
4798
4799 if let Some(command) = action.lsp_action.command() {
4800 let server_capabilities = lang_server.capabilities();
4801 let available_commands = server_capabilities
4802 .execute_command_provider
4803 .as_ref()
4804 .map(|options| options.commands.as_slice())
4805 .unwrap_or_default();
4806 if available_commands.contains(&command.command) {
4807 this.update(cx, |this, _| {
4808 this.as_local_mut()
4809 .unwrap()
4810 .last_workspace_edits_by_language_server
4811 .remove(&lang_server.server_id());
4812 })?;
4813
4814 let _result = lang_server
4815 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4816 command: command.command.clone(),
4817 arguments: command.arguments.clone().unwrap_or_default(),
4818 ..lsp::ExecuteCommandParams::default()
4819 })
4820 .await.into_response()
4821 .context("execute command")?;
4822
4823 return this.update(cx, |this, _| {
4824 this.as_local_mut()
4825 .unwrap()
4826 .last_workspace_edits_by_language_server
4827 .remove(&lang_server.server_id())
4828 .unwrap_or_default()
4829 });
4830 } else {
4831 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4832 }
4833 }
4834
4835 Ok(ProjectTransaction::default())
4836 })
4837 } else {
4838 Task::ready(Err(anyhow!("no upstream client and not local")))
4839 }
4840 }
4841
4842 pub fn apply_code_action_kind(
4843 &mut self,
4844 buffers: HashSet<Entity<Buffer>>,
4845 kind: CodeActionKind,
4846 push_to_history: bool,
4847 cx: &mut Context<Self>,
4848 ) -> Task<anyhow::Result<ProjectTransaction>> {
4849 if self.as_local().is_some() {
4850 cx.spawn(async move |lsp_store, cx| {
4851 let buffers = buffers.into_iter().collect::<Vec<_>>();
4852 let result = LocalLspStore::execute_code_action_kind_locally(
4853 lsp_store.clone(),
4854 buffers,
4855 kind,
4856 push_to_history,
4857 cx,
4858 )
4859 .await;
4860 lsp_store.update(cx, |lsp_store, _| {
4861 lsp_store.update_last_formatting_failure(&result);
4862 })?;
4863 result
4864 })
4865 } else if let Some((client, project_id)) = self.upstream_client() {
4866 let buffer_store = self.buffer_store();
4867 cx.spawn(async move |lsp_store, cx| {
4868 let result = client
4869 .request(proto::ApplyCodeActionKind {
4870 project_id,
4871 kind: kind.as_str().to_owned(),
4872 buffer_ids: buffers
4873 .iter()
4874 .map(|buffer| {
4875 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4876 })
4877 .collect::<Result<_>>()?,
4878 })
4879 .await
4880 .and_then(|result| result.transaction.context("missing transaction"));
4881 lsp_store.update(cx, |lsp_store, _| {
4882 lsp_store.update_last_formatting_failure(&result);
4883 })?;
4884
4885 let transaction_response = result?;
4886 buffer_store
4887 .update(cx, |buffer_store, cx| {
4888 buffer_store.deserialize_project_transaction(
4889 transaction_response,
4890 push_to_history,
4891 cx,
4892 )
4893 })?
4894 .await
4895 })
4896 } else {
4897 Task::ready(Ok(ProjectTransaction::default()))
4898 }
4899 }
4900
4901 pub fn resolve_inlay_hint(
4902 &self,
4903 mut hint: InlayHint,
4904 buffer: Entity<Buffer>,
4905 server_id: LanguageServerId,
4906 cx: &mut Context<Self>,
4907 ) -> Task<anyhow::Result<InlayHint>> {
4908 if let Some((upstream_client, project_id)) = self.upstream_client() {
4909 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4910 {
4911 hint.resolve_state = ResolveState::Resolved;
4912 return Task::ready(Ok(hint));
4913 }
4914 let request = proto::ResolveInlayHint {
4915 project_id,
4916 buffer_id: buffer.read(cx).remote_id().into(),
4917 language_server_id: server_id.0 as u64,
4918 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4919 };
4920 cx.background_spawn(async move {
4921 let response = upstream_client
4922 .request(request)
4923 .await
4924 .context("inlay hints proto request")?;
4925 match response.hint {
4926 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4927 .context("inlay hints proto resolve response conversion"),
4928 None => Ok(hint),
4929 }
4930 })
4931 } else {
4932 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4933 self.language_server_for_local_buffer(buffer, server_id, cx)
4934 .map(|(_, server)| server.clone())
4935 }) else {
4936 return Task::ready(Ok(hint));
4937 };
4938 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4939 return Task::ready(Ok(hint));
4940 }
4941 let buffer_snapshot = buffer.read(cx).snapshot();
4942 cx.spawn(async move |_, cx| {
4943 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4944 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4945 );
4946 let resolved_hint = resolve_task
4947 .await
4948 .into_response()
4949 .context("inlay hint resolve LSP request")?;
4950 let resolved_hint = InlayHints::lsp_to_project_hint(
4951 resolved_hint,
4952 &buffer,
4953 server_id,
4954 ResolveState::Resolved,
4955 false,
4956 cx,
4957 )
4958 .await?;
4959 Ok(resolved_hint)
4960 })
4961 }
4962 }
4963
4964 pub fn resolve_color_presentation(
4965 &mut self,
4966 mut color: DocumentColor,
4967 buffer: Entity<Buffer>,
4968 server_id: LanguageServerId,
4969 cx: &mut Context<Self>,
4970 ) -> Task<Result<DocumentColor>> {
4971 if color.resolved {
4972 return Task::ready(Ok(color));
4973 }
4974
4975 if let Some((upstream_client, project_id)) = self.upstream_client() {
4976 let start = color.lsp_range.start;
4977 let end = color.lsp_range.end;
4978 let request = proto::GetColorPresentation {
4979 project_id,
4980 server_id: server_id.to_proto(),
4981 buffer_id: buffer.read(cx).remote_id().into(),
4982 color: Some(proto::ColorInformation {
4983 red: color.color.red,
4984 green: color.color.green,
4985 blue: color.color.blue,
4986 alpha: color.color.alpha,
4987 lsp_range_start: Some(proto::PointUtf16 {
4988 row: start.line,
4989 column: start.character,
4990 }),
4991 lsp_range_end: Some(proto::PointUtf16 {
4992 row: end.line,
4993 column: end.character,
4994 }),
4995 }),
4996 };
4997 cx.background_spawn(async move {
4998 let response = upstream_client
4999 .request(request)
5000 .await
5001 .context("color presentation proto request")?;
5002 color.resolved = true;
5003 color.color_presentations = response
5004 .presentations
5005 .into_iter()
5006 .map(|presentation| ColorPresentation {
5007 label: SharedString::from(presentation.label),
5008 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5009 additional_text_edits: presentation
5010 .additional_text_edits
5011 .into_iter()
5012 .filter_map(deserialize_lsp_edit)
5013 .collect(),
5014 })
5015 .collect();
5016 Ok(color)
5017 })
5018 } else {
5019 let path = match buffer
5020 .update(cx, |buffer, cx| {
5021 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5022 })
5023 .context("buffer with the missing path")
5024 {
5025 Ok(path) => path,
5026 Err(e) => return Task::ready(Err(e)),
5027 };
5028 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5029 self.language_server_for_local_buffer(buffer, server_id, cx)
5030 .map(|(_, server)| server.clone())
5031 }) else {
5032 return Task::ready(Ok(color));
5033 };
5034 cx.background_spawn(async move {
5035 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5036 lsp::ColorPresentationParams {
5037 text_document: make_text_document_identifier(&path)?,
5038 color: color.color,
5039 range: color.lsp_range,
5040 work_done_progress_params: Default::default(),
5041 partial_result_params: Default::default(),
5042 },
5043 );
5044 color.color_presentations = resolve_task
5045 .await
5046 .into_response()
5047 .context("color presentation resolve LSP request")?
5048 .into_iter()
5049 .map(|presentation| ColorPresentation {
5050 label: SharedString::from(presentation.label),
5051 text_edit: presentation.text_edit,
5052 additional_text_edits: presentation
5053 .additional_text_edits
5054 .unwrap_or_default(),
5055 })
5056 .collect();
5057 color.resolved = true;
5058 Ok(color)
5059 })
5060 }
5061 }
5062
5063 pub(crate) fn linked_edits(
5064 &mut self,
5065 buffer: &Entity<Buffer>,
5066 position: Anchor,
5067 cx: &mut Context<Self>,
5068 ) -> Task<Result<Vec<Range<Anchor>>>> {
5069 let snapshot = buffer.read(cx).snapshot();
5070 let scope = snapshot.language_scope_at(position);
5071 let Some(server_id) = self
5072 .as_local()
5073 .and_then(|local| {
5074 buffer.update(cx, |buffer, cx| {
5075 local
5076 .language_servers_for_buffer(buffer, cx)
5077 .filter(|(_, server)| {
5078 LinkedEditingRange::check_server_capabilities(server.capabilities())
5079 })
5080 .filter(|(adapter, _)| {
5081 scope
5082 .as_ref()
5083 .map(|scope| scope.language_allowed(&adapter.name))
5084 .unwrap_or(true)
5085 })
5086 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5087 .next()
5088 })
5089 })
5090 .or_else(|| {
5091 self.upstream_client()
5092 .is_some()
5093 .then_some(LanguageServerToQuery::FirstCapable)
5094 })
5095 .filter(|_| {
5096 maybe!({
5097 let language = buffer.read(cx).language_at(position)?;
5098 Some(
5099 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5100 .linked_edits,
5101 )
5102 }) == Some(true)
5103 })
5104 else {
5105 return Task::ready(Ok(Vec::new()));
5106 };
5107
5108 self.request_lsp(
5109 buffer.clone(),
5110 server_id,
5111 LinkedEditingRange { position },
5112 cx,
5113 )
5114 }
5115
5116 fn apply_on_type_formatting(
5117 &mut self,
5118 buffer: Entity<Buffer>,
5119 position: Anchor,
5120 trigger: String,
5121 cx: &mut Context<Self>,
5122 ) -> Task<Result<Option<Transaction>>> {
5123 if let Some((client, project_id)) = self.upstream_client() {
5124 if !self.check_if_capable_for_proto_request(
5125 &buffer,
5126 |capabilities| {
5127 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5128 },
5129 cx,
5130 ) {
5131 return Task::ready(Ok(None));
5132 }
5133 let request = proto::OnTypeFormatting {
5134 project_id,
5135 buffer_id: buffer.read(cx).remote_id().into(),
5136 position: Some(serialize_anchor(&position)),
5137 trigger,
5138 version: serialize_version(&buffer.read(cx).version()),
5139 };
5140 cx.background_spawn(async move {
5141 client
5142 .request(request)
5143 .await?
5144 .transaction
5145 .map(language::proto::deserialize_transaction)
5146 .transpose()
5147 })
5148 } else if let Some(local) = self.as_local_mut() {
5149 let buffer_id = buffer.read(cx).remote_id();
5150 local.buffers_being_formatted.insert(buffer_id);
5151 cx.spawn(async move |this, cx| {
5152 let _cleanup = defer({
5153 let this = this.clone();
5154 let mut cx = cx.clone();
5155 move || {
5156 this.update(&mut cx, |this, _| {
5157 if let Some(local) = this.as_local_mut() {
5158 local.buffers_being_formatted.remove(&buffer_id);
5159 }
5160 })
5161 .ok();
5162 }
5163 });
5164
5165 buffer
5166 .update(cx, |buffer, _| {
5167 buffer.wait_for_edits(Some(position.timestamp))
5168 })?
5169 .await?;
5170 this.update(cx, |this, cx| {
5171 let position = position.to_point_utf16(buffer.read(cx));
5172 this.on_type_format(buffer, position, trigger, false, cx)
5173 })?
5174 .await
5175 })
5176 } else {
5177 Task::ready(Err(anyhow!("No upstream client or local language server")))
5178 }
5179 }
5180
5181 pub fn on_type_format<T: ToPointUtf16>(
5182 &mut self,
5183 buffer: Entity<Buffer>,
5184 position: T,
5185 trigger: String,
5186 push_to_history: bool,
5187 cx: &mut Context<Self>,
5188 ) -> Task<Result<Option<Transaction>>> {
5189 let position = position.to_point_utf16(buffer.read(cx));
5190 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5191 }
5192
5193 fn on_type_format_impl(
5194 &mut self,
5195 buffer: Entity<Buffer>,
5196 position: PointUtf16,
5197 trigger: String,
5198 push_to_history: bool,
5199 cx: &mut Context<Self>,
5200 ) -> Task<Result<Option<Transaction>>> {
5201 let options = buffer.update(cx, |buffer, cx| {
5202 lsp_command::lsp_formatting_options(
5203 language_settings(
5204 buffer.language_at(position).map(|l| l.name()),
5205 buffer.file(),
5206 cx,
5207 )
5208 .as_ref(),
5209 )
5210 });
5211
5212 cx.spawn(async move |this, cx| {
5213 if let Some(waiter) =
5214 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5215 {
5216 waiter.await?;
5217 }
5218 cx.update(|cx| {
5219 this.update(cx, |this, cx| {
5220 this.request_lsp(
5221 buffer.clone(),
5222 LanguageServerToQuery::FirstCapable,
5223 OnTypeFormatting {
5224 position,
5225 trigger,
5226 options,
5227 push_to_history,
5228 },
5229 cx,
5230 )
5231 })
5232 })??
5233 .await
5234 })
5235 }
5236
5237 pub fn definitions(
5238 &mut self,
5239 buffer_handle: &Entity<Buffer>,
5240 position: PointUtf16,
5241 cx: &mut Context<Self>,
5242 ) -> Task<Result<Vec<LocationLink>>> {
5243 if let Some((upstream_client, project_id)) = self.upstream_client() {
5244 let request = GetDefinitions { position };
5245 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5246 return Task::ready(Ok(Vec::new()));
5247 }
5248 let request_task = upstream_client.request(proto::MultiLspQuery {
5249 buffer_id: buffer_handle.read(cx).remote_id().into(),
5250 version: serialize_version(&buffer_handle.read(cx).version()),
5251 project_id,
5252 strategy: Some(proto::multi_lsp_query::Strategy::All(
5253 proto::AllLanguageServers {},
5254 )),
5255 request: Some(proto::multi_lsp_query::Request::GetDefinition(
5256 request.to_proto(project_id, buffer_handle.read(cx)),
5257 )),
5258 });
5259 let buffer = buffer_handle.clone();
5260 cx.spawn(async move |weak_project, cx| {
5261 let Some(project) = weak_project.upgrade() else {
5262 return Ok(Vec::new());
5263 };
5264 let responses = request_task.await?.responses;
5265 let actions = join_all(
5266 responses
5267 .into_iter()
5268 .filter_map(|lsp_response| match lsp_response.response? {
5269 proto::lsp_response::Response::GetDefinitionResponse(response) => {
5270 Some(response)
5271 }
5272 unexpected => {
5273 debug_panic!("Unexpected response: {unexpected:?}");
5274 None
5275 }
5276 })
5277 .map(|definitions_response| {
5278 GetDefinitions { position }.response_from_proto(
5279 definitions_response,
5280 project.clone(),
5281 buffer.clone(),
5282 cx.clone(),
5283 )
5284 }),
5285 )
5286 .await;
5287
5288 Ok(actions
5289 .into_iter()
5290 .collect::<Result<Vec<Vec<_>>>>()?
5291 .into_iter()
5292 .flatten()
5293 .dedup()
5294 .collect())
5295 })
5296 } else {
5297 let definitions_task = self.request_multiple_lsp_locally(
5298 buffer_handle,
5299 Some(position),
5300 GetDefinitions { position },
5301 cx,
5302 );
5303 cx.background_spawn(async move {
5304 Ok(definitions_task
5305 .await
5306 .into_iter()
5307 .flat_map(|(_, definitions)| definitions)
5308 .dedup()
5309 .collect())
5310 })
5311 }
5312 }
5313
5314 pub fn declarations(
5315 &mut self,
5316 buffer_handle: &Entity<Buffer>,
5317 position: PointUtf16,
5318 cx: &mut Context<Self>,
5319 ) -> Task<Result<Vec<LocationLink>>> {
5320 if let Some((upstream_client, project_id)) = self.upstream_client() {
5321 let request = GetDeclarations { position };
5322 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5323 return Task::ready(Ok(Vec::new()));
5324 }
5325 let request_task = upstream_client.request(proto::MultiLspQuery {
5326 buffer_id: buffer_handle.read(cx).remote_id().into(),
5327 version: serialize_version(&buffer_handle.read(cx).version()),
5328 project_id,
5329 strategy: Some(proto::multi_lsp_query::Strategy::All(
5330 proto::AllLanguageServers {},
5331 )),
5332 request: Some(proto::multi_lsp_query::Request::GetDeclaration(
5333 request.to_proto(project_id, buffer_handle.read(cx)),
5334 )),
5335 });
5336 let buffer = buffer_handle.clone();
5337 cx.spawn(async move |weak_project, cx| {
5338 let Some(project) = weak_project.upgrade() else {
5339 return Ok(Vec::new());
5340 };
5341 let responses = request_task.await?.responses;
5342 let actions = join_all(
5343 responses
5344 .into_iter()
5345 .filter_map(|lsp_response| match lsp_response.response? {
5346 proto::lsp_response::Response::GetDeclarationResponse(response) => {
5347 Some(response)
5348 }
5349 unexpected => {
5350 debug_panic!("Unexpected response: {unexpected:?}");
5351 None
5352 }
5353 })
5354 .map(|declarations_response| {
5355 GetDeclarations { position }.response_from_proto(
5356 declarations_response,
5357 project.clone(),
5358 buffer.clone(),
5359 cx.clone(),
5360 )
5361 }),
5362 )
5363 .await;
5364
5365 Ok(actions
5366 .into_iter()
5367 .collect::<Result<Vec<Vec<_>>>>()?
5368 .into_iter()
5369 .flatten()
5370 .dedup()
5371 .collect())
5372 })
5373 } else {
5374 let declarations_task = self.request_multiple_lsp_locally(
5375 buffer_handle,
5376 Some(position),
5377 GetDeclarations { position },
5378 cx,
5379 );
5380 cx.background_spawn(async move {
5381 Ok(declarations_task
5382 .await
5383 .into_iter()
5384 .flat_map(|(_, declarations)| declarations)
5385 .dedup()
5386 .collect())
5387 })
5388 }
5389 }
5390
5391 pub fn type_definitions(
5392 &mut self,
5393 buffer: &Entity<Buffer>,
5394 position: PointUtf16,
5395 cx: &mut Context<Self>,
5396 ) -> Task<Result<Vec<LocationLink>>> {
5397 if let Some((upstream_client, project_id)) = self.upstream_client() {
5398 let request = GetTypeDefinitions { position };
5399 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5400 return Task::ready(Ok(Vec::new()));
5401 }
5402 let request_task = upstream_client.request(proto::MultiLspQuery {
5403 buffer_id: buffer.read(cx).remote_id().into(),
5404 version: serialize_version(&buffer.read(cx).version()),
5405 project_id,
5406 strategy: Some(proto::multi_lsp_query::Strategy::All(
5407 proto::AllLanguageServers {},
5408 )),
5409 request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
5410 request.to_proto(project_id, buffer.read(cx)),
5411 )),
5412 });
5413 let buffer = buffer.clone();
5414 cx.spawn(async move |weak_project, cx| {
5415 let Some(project) = weak_project.upgrade() else {
5416 return Ok(Vec::new());
5417 };
5418 let responses = request_task.await?.responses;
5419 let actions = join_all(
5420 responses
5421 .into_iter()
5422 .filter_map(|lsp_response| match lsp_response.response? {
5423 proto::lsp_response::Response::GetTypeDefinitionResponse(response) => {
5424 Some(response)
5425 }
5426 unexpected => {
5427 debug_panic!("Unexpected response: {unexpected:?}");
5428 None
5429 }
5430 })
5431 .map(|type_definitions_response| {
5432 GetTypeDefinitions { position }.response_from_proto(
5433 type_definitions_response,
5434 project.clone(),
5435 buffer.clone(),
5436 cx.clone(),
5437 )
5438 }),
5439 )
5440 .await;
5441
5442 Ok(actions
5443 .into_iter()
5444 .collect::<Result<Vec<Vec<_>>>>()?
5445 .into_iter()
5446 .flatten()
5447 .dedup()
5448 .collect())
5449 })
5450 } else {
5451 let type_definitions_task = self.request_multiple_lsp_locally(
5452 buffer,
5453 Some(position),
5454 GetTypeDefinitions { position },
5455 cx,
5456 );
5457 cx.background_spawn(async move {
5458 Ok(type_definitions_task
5459 .await
5460 .into_iter()
5461 .flat_map(|(_, type_definitions)| type_definitions)
5462 .dedup()
5463 .collect())
5464 })
5465 }
5466 }
5467
5468 pub fn implementations(
5469 &mut self,
5470 buffer: &Entity<Buffer>,
5471 position: PointUtf16,
5472 cx: &mut Context<Self>,
5473 ) -> Task<Result<Vec<LocationLink>>> {
5474 if let Some((upstream_client, project_id)) = self.upstream_client() {
5475 let request = GetImplementations { position };
5476 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5477 return Task::ready(Ok(Vec::new()));
5478 }
5479 let request_task = upstream_client.request(proto::MultiLspQuery {
5480 buffer_id: buffer.read(cx).remote_id().into(),
5481 version: serialize_version(&buffer.read(cx).version()),
5482 project_id,
5483 strategy: Some(proto::multi_lsp_query::Strategy::All(
5484 proto::AllLanguageServers {},
5485 )),
5486 request: Some(proto::multi_lsp_query::Request::GetImplementation(
5487 request.to_proto(project_id, buffer.read(cx)),
5488 )),
5489 });
5490 let buffer = buffer.clone();
5491 cx.spawn(async move |weak_project, cx| {
5492 let Some(project) = weak_project.upgrade() else {
5493 return Ok(Vec::new());
5494 };
5495 let responses = request_task.await?.responses;
5496 let actions = join_all(
5497 responses
5498 .into_iter()
5499 .filter_map(|lsp_response| match lsp_response.response? {
5500 proto::lsp_response::Response::GetImplementationResponse(response) => {
5501 Some(response)
5502 }
5503 unexpected => {
5504 debug_panic!("Unexpected response: {unexpected:?}");
5505 None
5506 }
5507 })
5508 .map(|implementations_response| {
5509 GetImplementations { position }.response_from_proto(
5510 implementations_response,
5511 project.clone(),
5512 buffer.clone(),
5513 cx.clone(),
5514 )
5515 }),
5516 )
5517 .await;
5518
5519 Ok(actions
5520 .into_iter()
5521 .collect::<Result<Vec<Vec<_>>>>()?
5522 .into_iter()
5523 .flatten()
5524 .dedup()
5525 .collect())
5526 })
5527 } else {
5528 let implementations_task = self.request_multiple_lsp_locally(
5529 buffer,
5530 Some(position),
5531 GetImplementations { position },
5532 cx,
5533 );
5534 cx.background_spawn(async move {
5535 Ok(implementations_task
5536 .await
5537 .into_iter()
5538 .flat_map(|(_, implementations)| implementations)
5539 .dedup()
5540 .collect())
5541 })
5542 }
5543 }
5544
5545 pub fn references(
5546 &mut self,
5547 buffer: &Entity<Buffer>,
5548 position: PointUtf16,
5549 cx: &mut Context<Self>,
5550 ) -> Task<Result<Vec<Location>>> {
5551 if let Some((upstream_client, project_id)) = self.upstream_client() {
5552 let request = GetReferences { position };
5553 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5554 return Task::ready(Ok(Vec::new()));
5555 }
5556 let request_task = upstream_client.request(proto::MultiLspQuery {
5557 buffer_id: buffer.read(cx).remote_id().into(),
5558 version: serialize_version(&buffer.read(cx).version()),
5559 project_id,
5560 strategy: Some(proto::multi_lsp_query::Strategy::All(
5561 proto::AllLanguageServers {},
5562 )),
5563 request: Some(proto::multi_lsp_query::Request::GetReferences(
5564 request.to_proto(project_id, buffer.read(cx)),
5565 )),
5566 });
5567 let buffer = buffer.clone();
5568 cx.spawn(async move |weak_project, cx| {
5569 let Some(project) = weak_project.upgrade() else {
5570 return Ok(Vec::new());
5571 };
5572 let responses = request_task.await?.responses;
5573 let actions = join_all(
5574 responses
5575 .into_iter()
5576 .filter_map(|lsp_response| match lsp_response.response? {
5577 proto::lsp_response::Response::GetReferencesResponse(response) => {
5578 Some(response)
5579 }
5580 unexpected => {
5581 debug_panic!("Unexpected response: {unexpected:?}");
5582 None
5583 }
5584 })
5585 .map(|references_response| {
5586 GetReferences { position }.response_from_proto(
5587 references_response,
5588 project.clone(),
5589 buffer.clone(),
5590 cx.clone(),
5591 )
5592 }),
5593 )
5594 .await;
5595
5596 Ok(actions
5597 .into_iter()
5598 .collect::<Result<Vec<Vec<_>>>>()?
5599 .into_iter()
5600 .flatten()
5601 .dedup()
5602 .collect())
5603 })
5604 } else {
5605 let references_task = self.request_multiple_lsp_locally(
5606 buffer,
5607 Some(position),
5608 GetReferences { position },
5609 cx,
5610 );
5611 cx.background_spawn(async move {
5612 Ok(references_task
5613 .await
5614 .into_iter()
5615 .flat_map(|(_, references)| references)
5616 .dedup()
5617 .collect())
5618 })
5619 }
5620 }
5621
5622 pub fn code_actions(
5623 &mut self,
5624 buffer: &Entity<Buffer>,
5625 range: Range<Anchor>,
5626 kinds: Option<Vec<CodeActionKind>>,
5627 cx: &mut Context<Self>,
5628 ) -> Task<Result<Vec<CodeAction>>> {
5629 if let Some((upstream_client, project_id)) = self.upstream_client() {
5630 let request = GetCodeActions {
5631 range: range.clone(),
5632 kinds: kinds.clone(),
5633 };
5634 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5635 return Task::ready(Ok(Vec::new()));
5636 }
5637 let request_task = upstream_client.request(proto::MultiLspQuery {
5638 buffer_id: buffer.read(cx).remote_id().into(),
5639 version: serialize_version(&buffer.read(cx).version()),
5640 project_id,
5641 strategy: Some(proto::multi_lsp_query::Strategy::All(
5642 proto::AllLanguageServers {},
5643 )),
5644 request: Some(proto::multi_lsp_query::Request::GetCodeActions(
5645 request.to_proto(project_id, buffer.read(cx)),
5646 )),
5647 });
5648 let buffer = buffer.clone();
5649 cx.spawn(async move |weak_project, cx| {
5650 let Some(project) = weak_project.upgrade() else {
5651 return Ok(Vec::new());
5652 };
5653 let responses = request_task.await?.responses;
5654 let actions = join_all(
5655 responses
5656 .into_iter()
5657 .filter_map(|lsp_response| match lsp_response.response? {
5658 proto::lsp_response::Response::GetCodeActionsResponse(response) => {
5659 Some(response)
5660 }
5661 unexpected => {
5662 debug_panic!("Unexpected response: {unexpected:?}");
5663 None
5664 }
5665 })
5666 .map(|code_actions_response| {
5667 GetCodeActions {
5668 range: range.clone(),
5669 kinds: kinds.clone(),
5670 }
5671 .response_from_proto(
5672 code_actions_response,
5673 project.clone(),
5674 buffer.clone(),
5675 cx.clone(),
5676 )
5677 }),
5678 )
5679 .await;
5680
5681 Ok(actions
5682 .into_iter()
5683 .collect::<Result<Vec<Vec<_>>>>()?
5684 .into_iter()
5685 .flatten()
5686 .collect())
5687 })
5688 } else {
5689 let all_actions_task = self.request_multiple_lsp_locally(
5690 buffer,
5691 Some(range.start),
5692 GetCodeActions {
5693 range: range.clone(),
5694 kinds: kinds.clone(),
5695 },
5696 cx,
5697 );
5698 cx.background_spawn(async move {
5699 Ok(all_actions_task
5700 .await
5701 .into_iter()
5702 .flat_map(|(_, actions)| actions)
5703 .collect())
5704 })
5705 }
5706 }
5707
5708 pub fn code_lens_actions(
5709 &mut self,
5710 buffer: &Entity<Buffer>,
5711 cx: &mut Context<Self>,
5712 ) -> CodeLensTask {
5713 let version_queried_for = buffer.read(cx).version();
5714 let buffer_id = buffer.read(cx).remote_id();
5715
5716 if let Some(cached_data) = self.lsp_code_lens.get(&buffer_id)
5717 && !version_queried_for.changed_since(&cached_data.lens_for_version)
5718 {
5719 let has_different_servers = self.as_local().is_some_and(|local| {
5720 local
5721 .buffers_opened_in_servers
5722 .get(&buffer_id)
5723 .cloned()
5724 .unwrap_or_default()
5725 != cached_data.lens.keys().copied().collect()
5726 });
5727 if !has_different_servers {
5728 return Task::ready(Ok(cached_data.lens.values().flatten().cloned().collect()))
5729 .shared();
5730 }
5731 }
5732
5733 let lsp_data = self.lsp_code_lens.entry(buffer_id).or_default();
5734 if let Some((updating_for, running_update)) = &lsp_data.update
5735 && !version_queried_for.changed_since(updating_for)
5736 {
5737 return running_update.clone();
5738 }
5739 let buffer = buffer.clone();
5740 let query_version_queried_for = version_queried_for.clone();
5741 let new_task = cx
5742 .spawn(async move |lsp_store, cx| {
5743 cx.background_executor()
5744 .timer(Duration::from_millis(30))
5745 .await;
5746 let fetched_lens = lsp_store
5747 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5748 .map_err(Arc::new)?
5749 .await
5750 .context("fetching code lens")
5751 .map_err(Arc::new);
5752 let fetched_lens = match fetched_lens {
5753 Ok(fetched_lens) => fetched_lens,
5754 Err(e) => {
5755 lsp_store
5756 .update(cx, |lsp_store, _| {
5757 lsp_store.lsp_code_lens.entry(buffer_id).or_default().update = None;
5758 })
5759 .ok();
5760 return Err(e);
5761 }
5762 };
5763
5764 lsp_store
5765 .update(cx, |lsp_store, _| {
5766 let lsp_data = lsp_store.lsp_code_lens.entry(buffer_id).or_default();
5767 if lsp_data.lens_for_version == query_version_queried_for {
5768 lsp_data.lens.extend(fetched_lens.clone());
5769 } else if !lsp_data
5770 .lens_for_version
5771 .changed_since(&query_version_queried_for)
5772 {
5773 lsp_data.lens_for_version = query_version_queried_for;
5774 lsp_data.lens = fetched_lens.clone();
5775 }
5776 lsp_data.update = None;
5777 lsp_data.lens.values().flatten().cloned().collect()
5778 })
5779 .map_err(Arc::new)
5780 })
5781 .shared();
5782 lsp_data.update = Some((version_queried_for, new_task.clone()));
5783 new_task
5784 }
5785
5786 fn fetch_code_lens(
5787 &mut self,
5788 buffer: &Entity<Buffer>,
5789 cx: &mut Context<Self>,
5790 ) -> Task<Result<HashMap<LanguageServerId, Vec<CodeAction>>>> {
5791 if let Some((upstream_client, project_id)) = self.upstream_client() {
5792 let request = GetCodeLens;
5793 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5794 return Task::ready(Ok(HashMap::default()));
5795 }
5796 let request_task = upstream_client.request(proto::MultiLspQuery {
5797 buffer_id: buffer.read(cx).remote_id().into(),
5798 version: serialize_version(&buffer.read(cx).version()),
5799 project_id,
5800 strategy: Some(proto::multi_lsp_query::Strategy::All(
5801 proto::AllLanguageServers {},
5802 )),
5803 request: Some(proto::multi_lsp_query::Request::GetCodeLens(
5804 request.to_proto(project_id, buffer.read(cx)),
5805 )),
5806 });
5807 let buffer = buffer.clone();
5808 cx.spawn(async move |weak_lsp_store, cx| {
5809 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5810 return Ok(HashMap::default());
5811 };
5812 let responses = request_task.await?.responses;
5813 let code_lens_actions = join_all(
5814 responses
5815 .into_iter()
5816 .filter_map(|lsp_response| {
5817 let response = match lsp_response.response? {
5818 proto::lsp_response::Response::GetCodeLensResponse(response) => {
5819 Some(response)
5820 }
5821 unexpected => {
5822 debug_panic!("Unexpected response: {unexpected:?}");
5823 None
5824 }
5825 }?;
5826 let server_id = LanguageServerId::from_proto(lsp_response.server_id);
5827 Some((server_id, response))
5828 })
5829 .map(|(server_id, code_lens_response)| {
5830 let lsp_store = lsp_store.clone();
5831 let buffer = buffer.clone();
5832 let cx = cx.clone();
5833 async move {
5834 (
5835 server_id,
5836 GetCodeLens
5837 .response_from_proto(
5838 code_lens_response,
5839 lsp_store,
5840 buffer,
5841 cx,
5842 )
5843 .await,
5844 )
5845 }
5846 }),
5847 )
5848 .await;
5849
5850 let mut has_errors = false;
5851 let code_lens_actions = code_lens_actions
5852 .into_iter()
5853 .filter_map(|(server_id, code_lens)| match code_lens {
5854 Ok(code_lens) => Some((server_id, code_lens)),
5855 Err(e) => {
5856 has_errors = true;
5857 log::error!("{e:#}");
5858 None
5859 }
5860 })
5861 .collect::<HashMap<_, _>>();
5862 anyhow::ensure!(
5863 !has_errors || !code_lens_actions.is_empty(),
5864 "Failed to fetch code lens"
5865 );
5866 Ok(code_lens_actions)
5867 })
5868 } else {
5869 let code_lens_actions_task =
5870 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5871 cx.background_spawn(
5872 async move { Ok(code_lens_actions_task.await.into_iter().collect()) },
5873 )
5874 }
5875 }
5876
5877 #[inline(never)]
5878 pub fn completions(
5879 &self,
5880 buffer: &Entity<Buffer>,
5881 position: PointUtf16,
5882 context: CompletionContext,
5883 cx: &mut Context<Self>,
5884 ) -> Task<Result<Vec<CompletionResponse>>> {
5885 let language_registry = self.languages.clone();
5886
5887 if let Some((upstream_client, project_id)) = self.upstream_client() {
5888 let request = GetCompletions { position, context };
5889 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5890 return Task::ready(Ok(Vec::new()));
5891 }
5892 let task = self.send_lsp_proto_request(
5893 buffer.clone(),
5894 upstream_client,
5895 project_id,
5896 request,
5897 cx,
5898 );
5899 let language = buffer.read(cx).language().cloned();
5900
5901 // In the future, we should provide project guests with the names of LSP adapters,
5902 // so that they can use the correct LSP adapter when computing labels. For now,
5903 // guests just use the first LSP adapter associated with the buffer's language.
5904 let lsp_adapter = language.as_ref().and_then(|language| {
5905 language_registry
5906 .lsp_adapters(&language.name())
5907 .first()
5908 .cloned()
5909 });
5910
5911 cx.foreground_executor().spawn(async move {
5912 let completion_response = task.await?;
5913 let completions = populate_labels_for_completions(
5914 completion_response.completions,
5915 language,
5916 lsp_adapter,
5917 )
5918 .await;
5919 Ok(vec![CompletionResponse {
5920 completions,
5921 is_incomplete: completion_response.is_incomplete,
5922 }])
5923 })
5924 } else if let Some(local) = self.as_local() {
5925 let snapshot = buffer.read(cx).snapshot();
5926 let offset = position.to_offset(&snapshot);
5927 let scope = snapshot.language_scope_at(offset);
5928 let language = snapshot.language().cloned();
5929 let completion_settings = language_settings(
5930 language.as_ref().map(|language| language.name()),
5931 buffer.read(cx).file(),
5932 cx,
5933 )
5934 .completions;
5935 if !completion_settings.lsp {
5936 return Task::ready(Ok(Vec::new()));
5937 }
5938
5939 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5940 local
5941 .language_servers_for_buffer(buffer, cx)
5942 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5943 .filter(|(adapter, _)| {
5944 scope
5945 .as_ref()
5946 .map(|scope| scope.language_allowed(&adapter.name))
5947 .unwrap_or(true)
5948 })
5949 .map(|(_, server)| server.server_id())
5950 .collect()
5951 });
5952
5953 let buffer = buffer.clone();
5954 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5955 let lsp_timeout = if lsp_timeout > 0 {
5956 Some(Duration::from_millis(lsp_timeout))
5957 } else {
5958 None
5959 };
5960 cx.spawn(async move |this, cx| {
5961 let mut tasks = Vec::with_capacity(server_ids.len());
5962 this.update(cx, |lsp_store, cx| {
5963 for server_id in server_ids {
5964 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5965 let lsp_timeout = lsp_timeout
5966 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5967 let mut timeout = cx.background_spawn(async move {
5968 match lsp_timeout {
5969 Some(lsp_timeout) => {
5970 lsp_timeout.await;
5971 true
5972 },
5973 None => false,
5974 }
5975 }).fuse();
5976 let mut lsp_request = lsp_store.request_lsp(
5977 buffer.clone(),
5978 LanguageServerToQuery::Other(server_id),
5979 GetCompletions {
5980 position,
5981 context: context.clone(),
5982 },
5983 cx,
5984 ).fuse();
5985 let new_task = cx.background_spawn(async move {
5986 select_biased! {
5987 response = lsp_request => anyhow::Ok(Some(response?)),
5988 timeout_happened = timeout => {
5989 if timeout_happened {
5990 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5991 Ok(None)
5992 } else {
5993 let completions = lsp_request.await?;
5994 Ok(Some(completions))
5995 }
5996 },
5997 }
5998 });
5999 tasks.push((lsp_adapter, new_task));
6000 }
6001 })?;
6002
6003 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6004 let completion_response = task.await.ok()??;
6005 let completions = populate_labels_for_completions(
6006 completion_response.completions,
6007 language.clone(),
6008 lsp_adapter,
6009 )
6010 .await;
6011 Some(CompletionResponse {
6012 completions,
6013 is_incomplete: completion_response.is_incomplete,
6014 })
6015 });
6016
6017 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6018
6019 Ok(responses.into_iter().flatten().collect())
6020 })
6021 } else {
6022 Task::ready(Err(anyhow!("No upstream client or local language server")))
6023 }
6024 }
6025
6026 pub fn resolve_completions(
6027 &self,
6028 buffer: Entity<Buffer>,
6029 completion_indices: Vec<usize>,
6030 completions: Rc<RefCell<Box<[Completion]>>>,
6031 cx: &mut Context<Self>,
6032 ) -> Task<Result<bool>> {
6033 let client = self.upstream_client();
6034 let buffer_id = buffer.read(cx).remote_id();
6035 let buffer_snapshot = buffer.read(cx).snapshot();
6036
6037 if !self.check_if_capable_for_proto_request(
6038 &buffer,
6039 GetCompletions::can_resolve_completions,
6040 cx,
6041 ) {
6042 return Task::ready(Ok(false));
6043 }
6044 cx.spawn(async move |lsp_store, cx| {
6045 let mut did_resolve = false;
6046 if let Some((client, project_id)) = client {
6047 for completion_index in completion_indices {
6048 let server_id = {
6049 let completion = &completions.borrow()[completion_index];
6050 completion.source.server_id()
6051 };
6052 if let Some(server_id) = server_id {
6053 if Self::resolve_completion_remote(
6054 project_id,
6055 server_id,
6056 buffer_id,
6057 completions.clone(),
6058 completion_index,
6059 client.clone(),
6060 )
6061 .await
6062 .log_err()
6063 .is_some()
6064 {
6065 did_resolve = true;
6066 }
6067 } else {
6068 resolve_word_completion(
6069 &buffer_snapshot,
6070 &mut completions.borrow_mut()[completion_index],
6071 );
6072 }
6073 }
6074 } else {
6075 for completion_index in completion_indices {
6076 let server_id = {
6077 let completion = &completions.borrow()[completion_index];
6078 completion.source.server_id()
6079 };
6080 if let Some(server_id) = server_id {
6081 let server_and_adapter = lsp_store
6082 .read_with(cx, |lsp_store, _| {
6083 let server = lsp_store.language_server_for_id(server_id)?;
6084 let adapter =
6085 lsp_store.language_server_adapter_for_id(server.server_id())?;
6086 Some((server, adapter))
6087 })
6088 .ok()
6089 .flatten();
6090 let Some((server, adapter)) = server_and_adapter else {
6091 continue;
6092 };
6093
6094 let resolved = Self::resolve_completion_local(
6095 server,
6096 completions.clone(),
6097 completion_index,
6098 )
6099 .await
6100 .log_err()
6101 .is_some();
6102 if resolved {
6103 Self::regenerate_completion_labels(
6104 adapter,
6105 &buffer_snapshot,
6106 completions.clone(),
6107 completion_index,
6108 )
6109 .await
6110 .log_err();
6111 did_resolve = true;
6112 }
6113 } else {
6114 resolve_word_completion(
6115 &buffer_snapshot,
6116 &mut completions.borrow_mut()[completion_index],
6117 );
6118 }
6119 }
6120 }
6121
6122 Ok(did_resolve)
6123 })
6124 }
6125
6126 async fn resolve_completion_local(
6127 server: Arc<lsp::LanguageServer>,
6128 completions: Rc<RefCell<Box<[Completion]>>>,
6129 completion_index: usize,
6130 ) -> Result<()> {
6131 let server_id = server.server_id();
6132 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6133 return Ok(());
6134 }
6135
6136 let request = {
6137 let completion = &completions.borrow()[completion_index];
6138 match &completion.source {
6139 CompletionSource::Lsp {
6140 lsp_completion,
6141 resolved,
6142 server_id: completion_server_id,
6143 ..
6144 } => {
6145 if *resolved {
6146 return Ok(());
6147 }
6148 anyhow::ensure!(
6149 server_id == *completion_server_id,
6150 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6151 );
6152 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6153 }
6154 CompletionSource::BufferWord { .. }
6155 | CompletionSource::Dap { .. }
6156 | CompletionSource::Custom => {
6157 return Ok(());
6158 }
6159 }
6160 };
6161 let resolved_completion = request
6162 .await
6163 .into_response()
6164 .context("resolve completion")?;
6165
6166 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6167 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6168
6169 let mut completions = completions.borrow_mut();
6170 let completion = &mut completions[completion_index];
6171 if let CompletionSource::Lsp {
6172 lsp_completion,
6173 resolved,
6174 server_id: completion_server_id,
6175 ..
6176 } = &mut completion.source
6177 {
6178 if *resolved {
6179 return Ok(());
6180 }
6181 anyhow::ensure!(
6182 server_id == *completion_server_id,
6183 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6184 );
6185 *lsp_completion = Box::new(resolved_completion);
6186 *resolved = true;
6187 }
6188 Ok(())
6189 }
6190
6191 async fn regenerate_completion_labels(
6192 adapter: Arc<CachedLspAdapter>,
6193 snapshot: &BufferSnapshot,
6194 completions: Rc<RefCell<Box<[Completion]>>>,
6195 completion_index: usize,
6196 ) -> Result<()> {
6197 let completion_item = completions.borrow()[completion_index]
6198 .source
6199 .lsp_completion(true)
6200 .map(Cow::into_owned);
6201 if let Some(lsp_documentation) = completion_item
6202 .as_ref()
6203 .and_then(|completion_item| completion_item.documentation.clone())
6204 {
6205 let mut completions = completions.borrow_mut();
6206 let completion = &mut completions[completion_index];
6207 completion.documentation = Some(lsp_documentation.into());
6208 } else {
6209 let mut completions = completions.borrow_mut();
6210 let completion = &mut completions[completion_index];
6211 completion.documentation = Some(CompletionDocumentation::Undocumented);
6212 }
6213
6214 let mut new_label = match completion_item {
6215 Some(completion_item) => {
6216 // 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
6217 // So we have to update the label here anyway...
6218 let language = snapshot.language();
6219 match language {
6220 Some(language) => {
6221 adapter
6222 .labels_for_completions(
6223 std::slice::from_ref(&completion_item),
6224 language,
6225 )
6226 .await?
6227 }
6228 None => Vec::new(),
6229 }
6230 .pop()
6231 .flatten()
6232 .unwrap_or_else(|| {
6233 CodeLabel::fallback_for_completion(
6234 &completion_item,
6235 language.map(|language| language.as_ref()),
6236 )
6237 })
6238 }
6239 None => CodeLabel::plain(
6240 completions.borrow()[completion_index].new_text.clone(),
6241 None,
6242 ),
6243 };
6244 ensure_uniform_list_compatible_label(&mut new_label);
6245
6246 let mut completions = completions.borrow_mut();
6247 let completion = &mut completions[completion_index];
6248 if completion.label.filter_text() == new_label.filter_text() {
6249 completion.label = new_label;
6250 } else {
6251 log::error!(
6252 "Resolved completion changed display label from {} to {}. \
6253 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6254 completion.label.text(),
6255 new_label.text(),
6256 completion.label.filter_text(),
6257 new_label.filter_text()
6258 );
6259 }
6260
6261 Ok(())
6262 }
6263
6264 async fn resolve_completion_remote(
6265 project_id: u64,
6266 server_id: LanguageServerId,
6267 buffer_id: BufferId,
6268 completions: Rc<RefCell<Box<[Completion]>>>,
6269 completion_index: usize,
6270 client: AnyProtoClient,
6271 ) -> Result<()> {
6272 let lsp_completion = {
6273 let completion = &completions.borrow()[completion_index];
6274 match &completion.source {
6275 CompletionSource::Lsp {
6276 lsp_completion,
6277 resolved,
6278 server_id: completion_server_id,
6279 ..
6280 } => {
6281 anyhow::ensure!(
6282 server_id == *completion_server_id,
6283 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6284 );
6285 if *resolved {
6286 return Ok(());
6287 }
6288 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6289 }
6290 CompletionSource::Custom
6291 | CompletionSource::Dap { .. }
6292 | CompletionSource::BufferWord { .. } => {
6293 return Ok(());
6294 }
6295 }
6296 };
6297 let request = proto::ResolveCompletionDocumentation {
6298 project_id,
6299 language_server_id: server_id.0 as u64,
6300 lsp_completion,
6301 buffer_id: buffer_id.into(),
6302 };
6303
6304 let response = client
6305 .request(request)
6306 .await
6307 .context("completion documentation resolve proto request")?;
6308 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6309
6310 let documentation = if response.documentation.is_empty() {
6311 CompletionDocumentation::Undocumented
6312 } else if response.documentation_is_markdown {
6313 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6314 } else if response.documentation.lines().count() <= 1 {
6315 CompletionDocumentation::SingleLine(response.documentation.into())
6316 } else {
6317 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6318 };
6319
6320 let mut completions = completions.borrow_mut();
6321 let completion = &mut completions[completion_index];
6322 completion.documentation = Some(documentation);
6323 if let CompletionSource::Lsp {
6324 insert_range,
6325 lsp_completion,
6326 resolved,
6327 server_id: completion_server_id,
6328 lsp_defaults: _,
6329 } = &mut completion.source
6330 {
6331 let completion_insert_range = response
6332 .old_insert_start
6333 .and_then(deserialize_anchor)
6334 .zip(response.old_insert_end.and_then(deserialize_anchor));
6335 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6336
6337 if *resolved {
6338 return Ok(());
6339 }
6340 anyhow::ensure!(
6341 server_id == *completion_server_id,
6342 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6343 );
6344 *lsp_completion = Box::new(resolved_lsp_completion);
6345 *resolved = true;
6346 }
6347
6348 let replace_range = response
6349 .old_replace_start
6350 .and_then(deserialize_anchor)
6351 .zip(response.old_replace_end.and_then(deserialize_anchor));
6352 if let Some((old_replace_start, old_replace_end)) = replace_range
6353 && !response.new_text.is_empty()
6354 {
6355 completion.new_text = response.new_text;
6356 completion.replace_range = old_replace_start..old_replace_end;
6357 }
6358
6359 Ok(())
6360 }
6361
6362 pub fn apply_additional_edits_for_completion(
6363 &self,
6364 buffer_handle: Entity<Buffer>,
6365 completions: Rc<RefCell<Box<[Completion]>>>,
6366 completion_index: usize,
6367 push_to_history: bool,
6368 cx: &mut Context<Self>,
6369 ) -> Task<Result<Option<Transaction>>> {
6370 if let Some((client, project_id)) = self.upstream_client() {
6371 let buffer = buffer_handle.read(cx);
6372 let buffer_id = buffer.remote_id();
6373 cx.spawn(async move |_, cx| {
6374 let request = {
6375 let completion = completions.borrow()[completion_index].clone();
6376 proto::ApplyCompletionAdditionalEdits {
6377 project_id,
6378 buffer_id: buffer_id.into(),
6379 completion: Some(Self::serialize_completion(&CoreCompletion {
6380 replace_range: completion.replace_range,
6381 new_text: completion.new_text,
6382 source: completion.source,
6383 })),
6384 }
6385 };
6386
6387 if let Some(transaction) = client.request(request).await?.transaction {
6388 let transaction = language::proto::deserialize_transaction(transaction)?;
6389 buffer_handle
6390 .update(cx, |buffer, _| {
6391 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6392 })?
6393 .await?;
6394 if push_to_history {
6395 buffer_handle.update(cx, |buffer, _| {
6396 buffer.push_transaction(transaction.clone(), Instant::now());
6397 buffer.finalize_last_transaction();
6398 })?;
6399 }
6400 Ok(Some(transaction))
6401 } else {
6402 Ok(None)
6403 }
6404 })
6405 } else {
6406 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6407 let completion = &completions.borrow()[completion_index];
6408 let server_id = completion.source.server_id()?;
6409 Some(
6410 self.language_server_for_local_buffer(buffer, server_id, cx)?
6411 .1
6412 .clone(),
6413 )
6414 }) else {
6415 return Task::ready(Ok(None));
6416 };
6417
6418 cx.spawn(async move |this, cx| {
6419 Self::resolve_completion_local(
6420 server.clone(),
6421 completions.clone(),
6422 completion_index,
6423 )
6424 .await
6425 .context("resolving completion")?;
6426 let completion = completions.borrow()[completion_index].clone();
6427 let additional_text_edits = completion
6428 .source
6429 .lsp_completion(true)
6430 .as_ref()
6431 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6432 if let Some(edits) = additional_text_edits {
6433 let edits = this
6434 .update(cx, |this, cx| {
6435 this.as_local_mut().unwrap().edits_from_lsp(
6436 &buffer_handle,
6437 edits,
6438 server.server_id(),
6439 None,
6440 cx,
6441 )
6442 })?
6443 .await?;
6444
6445 buffer_handle.update(cx, |buffer, cx| {
6446 buffer.finalize_last_transaction();
6447 buffer.start_transaction();
6448
6449 for (range, text) in edits {
6450 let primary = &completion.replace_range;
6451 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6452 && primary.end.cmp(&range.start, buffer).is_ge();
6453 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6454 && range.end.cmp(&primary.end, buffer).is_ge();
6455
6456 //Skip additional edits which overlap with the primary completion edit
6457 //https://github.com/zed-industries/zed/pull/1871
6458 if !start_within && !end_within {
6459 buffer.edit([(range, text)], None, cx);
6460 }
6461 }
6462
6463 let transaction = if buffer.end_transaction(cx).is_some() {
6464 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6465 if !push_to_history {
6466 buffer.forget_transaction(transaction.id);
6467 }
6468 Some(transaction)
6469 } else {
6470 None
6471 };
6472 Ok(transaction)
6473 })?
6474 } else {
6475 Ok(None)
6476 }
6477 })
6478 }
6479 }
6480
6481 pub fn pull_diagnostics(
6482 &mut self,
6483 buffer: Entity<Buffer>,
6484 cx: &mut Context<Self>,
6485 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6486 let buffer_id = buffer.read(cx).remote_id();
6487
6488 if let Some((client, upstream_project_id)) = self.upstream_client() {
6489 if !self.is_capable_for_proto_request(
6490 &buffer,
6491 &GetDocumentDiagnostics {
6492 previous_result_id: None,
6493 },
6494 cx,
6495 ) {
6496 return Task::ready(Ok(None));
6497 }
6498 let request_task = client.request(proto::MultiLspQuery {
6499 buffer_id: buffer_id.to_proto(),
6500 version: serialize_version(&buffer.read(cx).version()),
6501 project_id: upstream_project_id,
6502 strategy: Some(proto::multi_lsp_query::Strategy::All(
6503 proto::AllLanguageServers {},
6504 )),
6505 request: Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(
6506 proto::GetDocumentDiagnostics {
6507 project_id: upstream_project_id,
6508 buffer_id: buffer_id.to_proto(),
6509 version: serialize_version(&buffer.read(cx).version()),
6510 },
6511 )),
6512 });
6513 cx.background_spawn(async move {
6514 let _proto_responses = request_task
6515 .await?
6516 .responses
6517 .into_iter()
6518 .filter_map(|lsp_response| match lsp_response.response? {
6519 proto::lsp_response::Response::GetDocumentDiagnosticsResponse(response) => {
6520 Some(response)
6521 }
6522 unexpected => {
6523 debug_panic!("Unexpected response: {unexpected:?}");
6524 None
6525 }
6526 })
6527 .collect::<Vec<_>>();
6528 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6529 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6530 // Do not attempt to further process the dummy responses here.
6531 Ok(None)
6532 })
6533 } else {
6534 let server_ids = buffer.update(cx, |buffer, cx| {
6535 self.language_servers_for_local_buffer(buffer, cx)
6536 .map(|(_, server)| server.server_id())
6537 .collect::<Vec<_>>()
6538 });
6539 let pull_diagnostics = server_ids
6540 .into_iter()
6541 .map(|server_id| {
6542 let result_id = self.result_id(server_id, buffer_id, cx);
6543 self.request_lsp(
6544 buffer.clone(),
6545 LanguageServerToQuery::Other(server_id),
6546 GetDocumentDiagnostics {
6547 previous_result_id: result_id,
6548 },
6549 cx,
6550 )
6551 })
6552 .collect::<Vec<_>>();
6553
6554 cx.background_spawn(async move {
6555 let mut responses = Vec::new();
6556 for diagnostics in join_all(pull_diagnostics).await {
6557 responses.extend(diagnostics?);
6558 }
6559 Ok(Some(responses))
6560 })
6561 }
6562 }
6563
6564 pub fn inlay_hints(
6565 &mut self,
6566 buffer: Entity<Buffer>,
6567 range: Range<Anchor>,
6568 cx: &mut Context<Self>,
6569 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6570 let range_start = range.start;
6571 let range_end = range.end;
6572 let buffer_id = buffer.read(cx).remote_id().into();
6573 let request = InlayHints { range };
6574
6575 if let Some((client, project_id)) = self.upstream_client() {
6576 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6577 return Task::ready(Ok(Vec::new()));
6578 }
6579 let proto_request = proto::InlayHints {
6580 project_id,
6581 buffer_id,
6582 start: Some(serialize_anchor(&range_start)),
6583 end: Some(serialize_anchor(&range_end)),
6584 version: serialize_version(&buffer.read(cx).version()),
6585 };
6586 cx.spawn(async move |project, cx| {
6587 let response = client
6588 .request(proto_request)
6589 .await
6590 .context("inlay hints proto request")?;
6591 LspCommand::response_from_proto(
6592 request,
6593 response,
6594 project.upgrade().context("No project")?,
6595 buffer.clone(),
6596 cx.clone(),
6597 )
6598 .await
6599 .context("inlay hints proto response conversion")
6600 })
6601 } else {
6602 let lsp_request_task = self.request_lsp(
6603 buffer.clone(),
6604 LanguageServerToQuery::FirstCapable,
6605 request,
6606 cx,
6607 );
6608 cx.spawn(async move |_, cx| {
6609 buffer
6610 .update(cx, |buffer, _| {
6611 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6612 })?
6613 .await
6614 .context("waiting for inlay hint request range edits")?;
6615 lsp_request_task.await.context("inlay hints LSP request")
6616 })
6617 }
6618 }
6619
6620 pub fn pull_diagnostics_for_buffer(
6621 &mut self,
6622 buffer: Entity<Buffer>,
6623 cx: &mut Context<Self>,
6624 ) -> Task<anyhow::Result<()>> {
6625 let diagnostics = self.pull_diagnostics(buffer, cx);
6626 cx.spawn(async move |lsp_store, cx| {
6627 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6628 return Ok(());
6629 };
6630 lsp_store.update(cx, |lsp_store, cx| {
6631 if lsp_store.as_local().is_none() {
6632 return;
6633 }
6634
6635 let mut unchanged_buffers = HashSet::default();
6636 let mut changed_buffers = HashSet::default();
6637 let server_diagnostics_updates = diagnostics
6638 .into_iter()
6639 .filter_map(|diagnostics_set| match diagnostics_set {
6640 LspPullDiagnostics::Response {
6641 server_id,
6642 uri,
6643 diagnostics,
6644 } => Some((server_id, uri, diagnostics)),
6645 LspPullDiagnostics::Default => None,
6646 })
6647 .fold(
6648 HashMap::default(),
6649 |mut acc, (server_id, uri, diagnostics)| {
6650 let (result_id, diagnostics) = match diagnostics {
6651 PulledDiagnostics::Unchanged { result_id } => {
6652 unchanged_buffers.insert(uri.clone());
6653 (Some(result_id), Vec::new())
6654 }
6655 PulledDiagnostics::Changed {
6656 result_id,
6657 diagnostics,
6658 } => {
6659 changed_buffers.insert(uri.clone());
6660 (result_id, diagnostics)
6661 }
6662 };
6663 let disk_based_sources = Cow::Owned(
6664 lsp_store
6665 .language_server_adapter_for_id(server_id)
6666 .as_ref()
6667 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6668 .unwrap_or(&[])
6669 .to_vec(),
6670 );
6671 acc.entry(server_id).or_insert_with(Vec::new).push(
6672 DocumentDiagnosticsUpdate {
6673 server_id,
6674 diagnostics: lsp::PublishDiagnosticsParams {
6675 uri,
6676 diagnostics,
6677 version: None,
6678 },
6679 result_id,
6680 disk_based_sources,
6681 },
6682 );
6683 acc
6684 },
6685 );
6686
6687 for diagnostic_updates in server_diagnostics_updates.into_values() {
6688 lsp_store
6689 .merge_lsp_diagnostics(
6690 DiagnosticSourceKind::Pulled,
6691 diagnostic_updates,
6692 |buffer, old_diagnostic, cx| {
6693 File::from_dyn(buffer.file())
6694 .and_then(|file| {
6695 let abs_path = file.as_local()?.abs_path(cx);
6696 lsp::Url::from_file_path(abs_path).ok()
6697 })
6698 .is_none_or(|buffer_uri| {
6699 unchanged_buffers.contains(&buffer_uri)
6700 || match old_diagnostic.source_kind {
6701 DiagnosticSourceKind::Pulled => {
6702 !changed_buffers.contains(&buffer_uri)
6703 }
6704 DiagnosticSourceKind::Other
6705 | DiagnosticSourceKind::Pushed => true,
6706 }
6707 })
6708 },
6709 cx,
6710 )
6711 .log_err();
6712 }
6713 })
6714 })
6715 }
6716
6717 pub fn document_colors(
6718 &mut self,
6719 fetch_strategy: LspFetchStrategy,
6720 buffer: Entity<Buffer>,
6721 cx: &mut Context<Self>,
6722 ) -> Option<DocumentColorTask> {
6723 let version_queried_for = buffer.read(cx).version();
6724 let buffer_id = buffer.read(cx).remote_id();
6725
6726 match fetch_strategy {
6727 LspFetchStrategy::IgnoreCache => {}
6728 LspFetchStrategy::UseCache {
6729 known_cache_version,
6730 } => {
6731 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6732 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6733 {
6734 let has_different_servers = self.as_local().is_some_and(|local| {
6735 local
6736 .buffers_opened_in_servers
6737 .get(&buffer_id)
6738 .cloned()
6739 .unwrap_or_default()
6740 != cached_data.colors.keys().copied().collect()
6741 });
6742 if !has_different_servers {
6743 if Some(cached_data.cache_version) == known_cache_version {
6744 return None;
6745 } else {
6746 return Some(
6747 Task::ready(Ok(DocumentColors {
6748 colors: cached_data
6749 .colors
6750 .values()
6751 .flatten()
6752 .cloned()
6753 .collect(),
6754 cache_version: Some(cached_data.cache_version),
6755 }))
6756 .shared(),
6757 );
6758 }
6759 }
6760 }
6761 }
6762 }
6763
6764 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6765 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6766 && !version_queried_for.changed_since(updating_for)
6767 {
6768 return Some(running_update.clone());
6769 }
6770 let query_version_queried_for = version_queried_for.clone();
6771 let new_task = cx
6772 .spawn(async move |lsp_store, cx| {
6773 cx.background_executor()
6774 .timer(Duration::from_millis(30))
6775 .await;
6776 let fetched_colors = lsp_store
6777 .update(cx, |lsp_store, cx| {
6778 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6779 })?
6780 .await
6781 .context("fetching document colors")
6782 .map_err(Arc::new);
6783 let fetched_colors = match fetched_colors {
6784 Ok(fetched_colors) => {
6785 if fetch_strategy != LspFetchStrategy::IgnoreCache
6786 && Some(true)
6787 == buffer
6788 .update(cx, |buffer, _| {
6789 buffer.version() != query_version_queried_for
6790 })
6791 .ok()
6792 {
6793 return Ok(DocumentColors::default());
6794 }
6795 fetched_colors
6796 }
6797 Err(e) => {
6798 lsp_store
6799 .update(cx, |lsp_store, _| {
6800 lsp_store
6801 .lsp_document_colors
6802 .entry(buffer_id)
6803 .or_default()
6804 .colors_update = None;
6805 })
6806 .ok();
6807 return Err(e);
6808 }
6809 };
6810
6811 lsp_store
6812 .update(cx, |lsp_store, _| {
6813 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6814
6815 if lsp_data.colors_for_version == query_version_queried_for {
6816 lsp_data.colors.extend(fetched_colors.clone());
6817 lsp_data.cache_version += 1;
6818 } else if !lsp_data
6819 .colors_for_version
6820 .changed_since(&query_version_queried_for)
6821 {
6822 lsp_data.colors_for_version = query_version_queried_for;
6823 lsp_data.colors = fetched_colors.clone();
6824 lsp_data.cache_version += 1;
6825 }
6826 lsp_data.colors_update = None;
6827 let colors = lsp_data
6828 .colors
6829 .values()
6830 .flatten()
6831 .cloned()
6832 .collect::<HashSet<_>>();
6833 DocumentColors {
6834 colors,
6835 cache_version: Some(lsp_data.cache_version),
6836 }
6837 })
6838 .map_err(Arc::new)
6839 })
6840 .shared();
6841 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6842 Some(new_task)
6843 }
6844
6845 fn fetch_document_colors_for_buffer(
6846 &mut self,
6847 buffer: &Entity<Buffer>,
6848 cx: &mut Context<Self>,
6849 ) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
6850 if let Some((client, project_id)) = self.upstream_client() {
6851 let request = GetDocumentColor {};
6852 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6853 return Task::ready(Ok(HashMap::default()));
6854 }
6855
6856 let request_task = client.request(proto::MultiLspQuery {
6857 project_id,
6858 buffer_id: buffer.read(cx).remote_id().to_proto(),
6859 version: serialize_version(&buffer.read(cx).version()),
6860 strategy: Some(proto::multi_lsp_query::Strategy::All(
6861 proto::AllLanguageServers {},
6862 )),
6863 request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
6864 request.to_proto(project_id, buffer.read(cx)),
6865 )),
6866 });
6867 let buffer = buffer.clone();
6868 cx.spawn(async move |project, cx| {
6869 let Some(project) = project.upgrade() else {
6870 return Ok(HashMap::default());
6871 };
6872 let colors = join_all(
6873 request_task
6874 .await
6875 .log_err()
6876 .map(|response| response.responses)
6877 .unwrap_or_default()
6878 .into_iter()
6879 .filter_map(|lsp_response| match lsp_response.response? {
6880 proto::lsp_response::Response::GetDocumentColorResponse(response) => {
6881 Some((
6882 LanguageServerId::from_proto(lsp_response.server_id),
6883 response,
6884 ))
6885 }
6886 unexpected => {
6887 debug_panic!("Unexpected response: {unexpected:?}");
6888 None
6889 }
6890 })
6891 .map(|(server_id, color_response)| {
6892 let response = request.response_from_proto(
6893 color_response,
6894 project.clone(),
6895 buffer.clone(),
6896 cx.clone(),
6897 );
6898 async move { (server_id, response.await.log_err().unwrap_or_default()) }
6899 }),
6900 )
6901 .await
6902 .into_iter()
6903 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6904 acc.entry(server_id)
6905 .or_insert_with(HashSet::default)
6906 .extend(colors);
6907 acc
6908 });
6909 Ok(colors)
6910 })
6911 } else {
6912 let document_colors_task =
6913 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6914 cx.background_spawn(async move {
6915 Ok(document_colors_task
6916 .await
6917 .into_iter()
6918 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6919 acc.entry(server_id)
6920 .or_insert_with(HashSet::default)
6921 .extend(colors);
6922 acc
6923 })
6924 .into_iter()
6925 .collect())
6926 })
6927 }
6928 }
6929
6930 pub fn signature_help<T: ToPointUtf16>(
6931 &mut self,
6932 buffer: &Entity<Buffer>,
6933 position: T,
6934 cx: &mut Context<Self>,
6935 ) -> Task<Vec<SignatureHelp>> {
6936 let position = position.to_point_utf16(buffer.read(cx));
6937
6938 if let Some((client, upstream_project_id)) = self.upstream_client() {
6939 let request = GetSignatureHelp { position };
6940 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6941 return Task::ready(Vec::new());
6942 }
6943 let request_task = client.request(proto::MultiLspQuery {
6944 buffer_id: buffer.read(cx).remote_id().into(),
6945 version: serialize_version(&buffer.read(cx).version()),
6946 project_id: upstream_project_id,
6947 strategy: Some(proto::multi_lsp_query::Strategy::All(
6948 proto::AllLanguageServers {},
6949 )),
6950 request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
6951 request.to_proto(upstream_project_id, buffer.read(cx)),
6952 )),
6953 });
6954 let buffer = buffer.clone();
6955 cx.spawn(async move |weak_project, cx| {
6956 let Some(project) = weak_project.upgrade() else {
6957 return Vec::new();
6958 };
6959 join_all(
6960 request_task
6961 .await
6962 .log_err()
6963 .map(|response| response.responses)
6964 .unwrap_or_default()
6965 .into_iter()
6966 .filter_map(|lsp_response| match lsp_response.response? {
6967 proto::lsp_response::Response::GetSignatureHelpResponse(response) => {
6968 Some(response)
6969 }
6970 unexpected => {
6971 debug_panic!("Unexpected response: {unexpected:?}");
6972 None
6973 }
6974 })
6975 .map(|signature_response| {
6976 let response = GetSignatureHelp { position }.response_from_proto(
6977 signature_response,
6978 project.clone(),
6979 buffer.clone(),
6980 cx.clone(),
6981 );
6982 async move { response.await.log_err().flatten() }
6983 }),
6984 )
6985 .await
6986 .into_iter()
6987 .flatten()
6988 .collect()
6989 })
6990 } else {
6991 let all_actions_task = self.request_multiple_lsp_locally(
6992 buffer,
6993 Some(position),
6994 GetSignatureHelp { position },
6995 cx,
6996 );
6997 cx.background_spawn(async move {
6998 all_actions_task
6999 .await
7000 .into_iter()
7001 .flat_map(|(_, actions)| actions)
7002 .collect::<Vec<_>>()
7003 })
7004 }
7005 }
7006
7007 pub fn hover(
7008 &mut self,
7009 buffer: &Entity<Buffer>,
7010 position: PointUtf16,
7011 cx: &mut Context<Self>,
7012 ) -> Task<Vec<Hover>> {
7013 if let Some((client, upstream_project_id)) = self.upstream_client() {
7014 let request = GetHover { position };
7015 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7016 return Task::ready(Vec::new());
7017 }
7018 let request_task = client.request(proto::MultiLspQuery {
7019 buffer_id: buffer.read(cx).remote_id().into(),
7020 version: serialize_version(&buffer.read(cx).version()),
7021 project_id: upstream_project_id,
7022 strategy: Some(proto::multi_lsp_query::Strategy::All(
7023 proto::AllLanguageServers {},
7024 )),
7025 request: Some(proto::multi_lsp_query::Request::GetHover(
7026 request.to_proto(upstream_project_id, buffer.read(cx)),
7027 )),
7028 });
7029 let buffer = buffer.clone();
7030 cx.spawn(async move |weak_project, cx| {
7031 let Some(project) = weak_project.upgrade() else {
7032 return Vec::new();
7033 };
7034 join_all(
7035 request_task
7036 .await
7037 .log_err()
7038 .map(|response| response.responses)
7039 .unwrap_or_default()
7040 .into_iter()
7041 .filter_map(|lsp_response| match lsp_response.response? {
7042 proto::lsp_response::Response::GetHoverResponse(response) => {
7043 Some(response)
7044 }
7045 unexpected => {
7046 debug_panic!("Unexpected response: {unexpected:?}");
7047 None
7048 }
7049 })
7050 .map(|hover_response| {
7051 let response = GetHover { position }.response_from_proto(
7052 hover_response,
7053 project.clone(),
7054 buffer.clone(),
7055 cx.clone(),
7056 );
7057 async move {
7058 response
7059 .await
7060 .log_err()
7061 .flatten()
7062 .and_then(remove_empty_hover_blocks)
7063 }
7064 }),
7065 )
7066 .await
7067 .into_iter()
7068 .flatten()
7069 .collect()
7070 })
7071 } else {
7072 let all_actions_task = self.request_multiple_lsp_locally(
7073 buffer,
7074 Some(position),
7075 GetHover { position },
7076 cx,
7077 );
7078 cx.background_spawn(async move {
7079 all_actions_task
7080 .await
7081 .into_iter()
7082 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7083 .collect::<Vec<Hover>>()
7084 })
7085 }
7086 }
7087
7088 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7089 let language_registry = self.languages.clone();
7090
7091 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7092 let request = upstream_client.request(proto::GetProjectSymbols {
7093 project_id: *project_id,
7094 query: query.to_string(),
7095 });
7096 cx.foreground_executor().spawn(async move {
7097 let response = request.await?;
7098 let mut symbols = Vec::new();
7099 let core_symbols = response
7100 .symbols
7101 .into_iter()
7102 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7103 .collect::<Vec<_>>();
7104 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7105 .await;
7106 Ok(symbols)
7107 })
7108 } else if let Some(local) = self.as_local() {
7109 struct WorkspaceSymbolsResult {
7110 server_id: LanguageServerId,
7111 lsp_adapter: Arc<CachedLspAdapter>,
7112 worktree: WeakEntity<Worktree>,
7113 worktree_abs_path: Arc<Path>,
7114 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7115 }
7116
7117 let mut requests = Vec::new();
7118 let mut requested_servers = BTreeSet::new();
7119 for (seed, state) in local.language_server_ids.iter() {
7120 let Some(worktree_handle) = self
7121 .worktree_store
7122 .read(cx)
7123 .worktree_for_id(seed.worktree_id, cx)
7124 else {
7125 continue;
7126 };
7127 let worktree = worktree_handle.read(cx);
7128 if !worktree.is_visible() {
7129 continue;
7130 }
7131
7132 if !requested_servers.insert(state.id) {
7133 continue;
7134 }
7135
7136 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7137 Some(LanguageServerState::Running {
7138 adapter, server, ..
7139 }) => (adapter.clone(), server),
7140
7141 _ => continue,
7142 };
7143 let supports_workspace_symbol_request =
7144 match server.capabilities().workspace_symbol_provider {
7145 Some(OneOf::Left(supported)) => supported,
7146 Some(OneOf::Right(_)) => true,
7147 None => false,
7148 };
7149 if !supports_workspace_symbol_request {
7150 continue;
7151 }
7152 let worktree_abs_path = worktree.abs_path().clone();
7153 let worktree_handle = worktree_handle.clone();
7154 let server_id = server.server_id();
7155 requests.push(
7156 server
7157 .request::<lsp::request::WorkspaceSymbolRequest>(
7158 lsp::WorkspaceSymbolParams {
7159 query: query.to_string(),
7160 ..Default::default()
7161 },
7162 )
7163 .map(move |response| {
7164 let lsp_symbols = response.into_response()
7165 .context("workspace symbols request")
7166 .log_err()
7167 .flatten()
7168 .map(|symbol_response| match symbol_response {
7169 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7170 flat_responses.into_iter().map(|lsp_symbol| {
7171 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7172 }).collect::<Vec<_>>()
7173 }
7174 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7175 nested_responses.into_iter().filter_map(|lsp_symbol| {
7176 let location = match lsp_symbol.location {
7177 OneOf::Left(location) => location,
7178 OneOf::Right(_) => {
7179 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7180 return None
7181 }
7182 };
7183 Some((lsp_symbol.name, lsp_symbol.kind, location))
7184 }).collect::<Vec<_>>()
7185 }
7186 }).unwrap_or_default();
7187
7188 WorkspaceSymbolsResult {
7189 server_id,
7190 lsp_adapter,
7191 worktree: worktree_handle.downgrade(),
7192 worktree_abs_path,
7193 lsp_symbols,
7194 }
7195 }),
7196 );
7197 }
7198
7199 cx.spawn(async move |this, cx| {
7200 let responses = futures::future::join_all(requests).await;
7201 let this = match this.upgrade() {
7202 Some(this) => this,
7203 None => return Ok(Vec::new()),
7204 };
7205
7206 let mut symbols = Vec::new();
7207 for result in responses {
7208 let core_symbols = this.update(cx, |this, cx| {
7209 result
7210 .lsp_symbols
7211 .into_iter()
7212 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7213 let abs_path = symbol_location.uri.to_file_path().ok()?;
7214 let source_worktree = result.worktree.upgrade()?;
7215 let source_worktree_id = source_worktree.read(cx).id();
7216
7217 let path;
7218 let worktree;
7219 if let Some((tree, rel_path)) =
7220 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7221 {
7222 worktree = tree;
7223 path = rel_path;
7224 } else {
7225 worktree = source_worktree.clone();
7226 path = relativize_path(&result.worktree_abs_path, &abs_path);
7227 }
7228
7229 let worktree_id = worktree.read(cx).id();
7230 let project_path = ProjectPath {
7231 worktree_id,
7232 path: path.into(),
7233 };
7234 let signature = this.symbol_signature(&project_path);
7235 Some(CoreSymbol {
7236 source_language_server_id: result.server_id,
7237 language_server_name: result.lsp_adapter.name.clone(),
7238 source_worktree_id,
7239 path: project_path,
7240 kind: symbol_kind,
7241 name: symbol_name,
7242 range: range_from_lsp(symbol_location.range),
7243 signature,
7244 })
7245 })
7246 .collect()
7247 })?;
7248
7249 populate_labels_for_symbols(
7250 core_symbols,
7251 &language_registry,
7252 Some(result.lsp_adapter),
7253 &mut symbols,
7254 )
7255 .await;
7256 }
7257
7258 Ok(symbols)
7259 })
7260 } else {
7261 Task::ready(Err(anyhow!("No upstream client or local language server")))
7262 }
7263 }
7264
7265 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7266 let mut summary = DiagnosticSummary::default();
7267 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7268 summary.error_count += path_summary.error_count;
7269 summary.warning_count += path_summary.warning_count;
7270 }
7271 summary
7272 }
7273
7274 pub fn diagnostic_summaries<'a>(
7275 &'a self,
7276 include_ignored: bool,
7277 cx: &'a App,
7278 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7279 self.worktree_store
7280 .read(cx)
7281 .visible_worktrees(cx)
7282 .filter_map(|worktree| {
7283 let worktree = worktree.read(cx);
7284 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7285 })
7286 .flat_map(move |(worktree, summaries)| {
7287 let worktree_id = worktree.id();
7288 summaries
7289 .iter()
7290 .filter(move |(path, _)| {
7291 include_ignored
7292 || worktree
7293 .entry_for_path(path.as_ref())
7294 .is_some_and(|entry| !entry.is_ignored)
7295 })
7296 .flat_map(move |(path, summaries)| {
7297 summaries.iter().map(move |(server_id, summary)| {
7298 (
7299 ProjectPath {
7300 worktree_id,
7301 path: path.clone(),
7302 },
7303 *server_id,
7304 *summary,
7305 )
7306 })
7307 })
7308 })
7309 }
7310
7311 pub fn on_buffer_edited(
7312 &mut self,
7313 buffer: Entity<Buffer>,
7314 cx: &mut Context<Self>,
7315 ) -> Option<()> {
7316 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7317 Some(
7318 self.as_local()?
7319 .language_servers_for_buffer(buffer, cx)
7320 .map(|i| i.1.clone())
7321 .collect(),
7322 )
7323 })?;
7324
7325 let buffer = buffer.read(cx);
7326 let file = File::from_dyn(buffer.file())?;
7327 let abs_path = file.as_local()?.abs_path(cx);
7328 let uri = lsp::Url::from_file_path(abs_path).unwrap();
7329 let next_snapshot = buffer.text_snapshot();
7330 for language_server in language_servers {
7331 let language_server = language_server.clone();
7332
7333 let buffer_snapshots = self
7334 .as_local_mut()
7335 .unwrap()
7336 .buffer_snapshots
7337 .get_mut(&buffer.remote_id())
7338 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7339 let previous_snapshot = buffer_snapshots.last()?;
7340
7341 let build_incremental_change = || {
7342 buffer
7343 .edits_since::<Dimensions<PointUtf16, usize>>(
7344 previous_snapshot.snapshot.version(),
7345 )
7346 .map(|edit| {
7347 let edit_start = edit.new.start.0;
7348 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7349 let new_text = next_snapshot
7350 .text_for_range(edit.new.start.1..edit.new.end.1)
7351 .collect();
7352 lsp::TextDocumentContentChangeEvent {
7353 range: Some(lsp::Range::new(
7354 point_to_lsp(edit_start),
7355 point_to_lsp(edit_end),
7356 )),
7357 range_length: None,
7358 text: new_text,
7359 }
7360 })
7361 .collect()
7362 };
7363
7364 let document_sync_kind = language_server
7365 .capabilities()
7366 .text_document_sync
7367 .as_ref()
7368 .and_then(|sync| match sync {
7369 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7370 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7371 });
7372
7373 let content_changes: Vec<_> = match document_sync_kind {
7374 Some(lsp::TextDocumentSyncKind::FULL) => {
7375 vec![lsp::TextDocumentContentChangeEvent {
7376 range: None,
7377 range_length: None,
7378 text: next_snapshot.text(),
7379 }]
7380 }
7381 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7382 _ => {
7383 #[cfg(any(test, feature = "test-support"))]
7384 {
7385 build_incremental_change()
7386 }
7387
7388 #[cfg(not(any(test, feature = "test-support")))]
7389 {
7390 continue;
7391 }
7392 }
7393 };
7394
7395 let next_version = previous_snapshot.version + 1;
7396 buffer_snapshots.push(LspBufferSnapshot {
7397 version: next_version,
7398 snapshot: next_snapshot.clone(),
7399 });
7400
7401 language_server
7402 .notify::<lsp::notification::DidChangeTextDocument>(
7403 &lsp::DidChangeTextDocumentParams {
7404 text_document: lsp::VersionedTextDocumentIdentifier::new(
7405 uri.clone(),
7406 next_version,
7407 ),
7408 content_changes,
7409 },
7410 )
7411 .ok();
7412 self.pull_workspace_diagnostics(language_server.server_id());
7413 }
7414
7415 None
7416 }
7417
7418 pub fn on_buffer_saved(
7419 &mut self,
7420 buffer: Entity<Buffer>,
7421 cx: &mut Context<Self>,
7422 ) -> Option<()> {
7423 let file = File::from_dyn(buffer.read(cx).file())?;
7424 let worktree_id = file.worktree_id(cx);
7425 let abs_path = file.as_local()?.abs_path(cx);
7426 let text_document = lsp::TextDocumentIdentifier {
7427 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7428 };
7429 let local = self.as_local()?;
7430
7431 for server in local.language_servers_for_worktree(worktree_id) {
7432 if let Some(include_text) = include_text(server.as_ref()) {
7433 let text = if include_text {
7434 Some(buffer.read(cx).text())
7435 } else {
7436 None
7437 };
7438 server
7439 .notify::<lsp::notification::DidSaveTextDocument>(
7440 &lsp::DidSaveTextDocumentParams {
7441 text_document: text_document.clone(),
7442 text,
7443 },
7444 )
7445 .ok();
7446 }
7447 }
7448
7449 let language_servers = buffer.update(cx, |buffer, cx| {
7450 local.language_server_ids_for_buffer(buffer, cx)
7451 });
7452 for language_server_id in language_servers {
7453 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7454 }
7455
7456 None
7457 }
7458
7459 async fn refresh_workspace_configurations(
7460 lsp_store: &WeakEntity<Self>,
7461 fs: Arc<dyn Fs>,
7462 cx: &mut AsyncApp,
7463 ) {
7464 maybe!(async move {
7465 let mut refreshed_servers = HashSet::default();
7466 let servers = lsp_store
7467 .update(cx, |lsp_store, cx| {
7468 let local = lsp_store.as_local()?;
7469
7470 let servers = local
7471 .language_server_ids
7472 .iter()
7473 .filter_map(|(seed, state)| {
7474 let worktree = lsp_store
7475 .worktree_store
7476 .read(cx)
7477 .worktree_for_id(seed.worktree_id, cx);
7478 let delegate: Arc<dyn LspAdapterDelegate> =
7479 worktree.map(|worktree| {
7480 LocalLspAdapterDelegate::new(
7481 local.languages.clone(),
7482 &local.environment,
7483 cx.weak_entity(),
7484 &worktree,
7485 local.http_client.clone(),
7486 local.fs.clone(),
7487 cx,
7488 )
7489 })?;
7490 let server_id = state.id;
7491
7492 let states = local.language_servers.get(&server_id)?;
7493
7494 match states {
7495 LanguageServerState::Starting { .. } => None,
7496 LanguageServerState::Running {
7497 adapter, server, ..
7498 } => {
7499 let fs = fs.clone();
7500
7501 let adapter = adapter.clone();
7502 let server = server.clone();
7503 refreshed_servers.insert(server.name());
7504 let toolchain = seed.toolchain.clone();
7505 Some(cx.spawn(async move |_, cx| {
7506 let settings =
7507 LocalLspStore::workspace_configuration_for_adapter(
7508 adapter.adapter.clone(),
7509 fs.as_ref(),
7510 &delegate,
7511 toolchain,
7512 cx,
7513 )
7514 .await
7515 .ok()?;
7516 server
7517 .notify::<lsp::notification::DidChangeConfiguration>(
7518 &lsp::DidChangeConfigurationParams { settings },
7519 )
7520 .ok()?;
7521 Some(())
7522 }))
7523 }
7524 }
7525 })
7526 .collect::<Vec<_>>();
7527
7528 Some(servers)
7529 })
7530 .ok()
7531 .flatten()?;
7532
7533 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7534 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7535 // to stop and unregister its language server wrapper.
7536 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7537 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7538 let _: Vec<Option<()>> = join_all(servers).await;
7539
7540 Some(())
7541 })
7542 .await;
7543 }
7544
7545 fn maintain_workspace_config(
7546 fs: Arc<dyn Fs>,
7547 external_refresh_requests: watch::Receiver<()>,
7548 cx: &mut Context<Self>,
7549 ) -> Task<Result<()>> {
7550 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7551 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7552
7553 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7554 *settings_changed_tx.borrow_mut() = ();
7555 });
7556
7557 let mut joint_future =
7558 futures::stream::select(settings_changed_rx, external_refresh_requests);
7559 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7560 // - We might shut down a language server if it's no longer enabled for a given language (and there are no buffers using it otherwise).
7561 // - We might also shut it down when the workspace configuration of all of the users of a given language server converges onto that of the other.
7562 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7563 // - In the easiest case (where we're not wrangling the lifetime of a language server anyhow), if none of the roots of a single language server diverge in their configuration,
7564 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7565 cx.spawn(async move |this, cx| {
7566 while let Some(()) = joint_future.next().await {
7567 this.update(cx, |this, cx| {
7568 this.refresh_server_tree(cx);
7569 })
7570 .ok();
7571
7572 Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
7573 }
7574
7575 drop(settings_observation);
7576 anyhow::Ok(())
7577 })
7578 }
7579
7580 pub fn language_servers_for_local_buffer<'a>(
7581 &'a self,
7582 buffer: &Buffer,
7583 cx: &mut App,
7584 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7585 let local = self.as_local();
7586 let language_server_ids = local
7587 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7588 .unwrap_or_default();
7589
7590 language_server_ids
7591 .into_iter()
7592 .filter_map(
7593 move |server_id| match local?.language_servers.get(&server_id)? {
7594 LanguageServerState::Running {
7595 adapter, server, ..
7596 } => Some((adapter, server)),
7597 _ => None,
7598 },
7599 )
7600 }
7601
7602 pub fn language_server_for_local_buffer<'a>(
7603 &'a self,
7604 buffer: &'a Buffer,
7605 server_id: LanguageServerId,
7606 cx: &'a mut App,
7607 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7608 self.as_local()?
7609 .language_servers_for_buffer(buffer, cx)
7610 .find(|(_, s)| s.server_id() == server_id)
7611 }
7612
7613 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7614 self.diagnostic_summaries.remove(&id_to_remove);
7615 if let Some(local) = self.as_local_mut() {
7616 let to_remove = local.remove_worktree(id_to_remove, cx);
7617 for server in to_remove {
7618 self.language_server_statuses.remove(&server);
7619 }
7620 }
7621 }
7622
7623 pub fn shared(
7624 &mut self,
7625 project_id: u64,
7626 downstream_client: AnyProtoClient,
7627 _: &mut Context<Self>,
7628 ) {
7629 self.downstream_client = Some((downstream_client.clone(), project_id));
7630
7631 for (server_id, status) in &self.language_server_statuses {
7632 if let Some(server) = self.language_server_for_id(*server_id) {
7633 downstream_client
7634 .send(proto::StartLanguageServer {
7635 project_id,
7636 server: Some(proto::LanguageServer {
7637 id: server_id.to_proto(),
7638 name: status.name.to_string(),
7639 worktree_id: None,
7640 }),
7641 capabilities: serde_json::to_string(&server.capabilities())
7642 .expect("serializing server LSP capabilities"),
7643 })
7644 .log_err();
7645 }
7646 }
7647 }
7648
7649 pub fn disconnected_from_host(&mut self) {
7650 self.downstream_client.take();
7651 }
7652
7653 pub fn disconnected_from_ssh_remote(&mut self) {
7654 if let LspStoreMode::Remote(RemoteLspStore {
7655 upstream_client, ..
7656 }) = &mut self.mode
7657 {
7658 upstream_client.take();
7659 }
7660 }
7661
7662 pub(crate) fn set_language_server_statuses_from_proto(
7663 &mut self,
7664 language_servers: Vec<proto::LanguageServer>,
7665 server_capabilities: Vec<String>,
7666 ) {
7667 self.language_server_statuses = language_servers
7668 .into_iter()
7669 .zip(server_capabilities)
7670 .map(|(server, server_capabilities)| {
7671 let server_id = LanguageServerId(server.id as usize);
7672 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7673 self.lsp_server_capabilities
7674 .insert(server_id, server_capabilities);
7675 }
7676 (
7677 server_id,
7678 LanguageServerStatus {
7679 name: LanguageServerName::from_proto(server.name),
7680 pending_work: Default::default(),
7681 has_pending_diagnostic_updates: false,
7682 progress_tokens: Default::default(),
7683 },
7684 )
7685 })
7686 .collect();
7687 }
7688
7689 #[cfg(test)]
7690 pub fn update_diagnostic_entries(
7691 &mut self,
7692 server_id: LanguageServerId,
7693 abs_path: PathBuf,
7694 result_id: Option<String>,
7695 version: Option<i32>,
7696 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7697 cx: &mut Context<Self>,
7698 ) -> anyhow::Result<()> {
7699 self.merge_diagnostic_entries(
7700 vec![DocumentDiagnosticsUpdate {
7701 diagnostics: DocumentDiagnostics {
7702 diagnostics,
7703 document_abs_path: abs_path,
7704 version,
7705 },
7706 result_id,
7707 server_id,
7708 disk_based_sources: Cow::Borrowed(&[]),
7709 }],
7710 |_, _, _| false,
7711 cx,
7712 )?;
7713 Ok(())
7714 }
7715
7716 pub fn merge_diagnostic_entries<'a>(
7717 &mut self,
7718 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7719 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7720 cx: &mut Context<Self>,
7721 ) -> anyhow::Result<()> {
7722 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7723 let mut updated_diagnostics_paths = HashMap::default();
7724 for mut update in diagnostic_updates {
7725 let abs_path = &update.diagnostics.document_abs_path;
7726 let server_id = update.server_id;
7727 let Some((worktree, relative_path)) =
7728 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7729 else {
7730 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7731 return Ok(());
7732 };
7733
7734 let worktree_id = worktree.read(cx).id();
7735 let project_path = ProjectPath {
7736 worktree_id,
7737 path: relative_path.into(),
7738 };
7739
7740 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7741 let snapshot = buffer_handle.read(cx).snapshot();
7742 let buffer = buffer_handle.read(cx);
7743 let reused_diagnostics = buffer
7744 .get_diagnostics(server_id)
7745 .into_iter()
7746 .flat_map(|diag| {
7747 diag.iter()
7748 .filter(|v| merge(buffer, &v.diagnostic, cx))
7749 .map(|v| {
7750 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7751 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7752 DiagnosticEntry {
7753 range: start..end,
7754 diagnostic: v.diagnostic.clone(),
7755 }
7756 })
7757 })
7758 .collect::<Vec<_>>();
7759
7760 self.as_local_mut()
7761 .context("cannot merge diagnostics on a remote LspStore")?
7762 .update_buffer_diagnostics(
7763 &buffer_handle,
7764 server_id,
7765 update.result_id,
7766 update.diagnostics.version,
7767 update.diagnostics.diagnostics.clone(),
7768 reused_diagnostics.clone(),
7769 cx,
7770 )?;
7771
7772 update.diagnostics.diagnostics.extend(reused_diagnostics);
7773 }
7774
7775 let updated = worktree.update(cx, |worktree, cx| {
7776 self.update_worktree_diagnostics(
7777 worktree.id(),
7778 server_id,
7779 project_path.path.clone(),
7780 update.diagnostics.diagnostics,
7781 cx,
7782 )
7783 })?;
7784 match updated {
7785 ControlFlow::Continue(new_summary) => {
7786 if let Some((project_id, new_summary)) = new_summary {
7787 match &mut diagnostics_summary {
7788 Some(diagnostics_summary) => {
7789 diagnostics_summary
7790 .more_summaries
7791 .push(proto::DiagnosticSummary {
7792 path: project_path.path.as_ref().to_proto(),
7793 language_server_id: server_id.0 as u64,
7794 error_count: new_summary.error_count,
7795 warning_count: new_summary.warning_count,
7796 })
7797 }
7798 None => {
7799 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7800 project_id,
7801 worktree_id: worktree_id.to_proto(),
7802 summary: Some(proto::DiagnosticSummary {
7803 path: project_path.path.as_ref().to_proto(),
7804 language_server_id: server_id.0 as u64,
7805 error_count: new_summary.error_count,
7806 warning_count: new_summary.warning_count,
7807 }),
7808 more_summaries: Vec::new(),
7809 })
7810 }
7811 }
7812 }
7813 updated_diagnostics_paths
7814 .entry(server_id)
7815 .or_insert_with(Vec::new)
7816 .push(project_path);
7817 }
7818 ControlFlow::Break(()) => {}
7819 }
7820 }
7821
7822 if let Some((diagnostics_summary, (downstream_client, _))) =
7823 diagnostics_summary.zip(self.downstream_client.as_ref())
7824 {
7825 downstream_client.send(diagnostics_summary).log_err();
7826 }
7827 for (server_id, paths) in updated_diagnostics_paths {
7828 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7829 }
7830 Ok(())
7831 }
7832
7833 fn update_worktree_diagnostics(
7834 &mut self,
7835 worktree_id: WorktreeId,
7836 server_id: LanguageServerId,
7837 path_in_worktree: Arc<Path>,
7838 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7839 _: &mut Context<Worktree>,
7840 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7841 let local = match &mut self.mode {
7842 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7843 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7844 };
7845
7846 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7847 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7848 let summaries_by_server_id = summaries_for_tree
7849 .entry(path_in_worktree.clone())
7850 .or_default();
7851
7852 let old_summary = summaries_by_server_id
7853 .remove(&server_id)
7854 .unwrap_or_default();
7855
7856 let new_summary = DiagnosticSummary::new(&diagnostics);
7857 if new_summary.is_empty() {
7858 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7859 {
7860 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7861 diagnostics_by_server_id.remove(ix);
7862 }
7863 if diagnostics_by_server_id.is_empty() {
7864 diagnostics_for_tree.remove(&path_in_worktree);
7865 }
7866 }
7867 } else {
7868 summaries_by_server_id.insert(server_id, new_summary);
7869 let diagnostics_by_server_id = diagnostics_for_tree
7870 .entry(path_in_worktree.clone())
7871 .or_default();
7872 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7873 Ok(ix) => {
7874 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7875 }
7876 Err(ix) => {
7877 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7878 }
7879 }
7880 }
7881
7882 if !old_summary.is_empty() || !new_summary.is_empty() {
7883 if let Some((_, project_id)) = &self.downstream_client {
7884 Ok(ControlFlow::Continue(Some((
7885 *project_id,
7886 proto::DiagnosticSummary {
7887 path: path_in_worktree.to_proto(),
7888 language_server_id: server_id.0 as u64,
7889 error_count: new_summary.error_count as u32,
7890 warning_count: new_summary.warning_count as u32,
7891 },
7892 ))))
7893 } else {
7894 Ok(ControlFlow::Continue(None))
7895 }
7896 } else {
7897 Ok(ControlFlow::Break(()))
7898 }
7899 }
7900
7901 pub fn open_buffer_for_symbol(
7902 &mut self,
7903 symbol: &Symbol,
7904 cx: &mut Context<Self>,
7905 ) -> Task<Result<Entity<Buffer>>> {
7906 if let Some((client, project_id)) = self.upstream_client() {
7907 let request = client.request(proto::OpenBufferForSymbol {
7908 project_id,
7909 symbol: Some(Self::serialize_symbol(symbol)),
7910 });
7911 cx.spawn(async move |this, cx| {
7912 let response = request.await?;
7913 let buffer_id = BufferId::new(response.buffer_id)?;
7914 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7915 .await
7916 })
7917 } else if let Some(local) = self.as_local() {
7918 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7919 seed.worktree_id == symbol.source_worktree_id
7920 && state.id == symbol.source_language_server_id
7921 && symbol.language_server_name == seed.name
7922 });
7923 if !is_valid {
7924 return Task::ready(Err(anyhow!(
7925 "language server for worktree and language not found"
7926 )));
7927 };
7928
7929 let worktree_abs_path = if let Some(worktree_abs_path) = self
7930 .worktree_store
7931 .read(cx)
7932 .worktree_for_id(symbol.path.worktree_id, cx)
7933 .map(|worktree| worktree.read(cx).abs_path())
7934 {
7935 worktree_abs_path
7936 } else {
7937 return Task::ready(Err(anyhow!("worktree not found for symbol")));
7938 };
7939
7940 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
7941 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
7942 uri
7943 } else {
7944 return Task::ready(Err(anyhow!("invalid symbol path")));
7945 };
7946
7947 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7948 } else {
7949 Task::ready(Err(anyhow!("no upstream client or local store")))
7950 }
7951 }
7952
7953 pub(crate) fn open_local_buffer_via_lsp(
7954 &mut self,
7955 mut abs_path: lsp::Url,
7956 language_server_id: LanguageServerId,
7957 cx: &mut Context<Self>,
7958 ) -> Task<Result<Entity<Buffer>>> {
7959 cx.spawn(async move |lsp_store, cx| {
7960 // Escape percent-encoded string.
7961 let current_scheme = abs_path.scheme().to_owned();
7962 let _ = abs_path.set_scheme("file");
7963
7964 let abs_path = abs_path
7965 .to_file_path()
7966 .map_err(|()| anyhow!("can't convert URI to path"))?;
7967 let p = abs_path.clone();
7968 let yarn_worktree = lsp_store
7969 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7970 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7971 cx.spawn(async move |this, cx| {
7972 let t = this
7973 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7974 .ok()?;
7975 t.await
7976 })
7977 }),
7978 None => Task::ready(None),
7979 })?
7980 .await;
7981 let (worktree_root_target, known_relative_path) =
7982 if let Some((zip_root, relative_path)) = yarn_worktree {
7983 (zip_root, Some(relative_path))
7984 } else {
7985 (Arc::<Path>::from(abs_path.as_path()), None)
7986 };
7987 let (worktree, relative_path) = if let Some(result) =
7988 lsp_store.update(cx, |lsp_store, cx| {
7989 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7990 worktree_store.find_worktree(&worktree_root_target, cx)
7991 })
7992 })? {
7993 let relative_path =
7994 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
7995 (result.0, relative_path)
7996 } else {
7997 let worktree = lsp_store
7998 .update(cx, |lsp_store, cx| {
7999 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8000 worktree_store.create_worktree(&worktree_root_target, false, cx)
8001 })
8002 })?
8003 .await?;
8004 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8005 lsp_store
8006 .update(cx, |lsp_store, cx| {
8007 if let Some(local) = lsp_store.as_local_mut() {
8008 local.register_language_server_for_invisible_worktree(
8009 &worktree,
8010 language_server_id,
8011 cx,
8012 )
8013 }
8014 })
8015 .ok();
8016 }
8017 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8018 let relative_path = if let Some(known_path) = known_relative_path {
8019 known_path
8020 } else {
8021 abs_path.strip_prefix(worktree_root)?.into()
8022 };
8023 (worktree, relative_path)
8024 };
8025 let project_path = ProjectPath {
8026 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8027 path: relative_path,
8028 };
8029 lsp_store
8030 .update(cx, |lsp_store, cx| {
8031 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8032 buffer_store.open_buffer(project_path, cx)
8033 })
8034 })?
8035 .await
8036 })
8037 }
8038
8039 fn request_multiple_lsp_locally<P, R>(
8040 &mut self,
8041 buffer: &Entity<Buffer>,
8042 position: Option<P>,
8043 request: R,
8044 cx: &mut Context<Self>,
8045 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8046 where
8047 P: ToOffset,
8048 R: LspCommand + Clone,
8049 <R::LspRequest as lsp::request::Request>::Result: Send,
8050 <R::LspRequest as lsp::request::Request>::Params: Send,
8051 {
8052 let Some(local) = self.as_local() else {
8053 return Task::ready(Vec::new());
8054 };
8055
8056 let snapshot = buffer.read(cx).snapshot();
8057 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8058
8059 let server_ids = buffer.update(cx, |buffer, cx| {
8060 local
8061 .language_servers_for_buffer(buffer, cx)
8062 .filter(|(adapter, _)| {
8063 scope
8064 .as_ref()
8065 .map(|scope| scope.language_allowed(&adapter.name))
8066 .unwrap_or(true)
8067 })
8068 .map(|(_, server)| server.server_id())
8069 .filter(|server_id| {
8070 self.as_local().is_none_or(|local| {
8071 local
8072 .buffers_opened_in_servers
8073 .get(&snapshot.remote_id())
8074 .is_some_and(|servers| servers.contains(server_id))
8075 })
8076 })
8077 .collect::<Vec<_>>()
8078 });
8079
8080 let mut response_results = server_ids
8081 .into_iter()
8082 .map(|server_id| {
8083 let task = self.request_lsp(
8084 buffer.clone(),
8085 LanguageServerToQuery::Other(server_id),
8086 request.clone(),
8087 cx,
8088 );
8089 async move { (server_id, task.await) }
8090 })
8091 .collect::<FuturesUnordered<_>>();
8092
8093 cx.background_spawn(async move {
8094 let mut responses = Vec::with_capacity(response_results.len());
8095 while let Some((server_id, response_result)) = response_results.next().await {
8096 if let Some(response) = response_result.log_err() {
8097 responses.push((server_id, response));
8098 }
8099 }
8100 responses
8101 })
8102 }
8103
8104 async fn handle_lsp_command<T: LspCommand>(
8105 this: Entity<Self>,
8106 envelope: TypedEnvelope<T::ProtoRequest>,
8107 mut cx: AsyncApp,
8108 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8109 where
8110 <T::LspRequest as lsp::request::Request>::Params: Send,
8111 <T::LspRequest as lsp::request::Request>::Result: Send,
8112 {
8113 let sender_id = envelope.original_sender_id().unwrap_or_default();
8114 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8115 let buffer_handle = this.update(&mut cx, |this, cx| {
8116 this.buffer_store.read(cx).get_existing(buffer_id)
8117 })??;
8118 let request = T::from_proto(
8119 envelope.payload,
8120 this.clone(),
8121 buffer_handle.clone(),
8122 cx.clone(),
8123 )
8124 .await?;
8125 let response = this
8126 .update(&mut cx, |this, cx| {
8127 this.request_lsp(
8128 buffer_handle.clone(),
8129 LanguageServerToQuery::FirstCapable,
8130 request,
8131 cx,
8132 )
8133 })?
8134 .await?;
8135 this.update(&mut cx, |this, cx| {
8136 Ok(T::response_to_proto(
8137 response,
8138 this,
8139 sender_id,
8140 &buffer_handle.read(cx).version(),
8141 cx,
8142 ))
8143 })?
8144 }
8145
8146 async fn handle_multi_lsp_query(
8147 lsp_store: Entity<Self>,
8148 envelope: TypedEnvelope<proto::MultiLspQuery>,
8149 mut cx: AsyncApp,
8150 ) -> Result<proto::MultiLspQueryResponse> {
8151 let response_from_ssh = lsp_store.read_with(&cx, |this, _| {
8152 let (upstream_client, project_id) = this.upstream_client()?;
8153 let mut payload = envelope.payload.clone();
8154 payload.project_id = project_id;
8155
8156 Some(upstream_client.request(payload))
8157 })?;
8158 if let Some(response_from_ssh) = response_from_ssh {
8159 return response_from_ssh.await;
8160 }
8161
8162 let sender_id = envelope.original_sender_id().unwrap_or_default();
8163 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8164 let version = deserialize_version(&envelope.payload.version);
8165 let buffer = lsp_store.update(&mut cx, |this, cx| {
8166 this.buffer_store.read(cx).get_existing(buffer_id)
8167 })??;
8168 buffer
8169 .update(&mut cx, |buffer, _| {
8170 buffer.wait_for_version(version.clone())
8171 })?
8172 .await?;
8173 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
8174 match envelope
8175 .payload
8176 .strategy
8177 .context("invalid request without the strategy")?
8178 {
8179 proto::multi_lsp_query::Strategy::All(_) => {
8180 // currently, there's only one multiple language servers query strategy,
8181 // so just ensure it's specified correctly
8182 }
8183 }
8184 match envelope.payload.request {
8185 Some(proto::multi_lsp_query::Request::GetHover(message)) => {
8186 buffer
8187 .update(&mut cx, |buffer, _| {
8188 buffer.wait_for_version(deserialize_version(&message.version))
8189 })?
8190 .await?;
8191 let get_hover =
8192 GetHover::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8193 .await?;
8194 let all_hovers = lsp_store
8195 .update(&mut cx, |this, cx| {
8196 this.request_multiple_lsp_locally(
8197 &buffer,
8198 Some(get_hover.position),
8199 get_hover,
8200 cx,
8201 )
8202 })?
8203 .await
8204 .into_iter()
8205 .filter_map(|(server_id, hover)| {
8206 Some((server_id, remove_empty_hover_blocks(hover?)?))
8207 });
8208 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8209 responses: all_hovers
8210 .map(|(server_id, hover)| proto::LspResponse {
8211 server_id: server_id.to_proto(),
8212 response: Some(proto::lsp_response::Response::GetHoverResponse(
8213 GetHover::response_to_proto(
8214 Some(hover),
8215 project,
8216 sender_id,
8217 &buffer_version,
8218 cx,
8219 ),
8220 )),
8221 })
8222 .collect(),
8223 })
8224 }
8225 Some(proto::multi_lsp_query::Request::GetCodeActions(message)) => {
8226 buffer
8227 .update(&mut cx, |buffer, _| {
8228 buffer.wait_for_version(deserialize_version(&message.version))
8229 })?
8230 .await?;
8231 let get_code_actions = GetCodeActions::from_proto(
8232 message,
8233 lsp_store.clone(),
8234 buffer.clone(),
8235 cx.clone(),
8236 )
8237 .await?;
8238
8239 let all_actions = lsp_store
8240 .update(&mut cx, |project, cx| {
8241 project.request_multiple_lsp_locally(
8242 &buffer,
8243 Some(get_code_actions.range.start),
8244 get_code_actions,
8245 cx,
8246 )
8247 })?
8248 .await
8249 .into_iter();
8250
8251 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8252 responses: all_actions
8253 .map(|(server_id, code_actions)| proto::LspResponse {
8254 server_id: server_id.to_proto(),
8255 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
8256 GetCodeActions::response_to_proto(
8257 code_actions,
8258 project,
8259 sender_id,
8260 &buffer_version,
8261 cx,
8262 ),
8263 )),
8264 })
8265 .collect(),
8266 })
8267 }
8268 Some(proto::multi_lsp_query::Request::GetSignatureHelp(message)) => {
8269 buffer
8270 .update(&mut cx, |buffer, _| {
8271 buffer.wait_for_version(deserialize_version(&message.version))
8272 })?
8273 .await?;
8274 let get_signature_help = GetSignatureHelp::from_proto(
8275 message,
8276 lsp_store.clone(),
8277 buffer.clone(),
8278 cx.clone(),
8279 )
8280 .await?;
8281
8282 let all_signatures = lsp_store
8283 .update(&mut cx, |project, cx| {
8284 project.request_multiple_lsp_locally(
8285 &buffer,
8286 Some(get_signature_help.position),
8287 get_signature_help,
8288 cx,
8289 )
8290 })?
8291 .await
8292 .into_iter();
8293
8294 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8295 responses: all_signatures
8296 .map(|(server_id, signature_help)| proto::LspResponse {
8297 server_id: server_id.to_proto(),
8298 response: Some(
8299 proto::lsp_response::Response::GetSignatureHelpResponse(
8300 GetSignatureHelp::response_to_proto(
8301 signature_help,
8302 project,
8303 sender_id,
8304 &buffer_version,
8305 cx,
8306 ),
8307 ),
8308 ),
8309 })
8310 .collect(),
8311 })
8312 }
8313 Some(proto::multi_lsp_query::Request::GetCodeLens(message)) => {
8314 buffer
8315 .update(&mut cx, |buffer, _| {
8316 buffer.wait_for_version(deserialize_version(&message.version))
8317 })?
8318 .await?;
8319 let get_code_lens =
8320 GetCodeLens::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8321 .await?;
8322
8323 let code_lens_actions = lsp_store
8324 .update(&mut cx, |project, cx| {
8325 project.request_multiple_lsp_locally(
8326 &buffer,
8327 None::<usize>,
8328 get_code_lens,
8329 cx,
8330 )
8331 })?
8332 .await
8333 .into_iter();
8334
8335 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8336 responses: code_lens_actions
8337 .map(|(server_id, actions)| proto::LspResponse {
8338 server_id: server_id.to_proto(),
8339 response: Some(proto::lsp_response::Response::GetCodeLensResponse(
8340 GetCodeLens::response_to_proto(
8341 actions,
8342 project,
8343 sender_id,
8344 &buffer_version,
8345 cx,
8346 ),
8347 )),
8348 })
8349 .collect(),
8350 })
8351 }
8352 Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(message)) => {
8353 buffer
8354 .update(&mut cx, |buffer, _| {
8355 buffer.wait_for_version(deserialize_version(&message.version))
8356 })?
8357 .await?;
8358 lsp_store
8359 .update(&mut cx, |lsp_store, cx| {
8360 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8361 })?
8362 .await?;
8363 // `pull_diagnostics_for_buffer` will merge in the new diagnostics and send them to the client.
8364 // The client cannot merge anything into its non-local LspStore, so we do not need to return anything.
8365 Ok(proto::MultiLspQueryResponse {
8366 responses: Vec::new(),
8367 })
8368 }
8369 Some(proto::multi_lsp_query::Request::GetDocumentColor(message)) => {
8370 buffer
8371 .update(&mut cx, |buffer, _| {
8372 buffer.wait_for_version(deserialize_version(&message.version))
8373 })?
8374 .await?;
8375 let get_document_color = GetDocumentColor::from_proto(
8376 message,
8377 lsp_store.clone(),
8378 buffer.clone(),
8379 cx.clone(),
8380 )
8381 .await?;
8382
8383 let all_colors = lsp_store
8384 .update(&mut cx, |project, cx| {
8385 project.request_multiple_lsp_locally(
8386 &buffer,
8387 None::<usize>,
8388 get_document_color,
8389 cx,
8390 )
8391 })?
8392 .await
8393 .into_iter();
8394
8395 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8396 responses: all_colors
8397 .map(|(server_id, colors)| proto::LspResponse {
8398 server_id: server_id.to_proto(),
8399 response: Some(
8400 proto::lsp_response::Response::GetDocumentColorResponse(
8401 GetDocumentColor::response_to_proto(
8402 colors,
8403 project,
8404 sender_id,
8405 &buffer_version,
8406 cx,
8407 ),
8408 ),
8409 ),
8410 })
8411 .collect(),
8412 })
8413 }
8414 Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
8415 let get_definitions = GetDefinitions::from_proto(
8416 message,
8417 lsp_store.clone(),
8418 buffer.clone(),
8419 cx.clone(),
8420 )
8421 .await?;
8422
8423 let definitions = lsp_store
8424 .update(&mut cx, |project, cx| {
8425 project.request_multiple_lsp_locally(
8426 &buffer,
8427 Some(get_definitions.position),
8428 get_definitions,
8429 cx,
8430 )
8431 })?
8432 .await
8433 .into_iter();
8434
8435 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8436 responses: definitions
8437 .map(|(server_id, definitions)| proto::LspResponse {
8438 server_id: server_id.to_proto(),
8439 response: Some(proto::lsp_response::Response::GetDefinitionResponse(
8440 GetDefinitions::response_to_proto(
8441 definitions,
8442 project,
8443 sender_id,
8444 &buffer_version,
8445 cx,
8446 ),
8447 )),
8448 })
8449 .collect(),
8450 })
8451 }
8452 Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
8453 let get_declarations = GetDeclarations::from_proto(
8454 message,
8455 lsp_store.clone(),
8456 buffer.clone(),
8457 cx.clone(),
8458 )
8459 .await?;
8460
8461 let declarations = lsp_store
8462 .update(&mut cx, |project, cx| {
8463 project.request_multiple_lsp_locally(
8464 &buffer,
8465 Some(get_declarations.position),
8466 get_declarations,
8467 cx,
8468 )
8469 })?
8470 .await
8471 .into_iter();
8472
8473 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8474 responses: declarations
8475 .map(|(server_id, declarations)| proto::LspResponse {
8476 server_id: server_id.to_proto(),
8477 response: Some(proto::lsp_response::Response::GetDeclarationResponse(
8478 GetDeclarations::response_to_proto(
8479 declarations,
8480 project,
8481 sender_id,
8482 &buffer_version,
8483 cx,
8484 ),
8485 )),
8486 })
8487 .collect(),
8488 })
8489 }
8490 Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
8491 let get_type_definitions = GetTypeDefinitions::from_proto(
8492 message,
8493 lsp_store.clone(),
8494 buffer.clone(),
8495 cx.clone(),
8496 )
8497 .await?;
8498
8499 let type_definitions = lsp_store
8500 .update(&mut cx, |project, cx| {
8501 project.request_multiple_lsp_locally(
8502 &buffer,
8503 Some(get_type_definitions.position),
8504 get_type_definitions,
8505 cx,
8506 )
8507 })?
8508 .await
8509 .into_iter();
8510
8511 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8512 responses: type_definitions
8513 .map(|(server_id, type_definitions)| proto::LspResponse {
8514 server_id: server_id.to_proto(),
8515 response: Some(
8516 proto::lsp_response::Response::GetTypeDefinitionResponse(
8517 GetTypeDefinitions::response_to_proto(
8518 type_definitions,
8519 project,
8520 sender_id,
8521 &buffer_version,
8522 cx,
8523 ),
8524 ),
8525 ),
8526 })
8527 .collect(),
8528 })
8529 }
8530 Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
8531 let get_implementations = GetImplementations::from_proto(
8532 message,
8533 lsp_store.clone(),
8534 buffer.clone(),
8535 cx.clone(),
8536 )
8537 .await?;
8538
8539 let implementations = lsp_store
8540 .update(&mut cx, |project, cx| {
8541 project.request_multiple_lsp_locally(
8542 &buffer,
8543 Some(get_implementations.position),
8544 get_implementations,
8545 cx,
8546 )
8547 })?
8548 .await
8549 .into_iter();
8550
8551 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8552 responses: implementations
8553 .map(|(server_id, implementations)| proto::LspResponse {
8554 server_id: server_id.to_proto(),
8555 response: Some(
8556 proto::lsp_response::Response::GetImplementationResponse(
8557 GetImplementations::response_to_proto(
8558 implementations,
8559 project,
8560 sender_id,
8561 &buffer_version,
8562 cx,
8563 ),
8564 ),
8565 ),
8566 })
8567 .collect(),
8568 })
8569 }
8570 Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
8571 let get_references = GetReferences::from_proto(
8572 message,
8573 lsp_store.clone(),
8574 buffer.clone(),
8575 cx.clone(),
8576 )
8577 .await?;
8578
8579 let references = lsp_store
8580 .update(&mut cx, |project, cx| {
8581 project.request_multiple_lsp_locally(
8582 &buffer,
8583 Some(get_references.position),
8584 get_references,
8585 cx,
8586 )
8587 })?
8588 .await
8589 .into_iter();
8590
8591 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8592 responses: references
8593 .map(|(server_id, references)| proto::LspResponse {
8594 server_id: server_id.to_proto(),
8595 response: Some(proto::lsp_response::Response::GetReferencesResponse(
8596 GetReferences::response_to_proto(
8597 references,
8598 project,
8599 sender_id,
8600 &buffer_version,
8601 cx,
8602 ),
8603 )),
8604 })
8605 .collect(),
8606 })
8607 }
8608 None => anyhow::bail!("empty multi lsp query request"),
8609 }
8610 }
8611
8612 async fn handle_apply_code_action(
8613 this: Entity<Self>,
8614 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8615 mut cx: AsyncApp,
8616 ) -> Result<proto::ApplyCodeActionResponse> {
8617 let sender_id = envelope.original_sender_id().unwrap_or_default();
8618 let action =
8619 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8620 let apply_code_action = this.update(&mut cx, |this, cx| {
8621 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8622 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8623 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8624 })??;
8625
8626 let project_transaction = apply_code_action.await?;
8627 let project_transaction = this.update(&mut cx, |this, cx| {
8628 this.buffer_store.update(cx, |buffer_store, cx| {
8629 buffer_store.serialize_project_transaction_for_peer(
8630 project_transaction,
8631 sender_id,
8632 cx,
8633 )
8634 })
8635 })?;
8636 Ok(proto::ApplyCodeActionResponse {
8637 transaction: Some(project_transaction),
8638 })
8639 }
8640
8641 async fn handle_register_buffer_with_language_servers(
8642 this: Entity<Self>,
8643 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8644 mut cx: AsyncApp,
8645 ) -> Result<proto::Ack> {
8646 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8647 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8648 this.update(&mut cx, |this, cx| {
8649 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8650 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8651 project_id: upstream_project_id,
8652 buffer_id: buffer_id.to_proto(),
8653 only_servers: envelope.payload.only_servers,
8654 });
8655 }
8656
8657 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8658 anyhow::bail!("buffer is not open");
8659 };
8660
8661 let handle = this.register_buffer_with_language_servers(
8662 &buffer,
8663 envelope
8664 .payload
8665 .only_servers
8666 .into_iter()
8667 .filter_map(|selector| {
8668 Some(match selector.selector? {
8669 proto::language_server_selector::Selector::ServerId(server_id) => {
8670 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8671 }
8672 proto::language_server_selector::Selector::Name(name) => {
8673 LanguageServerSelector::Name(LanguageServerName(
8674 SharedString::from(name),
8675 ))
8676 }
8677 })
8678 })
8679 .collect(),
8680 false,
8681 cx,
8682 );
8683 this.buffer_store().update(cx, |buffer_store, _| {
8684 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8685 });
8686
8687 Ok(())
8688 })??;
8689 Ok(proto::Ack {})
8690 }
8691
8692 async fn handle_rename_project_entry(
8693 this: Entity<Self>,
8694 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8695 mut cx: AsyncApp,
8696 ) -> Result<proto::ProjectEntryResponse> {
8697 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8698 let (worktree_id, worktree, old_path, is_dir) = this
8699 .update(&mut cx, |this, cx| {
8700 this.worktree_store
8701 .read(cx)
8702 .worktree_and_entry_for_id(entry_id, cx)
8703 .map(|(worktree, entry)| {
8704 (
8705 worktree.read(cx).id(),
8706 worktree,
8707 entry.path.clone(),
8708 entry.is_dir(),
8709 )
8710 })
8711 })?
8712 .context("worktree not found")?;
8713 let (old_abs_path, new_abs_path) = {
8714 let root_path = worktree.read_with(&cx, |this, _| this.abs_path())?;
8715 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8716 (root_path.join(&old_path), root_path.join(&new_path))
8717 };
8718
8719 Self::will_rename_entry(
8720 this.downgrade(),
8721 worktree_id,
8722 &old_abs_path,
8723 &new_abs_path,
8724 is_dir,
8725 cx.clone(),
8726 )
8727 .await;
8728 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8729 this.read_with(&cx, |this, _| {
8730 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8731 })
8732 .ok();
8733 response
8734 }
8735
8736 async fn handle_update_diagnostic_summary(
8737 this: Entity<Self>,
8738 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8739 mut cx: AsyncApp,
8740 ) -> Result<()> {
8741 this.update(&mut cx, |lsp_store, cx| {
8742 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8743 let mut updated_diagnostics_paths = HashMap::default();
8744 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8745 for message_summary in envelope
8746 .payload
8747 .summary
8748 .into_iter()
8749 .chain(envelope.payload.more_summaries)
8750 {
8751 let project_path = ProjectPath {
8752 worktree_id,
8753 path: Arc::<Path>::from_proto(message_summary.path),
8754 };
8755 let path = project_path.path.clone();
8756 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8757 let summary = DiagnosticSummary {
8758 error_count: message_summary.error_count as usize,
8759 warning_count: message_summary.warning_count as usize,
8760 };
8761
8762 if summary.is_empty() {
8763 if let Some(worktree_summaries) =
8764 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8765 && let Some(summaries) = worktree_summaries.get_mut(&path)
8766 {
8767 summaries.remove(&server_id);
8768 if summaries.is_empty() {
8769 worktree_summaries.remove(&path);
8770 }
8771 }
8772 } else {
8773 lsp_store
8774 .diagnostic_summaries
8775 .entry(worktree_id)
8776 .or_default()
8777 .entry(path)
8778 .or_default()
8779 .insert(server_id, summary);
8780 }
8781
8782 if let Some((_, project_id)) = &lsp_store.downstream_client {
8783 match &mut diagnostics_summary {
8784 Some(diagnostics_summary) => {
8785 diagnostics_summary
8786 .more_summaries
8787 .push(proto::DiagnosticSummary {
8788 path: project_path.path.as_ref().to_proto(),
8789 language_server_id: server_id.0 as u64,
8790 error_count: summary.error_count as u32,
8791 warning_count: summary.warning_count as u32,
8792 })
8793 }
8794 None => {
8795 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8796 project_id: *project_id,
8797 worktree_id: worktree_id.to_proto(),
8798 summary: Some(proto::DiagnosticSummary {
8799 path: project_path.path.as_ref().to_proto(),
8800 language_server_id: server_id.0 as u64,
8801 error_count: summary.error_count as u32,
8802 warning_count: summary.warning_count as u32,
8803 }),
8804 more_summaries: Vec::new(),
8805 })
8806 }
8807 }
8808 }
8809 updated_diagnostics_paths
8810 .entry(server_id)
8811 .or_insert_with(Vec::new)
8812 .push(project_path);
8813 }
8814
8815 if let Some((diagnostics_summary, (downstream_client, _))) =
8816 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8817 {
8818 downstream_client.send(diagnostics_summary).log_err();
8819 }
8820 for (server_id, paths) in updated_diagnostics_paths {
8821 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8822 }
8823 Ok(())
8824 })?
8825 }
8826
8827 async fn handle_start_language_server(
8828 lsp_store: Entity<Self>,
8829 envelope: TypedEnvelope<proto::StartLanguageServer>,
8830 mut cx: AsyncApp,
8831 ) -> Result<()> {
8832 let server = envelope.payload.server.context("invalid server")?;
8833 let server_capabilities =
8834 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8835 .with_context(|| {
8836 format!(
8837 "incorrect server capabilities {}",
8838 envelope.payload.capabilities
8839 )
8840 })?;
8841 lsp_store.update(&mut cx, |lsp_store, cx| {
8842 let server_id = LanguageServerId(server.id as usize);
8843 let server_name = LanguageServerName::from_proto(server.name.clone());
8844 lsp_store
8845 .lsp_server_capabilities
8846 .insert(server_id, server_capabilities);
8847 lsp_store.language_server_statuses.insert(
8848 server_id,
8849 LanguageServerStatus {
8850 name: server_name.clone(),
8851 pending_work: Default::default(),
8852 has_pending_diagnostic_updates: false,
8853 progress_tokens: Default::default(),
8854 },
8855 );
8856 cx.emit(LspStoreEvent::LanguageServerAdded(
8857 server_id,
8858 server_name,
8859 server.worktree_id.map(WorktreeId::from_proto),
8860 ));
8861 cx.notify();
8862 })?;
8863 Ok(())
8864 }
8865
8866 async fn handle_update_language_server(
8867 lsp_store: Entity<Self>,
8868 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8869 mut cx: AsyncApp,
8870 ) -> Result<()> {
8871 lsp_store.update(&mut cx, |lsp_store, cx| {
8872 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8873
8874 match envelope.payload.variant.context("invalid variant")? {
8875 proto::update_language_server::Variant::WorkStart(payload) => {
8876 lsp_store.on_lsp_work_start(
8877 language_server_id,
8878 payload.token,
8879 LanguageServerProgress {
8880 title: payload.title,
8881 is_disk_based_diagnostics_progress: false,
8882 is_cancellable: payload.is_cancellable.unwrap_or(false),
8883 message: payload.message,
8884 percentage: payload.percentage.map(|p| p as usize),
8885 last_update_at: cx.background_executor().now(),
8886 },
8887 cx,
8888 );
8889 }
8890 proto::update_language_server::Variant::WorkProgress(payload) => {
8891 lsp_store.on_lsp_work_progress(
8892 language_server_id,
8893 payload.token,
8894 LanguageServerProgress {
8895 title: None,
8896 is_disk_based_diagnostics_progress: false,
8897 is_cancellable: payload.is_cancellable.unwrap_or(false),
8898 message: payload.message,
8899 percentage: payload.percentage.map(|p| p as usize),
8900 last_update_at: cx.background_executor().now(),
8901 },
8902 cx,
8903 );
8904 }
8905
8906 proto::update_language_server::Variant::WorkEnd(payload) => {
8907 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8908 }
8909
8910 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8911 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8912 }
8913
8914 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8915 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8916 }
8917
8918 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8919 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8920 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8921 cx.emit(LspStoreEvent::LanguageServerUpdate {
8922 language_server_id,
8923 name: envelope
8924 .payload
8925 .server_name
8926 .map(SharedString::new)
8927 .map(LanguageServerName),
8928 message: non_lsp,
8929 });
8930 }
8931 }
8932
8933 Ok(())
8934 })?
8935 }
8936
8937 async fn handle_language_server_log(
8938 this: Entity<Self>,
8939 envelope: TypedEnvelope<proto::LanguageServerLog>,
8940 mut cx: AsyncApp,
8941 ) -> Result<()> {
8942 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8943 let log_type = envelope
8944 .payload
8945 .log_type
8946 .map(LanguageServerLogType::from_proto)
8947 .context("invalid language server log type")?;
8948
8949 let message = envelope.payload.message;
8950
8951 this.update(&mut cx, |_, cx| {
8952 cx.emit(LspStoreEvent::LanguageServerLog(
8953 language_server_id,
8954 log_type,
8955 message,
8956 ));
8957 })
8958 }
8959
8960 async fn handle_lsp_ext_cancel_flycheck(
8961 lsp_store: Entity<Self>,
8962 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8963 cx: AsyncApp,
8964 ) -> Result<proto::Ack> {
8965 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8966 lsp_store.read_with(&cx, |lsp_store, _| {
8967 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8968 server
8969 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
8970 .context("handling lsp ext cancel flycheck")
8971 } else {
8972 anyhow::Ok(())
8973 }
8974 })??;
8975
8976 Ok(proto::Ack {})
8977 }
8978
8979 async fn handle_lsp_ext_run_flycheck(
8980 lsp_store: Entity<Self>,
8981 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8982 mut cx: AsyncApp,
8983 ) -> Result<proto::Ack> {
8984 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8985 lsp_store.update(&mut cx, |lsp_store, cx| {
8986 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8987 let text_document = if envelope.payload.current_file_only {
8988 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8989 lsp_store
8990 .buffer_store()
8991 .read(cx)
8992 .get(buffer_id)
8993 .and_then(|buffer| Some(buffer.read(cx).file()?.as_local()?.abs_path(cx)))
8994 .map(|path| make_text_document_identifier(&path))
8995 .transpose()?
8996 } else {
8997 None
8998 };
8999 server
9000 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9001 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9002 )
9003 .context("handling lsp ext run flycheck")
9004 } else {
9005 anyhow::Ok(())
9006 }
9007 })??;
9008
9009 Ok(proto::Ack {})
9010 }
9011
9012 async fn handle_lsp_ext_clear_flycheck(
9013 lsp_store: Entity<Self>,
9014 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9015 cx: AsyncApp,
9016 ) -> Result<proto::Ack> {
9017 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9018 lsp_store.read_with(&cx, |lsp_store, _| {
9019 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9020 server
9021 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
9022 .context("handling lsp ext clear flycheck")
9023 } else {
9024 anyhow::Ok(())
9025 }
9026 })??;
9027
9028 Ok(proto::Ack {})
9029 }
9030
9031 pub fn disk_based_diagnostics_started(
9032 &mut self,
9033 language_server_id: LanguageServerId,
9034 cx: &mut Context<Self>,
9035 ) {
9036 if let Some(language_server_status) =
9037 self.language_server_statuses.get_mut(&language_server_id)
9038 {
9039 language_server_status.has_pending_diagnostic_updates = true;
9040 }
9041
9042 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9043 cx.emit(LspStoreEvent::LanguageServerUpdate {
9044 language_server_id,
9045 name: self
9046 .language_server_adapter_for_id(language_server_id)
9047 .map(|adapter| adapter.name()),
9048 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9049 Default::default(),
9050 ),
9051 })
9052 }
9053
9054 pub fn disk_based_diagnostics_finished(
9055 &mut self,
9056 language_server_id: LanguageServerId,
9057 cx: &mut Context<Self>,
9058 ) {
9059 if let Some(language_server_status) =
9060 self.language_server_statuses.get_mut(&language_server_id)
9061 {
9062 language_server_status.has_pending_diagnostic_updates = false;
9063 }
9064
9065 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9066 cx.emit(LspStoreEvent::LanguageServerUpdate {
9067 language_server_id,
9068 name: self
9069 .language_server_adapter_for_id(language_server_id)
9070 .map(|adapter| adapter.name()),
9071 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9072 Default::default(),
9073 ),
9074 })
9075 }
9076
9077 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9078 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9079 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9080 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9081 // the language server might take some time to publish diagnostics.
9082 fn simulate_disk_based_diagnostics_events_if_needed(
9083 &mut self,
9084 language_server_id: LanguageServerId,
9085 cx: &mut Context<Self>,
9086 ) {
9087 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9088
9089 let Some(LanguageServerState::Running {
9090 simulate_disk_based_diagnostics_completion,
9091 adapter,
9092 ..
9093 }) = self
9094 .as_local_mut()
9095 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9096 else {
9097 return;
9098 };
9099
9100 if adapter.disk_based_diagnostics_progress_token.is_some() {
9101 return;
9102 }
9103
9104 let prev_task =
9105 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9106 cx.background_executor()
9107 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9108 .await;
9109
9110 this.update(cx, |this, cx| {
9111 this.disk_based_diagnostics_finished(language_server_id, cx);
9112
9113 if let Some(LanguageServerState::Running {
9114 simulate_disk_based_diagnostics_completion,
9115 ..
9116 }) = this.as_local_mut().and_then(|local_store| {
9117 local_store.language_servers.get_mut(&language_server_id)
9118 }) {
9119 *simulate_disk_based_diagnostics_completion = None;
9120 }
9121 })
9122 .ok();
9123 }));
9124
9125 if prev_task.is_none() {
9126 self.disk_based_diagnostics_started(language_server_id, cx);
9127 }
9128 }
9129
9130 pub fn language_server_statuses(
9131 &self,
9132 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9133 self.language_server_statuses
9134 .iter()
9135 .map(|(key, value)| (*key, value))
9136 }
9137
9138 pub(super) fn did_rename_entry(
9139 &self,
9140 worktree_id: WorktreeId,
9141 old_path: &Path,
9142 new_path: &Path,
9143 is_dir: bool,
9144 ) {
9145 maybe!({
9146 let local_store = self.as_local()?;
9147
9148 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from)?;
9149 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from)?;
9150
9151 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9152 let Some(filter) = local_store
9153 .language_server_paths_watched_for_rename
9154 .get(&language_server.server_id())
9155 else {
9156 continue;
9157 };
9158
9159 if filter.should_send_did_rename(&old_uri, is_dir) {
9160 language_server
9161 .notify::<DidRenameFiles>(&RenameFilesParams {
9162 files: vec![FileRename {
9163 old_uri: old_uri.clone(),
9164 new_uri: new_uri.clone(),
9165 }],
9166 })
9167 .ok();
9168 }
9169 }
9170 Some(())
9171 });
9172 }
9173
9174 pub(super) fn will_rename_entry(
9175 this: WeakEntity<Self>,
9176 worktree_id: WorktreeId,
9177 old_path: &Path,
9178 new_path: &Path,
9179 is_dir: bool,
9180 cx: AsyncApp,
9181 ) -> Task<()> {
9182 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from);
9183 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from);
9184 cx.spawn(async move |cx| {
9185 let mut tasks = vec![];
9186 this.update(cx, |this, cx| {
9187 let local_store = this.as_local()?;
9188 let old_uri = old_uri?;
9189 let new_uri = new_uri?;
9190 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9191 let Some(filter) = local_store
9192 .language_server_paths_watched_for_rename
9193 .get(&language_server.server_id())
9194 else {
9195 continue;
9196 };
9197
9198 if filter.should_send_will_rename(&old_uri, is_dir) {
9199 let apply_edit = cx.spawn({
9200 let old_uri = old_uri.clone();
9201 let new_uri = new_uri.clone();
9202 let language_server = language_server.clone();
9203 async move |this, cx| {
9204 let edit = language_server
9205 .request::<WillRenameFiles>(RenameFilesParams {
9206 files: vec![FileRename { old_uri, new_uri }],
9207 })
9208 .await
9209 .into_response()
9210 .context("will rename files")
9211 .log_err()
9212 .flatten()?;
9213
9214 if let Some(transaction) =
9215 LocalLspStore::deserialize_workspace_edit(
9216 this.upgrade()?,
9217 edit,
9218 false,
9219 language_server.clone(),
9220 cx,
9221 )
9222 .await
9223 .ok()
9224 {
9225 for (buffer, _) in transaction.0 {
9226 this.update(cx, |_, cx| {
9227 cx.emit(LspStoreEvent::UnsavedBufferEdit(buffer));
9228 })
9229 .ok();
9230 }
9231 }
9232 Some(())
9233 }
9234 });
9235 tasks.push(apply_edit);
9236 }
9237 }
9238 Some(())
9239 })
9240 .ok()
9241 .flatten();
9242 for task in tasks {
9243 // Await on tasks sequentially so that the order of application of edits is deterministic
9244 // (at least with regards to the order of registration of language servers)
9245 task.await;
9246 }
9247 })
9248 }
9249
9250 fn lsp_notify_abs_paths_changed(
9251 &mut self,
9252 server_id: LanguageServerId,
9253 changes: Vec<PathEvent>,
9254 ) {
9255 maybe!({
9256 let server = self.language_server_for_id(server_id)?;
9257 let changes = changes
9258 .into_iter()
9259 .filter_map(|event| {
9260 let typ = match event.kind? {
9261 PathEventKind::Created => lsp::FileChangeType::CREATED,
9262 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9263 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9264 };
9265 Some(lsp::FileEvent {
9266 uri: file_path_to_lsp_url(&event.path).log_err()?,
9267 typ,
9268 })
9269 })
9270 .collect::<Vec<_>>();
9271 if !changes.is_empty() {
9272 server
9273 .notify::<lsp::notification::DidChangeWatchedFiles>(
9274 &lsp::DidChangeWatchedFilesParams { changes },
9275 )
9276 .ok();
9277 }
9278 Some(())
9279 });
9280 }
9281
9282 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9283 self.as_local()?.language_server_for_id(id)
9284 }
9285
9286 fn on_lsp_progress(
9287 &mut self,
9288 progress: lsp::ProgressParams,
9289 language_server_id: LanguageServerId,
9290 disk_based_diagnostics_progress_token: Option<String>,
9291 cx: &mut Context<Self>,
9292 ) {
9293 let token = match progress.token {
9294 lsp::NumberOrString::String(token) => token,
9295 lsp::NumberOrString::Number(token) => {
9296 log::info!("skipping numeric progress token {}", token);
9297 return;
9298 }
9299 };
9300
9301 match progress.value {
9302 lsp::ProgressParamsValue::WorkDone(progress) => {
9303 self.handle_work_done_progress(
9304 progress,
9305 language_server_id,
9306 disk_based_diagnostics_progress_token,
9307 token,
9308 cx,
9309 );
9310 }
9311 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9312 if let Some(LanguageServerState::Running {
9313 workspace_refresh_task: Some(workspace_refresh_task),
9314 ..
9315 }) = self
9316 .as_local_mut()
9317 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9318 {
9319 workspace_refresh_task.progress_tx.try_send(()).ok();
9320 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9321 }
9322 }
9323 }
9324 }
9325
9326 fn handle_work_done_progress(
9327 &mut self,
9328 progress: lsp::WorkDoneProgress,
9329 language_server_id: LanguageServerId,
9330 disk_based_diagnostics_progress_token: Option<String>,
9331 token: String,
9332 cx: &mut Context<Self>,
9333 ) {
9334 let language_server_status =
9335 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9336 status
9337 } else {
9338 return;
9339 };
9340
9341 if !language_server_status.progress_tokens.contains(&token) {
9342 return;
9343 }
9344
9345 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9346 .as_ref()
9347 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9348
9349 match progress {
9350 lsp::WorkDoneProgress::Begin(report) => {
9351 if is_disk_based_diagnostics_progress {
9352 self.disk_based_diagnostics_started(language_server_id, cx);
9353 }
9354 self.on_lsp_work_start(
9355 language_server_id,
9356 token.clone(),
9357 LanguageServerProgress {
9358 title: Some(report.title),
9359 is_disk_based_diagnostics_progress,
9360 is_cancellable: report.cancellable.unwrap_or(false),
9361 message: report.message.clone(),
9362 percentage: report.percentage.map(|p| p as usize),
9363 last_update_at: cx.background_executor().now(),
9364 },
9365 cx,
9366 );
9367 }
9368 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9369 language_server_id,
9370 token,
9371 LanguageServerProgress {
9372 title: None,
9373 is_disk_based_diagnostics_progress,
9374 is_cancellable: report.cancellable.unwrap_or(false),
9375 message: report.message,
9376 percentage: report.percentage.map(|p| p as usize),
9377 last_update_at: cx.background_executor().now(),
9378 },
9379 cx,
9380 ),
9381 lsp::WorkDoneProgress::End(_) => {
9382 language_server_status.progress_tokens.remove(&token);
9383 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9384 if is_disk_based_diagnostics_progress {
9385 self.disk_based_diagnostics_finished(language_server_id, cx);
9386 }
9387 }
9388 }
9389 }
9390
9391 fn on_lsp_work_start(
9392 &mut self,
9393 language_server_id: LanguageServerId,
9394 token: String,
9395 progress: LanguageServerProgress,
9396 cx: &mut Context<Self>,
9397 ) {
9398 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9399 status.pending_work.insert(token.clone(), progress.clone());
9400 cx.notify();
9401 }
9402 cx.emit(LspStoreEvent::LanguageServerUpdate {
9403 language_server_id,
9404 name: self
9405 .language_server_adapter_for_id(language_server_id)
9406 .map(|adapter| adapter.name()),
9407 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9408 token,
9409 title: progress.title,
9410 message: progress.message,
9411 percentage: progress.percentage.map(|p| p as u32),
9412 is_cancellable: Some(progress.is_cancellable),
9413 }),
9414 })
9415 }
9416
9417 fn on_lsp_work_progress(
9418 &mut self,
9419 language_server_id: LanguageServerId,
9420 token: String,
9421 progress: LanguageServerProgress,
9422 cx: &mut Context<Self>,
9423 ) {
9424 let mut did_update = false;
9425 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9426 match status.pending_work.entry(token.clone()) {
9427 btree_map::Entry::Vacant(entry) => {
9428 entry.insert(progress.clone());
9429 did_update = true;
9430 }
9431 btree_map::Entry::Occupied(mut entry) => {
9432 let entry = entry.get_mut();
9433 if (progress.last_update_at - entry.last_update_at)
9434 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9435 {
9436 entry.last_update_at = progress.last_update_at;
9437 if progress.message.is_some() {
9438 entry.message = progress.message.clone();
9439 }
9440 if progress.percentage.is_some() {
9441 entry.percentage = progress.percentage;
9442 }
9443 if progress.is_cancellable != entry.is_cancellable {
9444 entry.is_cancellable = progress.is_cancellable;
9445 }
9446 did_update = true;
9447 }
9448 }
9449 }
9450 }
9451
9452 if did_update {
9453 cx.emit(LspStoreEvent::LanguageServerUpdate {
9454 language_server_id,
9455 name: self
9456 .language_server_adapter_for_id(language_server_id)
9457 .map(|adapter| adapter.name()),
9458 message: proto::update_language_server::Variant::WorkProgress(
9459 proto::LspWorkProgress {
9460 token,
9461 message: progress.message,
9462 percentage: progress.percentage.map(|p| p as u32),
9463 is_cancellable: Some(progress.is_cancellable),
9464 },
9465 ),
9466 })
9467 }
9468 }
9469
9470 fn on_lsp_work_end(
9471 &mut self,
9472 language_server_id: LanguageServerId,
9473 token: String,
9474 cx: &mut Context<Self>,
9475 ) {
9476 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9477 if let Some(work) = status.pending_work.remove(&token)
9478 && !work.is_disk_based_diagnostics_progress
9479 {
9480 cx.emit(LspStoreEvent::RefreshInlayHints);
9481 }
9482 cx.notify();
9483 }
9484
9485 cx.emit(LspStoreEvent::LanguageServerUpdate {
9486 language_server_id,
9487 name: self
9488 .language_server_adapter_for_id(language_server_id)
9489 .map(|adapter| adapter.name()),
9490 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9491 })
9492 }
9493
9494 pub async fn handle_resolve_completion_documentation(
9495 this: Entity<Self>,
9496 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9497 mut cx: AsyncApp,
9498 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9499 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9500
9501 let completion = this
9502 .read_with(&cx, |this, cx| {
9503 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9504 let server = this
9505 .language_server_for_id(id)
9506 .with_context(|| format!("No language server {id}"))?;
9507
9508 anyhow::Ok(cx.background_spawn(async move {
9509 let can_resolve = server
9510 .capabilities()
9511 .completion_provider
9512 .as_ref()
9513 .and_then(|options| options.resolve_provider)
9514 .unwrap_or(false);
9515 if can_resolve {
9516 server
9517 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9518 .await
9519 .into_response()
9520 .context("resolve completion item")
9521 } else {
9522 anyhow::Ok(lsp_completion)
9523 }
9524 }))
9525 })??
9526 .await?;
9527
9528 let mut documentation_is_markdown = false;
9529 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9530 let documentation = match completion.documentation {
9531 Some(lsp::Documentation::String(text)) => text,
9532
9533 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9534 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9535 value
9536 }
9537
9538 _ => String::new(),
9539 };
9540
9541 // If we have a new buffer_id, that means we're talking to a new client
9542 // and want to check for new text_edits in the completion too.
9543 let mut old_replace_start = None;
9544 let mut old_replace_end = None;
9545 let mut old_insert_start = None;
9546 let mut old_insert_end = None;
9547 let mut new_text = String::default();
9548 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9549 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9550 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9551 anyhow::Ok(buffer.read(cx).snapshot())
9552 })??;
9553
9554 if let Some(text_edit) = completion.text_edit.as_ref() {
9555 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9556
9557 if let Some(mut edit) = edit {
9558 LineEnding::normalize(&mut edit.new_text);
9559
9560 new_text = edit.new_text;
9561 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9562 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9563 if let Some(insert_range) = edit.insert_range {
9564 old_insert_start = Some(serialize_anchor(&insert_range.start));
9565 old_insert_end = Some(serialize_anchor(&insert_range.end));
9566 }
9567 }
9568 }
9569 }
9570
9571 Ok(proto::ResolveCompletionDocumentationResponse {
9572 documentation,
9573 documentation_is_markdown,
9574 old_replace_start,
9575 old_replace_end,
9576 new_text,
9577 lsp_completion,
9578 old_insert_start,
9579 old_insert_end,
9580 })
9581 }
9582
9583 async fn handle_on_type_formatting(
9584 this: Entity<Self>,
9585 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9586 mut cx: AsyncApp,
9587 ) -> Result<proto::OnTypeFormattingResponse> {
9588 let on_type_formatting = this.update(&mut cx, |this, cx| {
9589 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9590 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9591 let position = envelope
9592 .payload
9593 .position
9594 .and_then(deserialize_anchor)
9595 .context("invalid position")?;
9596 anyhow::Ok(this.apply_on_type_formatting(
9597 buffer,
9598 position,
9599 envelope.payload.trigger.clone(),
9600 cx,
9601 ))
9602 })??;
9603
9604 let transaction = on_type_formatting
9605 .await?
9606 .as_ref()
9607 .map(language::proto::serialize_transaction);
9608 Ok(proto::OnTypeFormattingResponse { transaction })
9609 }
9610
9611 async fn handle_refresh_inlay_hints(
9612 this: Entity<Self>,
9613 _: TypedEnvelope<proto::RefreshInlayHints>,
9614 mut cx: AsyncApp,
9615 ) -> Result<proto::Ack> {
9616 this.update(&mut cx, |_, cx| {
9617 cx.emit(LspStoreEvent::RefreshInlayHints);
9618 })?;
9619 Ok(proto::Ack {})
9620 }
9621
9622 async fn handle_pull_workspace_diagnostics(
9623 lsp_store: Entity<Self>,
9624 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9625 mut cx: AsyncApp,
9626 ) -> Result<proto::Ack> {
9627 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9628 lsp_store.update(&mut cx, |lsp_store, _| {
9629 lsp_store.pull_workspace_diagnostics(server_id);
9630 })?;
9631 Ok(proto::Ack {})
9632 }
9633
9634 async fn handle_inlay_hints(
9635 this: Entity<Self>,
9636 envelope: TypedEnvelope<proto::InlayHints>,
9637 mut cx: AsyncApp,
9638 ) -> Result<proto::InlayHintsResponse> {
9639 let sender_id = envelope.original_sender_id().unwrap_or_default();
9640 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9641 let buffer = this.update(&mut cx, |this, cx| {
9642 this.buffer_store.read(cx).get_existing(buffer_id)
9643 })??;
9644 buffer
9645 .update(&mut cx, |buffer, _| {
9646 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9647 })?
9648 .await
9649 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9650
9651 let start = envelope
9652 .payload
9653 .start
9654 .and_then(deserialize_anchor)
9655 .context("missing range start")?;
9656 let end = envelope
9657 .payload
9658 .end
9659 .and_then(deserialize_anchor)
9660 .context("missing range end")?;
9661 let buffer_hints = this
9662 .update(&mut cx, |lsp_store, cx| {
9663 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9664 })?
9665 .await
9666 .context("inlay hints fetch")?;
9667
9668 this.update(&mut cx, |project, cx| {
9669 InlayHints::response_to_proto(
9670 buffer_hints,
9671 project,
9672 sender_id,
9673 &buffer.read(cx).version(),
9674 cx,
9675 )
9676 })
9677 }
9678
9679 async fn handle_get_color_presentation(
9680 lsp_store: Entity<Self>,
9681 envelope: TypedEnvelope<proto::GetColorPresentation>,
9682 mut cx: AsyncApp,
9683 ) -> Result<proto::GetColorPresentationResponse> {
9684 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9685 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9686 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9687 })??;
9688
9689 let color = envelope
9690 .payload
9691 .color
9692 .context("invalid color resolve request")?;
9693 let start = color
9694 .lsp_range_start
9695 .context("invalid color resolve request")?;
9696 let end = color
9697 .lsp_range_end
9698 .context("invalid color resolve request")?;
9699
9700 let color = DocumentColor {
9701 lsp_range: lsp::Range {
9702 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9703 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9704 },
9705 color: lsp::Color {
9706 red: color.red,
9707 green: color.green,
9708 blue: color.blue,
9709 alpha: color.alpha,
9710 },
9711 resolved: false,
9712 color_presentations: Vec::new(),
9713 };
9714 let resolved_color = lsp_store
9715 .update(&mut cx, |lsp_store, cx| {
9716 lsp_store.resolve_color_presentation(
9717 color,
9718 buffer.clone(),
9719 LanguageServerId(envelope.payload.server_id as usize),
9720 cx,
9721 )
9722 })?
9723 .await
9724 .context("resolving color presentation")?;
9725
9726 Ok(proto::GetColorPresentationResponse {
9727 presentations: resolved_color
9728 .color_presentations
9729 .into_iter()
9730 .map(|presentation| proto::ColorPresentation {
9731 label: presentation.label.to_string(),
9732 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9733 additional_text_edits: presentation
9734 .additional_text_edits
9735 .into_iter()
9736 .map(serialize_lsp_edit)
9737 .collect(),
9738 })
9739 .collect(),
9740 })
9741 }
9742
9743 async fn handle_resolve_inlay_hint(
9744 this: Entity<Self>,
9745 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9746 mut cx: AsyncApp,
9747 ) -> Result<proto::ResolveInlayHintResponse> {
9748 let proto_hint = envelope
9749 .payload
9750 .hint
9751 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9752 let hint = InlayHints::proto_to_project_hint(proto_hint)
9753 .context("resolved proto inlay hint conversion")?;
9754 let buffer = this.update(&mut cx, |this, cx| {
9755 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9756 this.buffer_store.read(cx).get_existing(buffer_id)
9757 })??;
9758 let response_hint = this
9759 .update(&mut cx, |this, cx| {
9760 this.resolve_inlay_hint(
9761 hint,
9762 buffer,
9763 LanguageServerId(envelope.payload.language_server_id as usize),
9764 cx,
9765 )
9766 })?
9767 .await
9768 .context("inlay hints fetch")?;
9769 Ok(proto::ResolveInlayHintResponse {
9770 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9771 })
9772 }
9773
9774 async fn handle_refresh_code_lens(
9775 this: Entity<Self>,
9776 _: TypedEnvelope<proto::RefreshCodeLens>,
9777 mut cx: AsyncApp,
9778 ) -> Result<proto::Ack> {
9779 this.update(&mut cx, |_, cx| {
9780 cx.emit(LspStoreEvent::RefreshCodeLens);
9781 })?;
9782 Ok(proto::Ack {})
9783 }
9784
9785 async fn handle_open_buffer_for_symbol(
9786 this: Entity<Self>,
9787 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9788 mut cx: AsyncApp,
9789 ) -> Result<proto::OpenBufferForSymbolResponse> {
9790 let peer_id = envelope.original_sender_id().unwrap_or_default();
9791 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9792 let symbol = Self::deserialize_symbol(symbol)?;
9793 let symbol = this.read_with(&cx, |this, _| {
9794 let signature = this.symbol_signature(&symbol.path);
9795 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9796 Ok(symbol)
9797 })??;
9798 let buffer = this
9799 .update(&mut cx, |this, cx| {
9800 this.open_buffer_for_symbol(
9801 &Symbol {
9802 language_server_name: symbol.language_server_name,
9803 source_worktree_id: symbol.source_worktree_id,
9804 source_language_server_id: symbol.source_language_server_id,
9805 path: symbol.path,
9806 name: symbol.name,
9807 kind: symbol.kind,
9808 range: symbol.range,
9809 signature: symbol.signature,
9810 label: CodeLabel {
9811 text: Default::default(),
9812 runs: Default::default(),
9813 filter_range: Default::default(),
9814 },
9815 },
9816 cx,
9817 )
9818 })?
9819 .await?;
9820
9821 this.update(&mut cx, |this, cx| {
9822 let is_private = buffer
9823 .read(cx)
9824 .file()
9825 .map(|f| f.is_private())
9826 .unwrap_or_default();
9827 if is_private {
9828 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9829 } else {
9830 this.buffer_store
9831 .update(cx, |buffer_store, cx| {
9832 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9833 })
9834 .detach_and_log_err(cx);
9835 let buffer_id = buffer.read(cx).remote_id().to_proto();
9836 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9837 }
9838 })?
9839 }
9840
9841 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
9842 let mut hasher = Sha256::new();
9843 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
9844 hasher.update(project_path.path.to_string_lossy().as_bytes());
9845 hasher.update(self.nonce.to_be_bytes());
9846 hasher.finalize().as_slice().try_into().unwrap()
9847 }
9848
9849 pub async fn handle_get_project_symbols(
9850 this: Entity<Self>,
9851 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9852 mut cx: AsyncApp,
9853 ) -> Result<proto::GetProjectSymbolsResponse> {
9854 let symbols = this
9855 .update(&mut cx, |this, cx| {
9856 this.symbols(&envelope.payload.query, cx)
9857 })?
9858 .await?;
9859
9860 Ok(proto::GetProjectSymbolsResponse {
9861 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9862 })
9863 }
9864
9865 pub async fn handle_restart_language_servers(
9866 this: Entity<Self>,
9867 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9868 mut cx: AsyncApp,
9869 ) -> Result<proto::Ack> {
9870 this.update(&mut cx, |lsp_store, cx| {
9871 let buffers =
9872 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9873 lsp_store.restart_language_servers_for_buffers(
9874 buffers,
9875 envelope
9876 .payload
9877 .only_servers
9878 .into_iter()
9879 .filter_map(|selector| {
9880 Some(match selector.selector? {
9881 proto::language_server_selector::Selector::ServerId(server_id) => {
9882 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9883 }
9884 proto::language_server_selector::Selector::Name(name) => {
9885 LanguageServerSelector::Name(LanguageServerName(
9886 SharedString::from(name),
9887 ))
9888 }
9889 })
9890 })
9891 .collect(),
9892 cx,
9893 );
9894 })?;
9895
9896 Ok(proto::Ack {})
9897 }
9898
9899 pub async fn handle_stop_language_servers(
9900 lsp_store: Entity<Self>,
9901 envelope: TypedEnvelope<proto::StopLanguageServers>,
9902 mut cx: AsyncApp,
9903 ) -> Result<proto::Ack> {
9904 lsp_store.update(&mut cx, |lsp_store, cx| {
9905 if envelope.payload.all
9906 && envelope.payload.also_servers.is_empty()
9907 && envelope.payload.buffer_ids.is_empty()
9908 {
9909 lsp_store.stop_all_language_servers(cx);
9910 } else {
9911 let buffers =
9912 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9913 lsp_store
9914 .stop_language_servers_for_buffers(
9915 buffers,
9916 envelope
9917 .payload
9918 .also_servers
9919 .into_iter()
9920 .filter_map(|selector| {
9921 Some(match selector.selector? {
9922 proto::language_server_selector::Selector::ServerId(
9923 server_id,
9924 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9925 server_id,
9926 )),
9927 proto::language_server_selector::Selector::Name(name) => {
9928 LanguageServerSelector::Name(LanguageServerName(
9929 SharedString::from(name),
9930 ))
9931 }
9932 })
9933 })
9934 .collect(),
9935 cx,
9936 )
9937 .detach_and_log_err(cx);
9938 }
9939 })?;
9940
9941 Ok(proto::Ack {})
9942 }
9943
9944 pub async fn handle_cancel_language_server_work(
9945 this: Entity<Self>,
9946 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9947 mut cx: AsyncApp,
9948 ) -> Result<proto::Ack> {
9949 this.update(&mut cx, |this, cx| {
9950 if let Some(work) = envelope.payload.work {
9951 match work {
9952 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9953 let buffers =
9954 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9955 this.cancel_language_server_work_for_buffers(buffers, cx);
9956 }
9957 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9958 let server_id = LanguageServerId::from_proto(work.language_server_id);
9959 this.cancel_language_server_work(server_id, work.token, cx);
9960 }
9961 }
9962 }
9963 })?;
9964
9965 Ok(proto::Ack {})
9966 }
9967
9968 fn buffer_ids_to_buffers(
9969 &mut self,
9970 buffer_ids: impl Iterator<Item = u64>,
9971 cx: &mut Context<Self>,
9972 ) -> Vec<Entity<Buffer>> {
9973 buffer_ids
9974 .into_iter()
9975 .flat_map(|buffer_id| {
9976 self.buffer_store
9977 .read(cx)
9978 .get(BufferId::new(buffer_id).log_err()?)
9979 })
9980 .collect::<Vec<_>>()
9981 }
9982
9983 async fn handle_apply_additional_edits_for_completion(
9984 this: Entity<Self>,
9985 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9986 mut cx: AsyncApp,
9987 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9988 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9989 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9990 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9991 let completion = Self::deserialize_completion(
9992 envelope.payload.completion.context("invalid completion")?,
9993 )?;
9994 anyhow::Ok((buffer, completion))
9995 })??;
9996
9997 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9998 this.apply_additional_edits_for_completion(
9999 buffer,
10000 Rc::new(RefCell::new(Box::new([Completion {
10001 replace_range: completion.replace_range,
10002 new_text: completion.new_text,
10003 source: completion.source,
10004 documentation: None,
10005 label: CodeLabel {
10006 text: Default::default(),
10007 runs: Default::default(),
10008 filter_range: Default::default(),
10009 },
10010 insert_text_mode: None,
10011 icon_path: None,
10012 confirm: None,
10013 }]))),
10014 0,
10015 false,
10016 cx,
10017 )
10018 })?;
10019
10020 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10021 transaction: apply_additional_edits
10022 .await?
10023 .as_ref()
10024 .map(language::proto::serialize_transaction),
10025 })
10026 }
10027
10028 pub fn last_formatting_failure(&self) -> Option<&str> {
10029 self.last_formatting_failure.as_deref()
10030 }
10031
10032 pub fn reset_last_formatting_failure(&mut self) {
10033 self.last_formatting_failure = None;
10034 }
10035
10036 pub fn environment_for_buffer(
10037 &self,
10038 buffer: &Entity<Buffer>,
10039 cx: &mut Context<Self>,
10040 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10041 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10042 environment.update(cx, |env, cx| {
10043 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10044 })
10045 } else {
10046 Task::ready(None).shared()
10047 }
10048 }
10049
10050 pub fn format(
10051 &mut self,
10052 buffers: HashSet<Entity<Buffer>>,
10053 target: LspFormatTarget,
10054 push_to_history: bool,
10055 trigger: FormatTrigger,
10056 cx: &mut Context<Self>,
10057 ) -> Task<anyhow::Result<ProjectTransaction>> {
10058 let logger = zlog::scoped!("format");
10059 if self.as_local().is_some() {
10060 zlog::trace!(logger => "Formatting locally");
10061 let logger = zlog::scoped!(logger => "local");
10062 let buffers = buffers
10063 .into_iter()
10064 .map(|buffer_handle| {
10065 let buffer = buffer_handle.read(cx);
10066 let buffer_abs_path = File::from_dyn(buffer.file())
10067 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10068
10069 (buffer_handle, buffer_abs_path, buffer.remote_id())
10070 })
10071 .collect::<Vec<_>>();
10072
10073 cx.spawn(async move |lsp_store, cx| {
10074 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10075
10076 for (handle, abs_path, id) in buffers {
10077 let env = lsp_store
10078 .update(cx, |lsp_store, cx| {
10079 lsp_store.environment_for_buffer(&handle, cx)
10080 })?
10081 .await;
10082
10083 let ranges = match &target {
10084 LspFormatTarget::Buffers => None,
10085 LspFormatTarget::Ranges(ranges) => {
10086 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10087 }
10088 };
10089
10090 formattable_buffers.push(FormattableBuffer {
10091 handle,
10092 abs_path,
10093 env,
10094 ranges,
10095 });
10096 }
10097 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10098
10099 let format_timer = zlog::time!(logger => "Formatting buffers");
10100 let result = LocalLspStore::format_locally(
10101 lsp_store.clone(),
10102 formattable_buffers,
10103 push_to_history,
10104 trigger,
10105 logger,
10106 cx,
10107 )
10108 .await;
10109 format_timer.end();
10110
10111 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10112
10113 lsp_store.update(cx, |lsp_store, _| {
10114 lsp_store.update_last_formatting_failure(&result);
10115 })?;
10116
10117 result
10118 })
10119 } else if let Some((client, project_id)) = self.upstream_client() {
10120 zlog::trace!(logger => "Formatting remotely");
10121 let logger = zlog::scoped!(logger => "remote");
10122 // Don't support formatting ranges via remote
10123 match target {
10124 LspFormatTarget::Buffers => {}
10125 LspFormatTarget::Ranges(_) => {
10126 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10127 return Task::ready(Ok(ProjectTransaction::default()));
10128 }
10129 }
10130
10131 let buffer_store = self.buffer_store();
10132 cx.spawn(async move |lsp_store, cx| {
10133 zlog::trace!(logger => "Sending remote format request");
10134 let request_timer = zlog::time!(logger => "remote format request");
10135 let result = client
10136 .request(proto::FormatBuffers {
10137 project_id,
10138 trigger: trigger as i32,
10139 buffer_ids: buffers
10140 .iter()
10141 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10142 .collect::<Result<_>>()?,
10143 })
10144 .await
10145 .and_then(|result| result.transaction.context("missing transaction"));
10146 request_timer.end();
10147
10148 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10149
10150 lsp_store.update(cx, |lsp_store, _| {
10151 lsp_store.update_last_formatting_failure(&result);
10152 })?;
10153
10154 let transaction_response = result?;
10155 let _timer = zlog::time!(logger => "deserializing project transaction");
10156 buffer_store
10157 .update(cx, |buffer_store, cx| {
10158 buffer_store.deserialize_project_transaction(
10159 transaction_response,
10160 push_to_history,
10161 cx,
10162 )
10163 })?
10164 .await
10165 })
10166 } else {
10167 zlog::trace!(logger => "Not formatting");
10168 Task::ready(Ok(ProjectTransaction::default()))
10169 }
10170 }
10171
10172 async fn handle_format_buffers(
10173 this: Entity<Self>,
10174 envelope: TypedEnvelope<proto::FormatBuffers>,
10175 mut cx: AsyncApp,
10176 ) -> Result<proto::FormatBuffersResponse> {
10177 let sender_id = envelope.original_sender_id().unwrap_or_default();
10178 let format = this.update(&mut cx, |this, cx| {
10179 let mut buffers = HashSet::default();
10180 for buffer_id in &envelope.payload.buffer_ids {
10181 let buffer_id = BufferId::new(*buffer_id)?;
10182 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10183 }
10184 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10185 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10186 })??;
10187
10188 let project_transaction = format.await?;
10189 let project_transaction = this.update(&mut cx, |this, cx| {
10190 this.buffer_store.update(cx, |buffer_store, cx| {
10191 buffer_store.serialize_project_transaction_for_peer(
10192 project_transaction,
10193 sender_id,
10194 cx,
10195 )
10196 })
10197 })?;
10198 Ok(proto::FormatBuffersResponse {
10199 transaction: Some(project_transaction),
10200 })
10201 }
10202
10203 async fn handle_apply_code_action_kind(
10204 this: Entity<Self>,
10205 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10206 mut cx: AsyncApp,
10207 ) -> Result<proto::ApplyCodeActionKindResponse> {
10208 let sender_id = envelope.original_sender_id().unwrap_or_default();
10209 let format = this.update(&mut cx, |this, cx| {
10210 let mut buffers = HashSet::default();
10211 for buffer_id in &envelope.payload.buffer_ids {
10212 let buffer_id = BufferId::new(*buffer_id)?;
10213 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10214 }
10215 let kind = match envelope.payload.kind.as_str() {
10216 "" => CodeActionKind::EMPTY,
10217 "quickfix" => CodeActionKind::QUICKFIX,
10218 "refactor" => CodeActionKind::REFACTOR,
10219 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10220 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10221 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10222 "source" => CodeActionKind::SOURCE,
10223 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10224 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10225 _ => anyhow::bail!(
10226 "Invalid code action kind {}",
10227 envelope.payload.kind.as_str()
10228 ),
10229 };
10230 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10231 })??;
10232
10233 let project_transaction = format.await?;
10234 let project_transaction = this.update(&mut cx, |this, cx| {
10235 this.buffer_store.update(cx, |buffer_store, cx| {
10236 buffer_store.serialize_project_transaction_for_peer(
10237 project_transaction,
10238 sender_id,
10239 cx,
10240 )
10241 })
10242 })?;
10243 Ok(proto::ApplyCodeActionKindResponse {
10244 transaction: Some(project_transaction),
10245 })
10246 }
10247
10248 async fn shutdown_language_server(
10249 server_state: Option<LanguageServerState>,
10250 name: LanguageServerName,
10251 cx: &mut AsyncApp,
10252 ) {
10253 let server = match server_state {
10254 Some(LanguageServerState::Starting { startup, .. }) => {
10255 let mut timer = cx
10256 .background_executor()
10257 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10258 .fuse();
10259
10260 select! {
10261 server = startup.fuse() => server,
10262 () = timer => {
10263 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10264 None
10265 },
10266 }
10267 }
10268
10269 Some(LanguageServerState::Running { server, .. }) => Some(server),
10270
10271 None => None,
10272 };
10273
10274 if let Some(server) = server
10275 && let Some(shutdown) = server.shutdown()
10276 {
10277 shutdown.await;
10278 }
10279 }
10280
10281 // Returns a list of all of the worktrees which no longer have a language server and the root path
10282 // for the stopped server
10283 fn stop_local_language_server(
10284 &mut self,
10285 server_id: LanguageServerId,
10286 cx: &mut Context<Self>,
10287 ) -> Task<()> {
10288 let local = match &mut self.mode {
10289 LspStoreMode::Local(local) => local,
10290 _ => {
10291 return Task::ready(());
10292 }
10293 };
10294
10295 // Remove this server ID from all entries in the given worktree.
10296 local
10297 .language_server_ids
10298 .retain(|_, state| state.id != server_id);
10299 self.buffer_store.update(cx, |buffer_store, cx| {
10300 for buffer in buffer_store.buffers() {
10301 buffer.update(cx, |buffer, cx| {
10302 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10303 buffer.set_completion_triggers(server_id, Default::default(), cx);
10304 });
10305 }
10306 });
10307
10308 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10309 summaries.retain(|path, summaries_by_server_id| {
10310 if summaries_by_server_id.remove(&server_id).is_some() {
10311 if let Some((client, project_id)) = self.downstream_client.clone() {
10312 client
10313 .send(proto::UpdateDiagnosticSummary {
10314 project_id,
10315 worktree_id: worktree_id.to_proto(),
10316 summary: Some(proto::DiagnosticSummary {
10317 path: path.as_ref().to_proto(),
10318 language_server_id: server_id.0 as u64,
10319 error_count: 0,
10320 warning_count: 0,
10321 }),
10322 more_summaries: Vec::new(),
10323 })
10324 .log_err();
10325 }
10326 !summaries_by_server_id.is_empty()
10327 } else {
10328 true
10329 }
10330 });
10331 }
10332
10333 let local = self.as_local_mut().unwrap();
10334 for diagnostics in local.diagnostics.values_mut() {
10335 diagnostics.retain(|_, diagnostics_by_server_id| {
10336 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10337 diagnostics_by_server_id.remove(ix);
10338 !diagnostics_by_server_id.is_empty()
10339 } else {
10340 true
10341 }
10342 });
10343 }
10344 local.language_server_watched_paths.remove(&server_id);
10345
10346 let server_state = local.language_servers.remove(&server_id);
10347 self.cleanup_lsp_data(server_id);
10348 let name = self
10349 .language_server_statuses
10350 .remove(&server_id)
10351 .map(|status| status.name.clone())
10352 .or_else(|| {
10353 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10354 Some(adapter.name())
10355 } else {
10356 None
10357 }
10358 });
10359
10360 if let Some(name) = name {
10361 log::info!("stopping language server {name}");
10362 self.languages
10363 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10364 cx.notify();
10365
10366 return cx.spawn(async move |lsp_store, cx| {
10367 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10368 lsp_store
10369 .update(cx, |lsp_store, cx| {
10370 lsp_store
10371 .languages
10372 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10373 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10374 cx.notify();
10375 })
10376 .ok();
10377 });
10378 }
10379
10380 if server_state.is_some() {
10381 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10382 }
10383 Task::ready(())
10384 }
10385
10386 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10387 if let Some((client, project_id)) = self.upstream_client() {
10388 let request = client.request(proto::StopLanguageServers {
10389 project_id,
10390 buffer_ids: Vec::new(),
10391 also_servers: Vec::new(),
10392 all: true,
10393 });
10394 cx.background_spawn(request).detach_and_log_err(cx);
10395 } else {
10396 let Some(local) = self.as_local_mut() else {
10397 return;
10398 };
10399 let language_servers_to_stop = local
10400 .language_server_ids
10401 .values()
10402 .map(|state| state.id)
10403 .collect();
10404 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10405 let tasks = language_servers_to_stop
10406 .into_iter()
10407 .map(|server| self.stop_local_language_server(server, cx))
10408 .collect::<Vec<_>>();
10409 cx.background_spawn(async move {
10410 futures::future::join_all(tasks).await;
10411 })
10412 .detach();
10413 }
10414 }
10415
10416 pub fn restart_language_servers_for_buffers(
10417 &mut self,
10418 buffers: Vec<Entity<Buffer>>,
10419 only_restart_servers: HashSet<LanguageServerSelector>,
10420 cx: &mut Context<Self>,
10421 ) {
10422 if let Some((client, project_id)) = self.upstream_client() {
10423 let request = client.request(proto::RestartLanguageServers {
10424 project_id,
10425 buffer_ids: buffers
10426 .into_iter()
10427 .map(|b| b.read(cx).remote_id().to_proto())
10428 .collect(),
10429 only_servers: only_restart_servers
10430 .into_iter()
10431 .map(|selector| {
10432 let selector = match selector {
10433 LanguageServerSelector::Id(language_server_id) => {
10434 proto::language_server_selector::Selector::ServerId(
10435 language_server_id.to_proto(),
10436 )
10437 }
10438 LanguageServerSelector::Name(language_server_name) => {
10439 proto::language_server_selector::Selector::Name(
10440 language_server_name.to_string(),
10441 )
10442 }
10443 };
10444 proto::LanguageServerSelector {
10445 selector: Some(selector),
10446 }
10447 })
10448 .collect(),
10449 all: false,
10450 });
10451 cx.background_spawn(request).detach_and_log_err(cx);
10452 } else {
10453 let stop_task = if only_restart_servers.is_empty() {
10454 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10455 } else {
10456 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10457 };
10458 cx.spawn(async move |lsp_store, cx| {
10459 stop_task.await;
10460 lsp_store
10461 .update(cx, |lsp_store, cx| {
10462 for buffer in buffers {
10463 lsp_store.register_buffer_with_language_servers(
10464 &buffer,
10465 only_restart_servers.clone(),
10466 true,
10467 cx,
10468 );
10469 }
10470 })
10471 .ok()
10472 })
10473 .detach();
10474 }
10475 }
10476
10477 pub fn stop_language_servers_for_buffers(
10478 &mut self,
10479 buffers: Vec<Entity<Buffer>>,
10480 also_stop_servers: HashSet<LanguageServerSelector>,
10481 cx: &mut Context<Self>,
10482 ) -> Task<Result<()>> {
10483 if let Some((client, project_id)) = self.upstream_client() {
10484 let request = client.request(proto::StopLanguageServers {
10485 project_id,
10486 buffer_ids: buffers
10487 .into_iter()
10488 .map(|b| b.read(cx).remote_id().to_proto())
10489 .collect(),
10490 also_servers: also_stop_servers
10491 .into_iter()
10492 .map(|selector| {
10493 let selector = match selector {
10494 LanguageServerSelector::Id(language_server_id) => {
10495 proto::language_server_selector::Selector::ServerId(
10496 language_server_id.to_proto(),
10497 )
10498 }
10499 LanguageServerSelector::Name(language_server_name) => {
10500 proto::language_server_selector::Selector::Name(
10501 language_server_name.to_string(),
10502 )
10503 }
10504 };
10505 proto::LanguageServerSelector {
10506 selector: Some(selector),
10507 }
10508 })
10509 .collect(),
10510 all: false,
10511 });
10512 cx.background_spawn(async move {
10513 let _ = request.await?;
10514 Ok(())
10515 })
10516 } else {
10517 let task =
10518 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10519 cx.background_spawn(async move {
10520 task.await;
10521 Ok(())
10522 })
10523 }
10524 }
10525
10526 fn stop_local_language_servers_for_buffers(
10527 &mut self,
10528 buffers: &[Entity<Buffer>],
10529 also_stop_servers: HashSet<LanguageServerSelector>,
10530 cx: &mut Context<Self>,
10531 ) -> Task<()> {
10532 let Some(local) = self.as_local_mut() else {
10533 return Task::ready(());
10534 };
10535 let mut language_server_names_to_stop = BTreeSet::default();
10536 let mut language_servers_to_stop = also_stop_servers
10537 .into_iter()
10538 .flat_map(|selector| match selector {
10539 LanguageServerSelector::Id(id) => Some(id),
10540 LanguageServerSelector::Name(name) => {
10541 language_server_names_to_stop.insert(name);
10542 None
10543 }
10544 })
10545 .collect::<BTreeSet<_>>();
10546
10547 let mut covered_worktrees = HashSet::default();
10548 for buffer in buffers {
10549 buffer.update(cx, |buffer, cx| {
10550 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10551 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10552 && covered_worktrees.insert(worktree_id)
10553 {
10554 language_server_names_to_stop.retain(|name| {
10555 let old_ids_count = language_servers_to_stop.len();
10556 let all_language_servers_with_this_name = local
10557 .language_server_ids
10558 .iter()
10559 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10560 language_servers_to_stop.extend(all_language_servers_with_this_name);
10561 old_ids_count == language_servers_to_stop.len()
10562 });
10563 }
10564 });
10565 }
10566 for name in language_server_names_to_stop {
10567 language_servers_to_stop.extend(
10568 local
10569 .language_server_ids
10570 .iter()
10571 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10572 );
10573 }
10574
10575 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10576 let tasks = language_servers_to_stop
10577 .into_iter()
10578 .map(|server| self.stop_local_language_server(server, cx))
10579 .collect::<Vec<_>>();
10580
10581 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10582 }
10583
10584 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10585 let (worktree, relative_path) =
10586 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10587
10588 let project_path = ProjectPath {
10589 worktree_id: worktree.read(cx).id(),
10590 path: relative_path.into(),
10591 };
10592
10593 Some(
10594 self.buffer_store()
10595 .read(cx)
10596 .get_by_path(&project_path)?
10597 .read(cx),
10598 )
10599 }
10600
10601 #[cfg(any(test, feature = "test-support"))]
10602 pub fn update_diagnostics(
10603 &mut self,
10604 server_id: LanguageServerId,
10605 diagnostics: lsp::PublishDiagnosticsParams,
10606 result_id: Option<String>,
10607 source_kind: DiagnosticSourceKind,
10608 disk_based_sources: &[String],
10609 cx: &mut Context<Self>,
10610 ) -> Result<()> {
10611 self.merge_lsp_diagnostics(
10612 source_kind,
10613 vec![DocumentDiagnosticsUpdate {
10614 diagnostics,
10615 result_id,
10616 server_id,
10617 disk_based_sources: Cow::Borrowed(disk_based_sources),
10618 }],
10619 |_, _, _| false,
10620 cx,
10621 )
10622 }
10623
10624 pub fn merge_lsp_diagnostics(
10625 &mut self,
10626 source_kind: DiagnosticSourceKind,
10627 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10628 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10629 cx: &mut Context<Self>,
10630 ) -> Result<()> {
10631 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10632 let updates = lsp_diagnostics
10633 .into_iter()
10634 .filter_map(|update| {
10635 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10636 Some(DocumentDiagnosticsUpdate {
10637 diagnostics: self.lsp_to_document_diagnostics(
10638 abs_path,
10639 source_kind,
10640 update.server_id,
10641 update.diagnostics,
10642 &update.disk_based_sources,
10643 ),
10644 result_id: update.result_id,
10645 server_id: update.server_id,
10646 disk_based_sources: update.disk_based_sources,
10647 })
10648 })
10649 .collect();
10650 self.merge_diagnostic_entries(updates, merge, cx)?;
10651 Ok(())
10652 }
10653
10654 fn lsp_to_document_diagnostics(
10655 &mut self,
10656 document_abs_path: PathBuf,
10657 source_kind: DiagnosticSourceKind,
10658 server_id: LanguageServerId,
10659 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10660 disk_based_sources: &[String],
10661 ) -> DocumentDiagnostics {
10662 let mut diagnostics = Vec::default();
10663 let mut primary_diagnostic_group_ids = HashMap::default();
10664 let mut sources_by_group_id = HashMap::default();
10665 let mut supporting_diagnostics = HashMap::default();
10666
10667 let adapter = self.language_server_adapter_for_id(server_id);
10668
10669 // Ensure that primary diagnostics are always the most severe
10670 lsp_diagnostics
10671 .diagnostics
10672 .sort_by_key(|item| item.severity);
10673
10674 for diagnostic in &lsp_diagnostics.diagnostics {
10675 let source = diagnostic.source.as_ref();
10676 let range = range_from_lsp(diagnostic.range);
10677 let is_supporting = diagnostic
10678 .related_information
10679 .as_ref()
10680 .is_some_and(|infos| {
10681 infos.iter().any(|info| {
10682 primary_diagnostic_group_ids.contains_key(&(
10683 source,
10684 diagnostic.code.clone(),
10685 range_from_lsp(info.location.range),
10686 ))
10687 })
10688 });
10689
10690 let is_unnecessary = diagnostic
10691 .tags
10692 .as_ref()
10693 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10694
10695 let underline = self
10696 .language_server_adapter_for_id(server_id)
10697 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10698
10699 if is_supporting {
10700 supporting_diagnostics.insert(
10701 (source, diagnostic.code.clone(), range),
10702 (diagnostic.severity, is_unnecessary),
10703 );
10704 } else {
10705 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10706 let is_disk_based =
10707 source.is_some_and(|source| disk_based_sources.contains(source));
10708
10709 sources_by_group_id.insert(group_id, source);
10710 primary_diagnostic_group_ids
10711 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10712
10713 diagnostics.push(DiagnosticEntry {
10714 range,
10715 diagnostic: Diagnostic {
10716 source: diagnostic.source.clone(),
10717 source_kind,
10718 code: diagnostic.code.clone(),
10719 code_description: diagnostic
10720 .code_description
10721 .as_ref()
10722 .and_then(|d| d.href.clone()),
10723 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10724 markdown: adapter.as_ref().and_then(|adapter| {
10725 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10726 }),
10727 message: diagnostic.message.trim().to_string(),
10728 group_id,
10729 is_primary: true,
10730 is_disk_based,
10731 is_unnecessary,
10732 underline,
10733 data: diagnostic.data.clone(),
10734 },
10735 });
10736 if let Some(infos) = &diagnostic.related_information {
10737 for info in infos {
10738 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10739 let range = range_from_lsp(info.location.range);
10740 diagnostics.push(DiagnosticEntry {
10741 range,
10742 diagnostic: Diagnostic {
10743 source: diagnostic.source.clone(),
10744 source_kind,
10745 code: diagnostic.code.clone(),
10746 code_description: diagnostic
10747 .code_description
10748 .as_ref()
10749 .and_then(|d| d.href.clone()),
10750 severity: DiagnosticSeverity::INFORMATION,
10751 markdown: adapter.as_ref().and_then(|adapter| {
10752 adapter.diagnostic_message_to_markdown(&info.message)
10753 }),
10754 message: info.message.trim().to_string(),
10755 group_id,
10756 is_primary: false,
10757 is_disk_based,
10758 is_unnecessary: false,
10759 underline,
10760 data: diagnostic.data.clone(),
10761 },
10762 });
10763 }
10764 }
10765 }
10766 }
10767 }
10768
10769 for entry in &mut diagnostics {
10770 let diagnostic = &mut entry.diagnostic;
10771 if !diagnostic.is_primary {
10772 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10773 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10774 source,
10775 diagnostic.code.clone(),
10776 entry.range.clone(),
10777 )) {
10778 if let Some(severity) = severity {
10779 diagnostic.severity = severity;
10780 }
10781 diagnostic.is_unnecessary = is_unnecessary;
10782 }
10783 }
10784 }
10785
10786 DocumentDiagnostics {
10787 diagnostics,
10788 document_abs_path,
10789 version: lsp_diagnostics.version,
10790 }
10791 }
10792
10793 fn insert_newly_running_language_server(
10794 &mut self,
10795 adapter: Arc<CachedLspAdapter>,
10796 language_server: Arc<LanguageServer>,
10797 server_id: LanguageServerId,
10798 key: LanguageServerSeed,
10799 workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
10800 cx: &mut Context<Self>,
10801 ) {
10802 let Some(local) = self.as_local_mut() else {
10803 return;
10804 };
10805 // If the language server for this key doesn't match the server id, don't store the
10806 // server. Which will cause it to be dropped, killing the process
10807 if local
10808 .language_server_ids
10809 .get(&key)
10810 .map(|state| state.id != server_id)
10811 .unwrap_or(false)
10812 {
10813 return;
10814 }
10815
10816 // Update language_servers collection with Running variant of LanguageServerState
10817 // indicating that the server is up and running and ready
10818 let workspace_folders = workspace_folders.lock().clone();
10819 language_server.set_workspace_folders(workspace_folders);
10820
10821 local.language_servers.insert(
10822 server_id,
10823 LanguageServerState::Running {
10824 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10825 language_server.clone(),
10826 cx,
10827 ),
10828 adapter: adapter.clone(),
10829 server: language_server.clone(),
10830 simulate_disk_based_diagnostics_completion: None,
10831 },
10832 );
10833 local
10834 .languages
10835 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10836 if let Some(file_ops_caps) = language_server
10837 .capabilities()
10838 .workspace
10839 .as_ref()
10840 .and_then(|ws| ws.file_operations.as_ref())
10841 {
10842 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10843 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10844 if did_rename_caps.or(will_rename_caps).is_some() {
10845 let watcher = RenamePathsWatchedForServer::default()
10846 .with_did_rename_patterns(did_rename_caps)
10847 .with_will_rename_patterns(will_rename_caps);
10848 local
10849 .language_server_paths_watched_for_rename
10850 .insert(server_id, watcher);
10851 }
10852 }
10853
10854 self.language_server_statuses.insert(
10855 server_id,
10856 LanguageServerStatus {
10857 name: language_server.name(),
10858 pending_work: Default::default(),
10859 has_pending_diagnostic_updates: false,
10860 progress_tokens: Default::default(),
10861 },
10862 );
10863
10864 cx.emit(LspStoreEvent::LanguageServerAdded(
10865 server_id,
10866 language_server.name(),
10867 Some(key.worktree_id),
10868 ));
10869 cx.emit(LspStoreEvent::RefreshInlayHints);
10870
10871 let server_capabilities = language_server.capabilities();
10872 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10873 downstream_client
10874 .send(proto::StartLanguageServer {
10875 project_id: *project_id,
10876 server: Some(proto::LanguageServer {
10877 id: server_id.to_proto(),
10878 name: language_server.name().to_string(),
10879 worktree_id: Some(key.worktree_id.to_proto()),
10880 }),
10881 capabilities: serde_json::to_string(&server_capabilities)
10882 .expect("serializing server LSP capabilities"),
10883 })
10884 .log_err();
10885 }
10886 self.lsp_server_capabilities
10887 .insert(server_id, server_capabilities);
10888
10889 // Tell the language server about every open buffer in the worktree that matches the language.
10890 // Also check for buffers in worktrees that reused this server
10891 let mut worktrees_using_server = vec![key.worktree_id];
10892 if let Some(local) = self.as_local() {
10893 // Find all worktrees that have this server in their language server tree
10894 for (worktree_id, servers) in &local.lsp_tree.instances {
10895 if *worktree_id != key.worktree_id {
10896 for (_, server_map) in &servers.roots {
10897 if server_map.contains_key(&key.name) {
10898 worktrees_using_server.push(*worktree_id);
10899 }
10900 }
10901 }
10902 }
10903 }
10904
10905 let mut buffer_paths_registered = Vec::new();
10906 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10907 for buffer_handle in buffer_store.buffers() {
10908 let buffer = buffer_handle.read(cx);
10909 let file = match File::from_dyn(buffer.file()) {
10910 Some(file) => file,
10911 None => continue,
10912 };
10913 let language = match buffer.language() {
10914 Some(language) => language,
10915 None => continue,
10916 };
10917
10918 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10919 || !self
10920 .languages
10921 .lsp_adapters(&language.name())
10922 .iter()
10923 .any(|a| a.name == key.name)
10924 {
10925 continue;
10926 }
10927 // didOpen
10928 let file = match file.as_local() {
10929 Some(file) => file,
10930 None => continue,
10931 };
10932
10933 let local = self.as_local_mut().unwrap();
10934
10935 let buffer_id = buffer.remote_id();
10936 if local.registered_buffers.contains_key(&buffer_id) {
10937 let versions = local
10938 .buffer_snapshots
10939 .entry(buffer_id)
10940 .or_default()
10941 .entry(server_id)
10942 .and_modify(|_| {
10943 assert!(
10944 false,
10945 "There should not be an existing snapshot for a newly inserted buffer"
10946 )
10947 })
10948 .or_insert_with(|| {
10949 vec![LspBufferSnapshot {
10950 version: 0,
10951 snapshot: buffer.text_snapshot(),
10952 }]
10953 });
10954
10955 let snapshot = versions.last().unwrap();
10956 let version = snapshot.version;
10957 let initial_snapshot = &snapshot.snapshot;
10958 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
10959 language_server.register_buffer(
10960 uri,
10961 adapter.language_id(&language.name()),
10962 version,
10963 initial_snapshot.text(),
10964 );
10965 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10966 local
10967 .buffers_opened_in_servers
10968 .entry(buffer_id)
10969 .or_default()
10970 .insert(server_id);
10971 }
10972 buffer_handle.update(cx, |buffer, cx| {
10973 buffer.set_completion_triggers(
10974 server_id,
10975 language_server
10976 .capabilities()
10977 .completion_provider
10978 .as_ref()
10979 .and_then(|provider| {
10980 provider
10981 .trigger_characters
10982 .as_ref()
10983 .map(|characters| characters.iter().cloned().collect())
10984 })
10985 .unwrap_or_default(),
10986 cx,
10987 )
10988 });
10989 }
10990 });
10991
10992 for (buffer_id, abs_path) in buffer_paths_registered {
10993 cx.emit(LspStoreEvent::LanguageServerUpdate {
10994 language_server_id: server_id,
10995 name: Some(adapter.name()),
10996 message: proto::update_language_server::Variant::RegisteredForBuffer(
10997 proto::RegisteredForBuffer {
10998 buffer_abs_path: abs_path.to_string_lossy().to_string(),
10999 buffer_id: buffer_id.to_proto(),
11000 },
11001 ),
11002 });
11003 }
11004
11005 cx.notify();
11006 }
11007
11008 pub fn language_servers_running_disk_based_diagnostics(
11009 &self,
11010 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11011 self.language_server_statuses
11012 .iter()
11013 .filter_map(|(id, status)| {
11014 if status.has_pending_diagnostic_updates {
11015 Some(*id)
11016 } else {
11017 None
11018 }
11019 })
11020 }
11021
11022 pub(crate) fn cancel_language_server_work_for_buffers(
11023 &mut self,
11024 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11025 cx: &mut Context<Self>,
11026 ) {
11027 if let Some((client, project_id)) = self.upstream_client() {
11028 let request = client.request(proto::CancelLanguageServerWork {
11029 project_id,
11030 work: Some(proto::cancel_language_server_work::Work::Buffers(
11031 proto::cancel_language_server_work::Buffers {
11032 buffer_ids: buffers
11033 .into_iter()
11034 .map(|b| b.read(cx).remote_id().to_proto())
11035 .collect(),
11036 },
11037 )),
11038 });
11039 cx.background_spawn(request).detach_and_log_err(cx);
11040 } else if let Some(local) = self.as_local() {
11041 let servers = buffers
11042 .into_iter()
11043 .flat_map(|buffer| {
11044 buffer.update(cx, |buffer, cx| {
11045 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11046 })
11047 })
11048 .collect::<HashSet<_>>();
11049 for server_id in servers {
11050 self.cancel_language_server_work(server_id, None, cx);
11051 }
11052 }
11053 }
11054
11055 pub(crate) fn cancel_language_server_work(
11056 &mut self,
11057 server_id: LanguageServerId,
11058 token_to_cancel: Option<String>,
11059 cx: &mut Context<Self>,
11060 ) {
11061 if let Some(local) = self.as_local() {
11062 let status = self.language_server_statuses.get(&server_id);
11063 let server = local.language_servers.get(&server_id);
11064 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11065 {
11066 for (token, progress) in &status.pending_work {
11067 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11068 && token != token_to_cancel
11069 {
11070 continue;
11071 }
11072 if progress.is_cancellable {
11073 server
11074 .notify::<lsp::notification::WorkDoneProgressCancel>(
11075 &WorkDoneProgressCancelParams {
11076 token: lsp::NumberOrString::String(token.clone()),
11077 },
11078 )
11079 .ok();
11080 }
11081 }
11082 }
11083 } else if let Some((client, project_id)) = self.upstream_client() {
11084 let request = client.request(proto::CancelLanguageServerWork {
11085 project_id,
11086 work: Some(
11087 proto::cancel_language_server_work::Work::LanguageServerWork(
11088 proto::cancel_language_server_work::LanguageServerWork {
11089 language_server_id: server_id.to_proto(),
11090 token: token_to_cancel,
11091 },
11092 ),
11093 ),
11094 });
11095 cx.background_spawn(request).detach_and_log_err(cx);
11096 }
11097 }
11098
11099 fn register_supplementary_language_server(
11100 &mut self,
11101 id: LanguageServerId,
11102 name: LanguageServerName,
11103 server: Arc<LanguageServer>,
11104 cx: &mut Context<Self>,
11105 ) {
11106 if let Some(local) = self.as_local_mut() {
11107 local
11108 .supplementary_language_servers
11109 .insert(id, (name.clone(), server));
11110 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11111 }
11112 }
11113
11114 fn unregister_supplementary_language_server(
11115 &mut self,
11116 id: LanguageServerId,
11117 cx: &mut Context<Self>,
11118 ) {
11119 if let Some(local) = self.as_local_mut() {
11120 local.supplementary_language_servers.remove(&id);
11121 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11122 }
11123 }
11124
11125 pub(crate) fn supplementary_language_servers(
11126 &self,
11127 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11128 self.as_local().into_iter().flat_map(|local| {
11129 local
11130 .supplementary_language_servers
11131 .iter()
11132 .map(|(id, (name, _))| (*id, name.clone()))
11133 })
11134 }
11135
11136 pub fn language_server_adapter_for_id(
11137 &self,
11138 id: LanguageServerId,
11139 ) -> Option<Arc<CachedLspAdapter>> {
11140 self.as_local()
11141 .and_then(|local| local.language_servers.get(&id))
11142 .and_then(|language_server_state| match language_server_state {
11143 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11144 _ => None,
11145 })
11146 }
11147
11148 pub(super) fn update_local_worktree_language_servers(
11149 &mut self,
11150 worktree_handle: &Entity<Worktree>,
11151 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
11152 cx: &mut Context<Self>,
11153 ) {
11154 if changes.is_empty() {
11155 return;
11156 }
11157
11158 let Some(local) = self.as_local() else { return };
11159
11160 local.prettier_store.update(cx, |prettier_store, cx| {
11161 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11162 });
11163
11164 let worktree_id = worktree_handle.read(cx).id();
11165 let mut language_server_ids = local
11166 .language_server_ids
11167 .iter()
11168 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11169 .collect::<Vec<_>>();
11170 language_server_ids.sort();
11171 language_server_ids.dedup();
11172
11173 let abs_path = worktree_handle.read(cx).abs_path();
11174 for server_id in &language_server_ids {
11175 if let Some(LanguageServerState::Running { server, .. }) =
11176 local.language_servers.get(server_id)
11177 && let Some(watched_paths) = local
11178 .language_server_watched_paths
11179 .get(server_id)
11180 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11181 {
11182 let params = lsp::DidChangeWatchedFilesParams {
11183 changes: changes
11184 .iter()
11185 .filter_map(|(path, _, change)| {
11186 if !watched_paths.is_match(path) {
11187 return None;
11188 }
11189 let typ = match change {
11190 PathChange::Loaded => return None,
11191 PathChange::Added => lsp::FileChangeType::CREATED,
11192 PathChange::Removed => lsp::FileChangeType::DELETED,
11193 PathChange::Updated => lsp::FileChangeType::CHANGED,
11194 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11195 };
11196 Some(lsp::FileEvent {
11197 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
11198 typ,
11199 })
11200 })
11201 .collect(),
11202 };
11203 if !params.changes.is_empty() {
11204 server
11205 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
11206 .ok();
11207 }
11208 }
11209 }
11210 for (path, _, _) in changes {
11211 if let Some(file_name) = path.file_name().and_then(|file_name| file_name.to_str())
11212 && local.watched_manifest_filenames.contains(file_name)
11213 {
11214 self.request_workspace_config_refresh();
11215 break;
11216 }
11217 }
11218 }
11219
11220 pub fn wait_for_remote_buffer(
11221 &mut self,
11222 id: BufferId,
11223 cx: &mut Context<Self>,
11224 ) -> Task<Result<Entity<Buffer>>> {
11225 self.buffer_store.update(cx, |buffer_store, cx| {
11226 buffer_store.wait_for_remote_buffer(id, cx)
11227 })
11228 }
11229
11230 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11231 proto::Symbol {
11232 language_server_name: symbol.language_server_name.0.to_string(),
11233 source_worktree_id: symbol.source_worktree_id.to_proto(),
11234 language_server_id: symbol.source_language_server_id.to_proto(),
11235 worktree_id: symbol.path.worktree_id.to_proto(),
11236 path: symbol.path.path.as_ref().to_proto(),
11237 name: symbol.name.clone(),
11238 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11239 start: Some(proto::PointUtf16 {
11240 row: symbol.range.start.0.row,
11241 column: symbol.range.start.0.column,
11242 }),
11243 end: Some(proto::PointUtf16 {
11244 row: symbol.range.end.0.row,
11245 column: symbol.range.end.0.column,
11246 }),
11247 signature: symbol.signature.to_vec(),
11248 }
11249 }
11250
11251 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11252 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11253 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11254 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11255 let path = ProjectPath {
11256 worktree_id,
11257 path: Arc::<Path>::from_proto(serialized_symbol.path),
11258 };
11259
11260 let start = serialized_symbol.start.context("invalid start")?;
11261 let end = serialized_symbol.end.context("invalid end")?;
11262 Ok(CoreSymbol {
11263 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11264 source_worktree_id,
11265 source_language_server_id: LanguageServerId::from_proto(
11266 serialized_symbol.language_server_id,
11267 ),
11268 path,
11269 name: serialized_symbol.name,
11270 range: Unclipped(PointUtf16::new(start.row, start.column))
11271 ..Unclipped(PointUtf16::new(end.row, end.column)),
11272 kind,
11273 signature: serialized_symbol
11274 .signature
11275 .try_into()
11276 .map_err(|_| anyhow!("invalid signature"))?,
11277 })
11278 }
11279
11280 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11281 let mut serialized_completion = proto::Completion {
11282 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11283 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11284 new_text: completion.new_text.clone(),
11285 ..proto::Completion::default()
11286 };
11287 match &completion.source {
11288 CompletionSource::Lsp {
11289 insert_range,
11290 server_id,
11291 lsp_completion,
11292 lsp_defaults,
11293 resolved,
11294 } => {
11295 let (old_insert_start, old_insert_end) = insert_range
11296 .as_ref()
11297 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11298 .unzip();
11299
11300 serialized_completion.old_insert_start = old_insert_start;
11301 serialized_completion.old_insert_end = old_insert_end;
11302 serialized_completion.source = proto::completion::Source::Lsp as i32;
11303 serialized_completion.server_id = server_id.0 as u64;
11304 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11305 serialized_completion.lsp_defaults = lsp_defaults
11306 .as_deref()
11307 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11308 serialized_completion.resolved = *resolved;
11309 }
11310 CompletionSource::BufferWord {
11311 word_range,
11312 resolved,
11313 } => {
11314 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11315 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11316 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11317 serialized_completion.resolved = *resolved;
11318 }
11319 CompletionSource::Custom => {
11320 serialized_completion.source = proto::completion::Source::Custom as i32;
11321 serialized_completion.resolved = true;
11322 }
11323 CompletionSource::Dap { sort_text } => {
11324 serialized_completion.source = proto::completion::Source::Dap as i32;
11325 serialized_completion.sort_text = Some(sort_text.clone());
11326 }
11327 }
11328
11329 serialized_completion
11330 }
11331
11332 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11333 let old_replace_start = completion
11334 .old_replace_start
11335 .and_then(deserialize_anchor)
11336 .context("invalid old start")?;
11337 let old_replace_end = completion
11338 .old_replace_end
11339 .and_then(deserialize_anchor)
11340 .context("invalid old end")?;
11341 let insert_range = {
11342 match completion.old_insert_start.zip(completion.old_insert_end) {
11343 Some((start, end)) => {
11344 let start = deserialize_anchor(start).context("invalid insert old start")?;
11345 let end = deserialize_anchor(end).context("invalid insert old end")?;
11346 Some(start..end)
11347 }
11348 None => None,
11349 }
11350 };
11351 Ok(CoreCompletion {
11352 replace_range: old_replace_start..old_replace_end,
11353 new_text: completion.new_text,
11354 source: match proto::completion::Source::from_i32(completion.source) {
11355 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11356 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11357 insert_range,
11358 server_id: LanguageServerId::from_proto(completion.server_id),
11359 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11360 lsp_defaults: completion
11361 .lsp_defaults
11362 .as_deref()
11363 .map(serde_json::from_slice)
11364 .transpose()?,
11365 resolved: completion.resolved,
11366 },
11367 Some(proto::completion::Source::BufferWord) => {
11368 let word_range = completion
11369 .buffer_word_start
11370 .and_then(deserialize_anchor)
11371 .context("invalid buffer word start")?
11372 ..completion
11373 .buffer_word_end
11374 .and_then(deserialize_anchor)
11375 .context("invalid buffer word end")?;
11376 CompletionSource::BufferWord {
11377 word_range,
11378 resolved: completion.resolved,
11379 }
11380 }
11381 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11382 sort_text: completion
11383 .sort_text
11384 .context("expected sort text to exist")?,
11385 },
11386 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11387 },
11388 })
11389 }
11390
11391 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11392 let (kind, lsp_action) = match &action.lsp_action {
11393 LspAction::Action(code_action) => (
11394 proto::code_action::Kind::Action as i32,
11395 serde_json::to_vec(code_action).unwrap(),
11396 ),
11397 LspAction::Command(command) => (
11398 proto::code_action::Kind::Command as i32,
11399 serde_json::to_vec(command).unwrap(),
11400 ),
11401 LspAction::CodeLens(code_lens) => (
11402 proto::code_action::Kind::CodeLens as i32,
11403 serde_json::to_vec(code_lens).unwrap(),
11404 ),
11405 };
11406
11407 proto::CodeAction {
11408 server_id: action.server_id.0 as u64,
11409 start: Some(serialize_anchor(&action.range.start)),
11410 end: Some(serialize_anchor(&action.range.end)),
11411 lsp_action,
11412 kind,
11413 resolved: action.resolved,
11414 }
11415 }
11416
11417 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11418 let start = action
11419 .start
11420 .and_then(deserialize_anchor)
11421 .context("invalid start")?;
11422 let end = action
11423 .end
11424 .and_then(deserialize_anchor)
11425 .context("invalid end")?;
11426 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11427 Some(proto::code_action::Kind::Action) => {
11428 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11429 }
11430 Some(proto::code_action::Kind::Command) => {
11431 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11432 }
11433 Some(proto::code_action::Kind::CodeLens) => {
11434 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11435 }
11436 None => anyhow::bail!("Unknown action kind {}", action.kind),
11437 };
11438 Ok(CodeAction {
11439 server_id: LanguageServerId(action.server_id as usize),
11440 range: start..end,
11441 resolved: action.resolved,
11442 lsp_action,
11443 })
11444 }
11445
11446 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11447 match &formatting_result {
11448 Ok(_) => self.last_formatting_failure = None,
11449 Err(error) => {
11450 let error_string = format!("{error:#}");
11451 log::error!("Formatting failed: {error_string}");
11452 self.last_formatting_failure
11453 .replace(error_string.lines().join(" "));
11454 }
11455 }
11456 }
11457
11458 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11459 self.lsp_server_capabilities.remove(&for_server);
11460 for buffer_colors in self.lsp_document_colors.values_mut() {
11461 buffer_colors.colors.remove(&for_server);
11462 buffer_colors.cache_version += 1;
11463 }
11464 for buffer_lens in self.lsp_code_lens.values_mut() {
11465 buffer_lens.lens.remove(&for_server);
11466 }
11467 if let Some(local) = self.as_local_mut() {
11468 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11469 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11470 buffer_servers.remove(&for_server);
11471 }
11472 }
11473 }
11474
11475 pub fn result_id(
11476 &self,
11477 server_id: LanguageServerId,
11478 buffer_id: BufferId,
11479 cx: &App,
11480 ) -> Option<String> {
11481 let abs_path = self
11482 .buffer_store
11483 .read(cx)
11484 .get(buffer_id)
11485 .and_then(|b| File::from_dyn(b.read(cx).file()))
11486 .map(|f| f.abs_path(cx))?;
11487 self.as_local()?
11488 .buffer_pull_diagnostics_result_ids
11489 .get(&server_id)?
11490 .get(&abs_path)?
11491 .clone()
11492 }
11493
11494 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11495 let Some(local) = self.as_local() else {
11496 return HashMap::default();
11497 };
11498 local
11499 .buffer_pull_diagnostics_result_ids
11500 .get(&server_id)
11501 .into_iter()
11502 .flatten()
11503 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11504 .collect()
11505 }
11506
11507 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11508 if let Some(LanguageServerState::Running {
11509 workspace_refresh_task: Some(workspace_refresh_task),
11510 ..
11511 }) = self
11512 .as_local_mut()
11513 .and_then(|local| local.language_servers.get_mut(&server_id))
11514 {
11515 workspace_refresh_task.refresh_tx.try_send(()).ok();
11516 }
11517 }
11518
11519 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11520 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11521 return;
11522 };
11523 let Some(local) = self.as_local_mut() else {
11524 return;
11525 };
11526
11527 for server_id in buffer.update(cx, |buffer, cx| {
11528 local.language_server_ids_for_buffer(buffer, cx)
11529 }) {
11530 if let Some(LanguageServerState::Running {
11531 workspace_refresh_task: Some(workspace_refresh_task),
11532 ..
11533 }) = local.language_servers.get_mut(&server_id)
11534 {
11535 workspace_refresh_task.refresh_tx.try_send(()).ok();
11536 }
11537 }
11538 }
11539
11540 fn apply_workspace_diagnostic_report(
11541 &mut self,
11542 server_id: LanguageServerId,
11543 report: lsp::WorkspaceDiagnosticReportResult,
11544 cx: &mut Context<Self>,
11545 ) {
11546 let workspace_diagnostics =
11547 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11548 let mut unchanged_buffers = HashSet::default();
11549 let mut changed_buffers = HashSet::default();
11550 let workspace_diagnostics_updates = workspace_diagnostics
11551 .into_iter()
11552 .filter_map(
11553 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11554 LspPullDiagnostics::Response {
11555 server_id,
11556 uri,
11557 diagnostics,
11558 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11559 LspPullDiagnostics::Default => None,
11560 },
11561 )
11562 .fold(
11563 HashMap::default(),
11564 |mut acc, (server_id, uri, diagnostics, version)| {
11565 let (result_id, diagnostics) = match diagnostics {
11566 PulledDiagnostics::Unchanged { result_id } => {
11567 unchanged_buffers.insert(uri.clone());
11568 (Some(result_id), Vec::new())
11569 }
11570 PulledDiagnostics::Changed {
11571 result_id,
11572 diagnostics,
11573 } => {
11574 changed_buffers.insert(uri.clone());
11575 (result_id, diagnostics)
11576 }
11577 };
11578 let disk_based_sources = Cow::Owned(
11579 self.language_server_adapter_for_id(server_id)
11580 .as_ref()
11581 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11582 .unwrap_or(&[])
11583 .to_vec(),
11584 );
11585 acc.entry(server_id)
11586 .or_insert_with(Vec::new)
11587 .push(DocumentDiagnosticsUpdate {
11588 server_id,
11589 diagnostics: lsp::PublishDiagnosticsParams {
11590 uri,
11591 diagnostics,
11592 version,
11593 },
11594 result_id,
11595 disk_based_sources,
11596 });
11597 acc
11598 },
11599 );
11600
11601 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11602 self.merge_lsp_diagnostics(
11603 DiagnosticSourceKind::Pulled,
11604 diagnostic_updates,
11605 |buffer, old_diagnostic, cx| {
11606 File::from_dyn(buffer.file())
11607 .and_then(|file| {
11608 let abs_path = file.as_local()?.abs_path(cx);
11609 lsp::Url::from_file_path(abs_path).ok()
11610 })
11611 .is_none_or(|buffer_uri| {
11612 unchanged_buffers.contains(&buffer_uri)
11613 || match old_diagnostic.source_kind {
11614 DiagnosticSourceKind::Pulled => {
11615 !changed_buffers.contains(&buffer_uri)
11616 }
11617 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11618 true
11619 }
11620 }
11621 })
11622 },
11623 cx,
11624 )
11625 .log_err();
11626 }
11627 }
11628
11629 fn register_server_capabilities(
11630 &mut self,
11631 server_id: LanguageServerId,
11632 params: lsp::RegistrationParams,
11633 cx: &mut Context<Self>,
11634 ) -> anyhow::Result<()> {
11635 let server = self
11636 .language_server_for_id(server_id)
11637 .with_context(|| format!("no server {server_id} found"))?;
11638 for reg in params.registrations {
11639 match reg.method.as_str() {
11640 "workspace/didChangeWatchedFiles" => {
11641 if let Some(options) = reg.register_options {
11642 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11643 let caps = serde_json::from_value(options)?;
11644 local_lsp_store
11645 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11646 true
11647 } else {
11648 false
11649 };
11650 if notify {
11651 notify_server_capabilities_updated(&server, cx);
11652 }
11653 }
11654 }
11655 "workspace/didChangeConfiguration" => {
11656 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11657 }
11658 "workspace/symbol" => {
11659 if let Some(options) = parse_register_capabilities(reg)? {
11660 server.update_capabilities(|capabilities| {
11661 capabilities.workspace_symbol_provider = Some(options);
11662 });
11663 notify_server_capabilities_updated(&server, cx);
11664 }
11665 }
11666 "workspace/fileOperations" => {
11667 if let Some(options) = reg.register_options {
11668 let caps = serde_json::from_value(options)?;
11669 server.update_capabilities(|capabilities| {
11670 capabilities
11671 .workspace
11672 .get_or_insert_default()
11673 .file_operations = Some(caps);
11674 });
11675 notify_server_capabilities_updated(&server, cx);
11676 }
11677 }
11678 "workspace/executeCommand" => {
11679 if let Some(options) = reg.register_options {
11680 let options = serde_json::from_value(options)?;
11681 server.update_capabilities(|capabilities| {
11682 capabilities.execute_command_provider = Some(options);
11683 });
11684 notify_server_capabilities_updated(&server, cx);
11685 }
11686 }
11687 "textDocument/rangeFormatting" => {
11688 if let Some(options) = parse_register_capabilities(reg)? {
11689 server.update_capabilities(|capabilities| {
11690 capabilities.document_range_formatting_provider = Some(options);
11691 });
11692 notify_server_capabilities_updated(&server, cx);
11693 }
11694 }
11695 "textDocument/onTypeFormatting" => {
11696 if let Some(options) = reg
11697 .register_options
11698 .map(serde_json::from_value)
11699 .transpose()?
11700 {
11701 server.update_capabilities(|capabilities| {
11702 capabilities.document_on_type_formatting_provider = Some(options);
11703 });
11704 notify_server_capabilities_updated(&server, cx);
11705 }
11706 }
11707 "textDocument/formatting" => {
11708 if let Some(options) = parse_register_capabilities(reg)? {
11709 server.update_capabilities(|capabilities| {
11710 capabilities.document_formatting_provider = Some(options);
11711 });
11712 notify_server_capabilities_updated(&server, cx);
11713 }
11714 }
11715 "textDocument/rename" => {
11716 if let Some(options) = parse_register_capabilities(reg)? {
11717 server.update_capabilities(|capabilities| {
11718 capabilities.rename_provider = Some(options);
11719 });
11720 notify_server_capabilities_updated(&server, cx);
11721 }
11722 }
11723 "textDocument/inlayHint" => {
11724 if let Some(options) = parse_register_capabilities(reg)? {
11725 server.update_capabilities(|capabilities| {
11726 capabilities.inlay_hint_provider = Some(options);
11727 });
11728 notify_server_capabilities_updated(&server, cx);
11729 }
11730 }
11731 "textDocument/documentSymbol" => {
11732 if let Some(options) = parse_register_capabilities(reg)? {
11733 server.update_capabilities(|capabilities| {
11734 capabilities.document_symbol_provider = Some(options);
11735 });
11736 notify_server_capabilities_updated(&server, cx);
11737 }
11738 }
11739 "textDocument/codeAction" => {
11740 if let Some(options) = reg
11741 .register_options
11742 .map(serde_json::from_value)
11743 .transpose()?
11744 {
11745 server.update_capabilities(|capabilities| {
11746 capabilities.code_action_provider =
11747 Some(lsp::CodeActionProviderCapability::Options(options));
11748 });
11749 notify_server_capabilities_updated(&server, cx);
11750 }
11751 }
11752 "textDocument/definition" => {
11753 if let Some(options) = parse_register_capabilities(reg)? {
11754 server.update_capabilities(|capabilities| {
11755 capabilities.definition_provider = Some(options);
11756 });
11757 notify_server_capabilities_updated(&server, cx);
11758 }
11759 }
11760 "textDocument/completion" => {
11761 if let Some(caps) = reg
11762 .register_options
11763 .map(serde_json::from_value)
11764 .transpose()?
11765 {
11766 server.update_capabilities(|capabilities| {
11767 capabilities.completion_provider = Some(caps);
11768 });
11769 notify_server_capabilities_updated(&server, cx);
11770 }
11771 }
11772 "textDocument/hover" => {
11773 if let Some(caps) = reg
11774 .register_options
11775 .map(serde_json::from_value)
11776 .transpose()?
11777 {
11778 server.update_capabilities(|capabilities| {
11779 capabilities.hover_provider = Some(caps);
11780 });
11781 notify_server_capabilities_updated(&server, cx);
11782 }
11783 }
11784 "textDocument/signatureHelp" => {
11785 if let Some(caps) = reg
11786 .register_options
11787 .map(serde_json::from_value)
11788 .transpose()?
11789 {
11790 server.update_capabilities(|capabilities| {
11791 capabilities.signature_help_provider = Some(caps);
11792 });
11793 notify_server_capabilities_updated(&server, cx);
11794 }
11795 }
11796 "textDocument/didChange" => {
11797 if let Some(sync_kind) = reg
11798 .register_options
11799 .and_then(|opts| opts.get("syncKind").cloned())
11800 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11801 .transpose()?
11802 {
11803 server.update_capabilities(|capabilities| {
11804 let mut sync_options =
11805 Self::take_text_document_sync_options(capabilities);
11806 sync_options.change = Some(sync_kind);
11807 capabilities.text_document_sync =
11808 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11809 });
11810 notify_server_capabilities_updated(&server, cx);
11811 }
11812 }
11813 "textDocument/didSave" => {
11814 if let Some(include_text) = reg
11815 .register_options
11816 .map(|opts| {
11817 let transpose = opts
11818 .get("includeText")
11819 .cloned()
11820 .map(serde_json::from_value::<Option<bool>>)
11821 .transpose();
11822 match transpose {
11823 Ok(value) => Ok(value.flatten()),
11824 Err(e) => Err(e),
11825 }
11826 })
11827 .transpose()?
11828 {
11829 server.update_capabilities(|capabilities| {
11830 let mut sync_options =
11831 Self::take_text_document_sync_options(capabilities);
11832 sync_options.save =
11833 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11834 include_text,
11835 }));
11836 capabilities.text_document_sync =
11837 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11838 });
11839 notify_server_capabilities_updated(&server, cx);
11840 }
11841 }
11842 "textDocument/codeLens" => {
11843 if let Some(caps) = reg
11844 .register_options
11845 .map(serde_json::from_value)
11846 .transpose()?
11847 {
11848 server.update_capabilities(|capabilities| {
11849 capabilities.code_lens_provider = Some(caps);
11850 });
11851 notify_server_capabilities_updated(&server, cx);
11852 }
11853 }
11854 "textDocument/diagnostic" => {
11855 if let Some(caps) = reg
11856 .register_options
11857 .map(serde_json::from_value)
11858 .transpose()?
11859 {
11860 server.update_capabilities(|capabilities| {
11861 capabilities.diagnostic_provider = Some(caps);
11862 });
11863 notify_server_capabilities_updated(&server, cx);
11864 }
11865 }
11866 "textDocument/colorProvider" => {
11867 if let Some(caps) = reg
11868 .register_options
11869 .map(serde_json::from_value)
11870 .transpose()?
11871 {
11872 server.update_capabilities(|capabilities| {
11873 capabilities.color_provider = Some(caps);
11874 });
11875 notify_server_capabilities_updated(&server, cx);
11876 }
11877 }
11878 _ => log::warn!("unhandled capability registration: {reg:?}"),
11879 }
11880 }
11881
11882 Ok(())
11883 }
11884
11885 fn unregister_server_capabilities(
11886 &mut self,
11887 server_id: LanguageServerId,
11888 params: lsp::UnregistrationParams,
11889 cx: &mut Context<Self>,
11890 ) -> anyhow::Result<()> {
11891 let server = self
11892 .language_server_for_id(server_id)
11893 .with_context(|| format!("no server {server_id} found"))?;
11894 for unreg in params.unregisterations.iter() {
11895 match unreg.method.as_str() {
11896 "workspace/didChangeWatchedFiles" => {
11897 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11898 local_lsp_store
11899 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11900 true
11901 } else {
11902 false
11903 };
11904 if notify {
11905 notify_server_capabilities_updated(&server, cx);
11906 }
11907 }
11908 "workspace/didChangeConfiguration" => {
11909 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11910 }
11911 "workspace/symbol" => {
11912 server.update_capabilities(|capabilities| {
11913 capabilities.workspace_symbol_provider = None
11914 });
11915 notify_server_capabilities_updated(&server, cx);
11916 }
11917 "workspace/fileOperations" => {
11918 server.update_capabilities(|capabilities| {
11919 capabilities
11920 .workspace
11921 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11922 workspace_folders: None,
11923 file_operations: None,
11924 })
11925 .file_operations = None;
11926 });
11927 notify_server_capabilities_updated(&server, cx);
11928 }
11929 "workspace/executeCommand" => {
11930 server.update_capabilities(|capabilities| {
11931 capabilities.execute_command_provider = None;
11932 });
11933 notify_server_capabilities_updated(&server, cx);
11934 }
11935 "textDocument/rangeFormatting" => {
11936 server.update_capabilities(|capabilities| {
11937 capabilities.document_range_formatting_provider = None
11938 });
11939 notify_server_capabilities_updated(&server, cx);
11940 }
11941 "textDocument/onTypeFormatting" => {
11942 server.update_capabilities(|capabilities| {
11943 capabilities.document_on_type_formatting_provider = None;
11944 });
11945 notify_server_capabilities_updated(&server, cx);
11946 }
11947 "textDocument/formatting" => {
11948 server.update_capabilities(|capabilities| {
11949 capabilities.document_formatting_provider = None;
11950 });
11951 notify_server_capabilities_updated(&server, cx);
11952 }
11953 "textDocument/rename" => {
11954 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11955 notify_server_capabilities_updated(&server, cx);
11956 }
11957 "textDocument/codeAction" => {
11958 server.update_capabilities(|capabilities| {
11959 capabilities.code_action_provider = None;
11960 });
11961 notify_server_capabilities_updated(&server, cx);
11962 }
11963 "textDocument/definition" => {
11964 server.update_capabilities(|capabilities| {
11965 capabilities.definition_provider = None;
11966 });
11967 notify_server_capabilities_updated(&server, cx);
11968 }
11969 "textDocument/completion" => {
11970 server.update_capabilities(|capabilities| {
11971 capabilities.completion_provider = None;
11972 });
11973 notify_server_capabilities_updated(&server, cx);
11974 }
11975 "textDocument/hover" => {
11976 server.update_capabilities(|capabilities| {
11977 capabilities.hover_provider = None;
11978 });
11979 notify_server_capabilities_updated(&server, cx);
11980 }
11981 "textDocument/signatureHelp" => {
11982 server.update_capabilities(|capabilities| {
11983 capabilities.signature_help_provider = None;
11984 });
11985 notify_server_capabilities_updated(&server, cx);
11986 }
11987 "textDocument/didChange" => {
11988 server.update_capabilities(|capabilities| {
11989 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11990 sync_options.change = None;
11991 capabilities.text_document_sync =
11992 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11993 });
11994 notify_server_capabilities_updated(&server, cx);
11995 }
11996 "textDocument/didSave" => {
11997 server.update_capabilities(|capabilities| {
11998 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11999 sync_options.save = None;
12000 capabilities.text_document_sync =
12001 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12002 });
12003 notify_server_capabilities_updated(&server, cx);
12004 }
12005 "textDocument/codeLens" => {
12006 server.update_capabilities(|capabilities| {
12007 capabilities.code_lens_provider = None;
12008 });
12009 notify_server_capabilities_updated(&server, cx);
12010 }
12011 "textDocument/diagnostic" => {
12012 server.update_capabilities(|capabilities| {
12013 capabilities.diagnostic_provider = None;
12014 });
12015 notify_server_capabilities_updated(&server, cx);
12016 }
12017 "textDocument/colorProvider" => {
12018 server.update_capabilities(|capabilities| {
12019 capabilities.color_provider = None;
12020 });
12021 notify_server_capabilities_updated(&server, cx);
12022 }
12023 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12024 }
12025 }
12026
12027 Ok(())
12028 }
12029
12030 fn take_text_document_sync_options(
12031 capabilities: &mut lsp::ServerCapabilities,
12032 ) -> lsp::TextDocumentSyncOptions {
12033 match capabilities.text_document_sync.take() {
12034 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12035 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12036 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12037 sync_options.change = Some(sync_kind);
12038 sync_options
12039 }
12040 None => lsp::TextDocumentSyncOptions::default(),
12041 }
12042 }
12043}
12044
12045// Registration with registerOptions as null, should fallback to true.
12046// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12047fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12048 reg: lsp::Registration,
12049) -> anyhow::Result<Option<OneOf<bool, T>>> {
12050 Ok(match reg.register_options {
12051 Some(options) => Some(OneOf::Right(serde_json::from_value::<T>(options)?)),
12052 None => Some(OneOf::Left(true)),
12053 })
12054}
12055
12056fn subscribe_to_binary_statuses(
12057 languages: &Arc<LanguageRegistry>,
12058 cx: &mut Context<'_, LspStore>,
12059) -> Task<()> {
12060 let mut server_statuses = languages.language_server_binary_statuses();
12061 cx.spawn(async move |lsp_store, cx| {
12062 while let Some((server_name, binary_status)) = server_statuses.next().await {
12063 if lsp_store
12064 .update(cx, |_, cx| {
12065 let mut message = None;
12066 let binary_status = match binary_status {
12067 BinaryStatus::None => proto::ServerBinaryStatus::None,
12068 BinaryStatus::CheckingForUpdate => {
12069 proto::ServerBinaryStatus::CheckingForUpdate
12070 }
12071 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12072 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12073 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12074 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12075 BinaryStatus::Failed { error } => {
12076 message = Some(error);
12077 proto::ServerBinaryStatus::Failed
12078 }
12079 };
12080 cx.emit(LspStoreEvent::LanguageServerUpdate {
12081 // Binary updates are about the binary that might not have any language server id at that point.
12082 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12083 language_server_id: LanguageServerId(0),
12084 name: Some(server_name),
12085 message: proto::update_language_server::Variant::StatusUpdate(
12086 proto::StatusUpdate {
12087 message,
12088 status: Some(proto::status_update::Status::Binary(
12089 binary_status as i32,
12090 )),
12091 },
12092 ),
12093 });
12094 })
12095 .is_err()
12096 {
12097 break;
12098 }
12099 }
12100 })
12101}
12102
12103fn lsp_workspace_diagnostics_refresh(
12104 server: Arc<LanguageServer>,
12105 cx: &mut Context<'_, LspStore>,
12106) -> Option<WorkspaceRefreshTask> {
12107 let identifier = match server.capabilities().diagnostic_provider? {
12108 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12109 if !diagnostic_options.workspace_diagnostics {
12110 return None;
12111 }
12112 diagnostic_options.identifier
12113 }
12114 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12115 let diagnostic_options = registration_options.diagnostic_options;
12116 if !diagnostic_options.workspace_diagnostics {
12117 return None;
12118 }
12119 diagnostic_options.identifier
12120 }
12121 };
12122
12123 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12124 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12125 refresh_tx.try_send(()).ok();
12126
12127 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12128 let mut attempts = 0;
12129 let max_attempts = 50;
12130 let mut requests = 0;
12131
12132 loop {
12133 let Some(()) = refresh_rx.recv().await else {
12134 return;
12135 };
12136
12137 'request: loop {
12138 requests += 1;
12139 if attempts > max_attempts {
12140 log::error!(
12141 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12142 );
12143 return;
12144 }
12145 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12146 cx.background_executor()
12147 .timer(Duration::from_millis(backoff_millis))
12148 .await;
12149 attempts += 1;
12150
12151 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12152 lsp_store
12153 .all_result_ids(server.server_id())
12154 .into_iter()
12155 .filter_map(|(abs_path, result_id)| {
12156 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12157 Some(lsp::PreviousResultId {
12158 uri,
12159 value: result_id,
12160 })
12161 })
12162 .collect()
12163 }) else {
12164 return;
12165 };
12166
12167 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12168
12169 progress_rx.try_recv().ok();
12170 let timer =
12171 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12172 let progress = pin!(progress_rx.recv().fuse());
12173 let response_result = server
12174 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12175 lsp::WorkspaceDiagnosticParams {
12176 previous_result_ids,
12177 identifier: identifier.clone(),
12178 work_done_progress_params: Default::default(),
12179 partial_result_params: lsp::PartialResultParams {
12180 partial_result_token: Some(lsp::ProgressToken::String(token)),
12181 },
12182 },
12183 select(timer, progress).then(|either| match either {
12184 Either::Left((message, ..)) => ready(message).left_future(),
12185 Either::Right(..) => pending::<String>().right_future(),
12186 }),
12187 )
12188 .await;
12189
12190 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12191 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12192 match response_result {
12193 ConnectionResult::Timeout => {
12194 log::error!("Timeout during workspace diagnostics pull");
12195 continue 'request;
12196 }
12197 ConnectionResult::ConnectionReset => {
12198 log::error!("Server closed a workspace diagnostics pull request");
12199 continue 'request;
12200 }
12201 ConnectionResult::Result(Err(e)) => {
12202 log::error!("Error during workspace diagnostics pull: {e:#}");
12203 break 'request;
12204 }
12205 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12206 attempts = 0;
12207 if lsp_store
12208 .update(cx, |lsp_store, cx| {
12209 lsp_store.apply_workspace_diagnostic_report(
12210 server.server_id(),
12211 pulled_diagnostics,
12212 cx,
12213 )
12214 })
12215 .is_err()
12216 {
12217 return;
12218 }
12219 break 'request;
12220 }
12221 }
12222 }
12223 }
12224 });
12225
12226 Some(WorkspaceRefreshTask {
12227 refresh_tx,
12228 progress_tx,
12229 task: workspace_query_language_server,
12230 })
12231}
12232
12233fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12234 let CompletionSource::BufferWord {
12235 word_range,
12236 resolved,
12237 } = &mut completion.source
12238 else {
12239 return;
12240 };
12241 if *resolved {
12242 return;
12243 }
12244
12245 if completion.new_text
12246 != snapshot
12247 .text_for_range(word_range.clone())
12248 .collect::<String>()
12249 {
12250 return;
12251 }
12252
12253 let mut offset = 0;
12254 for chunk in snapshot.chunks(word_range.clone(), true) {
12255 let end_offset = offset + chunk.text.len();
12256 if let Some(highlight_id) = chunk.syntax_highlight_id {
12257 completion
12258 .label
12259 .runs
12260 .push((offset..end_offset, highlight_id));
12261 }
12262 offset = end_offset;
12263 }
12264 *resolved = true;
12265}
12266
12267impl EventEmitter<LspStoreEvent> for LspStore {}
12268
12269fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12270 hover
12271 .contents
12272 .retain(|hover_block| !hover_block.text.trim().is_empty());
12273 if hover.contents.is_empty() {
12274 None
12275 } else {
12276 Some(hover)
12277 }
12278}
12279
12280async fn populate_labels_for_completions(
12281 new_completions: Vec<CoreCompletion>,
12282 language: Option<Arc<Language>>,
12283 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12284) -> Vec<Completion> {
12285 let lsp_completions = new_completions
12286 .iter()
12287 .filter_map(|new_completion| {
12288 if let Some(lsp_completion) = new_completion.source.lsp_completion(true) {
12289 Some(lsp_completion.into_owned())
12290 } else {
12291 None
12292 }
12293 })
12294 .collect::<Vec<_>>();
12295
12296 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12297 lsp_adapter
12298 .labels_for_completions(&lsp_completions, language)
12299 .await
12300 .log_err()
12301 .unwrap_or_default()
12302 } else {
12303 Vec::new()
12304 }
12305 .into_iter()
12306 .fuse();
12307
12308 let mut completions = Vec::new();
12309 for completion in new_completions {
12310 match completion.source.lsp_completion(true) {
12311 Some(lsp_completion) => {
12312 let documentation = if let Some(docs) = lsp_completion.documentation.clone() {
12313 Some(docs.into())
12314 } else {
12315 None
12316 };
12317
12318 let mut label = labels.next().flatten().unwrap_or_else(|| {
12319 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12320 });
12321 ensure_uniform_list_compatible_label(&mut label);
12322 completions.push(Completion {
12323 label,
12324 documentation,
12325 replace_range: completion.replace_range,
12326 new_text: completion.new_text,
12327 insert_text_mode: lsp_completion.insert_text_mode,
12328 source: completion.source,
12329 icon_path: None,
12330 confirm: None,
12331 });
12332 }
12333 None => {
12334 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12335 ensure_uniform_list_compatible_label(&mut label);
12336 completions.push(Completion {
12337 label,
12338 documentation: None,
12339 replace_range: completion.replace_range,
12340 new_text: completion.new_text,
12341 source: completion.source,
12342 insert_text_mode: None,
12343 icon_path: None,
12344 confirm: None,
12345 });
12346 }
12347 }
12348 }
12349 completions
12350}
12351
12352#[derive(Debug)]
12353pub enum LanguageServerToQuery {
12354 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12355 FirstCapable,
12356 /// Query a specific language server.
12357 Other(LanguageServerId),
12358}
12359
12360#[derive(Default)]
12361struct RenamePathsWatchedForServer {
12362 did_rename: Vec<RenameActionPredicate>,
12363 will_rename: Vec<RenameActionPredicate>,
12364}
12365
12366impl RenamePathsWatchedForServer {
12367 fn with_did_rename_patterns(
12368 mut self,
12369 did_rename: Option<&FileOperationRegistrationOptions>,
12370 ) -> Self {
12371 if let Some(did_rename) = did_rename {
12372 self.did_rename = did_rename
12373 .filters
12374 .iter()
12375 .filter_map(|filter| filter.try_into().log_err())
12376 .collect();
12377 }
12378 self
12379 }
12380 fn with_will_rename_patterns(
12381 mut self,
12382 will_rename: Option<&FileOperationRegistrationOptions>,
12383 ) -> Self {
12384 if let Some(will_rename) = will_rename {
12385 self.will_rename = will_rename
12386 .filters
12387 .iter()
12388 .filter_map(|filter| filter.try_into().log_err())
12389 .collect();
12390 }
12391 self
12392 }
12393
12394 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12395 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12396 }
12397 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12398 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12399 }
12400}
12401
12402impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12403 type Error = globset::Error;
12404 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12405 Ok(Self {
12406 kind: ops.pattern.matches.clone(),
12407 glob: GlobBuilder::new(&ops.pattern.glob)
12408 .case_insensitive(
12409 ops.pattern
12410 .options
12411 .as_ref()
12412 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12413 )
12414 .build()?
12415 .compile_matcher(),
12416 })
12417 }
12418}
12419struct RenameActionPredicate {
12420 glob: GlobMatcher,
12421 kind: Option<FileOperationPatternKind>,
12422}
12423
12424impl RenameActionPredicate {
12425 // Returns true if language server should be notified
12426 fn eval(&self, path: &str, is_dir: bool) -> bool {
12427 self.kind.as_ref().is_none_or(|kind| {
12428 let expected_kind = if is_dir {
12429 FileOperationPatternKind::Folder
12430 } else {
12431 FileOperationPatternKind::File
12432 };
12433 kind == &expected_kind
12434 }) && self.glob.is_match(path)
12435 }
12436}
12437
12438#[derive(Default)]
12439struct LanguageServerWatchedPaths {
12440 worktree_paths: HashMap<WorktreeId, GlobSet>,
12441 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12442}
12443
12444#[derive(Default)]
12445struct LanguageServerWatchedPathsBuilder {
12446 worktree_paths: HashMap<WorktreeId, GlobSet>,
12447 abs_paths: HashMap<Arc<Path>, GlobSet>,
12448}
12449
12450impl LanguageServerWatchedPathsBuilder {
12451 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12452 self.worktree_paths.insert(worktree_id, glob_set);
12453 }
12454 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12455 self.abs_paths.insert(path, glob_set);
12456 }
12457 fn build(
12458 self,
12459 fs: Arc<dyn Fs>,
12460 language_server_id: LanguageServerId,
12461 cx: &mut Context<LspStore>,
12462 ) -> LanguageServerWatchedPaths {
12463 let project = cx.weak_entity();
12464
12465 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12466 let abs_paths = self
12467 .abs_paths
12468 .into_iter()
12469 .map(|(abs_path, globset)| {
12470 let task = cx.spawn({
12471 let abs_path = abs_path.clone();
12472 let fs = fs.clone();
12473
12474 let lsp_store = project.clone();
12475 async move |_, cx| {
12476 maybe!(async move {
12477 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12478 while let Some(update) = push_updates.0.next().await {
12479 let action = lsp_store
12480 .update(cx, |this, _| {
12481 let Some(local) = this.as_local() else {
12482 return ControlFlow::Break(());
12483 };
12484 let Some(watcher) = local
12485 .language_server_watched_paths
12486 .get(&language_server_id)
12487 else {
12488 return ControlFlow::Break(());
12489 };
12490 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12491 "Watched abs path is not registered with a watcher",
12492 );
12493 let matching_entries = update
12494 .into_iter()
12495 .filter(|event| globs.is_match(&event.path))
12496 .collect::<Vec<_>>();
12497 this.lsp_notify_abs_paths_changed(
12498 language_server_id,
12499 matching_entries,
12500 );
12501 ControlFlow::Continue(())
12502 })
12503 .ok()?;
12504
12505 if action.is_break() {
12506 break;
12507 }
12508 }
12509 Some(())
12510 })
12511 .await;
12512 }
12513 });
12514 (abs_path, (globset, task))
12515 })
12516 .collect();
12517 LanguageServerWatchedPaths {
12518 worktree_paths: self.worktree_paths,
12519 abs_paths,
12520 }
12521 }
12522}
12523
12524struct LspBufferSnapshot {
12525 version: i32,
12526 snapshot: TextBufferSnapshot,
12527}
12528
12529/// A prompt requested by LSP server.
12530#[derive(Clone, Debug)]
12531pub struct LanguageServerPromptRequest {
12532 pub level: PromptLevel,
12533 pub message: String,
12534 pub actions: Vec<MessageActionItem>,
12535 pub lsp_name: String,
12536 pub(crate) response_channel: Sender<MessageActionItem>,
12537}
12538
12539impl LanguageServerPromptRequest {
12540 pub async fn respond(self, index: usize) -> Option<()> {
12541 if let Some(response) = self.actions.into_iter().nth(index) {
12542 self.response_channel.send(response).await.ok()
12543 } else {
12544 None
12545 }
12546 }
12547}
12548impl PartialEq for LanguageServerPromptRequest {
12549 fn eq(&self, other: &Self) -> bool {
12550 self.message == other.message && self.actions == other.actions
12551 }
12552}
12553
12554#[derive(Clone, Debug, PartialEq)]
12555pub enum LanguageServerLogType {
12556 Log(MessageType),
12557 Trace(Option<String>),
12558}
12559
12560impl LanguageServerLogType {
12561 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12562 match self {
12563 Self::Log(log_type) => {
12564 let message_type = match *log_type {
12565 MessageType::ERROR => 1,
12566 MessageType::WARNING => 2,
12567 MessageType::INFO => 3,
12568 MessageType::LOG => 4,
12569 other => {
12570 log::warn!("Unknown lsp log message type: {:?}", other);
12571 4
12572 }
12573 };
12574 proto::language_server_log::LogType::LogMessageType(message_type)
12575 }
12576 Self::Trace(message) => {
12577 proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
12578 message: message.clone(),
12579 })
12580 }
12581 }
12582 }
12583
12584 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12585 match log_type {
12586 proto::language_server_log::LogType::LogMessageType(message_type) => {
12587 Self::Log(match message_type {
12588 1 => MessageType::ERROR,
12589 2 => MessageType::WARNING,
12590 3 => MessageType::INFO,
12591 4 => MessageType::LOG,
12592 _ => MessageType::LOG,
12593 })
12594 }
12595 proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
12596 }
12597 }
12598}
12599
12600pub struct WorkspaceRefreshTask {
12601 refresh_tx: mpsc::Sender<()>,
12602 progress_tx: mpsc::Sender<()>,
12603 #[allow(dead_code)]
12604 task: Task<()>,
12605}
12606
12607pub enum LanguageServerState {
12608 Starting {
12609 startup: Task<Option<Arc<LanguageServer>>>,
12610 /// List of language servers that will be added to the workspace once it's initialization completes.
12611 pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
12612 },
12613
12614 Running {
12615 adapter: Arc<CachedLspAdapter>,
12616 server: Arc<LanguageServer>,
12617 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12618 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12619 },
12620}
12621
12622impl LanguageServerState {
12623 fn add_workspace_folder(&self, uri: Url) {
12624 match self {
12625 LanguageServerState::Starting {
12626 pending_workspace_folders,
12627 ..
12628 } => {
12629 pending_workspace_folders.lock().insert(uri);
12630 }
12631 LanguageServerState::Running { server, .. } => {
12632 server.add_workspace_folder(uri);
12633 }
12634 }
12635 }
12636 fn _remove_workspace_folder(&self, uri: Url) {
12637 match self {
12638 LanguageServerState::Starting {
12639 pending_workspace_folders,
12640 ..
12641 } => {
12642 pending_workspace_folders.lock().remove(&uri);
12643 }
12644 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12645 }
12646 }
12647}
12648
12649impl std::fmt::Debug for LanguageServerState {
12650 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12651 match self {
12652 LanguageServerState::Starting { .. } => {
12653 f.debug_struct("LanguageServerState::Starting").finish()
12654 }
12655 LanguageServerState::Running { .. } => {
12656 f.debug_struct("LanguageServerState::Running").finish()
12657 }
12658 }
12659 }
12660}
12661
12662#[derive(Clone, Debug, Serialize)]
12663pub struct LanguageServerProgress {
12664 pub is_disk_based_diagnostics_progress: bool,
12665 pub is_cancellable: bool,
12666 pub title: Option<String>,
12667 pub message: Option<String>,
12668 pub percentage: Option<usize>,
12669 #[serde(skip_serializing)]
12670 pub last_update_at: Instant,
12671}
12672
12673#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12674pub struct DiagnosticSummary {
12675 pub error_count: usize,
12676 pub warning_count: usize,
12677}
12678
12679impl DiagnosticSummary {
12680 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12681 let mut this = Self {
12682 error_count: 0,
12683 warning_count: 0,
12684 };
12685
12686 for entry in diagnostics {
12687 if entry.diagnostic.is_primary {
12688 match entry.diagnostic.severity {
12689 DiagnosticSeverity::ERROR => this.error_count += 1,
12690 DiagnosticSeverity::WARNING => this.warning_count += 1,
12691 _ => {}
12692 }
12693 }
12694 }
12695
12696 this
12697 }
12698
12699 pub fn is_empty(&self) -> bool {
12700 self.error_count == 0 && self.warning_count == 0
12701 }
12702
12703 pub fn to_proto(
12704 &self,
12705 language_server_id: LanguageServerId,
12706 path: &Path,
12707 ) -> proto::DiagnosticSummary {
12708 proto::DiagnosticSummary {
12709 path: path.to_proto(),
12710 language_server_id: language_server_id.0 as u64,
12711 error_count: self.error_count as u32,
12712 warning_count: self.warning_count as u32,
12713 }
12714 }
12715}
12716
12717#[derive(Clone, Debug)]
12718pub enum CompletionDocumentation {
12719 /// There is no documentation for this completion.
12720 Undocumented,
12721 /// A single line of documentation.
12722 SingleLine(SharedString),
12723 /// Multiple lines of plain text documentation.
12724 MultiLinePlainText(SharedString),
12725 /// Markdown documentation.
12726 MultiLineMarkdown(SharedString),
12727 /// Both single line and multiple lines of plain text documentation.
12728 SingleLineAndMultiLinePlainText {
12729 single_line: SharedString,
12730 plain_text: Option<SharedString>,
12731 },
12732}
12733
12734impl From<lsp::Documentation> for CompletionDocumentation {
12735 fn from(docs: lsp::Documentation) -> Self {
12736 match docs {
12737 lsp::Documentation::String(text) => {
12738 if text.lines().count() <= 1 {
12739 CompletionDocumentation::SingleLine(text.into())
12740 } else {
12741 CompletionDocumentation::MultiLinePlainText(text.into())
12742 }
12743 }
12744
12745 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12746 lsp::MarkupKind::PlainText => {
12747 if value.lines().count() <= 1 {
12748 CompletionDocumentation::SingleLine(value.into())
12749 } else {
12750 CompletionDocumentation::MultiLinePlainText(value.into())
12751 }
12752 }
12753
12754 lsp::MarkupKind::Markdown => {
12755 CompletionDocumentation::MultiLineMarkdown(value.into())
12756 }
12757 },
12758 }
12759 }
12760}
12761
12762fn glob_literal_prefix(glob: &Path) -> PathBuf {
12763 glob.components()
12764 .take_while(|component| match component {
12765 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12766 _ => true,
12767 })
12768 .collect()
12769}
12770
12771pub struct SshLspAdapter {
12772 name: LanguageServerName,
12773 binary: LanguageServerBinary,
12774 initialization_options: Option<String>,
12775 code_action_kinds: Option<Vec<CodeActionKind>>,
12776}
12777
12778impl SshLspAdapter {
12779 pub fn new(
12780 name: LanguageServerName,
12781 binary: LanguageServerBinary,
12782 initialization_options: Option<String>,
12783 code_action_kinds: Option<String>,
12784 ) -> Self {
12785 Self {
12786 name,
12787 binary,
12788 initialization_options,
12789 code_action_kinds: code_action_kinds
12790 .as_ref()
12791 .and_then(|c| serde_json::from_str(c).ok()),
12792 }
12793 }
12794}
12795
12796#[async_trait(?Send)]
12797impl LspAdapter for SshLspAdapter {
12798 fn name(&self) -> LanguageServerName {
12799 self.name.clone()
12800 }
12801
12802 async fn initialization_options(
12803 self: Arc<Self>,
12804 _: &dyn Fs,
12805 _: &Arc<dyn LspAdapterDelegate>,
12806 ) -> Result<Option<serde_json::Value>> {
12807 let Some(options) = &self.initialization_options else {
12808 return Ok(None);
12809 };
12810 let result = serde_json::from_str(options)?;
12811 Ok(result)
12812 }
12813
12814 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12815 self.code_action_kinds.clone()
12816 }
12817
12818 async fn check_if_user_installed(
12819 &self,
12820 _: &dyn LspAdapterDelegate,
12821 _: Option<Toolchain>,
12822 _: &AsyncApp,
12823 ) -> Option<LanguageServerBinary> {
12824 Some(self.binary.clone())
12825 }
12826
12827 async fn cached_server_binary(
12828 &self,
12829 _: PathBuf,
12830 _: &dyn LspAdapterDelegate,
12831 ) -> Option<LanguageServerBinary> {
12832 None
12833 }
12834
12835 async fn fetch_latest_server_version(
12836 &self,
12837 _: &dyn LspAdapterDelegate,
12838 ) -> Result<Box<dyn 'static + Send + Any>> {
12839 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12840 }
12841
12842 async fn fetch_server_binary(
12843 &self,
12844 _: Box<dyn 'static + Send + Any>,
12845 _: PathBuf,
12846 _: &dyn LspAdapterDelegate,
12847 ) -> Result<LanguageServerBinary> {
12848 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12849 }
12850}
12851
12852pub fn language_server_settings<'a>(
12853 delegate: &'a dyn LspAdapterDelegate,
12854 language: &LanguageServerName,
12855 cx: &'a App,
12856) -> Option<&'a LspSettings> {
12857 language_server_settings_for(
12858 SettingsLocation {
12859 worktree_id: delegate.worktree_id(),
12860 path: delegate.worktree_root_path(),
12861 },
12862 language,
12863 cx,
12864 )
12865}
12866
12867pub(crate) fn language_server_settings_for<'a>(
12868 location: SettingsLocation<'a>,
12869 language: &LanguageServerName,
12870 cx: &'a App,
12871) -> Option<&'a LspSettings> {
12872 ProjectSettings::get(Some(location), cx).lsp.get(language)
12873}
12874
12875pub struct LocalLspAdapterDelegate {
12876 lsp_store: WeakEntity<LspStore>,
12877 worktree: worktree::Snapshot,
12878 fs: Arc<dyn Fs>,
12879 http_client: Arc<dyn HttpClient>,
12880 language_registry: Arc<LanguageRegistry>,
12881 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
12882}
12883
12884impl LocalLspAdapterDelegate {
12885 pub fn new(
12886 language_registry: Arc<LanguageRegistry>,
12887 environment: &Entity<ProjectEnvironment>,
12888 lsp_store: WeakEntity<LspStore>,
12889 worktree: &Entity<Worktree>,
12890 http_client: Arc<dyn HttpClient>,
12891 fs: Arc<dyn Fs>,
12892 cx: &mut App,
12893 ) -> Arc<Self> {
12894 let load_shell_env_task = environment.update(cx, |env, cx| {
12895 env.get_worktree_environment(worktree.clone(), cx)
12896 });
12897
12898 Arc::new(Self {
12899 lsp_store,
12900 worktree: worktree.read(cx).snapshot(),
12901 fs,
12902 http_client,
12903 language_registry,
12904 load_shell_env_task,
12905 })
12906 }
12907
12908 fn from_local_lsp(
12909 local: &LocalLspStore,
12910 worktree: &Entity<Worktree>,
12911 cx: &mut App,
12912 ) -> Arc<Self> {
12913 Self::new(
12914 local.languages.clone(),
12915 &local.environment,
12916 local.weak.clone(),
12917 worktree,
12918 local.http_client.clone(),
12919 local.fs.clone(),
12920 cx,
12921 )
12922 }
12923}
12924
12925#[async_trait]
12926impl LspAdapterDelegate for LocalLspAdapterDelegate {
12927 fn show_notification(&self, message: &str, cx: &mut App) {
12928 self.lsp_store
12929 .update(cx, |_, cx| {
12930 cx.emit(LspStoreEvent::Notification(message.to_owned()))
12931 })
12932 .ok();
12933 }
12934
12935 fn http_client(&self) -> Arc<dyn HttpClient> {
12936 self.http_client.clone()
12937 }
12938
12939 fn worktree_id(&self) -> WorktreeId {
12940 self.worktree.id()
12941 }
12942
12943 fn worktree_root_path(&self) -> &Path {
12944 self.worktree.abs_path().as_ref()
12945 }
12946
12947 async fn shell_env(&self) -> HashMap<String, String> {
12948 let task = self.load_shell_env_task.clone();
12949 task.await.unwrap_or_default()
12950 }
12951
12952 async fn npm_package_installed_version(
12953 &self,
12954 package_name: &str,
12955 ) -> Result<Option<(PathBuf, String)>> {
12956 let local_package_directory = self.worktree_root_path();
12957 let node_modules_directory = local_package_directory.join("node_modules");
12958
12959 if let Some(version) =
12960 read_package_installed_version(node_modules_directory.clone(), package_name).await?
12961 {
12962 return Ok(Some((node_modules_directory, version)));
12963 }
12964 let Some(npm) = self.which("npm".as_ref()).await else {
12965 log::warn!(
12966 "Failed to find npm executable for {:?}",
12967 local_package_directory
12968 );
12969 return Ok(None);
12970 };
12971
12972 let env = self.shell_env().await;
12973 let output = util::command::new_smol_command(&npm)
12974 .args(["root", "-g"])
12975 .envs(env)
12976 .current_dir(local_package_directory)
12977 .output()
12978 .await?;
12979 let global_node_modules =
12980 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
12981
12982 if let Some(version) =
12983 read_package_installed_version(global_node_modules.clone(), package_name).await?
12984 {
12985 return Ok(Some((global_node_modules, version)));
12986 }
12987 return Ok(None);
12988 }
12989
12990 #[cfg(not(target_os = "windows"))]
12991 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12992 let worktree_abs_path = self.worktree.abs_path();
12993 let shell_path = self.shell_env().await.get("PATH").cloned();
12994 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
12995 }
12996
12997 #[cfg(target_os = "windows")]
12998 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12999 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
13000 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
13001 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
13002 which::which(command).ok()
13003 }
13004
13005 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13006 let working_dir = self.worktree_root_path();
13007 let output = util::command::new_smol_command(&command.path)
13008 .args(command.arguments)
13009 .envs(command.env.clone().unwrap_or_default())
13010 .current_dir(working_dir)
13011 .output()
13012 .await?;
13013
13014 anyhow::ensure!(
13015 output.status.success(),
13016 "{}, stdout: {:?}, stderr: {:?}",
13017 output.status,
13018 String::from_utf8_lossy(&output.stdout),
13019 String::from_utf8_lossy(&output.stderr)
13020 );
13021 Ok(())
13022 }
13023
13024 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13025 self.language_registry
13026 .update_lsp_binary_status(server_name, status);
13027 }
13028
13029 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13030 self.language_registry
13031 .all_lsp_adapters()
13032 .into_iter()
13033 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13034 .collect()
13035 }
13036
13037 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13038 let dir = self.language_registry.language_server_download_dir(name)?;
13039
13040 if !dir.exists() {
13041 smol::fs::create_dir_all(&dir)
13042 .await
13043 .context("failed to create container directory")
13044 .log_err()?;
13045 }
13046
13047 Some(dir)
13048 }
13049
13050 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
13051 let entry = self
13052 .worktree
13053 .entry_for_path(&path)
13054 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13055 let abs_path = self
13056 .worktree
13057 .absolutize(&entry.path)
13058 .with_context(|| format!("cannot absolutize path {path:?}"))?;
13059
13060 self.fs.load(&abs_path).await
13061 }
13062}
13063
13064async fn populate_labels_for_symbols(
13065 symbols: Vec<CoreSymbol>,
13066 language_registry: &Arc<LanguageRegistry>,
13067 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13068 output: &mut Vec<Symbol>,
13069) {
13070 #[allow(clippy::mutable_key_type)]
13071 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13072
13073 let mut unknown_paths = BTreeSet::new();
13074 for symbol in symbols {
13075 let language = language_registry
13076 .language_for_file_path(&symbol.path.path)
13077 .await
13078 .ok()
13079 .or_else(|| {
13080 unknown_paths.insert(symbol.path.path.clone());
13081 None
13082 });
13083 symbols_by_language
13084 .entry(language)
13085 .or_default()
13086 .push(symbol);
13087 }
13088
13089 for unknown_path in unknown_paths {
13090 log::info!(
13091 "no language found for symbol path {}",
13092 unknown_path.display()
13093 );
13094 }
13095
13096 let mut label_params = Vec::new();
13097 for (language, mut symbols) in symbols_by_language {
13098 label_params.clear();
13099 label_params.extend(
13100 symbols
13101 .iter_mut()
13102 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13103 );
13104
13105 let mut labels = Vec::new();
13106 if let Some(language) = language {
13107 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13108 language_registry
13109 .lsp_adapters(&language.name())
13110 .first()
13111 .cloned()
13112 });
13113 if let Some(lsp_adapter) = lsp_adapter {
13114 labels = lsp_adapter
13115 .labels_for_symbols(&label_params, &language)
13116 .await
13117 .log_err()
13118 .unwrap_or_default();
13119 }
13120 }
13121
13122 for ((symbol, (name, _)), label) in symbols
13123 .into_iter()
13124 .zip(label_params.drain(..))
13125 .zip(labels.into_iter().chain(iter::repeat(None)))
13126 {
13127 output.push(Symbol {
13128 language_server_name: symbol.language_server_name,
13129 source_worktree_id: symbol.source_worktree_id,
13130 source_language_server_id: symbol.source_language_server_id,
13131 path: symbol.path,
13132 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13133 name,
13134 kind: symbol.kind,
13135 range: symbol.range,
13136 signature: symbol.signature,
13137 });
13138 }
13139 }
13140}
13141
13142fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13143 match server.capabilities().text_document_sync.as_ref()? {
13144 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13145 // Server wants didSave but didn't specify includeText.
13146 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13147 // Server doesn't want didSave at all.
13148 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13149 // Server provided SaveOptions.
13150 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13151 Some(save_options.include_text.unwrap_or(false))
13152 }
13153 },
13154 // We do not have any save info. Kind affects didChange only.
13155 lsp::TextDocumentSyncCapability::Kind(_) => None,
13156 }
13157}
13158
13159/// Completion items are displayed in a `UniformList`.
13160/// Usually, those items are single-line strings, but in LSP responses,
13161/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13162/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13163/// 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,
13164/// breaking the completions menu presentation.
13165///
13166/// 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.
13167fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13168 let mut new_text = String::with_capacity(label.text.len());
13169 let mut offset_map = vec![0; label.text.len() + 1];
13170 let mut last_char_was_space = false;
13171 let mut new_idx = 0;
13172 let mut chars = label.text.char_indices().fuse();
13173 let mut newlines_removed = false;
13174
13175 while let Some((idx, c)) = chars.next() {
13176 offset_map[idx] = new_idx;
13177
13178 match c {
13179 '\n' if last_char_was_space => {
13180 newlines_removed = true;
13181 }
13182 '\t' | ' ' if last_char_was_space => {}
13183 '\n' if !last_char_was_space => {
13184 new_text.push(' ');
13185 new_idx += 1;
13186 last_char_was_space = true;
13187 newlines_removed = true;
13188 }
13189 ' ' | '\t' => {
13190 new_text.push(' ');
13191 new_idx += 1;
13192 last_char_was_space = true;
13193 }
13194 _ => {
13195 new_text.push(c);
13196 new_idx += c.len_utf8();
13197 last_char_was_space = false;
13198 }
13199 }
13200 }
13201 offset_map[label.text.len()] = new_idx;
13202
13203 // Only modify the label if newlines were removed.
13204 if !newlines_removed {
13205 return;
13206 }
13207
13208 let last_index = new_idx;
13209 let mut run_ranges_errors = Vec::new();
13210 label.runs.retain_mut(|(range, _)| {
13211 match offset_map.get(range.start) {
13212 Some(&start) => range.start = start,
13213 None => {
13214 run_ranges_errors.push(range.clone());
13215 return false;
13216 }
13217 }
13218
13219 match offset_map.get(range.end) {
13220 Some(&end) => range.end = end,
13221 None => {
13222 run_ranges_errors.push(range.clone());
13223 range.end = last_index;
13224 }
13225 }
13226 true
13227 });
13228 if !run_ranges_errors.is_empty() {
13229 log::error!(
13230 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13231 label.text
13232 );
13233 }
13234
13235 let mut wrong_filter_range = None;
13236 if label.filter_range == (0..label.text.len()) {
13237 label.filter_range = 0..new_text.len();
13238 } else {
13239 let mut original_filter_range = Some(label.filter_range.clone());
13240 match offset_map.get(label.filter_range.start) {
13241 Some(&start) => label.filter_range.start = start,
13242 None => {
13243 wrong_filter_range = original_filter_range.take();
13244 label.filter_range.start = last_index;
13245 }
13246 }
13247
13248 match offset_map.get(label.filter_range.end) {
13249 Some(&end) => label.filter_range.end = end,
13250 None => {
13251 wrong_filter_range = original_filter_range.take();
13252 label.filter_range.end = last_index;
13253 }
13254 }
13255 }
13256 if let Some(wrong_filter_range) = wrong_filter_range {
13257 log::error!(
13258 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13259 label.text
13260 );
13261 }
13262
13263 label.text = new_text;
13264}
13265
13266#[cfg(test)]
13267mod tests {
13268 use language::HighlightId;
13269
13270 use super::*;
13271
13272 #[test]
13273 fn test_glob_literal_prefix() {
13274 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13275 assert_eq!(
13276 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13277 Path::new("node_modules")
13278 );
13279 assert_eq!(
13280 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13281 Path::new("foo")
13282 );
13283 assert_eq!(
13284 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13285 Path::new("foo/bar/baz.js")
13286 );
13287
13288 #[cfg(target_os = "windows")]
13289 {
13290 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13291 assert_eq!(
13292 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13293 Path::new("node_modules")
13294 );
13295 assert_eq!(
13296 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13297 Path::new("foo")
13298 );
13299 assert_eq!(
13300 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13301 Path::new("foo/bar/baz.js")
13302 );
13303 }
13304 }
13305
13306 #[test]
13307 fn test_multi_len_chars_normalization() {
13308 let mut label = CodeLabel {
13309 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13310 runs: vec![(0..6, HighlightId(1))],
13311 filter_range: 0..6,
13312 };
13313 ensure_uniform_list_compatible_label(&mut label);
13314 assert_eq!(
13315 label,
13316 CodeLabel {
13317 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13318 runs: vec![(0..6, HighlightId(1))],
13319 filter_range: 0..6,
13320 }
13321 );
13322 }
13323}