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 log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticServerCapabilities,
79 DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit,
80 FileOperationFilter, FileOperationPatternKind, FileOperationRegistrationOptions, FileRename,
81 FileSystemWatcher, LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary,
82 LanguageServerBinaryOptions, LanguageServerId, LanguageServerName, LanguageServerSelector,
83 LspRequestFuture, MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
84 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
85 WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum FormatTrigger {
144 Save,
145 Manual,
146}
147
148pub enum LspFormatTarget {
149 Buffers,
150 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
151}
152
153pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
154
155impl FormatTrigger {
156 fn from_proto(value: i32) -> FormatTrigger {
157 match value {
158 0 => FormatTrigger::Save,
159 1 => FormatTrigger::Manual,
160 _ => FormatTrigger::Save,
161 }
162 }
163}
164
165#[derive(Clone)]
166struct UnifiedLanguageServer {
167 id: LanguageServerId,
168 project_roots: HashSet<Arc<RelPath>>,
169}
170
171#[derive(Clone, Hash, PartialEq, Eq)]
172struct LanguageServerSeed {
173 worktree_id: WorktreeId,
174 name: LanguageServerName,
175 toolchain: Option<Toolchain>,
176 settings: Arc<LspSettings>,
177}
178
179#[derive(Debug)]
180pub struct DocumentDiagnosticsUpdate<'a, D> {
181 pub diagnostics: D,
182 pub result_id: Option<String>,
183 pub server_id: LanguageServerId,
184 pub disk_based_sources: Cow<'a, [String]>,
185}
186
187pub struct DocumentDiagnostics {
188 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
189 document_abs_path: PathBuf,
190 version: Option<i32>,
191}
192
193#[derive(Default)]
194struct DynamicRegistrations {
195 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
196 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
197}
198
199pub struct LocalLspStore {
200 weak: WeakEntity<LspStore>,
201 worktree_store: Entity<WorktreeStore>,
202 toolchain_store: Entity<LocalToolchainStore>,
203 http_client: Arc<dyn HttpClient>,
204 environment: Entity<ProjectEnvironment>,
205 fs: Arc<dyn Fs>,
206 languages: Arc<LanguageRegistry>,
207 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
208 yarn: Entity<YarnPathStore>,
209 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
210 buffers_being_formatted: HashSet<BufferId>,
211 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
212 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
213 watched_manifest_filenames: HashSet<ManifestName>,
214 language_server_paths_watched_for_rename:
215 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
216 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
217 supplementary_language_servers:
218 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
219 prettier_store: Entity<PrettierStore>,
220 next_diagnostic_group_id: usize,
221 diagnostics: HashMap<
222 WorktreeId,
223 HashMap<
224 Arc<RelPath>,
225 Vec<(
226 LanguageServerId,
227 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
228 )>,
229 >,
230 >,
231 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
232 _subscription: gpui::Subscription,
233 lsp_tree: LanguageServerTree,
234 registered_buffers: HashMap<BufferId, usize>,
235 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
236 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
237}
238
239impl LocalLspStore {
240 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
241 pub fn running_language_server_for_id(
242 &self,
243 id: LanguageServerId,
244 ) -> Option<&Arc<LanguageServer>> {
245 let language_server_state = self.language_servers.get(&id)?;
246
247 match language_server_state {
248 LanguageServerState::Running { server, .. } => Some(server),
249 LanguageServerState::Starting { .. } => None,
250 }
251 }
252
253 fn get_or_insert_language_server(
254 &mut self,
255 worktree_handle: &Entity<Worktree>,
256 delegate: Arc<LocalLspAdapterDelegate>,
257 disposition: &Arc<LaunchDisposition>,
258 language_name: &LanguageName,
259 cx: &mut App,
260 ) -> LanguageServerId {
261 let key = LanguageServerSeed {
262 worktree_id: worktree_handle.read(cx).id(),
263 name: disposition.server_name.clone(),
264 settings: disposition.settings.clone(),
265 toolchain: disposition.toolchain.clone(),
266 };
267 if let Some(state) = self.language_server_ids.get_mut(&key) {
268 state.project_roots.insert(disposition.path.path.clone());
269 state.id
270 } else {
271 let adapter = self
272 .languages
273 .lsp_adapters(language_name)
274 .into_iter()
275 .find(|adapter| adapter.name() == disposition.server_name)
276 .expect("To find LSP adapter");
277 let new_language_server_id = self.start_language_server(
278 worktree_handle,
279 delegate,
280 adapter,
281 disposition.settings.clone(),
282 key.clone(),
283 cx,
284 );
285 if let Some(state) = self.language_server_ids.get_mut(&key) {
286 state.project_roots.insert(disposition.path.path.clone());
287 } else {
288 debug_assert!(
289 false,
290 "Expected `start_language_server` to ensure that `key` exists in a map"
291 );
292 }
293 new_language_server_id
294 }
295 }
296
297 fn start_language_server(
298 &mut self,
299 worktree_handle: &Entity<Worktree>,
300 delegate: Arc<LocalLspAdapterDelegate>,
301 adapter: Arc<CachedLspAdapter>,
302 settings: Arc<LspSettings>,
303 key: LanguageServerSeed,
304 cx: &mut App,
305 ) -> LanguageServerId {
306 let worktree = worktree_handle.read(cx);
307
308 let root_path = worktree.abs_path();
309 let toolchain = key.toolchain.clone();
310 let override_options = settings.initialization_options.clone();
311
312 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
313
314 let server_id = self.languages.next_language_server_id();
315 log::trace!(
316 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
317 adapter.name.0
318 );
319
320 let binary = self.get_language_server_binary(
321 adapter.clone(),
322 settings,
323 toolchain.clone(),
324 delegate.clone(),
325 true,
326 cx,
327 );
328 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
329
330 let pending_server = cx.spawn({
331 let adapter = adapter.clone();
332 let server_name = adapter.name.clone();
333 let stderr_capture = stderr_capture.clone();
334 #[cfg(any(test, feature = "test-support"))]
335 let lsp_store = self.weak.clone();
336 let pending_workspace_folders = pending_workspace_folders.clone();
337 async move |cx| {
338 let binary = binary.await?;
339 #[cfg(any(test, feature = "test-support"))]
340 if let Some(server) = lsp_store
341 .update(&mut cx.clone(), |this, cx| {
342 this.languages.create_fake_language_server(
343 server_id,
344 &server_name,
345 binary.clone(),
346 &mut cx.to_async(),
347 )
348 })
349 .ok()
350 .flatten()
351 {
352 return Ok(server);
353 }
354
355 let code_action_kinds = adapter.code_action_kinds();
356 lsp::LanguageServer::new(
357 stderr_capture,
358 server_id,
359 server_name,
360 binary,
361 &root_path,
362 code_action_kinds,
363 Some(pending_workspace_folders),
364 cx,
365 )
366 }
367 });
368
369 let startup = {
370 let server_name = adapter.name.0.clone();
371 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
372 let key = key.clone();
373 let adapter = adapter.clone();
374 let lsp_store = self.weak.clone();
375 let pending_workspace_folders = pending_workspace_folders.clone();
376
377 let pull_diagnostics = ProjectSettings::get_global(cx)
378 .diagnostics
379 .lsp_pull_diagnostics
380 .enabled;
381 cx.spawn(async move |cx| {
382 let result = async {
383 let language_server = pending_server.await?;
384
385 let workspace_config = Self::workspace_configuration_for_adapter(
386 adapter.adapter.clone(),
387 &delegate,
388 toolchain,
389 cx,
390 )
391 .await?;
392
393 let mut initialization_options = Self::initialization_options_for_adapter(
394 adapter.adapter.clone(),
395 &delegate,
396 )
397 .await?;
398
399 match (&mut initialization_options, override_options) {
400 (Some(initialization_options), Some(override_options)) => {
401 merge_json_value_into(override_options, initialization_options);
402 }
403 (None, override_options) => initialization_options = override_options,
404 _ => {}
405 }
406
407 let initialization_params = cx.update(|cx| {
408 let mut params =
409 language_server.default_initialize_params(pull_diagnostics, cx);
410 params.initialization_options = initialization_options;
411 adapter.adapter.prepare_initialize_params(params, cx)
412 })??;
413
414 Self::setup_lsp_messages(
415 lsp_store.clone(),
416 &language_server,
417 delegate.clone(),
418 adapter.clone(),
419 );
420
421 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
422 settings: workspace_config,
423 };
424 let language_server = cx
425 .update(|cx| {
426 language_server.initialize(
427 initialization_params,
428 Arc::new(did_change_configuration_params.clone()),
429 cx,
430 )
431 })?
432 .await
433 .inspect_err(|_| {
434 if let Some(lsp_store) = lsp_store.upgrade() {
435 lsp_store
436 .update(cx, |lsp_store, cx| {
437 lsp_store.cleanup_lsp_data(server_id);
438 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
439 })
440 .ok();
441 }
442 })?;
443
444 language_server.notify::<lsp::notification::DidChangeConfiguration>(
445 did_change_configuration_params,
446 )?;
447
448 anyhow::Ok(language_server)
449 }
450 .await;
451
452 match result {
453 Ok(server) => {
454 lsp_store
455 .update(cx, |lsp_store, cx| {
456 lsp_store.insert_newly_running_language_server(
457 adapter,
458 server.clone(),
459 server_id,
460 key,
461 pending_workspace_folders,
462 cx,
463 );
464 })
465 .ok();
466 stderr_capture.lock().take();
467 Some(server)
468 }
469
470 Err(err) => {
471 let log = stderr_capture.lock().take().unwrap_or_default();
472 delegate.update_status(
473 adapter.name(),
474 BinaryStatus::Failed {
475 error: if log.is_empty() {
476 format!("{err:#}")
477 } else {
478 format!("{err:#}\n-- stderr --\n{log}")
479 },
480 },
481 );
482 log::error!("Failed to start language server {server_name:?}: {err:?}");
483 if !log.is_empty() {
484 log::error!("server stderr: {log}");
485 }
486 None
487 }
488 }
489 })
490 };
491 let state = LanguageServerState::Starting {
492 startup,
493 pending_workspace_folders,
494 };
495
496 self.languages
497 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
498
499 self.language_servers.insert(server_id, state);
500 self.language_server_ids
501 .entry(key)
502 .or_insert(UnifiedLanguageServer {
503 id: server_id,
504 project_roots: Default::default(),
505 });
506 server_id
507 }
508
509 fn get_language_server_binary(
510 &self,
511 adapter: Arc<CachedLspAdapter>,
512 settings: Arc<LspSettings>,
513 toolchain: Option<Toolchain>,
514 delegate: Arc<dyn LspAdapterDelegate>,
515 allow_binary_download: bool,
516 cx: &mut App,
517 ) -> Task<Result<LanguageServerBinary>> {
518 if let Some(settings) = settings.binary.as_ref()
519 && settings.path.is_some()
520 {
521 let settings = settings.clone();
522
523 return cx.background_spawn(async move {
524 let mut env = delegate.shell_env().await;
525 env.extend(settings.env.unwrap_or_default());
526
527 Ok(LanguageServerBinary {
528 path: PathBuf::from(&settings.path.unwrap()),
529 env: Some(env),
530 arguments: settings
531 .arguments
532 .unwrap_or_default()
533 .iter()
534 .map(Into::into)
535 .collect(),
536 })
537 });
538 }
539 let lsp_binary_options = LanguageServerBinaryOptions {
540 allow_path_lookup: !settings
541 .binary
542 .as_ref()
543 .and_then(|b| b.ignore_system_version)
544 .unwrap_or_default(),
545 allow_binary_download,
546 pre_release: settings
547 .fetch
548 .as_ref()
549 .and_then(|f| f.pre_release)
550 .unwrap_or(false),
551 };
552
553 cx.spawn(async move |cx| {
554 let binary_result = adapter
555 .clone()
556 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
557 .await;
558
559 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
560
561 let mut binary = binary_result?;
562 let mut shell_env = delegate.shell_env().await;
563
564 shell_env.extend(binary.env.unwrap_or_default());
565
566 if let Some(settings) = settings.binary.as_ref() {
567 if let Some(arguments) = &settings.arguments {
568 binary.arguments = arguments.iter().map(Into::into).collect();
569 }
570 if let Some(env) = &settings.env {
571 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
572 }
573 }
574
575 binary.env = Some(shell_env);
576 Ok(binary)
577 })
578 }
579
580 fn setup_lsp_messages(
581 lsp_store: WeakEntity<LspStore>,
582 language_server: &LanguageServer,
583 delegate: Arc<dyn LspAdapterDelegate>,
584 adapter: Arc<CachedLspAdapter>,
585 ) {
586 let name = language_server.name();
587 let server_id = language_server.server_id();
588 language_server
589 .on_notification::<lsp::notification::PublishDiagnostics, _>({
590 let adapter = adapter.clone();
591 let this = lsp_store.clone();
592 move |mut params, cx| {
593 let adapter = adapter.clone();
594 if let Some(this) = this.upgrade() {
595 this.update(cx, |this, cx| {
596 {
597 let buffer = params
598 .uri
599 .to_file_path()
600 .map(|file_path| this.get_buffer(&file_path, cx))
601 .ok()
602 .flatten();
603 adapter.process_diagnostics(&mut params, server_id, buffer);
604 }
605
606 this.merge_lsp_diagnostics(
607 DiagnosticSourceKind::Pushed,
608 vec![DocumentDiagnosticsUpdate {
609 server_id,
610 diagnostics: params,
611 result_id: None,
612 disk_based_sources: Cow::Borrowed(
613 &adapter.disk_based_diagnostic_sources,
614 ),
615 }],
616 |_, diagnostic, cx| match diagnostic.source_kind {
617 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
618 adapter.retain_old_diagnostic(diagnostic, cx)
619 }
620 DiagnosticSourceKind::Pulled => true,
621 },
622 cx,
623 )
624 .log_err();
625 })
626 .ok();
627 }
628 }
629 })
630 .detach();
631 language_server
632 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
633 let adapter = adapter.adapter.clone();
634 let delegate = delegate.clone();
635 let this = lsp_store.clone();
636 move |params, cx| {
637 let adapter = adapter.clone();
638 let delegate = delegate.clone();
639 let this = this.clone();
640 let mut cx = cx.clone();
641 async move {
642 let toolchain_for_id = this
643 .update(&mut cx, |this, _| {
644 this.as_local()?.language_server_ids.iter().find_map(
645 |(seed, value)| {
646 (value.id == server_id).then(|| seed.toolchain.clone())
647 },
648 )
649 })?
650 .context("Expected the LSP store to be in a local mode")?;
651 let workspace_config = Self::workspace_configuration_for_adapter(
652 adapter.clone(),
653 &delegate,
654 toolchain_for_id,
655 &mut cx,
656 )
657 .await?;
658
659 Ok(params
660 .items
661 .into_iter()
662 .map(|item| {
663 if let Some(section) = &item.section {
664 workspace_config
665 .get(section)
666 .cloned()
667 .unwrap_or(serde_json::Value::Null)
668 } else {
669 workspace_config.clone()
670 }
671 })
672 .collect())
673 }
674 }
675 })
676 .detach();
677
678 language_server
679 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
680 let this = lsp_store.clone();
681 move |_, cx| {
682 let this = this.clone();
683 let cx = cx.clone();
684 async move {
685 let Some(server) =
686 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
687 else {
688 return Ok(None);
689 };
690 let root = server.workspace_folders();
691 Ok(Some(
692 root.into_iter()
693 .map(|uri| WorkspaceFolder {
694 uri,
695 name: Default::default(),
696 })
697 .collect(),
698 ))
699 }
700 }
701 })
702 .detach();
703 // Even though we don't have handling for these requests, respond to them to
704 // avoid stalling any language server like `gopls` which waits for a response
705 // to these requests when initializing.
706 language_server
707 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
708 let this = lsp_store.clone();
709 move |params, cx| {
710 let this = this.clone();
711 let mut cx = cx.clone();
712 async move {
713 this.update(&mut cx, |this, _| {
714 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
715 && let lsp::NumberOrString::String(token) = params.token
716 {
717 status.progress_tokens.insert(token);
718 }
719 })?;
720
721 Ok(())
722 }
723 }
724 })
725 .detach();
726
727 language_server
728 .on_request::<lsp::request::RegisterCapability, _, _>({
729 let lsp_store = lsp_store.clone();
730 move |params, cx| {
731 let lsp_store = lsp_store.clone();
732 let mut cx = cx.clone();
733 async move {
734 lsp_store
735 .update(&mut cx, |lsp_store, cx| {
736 if lsp_store.as_local().is_some() {
737 match lsp_store
738 .register_server_capabilities(server_id, params, cx)
739 {
740 Ok(()) => {}
741 Err(e) => {
742 log::error!(
743 "Failed to register server capabilities: {e:#}"
744 );
745 }
746 };
747 }
748 })
749 .ok();
750 Ok(())
751 }
752 }
753 })
754 .detach();
755
756 language_server
757 .on_request::<lsp::request::UnregisterCapability, _, _>({
758 let lsp_store = lsp_store.clone();
759 move |params, cx| {
760 let lsp_store = lsp_store.clone();
761 let mut cx = cx.clone();
762 async move {
763 lsp_store
764 .update(&mut cx, |lsp_store, cx| {
765 if lsp_store.as_local().is_some() {
766 match lsp_store
767 .unregister_server_capabilities(server_id, params, cx)
768 {
769 Ok(()) => {}
770 Err(e) => {
771 log::error!(
772 "Failed to unregister server capabilities: {e:#}"
773 );
774 }
775 }
776 }
777 })
778 .ok();
779 Ok(())
780 }
781 }
782 })
783 .detach();
784
785 language_server
786 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
787 let this = lsp_store.clone();
788 move |params, cx| {
789 let mut cx = cx.clone();
790 let this = this.clone();
791 async move {
792 LocalLspStore::on_lsp_workspace_edit(
793 this.clone(),
794 params,
795 server_id,
796 &mut cx,
797 )
798 .await
799 }
800 }
801 })
802 .detach();
803
804 language_server
805 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
806 let lsp_store = lsp_store.clone();
807 move |(), cx| {
808 let this = lsp_store.clone();
809 let mut cx = cx.clone();
810 async move {
811 this.update(&mut cx, |lsp_store, cx| {
812 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
813 lsp_store
814 .downstream_client
815 .as_ref()
816 .map(|(client, project_id)| {
817 client.send(proto::RefreshInlayHints {
818 project_id: *project_id,
819 server_id: server_id.to_proto(),
820 })
821 })
822 })?
823 .transpose()?;
824 Ok(())
825 }
826 }
827 })
828 .detach();
829
830 language_server
831 .on_request::<lsp::request::CodeLensRefresh, _, _>({
832 let this = lsp_store.clone();
833 move |(), cx| {
834 let this = this.clone();
835 let mut cx = cx.clone();
836 async move {
837 this.update(&mut cx, |this, cx| {
838 cx.emit(LspStoreEvent::RefreshCodeLens);
839 this.downstream_client.as_ref().map(|(client, project_id)| {
840 client.send(proto::RefreshCodeLens {
841 project_id: *project_id,
842 })
843 })
844 })?
845 .transpose()?;
846 Ok(())
847 }
848 }
849 })
850 .detach();
851
852 language_server
853 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
854 let this = lsp_store.clone();
855 move |(), cx| {
856 let this = this.clone();
857 let mut cx = cx.clone();
858 async move {
859 this.update(&mut cx, |lsp_store, _| {
860 lsp_store.pull_workspace_diagnostics(server_id);
861 lsp_store
862 .downstream_client
863 .as_ref()
864 .map(|(client, project_id)| {
865 client.send(proto::PullWorkspaceDiagnostics {
866 project_id: *project_id,
867 server_id: server_id.to_proto(),
868 })
869 })
870 })?
871 .transpose()?;
872 Ok(())
873 }
874 }
875 })
876 .detach();
877
878 language_server
879 .on_request::<lsp::request::ShowMessageRequest, _, _>({
880 let this = lsp_store.clone();
881 let name = name.to_string();
882 move |params, cx| {
883 let this = this.clone();
884 let name = name.to_string();
885 let mut cx = cx.clone();
886 async move {
887 let actions = params.actions.unwrap_or_default();
888 let (tx, rx) = smol::channel::bounded(1);
889 let request = LanguageServerPromptRequest {
890 level: match params.typ {
891 lsp::MessageType::ERROR => PromptLevel::Critical,
892 lsp::MessageType::WARNING => PromptLevel::Warning,
893 _ => PromptLevel::Info,
894 },
895 message: params.message,
896 actions,
897 response_channel: tx,
898 lsp_name: name.clone(),
899 };
900
901 let did_update = this
902 .update(&mut cx, |_, cx| {
903 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
904 })
905 .is_ok();
906 if did_update {
907 let response = rx.recv().await.ok();
908 Ok(response)
909 } else {
910 Ok(None)
911 }
912 }
913 }
914 })
915 .detach();
916 language_server
917 .on_notification::<lsp::notification::ShowMessage, _>({
918 let this = lsp_store.clone();
919 let name = name.to_string();
920 move |params, cx| {
921 let this = this.clone();
922 let name = name.to_string();
923 let mut cx = cx.clone();
924
925 let (tx, _) = smol::channel::bounded(1);
926 let request = LanguageServerPromptRequest {
927 level: match params.typ {
928 lsp::MessageType::ERROR => PromptLevel::Critical,
929 lsp::MessageType::WARNING => PromptLevel::Warning,
930 _ => PromptLevel::Info,
931 },
932 message: params.message,
933 actions: vec![],
934 response_channel: tx,
935 lsp_name: name,
936 };
937
938 let _ = this.update(&mut cx, |_, cx| {
939 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
940 });
941 }
942 })
943 .detach();
944
945 let disk_based_diagnostics_progress_token =
946 adapter.disk_based_diagnostics_progress_token.clone();
947
948 language_server
949 .on_notification::<lsp::notification::Progress, _>({
950 let this = lsp_store.clone();
951 move |params, cx| {
952 if let Some(this) = this.upgrade() {
953 this.update(cx, |this, cx| {
954 this.on_lsp_progress(
955 params,
956 server_id,
957 disk_based_diagnostics_progress_token.clone(),
958 cx,
959 );
960 })
961 .ok();
962 }
963 }
964 })
965 .detach();
966
967 language_server
968 .on_notification::<lsp::notification::LogMessage, _>({
969 let this = lsp_store.clone();
970 move |params, cx| {
971 if let Some(this) = this.upgrade() {
972 this.update(cx, |_, cx| {
973 cx.emit(LspStoreEvent::LanguageServerLog(
974 server_id,
975 LanguageServerLogType::Log(params.typ),
976 params.message,
977 ));
978 })
979 .ok();
980 }
981 }
982 })
983 .detach();
984
985 language_server
986 .on_notification::<lsp::notification::LogTrace, _>({
987 let this = lsp_store.clone();
988 move |params, cx| {
989 let mut cx = cx.clone();
990 if let Some(this) = this.upgrade() {
991 this.update(&mut cx, |_, cx| {
992 cx.emit(LspStoreEvent::LanguageServerLog(
993 server_id,
994 LanguageServerLogType::Trace {
995 verbose_info: params.verbose,
996 },
997 params.message,
998 ));
999 })
1000 .ok();
1001 }
1002 }
1003 })
1004 .detach();
1005
1006 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1007 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1008 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1009 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1010 }
1011
1012 fn shutdown_language_servers_on_quit(
1013 &mut self,
1014 _: &mut Context<LspStore>,
1015 ) -> impl Future<Output = ()> + use<> {
1016 let shutdown_futures = self
1017 .language_servers
1018 .drain()
1019 .map(|(_, server_state)| Self::shutdown_server(server_state))
1020 .collect::<Vec<_>>();
1021
1022 async move {
1023 join_all(shutdown_futures).await;
1024 }
1025 }
1026
1027 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1028 match server_state {
1029 LanguageServerState::Running { server, .. } => {
1030 if let Some(shutdown) = server.shutdown() {
1031 shutdown.await;
1032 }
1033 }
1034 LanguageServerState::Starting { startup, .. } => {
1035 if let Some(server) = startup.await
1036 && let Some(shutdown) = server.shutdown()
1037 {
1038 shutdown.await;
1039 }
1040 }
1041 }
1042 Ok(())
1043 }
1044
1045 fn language_servers_for_worktree(
1046 &self,
1047 worktree_id: WorktreeId,
1048 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1049 self.language_server_ids
1050 .iter()
1051 .filter_map(move |(seed, state)| {
1052 if seed.worktree_id != worktree_id {
1053 return None;
1054 }
1055
1056 if let Some(LanguageServerState::Running { server, .. }) =
1057 self.language_servers.get(&state.id)
1058 {
1059 Some(server)
1060 } else {
1061 None
1062 }
1063 })
1064 }
1065
1066 fn language_server_ids_for_project_path(
1067 &self,
1068 project_path: ProjectPath,
1069 language: &Language,
1070 cx: &mut App,
1071 ) -> Vec<LanguageServerId> {
1072 let Some(worktree) = self
1073 .worktree_store
1074 .read(cx)
1075 .worktree_for_id(project_path.worktree_id, cx)
1076 else {
1077 return Vec::new();
1078 };
1079 let delegate: Arc<dyn ManifestDelegate> =
1080 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1081
1082 self.lsp_tree
1083 .get(
1084 project_path,
1085 language.name(),
1086 language.manifest(),
1087 &delegate,
1088 cx,
1089 )
1090 .collect::<Vec<_>>()
1091 }
1092
1093 fn language_server_ids_for_buffer(
1094 &self,
1095 buffer: &Buffer,
1096 cx: &mut App,
1097 ) -> Vec<LanguageServerId> {
1098 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1099 let worktree_id = file.worktree_id(cx);
1100
1101 let path: Arc<RelPath> = file
1102 .path()
1103 .parent()
1104 .map(Arc::from)
1105 .unwrap_or_else(|| file.path().clone());
1106 let worktree_path = ProjectPath { worktree_id, path };
1107 self.language_server_ids_for_project_path(worktree_path, language, cx)
1108 } else {
1109 Vec::new()
1110 }
1111 }
1112
1113 fn language_servers_for_buffer<'a>(
1114 &'a self,
1115 buffer: &'a Buffer,
1116 cx: &'a mut App,
1117 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1118 self.language_server_ids_for_buffer(buffer, cx)
1119 .into_iter()
1120 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1121 LanguageServerState::Running {
1122 adapter, server, ..
1123 } => Some((adapter, server)),
1124 _ => None,
1125 })
1126 }
1127
1128 async fn execute_code_action_kind_locally(
1129 lsp_store: WeakEntity<LspStore>,
1130 mut buffers: Vec<Entity<Buffer>>,
1131 kind: CodeActionKind,
1132 push_to_history: bool,
1133 cx: &mut AsyncApp,
1134 ) -> anyhow::Result<ProjectTransaction> {
1135 // Do not allow multiple concurrent code actions requests for the
1136 // same buffer.
1137 lsp_store.update(cx, |this, cx| {
1138 let this = this.as_local_mut().unwrap();
1139 buffers.retain(|buffer| {
1140 this.buffers_being_formatted
1141 .insert(buffer.read(cx).remote_id())
1142 });
1143 })?;
1144 let _cleanup = defer({
1145 let this = lsp_store.clone();
1146 let mut cx = cx.clone();
1147 let buffers = &buffers;
1148 move || {
1149 this.update(&mut cx, |this, cx| {
1150 let this = this.as_local_mut().unwrap();
1151 for buffer in buffers {
1152 this.buffers_being_formatted
1153 .remove(&buffer.read(cx).remote_id());
1154 }
1155 })
1156 .ok();
1157 }
1158 });
1159 let mut project_transaction = ProjectTransaction::default();
1160
1161 for buffer in &buffers {
1162 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1163 buffer.update(cx, |buffer, cx| {
1164 lsp_store
1165 .as_local()
1166 .unwrap()
1167 .language_servers_for_buffer(buffer, cx)
1168 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1169 .collect::<Vec<_>>()
1170 })
1171 })?;
1172 for (_, language_server) in adapters_and_servers.iter() {
1173 let actions = Self::get_server_code_actions_from_action_kinds(
1174 &lsp_store,
1175 language_server.server_id(),
1176 vec![kind.clone()],
1177 buffer,
1178 cx,
1179 )
1180 .await?;
1181 Self::execute_code_actions_on_server(
1182 &lsp_store,
1183 language_server,
1184 actions,
1185 push_to_history,
1186 &mut project_transaction,
1187 cx,
1188 )
1189 .await?;
1190 }
1191 }
1192 Ok(project_transaction)
1193 }
1194
1195 async fn format_locally(
1196 lsp_store: WeakEntity<LspStore>,
1197 mut buffers: Vec<FormattableBuffer>,
1198 push_to_history: bool,
1199 trigger: FormatTrigger,
1200 logger: zlog::Logger,
1201 cx: &mut AsyncApp,
1202 ) -> anyhow::Result<ProjectTransaction> {
1203 // Do not allow multiple concurrent formatting requests for the
1204 // same buffer.
1205 lsp_store.update(cx, |this, cx| {
1206 let this = this.as_local_mut().unwrap();
1207 buffers.retain(|buffer| {
1208 this.buffers_being_formatted
1209 .insert(buffer.handle.read(cx).remote_id())
1210 });
1211 })?;
1212
1213 let _cleanup = defer({
1214 let this = lsp_store.clone();
1215 let mut cx = cx.clone();
1216 let buffers = &buffers;
1217 move || {
1218 this.update(&mut cx, |this, cx| {
1219 let this = this.as_local_mut().unwrap();
1220 for buffer in buffers {
1221 this.buffers_being_formatted
1222 .remove(&buffer.handle.read(cx).remote_id());
1223 }
1224 })
1225 .ok();
1226 }
1227 });
1228
1229 let mut project_transaction = ProjectTransaction::default();
1230
1231 for buffer in &buffers {
1232 zlog::debug!(
1233 logger =>
1234 "formatting buffer '{:?}'",
1235 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1236 );
1237 // Create an empty transaction to hold all of the formatting edits.
1238 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1239 // ensure no transactions created while formatting are
1240 // grouped with the previous transaction in the history
1241 // based on the transaction group interval
1242 buffer.finalize_last_transaction();
1243 buffer
1244 .start_transaction()
1245 .context("transaction already open")?;
1246 buffer.end_transaction(cx);
1247 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1248 buffer.finalize_last_transaction();
1249 anyhow::Ok(transaction_id)
1250 })??;
1251
1252 let result = Self::format_buffer_locally(
1253 lsp_store.clone(),
1254 buffer,
1255 formatting_transaction_id,
1256 trigger,
1257 logger,
1258 cx,
1259 )
1260 .await;
1261
1262 buffer.handle.update(cx, |buffer, cx| {
1263 let Some(formatting_transaction) =
1264 buffer.get_transaction(formatting_transaction_id).cloned()
1265 else {
1266 zlog::warn!(logger => "no formatting transaction");
1267 return;
1268 };
1269 if formatting_transaction.edit_ids.is_empty() {
1270 zlog::debug!(logger => "no changes made while formatting");
1271 buffer.forget_transaction(formatting_transaction_id);
1272 return;
1273 }
1274 if !push_to_history {
1275 zlog::trace!(logger => "forgetting format transaction");
1276 buffer.forget_transaction(formatting_transaction.id);
1277 }
1278 project_transaction
1279 .0
1280 .insert(cx.entity(), formatting_transaction);
1281 })?;
1282
1283 result?;
1284 }
1285
1286 Ok(project_transaction)
1287 }
1288
1289 async fn format_buffer_locally(
1290 lsp_store: WeakEntity<LspStore>,
1291 buffer: &FormattableBuffer,
1292 formatting_transaction_id: clock::Lamport,
1293 trigger: FormatTrigger,
1294 logger: zlog::Logger,
1295 cx: &mut AsyncApp,
1296 ) -> Result<()> {
1297 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1298 buffer.handle.update(cx, |buffer, cx| {
1299 let adapters_and_servers = lsp_store
1300 .as_local()
1301 .unwrap()
1302 .language_servers_for_buffer(buffer, cx)
1303 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1304 .collect::<Vec<_>>();
1305 let settings =
1306 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1307 .into_owned();
1308 (adapters_and_servers, settings)
1309 })
1310 })?;
1311
1312 /// Apply edits to the buffer that will become part of the formatting transaction.
1313 /// Fails if the buffer has been edited since the start of that transaction.
1314 fn extend_formatting_transaction(
1315 buffer: &FormattableBuffer,
1316 formatting_transaction_id: text::TransactionId,
1317 cx: &mut AsyncApp,
1318 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1319 ) -> anyhow::Result<()> {
1320 buffer.handle.update(cx, |buffer, cx| {
1321 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1322 if last_transaction_id != Some(formatting_transaction_id) {
1323 anyhow::bail!("Buffer edited while formatting. Aborting")
1324 }
1325 buffer.start_transaction();
1326 operation(buffer, cx);
1327 if let Some(transaction_id) = buffer.end_transaction(cx) {
1328 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1329 }
1330 Ok(())
1331 })?
1332 }
1333
1334 // handle whitespace formatting
1335 if settings.remove_trailing_whitespace_on_save {
1336 zlog::trace!(logger => "removing trailing whitespace");
1337 let diff = buffer
1338 .handle
1339 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1340 .await;
1341 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1342 buffer.apply_diff(diff, cx);
1343 })?;
1344 }
1345
1346 if settings.ensure_final_newline_on_save {
1347 zlog::trace!(logger => "ensuring final newline");
1348 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1349 buffer.ensure_final_newline(cx);
1350 })?;
1351 }
1352
1353 // Formatter for `code_actions_on_format` that runs before
1354 // the rest of the formatters
1355 let mut code_actions_on_format_formatters = None;
1356 let should_run_code_actions_on_format = !matches!(
1357 (trigger, &settings.format_on_save),
1358 (FormatTrigger::Save, &FormatOnSave::Off)
1359 );
1360 if should_run_code_actions_on_format {
1361 let have_code_actions_to_run_on_format = settings
1362 .code_actions_on_format
1363 .values()
1364 .any(|enabled| *enabled);
1365 if have_code_actions_to_run_on_format {
1366 zlog::trace!(logger => "going to run code actions on format");
1367 code_actions_on_format_formatters = Some(
1368 settings
1369 .code_actions_on_format
1370 .iter()
1371 .filter_map(|(action, enabled)| enabled.then_some(action))
1372 .cloned()
1373 .map(Formatter::CodeAction)
1374 .collect::<Vec<_>>(),
1375 );
1376 }
1377 }
1378
1379 let formatters = match (trigger, &settings.format_on_save) {
1380 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1381 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1382 settings.formatter.as_ref()
1383 }
1384 };
1385
1386 let formatters = code_actions_on_format_formatters
1387 .iter()
1388 .flatten()
1389 .chain(formatters);
1390
1391 for formatter in formatters {
1392 let formatter = if formatter == &Formatter::Auto {
1393 if settings.prettier.allowed {
1394 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1395 &Formatter::Prettier
1396 } else {
1397 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1398 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1399 }
1400 } else {
1401 formatter
1402 };
1403 match formatter {
1404 Formatter::Auto => unreachable!("Auto resolved above"),
1405 Formatter::Prettier => {
1406 let logger = zlog::scoped!(logger => "prettier");
1407 zlog::trace!(logger => "formatting");
1408 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1409
1410 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1411 lsp_store.prettier_store().unwrap().downgrade()
1412 })?;
1413 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1414 .await
1415 .transpose()?;
1416 let Some(diff) = diff else {
1417 zlog::trace!(logger => "No changes");
1418 continue;
1419 };
1420
1421 extend_formatting_transaction(
1422 buffer,
1423 formatting_transaction_id,
1424 cx,
1425 |buffer, cx| {
1426 buffer.apply_diff(diff, cx);
1427 },
1428 )?;
1429 }
1430 Formatter::External { command, arguments } => {
1431 let logger = zlog::scoped!(logger => "command");
1432 zlog::trace!(logger => "formatting");
1433 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1434
1435 let diff = Self::format_via_external_command(
1436 buffer,
1437 command.as_ref(),
1438 arguments.as_deref(),
1439 cx,
1440 )
1441 .await
1442 .with_context(|| {
1443 format!("Failed to format buffer via external command: {}", command)
1444 })?;
1445 let Some(diff) = diff else {
1446 zlog::trace!(logger => "No changes");
1447 continue;
1448 };
1449
1450 extend_formatting_transaction(
1451 buffer,
1452 formatting_transaction_id,
1453 cx,
1454 |buffer, cx| {
1455 buffer.apply_diff(diff, cx);
1456 },
1457 )?;
1458 }
1459 Formatter::LanguageServer(specifier) => {
1460 let logger = zlog::scoped!(logger => "language-server");
1461 zlog::trace!(logger => "formatting");
1462 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1463
1464 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1465 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1466 continue;
1467 };
1468
1469 let language_server = match specifier {
1470 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1471 adapters_and_servers.iter().find_map(|(adapter, server)| {
1472 if adapter.name.0.as_ref() == name {
1473 Some(server.clone())
1474 } else {
1475 None
1476 }
1477 })
1478 }
1479 settings::LanguageServerFormatterSpecifier::Current => {
1480 adapters_and_servers.first().map(|e| e.1.clone())
1481 }
1482 };
1483
1484 let Some(language_server) = language_server else {
1485 log::debug!(
1486 "No language server found to format buffer '{:?}'. Skipping",
1487 buffer_path_abs.as_path().to_string_lossy()
1488 );
1489 continue;
1490 };
1491
1492 zlog::trace!(
1493 logger =>
1494 "Formatting buffer '{:?}' using language server '{:?}'",
1495 buffer_path_abs.as_path().to_string_lossy(),
1496 language_server.name()
1497 );
1498
1499 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1500 zlog::trace!(logger => "formatting ranges");
1501 Self::format_ranges_via_lsp(
1502 &lsp_store,
1503 &buffer.handle,
1504 ranges,
1505 buffer_path_abs,
1506 &language_server,
1507 &settings,
1508 cx,
1509 )
1510 .await
1511 .context("Failed to format ranges via language server")?
1512 } else {
1513 zlog::trace!(logger => "formatting full");
1514 Self::format_via_lsp(
1515 &lsp_store,
1516 &buffer.handle,
1517 buffer_path_abs,
1518 &language_server,
1519 &settings,
1520 cx,
1521 )
1522 .await
1523 .context("failed to format via language server")?
1524 };
1525
1526 if edits.is_empty() {
1527 zlog::trace!(logger => "No changes");
1528 continue;
1529 }
1530 extend_formatting_transaction(
1531 buffer,
1532 formatting_transaction_id,
1533 cx,
1534 |buffer, cx| {
1535 buffer.edit(edits, None, cx);
1536 },
1537 )?;
1538 }
1539 Formatter::CodeAction(code_action_name) => {
1540 let logger = zlog::scoped!(logger => "code-actions");
1541 zlog::trace!(logger => "formatting");
1542 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1543
1544 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1545 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1546 continue;
1547 };
1548
1549 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1550 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1551
1552 let mut actions_and_servers = Vec::new();
1553
1554 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1555 let actions_result = Self::get_server_code_actions_from_action_kinds(
1556 &lsp_store,
1557 language_server.server_id(),
1558 vec![code_action_kind.clone()],
1559 &buffer.handle,
1560 cx,
1561 )
1562 .await
1563 .with_context(|| {
1564 format!(
1565 "Failed to resolve code action {:?} with language server {}",
1566 code_action_kind,
1567 language_server.name()
1568 )
1569 });
1570 let Ok(actions) = actions_result else {
1571 // note: it may be better to set result to the error and break formatters here
1572 // but for now we try to execute the actions that we can resolve and skip the rest
1573 zlog::error!(
1574 logger =>
1575 "Failed to resolve code action {:?} with language server {}",
1576 code_action_kind,
1577 language_server.name()
1578 );
1579 continue;
1580 };
1581 for action in actions {
1582 actions_and_servers.push((action, index));
1583 }
1584 }
1585
1586 if actions_and_servers.is_empty() {
1587 zlog::warn!(logger => "No code actions were resolved, continuing");
1588 continue;
1589 }
1590
1591 'actions: for (mut action, server_index) in actions_and_servers {
1592 let server = &adapters_and_servers[server_index].1;
1593
1594 let describe_code_action = |action: &CodeAction| {
1595 format!(
1596 "code action '{}' with title \"{}\" on server {}",
1597 action
1598 .lsp_action
1599 .action_kind()
1600 .unwrap_or("unknown".into())
1601 .as_str(),
1602 action.lsp_action.title(),
1603 server.name(),
1604 )
1605 };
1606
1607 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1608
1609 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1610 zlog::error!(
1611 logger =>
1612 "Failed to resolve {}. Error: {}",
1613 describe_code_action(&action),
1614 err
1615 );
1616 continue;
1617 }
1618
1619 if let Some(edit) = action.lsp_action.edit().cloned() {
1620 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1621 // but filters out and logs warnings for code actions that require unreasonably
1622 // difficult handling on our part, such as:
1623 // - applying edits that call commands
1624 // which can result in arbitrary workspace edits being sent from the server that
1625 // have no way of being tied back to the command that initiated them (i.e. we
1626 // can't know which edits are part of the format request, or if the server is done sending
1627 // actions in response to the command)
1628 // - actions that create/delete/modify/rename files other than the one we are formatting
1629 // as we then would need to handle such changes correctly in the local history as well
1630 // as the remote history through the ProjectTransaction
1631 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1632 // Supporting these actions is not impossible, but not supported as of yet.
1633 if edit.changes.is_none() && edit.document_changes.is_none() {
1634 zlog::trace!(
1635 logger =>
1636 "No changes for code action. Skipping {}",
1637 describe_code_action(&action),
1638 );
1639 continue;
1640 }
1641
1642 let mut operations = Vec::new();
1643 if let Some(document_changes) = edit.document_changes {
1644 match document_changes {
1645 lsp::DocumentChanges::Edits(edits) => operations.extend(
1646 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1647 ),
1648 lsp::DocumentChanges::Operations(ops) => operations = ops,
1649 }
1650 } else if let Some(changes) = edit.changes {
1651 operations.extend(changes.into_iter().map(|(uri, edits)| {
1652 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1653 text_document:
1654 lsp::OptionalVersionedTextDocumentIdentifier {
1655 uri,
1656 version: None,
1657 },
1658 edits: edits.into_iter().map(Edit::Plain).collect(),
1659 })
1660 }));
1661 }
1662
1663 let mut edits = Vec::with_capacity(operations.len());
1664
1665 if operations.is_empty() {
1666 zlog::trace!(
1667 logger =>
1668 "No changes for code action. Skipping {}",
1669 describe_code_action(&action),
1670 );
1671 continue;
1672 }
1673 for operation in operations {
1674 let op = match operation {
1675 lsp::DocumentChangeOperation::Edit(op) => op,
1676 lsp::DocumentChangeOperation::Op(_) => {
1677 zlog::warn!(
1678 logger =>
1679 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1680 describe_code_action(&action),
1681 );
1682 continue 'actions;
1683 }
1684 };
1685 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1686 zlog::warn!(
1687 logger =>
1688 "Failed to convert URI '{:?}' to file path. Skipping {}",
1689 &op.text_document.uri,
1690 describe_code_action(&action),
1691 );
1692 continue 'actions;
1693 };
1694 if &file_path != buffer_path_abs {
1695 zlog::warn!(
1696 logger =>
1697 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1698 file_path,
1699 buffer_path_abs,
1700 describe_code_action(&action),
1701 );
1702 continue 'actions;
1703 }
1704
1705 let mut lsp_edits = Vec::new();
1706 for edit in op.edits {
1707 match edit {
1708 Edit::Plain(edit) => {
1709 if !lsp_edits.contains(&edit) {
1710 lsp_edits.push(edit);
1711 }
1712 }
1713 Edit::Annotated(edit) => {
1714 if !lsp_edits.contains(&edit.text_edit) {
1715 lsp_edits.push(edit.text_edit);
1716 }
1717 }
1718 Edit::Snippet(_) => {
1719 zlog::warn!(
1720 logger =>
1721 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1722 describe_code_action(&action),
1723 );
1724 continue 'actions;
1725 }
1726 }
1727 }
1728 let edits_result = lsp_store
1729 .update(cx, |lsp_store, cx| {
1730 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1731 &buffer.handle,
1732 lsp_edits,
1733 server.server_id(),
1734 op.text_document.version,
1735 cx,
1736 )
1737 })?
1738 .await;
1739 let Ok(resolved_edits) = edits_result else {
1740 zlog::warn!(
1741 logger =>
1742 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1743 buffer_path_abs.as_path(),
1744 describe_code_action(&action),
1745 );
1746 continue 'actions;
1747 };
1748 edits.extend(resolved_edits);
1749 }
1750
1751 if edits.is_empty() {
1752 zlog::warn!(logger => "No edits resolved from LSP");
1753 continue;
1754 }
1755
1756 extend_formatting_transaction(
1757 buffer,
1758 formatting_transaction_id,
1759 cx,
1760 |buffer, cx| {
1761 zlog::info!(
1762 "Applying edits {edits:?}. Content: {:?}",
1763 buffer.text()
1764 );
1765 buffer.edit(edits, None, cx);
1766 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1767 },
1768 )?;
1769 }
1770
1771 if let Some(command) = action.lsp_action.command() {
1772 zlog::warn!(
1773 logger =>
1774 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1775 &command.command,
1776 );
1777
1778 // bail early if command is invalid
1779 let server_capabilities = server.capabilities();
1780 let available_commands = server_capabilities
1781 .execute_command_provider
1782 .as_ref()
1783 .map(|options| options.commands.as_slice())
1784 .unwrap_or_default();
1785 if !available_commands.contains(&command.command) {
1786 zlog::warn!(
1787 logger =>
1788 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1789 command.command,
1790 server.name(),
1791 );
1792 continue;
1793 }
1794
1795 // noop so we just ensure buffer hasn't been edited since resolving code actions
1796 extend_formatting_transaction(
1797 buffer,
1798 formatting_transaction_id,
1799 cx,
1800 |_, _| {},
1801 )?;
1802 zlog::info!(logger => "Executing command {}", &command.command);
1803
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 })?;
1810
1811 let execute_command_result = server
1812 .request::<lsp::request::ExecuteCommand>(
1813 lsp::ExecuteCommandParams {
1814 command: command.command.clone(),
1815 arguments: command.arguments.clone().unwrap_or_default(),
1816 ..Default::default()
1817 },
1818 )
1819 .await
1820 .into_response();
1821
1822 if execute_command_result.is_err() {
1823 zlog::error!(
1824 logger =>
1825 "Failed to execute command '{}' as part of {}",
1826 &command.command,
1827 describe_code_action(&action),
1828 );
1829 continue 'actions;
1830 }
1831
1832 let mut project_transaction_command =
1833 lsp_store.update(cx, |this, _| {
1834 this.as_local_mut()
1835 .unwrap()
1836 .last_workspace_edits_by_language_server
1837 .remove(&server.server_id())
1838 .unwrap_or_default()
1839 })?;
1840
1841 if let Some(transaction) =
1842 project_transaction_command.0.remove(&buffer.handle)
1843 {
1844 zlog::trace!(
1845 logger =>
1846 "Successfully captured {} edits that resulted from command {}",
1847 transaction.edit_ids.len(),
1848 &command.command,
1849 );
1850 let transaction_id_project_transaction = transaction.id;
1851 buffer.handle.update(cx, |buffer, _| {
1852 // it may have been removed from history if push_to_history was
1853 // false in deserialize_workspace_edit. If so push it so we
1854 // can merge it with the format transaction
1855 // and pop the combined transaction off the history stack
1856 // later if push_to_history is false
1857 if buffer.get_transaction(transaction.id).is_none() {
1858 buffer.push_transaction(transaction, Instant::now());
1859 }
1860 buffer.merge_transactions(
1861 transaction_id_project_transaction,
1862 formatting_transaction_id,
1863 );
1864 })?;
1865 }
1866
1867 if !project_transaction_command.0.is_empty() {
1868 let mut extra_buffers = String::new();
1869 for buffer in project_transaction_command.0.keys() {
1870 buffer
1871 .read_with(cx, |b, cx| {
1872 if let Some(path) = b.project_path(cx) {
1873 if !extra_buffers.is_empty() {
1874 extra_buffers.push_str(", ");
1875 }
1876 extra_buffers.push_str(path.path.as_unix_str());
1877 }
1878 })
1879 .ok();
1880 }
1881 zlog::warn!(
1882 logger =>
1883 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1884 &command.command,
1885 extra_buffers,
1886 );
1887 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1888 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1889 // add it so it's included, and merge it into the format transaction when its created later
1890 }
1891 }
1892 }
1893 }
1894 }
1895 }
1896
1897 Ok(())
1898 }
1899
1900 pub async fn format_ranges_via_lsp(
1901 this: &WeakEntity<LspStore>,
1902 buffer_handle: &Entity<Buffer>,
1903 ranges: &[Range<Anchor>],
1904 abs_path: &Path,
1905 language_server: &Arc<LanguageServer>,
1906 settings: &LanguageSettings,
1907 cx: &mut AsyncApp,
1908 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1909 let capabilities = &language_server.capabilities();
1910 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1911 if range_formatting_provider == Some(&OneOf::Left(false)) {
1912 anyhow::bail!(
1913 "{} language server does not support range formatting",
1914 language_server.name()
1915 );
1916 }
1917
1918 let uri = file_path_to_lsp_url(abs_path)?;
1919 let text_document = lsp::TextDocumentIdentifier::new(uri);
1920
1921 let lsp_edits = {
1922 let mut lsp_ranges = Vec::new();
1923 this.update(cx, |_this, cx| {
1924 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1925 // not have been sent to the language server. This seems like a fairly systemic
1926 // issue, though, the resolution probably is not specific to formatting.
1927 //
1928 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1929 // LSP.
1930 let snapshot = buffer_handle.read(cx).snapshot();
1931 for range in ranges {
1932 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1933 }
1934 anyhow::Ok(())
1935 })??;
1936
1937 let mut edits = None;
1938 for range in lsp_ranges {
1939 if let Some(mut edit) = language_server
1940 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1941 text_document: text_document.clone(),
1942 range,
1943 options: lsp_command::lsp_formatting_options(settings),
1944 work_done_progress_params: Default::default(),
1945 })
1946 .await
1947 .into_response()?
1948 {
1949 edits.get_or_insert_with(Vec::new).append(&mut edit);
1950 }
1951 }
1952 edits
1953 };
1954
1955 if let Some(lsp_edits) = lsp_edits {
1956 this.update(cx, |this, cx| {
1957 this.as_local_mut().unwrap().edits_from_lsp(
1958 buffer_handle,
1959 lsp_edits,
1960 language_server.server_id(),
1961 None,
1962 cx,
1963 )
1964 })?
1965 .await
1966 } else {
1967 Ok(Vec::with_capacity(0))
1968 }
1969 }
1970
1971 async fn format_via_lsp(
1972 this: &WeakEntity<LspStore>,
1973 buffer: &Entity<Buffer>,
1974 abs_path: &Path,
1975 language_server: &Arc<LanguageServer>,
1976 settings: &LanguageSettings,
1977 cx: &mut AsyncApp,
1978 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1979 let logger = zlog::scoped!("lsp_format");
1980 zlog::info!(logger => "Formatting via LSP");
1981
1982 let uri = file_path_to_lsp_url(abs_path)?;
1983 let text_document = lsp::TextDocumentIdentifier::new(uri);
1984 let capabilities = &language_server.capabilities();
1985
1986 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1987 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1988
1989 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1990 let _timer = zlog::time!(logger => "format-full");
1991 language_server
1992 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1993 text_document,
1994 options: lsp_command::lsp_formatting_options(settings),
1995 work_done_progress_params: Default::default(),
1996 })
1997 .await
1998 .into_response()?
1999 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2000 let _timer = zlog::time!(logger => "format-range");
2001 let buffer_start = lsp::Position::new(0, 0);
2002 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2003 language_server
2004 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2005 text_document: text_document.clone(),
2006 range: lsp::Range::new(buffer_start, buffer_end),
2007 options: lsp_command::lsp_formatting_options(settings),
2008 work_done_progress_params: Default::default(),
2009 })
2010 .await
2011 .into_response()?
2012 } else {
2013 None
2014 };
2015
2016 if let Some(lsp_edits) = lsp_edits {
2017 this.update(cx, |this, cx| {
2018 this.as_local_mut().unwrap().edits_from_lsp(
2019 buffer,
2020 lsp_edits,
2021 language_server.server_id(),
2022 None,
2023 cx,
2024 )
2025 })?
2026 .await
2027 } else {
2028 Ok(Vec::with_capacity(0))
2029 }
2030 }
2031
2032 async fn format_via_external_command(
2033 buffer: &FormattableBuffer,
2034 command: &str,
2035 arguments: Option<&[String]>,
2036 cx: &mut AsyncApp,
2037 ) -> Result<Option<Diff>> {
2038 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2039 let file = File::from_dyn(buffer.file())?;
2040 let worktree = file.worktree.read(cx);
2041 let mut worktree_path = worktree.abs_path().to_path_buf();
2042 if worktree.root_entry()?.is_file() {
2043 worktree_path.pop();
2044 }
2045 Some(worktree_path)
2046 })?;
2047
2048 let mut child = util::command::new_smol_command(command);
2049
2050 if let Some(buffer_env) = buffer.env.as_ref() {
2051 child.envs(buffer_env);
2052 }
2053
2054 if let Some(working_dir_path) = working_dir_path {
2055 child.current_dir(working_dir_path);
2056 }
2057
2058 if let Some(arguments) = arguments {
2059 child.args(arguments.iter().map(|arg| {
2060 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2061 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2062 } else {
2063 arg.replace("{buffer_path}", "Untitled")
2064 }
2065 }));
2066 }
2067
2068 let mut child = child
2069 .stdin(smol::process::Stdio::piped())
2070 .stdout(smol::process::Stdio::piped())
2071 .stderr(smol::process::Stdio::piped())
2072 .spawn()?;
2073
2074 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2075 let text = buffer
2076 .handle
2077 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2078 for chunk in text.chunks() {
2079 stdin.write_all(chunk.as_bytes()).await?;
2080 }
2081 stdin.flush().await?;
2082
2083 let output = child.output().await?;
2084 anyhow::ensure!(
2085 output.status.success(),
2086 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2087 output.status.code(),
2088 String::from_utf8_lossy(&output.stdout),
2089 String::from_utf8_lossy(&output.stderr),
2090 );
2091
2092 let stdout = String::from_utf8(output.stdout)?;
2093 Ok(Some(
2094 buffer
2095 .handle
2096 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2097 .await,
2098 ))
2099 }
2100
2101 async fn try_resolve_code_action(
2102 lang_server: &LanguageServer,
2103 action: &mut CodeAction,
2104 ) -> anyhow::Result<()> {
2105 match &mut action.lsp_action {
2106 LspAction::Action(lsp_action) => {
2107 if !action.resolved
2108 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2109 && lsp_action.data.is_some()
2110 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2111 {
2112 *lsp_action = Box::new(
2113 lang_server
2114 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2115 .await
2116 .into_response()?,
2117 );
2118 }
2119 }
2120 LspAction::CodeLens(lens) => {
2121 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2122 *lens = lang_server
2123 .request::<lsp::request::CodeLensResolve>(lens.clone())
2124 .await
2125 .into_response()?;
2126 }
2127 }
2128 LspAction::Command(_) => {}
2129 }
2130
2131 action.resolved = true;
2132 anyhow::Ok(())
2133 }
2134
2135 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2136 let buffer = buffer_handle.read(cx);
2137
2138 let file = buffer.file().cloned();
2139
2140 let Some(file) = File::from_dyn(file.as_ref()) else {
2141 return;
2142 };
2143 if !file.is_local() {
2144 return;
2145 }
2146 let path = ProjectPath::from_file(file, cx);
2147 let worktree_id = file.worktree_id(cx);
2148 let language = buffer.language().cloned();
2149
2150 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2151 for (server_id, diagnostics) in
2152 diagnostics.get(file.path()).cloned().unwrap_or_default()
2153 {
2154 self.update_buffer_diagnostics(
2155 buffer_handle,
2156 server_id,
2157 None,
2158 None,
2159 diagnostics,
2160 Vec::new(),
2161 cx,
2162 )
2163 .log_err();
2164 }
2165 }
2166 let Some(language) = language else {
2167 return;
2168 };
2169 let Some(snapshot) = self
2170 .worktree_store
2171 .read(cx)
2172 .worktree_for_id(worktree_id, cx)
2173 .map(|worktree| worktree.read(cx).snapshot())
2174 else {
2175 return;
2176 };
2177 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2178
2179 for server_id in
2180 self.lsp_tree
2181 .get(path, language.name(), language.manifest(), &delegate, cx)
2182 {
2183 let server = self
2184 .language_servers
2185 .get(&server_id)
2186 .and_then(|server_state| {
2187 if let LanguageServerState::Running { server, .. } = server_state {
2188 Some(server.clone())
2189 } else {
2190 None
2191 }
2192 });
2193 let server = match server {
2194 Some(server) => server,
2195 None => continue,
2196 };
2197
2198 buffer_handle.update(cx, |buffer, cx| {
2199 buffer.set_completion_triggers(
2200 server.server_id(),
2201 server
2202 .capabilities()
2203 .completion_provider
2204 .as_ref()
2205 .and_then(|provider| {
2206 provider
2207 .trigger_characters
2208 .as_ref()
2209 .map(|characters| characters.iter().cloned().collect())
2210 })
2211 .unwrap_or_default(),
2212 cx,
2213 );
2214 });
2215 }
2216 }
2217
2218 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2219 buffer.update(cx, |buffer, cx| {
2220 let Some(language) = buffer.language() else {
2221 return;
2222 };
2223 let path = ProjectPath {
2224 worktree_id: old_file.worktree_id(cx),
2225 path: old_file.path.clone(),
2226 };
2227 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2228 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2229 buffer.set_completion_triggers(server_id, Default::default(), cx);
2230 }
2231 });
2232 }
2233
2234 fn update_buffer_diagnostics(
2235 &mut self,
2236 buffer: &Entity<Buffer>,
2237 server_id: LanguageServerId,
2238 result_id: Option<String>,
2239 version: Option<i32>,
2240 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2241 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2242 cx: &mut Context<LspStore>,
2243 ) -> Result<()> {
2244 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2245 Ordering::Equal
2246 .then_with(|| b.is_primary.cmp(&a.is_primary))
2247 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2248 .then_with(|| a.severity.cmp(&b.severity))
2249 .then_with(|| a.message.cmp(&b.message))
2250 }
2251
2252 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2253 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2254 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2255
2256 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2257 Ordering::Equal
2258 .then_with(|| a.range.start.cmp(&b.range.start))
2259 .then_with(|| b.range.end.cmp(&a.range.end))
2260 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2261 });
2262
2263 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2264
2265 let edits_since_save = std::cell::LazyCell::new(|| {
2266 let saved_version = buffer.read(cx).saved_version();
2267 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2268 });
2269
2270 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2271
2272 for (new_diagnostic, entry) in diagnostics {
2273 let start;
2274 let end;
2275 if new_diagnostic && entry.diagnostic.is_disk_based {
2276 // Some diagnostics are based on files on disk instead of buffers'
2277 // current contents. Adjust these diagnostics' ranges to reflect
2278 // any unsaved edits.
2279 // Do not alter the reused ones though, as their coordinates were stored as anchors
2280 // and were properly adjusted on reuse.
2281 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2282 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2283 } else {
2284 start = entry.range.start;
2285 end = entry.range.end;
2286 }
2287
2288 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2289 ..snapshot.clip_point_utf16(end, Bias::Right);
2290
2291 // Expand empty ranges by one codepoint
2292 if range.start == range.end {
2293 // This will be go to the next boundary when being clipped
2294 range.end.column += 1;
2295 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2296 if range.start == range.end && range.end.column > 0 {
2297 range.start.column -= 1;
2298 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2299 }
2300 }
2301
2302 sanitized_diagnostics.push(DiagnosticEntry {
2303 range,
2304 diagnostic: entry.diagnostic,
2305 });
2306 }
2307 drop(edits_since_save);
2308
2309 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2310 buffer.update(cx, |buffer, cx| {
2311 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2312 self.buffer_pull_diagnostics_result_ids
2313 .entry(server_id)
2314 .or_default()
2315 .insert(abs_path, result_id);
2316 }
2317
2318 buffer.update_diagnostics(server_id, set, cx)
2319 });
2320
2321 Ok(())
2322 }
2323
2324 fn register_language_server_for_invisible_worktree(
2325 &mut self,
2326 worktree: &Entity<Worktree>,
2327 language_server_id: LanguageServerId,
2328 cx: &mut App,
2329 ) {
2330 let worktree = worktree.read(cx);
2331 let worktree_id = worktree.id();
2332 debug_assert!(!worktree.is_visible());
2333 let Some(mut origin_seed) = self
2334 .language_server_ids
2335 .iter()
2336 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2337 else {
2338 return;
2339 };
2340 origin_seed.worktree_id = worktree_id;
2341 self.language_server_ids
2342 .entry(origin_seed)
2343 .or_insert_with(|| UnifiedLanguageServer {
2344 id: language_server_id,
2345 project_roots: Default::default(),
2346 });
2347 }
2348
2349 fn register_buffer_with_language_servers(
2350 &mut self,
2351 buffer_handle: &Entity<Buffer>,
2352 only_register_servers: HashSet<LanguageServerSelector>,
2353 cx: &mut Context<LspStore>,
2354 ) {
2355 let buffer = buffer_handle.read(cx);
2356 let buffer_id = buffer.remote_id();
2357
2358 let Some(file) = File::from_dyn(buffer.file()) else {
2359 return;
2360 };
2361 if !file.is_local() {
2362 return;
2363 }
2364
2365 let abs_path = file.abs_path(cx);
2366 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2367 return;
2368 };
2369 let initial_snapshot = buffer.text_snapshot();
2370 let worktree_id = file.worktree_id(cx);
2371
2372 let Some(language) = buffer.language().cloned() else {
2373 return;
2374 };
2375 let path: Arc<RelPath> = file
2376 .path()
2377 .parent()
2378 .map(Arc::from)
2379 .unwrap_or_else(|| file.path().clone());
2380 let Some(worktree) = self
2381 .worktree_store
2382 .read(cx)
2383 .worktree_for_id(worktree_id, cx)
2384 else {
2385 return;
2386 };
2387 let language_name = language.name();
2388 let (reused, delegate, servers) = self
2389 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2390 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2391 .unwrap_or_else(|| {
2392 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2393 let delegate: Arc<dyn ManifestDelegate> =
2394 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2395
2396 let servers = self
2397 .lsp_tree
2398 .walk(
2399 ProjectPath { worktree_id, path },
2400 language.name(),
2401 language.manifest(),
2402 &delegate,
2403 cx,
2404 )
2405 .collect::<Vec<_>>();
2406 (false, lsp_delegate, servers)
2407 });
2408 let servers_and_adapters = servers
2409 .into_iter()
2410 .filter_map(|server_node| {
2411 if reused && server_node.server_id().is_none() {
2412 return None;
2413 }
2414 if !only_register_servers.is_empty() {
2415 if let Some(server_id) = server_node.server_id()
2416 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2417 {
2418 return None;
2419 }
2420 if let Some(name) = server_node.name()
2421 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2422 {
2423 return None;
2424 }
2425 }
2426
2427 let server_id = server_node.server_id_or_init(|disposition| {
2428 let path = &disposition.path;
2429
2430 {
2431 let absolute_path = worktree.read(cx).absolutize(&path.path);
2432 let uri = absolute_path
2433 .is_dir()
2434 .then(|| Uri::from_file_path(absolute_path))
2435 .transpose();
2436
2437 let server_id = self.get_or_insert_language_server(
2438 &worktree,
2439 delegate.clone(),
2440 disposition,
2441 &language_name,
2442 cx,
2443 );
2444
2445 if let Some(state) = self.language_servers.get(&server_id)
2446 && let Ok(Some(uri)) = uri
2447 {
2448 state.add_workspace_folder(uri);
2449 };
2450 server_id
2451 }
2452 })?;
2453 let server_state = self.language_servers.get(&server_id)?;
2454 if let LanguageServerState::Running {
2455 server, adapter, ..
2456 } = server_state
2457 {
2458 Some((server.clone(), adapter.clone()))
2459 } else {
2460 None
2461 }
2462 })
2463 .collect::<Vec<_>>();
2464 for (server, adapter) in servers_and_adapters {
2465 buffer_handle.update(cx, |buffer, cx| {
2466 buffer.set_completion_triggers(
2467 server.server_id(),
2468 server
2469 .capabilities()
2470 .completion_provider
2471 .as_ref()
2472 .and_then(|provider| {
2473 provider
2474 .trigger_characters
2475 .as_ref()
2476 .map(|characters| characters.iter().cloned().collect())
2477 })
2478 .unwrap_or_default(),
2479 cx,
2480 );
2481 });
2482
2483 let snapshot = LspBufferSnapshot {
2484 version: 0,
2485 snapshot: initial_snapshot.clone(),
2486 };
2487
2488 let mut registered = false;
2489 self.buffer_snapshots
2490 .entry(buffer_id)
2491 .or_default()
2492 .entry(server.server_id())
2493 .or_insert_with(|| {
2494 registered = true;
2495 server.register_buffer(
2496 uri.clone(),
2497 adapter.language_id(&language.name()),
2498 0,
2499 initial_snapshot.text(),
2500 );
2501
2502 vec![snapshot]
2503 });
2504
2505 self.buffers_opened_in_servers
2506 .entry(buffer_id)
2507 .or_default()
2508 .insert(server.server_id());
2509 if registered {
2510 cx.emit(LspStoreEvent::LanguageServerUpdate {
2511 language_server_id: server.server_id(),
2512 name: None,
2513 message: proto::update_language_server::Variant::RegisteredForBuffer(
2514 proto::RegisteredForBuffer {
2515 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2516 buffer_id: buffer_id.to_proto(),
2517 },
2518 ),
2519 });
2520 }
2521 }
2522 }
2523
2524 fn reuse_existing_language_server<'lang_name>(
2525 &self,
2526 server_tree: &LanguageServerTree,
2527 worktree: &Entity<Worktree>,
2528 language_name: &'lang_name LanguageName,
2529 cx: &mut App,
2530 ) -> Option<(
2531 Arc<LocalLspAdapterDelegate>,
2532 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2533 )> {
2534 if worktree.read(cx).is_visible() {
2535 return None;
2536 }
2537
2538 let worktree_store = self.worktree_store.read(cx);
2539 let servers = server_tree
2540 .instances
2541 .iter()
2542 .filter(|(worktree_id, _)| {
2543 worktree_store
2544 .worktree_for_id(**worktree_id, cx)
2545 .is_some_and(|worktree| worktree.read(cx).is_visible())
2546 })
2547 .flat_map(|(worktree_id, servers)| {
2548 servers
2549 .roots
2550 .iter()
2551 .flat_map(|(_, language_servers)| language_servers)
2552 .map(move |(_, (server_node, server_languages))| {
2553 (worktree_id, server_node, server_languages)
2554 })
2555 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2556 .map(|(worktree_id, server_node, _)| {
2557 (
2558 *worktree_id,
2559 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2560 )
2561 })
2562 })
2563 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2564 acc.entry(worktree_id)
2565 .or_insert_with(Vec::new)
2566 .push(server_node);
2567 acc
2568 })
2569 .into_values()
2570 .max_by_key(|servers| servers.len())?;
2571
2572 let worktree_id = worktree.read(cx).id();
2573 let apply = move |tree: &mut LanguageServerTree| {
2574 for server_node in &servers {
2575 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2576 }
2577 servers
2578 };
2579
2580 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2581 Some((delegate, apply))
2582 }
2583
2584 pub(crate) fn unregister_old_buffer_from_language_servers(
2585 &mut self,
2586 buffer: &Entity<Buffer>,
2587 old_file: &File,
2588 cx: &mut App,
2589 ) {
2590 let old_path = match old_file.as_local() {
2591 Some(local) => local.abs_path(cx),
2592 None => return,
2593 };
2594
2595 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2596 debug_panic!("{old_path:?} is not parseable as an URI");
2597 return;
2598 };
2599 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2600 }
2601
2602 pub(crate) fn unregister_buffer_from_language_servers(
2603 &mut self,
2604 buffer: &Entity<Buffer>,
2605 file_url: &lsp::Uri,
2606 cx: &mut App,
2607 ) {
2608 buffer.update(cx, |buffer, cx| {
2609 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2610
2611 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2612 language_server.unregister_buffer(file_url.clone());
2613 }
2614 });
2615 }
2616
2617 fn buffer_snapshot_for_lsp_version(
2618 &mut self,
2619 buffer: &Entity<Buffer>,
2620 server_id: LanguageServerId,
2621 version: Option<i32>,
2622 cx: &App,
2623 ) -> Result<TextBufferSnapshot> {
2624 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2625
2626 if let Some(version) = version {
2627 let buffer_id = buffer.read(cx).remote_id();
2628 let snapshots = if let Some(snapshots) = self
2629 .buffer_snapshots
2630 .get_mut(&buffer_id)
2631 .and_then(|m| m.get_mut(&server_id))
2632 {
2633 snapshots
2634 } else if version == 0 {
2635 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2636 // We detect this case and treat it as if the version was `None`.
2637 return Ok(buffer.read(cx).text_snapshot());
2638 } else {
2639 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2640 };
2641
2642 let found_snapshot = snapshots
2643 .binary_search_by_key(&version, |e| e.version)
2644 .map(|ix| snapshots[ix].snapshot.clone())
2645 .map_err(|_| {
2646 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2647 })?;
2648
2649 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2650 Ok(found_snapshot)
2651 } else {
2652 Ok((buffer.read(cx)).text_snapshot())
2653 }
2654 }
2655
2656 async fn get_server_code_actions_from_action_kinds(
2657 lsp_store: &WeakEntity<LspStore>,
2658 language_server_id: LanguageServerId,
2659 code_action_kinds: Vec<lsp::CodeActionKind>,
2660 buffer: &Entity<Buffer>,
2661 cx: &mut AsyncApp,
2662 ) -> Result<Vec<CodeAction>> {
2663 let actions = lsp_store
2664 .update(cx, move |this, cx| {
2665 let request = GetCodeActions {
2666 range: text::Anchor::MIN..text::Anchor::MAX,
2667 kinds: Some(code_action_kinds),
2668 };
2669 let server = LanguageServerToQuery::Other(language_server_id);
2670 this.request_lsp(buffer.clone(), server, request, cx)
2671 })?
2672 .await?;
2673 Ok(actions)
2674 }
2675
2676 pub async fn execute_code_actions_on_server(
2677 lsp_store: &WeakEntity<LspStore>,
2678 language_server: &Arc<LanguageServer>,
2679
2680 actions: Vec<CodeAction>,
2681 push_to_history: bool,
2682 project_transaction: &mut ProjectTransaction,
2683 cx: &mut AsyncApp,
2684 ) -> anyhow::Result<()> {
2685 for mut action in actions {
2686 Self::try_resolve_code_action(language_server, &mut action)
2687 .await
2688 .context("resolving a formatting code action")?;
2689
2690 if let Some(edit) = action.lsp_action.edit() {
2691 if edit.changes.is_none() && edit.document_changes.is_none() {
2692 continue;
2693 }
2694
2695 let new = Self::deserialize_workspace_edit(
2696 lsp_store.upgrade().context("project dropped")?,
2697 edit.clone(),
2698 push_to_history,
2699 language_server.clone(),
2700 cx,
2701 )
2702 .await?;
2703 project_transaction.0.extend(new.0);
2704 }
2705
2706 if let Some(command) = action.lsp_action.command() {
2707 let server_capabilities = language_server.capabilities();
2708 let available_commands = server_capabilities
2709 .execute_command_provider
2710 .as_ref()
2711 .map(|options| options.commands.as_slice())
2712 .unwrap_or_default();
2713 if available_commands.contains(&command.command) {
2714 lsp_store.update(cx, |lsp_store, _| {
2715 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2716 mode.last_workspace_edits_by_language_server
2717 .remove(&language_server.server_id());
2718 }
2719 })?;
2720
2721 language_server
2722 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2723 command: command.command.clone(),
2724 arguments: command.arguments.clone().unwrap_or_default(),
2725 ..Default::default()
2726 })
2727 .await
2728 .into_response()
2729 .context("execute command")?;
2730
2731 lsp_store.update(cx, |this, _| {
2732 if let LspStoreMode::Local(mode) = &mut this.mode {
2733 project_transaction.0.extend(
2734 mode.last_workspace_edits_by_language_server
2735 .remove(&language_server.server_id())
2736 .unwrap_or_default()
2737 .0,
2738 )
2739 }
2740 })?;
2741 } else {
2742 log::warn!(
2743 "Cannot execute a command {} not listed in the language server capabilities",
2744 command.command
2745 )
2746 }
2747 }
2748 }
2749 Ok(())
2750 }
2751
2752 pub async fn deserialize_text_edits(
2753 this: Entity<LspStore>,
2754 buffer_to_edit: Entity<Buffer>,
2755 edits: Vec<lsp::TextEdit>,
2756 push_to_history: bool,
2757 _: Arc<CachedLspAdapter>,
2758 language_server: Arc<LanguageServer>,
2759 cx: &mut AsyncApp,
2760 ) -> Result<Option<Transaction>> {
2761 let edits = this
2762 .update(cx, |this, cx| {
2763 this.as_local_mut().unwrap().edits_from_lsp(
2764 &buffer_to_edit,
2765 edits,
2766 language_server.server_id(),
2767 None,
2768 cx,
2769 )
2770 })?
2771 .await?;
2772
2773 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2774 buffer.finalize_last_transaction();
2775 buffer.start_transaction();
2776 for (range, text) in edits {
2777 buffer.edit([(range, text)], None, cx);
2778 }
2779
2780 if buffer.end_transaction(cx).is_some() {
2781 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2782 if !push_to_history {
2783 buffer.forget_transaction(transaction.id);
2784 }
2785 Some(transaction)
2786 } else {
2787 None
2788 }
2789 })?;
2790
2791 Ok(transaction)
2792 }
2793
2794 #[allow(clippy::type_complexity)]
2795 pub(crate) fn edits_from_lsp(
2796 &mut self,
2797 buffer: &Entity<Buffer>,
2798 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2799 server_id: LanguageServerId,
2800 version: Option<i32>,
2801 cx: &mut Context<LspStore>,
2802 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2803 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2804 cx.background_spawn(async move {
2805 let snapshot = snapshot?;
2806 let mut lsp_edits = lsp_edits
2807 .into_iter()
2808 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2809 .collect::<Vec<_>>();
2810
2811 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2812
2813 let mut lsp_edits = lsp_edits.into_iter().peekable();
2814 let mut edits = Vec::new();
2815 while let Some((range, mut new_text)) = lsp_edits.next() {
2816 // Clip invalid ranges provided by the language server.
2817 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2818 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2819
2820 // Combine any LSP edits that are adjacent.
2821 //
2822 // Also, combine LSP edits that are separated from each other by only
2823 // a newline. This is important because for some code actions,
2824 // Rust-analyzer rewrites the entire buffer via a series of edits that
2825 // are separated by unchanged newline characters.
2826 //
2827 // In order for the diffing logic below to work properly, any edits that
2828 // cancel each other out must be combined into one.
2829 while let Some((next_range, next_text)) = lsp_edits.peek() {
2830 if next_range.start.0 > range.end {
2831 if next_range.start.0.row > range.end.row + 1
2832 || next_range.start.0.column > 0
2833 || snapshot.clip_point_utf16(
2834 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2835 Bias::Left,
2836 ) > range.end
2837 {
2838 break;
2839 }
2840 new_text.push('\n');
2841 }
2842 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2843 new_text.push_str(next_text);
2844 lsp_edits.next();
2845 }
2846
2847 // For multiline edits, perform a diff of the old and new text so that
2848 // we can identify the changes more precisely, preserving the locations
2849 // of any anchors positioned in the unchanged regions.
2850 if range.end.row > range.start.row {
2851 let offset = range.start.to_offset(&snapshot);
2852 let old_text = snapshot.text_for_range(range).collect::<String>();
2853 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2854 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2855 (
2856 snapshot.anchor_after(offset + range.start)
2857 ..snapshot.anchor_before(offset + range.end),
2858 replacement,
2859 )
2860 }));
2861 } else if range.end == range.start {
2862 let anchor = snapshot.anchor_after(range.start);
2863 edits.push((anchor..anchor, new_text.into()));
2864 } else {
2865 let edit_start = snapshot.anchor_after(range.start);
2866 let edit_end = snapshot.anchor_before(range.end);
2867 edits.push((edit_start..edit_end, new_text.into()));
2868 }
2869 }
2870
2871 Ok(edits)
2872 })
2873 }
2874
2875 pub(crate) async fn deserialize_workspace_edit(
2876 this: Entity<LspStore>,
2877 edit: lsp::WorkspaceEdit,
2878 push_to_history: bool,
2879 language_server: Arc<LanguageServer>,
2880 cx: &mut AsyncApp,
2881 ) -> Result<ProjectTransaction> {
2882 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2883
2884 let mut operations = Vec::new();
2885 if let Some(document_changes) = edit.document_changes {
2886 match document_changes {
2887 lsp::DocumentChanges::Edits(edits) => {
2888 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2889 }
2890 lsp::DocumentChanges::Operations(ops) => operations = ops,
2891 }
2892 } else if let Some(changes) = edit.changes {
2893 operations.extend(changes.into_iter().map(|(uri, edits)| {
2894 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2895 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2896 uri,
2897 version: None,
2898 },
2899 edits: edits.into_iter().map(Edit::Plain).collect(),
2900 })
2901 }));
2902 }
2903
2904 let mut project_transaction = ProjectTransaction::default();
2905 for operation in operations {
2906 match operation {
2907 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2908 let abs_path = op
2909 .uri
2910 .to_file_path()
2911 .map_err(|()| anyhow!("can't convert URI to path"))?;
2912
2913 if let Some(parent_path) = abs_path.parent() {
2914 fs.create_dir(parent_path).await?;
2915 }
2916 if abs_path.ends_with("/") {
2917 fs.create_dir(&abs_path).await?;
2918 } else {
2919 fs.create_file(
2920 &abs_path,
2921 op.options
2922 .map(|options| fs::CreateOptions {
2923 overwrite: options.overwrite.unwrap_or(false),
2924 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2925 })
2926 .unwrap_or_default(),
2927 )
2928 .await?;
2929 }
2930 }
2931
2932 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2933 let source_abs_path = op
2934 .old_uri
2935 .to_file_path()
2936 .map_err(|()| anyhow!("can't convert URI to path"))?;
2937 let target_abs_path = op
2938 .new_uri
2939 .to_file_path()
2940 .map_err(|()| anyhow!("can't convert URI to path"))?;
2941 fs.rename(
2942 &source_abs_path,
2943 &target_abs_path,
2944 op.options
2945 .map(|options| fs::RenameOptions {
2946 overwrite: options.overwrite.unwrap_or(false),
2947 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2948 })
2949 .unwrap_or_default(),
2950 )
2951 .await?;
2952 }
2953
2954 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2955 let abs_path = op
2956 .uri
2957 .to_file_path()
2958 .map_err(|()| anyhow!("can't convert URI to path"))?;
2959 let options = op
2960 .options
2961 .map(|options| fs::RemoveOptions {
2962 recursive: options.recursive.unwrap_or(false),
2963 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
2964 })
2965 .unwrap_or_default();
2966 if abs_path.ends_with("/") {
2967 fs.remove_dir(&abs_path, options).await?;
2968 } else {
2969 fs.remove_file(&abs_path, options).await?;
2970 }
2971 }
2972
2973 lsp::DocumentChangeOperation::Edit(op) => {
2974 let buffer_to_edit = this
2975 .update(cx, |this, cx| {
2976 this.open_local_buffer_via_lsp(
2977 op.text_document.uri.clone(),
2978 language_server.server_id(),
2979 cx,
2980 )
2981 })?
2982 .await?;
2983
2984 let edits = this
2985 .update(cx, |this, cx| {
2986 let path = buffer_to_edit.read(cx).project_path(cx);
2987 let active_entry = this.active_entry;
2988 let is_active_entry = path.is_some_and(|project_path| {
2989 this.worktree_store
2990 .read(cx)
2991 .entry_for_path(&project_path, cx)
2992 .is_some_and(|entry| Some(entry.id) == active_entry)
2993 });
2994 let local = this.as_local_mut().unwrap();
2995
2996 let (mut edits, mut snippet_edits) = (vec![], vec![]);
2997 for edit in op.edits {
2998 match edit {
2999 Edit::Plain(edit) => {
3000 if !edits.contains(&edit) {
3001 edits.push(edit)
3002 }
3003 }
3004 Edit::Annotated(edit) => {
3005 if !edits.contains(&edit.text_edit) {
3006 edits.push(edit.text_edit)
3007 }
3008 }
3009 Edit::Snippet(edit) => {
3010 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3011 else {
3012 continue;
3013 };
3014
3015 if is_active_entry {
3016 snippet_edits.push((edit.range, snippet));
3017 } else {
3018 // Since this buffer is not focused, apply a normal edit.
3019 let new_edit = TextEdit {
3020 range: edit.range,
3021 new_text: snippet.text,
3022 };
3023 if !edits.contains(&new_edit) {
3024 edits.push(new_edit);
3025 }
3026 }
3027 }
3028 }
3029 }
3030 if !snippet_edits.is_empty() {
3031 let buffer_id = buffer_to_edit.read(cx).remote_id();
3032 let version = if let Some(buffer_version) = op.text_document.version
3033 {
3034 local
3035 .buffer_snapshot_for_lsp_version(
3036 &buffer_to_edit,
3037 language_server.server_id(),
3038 Some(buffer_version),
3039 cx,
3040 )
3041 .ok()
3042 .map(|snapshot| snapshot.version)
3043 } else {
3044 Some(buffer_to_edit.read(cx).saved_version().clone())
3045 };
3046
3047 let most_recent_edit =
3048 version.and_then(|version| version.most_recent());
3049 // Check if the edit that triggered that edit has been made by this participant.
3050
3051 if let Some(most_recent_edit) = most_recent_edit {
3052 cx.emit(LspStoreEvent::SnippetEdit {
3053 buffer_id,
3054 edits: snippet_edits,
3055 most_recent_edit,
3056 });
3057 }
3058 }
3059
3060 local.edits_from_lsp(
3061 &buffer_to_edit,
3062 edits,
3063 language_server.server_id(),
3064 op.text_document.version,
3065 cx,
3066 )
3067 })?
3068 .await?;
3069
3070 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3071 buffer.finalize_last_transaction();
3072 buffer.start_transaction();
3073 for (range, text) in edits {
3074 buffer.edit([(range, text)], None, cx);
3075 }
3076
3077 buffer.end_transaction(cx).and_then(|transaction_id| {
3078 if push_to_history {
3079 buffer.finalize_last_transaction();
3080 buffer.get_transaction(transaction_id).cloned()
3081 } else {
3082 buffer.forget_transaction(transaction_id)
3083 }
3084 })
3085 })?;
3086 if let Some(transaction) = transaction {
3087 project_transaction.0.insert(buffer_to_edit, transaction);
3088 }
3089 }
3090 }
3091 }
3092
3093 Ok(project_transaction)
3094 }
3095
3096 async fn on_lsp_workspace_edit(
3097 this: WeakEntity<LspStore>,
3098 params: lsp::ApplyWorkspaceEditParams,
3099 server_id: LanguageServerId,
3100 cx: &mut AsyncApp,
3101 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3102 let this = this.upgrade().context("project project closed")?;
3103 let language_server = this
3104 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3105 .context("language server not found")?;
3106 let transaction = Self::deserialize_workspace_edit(
3107 this.clone(),
3108 params.edit,
3109 true,
3110 language_server.clone(),
3111 cx,
3112 )
3113 .await
3114 .log_err();
3115 this.update(cx, |this, _| {
3116 if let Some(transaction) = transaction {
3117 this.as_local_mut()
3118 .unwrap()
3119 .last_workspace_edits_by_language_server
3120 .insert(server_id, transaction);
3121 }
3122 })?;
3123 Ok(lsp::ApplyWorkspaceEditResponse {
3124 applied: true,
3125 failed_change: None,
3126 failure_reason: None,
3127 })
3128 }
3129
3130 fn remove_worktree(
3131 &mut self,
3132 id_to_remove: WorktreeId,
3133 cx: &mut Context<LspStore>,
3134 ) -> Vec<LanguageServerId> {
3135 self.diagnostics.remove(&id_to_remove);
3136 self.prettier_store.update(cx, |prettier_store, cx| {
3137 prettier_store.remove_worktree(id_to_remove, cx);
3138 });
3139
3140 let mut servers_to_remove = BTreeSet::default();
3141 let mut servers_to_preserve = HashSet::default();
3142 for (seed, state) in &self.language_server_ids {
3143 if seed.worktree_id == id_to_remove {
3144 servers_to_remove.insert(state.id);
3145 } else {
3146 servers_to_preserve.insert(state.id);
3147 }
3148 }
3149 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3150 self.language_server_ids
3151 .retain(|_, state| !servers_to_remove.contains(&state.id));
3152 for server_id_to_remove in &servers_to_remove {
3153 self.language_server_watched_paths
3154 .remove(server_id_to_remove);
3155 self.language_server_paths_watched_for_rename
3156 .remove(server_id_to_remove);
3157 self.last_workspace_edits_by_language_server
3158 .remove(server_id_to_remove);
3159 self.language_servers.remove(server_id_to_remove);
3160 self.buffer_pull_diagnostics_result_ids
3161 .remove(server_id_to_remove);
3162 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3163 buffer_servers.remove(server_id_to_remove);
3164 }
3165 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3166 }
3167 servers_to_remove.into_iter().collect()
3168 }
3169
3170 fn rebuild_watched_paths_inner<'a>(
3171 &'a self,
3172 language_server_id: LanguageServerId,
3173 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3174 cx: &mut Context<LspStore>,
3175 ) -> LanguageServerWatchedPathsBuilder {
3176 let worktrees = self
3177 .worktree_store
3178 .read(cx)
3179 .worktrees()
3180 .filter_map(|worktree| {
3181 self.language_servers_for_worktree(worktree.read(cx).id())
3182 .find(|server| server.server_id() == language_server_id)
3183 .map(|_| worktree)
3184 })
3185 .collect::<Vec<_>>();
3186
3187 let mut worktree_globs = HashMap::default();
3188 let mut abs_globs = HashMap::default();
3189 log::trace!(
3190 "Processing new watcher paths for language server with id {}",
3191 language_server_id
3192 );
3193
3194 for watcher in watchers {
3195 if let Some((worktree, literal_prefix, pattern)) =
3196 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3197 {
3198 worktree.update(cx, |worktree, _| {
3199 if let Some((tree, glob)) =
3200 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3201 {
3202 tree.add_path_prefix_to_scan(literal_prefix);
3203 worktree_globs
3204 .entry(tree.id())
3205 .or_insert_with(GlobSetBuilder::new)
3206 .add(glob);
3207 }
3208 });
3209 } else {
3210 let (path, pattern) = match &watcher.glob_pattern {
3211 lsp::GlobPattern::String(s) => {
3212 let watcher_path = SanitizedPath::new(s);
3213 let path = glob_literal_prefix(watcher_path.as_path());
3214 let pattern = watcher_path
3215 .as_path()
3216 .strip_prefix(&path)
3217 .map(|p| p.to_string_lossy().into_owned())
3218 .unwrap_or_else(|e| {
3219 debug_panic!(
3220 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3221 s,
3222 path.display(),
3223 e
3224 );
3225 watcher_path.as_path().to_string_lossy().into_owned()
3226 });
3227 (path, pattern)
3228 }
3229 lsp::GlobPattern::Relative(rp) => {
3230 let Ok(mut base_uri) = match &rp.base_uri {
3231 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3232 lsp::OneOf::Right(base_uri) => base_uri,
3233 }
3234 .to_file_path() else {
3235 continue;
3236 };
3237
3238 let path = glob_literal_prefix(Path::new(&rp.pattern));
3239 let pattern = Path::new(&rp.pattern)
3240 .strip_prefix(&path)
3241 .map(|p| p.to_string_lossy().into_owned())
3242 .unwrap_or_else(|e| {
3243 debug_panic!(
3244 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3245 rp.pattern,
3246 path.display(),
3247 e
3248 );
3249 rp.pattern.clone()
3250 });
3251 base_uri.push(path);
3252 (base_uri, pattern)
3253 }
3254 };
3255
3256 if let Some(glob) = Glob::new(&pattern).log_err() {
3257 if !path
3258 .components()
3259 .any(|c| matches!(c, path::Component::Normal(_)))
3260 {
3261 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3262 // rather than adding a new watcher for `/`.
3263 for worktree in &worktrees {
3264 worktree_globs
3265 .entry(worktree.read(cx).id())
3266 .or_insert_with(GlobSetBuilder::new)
3267 .add(glob.clone());
3268 }
3269 } else {
3270 abs_globs
3271 .entry(path.into())
3272 .or_insert_with(GlobSetBuilder::new)
3273 .add(glob);
3274 }
3275 }
3276 }
3277 }
3278
3279 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3280 for (worktree_id, builder) in worktree_globs {
3281 if let Ok(globset) = builder.build() {
3282 watch_builder.watch_worktree(worktree_id, globset);
3283 }
3284 }
3285 for (abs_path, builder) in abs_globs {
3286 if let Ok(globset) = builder.build() {
3287 watch_builder.watch_abs_path(abs_path, globset);
3288 }
3289 }
3290 watch_builder
3291 }
3292
3293 fn worktree_and_path_for_file_watcher(
3294 worktrees: &[Entity<Worktree>],
3295 watcher: &FileSystemWatcher,
3296 cx: &App,
3297 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3298 worktrees.iter().find_map(|worktree| {
3299 let tree = worktree.read(cx);
3300 let worktree_root_path = tree.abs_path();
3301 let path_style = tree.path_style();
3302 match &watcher.glob_pattern {
3303 lsp::GlobPattern::String(s) => {
3304 let watcher_path = SanitizedPath::new(s);
3305 let relative = watcher_path
3306 .as_path()
3307 .strip_prefix(&worktree_root_path)
3308 .ok()?;
3309 let literal_prefix = glob_literal_prefix(relative);
3310 Some((
3311 worktree.clone(),
3312 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3313 relative.to_string_lossy().into_owned(),
3314 ))
3315 }
3316 lsp::GlobPattern::Relative(rp) => {
3317 let base_uri = match &rp.base_uri {
3318 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3319 lsp::OneOf::Right(base_uri) => base_uri,
3320 }
3321 .to_file_path()
3322 .ok()?;
3323 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3324 let mut literal_prefix = relative.to_owned();
3325 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3326 Some((
3327 worktree.clone(),
3328 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3329 rp.pattern.clone(),
3330 ))
3331 }
3332 }
3333 })
3334 }
3335
3336 fn rebuild_watched_paths(
3337 &mut self,
3338 language_server_id: LanguageServerId,
3339 cx: &mut Context<LspStore>,
3340 ) {
3341 let Some(registrations) = self
3342 .language_server_dynamic_registrations
3343 .get(&language_server_id)
3344 else {
3345 return;
3346 };
3347
3348 let watch_builder = self.rebuild_watched_paths_inner(
3349 language_server_id,
3350 registrations.did_change_watched_files.values().flatten(),
3351 cx,
3352 );
3353 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3354 self.language_server_watched_paths
3355 .insert(language_server_id, watcher);
3356
3357 cx.notify();
3358 }
3359
3360 fn on_lsp_did_change_watched_files(
3361 &mut self,
3362 language_server_id: LanguageServerId,
3363 registration_id: &str,
3364 params: DidChangeWatchedFilesRegistrationOptions,
3365 cx: &mut Context<LspStore>,
3366 ) {
3367 let registrations = self
3368 .language_server_dynamic_registrations
3369 .entry(language_server_id)
3370 .or_default();
3371
3372 registrations
3373 .did_change_watched_files
3374 .insert(registration_id.to_string(), params.watchers);
3375
3376 self.rebuild_watched_paths(language_server_id, cx);
3377 }
3378
3379 fn on_lsp_unregister_did_change_watched_files(
3380 &mut self,
3381 language_server_id: LanguageServerId,
3382 registration_id: &str,
3383 cx: &mut Context<LspStore>,
3384 ) {
3385 let registrations = self
3386 .language_server_dynamic_registrations
3387 .entry(language_server_id)
3388 .or_default();
3389
3390 if registrations
3391 .did_change_watched_files
3392 .remove(registration_id)
3393 .is_some()
3394 {
3395 log::info!(
3396 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3397 language_server_id,
3398 registration_id
3399 );
3400 } else {
3401 log::warn!(
3402 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3403 language_server_id,
3404 registration_id
3405 );
3406 }
3407
3408 self.rebuild_watched_paths(language_server_id, cx);
3409 }
3410
3411 async fn initialization_options_for_adapter(
3412 adapter: Arc<dyn LspAdapter>,
3413 delegate: &Arc<dyn LspAdapterDelegate>,
3414 ) -> Result<Option<serde_json::Value>> {
3415 let Some(mut initialization_config) =
3416 adapter.clone().initialization_options(delegate).await?
3417 else {
3418 return Ok(None);
3419 };
3420
3421 for other_adapter in delegate.registered_lsp_adapters() {
3422 if other_adapter.name() == adapter.name() {
3423 continue;
3424 }
3425 if let Ok(Some(target_config)) = other_adapter
3426 .clone()
3427 .additional_initialization_options(adapter.name(), delegate)
3428 .await
3429 {
3430 merge_json_value_into(target_config.clone(), &mut initialization_config);
3431 }
3432 }
3433
3434 Ok(Some(initialization_config))
3435 }
3436
3437 async fn workspace_configuration_for_adapter(
3438 adapter: Arc<dyn LspAdapter>,
3439 delegate: &Arc<dyn LspAdapterDelegate>,
3440 toolchain: Option<Toolchain>,
3441 cx: &mut AsyncApp,
3442 ) -> Result<serde_json::Value> {
3443 let mut workspace_config = adapter
3444 .clone()
3445 .workspace_configuration(delegate, toolchain, cx)
3446 .await?;
3447
3448 for other_adapter in delegate.registered_lsp_adapters() {
3449 if other_adapter.name() == adapter.name() {
3450 continue;
3451 }
3452 if let Ok(Some(target_config)) = other_adapter
3453 .clone()
3454 .additional_workspace_configuration(adapter.name(), delegate, cx)
3455 .await
3456 {
3457 merge_json_value_into(target_config.clone(), &mut workspace_config);
3458 }
3459 }
3460
3461 Ok(workspace_config)
3462 }
3463
3464 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3465 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3466 Some(server.clone())
3467 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3468 Some(Arc::clone(server))
3469 } else {
3470 None
3471 }
3472 }
3473}
3474
3475fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3476 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3477 cx.emit(LspStoreEvent::LanguageServerUpdate {
3478 language_server_id: server.server_id(),
3479 name: Some(server.name()),
3480 message: proto::update_language_server::Variant::MetadataUpdated(
3481 proto::ServerMetadataUpdated {
3482 capabilities: Some(capabilities),
3483 },
3484 ),
3485 });
3486 }
3487}
3488
3489#[derive(Debug)]
3490pub struct FormattableBuffer {
3491 handle: Entity<Buffer>,
3492 abs_path: Option<PathBuf>,
3493 env: Option<HashMap<String, String>>,
3494 ranges: Option<Vec<Range<Anchor>>>,
3495}
3496
3497pub struct RemoteLspStore {
3498 upstream_client: Option<AnyProtoClient>,
3499 upstream_project_id: u64,
3500}
3501
3502pub(crate) enum LspStoreMode {
3503 Local(LocalLspStore), // ssh host and collab host
3504 Remote(RemoteLspStore), // collab guest
3505}
3506
3507impl LspStoreMode {
3508 fn is_local(&self) -> bool {
3509 matches!(self, LspStoreMode::Local(_))
3510 }
3511}
3512
3513pub struct LspStore {
3514 mode: LspStoreMode,
3515 last_formatting_failure: Option<String>,
3516 downstream_client: Option<(AnyProtoClient, u64)>,
3517 nonce: u128,
3518 buffer_store: Entity<BufferStore>,
3519 worktree_store: Entity<WorktreeStore>,
3520 pub languages: Arc<LanguageRegistry>,
3521 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3522 active_entry: Option<ProjectEntryId>,
3523 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3524 _maintain_buffer_languages: Task<()>,
3525 diagnostic_summaries:
3526 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3527 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3528 lsp_data: HashMap<BufferId, BufferLspData>,
3529 next_hint_id: Arc<AtomicUsize>,
3530}
3531
3532#[derive(Debug)]
3533pub struct BufferLspData {
3534 buffer_version: Global,
3535 document_colors: Option<DocumentColorData>,
3536 code_lens: Option<CodeLensData>,
3537 inlay_hints: BufferInlayHints,
3538 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3539 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3540}
3541
3542#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3543struct LspKey {
3544 request_type: TypeId,
3545 server_queried: Option<LanguageServerId>,
3546}
3547
3548impl BufferLspData {
3549 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3550 Self {
3551 buffer_version: buffer.read(cx).version(),
3552 document_colors: None,
3553 code_lens: None,
3554 inlay_hints: BufferInlayHints::new(buffer, cx),
3555 lsp_requests: HashMap::default(),
3556 chunk_lsp_requests: HashMap::default(),
3557 }
3558 }
3559
3560 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3561 if let Some(document_colors) = &mut self.document_colors {
3562 document_colors.colors.remove(&for_server);
3563 document_colors.cache_version += 1;
3564 }
3565
3566 if let Some(code_lens) = &mut self.code_lens {
3567 code_lens.lens.remove(&for_server);
3568 }
3569
3570 self.inlay_hints.remove_server_data(for_server);
3571 }
3572
3573 #[cfg(any(test, feature = "test-support"))]
3574 pub fn inlay_hints(&self) -> &BufferInlayHints {
3575 &self.inlay_hints
3576 }
3577}
3578
3579#[derive(Debug, Default, Clone)]
3580pub struct DocumentColors {
3581 pub colors: HashSet<DocumentColor>,
3582 pub cache_version: Option<usize>,
3583}
3584
3585type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3586type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3587
3588#[derive(Debug, Default)]
3589struct DocumentColorData {
3590 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3591 cache_version: usize,
3592 colors_update: Option<(Global, DocumentColorTask)>,
3593}
3594
3595#[derive(Debug, Default)]
3596struct CodeLensData {
3597 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3598 update: Option<(Global, CodeLensTask)>,
3599}
3600
3601#[derive(Debug)]
3602pub enum LspStoreEvent {
3603 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3604 LanguageServerRemoved(LanguageServerId),
3605 LanguageServerUpdate {
3606 language_server_id: LanguageServerId,
3607 name: Option<LanguageServerName>,
3608 message: proto::update_language_server::Variant,
3609 },
3610 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3611 LanguageServerPrompt(LanguageServerPromptRequest),
3612 LanguageDetected {
3613 buffer: Entity<Buffer>,
3614 new_language: Option<Arc<Language>>,
3615 },
3616 Notification(String),
3617 RefreshInlayHints(LanguageServerId),
3618 RefreshCodeLens,
3619 DiagnosticsUpdated {
3620 server_id: LanguageServerId,
3621 paths: Vec<ProjectPath>,
3622 },
3623 DiskBasedDiagnosticsStarted {
3624 language_server_id: LanguageServerId,
3625 },
3626 DiskBasedDiagnosticsFinished {
3627 language_server_id: LanguageServerId,
3628 },
3629 SnippetEdit {
3630 buffer_id: BufferId,
3631 edits: Vec<(lsp::Range, Snippet)>,
3632 most_recent_edit: clock::Lamport,
3633 },
3634}
3635
3636#[derive(Clone, Debug, Serialize)]
3637pub struct LanguageServerStatus {
3638 pub name: LanguageServerName,
3639 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3640 pub has_pending_diagnostic_updates: bool,
3641 progress_tokens: HashSet<String>,
3642 pub worktree: Option<WorktreeId>,
3643}
3644
3645#[derive(Clone, Debug)]
3646struct CoreSymbol {
3647 pub language_server_name: LanguageServerName,
3648 pub source_worktree_id: WorktreeId,
3649 pub source_language_server_id: LanguageServerId,
3650 pub path: SymbolLocation,
3651 pub name: String,
3652 pub kind: lsp::SymbolKind,
3653 pub range: Range<Unclipped<PointUtf16>>,
3654}
3655
3656#[derive(Clone, Debug, PartialEq, Eq)]
3657pub enum SymbolLocation {
3658 InProject(ProjectPath),
3659 OutsideProject {
3660 abs_path: Arc<Path>,
3661 signature: [u8; 32],
3662 },
3663}
3664
3665impl SymbolLocation {
3666 fn file_name(&self) -> Option<&str> {
3667 match self {
3668 Self::InProject(path) => path.path.file_name(),
3669 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3670 }
3671 }
3672}
3673
3674impl LspStore {
3675 pub fn init(client: &AnyProtoClient) {
3676 client.add_entity_request_handler(Self::handle_lsp_query);
3677 client.add_entity_message_handler(Self::handle_lsp_query_response);
3678 client.add_entity_request_handler(Self::handle_restart_language_servers);
3679 client.add_entity_request_handler(Self::handle_stop_language_servers);
3680 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3681 client.add_entity_message_handler(Self::handle_start_language_server);
3682 client.add_entity_message_handler(Self::handle_update_language_server);
3683 client.add_entity_message_handler(Self::handle_language_server_log);
3684 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3685 client.add_entity_request_handler(Self::handle_format_buffers);
3686 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3687 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3688 client.add_entity_request_handler(Self::handle_apply_code_action);
3689 client.add_entity_request_handler(Self::handle_get_project_symbols);
3690 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3691 client.add_entity_request_handler(Self::handle_get_color_presentation);
3692 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3693 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3694 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3695 client.add_entity_request_handler(Self::handle_on_type_formatting);
3696 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3697 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3698 client.add_entity_request_handler(Self::handle_rename_project_entry);
3699 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3700 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3701 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3702 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3703 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3704 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3705 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3706
3707 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3708 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3709 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3710 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3711 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3712 client.add_entity_request_handler(
3713 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3714 );
3715 client.add_entity_request_handler(
3716 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3717 );
3718 client.add_entity_request_handler(
3719 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3720 );
3721 }
3722
3723 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3724 match &self.mode {
3725 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3726 _ => None,
3727 }
3728 }
3729
3730 pub fn as_local(&self) -> Option<&LocalLspStore> {
3731 match &self.mode {
3732 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3733 _ => None,
3734 }
3735 }
3736
3737 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3738 match &mut self.mode {
3739 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3740 _ => None,
3741 }
3742 }
3743
3744 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3745 match &self.mode {
3746 LspStoreMode::Remote(RemoteLspStore {
3747 upstream_client: Some(upstream_client),
3748 upstream_project_id,
3749 ..
3750 }) => Some((upstream_client.clone(), *upstream_project_id)),
3751
3752 LspStoreMode::Remote(RemoteLspStore {
3753 upstream_client: None,
3754 ..
3755 }) => None,
3756 LspStoreMode::Local(_) => None,
3757 }
3758 }
3759
3760 pub fn new_local(
3761 buffer_store: Entity<BufferStore>,
3762 worktree_store: Entity<WorktreeStore>,
3763 prettier_store: Entity<PrettierStore>,
3764 toolchain_store: Entity<LocalToolchainStore>,
3765 environment: Entity<ProjectEnvironment>,
3766 manifest_tree: Entity<ManifestTree>,
3767 languages: Arc<LanguageRegistry>,
3768 http_client: Arc<dyn HttpClient>,
3769 fs: Arc<dyn Fs>,
3770 cx: &mut Context<Self>,
3771 ) -> Self {
3772 let yarn = YarnPathStore::new(fs.clone(), cx);
3773 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3774 .detach();
3775 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3776 .detach();
3777 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3778 .detach();
3779 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3780 .detach();
3781 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3782 .detach();
3783 subscribe_to_binary_statuses(&languages, cx).detach();
3784
3785 let _maintain_workspace_config = {
3786 let (sender, receiver) = watch::channel();
3787 (Self::maintain_workspace_config(receiver, cx), sender)
3788 };
3789
3790 Self {
3791 mode: LspStoreMode::Local(LocalLspStore {
3792 weak: cx.weak_entity(),
3793 worktree_store: worktree_store.clone(),
3794
3795 supplementary_language_servers: Default::default(),
3796 languages: languages.clone(),
3797 language_server_ids: Default::default(),
3798 language_servers: Default::default(),
3799 last_workspace_edits_by_language_server: Default::default(),
3800 language_server_watched_paths: Default::default(),
3801 language_server_paths_watched_for_rename: Default::default(),
3802 language_server_dynamic_registrations: Default::default(),
3803 buffers_being_formatted: Default::default(),
3804 buffer_snapshots: Default::default(),
3805 prettier_store,
3806 environment,
3807 http_client,
3808 fs,
3809 yarn,
3810 next_diagnostic_group_id: Default::default(),
3811 diagnostics: Default::default(),
3812 _subscription: cx.on_app_quit(|this, cx| {
3813 this.as_local_mut()
3814 .unwrap()
3815 .shutdown_language_servers_on_quit(cx)
3816 }),
3817 lsp_tree: LanguageServerTree::new(
3818 manifest_tree,
3819 languages.clone(),
3820 toolchain_store.clone(),
3821 ),
3822 toolchain_store,
3823 registered_buffers: HashMap::default(),
3824 buffers_opened_in_servers: HashMap::default(),
3825 buffer_pull_diagnostics_result_ids: HashMap::default(),
3826 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3827 .manifest_file_names(),
3828 }),
3829 last_formatting_failure: None,
3830 downstream_client: None,
3831 buffer_store,
3832 worktree_store,
3833 languages: languages.clone(),
3834 language_server_statuses: Default::default(),
3835 nonce: StdRng::from_os_rng().random(),
3836 diagnostic_summaries: HashMap::default(),
3837 lsp_server_capabilities: HashMap::default(),
3838 lsp_data: HashMap::default(),
3839 next_hint_id: Arc::default(),
3840 active_entry: None,
3841 _maintain_workspace_config,
3842 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3843 }
3844 }
3845
3846 fn send_lsp_proto_request<R: LspCommand>(
3847 &self,
3848 buffer: Entity<Buffer>,
3849 client: AnyProtoClient,
3850 upstream_project_id: u64,
3851 request: R,
3852 cx: &mut Context<LspStore>,
3853 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3854 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3855 return Task::ready(Ok(R::Response::default()));
3856 }
3857 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3858 cx.spawn(async move |this, cx| {
3859 let response = client.request(message).await?;
3860 let this = this.upgrade().context("project dropped")?;
3861 request
3862 .response_from_proto(response, this, buffer, cx.clone())
3863 .await
3864 })
3865 }
3866
3867 pub(super) fn new_remote(
3868 buffer_store: Entity<BufferStore>,
3869 worktree_store: Entity<WorktreeStore>,
3870 languages: Arc<LanguageRegistry>,
3871 upstream_client: AnyProtoClient,
3872 project_id: u64,
3873 cx: &mut Context<Self>,
3874 ) -> Self {
3875 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3876 .detach();
3877 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3878 .detach();
3879 subscribe_to_binary_statuses(&languages, cx).detach();
3880 let _maintain_workspace_config = {
3881 let (sender, receiver) = watch::channel();
3882 (Self::maintain_workspace_config(receiver, cx), sender)
3883 };
3884 Self {
3885 mode: LspStoreMode::Remote(RemoteLspStore {
3886 upstream_client: Some(upstream_client),
3887 upstream_project_id: project_id,
3888 }),
3889 downstream_client: None,
3890 last_formatting_failure: None,
3891 buffer_store,
3892 worktree_store,
3893 languages: languages.clone(),
3894 language_server_statuses: Default::default(),
3895 nonce: StdRng::from_os_rng().random(),
3896 diagnostic_summaries: HashMap::default(),
3897 lsp_server_capabilities: HashMap::default(),
3898 next_hint_id: Arc::default(),
3899 lsp_data: HashMap::default(),
3900 active_entry: None,
3901
3902 _maintain_workspace_config,
3903 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3904 }
3905 }
3906
3907 fn on_buffer_store_event(
3908 &mut self,
3909 _: Entity<BufferStore>,
3910 event: &BufferStoreEvent,
3911 cx: &mut Context<Self>,
3912 ) {
3913 match event {
3914 BufferStoreEvent::BufferAdded(buffer) => {
3915 self.on_buffer_added(buffer, cx).log_err();
3916 }
3917 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3918 let buffer_id = buffer.read(cx).remote_id();
3919 if let Some(local) = self.as_local_mut()
3920 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3921 {
3922 local.reset_buffer(buffer, old_file, cx);
3923
3924 if local.registered_buffers.contains_key(&buffer_id) {
3925 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3926 }
3927 }
3928
3929 self.detect_language_for_buffer(buffer, cx);
3930 if let Some(local) = self.as_local_mut() {
3931 local.initialize_buffer(buffer, cx);
3932 if local.registered_buffers.contains_key(&buffer_id) {
3933 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3934 }
3935 }
3936 }
3937 _ => {}
3938 }
3939 }
3940
3941 fn on_worktree_store_event(
3942 &mut self,
3943 _: Entity<WorktreeStore>,
3944 event: &WorktreeStoreEvent,
3945 cx: &mut Context<Self>,
3946 ) {
3947 match event {
3948 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3949 if !worktree.read(cx).is_local() {
3950 return;
3951 }
3952 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3953 worktree::Event::UpdatedEntries(changes) => {
3954 this.update_local_worktree_language_servers(&worktree, changes, cx);
3955 }
3956 worktree::Event::UpdatedGitRepositories(_)
3957 | worktree::Event::DeletedEntry(_) => {}
3958 })
3959 .detach()
3960 }
3961 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3962 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3963 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3964 }
3965 WorktreeStoreEvent::WorktreeReleased(..)
3966 | WorktreeStoreEvent::WorktreeOrderChanged
3967 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3968 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3969 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3970 }
3971 }
3972
3973 fn on_prettier_store_event(
3974 &mut self,
3975 _: Entity<PrettierStore>,
3976 event: &PrettierStoreEvent,
3977 cx: &mut Context<Self>,
3978 ) {
3979 match event {
3980 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3981 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3982 }
3983 PrettierStoreEvent::LanguageServerAdded {
3984 new_server_id,
3985 name,
3986 prettier_server,
3987 } => {
3988 self.register_supplementary_language_server(
3989 *new_server_id,
3990 name.clone(),
3991 prettier_server.clone(),
3992 cx,
3993 );
3994 }
3995 }
3996 }
3997
3998 fn on_toolchain_store_event(
3999 &mut self,
4000 _: Entity<LocalToolchainStore>,
4001 event: &ToolchainStoreEvent,
4002 _: &mut Context<Self>,
4003 ) {
4004 if let ToolchainStoreEvent::ToolchainActivated = event {
4005 self.request_workspace_config_refresh()
4006 }
4007 }
4008
4009 fn request_workspace_config_refresh(&mut self) {
4010 *self._maintain_workspace_config.1.borrow_mut() = ();
4011 }
4012
4013 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4014 self.as_local().map(|local| local.prettier_store.clone())
4015 }
4016
4017 fn on_buffer_event(
4018 &mut self,
4019 buffer: Entity<Buffer>,
4020 event: &language::BufferEvent,
4021 cx: &mut Context<Self>,
4022 ) {
4023 match event {
4024 language::BufferEvent::Edited => {
4025 self.on_buffer_edited(buffer, cx);
4026 }
4027
4028 language::BufferEvent::Saved => {
4029 self.on_buffer_saved(buffer, cx);
4030 }
4031
4032 _ => {}
4033 }
4034 }
4035
4036 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4037 buffer
4038 .read(cx)
4039 .set_language_registry(self.languages.clone());
4040
4041 cx.subscribe(buffer, |this, buffer, event, cx| {
4042 this.on_buffer_event(buffer, event, cx);
4043 })
4044 .detach();
4045
4046 self.detect_language_for_buffer(buffer, cx);
4047 if let Some(local) = self.as_local_mut() {
4048 local.initialize_buffer(buffer, cx);
4049 }
4050
4051 Ok(())
4052 }
4053
4054 pub(crate) fn register_buffer_with_language_servers(
4055 &mut self,
4056 buffer: &Entity<Buffer>,
4057 only_register_servers: HashSet<LanguageServerSelector>,
4058 ignore_refcounts: bool,
4059 cx: &mut Context<Self>,
4060 ) -> OpenLspBufferHandle {
4061 let buffer_id = buffer.read(cx).remote_id();
4062 let handle = cx.new(|_| buffer.clone());
4063 if let Some(local) = self.as_local_mut() {
4064 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4065 if !ignore_refcounts {
4066 *refcount += 1;
4067 }
4068
4069 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4070 // 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
4071 // 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
4072 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4073 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4074 return handle;
4075 };
4076 if !file.is_local() {
4077 return handle;
4078 }
4079
4080 if ignore_refcounts || *refcount == 1 {
4081 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4082 }
4083 if !ignore_refcounts {
4084 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4085 let refcount = {
4086 let local = lsp_store.as_local_mut().unwrap();
4087 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4088 debug_panic!("bad refcounting");
4089 return;
4090 };
4091
4092 *refcount -= 1;
4093 *refcount
4094 };
4095 if refcount == 0 {
4096 lsp_store.lsp_data.remove(&buffer_id);
4097 let local = lsp_store.as_local_mut().unwrap();
4098 local.registered_buffers.remove(&buffer_id);
4099 local.buffers_opened_in_servers.remove(&buffer_id);
4100 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4101 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4102 }
4103 }
4104 })
4105 .detach();
4106 }
4107 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4108 let buffer_id = buffer.read(cx).remote_id().to_proto();
4109 cx.background_spawn(async move {
4110 upstream_client
4111 .request(proto::RegisterBufferWithLanguageServers {
4112 project_id: upstream_project_id,
4113 buffer_id,
4114 only_servers: only_register_servers
4115 .into_iter()
4116 .map(|selector| {
4117 let selector = match selector {
4118 LanguageServerSelector::Id(language_server_id) => {
4119 proto::language_server_selector::Selector::ServerId(
4120 language_server_id.to_proto(),
4121 )
4122 }
4123 LanguageServerSelector::Name(language_server_name) => {
4124 proto::language_server_selector::Selector::Name(
4125 language_server_name.to_string(),
4126 )
4127 }
4128 };
4129 proto::LanguageServerSelector {
4130 selector: Some(selector),
4131 }
4132 })
4133 .collect(),
4134 })
4135 .await
4136 })
4137 .detach();
4138 } else {
4139 panic!("oops!");
4140 }
4141 handle
4142 }
4143
4144 fn maintain_buffer_languages(
4145 languages: Arc<LanguageRegistry>,
4146 cx: &mut Context<Self>,
4147 ) -> Task<()> {
4148 let mut subscription = languages.subscribe();
4149 let mut prev_reload_count = languages.reload_count();
4150 cx.spawn(async move |this, cx| {
4151 while let Some(()) = subscription.next().await {
4152 if let Some(this) = this.upgrade() {
4153 // If the language registry has been reloaded, then remove and
4154 // re-assign the languages on all open buffers.
4155 let reload_count = languages.reload_count();
4156 if reload_count > prev_reload_count {
4157 prev_reload_count = reload_count;
4158 this.update(cx, |this, cx| {
4159 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4160 for buffer in buffer_store.buffers() {
4161 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4162 {
4163 buffer
4164 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4165 if let Some(local) = this.as_local_mut() {
4166 local.reset_buffer(&buffer, &f, cx);
4167
4168 if local
4169 .registered_buffers
4170 .contains_key(&buffer.read(cx).remote_id())
4171 && let Some(file_url) =
4172 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4173 {
4174 local.unregister_buffer_from_language_servers(
4175 &buffer, &file_url, cx,
4176 );
4177 }
4178 }
4179 }
4180 }
4181 });
4182 })
4183 .ok();
4184 }
4185
4186 this.update(cx, |this, cx| {
4187 let mut plain_text_buffers = Vec::new();
4188 let mut buffers_with_unknown_injections = Vec::new();
4189 for handle in this.buffer_store.read(cx).buffers() {
4190 let buffer = handle.read(cx);
4191 if buffer.language().is_none()
4192 || buffer.language() == Some(&*language::PLAIN_TEXT)
4193 {
4194 plain_text_buffers.push(handle);
4195 } else if buffer.contains_unknown_injections() {
4196 buffers_with_unknown_injections.push(handle);
4197 }
4198 }
4199
4200 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4201 // and reused later in the invisible worktrees.
4202 plain_text_buffers.sort_by_key(|buffer| {
4203 Reverse(
4204 File::from_dyn(buffer.read(cx).file())
4205 .map(|file| file.worktree.read(cx).is_visible()),
4206 )
4207 });
4208
4209 for buffer in plain_text_buffers {
4210 this.detect_language_for_buffer(&buffer, cx);
4211 if let Some(local) = this.as_local_mut() {
4212 local.initialize_buffer(&buffer, cx);
4213 if local
4214 .registered_buffers
4215 .contains_key(&buffer.read(cx).remote_id())
4216 {
4217 local.register_buffer_with_language_servers(
4218 &buffer,
4219 HashSet::default(),
4220 cx,
4221 );
4222 }
4223 }
4224 }
4225
4226 for buffer in buffers_with_unknown_injections {
4227 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4228 }
4229 })
4230 .ok();
4231 }
4232 }
4233 })
4234 }
4235
4236 fn detect_language_for_buffer(
4237 &mut self,
4238 buffer_handle: &Entity<Buffer>,
4239 cx: &mut Context<Self>,
4240 ) -> Option<language::AvailableLanguage> {
4241 // If the buffer has a language, set it and start the language server if we haven't already.
4242 let buffer = buffer_handle.read(cx);
4243 let file = buffer.file()?;
4244
4245 let content = buffer.as_rope();
4246 let available_language = self.languages.language_for_file(file, Some(content), cx);
4247 if let Some(available_language) = &available_language {
4248 if let Some(Ok(Ok(new_language))) = self
4249 .languages
4250 .load_language(available_language)
4251 .now_or_never()
4252 {
4253 self.set_language_for_buffer(buffer_handle, new_language, cx);
4254 }
4255 } else {
4256 cx.emit(LspStoreEvent::LanguageDetected {
4257 buffer: buffer_handle.clone(),
4258 new_language: None,
4259 });
4260 }
4261
4262 available_language
4263 }
4264
4265 pub(crate) fn set_language_for_buffer(
4266 &mut self,
4267 buffer_entity: &Entity<Buffer>,
4268 new_language: Arc<Language>,
4269 cx: &mut Context<Self>,
4270 ) {
4271 let buffer = buffer_entity.read(cx);
4272 let buffer_file = buffer.file().cloned();
4273 let buffer_id = buffer.remote_id();
4274 if let Some(local_store) = self.as_local_mut()
4275 && local_store.registered_buffers.contains_key(&buffer_id)
4276 && let Some(abs_path) =
4277 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4278 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4279 {
4280 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4281 }
4282 buffer_entity.update(cx, |buffer, cx| {
4283 if buffer
4284 .language()
4285 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4286 {
4287 buffer.set_language(Some(new_language.clone()), cx);
4288 }
4289 });
4290
4291 let settings =
4292 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4293 let buffer_file = File::from_dyn(buffer_file.as_ref());
4294
4295 let worktree_id = if let Some(file) = buffer_file {
4296 let worktree = file.worktree.clone();
4297
4298 if let Some(local) = self.as_local_mut()
4299 && local.registered_buffers.contains_key(&buffer_id)
4300 {
4301 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4302 }
4303 Some(worktree.read(cx).id())
4304 } else {
4305 None
4306 };
4307
4308 if settings.prettier.allowed
4309 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4310 {
4311 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4312 if let Some(prettier_store) = prettier_store {
4313 prettier_store.update(cx, |prettier_store, cx| {
4314 prettier_store.install_default_prettier(
4315 worktree_id,
4316 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4317 cx,
4318 )
4319 })
4320 }
4321 }
4322
4323 cx.emit(LspStoreEvent::LanguageDetected {
4324 buffer: buffer_entity.clone(),
4325 new_language: Some(new_language),
4326 })
4327 }
4328
4329 pub fn buffer_store(&self) -> Entity<BufferStore> {
4330 self.buffer_store.clone()
4331 }
4332
4333 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4334 self.active_entry = active_entry;
4335 }
4336
4337 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4338 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4339 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4340 {
4341 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4342 summaries
4343 .iter()
4344 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4345 });
4346 if let Some(summary) = summaries.next() {
4347 client
4348 .send(proto::UpdateDiagnosticSummary {
4349 project_id: downstream_project_id,
4350 worktree_id: worktree.id().to_proto(),
4351 summary: Some(summary),
4352 more_summaries: summaries.collect(),
4353 })
4354 .log_err();
4355 }
4356 }
4357 }
4358
4359 fn is_capable_for_proto_request<R>(
4360 &self,
4361 buffer: &Entity<Buffer>,
4362 request: &R,
4363 cx: &App,
4364 ) -> bool
4365 where
4366 R: LspCommand,
4367 {
4368 self.check_if_capable_for_proto_request(
4369 buffer,
4370 |capabilities| {
4371 request.check_capabilities(AdapterServerCapabilities {
4372 server_capabilities: capabilities.clone(),
4373 code_action_kinds: None,
4374 })
4375 },
4376 cx,
4377 )
4378 }
4379
4380 fn check_if_capable_for_proto_request<F>(
4381 &self,
4382 buffer: &Entity<Buffer>,
4383 check: F,
4384 cx: &App,
4385 ) -> bool
4386 where
4387 F: FnMut(&lsp::ServerCapabilities) -> bool,
4388 {
4389 let Some(language) = buffer.read(cx).language().cloned() else {
4390 return false;
4391 };
4392 let relevant_language_servers = self
4393 .languages
4394 .lsp_adapters(&language.name())
4395 .into_iter()
4396 .map(|lsp_adapter| lsp_adapter.name())
4397 .collect::<HashSet<_>>();
4398 self.language_server_statuses
4399 .iter()
4400 .filter_map(|(server_id, server_status)| {
4401 relevant_language_servers
4402 .contains(&server_status.name)
4403 .then_some(server_id)
4404 })
4405 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4406 .any(check)
4407 }
4408
4409 pub fn request_lsp<R>(
4410 &mut self,
4411 buffer: Entity<Buffer>,
4412 server: LanguageServerToQuery,
4413 request: R,
4414 cx: &mut Context<Self>,
4415 ) -> Task<Result<R::Response>>
4416 where
4417 R: LspCommand,
4418 <R::LspRequest as lsp::request::Request>::Result: Send,
4419 <R::LspRequest as lsp::request::Request>::Params: Send,
4420 {
4421 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4422 return self.send_lsp_proto_request(
4423 buffer,
4424 upstream_client,
4425 upstream_project_id,
4426 request,
4427 cx,
4428 );
4429 }
4430
4431 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4432 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4433 local
4434 .language_servers_for_buffer(buffer, cx)
4435 .find(|(_, server)| {
4436 request.check_capabilities(server.adapter_server_capabilities())
4437 })
4438 .map(|(_, server)| server.clone())
4439 }),
4440 LanguageServerToQuery::Other(id) => self
4441 .language_server_for_local_buffer(buffer, id, cx)
4442 .and_then(|(_, server)| {
4443 request
4444 .check_capabilities(server.adapter_server_capabilities())
4445 .then(|| Arc::clone(server))
4446 }),
4447 }) else {
4448 return Task::ready(Ok(Default::default()));
4449 };
4450
4451 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4452
4453 let Some(file) = file else {
4454 return Task::ready(Ok(Default::default()));
4455 };
4456
4457 let lsp_params = match request.to_lsp_params_or_response(
4458 &file.abs_path(cx),
4459 buffer.read(cx),
4460 &language_server,
4461 cx,
4462 ) {
4463 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4464 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4465
4466 Err(err) => {
4467 let message = format!(
4468 "{} via {} failed: {}",
4469 request.display_name(),
4470 language_server.name(),
4471 err
4472 );
4473 log::warn!("{message}");
4474 return Task::ready(Err(anyhow!(message)));
4475 }
4476 };
4477
4478 let status = request.status();
4479 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4480 return Task::ready(Ok(Default::default()));
4481 }
4482 cx.spawn(async move |this, cx| {
4483 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4484
4485 let id = lsp_request.id();
4486 let _cleanup = if status.is_some() {
4487 cx.update(|cx| {
4488 this.update(cx, |this, cx| {
4489 this.on_lsp_work_start(
4490 language_server.server_id(),
4491 id.to_string(),
4492 LanguageServerProgress {
4493 is_disk_based_diagnostics_progress: false,
4494 is_cancellable: false,
4495 title: None,
4496 message: status.clone(),
4497 percentage: None,
4498 last_update_at: cx.background_executor().now(),
4499 },
4500 cx,
4501 );
4502 })
4503 })
4504 .log_err();
4505
4506 Some(defer(|| {
4507 cx.update(|cx| {
4508 this.update(cx, |this, cx| {
4509 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4510 })
4511 })
4512 .log_err();
4513 }))
4514 } else {
4515 None
4516 };
4517
4518 let result = lsp_request.await.into_response();
4519
4520 let response = result.map_err(|err| {
4521 let message = format!(
4522 "{} via {} failed: {}",
4523 request.display_name(),
4524 language_server.name(),
4525 err
4526 );
4527 log::warn!("{message}");
4528 anyhow::anyhow!(message)
4529 })?;
4530
4531 request
4532 .response_from_lsp(
4533 response,
4534 this.upgrade().context("no app context")?,
4535 buffer,
4536 language_server.server_id(),
4537 cx.clone(),
4538 )
4539 .await
4540 })
4541 }
4542
4543 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4544 let mut language_formatters_to_check = Vec::new();
4545 for buffer in self.buffer_store.read(cx).buffers() {
4546 let buffer = buffer.read(cx);
4547 let buffer_file = File::from_dyn(buffer.file());
4548 let buffer_language = buffer.language();
4549 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4550 if buffer_language.is_some() {
4551 language_formatters_to_check.push((
4552 buffer_file.map(|f| f.worktree_id(cx)),
4553 settings.into_owned(),
4554 ));
4555 }
4556 }
4557
4558 self.request_workspace_config_refresh();
4559
4560 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4561 prettier_store.update(cx, |prettier_store, cx| {
4562 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4563 })
4564 }
4565
4566 cx.notify();
4567 }
4568
4569 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4570 let buffer_store = self.buffer_store.clone();
4571 let Some(local) = self.as_local_mut() else {
4572 return;
4573 };
4574 let mut adapters = BTreeMap::default();
4575 let get_adapter = {
4576 let languages = local.languages.clone();
4577 let environment = local.environment.clone();
4578 let weak = local.weak.clone();
4579 let worktree_store = local.worktree_store.clone();
4580 let http_client = local.http_client.clone();
4581 let fs = local.fs.clone();
4582 move |worktree_id, cx: &mut App| {
4583 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4584 Some(LocalLspAdapterDelegate::new(
4585 languages.clone(),
4586 &environment,
4587 weak.clone(),
4588 &worktree,
4589 http_client.clone(),
4590 fs.clone(),
4591 cx,
4592 ))
4593 }
4594 };
4595
4596 let mut messages_to_report = Vec::new();
4597 let (new_tree, to_stop) = {
4598 let mut rebase = local.lsp_tree.rebase();
4599 let buffers = buffer_store
4600 .read(cx)
4601 .buffers()
4602 .filter_map(|buffer| {
4603 let raw_buffer = buffer.read(cx);
4604 if !local
4605 .registered_buffers
4606 .contains_key(&raw_buffer.remote_id())
4607 {
4608 return None;
4609 }
4610 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4611 let language = raw_buffer.language().cloned()?;
4612 Some((file, language, raw_buffer.remote_id()))
4613 })
4614 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4615 for (file, language, buffer_id) in buffers {
4616 let worktree_id = file.worktree_id(cx);
4617 let Some(worktree) = local
4618 .worktree_store
4619 .read(cx)
4620 .worktree_for_id(worktree_id, cx)
4621 else {
4622 continue;
4623 };
4624
4625 if let Some((_, apply)) = local.reuse_existing_language_server(
4626 rebase.server_tree(),
4627 &worktree,
4628 &language.name(),
4629 cx,
4630 ) {
4631 (apply)(rebase.server_tree());
4632 } else if let Some(lsp_delegate) = adapters
4633 .entry(worktree_id)
4634 .or_insert_with(|| get_adapter(worktree_id, cx))
4635 .clone()
4636 {
4637 let delegate =
4638 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4639 let path = file
4640 .path()
4641 .parent()
4642 .map(Arc::from)
4643 .unwrap_or_else(|| file.path().clone());
4644 let worktree_path = ProjectPath { worktree_id, path };
4645 let abs_path = file.abs_path(cx);
4646 let nodes = rebase
4647 .walk(
4648 worktree_path,
4649 language.name(),
4650 language.manifest(),
4651 delegate.clone(),
4652 cx,
4653 )
4654 .collect::<Vec<_>>();
4655 for node in nodes {
4656 let server_id = node.server_id_or_init(|disposition| {
4657 let path = &disposition.path;
4658 let absolute_path = worktree.read(cx).absolutize(&path.path);
4659 let uri = absolute_path
4660 .is_dir()
4661 .then(|| Uri::from_file_path(absolute_path))
4662 .transpose();
4663 let key = LanguageServerSeed {
4664 worktree_id,
4665 name: disposition.server_name.clone(),
4666 settings: disposition.settings.clone(),
4667 toolchain: local.toolchain_store.read(cx).active_toolchain(
4668 path.worktree_id,
4669 &path.path,
4670 language.name(),
4671 ),
4672 };
4673 local.language_server_ids.remove(&key);
4674
4675 let server_id = local.get_or_insert_language_server(
4676 &worktree,
4677 lsp_delegate.clone(),
4678 disposition,
4679 &language.name(),
4680 cx,
4681 );
4682 if let Some(state) = local.language_servers.get(&server_id)
4683 && let Ok(Some(uri)) = uri
4684 {
4685 state.add_workspace_folder(uri);
4686 };
4687 server_id
4688 });
4689
4690 if let Some(language_server_id) = server_id {
4691 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4692 language_server_id,
4693 name: node.name(),
4694 message:
4695 proto::update_language_server::Variant::RegisteredForBuffer(
4696 proto::RegisteredForBuffer {
4697 buffer_abs_path: abs_path
4698 .to_string_lossy()
4699 .into_owned(),
4700 buffer_id: buffer_id.to_proto(),
4701 },
4702 ),
4703 });
4704 }
4705 }
4706 } else {
4707 continue;
4708 }
4709 }
4710 rebase.finish()
4711 };
4712 for message in messages_to_report {
4713 cx.emit(message);
4714 }
4715 local.lsp_tree = new_tree;
4716 for (id, _) in to_stop {
4717 self.stop_local_language_server(id, cx).detach();
4718 }
4719 }
4720
4721 pub fn apply_code_action(
4722 &self,
4723 buffer_handle: Entity<Buffer>,
4724 mut action: CodeAction,
4725 push_to_history: bool,
4726 cx: &mut Context<Self>,
4727 ) -> Task<Result<ProjectTransaction>> {
4728 if let Some((upstream_client, project_id)) = self.upstream_client() {
4729 let request = proto::ApplyCodeAction {
4730 project_id,
4731 buffer_id: buffer_handle.read(cx).remote_id().into(),
4732 action: Some(Self::serialize_code_action(&action)),
4733 };
4734 let buffer_store = self.buffer_store();
4735 cx.spawn(async move |_, cx| {
4736 let response = upstream_client
4737 .request(request)
4738 .await?
4739 .transaction
4740 .context("missing transaction")?;
4741
4742 buffer_store
4743 .update(cx, |buffer_store, cx| {
4744 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4745 })?
4746 .await
4747 })
4748 } else if self.mode.is_local() {
4749 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4750 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4751 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4752 }) else {
4753 return Task::ready(Ok(ProjectTransaction::default()));
4754 };
4755 cx.spawn(async move |this, cx| {
4756 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4757 .await
4758 .context("resolving a code action")?;
4759 if let Some(edit) = action.lsp_action.edit()
4760 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4761 return LocalLspStore::deserialize_workspace_edit(
4762 this.upgrade().context("no app present")?,
4763 edit.clone(),
4764 push_to_history,
4765
4766 lang_server.clone(),
4767 cx,
4768 )
4769 .await;
4770 }
4771
4772 if let Some(command) = action.lsp_action.command() {
4773 let server_capabilities = lang_server.capabilities();
4774 let available_commands = server_capabilities
4775 .execute_command_provider
4776 .as_ref()
4777 .map(|options| options.commands.as_slice())
4778 .unwrap_or_default();
4779 if available_commands.contains(&command.command) {
4780 this.update(cx, |this, _| {
4781 this.as_local_mut()
4782 .unwrap()
4783 .last_workspace_edits_by_language_server
4784 .remove(&lang_server.server_id());
4785 })?;
4786
4787 let _result = lang_server
4788 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4789 command: command.command.clone(),
4790 arguments: command.arguments.clone().unwrap_or_default(),
4791 ..lsp::ExecuteCommandParams::default()
4792 })
4793 .await.into_response()
4794 .context("execute command")?;
4795
4796 return this.update(cx, |this, _| {
4797 this.as_local_mut()
4798 .unwrap()
4799 .last_workspace_edits_by_language_server
4800 .remove(&lang_server.server_id())
4801 .unwrap_or_default()
4802 });
4803 } else {
4804 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4805 }
4806 }
4807
4808 Ok(ProjectTransaction::default())
4809 })
4810 } else {
4811 Task::ready(Err(anyhow!("no upstream client and not local")))
4812 }
4813 }
4814
4815 pub fn apply_code_action_kind(
4816 &mut self,
4817 buffers: HashSet<Entity<Buffer>>,
4818 kind: CodeActionKind,
4819 push_to_history: bool,
4820 cx: &mut Context<Self>,
4821 ) -> Task<anyhow::Result<ProjectTransaction>> {
4822 if self.as_local().is_some() {
4823 cx.spawn(async move |lsp_store, cx| {
4824 let buffers = buffers.into_iter().collect::<Vec<_>>();
4825 let result = LocalLspStore::execute_code_action_kind_locally(
4826 lsp_store.clone(),
4827 buffers,
4828 kind,
4829 push_to_history,
4830 cx,
4831 )
4832 .await;
4833 lsp_store.update(cx, |lsp_store, _| {
4834 lsp_store.update_last_formatting_failure(&result);
4835 })?;
4836 result
4837 })
4838 } else if let Some((client, project_id)) = self.upstream_client() {
4839 let buffer_store = self.buffer_store();
4840 cx.spawn(async move |lsp_store, cx| {
4841 let result = client
4842 .request(proto::ApplyCodeActionKind {
4843 project_id,
4844 kind: kind.as_str().to_owned(),
4845 buffer_ids: buffers
4846 .iter()
4847 .map(|buffer| {
4848 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4849 })
4850 .collect::<Result<_>>()?,
4851 })
4852 .await
4853 .and_then(|result| result.transaction.context("missing transaction"));
4854 lsp_store.update(cx, |lsp_store, _| {
4855 lsp_store.update_last_formatting_failure(&result);
4856 })?;
4857
4858 let transaction_response = result?;
4859 buffer_store
4860 .update(cx, |buffer_store, cx| {
4861 buffer_store.deserialize_project_transaction(
4862 transaction_response,
4863 push_to_history,
4864 cx,
4865 )
4866 })?
4867 .await
4868 })
4869 } else {
4870 Task::ready(Ok(ProjectTransaction::default()))
4871 }
4872 }
4873
4874 pub fn resolved_hint(
4875 &mut self,
4876 buffer_id: BufferId,
4877 id: InlayId,
4878 cx: &mut Context<Self>,
4879 ) -> Option<ResolvedHint> {
4880 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4881
4882 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4883 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4884 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4885 let (server_id, resolve_data) = match &hint.resolve_state {
4886 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4887 ResolveState::Resolving => {
4888 return Some(ResolvedHint::Resolving(
4889 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4890 ));
4891 }
4892 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4893 };
4894
4895 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4896 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4897 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4898 id,
4899 cx.spawn(async move |lsp_store, cx| {
4900 let resolved_hint = resolve_task.await;
4901 lsp_store
4902 .update(cx, |lsp_store, _| {
4903 if let Some(old_inlay_hint) = lsp_store
4904 .lsp_data
4905 .get_mut(&buffer_id)
4906 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4907 {
4908 match resolved_hint {
4909 Ok(resolved_hint) => {
4910 *old_inlay_hint = resolved_hint;
4911 }
4912 Err(e) => {
4913 old_inlay_hint.resolve_state =
4914 ResolveState::CanResolve(server_id, resolve_data);
4915 log::error!("Inlay hint resolve failed: {e:#}");
4916 }
4917 }
4918 }
4919 })
4920 .ok();
4921 })
4922 .shared(),
4923 );
4924 debug_assert!(
4925 previous_task.is_none(),
4926 "Did not change hint's resolve state after spawning its resolve"
4927 );
4928 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4929 None
4930 }
4931
4932 fn resolve_inlay_hint(
4933 &self,
4934 mut hint: InlayHint,
4935 buffer: Entity<Buffer>,
4936 server_id: LanguageServerId,
4937 cx: &mut Context<Self>,
4938 ) -> Task<anyhow::Result<InlayHint>> {
4939 if let Some((upstream_client, project_id)) = self.upstream_client() {
4940 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4941 {
4942 hint.resolve_state = ResolveState::Resolved;
4943 return Task::ready(Ok(hint));
4944 }
4945 let request = proto::ResolveInlayHint {
4946 project_id,
4947 buffer_id: buffer.read(cx).remote_id().into(),
4948 language_server_id: server_id.0 as u64,
4949 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4950 };
4951 cx.background_spawn(async move {
4952 let response = upstream_client
4953 .request(request)
4954 .await
4955 .context("inlay hints proto request")?;
4956 match response.hint {
4957 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4958 .context("inlay hints proto resolve response conversion"),
4959 None => Ok(hint),
4960 }
4961 })
4962 } else {
4963 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4964 self.language_server_for_local_buffer(buffer, server_id, cx)
4965 .map(|(_, server)| server.clone())
4966 }) else {
4967 return Task::ready(Ok(hint));
4968 };
4969 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4970 return Task::ready(Ok(hint));
4971 }
4972 let buffer_snapshot = buffer.read(cx).snapshot();
4973 cx.spawn(async move |_, cx| {
4974 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4975 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4976 );
4977 let resolved_hint = resolve_task
4978 .await
4979 .into_response()
4980 .context("inlay hint resolve LSP request")?;
4981 let resolved_hint = InlayHints::lsp_to_project_hint(
4982 resolved_hint,
4983 &buffer,
4984 server_id,
4985 ResolveState::Resolved,
4986 false,
4987 cx,
4988 )
4989 .await?;
4990 Ok(resolved_hint)
4991 })
4992 }
4993 }
4994
4995 pub fn resolve_color_presentation(
4996 &mut self,
4997 mut color: DocumentColor,
4998 buffer: Entity<Buffer>,
4999 server_id: LanguageServerId,
5000 cx: &mut Context<Self>,
5001 ) -> Task<Result<DocumentColor>> {
5002 if color.resolved {
5003 return Task::ready(Ok(color));
5004 }
5005
5006 if let Some((upstream_client, project_id)) = self.upstream_client() {
5007 let start = color.lsp_range.start;
5008 let end = color.lsp_range.end;
5009 let request = proto::GetColorPresentation {
5010 project_id,
5011 server_id: server_id.to_proto(),
5012 buffer_id: buffer.read(cx).remote_id().into(),
5013 color: Some(proto::ColorInformation {
5014 red: color.color.red,
5015 green: color.color.green,
5016 blue: color.color.blue,
5017 alpha: color.color.alpha,
5018 lsp_range_start: Some(proto::PointUtf16 {
5019 row: start.line,
5020 column: start.character,
5021 }),
5022 lsp_range_end: Some(proto::PointUtf16 {
5023 row: end.line,
5024 column: end.character,
5025 }),
5026 }),
5027 };
5028 cx.background_spawn(async move {
5029 let response = upstream_client
5030 .request(request)
5031 .await
5032 .context("color presentation proto request")?;
5033 color.resolved = true;
5034 color.color_presentations = response
5035 .presentations
5036 .into_iter()
5037 .map(|presentation| ColorPresentation {
5038 label: SharedString::from(presentation.label),
5039 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5040 additional_text_edits: presentation
5041 .additional_text_edits
5042 .into_iter()
5043 .filter_map(deserialize_lsp_edit)
5044 .collect(),
5045 })
5046 .collect();
5047 Ok(color)
5048 })
5049 } else {
5050 let path = match buffer
5051 .update(cx, |buffer, cx| {
5052 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5053 })
5054 .context("buffer with the missing path")
5055 {
5056 Ok(path) => path,
5057 Err(e) => return Task::ready(Err(e)),
5058 };
5059 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5060 self.language_server_for_local_buffer(buffer, server_id, cx)
5061 .map(|(_, server)| server.clone())
5062 }) else {
5063 return Task::ready(Ok(color));
5064 };
5065 cx.background_spawn(async move {
5066 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5067 lsp::ColorPresentationParams {
5068 text_document: make_text_document_identifier(&path)?,
5069 color: color.color,
5070 range: color.lsp_range,
5071 work_done_progress_params: Default::default(),
5072 partial_result_params: Default::default(),
5073 },
5074 );
5075 color.color_presentations = resolve_task
5076 .await
5077 .into_response()
5078 .context("color presentation resolve LSP request")?
5079 .into_iter()
5080 .map(|presentation| ColorPresentation {
5081 label: SharedString::from(presentation.label),
5082 text_edit: presentation.text_edit,
5083 additional_text_edits: presentation
5084 .additional_text_edits
5085 .unwrap_or_default(),
5086 })
5087 .collect();
5088 color.resolved = true;
5089 Ok(color)
5090 })
5091 }
5092 }
5093
5094 pub(crate) fn linked_edits(
5095 &mut self,
5096 buffer: &Entity<Buffer>,
5097 position: Anchor,
5098 cx: &mut Context<Self>,
5099 ) -> Task<Result<Vec<Range<Anchor>>>> {
5100 let snapshot = buffer.read(cx).snapshot();
5101 let scope = snapshot.language_scope_at(position);
5102 let Some(server_id) = self
5103 .as_local()
5104 .and_then(|local| {
5105 buffer.update(cx, |buffer, cx| {
5106 local
5107 .language_servers_for_buffer(buffer, cx)
5108 .filter(|(_, server)| {
5109 LinkedEditingRange::check_server_capabilities(server.capabilities())
5110 })
5111 .filter(|(adapter, _)| {
5112 scope
5113 .as_ref()
5114 .map(|scope| scope.language_allowed(&adapter.name))
5115 .unwrap_or(true)
5116 })
5117 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5118 .next()
5119 })
5120 })
5121 .or_else(|| {
5122 self.upstream_client()
5123 .is_some()
5124 .then_some(LanguageServerToQuery::FirstCapable)
5125 })
5126 .filter(|_| {
5127 maybe!({
5128 let language = buffer.read(cx).language_at(position)?;
5129 Some(
5130 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5131 .linked_edits,
5132 )
5133 }) == Some(true)
5134 })
5135 else {
5136 return Task::ready(Ok(Vec::new()));
5137 };
5138
5139 self.request_lsp(
5140 buffer.clone(),
5141 server_id,
5142 LinkedEditingRange { position },
5143 cx,
5144 )
5145 }
5146
5147 fn apply_on_type_formatting(
5148 &mut self,
5149 buffer: Entity<Buffer>,
5150 position: Anchor,
5151 trigger: String,
5152 cx: &mut Context<Self>,
5153 ) -> Task<Result<Option<Transaction>>> {
5154 if let Some((client, project_id)) = self.upstream_client() {
5155 if !self.check_if_capable_for_proto_request(
5156 &buffer,
5157 |capabilities| {
5158 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5159 },
5160 cx,
5161 ) {
5162 return Task::ready(Ok(None));
5163 }
5164 let request = proto::OnTypeFormatting {
5165 project_id,
5166 buffer_id: buffer.read(cx).remote_id().into(),
5167 position: Some(serialize_anchor(&position)),
5168 trigger,
5169 version: serialize_version(&buffer.read(cx).version()),
5170 };
5171 cx.background_spawn(async move {
5172 client
5173 .request(request)
5174 .await?
5175 .transaction
5176 .map(language::proto::deserialize_transaction)
5177 .transpose()
5178 })
5179 } else if let Some(local) = self.as_local_mut() {
5180 let buffer_id = buffer.read(cx).remote_id();
5181 local.buffers_being_formatted.insert(buffer_id);
5182 cx.spawn(async move |this, cx| {
5183 let _cleanup = defer({
5184 let this = this.clone();
5185 let mut cx = cx.clone();
5186 move || {
5187 this.update(&mut cx, |this, _| {
5188 if let Some(local) = this.as_local_mut() {
5189 local.buffers_being_formatted.remove(&buffer_id);
5190 }
5191 })
5192 .ok();
5193 }
5194 });
5195
5196 buffer
5197 .update(cx, |buffer, _| {
5198 buffer.wait_for_edits(Some(position.timestamp))
5199 })?
5200 .await?;
5201 this.update(cx, |this, cx| {
5202 let position = position.to_point_utf16(buffer.read(cx));
5203 this.on_type_format(buffer, position, trigger, false, cx)
5204 })?
5205 .await
5206 })
5207 } else {
5208 Task::ready(Err(anyhow!("No upstream client or local language server")))
5209 }
5210 }
5211
5212 pub fn on_type_format<T: ToPointUtf16>(
5213 &mut self,
5214 buffer: Entity<Buffer>,
5215 position: T,
5216 trigger: String,
5217 push_to_history: bool,
5218 cx: &mut Context<Self>,
5219 ) -> Task<Result<Option<Transaction>>> {
5220 let position = position.to_point_utf16(buffer.read(cx));
5221 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5222 }
5223
5224 fn on_type_format_impl(
5225 &mut self,
5226 buffer: Entity<Buffer>,
5227 position: PointUtf16,
5228 trigger: String,
5229 push_to_history: bool,
5230 cx: &mut Context<Self>,
5231 ) -> Task<Result<Option<Transaction>>> {
5232 let options = buffer.update(cx, |buffer, cx| {
5233 lsp_command::lsp_formatting_options(
5234 language_settings(
5235 buffer.language_at(position).map(|l| l.name()),
5236 buffer.file(),
5237 cx,
5238 )
5239 .as_ref(),
5240 )
5241 });
5242
5243 cx.spawn(async move |this, cx| {
5244 if let Some(waiter) =
5245 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5246 {
5247 waiter.await?;
5248 }
5249 cx.update(|cx| {
5250 this.update(cx, |this, cx| {
5251 this.request_lsp(
5252 buffer.clone(),
5253 LanguageServerToQuery::FirstCapable,
5254 OnTypeFormatting {
5255 position,
5256 trigger,
5257 options,
5258 push_to_history,
5259 },
5260 cx,
5261 )
5262 })
5263 })??
5264 .await
5265 })
5266 }
5267
5268 pub fn definitions(
5269 &mut self,
5270 buffer: &Entity<Buffer>,
5271 position: PointUtf16,
5272 cx: &mut Context<Self>,
5273 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5274 if let Some((upstream_client, project_id)) = self.upstream_client() {
5275 let request = GetDefinitions { position };
5276 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5277 return Task::ready(Ok(None));
5278 }
5279 let request_task = upstream_client.request_lsp(
5280 project_id,
5281 None,
5282 LSP_REQUEST_TIMEOUT,
5283 cx.background_executor().clone(),
5284 request.to_proto(project_id, buffer.read(cx)),
5285 );
5286 let buffer = buffer.clone();
5287 cx.spawn(async move |weak_project, cx| {
5288 let Some(project) = weak_project.upgrade() else {
5289 return Ok(None);
5290 };
5291 let Some(responses) = request_task.await? else {
5292 return Ok(None);
5293 };
5294 let actions = join_all(responses.payload.into_iter().map(|response| {
5295 GetDefinitions { position }.response_from_proto(
5296 response.response,
5297 project.clone(),
5298 buffer.clone(),
5299 cx.clone(),
5300 )
5301 }))
5302 .await;
5303
5304 Ok(Some(
5305 actions
5306 .into_iter()
5307 .collect::<Result<Vec<Vec<_>>>>()?
5308 .into_iter()
5309 .flatten()
5310 .dedup()
5311 .collect(),
5312 ))
5313 })
5314 } else {
5315 let definitions_task = self.request_multiple_lsp_locally(
5316 buffer,
5317 Some(position),
5318 GetDefinitions { position },
5319 cx,
5320 );
5321 cx.background_spawn(async move {
5322 Ok(Some(
5323 definitions_task
5324 .await
5325 .into_iter()
5326 .flat_map(|(_, definitions)| definitions)
5327 .dedup()
5328 .collect(),
5329 ))
5330 })
5331 }
5332 }
5333
5334 pub fn declarations(
5335 &mut self,
5336 buffer: &Entity<Buffer>,
5337 position: PointUtf16,
5338 cx: &mut Context<Self>,
5339 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5340 if let Some((upstream_client, project_id)) = self.upstream_client() {
5341 let request = GetDeclarations { position };
5342 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5343 return Task::ready(Ok(None));
5344 }
5345 let request_task = upstream_client.request_lsp(
5346 project_id,
5347 None,
5348 LSP_REQUEST_TIMEOUT,
5349 cx.background_executor().clone(),
5350 request.to_proto(project_id, buffer.read(cx)),
5351 );
5352 let buffer = buffer.clone();
5353 cx.spawn(async move |weak_project, cx| {
5354 let Some(project) = weak_project.upgrade() else {
5355 return Ok(None);
5356 };
5357 let Some(responses) = request_task.await? else {
5358 return Ok(None);
5359 };
5360 let actions = join_all(responses.payload.into_iter().map(|response| {
5361 GetDeclarations { position }.response_from_proto(
5362 response.response,
5363 project.clone(),
5364 buffer.clone(),
5365 cx.clone(),
5366 )
5367 }))
5368 .await;
5369
5370 Ok(Some(
5371 actions
5372 .into_iter()
5373 .collect::<Result<Vec<Vec<_>>>>()?
5374 .into_iter()
5375 .flatten()
5376 .dedup()
5377 .collect(),
5378 ))
5379 })
5380 } else {
5381 let declarations_task = self.request_multiple_lsp_locally(
5382 buffer,
5383 Some(position),
5384 GetDeclarations { position },
5385 cx,
5386 );
5387 cx.background_spawn(async move {
5388 Ok(Some(
5389 declarations_task
5390 .await
5391 .into_iter()
5392 .flat_map(|(_, declarations)| declarations)
5393 .dedup()
5394 .collect(),
5395 ))
5396 })
5397 }
5398 }
5399
5400 pub fn type_definitions(
5401 &mut self,
5402 buffer: &Entity<Buffer>,
5403 position: PointUtf16,
5404 cx: &mut Context<Self>,
5405 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5406 if let Some((upstream_client, project_id)) = self.upstream_client() {
5407 let request = GetTypeDefinitions { position };
5408 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5409 return Task::ready(Ok(None));
5410 }
5411 let request_task = upstream_client.request_lsp(
5412 project_id,
5413 None,
5414 LSP_REQUEST_TIMEOUT,
5415 cx.background_executor().clone(),
5416 request.to_proto(project_id, buffer.read(cx)),
5417 );
5418 let buffer = buffer.clone();
5419 cx.spawn(async move |weak_project, cx| {
5420 let Some(project) = weak_project.upgrade() else {
5421 return Ok(None);
5422 };
5423 let Some(responses) = request_task.await? else {
5424 return Ok(None);
5425 };
5426 let actions = join_all(responses.payload.into_iter().map(|response| {
5427 GetTypeDefinitions { position }.response_from_proto(
5428 response.response,
5429 project.clone(),
5430 buffer.clone(),
5431 cx.clone(),
5432 )
5433 }))
5434 .await;
5435
5436 Ok(Some(
5437 actions
5438 .into_iter()
5439 .collect::<Result<Vec<Vec<_>>>>()?
5440 .into_iter()
5441 .flatten()
5442 .dedup()
5443 .collect(),
5444 ))
5445 })
5446 } else {
5447 let type_definitions_task = self.request_multiple_lsp_locally(
5448 buffer,
5449 Some(position),
5450 GetTypeDefinitions { position },
5451 cx,
5452 );
5453 cx.background_spawn(async move {
5454 Ok(Some(
5455 type_definitions_task
5456 .await
5457 .into_iter()
5458 .flat_map(|(_, type_definitions)| type_definitions)
5459 .dedup()
5460 .collect(),
5461 ))
5462 })
5463 }
5464 }
5465
5466 pub fn implementations(
5467 &mut self,
5468 buffer: &Entity<Buffer>,
5469 position: PointUtf16,
5470 cx: &mut Context<Self>,
5471 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5472 if let Some((upstream_client, project_id)) = self.upstream_client() {
5473 let request = GetImplementations { position };
5474 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5475 return Task::ready(Ok(None));
5476 }
5477 let request_task = upstream_client.request_lsp(
5478 project_id,
5479 None,
5480 LSP_REQUEST_TIMEOUT,
5481 cx.background_executor().clone(),
5482 request.to_proto(project_id, buffer.read(cx)),
5483 );
5484 let buffer = buffer.clone();
5485 cx.spawn(async move |weak_project, cx| {
5486 let Some(project) = weak_project.upgrade() else {
5487 return Ok(None);
5488 };
5489 let Some(responses) = request_task.await? else {
5490 return Ok(None);
5491 };
5492 let actions = join_all(responses.payload.into_iter().map(|response| {
5493 GetImplementations { position }.response_from_proto(
5494 response.response,
5495 project.clone(),
5496 buffer.clone(),
5497 cx.clone(),
5498 )
5499 }))
5500 .await;
5501
5502 Ok(Some(
5503 actions
5504 .into_iter()
5505 .collect::<Result<Vec<Vec<_>>>>()?
5506 .into_iter()
5507 .flatten()
5508 .dedup()
5509 .collect(),
5510 ))
5511 })
5512 } else {
5513 let implementations_task = self.request_multiple_lsp_locally(
5514 buffer,
5515 Some(position),
5516 GetImplementations { position },
5517 cx,
5518 );
5519 cx.background_spawn(async move {
5520 Ok(Some(
5521 implementations_task
5522 .await
5523 .into_iter()
5524 .flat_map(|(_, implementations)| implementations)
5525 .dedup()
5526 .collect(),
5527 ))
5528 })
5529 }
5530 }
5531
5532 pub fn references(
5533 &mut self,
5534 buffer: &Entity<Buffer>,
5535 position: PointUtf16,
5536 cx: &mut Context<Self>,
5537 ) -> Task<Result<Option<Vec<Location>>>> {
5538 if let Some((upstream_client, project_id)) = self.upstream_client() {
5539 let request = GetReferences { position };
5540 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5541 return Task::ready(Ok(None));
5542 }
5543
5544 let request_task = upstream_client.request_lsp(
5545 project_id,
5546 None,
5547 LSP_REQUEST_TIMEOUT,
5548 cx.background_executor().clone(),
5549 request.to_proto(project_id, buffer.read(cx)),
5550 );
5551 let buffer = buffer.clone();
5552 cx.spawn(async move |weak_project, cx| {
5553 let Some(project) = weak_project.upgrade() else {
5554 return Ok(None);
5555 };
5556 let Some(responses) = request_task.await? else {
5557 return Ok(None);
5558 };
5559
5560 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5561 GetReferences { position }.response_from_proto(
5562 lsp_response.response,
5563 project.clone(),
5564 buffer.clone(),
5565 cx.clone(),
5566 )
5567 }))
5568 .await
5569 .into_iter()
5570 .collect::<Result<Vec<Vec<_>>>>()?
5571 .into_iter()
5572 .flatten()
5573 .dedup()
5574 .collect();
5575 Ok(Some(locations))
5576 })
5577 } else {
5578 let references_task = self.request_multiple_lsp_locally(
5579 buffer,
5580 Some(position),
5581 GetReferences { position },
5582 cx,
5583 );
5584 cx.background_spawn(async move {
5585 Ok(Some(
5586 references_task
5587 .await
5588 .into_iter()
5589 .flat_map(|(_, references)| references)
5590 .dedup()
5591 .collect(),
5592 ))
5593 })
5594 }
5595 }
5596
5597 pub fn code_actions(
5598 &mut self,
5599 buffer: &Entity<Buffer>,
5600 range: Range<Anchor>,
5601 kinds: Option<Vec<CodeActionKind>>,
5602 cx: &mut Context<Self>,
5603 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5604 if let Some((upstream_client, project_id)) = self.upstream_client() {
5605 let request = GetCodeActions {
5606 range: range.clone(),
5607 kinds: kinds.clone(),
5608 };
5609 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5610 return Task::ready(Ok(None));
5611 }
5612 let request_task = upstream_client.request_lsp(
5613 project_id,
5614 None,
5615 LSP_REQUEST_TIMEOUT,
5616 cx.background_executor().clone(),
5617 request.to_proto(project_id, buffer.read(cx)),
5618 );
5619 let buffer = buffer.clone();
5620 cx.spawn(async move |weak_project, cx| {
5621 let Some(project) = weak_project.upgrade() else {
5622 return Ok(None);
5623 };
5624 let Some(responses) = request_task.await? else {
5625 return Ok(None);
5626 };
5627 let actions = join_all(responses.payload.into_iter().map(|response| {
5628 GetCodeActions {
5629 range: range.clone(),
5630 kinds: kinds.clone(),
5631 }
5632 .response_from_proto(
5633 response.response,
5634 project.clone(),
5635 buffer.clone(),
5636 cx.clone(),
5637 )
5638 }))
5639 .await;
5640
5641 Ok(Some(
5642 actions
5643 .into_iter()
5644 .collect::<Result<Vec<Vec<_>>>>()?
5645 .into_iter()
5646 .flatten()
5647 .collect(),
5648 ))
5649 })
5650 } else {
5651 let all_actions_task = self.request_multiple_lsp_locally(
5652 buffer,
5653 Some(range.start),
5654 GetCodeActions { range, kinds },
5655 cx,
5656 );
5657 cx.background_spawn(async move {
5658 Ok(Some(
5659 all_actions_task
5660 .await
5661 .into_iter()
5662 .flat_map(|(_, actions)| actions)
5663 .collect(),
5664 ))
5665 })
5666 }
5667 }
5668
5669 pub fn code_lens_actions(
5670 &mut self,
5671 buffer: &Entity<Buffer>,
5672 cx: &mut Context<Self>,
5673 ) -> CodeLensTask {
5674 let version_queried_for = buffer.read(cx).version();
5675 let buffer_id = buffer.read(cx).remote_id();
5676 let existing_servers = self.as_local().map(|local| {
5677 local
5678 .buffers_opened_in_servers
5679 .get(&buffer_id)
5680 .cloned()
5681 .unwrap_or_default()
5682 });
5683
5684 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5685 if let Some(cached_lens) = &lsp_data.code_lens {
5686 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5687 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5688 existing_servers != cached_lens.lens.keys().copied().collect()
5689 });
5690 if !has_different_servers {
5691 return Task::ready(Ok(Some(
5692 cached_lens.lens.values().flatten().cloned().collect(),
5693 )))
5694 .shared();
5695 }
5696 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5697 if !version_queried_for.changed_since(updating_for) {
5698 return running_update.clone();
5699 }
5700 }
5701 }
5702 }
5703
5704 let lens_lsp_data = self
5705 .latest_lsp_data(buffer, cx)
5706 .code_lens
5707 .get_or_insert_default();
5708 let buffer = buffer.clone();
5709 let query_version_queried_for = version_queried_for.clone();
5710 let new_task = cx
5711 .spawn(async move |lsp_store, cx| {
5712 cx.background_executor()
5713 .timer(Duration::from_millis(30))
5714 .await;
5715 let fetched_lens = lsp_store
5716 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5717 .map_err(Arc::new)?
5718 .await
5719 .context("fetching code lens")
5720 .map_err(Arc::new);
5721 let fetched_lens = match fetched_lens {
5722 Ok(fetched_lens) => fetched_lens,
5723 Err(e) => {
5724 lsp_store
5725 .update(cx, |lsp_store, _| {
5726 if let Some(lens_lsp_data) = lsp_store
5727 .lsp_data
5728 .get_mut(&buffer_id)
5729 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5730 {
5731 lens_lsp_data.update = None;
5732 }
5733 })
5734 .ok();
5735 return Err(e);
5736 }
5737 };
5738
5739 lsp_store
5740 .update(cx, |lsp_store, _| {
5741 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5742 let code_lens = lsp_data.code_lens.as_mut()?;
5743 if let Some(fetched_lens) = fetched_lens {
5744 if lsp_data.buffer_version == query_version_queried_for {
5745 code_lens.lens.extend(fetched_lens);
5746 } else if !lsp_data
5747 .buffer_version
5748 .changed_since(&query_version_queried_for)
5749 {
5750 lsp_data.buffer_version = query_version_queried_for;
5751 code_lens.lens = fetched_lens;
5752 }
5753 }
5754 code_lens.update = None;
5755 Some(code_lens.lens.values().flatten().cloned().collect())
5756 })
5757 .map_err(Arc::new)
5758 })
5759 .shared();
5760 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5761 new_task
5762 }
5763
5764 fn fetch_code_lens(
5765 &mut self,
5766 buffer: &Entity<Buffer>,
5767 cx: &mut Context<Self>,
5768 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5769 if let Some((upstream_client, project_id)) = self.upstream_client() {
5770 let request = GetCodeLens;
5771 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5772 return Task::ready(Ok(None));
5773 }
5774 let request_task = upstream_client.request_lsp(
5775 project_id,
5776 None,
5777 LSP_REQUEST_TIMEOUT,
5778 cx.background_executor().clone(),
5779 request.to_proto(project_id, buffer.read(cx)),
5780 );
5781 let buffer = buffer.clone();
5782 cx.spawn(async move |weak_lsp_store, cx| {
5783 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5784 return Ok(None);
5785 };
5786 let Some(responses) = request_task.await? else {
5787 return Ok(None);
5788 };
5789
5790 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5791 let lsp_store = lsp_store.clone();
5792 let buffer = buffer.clone();
5793 let cx = cx.clone();
5794 async move {
5795 (
5796 LanguageServerId::from_proto(response.server_id),
5797 GetCodeLens
5798 .response_from_proto(response.response, lsp_store, buffer, cx)
5799 .await,
5800 )
5801 }
5802 }))
5803 .await;
5804
5805 let mut has_errors = false;
5806 let code_lens_actions = code_lens_actions
5807 .into_iter()
5808 .filter_map(|(server_id, code_lens)| match code_lens {
5809 Ok(code_lens) => Some((server_id, code_lens)),
5810 Err(e) => {
5811 has_errors = true;
5812 log::error!("{e:#}");
5813 None
5814 }
5815 })
5816 .collect::<HashMap<_, _>>();
5817 anyhow::ensure!(
5818 !has_errors || !code_lens_actions.is_empty(),
5819 "Failed to fetch code lens"
5820 );
5821 Ok(Some(code_lens_actions))
5822 })
5823 } else {
5824 let code_lens_actions_task =
5825 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5826 cx.background_spawn(async move {
5827 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5828 })
5829 }
5830 }
5831
5832 #[inline(never)]
5833 pub fn completions(
5834 &self,
5835 buffer: &Entity<Buffer>,
5836 position: PointUtf16,
5837 context: CompletionContext,
5838 cx: &mut Context<Self>,
5839 ) -> Task<Result<Vec<CompletionResponse>>> {
5840 let language_registry = self.languages.clone();
5841
5842 if let Some((upstream_client, project_id)) = self.upstream_client() {
5843 let request = GetCompletions { position, context };
5844 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5845 return Task::ready(Ok(Vec::new()));
5846 }
5847 let task = self.send_lsp_proto_request(
5848 buffer.clone(),
5849 upstream_client,
5850 project_id,
5851 request,
5852 cx,
5853 );
5854 let language = buffer.read(cx).language().cloned();
5855
5856 // In the future, we should provide project guests with the names of LSP adapters,
5857 // so that they can use the correct LSP adapter when computing labels. For now,
5858 // guests just use the first LSP adapter associated with the buffer's language.
5859 let lsp_adapter = language.as_ref().and_then(|language| {
5860 language_registry
5861 .lsp_adapters(&language.name())
5862 .first()
5863 .cloned()
5864 });
5865
5866 cx.foreground_executor().spawn(async move {
5867 let completion_response = task.await?;
5868 let completions = populate_labels_for_completions(
5869 completion_response.completions,
5870 language,
5871 lsp_adapter,
5872 )
5873 .await;
5874 Ok(vec![CompletionResponse {
5875 completions,
5876 display_options: CompletionDisplayOptions::default(),
5877 is_incomplete: completion_response.is_incomplete,
5878 }])
5879 })
5880 } else if let Some(local) = self.as_local() {
5881 let snapshot = buffer.read(cx).snapshot();
5882 let offset = position.to_offset(&snapshot);
5883 let scope = snapshot.language_scope_at(offset);
5884 let language = snapshot.language().cloned();
5885 let completion_settings = language_settings(
5886 language.as_ref().map(|language| language.name()),
5887 buffer.read(cx).file(),
5888 cx,
5889 )
5890 .completions
5891 .clone();
5892 if !completion_settings.lsp {
5893 return Task::ready(Ok(Vec::new()));
5894 }
5895
5896 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5897 local
5898 .language_servers_for_buffer(buffer, cx)
5899 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5900 .filter(|(adapter, _)| {
5901 scope
5902 .as_ref()
5903 .map(|scope| scope.language_allowed(&adapter.name))
5904 .unwrap_or(true)
5905 })
5906 .map(|(_, server)| server.server_id())
5907 .collect()
5908 });
5909
5910 let buffer = buffer.clone();
5911 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5912 let lsp_timeout = if lsp_timeout > 0 {
5913 Some(Duration::from_millis(lsp_timeout))
5914 } else {
5915 None
5916 };
5917 cx.spawn(async move |this, cx| {
5918 let mut tasks = Vec::with_capacity(server_ids.len());
5919 this.update(cx, |lsp_store, cx| {
5920 for server_id in server_ids {
5921 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5922 let lsp_timeout = lsp_timeout
5923 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5924 let mut timeout = cx.background_spawn(async move {
5925 match lsp_timeout {
5926 Some(lsp_timeout) => {
5927 lsp_timeout.await;
5928 true
5929 },
5930 None => false,
5931 }
5932 }).fuse();
5933 let mut lsp_request = lsp_store.request_lsp(
5934 buffer.clone(),
5935 LanguageServerToQuery::Other(server_id),
5936 GetCompletions {
5937 position,
5938 context: context.clone(),
5939 },
5940 cx,
5941 ).fuse();
5942 let new_task = cx.background_spawn(async move {
5943 select_biased! {
5944 response = lsp_request => anyhow::Ok(Some(response?)),
5945 timeout_happened = timeout => {
5946 if timeout_happened {
5947 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5948 Ok(None)
5949 } else {
5950 let completions = lsp_request.await?;
5951 Ok(Some(completions))
5952 }
5953 },
5954 }
5955 });
5956 tasks.push((lsp_adapter, new_task));
5957 }
5958 })?;
5959
5960 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5961 let completion_response = task.await.ok()??;
5962 let completions = populate_labels_for_completions(
5963 completion_response.completions,
5964 language.clone(),
5965 lsp_adapter,
5966 )
5967 .await;
5968 Some(CompletionResponse {
5969 completions,
5970 display_options: CompletionDisplayOptions::default(),
5971 is_incomplete: completion_response.is_incomplete,
5972 })
5973 });
5974
5975 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5976
5977 Ok(responses.into_iter().flatten().collect())
5978 })
5979 } else {
5980 Task::ready(Err(anyhow!("No upstream client or local language server")))
5981 }
5982 }
5983
5984 pub fn resolve_completions(
5985 &self,
5986 buffer: Entity<Buffer>,
5987 completion_indices: Vec<usize>,
5988 completions: Rc<RefCell<Box<[Completion]>>>,
5989 cx: &mut Context<Self>,
5990 ) -> Task<Result<bool>> {
5991 let client = self.upstream_client();
5992 let buffer_id = buffer.read(cx).remote_id();
5993 let buffer_snapshot = buffer.read(cx).snapshot();
5994
5995 if !self.check_if_capable_for_proto_request(
5996 &buffer,
5997 GetCompletions::can_resolve_completions,
5998 cx,
5999 ) {
6000 return Task::ready(Ok(false));
6001 }
6002 cx.spawn(async move |lsp_store, cx| {
6003 let mut did_resolve = false;
6004 if let Some((client, project_id)) = client {
6005 for completion_index in completion_indices {
6006 let server_id = {
6007 let completion = &completions.borrow()[completion_index];
6008 completion.source.server_id()
6009 };
6010 if let Some(server_id) = server_id {
6011 if Self::resolve_completion_remote(
6012 project_id,
6013 server_id,
6014 buffer_id,
6015 completions.clone(),
6016 completion_index,
6017 client.clone(),
6018 )
6019 .await
6020 .log_err()
6021 .is_some()
6022 {
6023 did_resolve = true;
6024 }
6025 } else {
6026 resolve_word_completion(
6027 &buffer_snapshot,
6028 &mut completions.borrow_mut()[completion_index],
6029 );
6030 }
6031 }
6032 } else {
6033 for completion_index in completion_indices {
6034 let server_id = {
6035 let completion = &completions.borrow()[completion_index];
6036 completion.source.server_id()
6037 };
6038 if let Some(server_id) = server_id {
6039 let server_and_adapter = lsp_store
6040 .read_with(cx, |lsp_store, _| {
6041 let server = lsp_store.language_server_for_id(server_id)?;
6042 let adapter =
6043 lsp_store.language_server_adapter_for_id(server.server_id())?;
6044 Some((server, adapter))
6045 })
6046 .ok()
6047 .flatten();
6048 let Some((server, adapter)) = server_and_adapter else {
6049 continue;
6050 };
6051
6052 let resolved = Self::resolve_completion_local(
6053 server,
6054 completions.clone(),
6055 completion_index,
6056 )
6057 .await
6058 .log_err()
6059 .is_some();
6060 if resolved {
6061 Self::regenerate_completion_labels(
6062 adapter,
6063 &buffer_snapshot,
6064 completions.clone(),
6065 completion_index,
6066 )
6067 .await
6068 .log_err();
6069 did_resolve = true;
6070 }
6071 } else {
6072 resolve_word_completion(
6073 &buffer_snapshot,
6074 &mut completions.borrow_mut()[completion_index],
6075 );
6076 }
6077 }
6078 }
6079
6080 Ok(did_resolve)
6081 })
6082 }
6083
6084 async fn resolve_completion_local(
6085 server: Arc<lsp::LanguageServer>,
6086 completions: Rc<RefCell<Box<[Completion]>>>,
6087 completion_index: usize,
6088 ) -> Result<()> {
6089 let server_id = server.server_id();
6090 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6091 return Ok(());
6092 }
6093
6094 let request = {
6095 let completion = &completions.borrow()[completion_index];
6096 match &completion.source {
6097 CompletionSource::Lsp {
6098 lsp_completion,
6099 resolved,
6100 server_id: completion_server_id,
6101 ..
6102 } => {
6103 if *resolved {
6104 return Ok(());
6105 }
6106 anyhow::ensure!(
6107 server_id == *completion_server_id,
6108 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6109 );
6110 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6111 }
6112 CompletionSource::BufferWord { .. }
6113 | CompletionSource::Dap { .. }
6114 | CompletionSource::Custom => {
6115 return Ok(());
6116 }
6117 }
6118 };
6119 let resolved_completion = request
6120 .await
6121 .into_response()
6122 .context("resolve completion")?;
6123
6124 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6125 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6126
6127 let mut completions = completions.borrow_mut();
6128 let completion = &mut completions[completion_index];
6129 if let CompletionSource::Lsp {
6130 lsp_completion,
6131 resolved,
6132 server_id: completion_server_id,
6133 ..
6134 } = &mut completion.source
6135 {
6136 if *resolved {
6137 return Ok(());
6138 }
6139 anyhow::ensure!(
6140 server_id == *completion_server_id,
6141 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6142 );
6143 *lsp_completion = Box::new(resolved_completion);
6144 *resolved = true;
6145 }
6146 Ok(())
6147 }
6148
6149 async fn regenerate_completion_labels(
6150 adapter: Arc<CachedLspAdapter>,
6151 snapshot: &BufferSnapshot,
6152 completions: Rc<RefCell<Box<[Completion]>>>,
6153 completion_index: usize,
6154 ) -> Result<()> {
6155 let completion_item = completions.borrow()[completion_index]
6156 .source
6157 .lsp_completion(true)
6158 .map(Cow::into_owned);
6159 if let Some(lsp_documentation) = completion_item
6160 .as_ref()
6161 .and_then(|completion_item| completion_item.documentation.clone())
6162 {
6163 let mut completions = completions.borrow_mut();
6164 let completion = &mut completions[completion_index];
6165 completion.documentation = Some(lsp_documentation.into());
6166 } else {
6167 let mut completions = completions.borrow_mut();
6168 let completion = &mut completions[completion_index];
6169 completion.documentation = Some(CompletionDocumentation::Undocumented);
6170 }
6171
6172 let mut new_label = match completion_item {
6173 Some(completion_item) => {
6174 // 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
6175 // So we have to update the label here anyway...
6176 let language = snapshot.language();
6177 match language {
6178 Some(language) => {
6179 adapter
6180 .labels_for_completions(
6181 std::slice::from_ref(&completion_item),
6182 language,
6183 )
6184 .await?
6185 }
6186 None => Vec::new(),
6187 }
6188 .pop()
6189 .flatten()
6190 .unwrap_or_else(|| {
6191 CodeLabel::fallback_for_completion(
6192 &completion_item,
6193 language.map(|language| language.as_ref()),
6194 )
6195 })
6196 }
6197 None => CodeLabel::plain(
6198 completions.borrow()[completion_index].new_text.clone(),
6199 None,
6200 ),
6201 };
6202 ensure_uniform_list_compatible_label(&mut new_label);
6203
6204 let mut completions = completions.borrow_mut();
6205 let completion = &mut completions[completion_index];
6206 if completion.label.filter_text() == new_label.filter_text() {
6207 completion.label = new_label;
6208 } else {
6209 log::error!(
6210 "Resolved completion changed display label from {} to {}. \
6211 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6212 completion.label.text(),
6213 new_label.text(),
6214 completion.label.filter_text(),
6215 new_label.filter_text()
6216 );
6217 }
6218
6219 Ok(())
6220 }
6221
6222 async fn resolve_completion_remote(
6223 project_id: u64,
6224 server_id: LanguageServerId,
6225 buffer_id: BufferId,
6226 completions: Rc<RefCell<Box<[Completion]>>>,
6227 completion_index: usize,
6228 client: AnyProtoClient,
6229 ) -> Result<()> {
6230 let lsp_completion = {
6231 let completion = &completions.borrow()[completion_index];
6232 match &completion.source {
6233 CompletionSource::Lsp {
6234 lsp_completion,
6235 resolved,
6236 server_id: completion_server_id,
6237 ..
6238 } => {
6239 anyhow::ensure!(
6240 server_id == *completion_server_id,
6241 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6242 );
6243 if *resolved {
6244 return Ok(());
6245 }
6246 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6247 }
6248 CompletionSource::Custom
6249 | CompletionSource::Dap { .. }
6250 | CompletionSource::BufferWord { .. } => {
6251 return Ok(());
6252 }
6253 }
6254 };
6255 let request = proto::ResolveCompletionDocumentation {
6256 project_id,
6257 language_server_id: server_id.0 as u64,
6258 lsp_completion,
6259 buffer_id: buffer_id.into(),
6260 };
6261
6262 let response = client
6263 .request(request)
6264 .await
6265 .context("completion documentation resolve proto request")?;
6266 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6267
6268 let documentation = if response.documentation.is_empty() {
6269 CompletionDocumentation::Undocumented
6270 } else if response.documentation_is_markdown {
6271 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6272 } else if response.documentation.lines().count() <= 1 {
6273 CompletionDocumentation::SingleLine(response.documentation.into())
6274 } else {
6275 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6276 };
6277
6278 let mut completions = completions.borrow_mut();
6279 let completion = &mut completions[completion_index];
6280 completion.documentation = Some(documentation);
6281 if let CompletionSource::Lsp {
6282 insert_range,
6283 lsp_completion,
6284 resolved,
6285 server_id: completion_server_id,
6286 lsp_defaults: _,
6287 } = &mut completion.source
6288 {
6289 let completion_insert_range = response
6290 .old_insert_start
6291 .and_then(deserialize_anchor)
6292 .zip(response.old_insert_end.and_then(deserialize_anchor));
6293 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6294
6295 if *resolved {
6296 return Ok(());
6297 }
6298 anyhow::ensure!(
6299 server_id == *completion_server_id,
6300 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6301 );
6302 *lsp_completion = Box::new(resolved_lsp_completion);
6303 *resolved = true;
6304 }
6305
6306 let replace_range = response
6307 .old_replace_start
6308 .and_then(deserialize_anchor)
6309 .zip(response.old_replace_end.and_then(deserialize_anchor));
6310 if let Some((old_replace_start, old_replace_end)) = replace_range
6311 && !response.new_text.is_empty()
6312 {
6313 completion.new_text = response.new_text;
6314 completion.replace_range = old_replace_start..old_replace_end;
6315 }
6316
6317 Ok(())
6318 }
6319
6320 pub fn apply_additional_edits_for_completion(
6321 &self,
6322 buffer_handle: Entity<Buffer>,
6323 completions: Rc<RefCell<Box<[Completion]>>>,
6324 completion_index: usize,
6325 push_to_history: bool,
6326 cx: &mut Context<Self>,
6327 ) -> Task<Result<Option<Transaction>>> {
6328 if let Some((client, project_id)) = self.upstream_client() {
6329 let buffer = buffer_handle.read(cx);
6330 let buffer_id = buffer.remote_id();
6331 cx.spawn(async move |_, cx| {
6332 let request = {
6333 let completion = completions.borrow()[completion_index].clone();
6334 proto::ApplyCompletionAdditionalEdits {
6335 project_id,
6336 buffer_id: buffer_id.into(),
6337 completion: Some(Self::serialize_completion(&CoreCompletion {
6338 replace_range: completion.replace_range,
6339 new_text: completion.new_text,
6340 source: completion.source,
6341 })),
6342 }
6343 };
6344
6345 if let Some(transaction) = client.request(request).await?.transaction {
6346 let transaction = language::proto::deserialize_transaction(transaction)?;
6347 buffer_handle
6348 .update(cx, |buffer, _| {
6349 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6350 })?
6351 .await?;
6352 if push_to_history {
6353 buffer_handle.update(cx, |buffer, _| {
6354 buffer.push_transaction(transaction.clone(), Instant::now());
6355 buffer.finalize_last_transaction();
6356 })?;
6357 }
6358 Ok(Some(transaction))
6359 } else {
6360 Ok(None)
6361 }
6362 })
6363 } else {
6364 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6365 let completion = &completions.borrow()[completion_index];
6366 let server_id = completion.source.server_id()?;
6367 Some(
6368 self.language_server_for_local_buffer(buffer, server_id, cx)?
6369 .1
6370 .clone(),
6371 )
6372 }) else {
6373 return Task::ready(Ok(None));
6374 };
6375
6376 cx.spawn(async move |this, cx| {
6377 Self::resolve_completion_local(
6378 server.clone(),
6379 completions.clone(),
6380 completion_index,
6381 )
6382 .await
6383 .context("resolving completion")?;
6384 let completion = completions.borrow()[completion_index].clone();
6385 let additional_text_edits = completion
6386 .source
6387 .lsp_completion(true)
6388 .as_ref()
6389 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6390 if let Some(edits) = additional_text_edits {
6391 let edits = this
6392 .update(cx, |this, cx| {
6393 this.as_local_mut().unwrap().edits_from_lsp(
6394 &buffer_handle,
6395 edits,
6396 server.server_id(),
6397 None,
6398 cx,
6399 )
6400 })?
6401 .await?;
6402
6403 buffer_handle.update(cx, |buffer, cx| {
6404 buffer.finalize_last_transaction();
6405 buffer.start_transaction();
6406
6407 for (range, text) in edits {
6408 let primary = &completion.replace_range;
6409
6410 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6411 // and the primary completion is just an insertion (empty range), then this is likely
6412 // an auto-import scenario and should not be considered overlapping
6413 // https://github.com/zed-industries/zed/issues/26136
6414 let is_file_start_auto_import = {
6415 let snapshot = buffer.snapshot();
6416 let primary_start_point = primary.start.to_point(&snapshot);
6417 let range_start_point = range.start.to_point(&snapshot);
6418
6419 let result = primary_start_point.row == 0
6420 && primary_start_point.column == 0
6421 && range_start_point.row == 0
6422 && range_start_point.column == 0;
6423
6424 result
6425 };
6426
6427 let has_overlap = if is_file_start_auto_import {
6428 false
6429 } else {
6430 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6431 && primary.end.cmp(&range.start, buffer).is_ge();
6432 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6433 && range.end.cmp(&primary.end, buffer).is_ge();
6434 let result = start_within || end_within;
6435 result
6436 };
6437
6438 //Skip additional edits which overlap with the primary completion edit
6439 //https://github.com/zed-industries/zed/pull/1871
6440 if !has_overlap {
6441 buffer.edit([(range, text)], None, cx);
6442 }
6443 }
6444
6445 let transaction = if buffer.end_transaction(cx).is_some() {
6446 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6447 if !push_to_history {
6448 buffer.forget_transaction(transaction.id);
6449 }
6450 Some(transaction)
6451 } else {
6452 None
6453 };
6454 Ok(transaction)
6455 })?
6456 } else {
6457 Ok(None)
6458 }
6459 })
6460 }
6461 }
6462
6463 pub fn pull_diagnostics(
6464 &mut self,
6465 buffer: Entity<Buffer>,
6466 cx: &mut Context<Self>,
6467 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6468 let buffer_id = buffer.read(cx).remote_id();
6469
6470 if let Some((client, upstream_project_id)) = self.upstream_client() {
6471 let mut suitable_capabilities = None;
6472 // Are we capable for proto request?
6473 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6474 &buffer,
6475 |capabilities| {
6476 if let Some(caps) = &capabilities.diagnostic_provider {
6477 suitable_capabilities = Some(caps.clone());
6478 true
6479 } else {
6480 false
6481 }
6482 },
6483 cx,
6484 );
6485 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6486 let Some(dynamic_caps) = suitable_capabilities else {
6487 return Task::ready(Ok(None));
6488 };
6489 assert!(any_server_has_diagnostics_provider);
6490
6491 let request = GetDocumentDiagnostics {
6492 previous_result_id: None,
6493 dynamic_caps,
6494 };
6495 let request_task = client.request_lsp(
6496 upstream_project_id,
6497 None,
6498 LSP_REQUEST_TIMEOUT,
6499 cx.background_executor().clone(),
6500 request.to_proto(upstream_project_id, buffer.read(cx)),
6501 );
6502 cx.background_spawn(async move {
6503 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6504 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6505 // Do not attempt to further process the dummy responses here.
6506 let _response = request_task.await?;
6507 Ok(None)
6508 })
6509 } else {
6510 let servers = buffer.update(cx, |buffer, cx| {
6511 self.language_servers_for_local_buffer(buffer, cx)
6512 .map(|(_, server)| server.clone())
6513 .collect::<Vec<_>>()
6514 });
6515
6516 let pull_diagnostics = servers
6517 .into_iter()
6518 .flat_map(|server| {
6519 let result = maybe!({
6520 let local = self.as_local()?;
6521 let server_id = server.server_id();
6522 let providers_with_identifiers = local
6523 .language_server_dynamic_registrations
6524 .get(&server_id)
6525 .into_iter()
6526 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6527 .collect::<Vec<_>>();
6528 Some(
6529 providers_with_identifiers
6530 .into_iter()
6531 .map(|dynamic_caps| {
6532 let result_id = self.result_id(server_id, buffer_id, cx);
6533 self.request_lsp(
6534 buffer.clone(),
6535 LanguageServerToQuery::Other(server_id),
6536 GetDocumentDiagnostics {
6537 previous_result_id: result_id,
6538 dynamic_caps,
6539 },
6540 cx,
6541 )
6542 })
6543 .collect::<Vec<_>>(),
6544 )
6545 });
6546
6547 result.unwrap_or_default()
6548 })
6549 .collect::<Vec<_>>();
6550
6551 cx.background_spawn(async move {
6552 let mut responses = Vec::new();
6553 for diagnostics in join_all(pull_diagnostics).await {
6554 responses.extend(diagnostics?);
6555 }
6556 Ok(Some(responses))
6557 })
6558 }
6559 }
6560
6561 pub fn applicable_inlay_chunks(
6562 &mut self,
6563 buffer: &Entity<Buffer>,
6564 ranges: &[Range<text::Anchor>],
6565 cx: &mut Context<Self>,
6566 ) -> Vec<Range<BufferRow>> {
6567 self.latest_lsp_data(buffer, cx)
6568 .inlay_hints
6569 .applicable_chunks(ranges)
6570 .map(|chunk| chunk.start..chunk.end)
6571 .collect()
6572 }
6573
6574 pub fn invalidate_inlay_hints<'a>(
6575 &'a mut self,
6576 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6577 ) {
6578 for buffer_id in for_buffers {
6579 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6580 lsp_data.inlay_hints.clear();
6581 }
6582 }
6583 }
6584
6585 pub fn inlay_hints(
6586 &mut self,
6587 invalidate: InvalidationStrategy,
6588 buffer: Entity<Buffer>,
6589 ranges: Vec<Range<text::Anchor>>,
6590 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6591 cx: &mut Context<Self>,
6592 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6593 let buffer_snapshot = buffer.read(cx).snapshot();
6594 let for_server = if let InvalidationStrategy::RefreshRequested(server_id) = invalidate {
6595 Some(server_id)
6596 } else {
6597 None
6598 };
6599 let invalidate_cache = invalidate.should_invalidate();
6600 let next_hint_id = self.next_hint_id.clone();
6601 let lsp_data = self.latest_lsp_data(&buffer, cx);
6602 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6603 let known_chunks = known_chunks
6604 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6605 .map(|(_, known_chunks)| known_chunks)
6606 .unwrap_or_default();
6607
6608 let mut hint_fetch_tasks = Vec::new();
6609 let mut cached_inlay_hints = HashMap::default();
6610 let mut ranges_to_query = Vec::new();
6611 let applicable_chunks = existing_inlay_hints
6612 .applicable_chunks(ranges.as_slice())
6613 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6614 .collect::<Vec<_>>();
6615 if applicable_chunks.is_empty() {
6616 return HashMap::default();
6617 }
6618
6619 let last_chunk_number = applicable_chunks.len() - 1;
6620
6621 for (i, row_chunk) in applicable_chunks.into_iter().enumerate() {
6622 match (
6623 existing_inlay_hints
6624 .cached_hints(&row_chunk)
6625 .filter(|_| !invalidate_cache)
6626 .cloned(),
6627 existing_inlay_hints
6628 .fetched_hints(&row_chunk)
6629 .as_ref()
6630 .filter(|_| !invalidate_cache)
6631 .cloned(),
6632 ) {
6633 (None, None) => {
6634 let end = if last_chunk_number == i {
6635 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6636 } else {
6637 Point::new(row_chunk.end, 0)
6638 };
6639 ranges_to_query.push((
6640 row_chunk,
6641 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6642 ..buffer_snapshot.anchor_after(end),
6643 ));
6644 }
6645 (None, Some(fetched_hints)) => {
6646 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()))
6647 }
6648 (Some(cached_hints), None) => {
6649 for (server_id, cached_hints) in cached_hints {
6650 if for_server.is_none_or(|for_server| for_server == server_id) {
6651 cached_inlay_hints
6652 .entry(row_chunk.start..row_chunk.end)
6653 .or_insert_with(HashMap::default)
6654 .entry(server_id)
6655 .or_insert_with(Vec::new)
6656 .extend(cached_hints);
6657 }
6658 }
6659 }
6660 (Some(cached_hints), Some(fetched_hints)) => {
6661 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()));
6662 for (server_id, cached_hints) in cached_hints {
6663 if for_server.is_none_or(|for_server| for_server == server_id) {
6664 cached_inlay_hints
6665 .entry(row_chunk.start..row_chunk.end)
6666 .or_insert_with(HashMap::default)
6667 .entry(server_id)
6668 .or_insert_with(Vec::new)
6669 .extend(cached_hints);
6670 }
6671 }
6672 }
6673 }
6674 }
6675
6676 let cached_chunk_data = cached_inlay_hints
6677 .into_iter()
6678 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6679 .collect();
6680 if hint_fetch_tasks.is_empty() && ranges_to_query.is_empty() {
6681 cached_chunk_data
6682 } else {
6683 if invalidate_cache {
6684 lsp_data.inlay_hints.clear();
6685 }
6686
6687 for (chunk, range_to_query) in ranges_to_query {
6688 let next_hint_id = next_hint_id.clone();
6689 let buffer = buffer.clone();
6690 let new_inlay_hints = cx
6691 .spawn(async move |lsp_store, cx| {
6692 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6693 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6694 })?;
6695 new_fetch_task
6696 .await
6697 .and_then(|new_hints_by_server| {
6698 lsp_store.update(cx, |lsp_store, cx| {
6699 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6700 let update_cache = !lsp_data
6701 .buffer_version
6702 .changed_since(&buffer.read(cx).version());
6703 new_hints_by_server
6704 .into_iter()
6705 .map(|(server_id, new_hints)| {
6706 let new_hints = new_hints
6707 .into_iter()
6708 .map(|new_hint| {
6709 (
6710 InlayId::Hint(next_hint_id.fetch_add(
6711 1,
6712 atomic::Ordering::AcqRel,
6713 )),
6714 new_hint,
6715 )
6716 })
6717 .collect::<Vec<_>>();
6718 if update_cache {
6719 lsp_data.inlay_hints.insert_new_hints(
6720 chunk,
6721 server_id,
6722 new_hints.clone(),
6723 );
6724 }
6725 (server_id, new_hints)
6726 })
6727 .collect()
6728 })
6729 })
6730 .map_err(Arc::new)
6731 })
6732 .shared();
6733
6734 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6735 *fetch_task = Some(new_inlay_hints.clone());
6736 hint_fetch_tasks.push((chunk, new_inlay_hints));
6737 }
6738
6739 let mut combined_data = cached_chunk_data;
6740 combined_data.extend(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6741 (
6742 chunk.start..chunk.end,
6743 cx.spawn(async move |_, _| {
6744 hints_fetch.await.map_err(|e| {
6745 if e.error_code() != ErrorCode::Internal {
6746 anyhow!(e.error_code())
6747 } else {
6748 anyhow!("{e:#}")
6749 }
6750 })
6751 }),
6752 )
6753 }));
6754 combined_data
6755 }
6756 }
6757
6758 fn fetch_inlay_hints(
6759 &mut self,
6760 for_server: Option<LanguageServerId>,
6761 buffer: &Entity<Buffer>,
6762 range: Range<Anchor>,
6763 cx: &mut Context<Self>,
6764 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6765 let request = InlayHints {
6766 range: range.clone(),
6767 };
6768 if let Some((upstream_client, project_id)) = self.upstream_client() {
6769 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6770 return Task::ready(Ok(HashMap::default()));
6771 }
6772 let request_task = upstream_client.request_lsp(
6773 project_id,
6774 for_server.map(|id| id.to_proto()),
6775 LSP_REQUEST_TIMEOUT,
6776 cx.background_executor().clone(),
6777 request.to_proto(project_id, buffer.read(cx)),
6778 );
6779 let buffer = buffer.clone();
6780 cx.spawn(async move |weak_lsp_store, cx| {
6781 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6782 return Ok(HashMap::default());
6783 };
6784 let Some(responses) = request_task.await? else {
6785 return Ok(HashMap::default());
6786 };
6787
6788 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6789 let lsp_store = lsp_store.clone();
6790 let buffer = buffer.clone();
6791 let cx = cx.clone();
6792 let request = request.clone();
6793 async move {
6794 (
6795 LanguageServerId::from_proto(response.server_id),
6796 request
6797 .response_from_proto(response.response, lsp_store, buffer, cx)
6798 .await,
6799 )
6800 }
6801 }))
6802 .await;
6803
6804 let mut has_errors = false;
6805 let inlay_hints = inlay_hints
6806 .into_iter()
6807 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6808 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6809 Err(e) => {
6810 has_errors = true;
6811 log::error!("{e:#}");
6812 None
6813 }
6814 })
6815 .collect::<HashMap<_, _>>();
6816 anyhow::ensure!(
6817 !has_errors || !inlay_hints.is_empty(),
6818 "Failed to fetch inlay hints"
6819 );
6820 Ok(inlay_hints)
6821 })
6822 } else {
6823 let inlay_hints_task = match for_server {
6824 Some(server_id) => {
6825 let server_task = self.request_lsp(
6826 buffer.clone(),
6827 LanguageServerToQuery::Other(server_id),
6828 request,
6829 cx,
6830 );
6831 cx.background_spawn(async move {
6832 let mut responses = Vec::new();
6833 match server_task.await {
6834 Ok(response) => responses.push((server_id, response)),
6835 Err(e) => log::error!(
6836 "Error handling response for inlay hints request: {e:#}"
6837 ),
6838 }
6839 responses
6840 })
6841 }
6842 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6843 };
6844 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6845 cx.background_spawn(async move {
6846 Ok(inlay_hints_task
6847 .await
6848 .into_iter()
6849 .map(|(server_id, mut new_hints)| {
6850 new_hints.retain(|hint| {
6851 hint.position.is_valid(&buffer_snapshot)
6852 && range.start.is_valid(&buffer_snapshot)
6853 && range.end.is_valid(&buffer_snapshot)
6854 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6855 && hint.position.cmp(&range.end, &buffer_snapshot).is_le()
6856 });
6857 (server_id, new_hints)
6858 })
6859 .collect())
6860 })
6861 }
6862 }
6863
6864 pub fn pull_diagnostics_for_buffer(
6865 &mut self,
6866 buffer: Entity<Buffer>,
6867 cx: &mut Context<Self>,
6868 ) -> Task<anyhow::Result<()>> {
6869 let diagnostics = self.pull_diagnostics(buffer, cx);
6870 cx.spawn(async move |lsp_store, cx| {
6871 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6872 return Ok(());
6873 };
6874 lsp_store.update(cx, |lsp_store, cx| {
6875 if lsp_store.as_local().is_none() {
6876 return;
6877 }
6878
6879 let mut unchanged_buffers = HashSet::default();
6880 let mut changed_buffers = HashSet::default();
6881 let server_diagnostics_updates = diagnostics
6882 .into_iter()
6883 .filter_map(|diagnostics_set| match diagnostics_set {
6884 LspPullDiagnostics::Response {
6885 server_id,
6886 uri,
6887 diagnostics,
6888 } => Some((server_id, uri, diagnostics)),
6889 LspPullDiagnostics::Default => None,
6890 })
6891 .fold(
6892 HashMap::default(),
6893 |mut acc, (server_id, uri, diagnostics)| {
6894 let (result_id, diagnostics) = match diagnostics {
6895 PulledDiagnostics::Unchanged { result_id } => {
6896 unchanged_buffers.insert(uri.clone());
6897 (Some(result_id), Vec::new())
6898 }
6899 PulledDiagnostics::Changed {
6900 result_id,
6901 diagnostics,
6902 } => {
6903 changed_buffers.insert(uri.clone());
6904 (result_id, diagnostics)
6905 }
6906 };
6907 let disk_based_sources = Cow::Owned(
6908 lsp_store
6909 .language_server_adapter_for_id(server_id)
6910 .as_ref()
6911 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6912 .unwrap_or(&[])
6913 .to_vec(),
6914 );
6915 acc.entry(server_id).or_insert_with(Vec::new).push(
6916 DocumentDiagnosticsUpdate {
6917 server_id,
6918 diagnostics: lsp::PublishDiagnosticsParams {
6919 uri,
6920 diagnostics,
6921 version: None,
6922 },
6923 result_id,
6924 disk_based_sources,
6925 },
6926 );
6927 acc
6928 },
6929 );
6930
6931 for diagnostic_updates in server_diagnostics_updates.into_values() {
6932 lsp_store
6933 .merge_lsp_diagnostics(
6934 DiagnosticSourceKind::Pulled,
6935 diagnostic_updates,
6936 |buffer, old_diagnostic, cx| {
6937 File::from_dyn(buffer.file())
6938 .and_then(|file| {
6939 let abs_path = file.as_local()?.abs_path(cx);
6940 lsp::Uri::from_file_path(abs_path).ok()
6941 })
6942 .is_none_or(|buffer_uri| {
6943 unchanged_buffers.contains(&buffer_uri)
6944 || match old_diagnostic.source_kind {
6945 DiagnosticSourceKind::Pulled => {
6946 !changed_buffers.contains(&buffer_uri)
6947 }
6948 DiagnosticSourceKind::Other
6949 | DiagnosticSourceKind::Pushed => true,
6950 }
6951 })
6952 },
6953 cx,
6954 )
6955 .log_err();
6956 }
6957 })
6958 })
6959 }
6960
6961 pub fn document_colors(
6962 &mut self,
6963 known_cache_version: Option<usize>,
6964 buffer: Entity<Buffer>,
6965 cx: &mut Context<Self>,
6966 ) -> Option<DocumentColorTask> {
6967 let version_queried_for = buffer.read(cx).version();
6968 let buffer_id = buffer.read(cx).remote_id();
6969
6970 let current_language_servers = self.as_local().map(|local| {
6971 local
6972 .buffers_opened_in_servers
6973 .get(&buffer_id)
6974 .cloned()
6975 .unwrap_or_default()
6976 });
6977
6978 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6979 if let Some(cached_colors) = &lsp_data.document_colors {
6980 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6981 let has_different_servers =
6982 current_language_servers.is_some_and(|current_language_servers| {
6983 current_language_servers
6984 != cached_colors.colors.keys().copied().collect()
6985 });
6986 if !has_different_servers {
6987 let cache_version = cached_colors.cache_version;
6988 if Some(cache_version) == known_cache_version {
6989 return None;
6990 } else {
6991 return Some(
6992 Task::ready(Ok(DocumentColors {
6993 colors: cached_colors
6994 .colors
6995 .values()
6996 .flatten()
6997 .cloned()
6998 .collect(),
6999 cache_version: Some(cache_version),
7000 }))
7001 .shared(),
7002 );
7003 }
7004 }
7005 }
7006 }
7007 }
7008
7009 let color_lsp_data = self
7010 .latest_lsp_data(&buffer, cx)
7011 .document_colors
7012 .get_or_insert_default();
7013 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7014 && !version_queried_for.changed_since(updating_for)
7015 {
7016 return Some(running_update.clone());
7017 }
7018 let buffer_version_queried_for = version_queried_for.clone();
7019 let new_task = cx
7020 .spawn(async move |lsp_store, cx| {
7021 cx.background_executor()
7022 .timer(Duration::from_millis(30))
7023 .await;
7024 let fetched_colors = lsp_store
7025 .update(cx, |lsp_store, cx| {
7026 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7027 })?
7028 .await
7029 .context("fetching document colors")
7030 .map_err(Arc::new);
7031 let fetched_colors = match fetched_colors {
7032 Ok(fetched_colors) => {
7033 if Some(true)
7034 == buffer
7035 .update(cx, |buffer, _| {
7036 buffer.version() != buffer_version_queried_for
7037 })
7038 .ok()
7039 {
7040 return Ok(DocumentColors::default());
7041 }
7042 fetched_colors
7043 }
7044 Err(e) => {
7045 lsp_store
7046 .update(cx, |lsp_store, _| {
7047 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7048 if let Some(document_colors) = &mut lsp_data.document_colors {
7049 document_colors.colors_update = None;
7050 }
7051 }
7052 })
7053 .ok();
7054 return Err(e);
7055 }
7056 };
7057
7058 lsp_store
7059 .update(cx, |lsp_store, cx| {
7060 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7061 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7062
7063 if let Some(fetched_colors) = fetched_colors {
7064 if lsp_data.buffer_version == buffer_version_queried_for {
7065 lsp_colors.colors.extend(fetched_colors);
7066 lsp_colors.cache_version += 1;
7067 } else if !lsp_data
7068 .buffer_version
7069 .changed_since(&buffer_version_queried_for)
7070 {
7071 lsp_data.buffer_version = buffer_version_queried_for;
7072 lsp_colors.colors = fetched_colors;
7073 lsp_colors.cache_version += 1;
7074 }
7075 }
7076 lsp_colors.colors_update = None;
7077 let colors = lsp_colors
7078 .colors
7079 .values()
7080 .flatten()
7081 .cloned()
7082 .collect::<HashSet<_>>();
7083 DocumentColors {
7084 colors,
7085 cache_version: Some(lsp_colors.cache_version),
7086 }
7087 })
7088 .map_err(Arc::new)
7089 })
7090 .shared();
7091 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7092 Some(new_task)
7093 }
7094
7095 fn fetch_document_colors_for_buffer(
7096 &mut self,
7097 buffer: &Entity<Buffer>,
7098 cx: &mut Context<Self>,
7099 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7100 if let Some((client, project_id)) = self.upstream_client() {
7101 let request = GetDocumentColor {};
7102 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7103 return Task::ready(Ok(None));
7104 }
7105
7106 let request_task = client.request_lsp(
7107 project_id,
7108 None,
7109 LSP_REQUEST_TIMEOUT,
7110 cx.background_executor().clone(),
7111 request.to_proto(project_id, buffer.read(cx)),
7112 );
7113 let buffer = buffer.clone();
7114 cx.spawn(async move |lsp_store, cx| {
7115 let Some(project) = lsp_store.upgrade() else {
7116 return Ok(None);
7117 };
7118 let colors = join_all(
7119 request_task
7120 .await
7121 .log_err()
7122 .flatten()
7123 .map(|response| response.payload)
7124 .unwrap_or_default()
7125 .into_iter()
7126 .map(|color_response| {
7127 let response = request.response_from_proto(
7128 color_response.response,
7129 project.clone(),
7130 buffer.clone(),
7131 cx.clone(),
7132 );
7133 async move {
7134 (
7135 LanguageServerId::from_proto(color_response.server_id),
7136 response.await.log_err().unwrap_or_default(),
7137 )
7138 }
7139 }),
7140 )
7141 .await
7142 .into_iter()
7143 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7144 acc.entry(server_id)
7145 .or_insert_with(HashSet::default)
7146 .extend(colors);
7147 acc
7148 });
7149 Ok(Some(colors))
7150 })
7151 } else {
7152 let document_colors_task =
7153 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7154 cx.background_spawn(async move {
7155 Ok(Some(
7156 document_colors_task
7157 .await
7158 .into_iter()
7159 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7160 acc.entry(server_id)
7161 .or_insert_with(HashSet::default)
7162 .extend(colors);
7163 acc
7164 })
7165 .into_iter()
7166 .collect(),
7167 ))
7168 })
7169 }
7170 }
7171
7172 pub fn signature_help<T: ToPointUtf16>(
7173 &mut self,
7174 buffer: &Entity<Buffer>,
7175 position: T,
7176 cx: &mut Context<Self>,
7177 ) -> Task<Option<Vec<SignatureHelp>>> {
7178 let position = position.to_point_utf16(buffer.read(cx));
7179
7180 if let Some((client, upstream_project_id)) = self.upstream_client() {
7181 let request = GetSignatureHelp { position };
7182 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7183 return Task::ready(None);
7184 }
7185 let request_task = client.request_lsp(
7186 upstream_project_id,
7187 None,
7188 LSP_REQUEST_TIMEOUT,
7189 cx.background_executor().clone(),
7190 request.to_proto(upstream_project_id, buffer.read(cx)),
7191 );
7192 let buffer = buffer.clone();
7193 cx.spawn(async move |weak_project, cx| {
7194 let project = weak_project.upgrade()?;
7195 let signatures = join_all(
7196 request_task
7197 .await
7198 .log_err()
7199 .flatten()
7200 .map(|response| response.payload)
7201 .unwrap_or_default()
7202 .into_iter()
7203 .map(|response| {
7204 let response = GetSignatureHelp { position }.response_from_proto(
7205 response.response,
7206 project.clone(),
7207 buffer.clone(),
7208 cx.clone(),
7209 );
7210 async move { response.await.log_err().flatten() }
7211 }),
7212 )
7213 .await
7214 .into_iter()
7215 .flatten()
7216 .collect();
7217 Some(signatures)
7218 })
7219 } else {
7220 let all_actions_task = self.request_multiple_lsp_locally(
7221 buffer,
7222 Some(position),
7223 GetSignatureHelp { position },
7224 cx,
7225 );
7226 cx.background_spawn(async move {
7227 Some(
7228 all_actions_task
7229 .await
7230 .into_iter()
7231 .flat_map(|(_, actions)| actions)
7232 .collect::<Vec<_>>(),
7233 )
7234 })
7235 }
7236 }
7237
7238 pub fn hover(
7239 &mut self,
7240 buffer: &Entity<Buffer>,
7241 position: PointUtf16,
7242 cx: &mut Context<Self>,
7243 ) -> Task<Option<Vec<Hover>>> {
7244 if let Some((client, upstream_project_id)) = self.upstream_client() {
7245 let request = GetHover { position };
7246 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7247 return Task::ready(None);
7248 }
7249 let request_task = client.request_lsp(
7250 upstream_project_id,
7251 None,
7252 LSP_REQUEST_TIMEOUT,
7253 cx.background_executor().clone(),
7254 request.to_proto(upstream_project_id, buffer.read(cx)),
7255 );
7256 let buffer = buffer.clone();
7257 cx.spawn(async move |weak_project, cx| {
7258 let project = weak_project.upgrade()?;
7259 let hovers = join_all(
7260 request_task
7261 .await
7262 .log_err()
7263 .flatten()
7264 .map(|response| response.payload)
7265 .unwrap_or_default()
7266 .into_iter()
7267 .map(|response| {
7268 let response = GetHover { position }.response_from_proto(
7269 response.response,
7270 project.clone(),
7271 buffer.clone(),
7272 cx.clone(),
7273 );
7274 async move {
7275 response
7276 .await
7277 .log_err()
7278 .flatten()
7279 .and_then(remove_empty_hover_blocks)
7280 }
7281 }),
7282 )
7283 .await
7284 .into_iter()
7285 .flatten()
7286 .collect();
7287 Some(hovers)
7288 })
7289 } else {
7290 let all_actions_task = self.request_multiple_lsp_locally(
7291 buffer,
7292 Some(position),
7293 GetHover { position },
7294 cx,
7295 );
7296 cx.background_spawn(async move {
7297 Some(
7298 all_actions_task
7299 .await
7300 .into_iter()
7301 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7302 .collect::<Vec<Hover>>(),
7303 )
7304 })
7305 }
7306 }
7307
7308 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7309 let language_registry = self.languages.clone();
7310
7311 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7312 let request = upstream_client.request(proto::GetProjectSymbols {
7313 project_id: *project_id,
7314 query: query.to_string(),
7315 });
7316 cx.foreground_executor().spawn(async move {
7317 let response = request.await?;
7318 let mut symbols = Vec::new();
7319 let core_symbols = response
7320 .symbols
7321 .into_iter()
7322 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7323 .collect::<Vec<_>>();
7324 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7325 .await;
7326 Ok(symbols)
7327 })
7328 } else if let Some(local) = self.as_local() {
7329 struct WorkspaceSymbolsResult {
7330 server_id: LanguageServerId,
7331 lsp_adapter: Arc<CachedLspAdapter>,
7332 worktree: WeakEntity<Worktree>,
7333 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7334 }
7335
7336 let mut requests = Vec::new();
7337 let mut requested_servers = BTreeSet::new();
7338 for (seed, state) in local.language_server_ids.iter() {
7339 let Some(worktree_handle) = self
7340 .worktree_store
7341 .read(cx)
7342 .worktree_for_id(seed.worktree_id, cx)
7343 else {
7344 continue;
7345 };
7346 let worktree = worktree_handle.read(cx);
7347 if !worktree.is_visible() {
7348 continue;
7349 }
7350
7351 if !requested_servers.insert(state.id) {
7352 continue;
7353 }
7354
7355 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7356 Some(LanguageServerState::Running {
7357 adapter, server, ..
7358 }) => (adapter.clone(), server),
7359
7360 _ => continue,
7361 };
7362 let supports_workspace_symbol_request =
7363 match server.capabilities().workspace_symbol_provider {
7364 Some(OneOf::Left(supported)) => supported,
7365 Some(OneOf::Right(_)) => true,
7366 None => false,
7367 };
7368 if !supports_workspace_symbol_request {
7369 continue;
7370 }
7371 let worktree_handle = worktree_handle.clone();
7372 let server_id = server.server_id();
7373 requests.push(
7374 server
7375 .request::<lsp::request::WorkspaceSymbolRequest>(
7376 lsp::WorkspaceSymbolParams {
7377 query: query.to_string(),
7378 ..Default::default()
7379 },
7380 )
7381 .map(move |response| {
7382 let lsp_symbols = response.into_response()
7383 .context("workspace symbols request")
7384 .log_err()
7385 .flatten()
7386 .map(|symbol_response| match symbol_response {
7387 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7388 flat_responses.into_iter().map(|lsp_symbol| {
7389 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7390 }).collect::<Vec<_>>()
7391 }
7392 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7393 nested_responses.into_iter().filter_map(|lsp_symbol| {
7394 let location = match lsp_symbol.location {
7395 OneOf::Left(location) => location,
7396 OneOf::Right(_) => {
7397 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7398 return None
7399 }
7400 };
7401 Some((lsp_symbol.name, lsp_symbol.kind, location))
7402 }).collect::<Vec<_>>()
7403 }
7404 }).unwrap_or_default();
7405
7406 WorkspaceSymbolsResult {
7407 server_id,
7408 lsp_adapter,
7409 worktree: worktree_handle.downgrade(),
7410 lsp_symbols,
7411 }
7412 }),
7413 );
7414 }
7415
7416 cx.spawn(async move |this, cx| {
7417 let responses = futures::future::join_all(requests).await;
7418 let this = match this.upgrade() {
7419 Some(this) => this,
7420 None => return Ok(Vec::new()),
7421 };
7422
7423 let mut symbols = Vec::new();
7424 for result in responses {
7425 let core_symbols = this.update(cx, |this, cx| {
7426 result
7427 .lsp_symbols
7428 .into_iter()
7429 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7430 let abs_path = symbol_location.uri.to_file_path().ok()?;
7431 let source_worktree = result.worktree.upgrade()?;
7432 let source_worktree_id = source_worktree.read(cx).id();
7433
7434 let path = if let Some((tree, rel_path)) =
7435 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7436 {
7437 let worktree_id = tree.read(cx).id();
7438 SymbolLocation::InProject(ProjectPath {
7439 worktree_id,
7440 path: rel_path,
7441 })
7442 } else {
7443 SymbolLocation::OutsideProject {
7444 signature: this.symbol_signature(&abs_path),
7445 abs_path: abs_path.into(),
7446 }
7447 };
7448
7449 Some(CoreSymbol {
7450 source_language_server_id: result.server_id,
7451 language_server_name: result.lsp_adapter.name.clone(),
7452 source_worktree_id,
7453 path,
7454 kind: symbol_kind,
7455 name: symbol_name,
7456 range: range_from_lsp(symbol_location.range),
7457 })
7458 })
7459 .collect()
7460 })?;
7461
7462 populate_labels_for_symbols(
7463 core_symbols,
7464 &language_registry,
7465 Some(result.lsp_adapter),
7466 &mut symbols,
7467 )
7468 .await;
7469 }
7470
7471 Ok(symbols)
7472 })
7473 } else {
7474 Task::ready(Err(anyhow!("No upstream client or local language server")))
7475 }
7476 }
7477
7478 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7479 let mut summary = DiagnosticSummary::default();
7480 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7481 summary.error_count += path_summary.error_count;
7482 summary.warning_count += path_summary.warning_count;
7483 }
7484 summary
7485 }
7486
7487 /// Returns the diagnostic summary for a specific project path.
7488 pub fn diagnostic_summary_for_path(
7489 &self,
7490 project_path: &ProjectPath,
7491 _: &App,
7492 ) -> DiagnosticSummary {
7493 if let Some(summaries) = self
7494 .diagnostic_summaries
7495 .get(&project_path.worktree_id)
7496 .and_then(|map| map.get(&project_path.path))
7497 {
7498 let (error_count, warning_count) = summaries.iter().fold(
7499 (0, 0),
7500 |(error_count, warning_count), (_language_server_id, summary)| {
7501 (
7502 error_count + summary.error_count,
7503 warning_count + summary.warning_count,
7504 )
7505 },
7506 );
7507
7508 DiagnosticSummary {
7509 error_count,
7510 warning_count,
7511 }
7512 } else {
7513 DiagnosticSummary::default()
7514 }
7515 }
7516
7517 pub fn diagnostic_summaries<'a>(
7518 &'a self,
7519 include_ignored: bool,
7520 cx: &'a App,
7521 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7522 self.worktree_store
7523 .read(cx)
7524 .visible_worktrees(cx)
7525 .filter_map(|worktree| {
7526 let worktree = worktree.read(cx);
7527 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7528 })
7529 .flat_map(move |(worktree, summaries)| {
7530 let worktree_id = worktree.id();
7531 summaries
7532 .iter()
7533 .filter(move |(path, _)| {
7534 include_ignored
7535 || worktree
7536 .entry_for_path(path.as_ref())
7537 .is_some_and(|entry| !entry.is_ignored)
7538 })
7539 .flat_map(move |(path, summaries)| {
7540 summaries.iter().map(move |(server_id, summary)| {
7541 (
7542 ProjectPath {
7543 worktree_id,
7544 path: path.clone(),
7545 },
7546 *server_id,
7547 *summary,
7548 )
7549 })
7550 })
7551 })
7552 }
7553
7554 pub fn on_buffer_edited(
7555 &mut self,
7556 buffer: Entity<Buffer>,
7557 cx: &mut Context<Self>,
7558 ) -> Option<()> {
7559 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7560 Some(
7561 self.as_local()?
7562 .language_servers_for_buffer(buffer, cx)
7563 .map(|i| i.1.clone())
7564 .collect(),
7565 )
7566 })?;
7567
7568 let buffer = buffer.read(cx);
7569 let file = File::from_dyn(buffer.file())?;
7570 let abs_path = file.as_local()?.abs_path(cx);
7571 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7572 let next_snapshot = buffer.text_snapshot();
7573 for language_server in language_servers {
7574 let language_server = language_server.clone();
7575
7576 let buffer_snapshots = self
7577 .as_local_mut()
7578 .unwrap()
7579 .buffer_snapshots
7580 .get_mut(&buffer.remote_id())
7581 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7582 let previous_snapshot = buffer_snapshots.last()?;
7583
7584 let build_incremental_change = || {
7585 buffer
7586 .edits_since::<Dimensions<PointUtf16, usize>>(
7587 previous_snapshot.snapshot.version(),
7588 )
7589 .map(|edit| {
7590 let edit_start = edit.new.start.0;
7591 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7592 let new_text = next_snapshot
7593 .text_for_range(edit.new.start.1..edit.new.end.1)
7594 .collect();
7595 lsp::TextDocumentContentChangeEvent {
7596 range: Some(lsp::Range::new(
7597 point_to_lsp(edit_start),
7598 point_to_lsp(edit_end),
7599 )),
7600 range_length: None,
7601 text: new_text,
7602 }
7603 })
7604 .collect()
7605 };
7606
7607 let document_sync_kind = language_server
7608 .capabilities()
7609 .text_document_sync
7610 .as_ref()
7611 .and_then(|sync| match sync {
7612 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7613 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7614 });
7615
7616 let content_changes: Vec<_> = match document_sync_kind {
7617 Some(lsp::TextDocumentSyncKind::FULL) => {
7618 vec![lsp::TextDocumentContentChangeEvent {
7619 range: None,
7620 range_length: None,
7621 text: next_snapshot.text(),
7622 }]
7623 }
7624 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7625 _ => {
7626 #[cfg(any(test, feature = "test-support"))]
7627 {
7628 build_incremental_change()
7629 }
7630
7631 #[cfg(not(any(test, feature = "test-support")))]
7632 {
7633 continue;
7634 }
7635 }
7636 };
7637
7638 let next_version = previous_snapshot.version + 1;
7639 buffer_snapshots.push(LspBufferSnapshot {
7640 version: next_version,
7641 snapshot: next_snapshot.clone(),
7642 });
7643
7644 language_server
7645 .notify::<lsp::notification::DidChangeTextDocument>(
7646 lsp::DidChangeTextDocumentParams {
7647 text_document: lsp::VersionedTextDocumentIdentifier::new(
7648 uri.clone(),
7649 next_version,
7650 ),
7651 content_changes,
7652 },
7653 )
7654 .ok();
7655 self.pull_workspace_diagnostics(language_server.server_id());
7656 }
7657
7658 None
7659 }
7660
7661 pub fn on_buffer_saved(
7662 &mut self,
7663 buffer: Entity<Buffer>,
7664 cx: &mut Context<Self>,
7665 ) -> Option<()> {
7666 let file = File::from_dyn(buffer.read(cx).file())?;
7667 let worktree_id = file.worktree_id(cx);
7668 let abs_path = file.as_local()?.abs_path(cx);
7669 let text_document = lsp::TextDocumentIdentifier {
7670 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7671 };
7672 let local = self.as_local()?;
7673
7674 for server in local.language_servers_for_worktree(worktree_id) {
7675 if let Some(include_text) = include_text(server.as_ref()) {
7676 let text = if include_text {
7677 Some(buffer.read(cx).text())
7678 } else {
7679 None
7680 };
7681 server
7682 .notify::<lsp::notification::DidSaveTextDocument>(
7683 lsp::DidSaveTextDocumentParams {
7684 text_document: text_document.clone(),
7685 text,
7686 },
7687 )
7688 .ok();
7689 }
7690 }
7691
7692 let language_servers = buffer.update(cx, |buffer, cx| {
7693 local.language_server_ids_for_buffer(buffer, cx)
7694 });
7695 for language_server_id in language_servers {
7696 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7697 }
7698
7699 None
7700 }
7701
7702 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7703 maybe!(async move {
7704 let mut refreshed_servers = HashSet::default();
7705 let servers = lsp_store
7706 .update(cx, |lsp_store, cx| {
7707 let local = lsp_store.as_local()?;
7708
7709 let servers = local
7710 .language_server_ids
7711 .iter()
7712 .filter_map(|(seed, state)| {
7713 let worktree = lsp_store
7714 .worktree_store
7715 .read(cx)
7716 .worktree_for_id(seed.worktree_id, cx);
7717 let delegate: Arc<dyn LspAdapterDelegate> =
7718 worktree.map(|worktree| {
7719 LocalLspAdapterDelegate::new(
7720 local.languages.clone(),
7721 &local.environment,
7722 cx.weak_entity(),
7723 &worktree,
7724 local.http_client.clone(),
7725 local.fs.clone(),
7726 cx,
7727 )
7728 })?;
7729 let server_id = state.id;
7730
7731 let states = local.language_servers.get(&server_id)?;
7732
7733 match states {
7734 LanguageServerState::Starting { .. } => None,
7735 LanguageServerState::Running {
7736 adapter, server, ..
7737 } => {
7738 let adapter = adapter.clone();
7739 let server = server.clone();
7740 refreshed_servers.insert(server.name());
7741 let toolchain = seed.toolchain.clone();
7742 Some(cx.spawn(async move |_, cx| {
7743 let settings =
7744 LocalLspStore::workspace_configuration_for_adapter(
7745 adapter.adapter.clone(),
7746 &delegate,
7747 toolchain,
7748 cx,
7749 )
7750 .await
7751 .ok()?;
7752 server
7753 .notify::<lsp::notification::DidChangeConfiguration>(
7754 lsp::DidChangeConfigurationParams { settings },
7755 )
7756 .ok()?;
7757 Some(())
7758 }))
7759 }
7760 }
7761 })
7762 .collect::<Vec<_>>();
7763
7764 Some(servers)
7765 })
7766 .ok()
7767 .flatten()?;
7768
7769 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7770 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7771 // to stop and unregister its language server wrapper.
7772 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7773 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7774 let _: Vec<Option<()>> = join_all(servers).await;
7775
7776 Some(())
7777 })
7778 .await;
7779 }
7780
7781 fn maintain_workspace_config(
7782 external_refresh_requests: watch::Receiver<()>,
7783 cx: &mut Context<Self>,
7784 ) -> Task<Result<()>> {
7785 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7786 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7787
7788 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7789 *settings_changed_tx.borrow_mut() = ();
7790 });
7791
7792 let mut joint_future =
7793 futures::stream::select(settings_changed_rx, external_refresh_requests);
7794 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7795 // - 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).
7796 // - 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.
7797 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7798 // - 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,
7799 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7800 cx.spawn(async move |this, cx| {
7801 while let Some(()) = joint_future.next().await {
7802 this.update(cx, |this, cx| {
7803 this.refresh_server_tree(cx);
7804 })
7805 .ok();
7806
7807 Self::refresh_workspace_configurations(&this, cx).await;
7808 }
7809
7810 drop(settings_observation);
7811 anyhow::Ok(())
7812 })
7813 }
7814
7815 pub fn language_servers_for_local_buffer<'a>(
7816 &'a self,
7817 buffer: &Buffer,
7818 cx: &mut App,
7819 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7820 let local = self.as_local();
7821 let language_server_ids = local
7822 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7823 .unwrap_or_default();
7824
7825 language_server_ids
7826 .into_iter()
7827 .filter_map(
7828 move |server_id| match local?.language_servers.get(&server_id)? {
7829 LanguageServerState::Running {
7830 adapter, server, ..
7831 } => Some((adapter, server)),
7832 _ => None,
7833 },
7834 )
7835 }
7836
7837 pub fn language_server_for_local_buffer<'a>(
7838 &'a self,
7839 buffer: &'a Buffer,
7840 server_id: LanguageServerId,
7841 cx: &'a mut App,
7842 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7843 self.as_local()?
7844 .language_servers_for_buffer(buffer, cx)
7845 .find(|(_, s)| s.server_id() == server_id)
7846 }
7847
7848 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7849 self.diagnostic_summaries.remove(&id_to_remove);
7850 if let Some(local) = self.as_local_mut() {
7851 let to_remove = local.remove_worktree(id_to_remove, cx);
7852 for server in to_remove {
7853 self.language_server_statuses.remove(&server);
7854 }
7855 }
7856 }
7857
7858 pub fn shared(
7859 &mut self,
7860 project_id: u64,
7861 downstream_client: AnyProtoClient,
7862 _: &mut Context<Self>,
7863 ) {
7864 self.downstream_client = Some((downstream_client.clone(), project_id));
7865
7866 for (server_id, status) in &self.language_server_statuses {
7867 if let Some(server) = self.language_server_for_id(*server_id) {
7868 downstream_client
7869 .send(proto::StartLanguageServer {
7870 project_id,
7871 server: Some(proto::LanguageServer {
7872 id: server_id.to_proto(),
7873 name: status.name.to_string(),
7874 worktree_id: status.worktree.map(|id| id.to_proto()),
7875 }),
7876 capabilities: serde_json::to_string(&server.capabilities())
7877 .expect("serializing server LSP capabilities"),
7878 })
7879 .log_err();
7880 }
7881 }
7882 }
7883
7884 pub fn disconnected_from_host(&mut self) {
7885 self.downstream_client.take();
7886 }
7887
7888 pub fn disconnected_from_ssh_remote(&mut self) {
7889 if let LspStoreMode::Remote(RemoteLspStore {
7890 upstream_client, ..
7891 }) = &mut self.mode
7892 {
7893 upstream_client.take();
7894 }
7895 }
7896
7897 pub(crate) fn set_language_server_statuses_from_proto(
7898 &mut self,
7899 project: WeakEntity<Project>,
7900 language_servers: Vec<proto::LanguageServer>,
7901 server_capabilities: Vec<String>,
7902 cx: &mut Context<Self>,
7903 ) {
7904 let lsp_logs = cx
7905 .try_global::<GlobalLogStore>()
7906 .map(|lsp_store| lsp_store.0.clone());
7907
7908 self.language_server_statuses = language_servers
7909 .into_iter()
7910 .zip(server_capabilities)
7911 .map(|(server, server_capabilities)| {
7912 let server_id = LanguageServerId(server.id as usize);
7913 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7914 self.lsp_server_capabilities
7915 .insert(server_id, server_capabilities);
7916 }
7917
7918 let name = LanguageServerName::from_proto(server.name);
7919 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7920
7921 if let Some(lsp_logs) = &lsp_logs {
7922 lsp_logs.update(cx, |lsp_logs, cx| {
7923 lsp_logs.add_language_server(
7924 // Only remote clients get their language servers set from proto
7925 LanguageServerKind::Remote {
7926 project: project.clone(),
7927 },
7928 server_id,
7929 Some(name.clone()),
7930 worktree,
7931 None,
7932 cx,
7933 );
7934 });
7935 }
7936
7937 (
7938 server_id,
7939 LanguageServerStatus {
7940 name,
7941 pending_work: Default::default(),
7942 has_pending_diagnostic_updates: false,
7943 progress_tokens: Default::default(),
7944 worktree,
7945 },
7946 )
7947 })
7948 .collect();
7949 }
7950
7951 #[cfg(test)]
7952 pub fn update_diagnostic_entries(
7953 &mut self,
7954 server_id: LanguageServerId,
7955 abs_path: PathBuf,
7956 result_id: Option<String>,
7957 version: Option<i32>,
7958 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7959 cx: &mut Context<Self>,
7960 ) -> anyhow::Result<()> {
7961 self.merge_diagnostic_entries(
7962 vec![DocumentDiagnosticsUpdate {
7963 diagnostics: DocumentDiagnostics {
7964 diagnostics,
7965 document_abs_path: abs_path,
7966 version,
7967 },
7968 result_id,
7969 server_id,
7970 disk_based_sources: Cow::Borrowed(&[]),
7971 }],
7972 |_, _, _| false,
7973 cx,
7974 )?;
7975 Ok(())
7976 }
7977
7978 pub fn merge_diagnostic_entries<'a>(
7979 &mut self,
7980 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7981 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7982 cx: &mut Context<Self>,
7983 ) -> anyhow::Result<()> {
7984 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7985 let mut updated_diagnostics_paths = HashMap::default();
7986 for mut update in diagnostic_updates {
7987 let abs_path = &update.diagnostics.document_abs_path;
7988 let server_id = update.server_id;
7989 let Some((worktree, relative_path)) =
7990 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7991 else {
7992 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7993 return Ok(());
7994 };
7995
7996 let worktree_id = worktree.read(cx).id();
7997 let project_path = ProjectPath {
7998 worktree_id,
7999 path: relative_path,
8000 };
8001
8002 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8003 let snapshot = buffer_handle.read(cx).snapshot();
8004 let buffer = buffer_handle.read(cx);
8005 let reused_diagnostics = buffer
8006 .buffer_diagnostics(Some(server_id))
8007 .iter()
8008 .filter(|v| merge(buffer, &v.diagnostic, cx))
8009 .map(|v| {
8010 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8011 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8012 DiagnosticEntry {
8013 range: start..end,
8014 diagnostic: v.diagnostic.clone(),
8015 }
8016 })
8017 .collect::<Vec<_>>();
8018
8019 self.as_local_mut()
8020 .context("cannot merge diagnostics on a remote LspStore")?
8021 .update_buffer_diagnostics(
8022 &buffer_handle,
8023 server_id,
8024 update.result_id,
8025 update.diagnostics.version,
8026 update.diagnostics.diagnostics.clone(),
8027 reused_diagnostics.clone(),
8028 cx,
8029 )?;
8030
8031 update.diagnostics.diagnostics.extend(reused_diagnostics);
8032 }
8033
8034 let updated = worktree.update(cx, |worktree, cx| {
8035 self.update_worktree_diagnostics(
8036 worktree.id(),
8037 server_id,
8038 project_path.path.clone(),
8039 update.diagnostics.diagnostics,
8040 cx,
8041 )
8042 })?;
8043 match updated {
8044 ControlFlow::Continue(new_summary) => {
8045 if let Some((project_id, new_summary)) = new_summary {
8046 match &mut diagnostics_summary {
8047 Some(diagnostics_summary) => {
8048 diagnostics_summary
8049 .more_summaries
8050 .push(proto::DiagnosticSummary {
8051 path: project_path.path.as_ref().to_proto(),
8052 language_server_id: server_id.0 as u64,
8053 error_count: new_summary.error_count,
8054 warning_count: new_summary.warning_count,
8055 })
8056 }
8057 None => {
8058 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8059 project_id,
8060 worktree_id: worktree_id.to_proto(),
8061 summary: Some(proto::DiagnosticSummary {
8062 path: project_path.path.as_ref().to_proto(),
8063 language_server_id: server_id.0 as u64,
8064 error_count: new_summary.error_count,
8065 warning_count: new_summary.warning_count,
8066 }),
8067 more_summaries: Vec::new(),
8068 })
8069 }
8070 }
8071 }
8072 updated_diagnostics_paths
8073 .entry(server_id)
8074 .or_insert_with(Vec::new)
8075 .push(project_path);
8076 }
8077 ControlFlow::Break(()) => {}
8078 }
8079 }
8080
8081 if let Some((diagnostics_summary, (downstream_client, _))) =
8082 diagnostics_summary.zip(self.downstream_client.as_ref())
8083 {
8084 downstream_client.send(diagnostics_summary).log_err();
8085 }
8086 for (server_id, paths) in updated_diagnostics_paths {
8087 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8088 }
8089 Ok(())
8090 }
8091
8092 fn update_worktree_diagnostics(
8093 &mut self,
8094 worktree_id: WorktreeId,
8095 server_id: LanguageServerId,
8096 path_in_worktree: Arc<RelPath>,
8097 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8098 _: &mut Context<Worktree>,
8099 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8100 let local = match &mut self.mode {
8101 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8102 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8103 };
8104
8105 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8106 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8107 let summaries_by_server_id = summaries_for_tree
8108 .entry(path_in_worktree.clone())
8109 .or_default();
8110
8111 let old_summary = summaries_by_server_id
8112 .remove(&server_id)
8113 .unwrap_or_default();
8114
8115 let new_summary = DiagnosticSummary::new(&diagnostics);
8116 if new_summary.is_empty() {
8117 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8118 {
8119 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8120 diagnostics_by_server_id.remove(ix);
8121 }
8122 if diagnostics_by_server_id.is_empty() {
8123 diagnostics_for_tree.remove(&path_in_worktree);
8124 }
8125 }
8126 } else {
8127 summaries_by_server_id.insert(server_id, new_summary);
8128 let diagnostics_by_server_id = diagnostics_for_tree
8129 .entry(path_in_worktree.clone())
8130 .or_default();
8131 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8132 Ok(ix) => {
8133 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8134 }
8135 Err(ix) => {
8136 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8137 }
8138 }
8139 }
8140
8141 if !old_summary.is_empty() || !new_summary.is_empty() {
8142 if let Some((_, project_id)) = &self.downstream_client {
8143 Ok(ControlFlow::Continue(Some((
8144 *project_id,
8145 proto::DiagnosticSummary {
8146 path: path_in_worktree.to_proto(),
8147 language_server_id: server_id.0 as u64,
8148 error_count: new_summary.error_count as u32,
8149 warning_count: new_summary.warning_count as u32,
8150 },
8151 ))))
8152 } else {
8153 Ok(ControlFlow::Continue(None))
8154 }
8155 } else {
8156 Ok(ControlFlow::Break(()))
8157 }
8158 }
8159
8160 pub fn open_buffer_for_symbol(
8161 &mut self,
8162 symbol: &Symbol,
8163 cx: &mut Context<Self>,
8164 ) -> Task<Result<Entity<Buffer>>> {
8165 if let Some((client, project_id)) = self.upstream_client() {
8166 let request = client.request(proto::OpenBufferForSymbol {
8167 project_id,
8168 symbol: Some(Self::serialize_symbol(symbol)),
8169 });
8170 cx.spawn(async move |this, cx| {
8171 let response = request.await?;
8172 let buffer_id = BufferId::new(response.buffer_id)?;
8173 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8174 .await
8175 })
8176 } else if let Some(local) = self.as_local() {
8177 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8178 seed.worktree_id == symbol.source_worktree_id
8179 && state.id == symbol.source_language_server_id
8180 && symbol.language_server_name == seed.name
8181 });
8182 if !is_valid {
8183 return Task::ready(Err(anyhow!(
8184 "language server for worktree and language not found"
8185 )));
8186 };
8187
8188 let symbol_abs_path = match &symbol.path {
8189 SymbolLocation::InProject(project_path) => self
8190 .worktree_store
8191 .read(cx)
8192 .absolutize(&project_path, cx)
8193 .context("no such worktree"),
8194 SymbolLocation::OutsideProject {
8195 abs_path,
8196 signature: _,
8197 } => Ok(abs_path.to_path_buf()),
8198 };
8199 let symbol_abs_path = match symbol_abs_path {
8200 Ok(abs_path) => abs_path,
8201 Err(err) => return Task::ready(Err(err)),
8202 };
8203 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8204 uri
8205 } else {
8206 return Task::ready(Err(anyhow!("invalid symbol path")));
8207 };
8208
8209 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8210 } else {
8211 Task::ready(Err(anyhow!("no upstream client or local store")))
8212 }
8213 }
8214
8215 pub(crate) fn open_local_buffer_via_lsp(
8216 &mut self,
8217 abs_path: lsp::Uri,
8218 language_server_id: LanguageServerId,
8219 cx: &mut Context<Self>,
8220 ) -> Task<Result<Entity<Buffer>>> {
8221 cx.spawn(async move |lsp_store, cx| {
8222 // Escape percent-encoded string.
8223 let current_scheme = abs_path.scheme().to_owned();
8224 // Uri is immutable, so we can't modify the scheme
8225
8226 let abs_path = abs_path
8227 .to_file_path()
8228 .map_err(|()| anyhow!("can't convert URI to path"))?;
8229 let p = abs_path.clone();
8230 let yarn_worktree = lsp_store
8231 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8232 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8233 cx.spawn(async move |this, cx| {
8234 let t = this
8235 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8236 .ok()?;
8237 t.await
8238 })
8239 }),
8240 None => Task::ready(None),
8241 })?
8242 .await;
8243 let (worktree_root_target, known_relative_path) =
8244 if let Some((zip_root, relative_path)) = yarn_worktree {
8245 (zip_root, Some(relative_path))
8246 } else {
8247 (Arc::<Path>::from(abs_path.as_path()), None)
8248 };
8249 let (worktree, relative_path) = if let Some(result) =
8250 lsp_store.update(cx, |lsp_store, cx| {
8251 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8252 worktree_store.find_worktree(&worktree_root_target, cx)
8253 })
8254 })? {
8255 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8256 (result.0, relative_path)
8257 } else {
8258 let worktree = lsp_store
8259 .update(cx, |lsp_store, cx| {
8260 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8261 worktree_store.create_worktree(&worktree_root_target, false, cx)
8262 })
8263 })?
8264 .await?;
8265 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8266 lsp_store
8267 .update(cx, |lsp_store, cx| {
8268 if let Some(local) = lsp_store.as_local_mut() {
8269 local.register_language_server_for_invisible_worktree(
8270 &worktree,
8271 language_server_id,
8272 cx,
8273 )
8274 }
8275 })
8276 .ok();
8277 }
8278 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8279 let relative_path = if let Some(known_path) = known_relative_path {
8280 known_path
8281 } else {
8282 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8283 .into_arc()
8284 };
8285 (worktree, relative_path)
8286 };
8287 let project_path = ProjectPath {
8288 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8289 path: relative_path,
8290 };
8291 lsp_store
8292 .update(cx, |lsp_store, cx| {
8293 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8294 buffer_store.open_buffer(project_path, cx)
8295 })
8296 })?
8297 .await
8298 })
8299 }
8300
8301 fn request_multiple_lsp_locally<P, R>(
8302 &mut self,
8303 buffer: &Entity<Buffer>,
8304 position: Option<P>,
8305 request: R,
8306 cx: &mut Context<Self>,
8307 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8308 where
8309 P: ToOffset,
8310 R: LspCommand + Clone,
8311 <R::LspRequest as lsp::request::Request>::Result: Send,
8312 <R::LspRequest as lsp::request::Request>::Params: Send,
8313 {
8314 let Some(local) = self.as_local() else {
8315 return Task::ready(Vec::new());
8316 };
8317
8318 let snapshot = buffer.read(cx).snapshot();
8319 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8320
8321 let server_ids = buffer.update(cx, |buffer, cx| {
8322 local
8323 .language_servers_for_buffer(buffer, cx)
8324 .filter(|(adapter, _)| {
8325 scope
8326 .as_ref()
8327 .map(|scope| scope.language_allowed(&adapter.name))
8328 .unwrap_or(true)
8329 })
8330 .map(|(_, server)| server.server_id())
8331 .filter(|server_id| {
8332 self.as_local().is_none_or(|local| {
8333 local
8334 .buffers_opened_in_servers
8335 .get(&snapshot.remote_id())
8336 .is_some_and(|servers| servers.contains(server_id))
8337 })
8338 })
8339 .collect::<Vec<_>>()
8340 });
8341
8342 let mut response_results = server_ids
8343 .into_iter()
8344 .map(|server_id| {
8345 let task = self.request_lsp(
8346 buffer.clone(),
8347 LanguageServerToQuery::Other(server_id),
8348 request.clone(),
8349 cx,
8350 );
8351 async move { (server_id, task.await) }
8352 })
8353 .collect::<FuturesUnordered<_>>();
8354
8355 cx.background_spawn(async move {
8356 let mut responses = Vec::with_capacity(response_results.len());
8357 while let Some((server_id, response_result)) = response_results.next().await {
8358 match response_result {
8359 Ok(response) => responses.push((server_id, response)),
8360 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8361 }
8362 }
8363 responses
8364 })
8365 }
8366
8367 async fn handle_lsp_command<T: LspCommand>(
8368 this: Entity<Self>,
8369 envelope: TypedEnvelope<T::ProtoRequest>,
8370 mut cx: AsyncApp,
8371 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8372 where
8373 <T::LspRequest as lsp::request::Request>::Params: Send,
8374 <T::LspRequest as lsp::request::Request>::Result: Send,
8375 {
8376 let sender_id = envelope.original_sender_id().unwrap_or_default();
8377 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8378 let buffer_handle = this.update(&mut cx, |this, cx| {
8379 this.buffer_store.read(cx).get_existing(buffer_id)
8380 })??;
8381 let request = T::from_proto(
8382 envelope.payload,
8383 this.clone(),
8384 buffer_handle.clone(),
8385 cx.clone(),
8386 )
8387 .await?;
8388 let response = this
8389 .update(&mut cx, |this, cx| {
8390 this.request_lsp(
8391 buffer_handle.clone(),
8392 LanguageServerToQuery::FirstCapable,
8393 request,
8394 cx,
8395 )
8396 })?
8397 .await?;
8398 this.update(&mut cx, |this, cx| {
8399 Ok(T::response_to_proto(
8400 response,
8401 this,
8402 sender_id,
8403 &buffer_handle.read(cx).version(),
8404 cx,
8405 ))
8406 })?
8407 }
8408
8409 async fn handle_lsp_query(
8410 lsp_store: Entity<Self>,
8411 envelope: TypedEnvelope<proto::LspQuery>,
8412 mut cx: AsyncApp,
8413 ) -> Result<proto::Ack> {
8414 use proto::lsp_query::Request;
8415 let sender_id = envelope.original_sender_id().unwrap_or_default();
8416 let lsp_query = envelope.payload;
8417 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8418 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8419 match lsp_query.request.context("invalid LSP query request")? {
8420 Request::GetReferences(get_references) => {
8421 let position = get_references.position.clone().and_then(deserialize_anchor);
8422 Self::query_lsp_locally::<GetReferences>(
8423 lsp_store,
8424 server_id,
8425 sender_id,
8426 lsp_request_id,
8427 get_references,
8428 position,
8429 &mut cx,
8430 )
8431 .await?;
8432 }
8433 Request::GetDocumentColor(get_document_color) => {
8434 Self::query_lsp_locally::<GetDocumentColor>(
8435 lsp_store,
8436 server_id,
8437 sender_id,
8438 lsp_request_id,
8439 get_document_color,
8440 None,
8441 &mut cx,
8442 )
8443 .await?;
8444 }
8445 Request::GetHover(get_hover) => {
8446 let position = get_hover.position.clone().and_then(deserialize_anchor);
8447 Self::query_lsp_locally::<GetHover>(
8448 lsp_store,
8449 server_id,
8450 sender_id,
8451 lsp_request_id,
8452 get_hover,
8453 position,
8454 &mut cx,
8455 )
8456 .await?;
8457 }
8458 Request::GetCodeActions(get_code_actions) => {
8459 Self::query_lsp_locally::<GetCodeActions>(
8460 lsp_store,
8461 server_id,
8462 sender_id,
8463 lsp_request_id,
8464 get_code_actions,
8465 None,
8466 &mut cx,
8467 )
8468 .await?;
8469 }
8470 Request::GetSignatureHelp(get_signature_help) => {
8471 let position = get_signature_help
8472 .position
8473 .clone()
8474 .and_then(deserialize_anchor);
8475 Self::query_lsp_locally::<GetSignatureHelp>(
8476 lsp_store,
8477 server_id,
8478 sender_id,
8479 lsp_request_id,
8480 get_signature_help,
8481 position,
8482 &mut cx,
8483 )
8484 .await?;
8485 }
8486 Request::GetCodeLens(get_code_lens) => {
8487 Self::query_lsp_locally::<GetCodeLens>(
8488 lsp_store,
8489 server_id,
8490 sender_id,
8491 lsp_request_id,
8492 get_code_lens,
8493 None,
8494 &mut cx,
8495 )
8496 .await?;
8497 }
8498 Request::GetDefinition(get_definition) => {
8499 let position = get_definition.position.clone().and_then(deserialize_anchor);
8500 Self::query_lsp_locally::<GetDefinitions>(
8501 lsp_store,
8502 server_id,
8503 sender_id,
8504 lsp_request_id,
8505 get_definition,
8506 position,
8507 &mut cx,
8508 )
8509 .await?;
8510 }
8511 Request::GetDeclaration(get_declaration) => {
8512 let position = get_declaration
8513 .position
8514 .clone()
8515 .and_then(deserialize_anchor);
8516 Self::query_lsp_locally::<GetDeclarations>(
8517 lsp_store,
8518 server_id,
8519 sender_id,
8520 lsp_request_id,
8521 get_declaration,
8522 position,
8523 &mut cx,
8524 )
8525 .await?;
8526 }
8527 Request::GetTypeDefinition(get_type_definition) => {
8528 let position = get_type_definition
8529 .position
8530 .clone()
8531 .and_then(deserialize_anchor);
8532 Self::query_lsp_locally::<GetTypeDefinitions>(
8533 lsp_store,
8534 server_id,
8535 sender_id,
8536 lsp_request_id,
8537 get_type_definition,
8538 position,
8539 &mut cx,
8540 )
8541 .await?;
8542 }
8543 Request::GetImplementation(get_implementation) => {
8544 let position = get_implementation
8545 .position
8546 .clone()
8547 .and_then(deserialize_anchor);
8548 Self::query_lsp_locally::<GetImplementations>(
8549 lsp_store,
8550 server_id,
8551 sender_id,
8552 lsp_request_id,
8553 get_implementation,
8554 position,
8555 &mut cx,
8556 )
8557 .await?;
8558 }
8559 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8560 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8561 let version = deserialize_version(get_document_diagnostics.buffer_version());
8562 let buffer = lsp_store.update(&mut cx, |this, cx| {
8563 this.buffer_store.read(cx).get_existing(buffer_id)
8564 })??;
8565 buffer
8566 .update(&mut cx, |buffer, _| {
8567 buffer.wait_for_version(version.clone())
8568 })?
8569 .await?;
8570 lsp_store.update(&mut cx, |lsp_store, cx| {
8571 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8572 let key = LspKey {
8573 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8574 server_queried: server_id,
8575 };
8576 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8577 ) {
8578 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8579 lsp_requests.clear();
8580 };
8581 }
8582
8583 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8584 existing_queries.insert(
8585 lsp_request_id,
8586 cx.spawn(async move |lsp_store, cx| {
8587 let diagnostics_pull = lsp_store
8588 .update(cx, |lsp_store, cx| {
8589 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8590 })
8591 .ok();
8592 if let Some(diagnostics_pull) = diagnostics_pull {
8593 match diagnostics_pull.await {
8594 Ok(()) => {}
8595 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8596 };
8597 }
8598 }),
8599 );
8600 })?;
8601 }
8602 Request::InlayHints(inlay_hints) => {
8603 let query_start = inlay_hints
8604 .start
8605 .clone()
8606 .and_then(deserialize_anchor)
8607 .context("invalid inlay hints range start")?;
8608 let query_end = inlay_hints
8609 .end
8610 .clone()
8611 .and_then(deserialize_anchor)
8612 .context("invalid inlay hints range end")?;
8613 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8614 &lsp_store,
8615 server_id,
8616 lsp_request_id,
8617 &inlay_hints,
8618 query_start..query_end,
8619 &mut cx,
8620 )
8621 .await
8622 .context("preparing inlay hints request")?;
8623 Self::query_lsp_locally::<InlayHints>(
8624 lsp_store,
8625 server_id,
8626 sender_id,
8627 lsp_request_id,
8628 inlay_hints,
8629 None,
8630 &mut cx,
8631 )
8632 .await
8633 .context("querying for inlay hints")?
8634 }
8635 }
8636 Ok(proto::Ack {})
8637 }
8638
8639 async fn handle_lsp_query_response(
8640 lsp_store: Entity<Self>,
8641 envelope: TypedEnvelope<proto::LspQueryResponse>,
8642 cx: AsyncApp,
8643 ) -> Result<()> {
8644 lsp_store.read_with(&cx, |lsp_store, _| {
8645 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8646 upstream_client.handle_lsp_response(envelope.clone());
8647 }
8648 })?;
8649 Ok(())
8650 }
8651
8652 async fn handle_apply_code_action(
8653 this: Entity<Self>,
8654 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8655 mut cx: AsyncApp,
8656 ) -> Result<proto::ApplyCodeActionResponse> {
8657 let sender_id = envelope.original_sender_id().unwrap_or_default();
8658 let action =
8659 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8660 let apply_code_action = this.update(&mut cx, |this, cx| {
8661 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8662 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8663 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8664 })??;
8665
8666 let project_transaction = apply_code_action.await?;
8667 let project_transaction = this.update(&mut cx, |this, cx| {
8668 this.buffer_store.update(cx, |buffer_store, cx| {
8669 buffer_store.serialize_project_transaction_for_peer(
8670 project_transaction,
8671 sender_id,
8672 cx,
8673 )
8674 })
8675 })?;
8676 Ok(proto::ApplyCodeActionResponse {
8677 transaction: Some(project_transaction),
8678 })
8679 }
8680
8681 async fn handle_register_buffer_with_language_servers(
8682 this: Entity<Self>,
8683 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8684 mut cx: AsyncApp,
8685 ) -> Result<proto::Ack> {
8686 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8687 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8688 this.update(&mut cx, |this, cx| {
8689 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8690 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8691 project_id: upstream_project_id,
8692 buffer_id: buffer_id.to_proto(),
8693 only_servers: envelope.payload.only_servers,
8694 });
8695 }
8696
8697 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8698 anyhow::bail!("buffer is not open");
8699 };
8700
8701 let handle = this.register_buffer_with_language_servers(
8702 &buffer,
8703 envelope
8704 .payload
8705 .only_servers
8706 .into_iter()
8707 .filter_map(|selector| {
8708 Some(match selector.selector? {
8709 proto::language_server_selector::Selector::ServerId(server_id) => {
8710 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8711 }
8712 proto::language_server_selector::Selector::Name(name) => {
8713 LanguageServerSelector::Name(LanguageServerName(
8714 SharedString::from(name),
8715 ))
8716 }
8717 })
8718 })
8719 .collect(),
8720 false,
8721 cx,
8722 );
8723 this.buffer_store().update(cx, |buffer_store, _| {
8724 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8725 });
8726
8727 Ok(())
8728 })??;
8729 Ok(proto::Ack {})
8730 }
8731
8732 async fn handle_rename_project_entry(
8733 this: Entity<Self>,
8734 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8735 mut cx: AsyncApp,
8736 ) -> Result<proto::ProjectEntryResponse> {
8737 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8738 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8739 let new_path =
8740 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8741
8742 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8743 .update(&mut cx, |this, cx| {
8744 let (worktree, entry) = this
8745 .worktree_store
8746 .read(cx)
8747 .worktree_and_entry_for_id(entry_id, cx)?;
8748 let new_worktree = this
8749 .worktree_store
8750 .read(cx)
8751 .worktree_for_id(new_worktree_id, cx)?;
8752 Some((
8753 this.worktree_store.clone(),
8754 worktree,
8755 new_worktree,
8756 entry.clone(),
8757 ))
8758 })?
8759 .context("worktree not found")?;
8760 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8761 (worktree.absolutize(&old_entry.path), worktree.id())
8762 })?;
8763 let new_abs_path =
8764 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8765
8766 let _transaction = Self::will_rename_entry(
8767 this.downgrade(),
8768 old_worktree_id,
8769 &old_abs_path,
8770 &new_abs_path,
8771 old_entry.is_dir(),
8772 cx.clone(),
8773 )
8774 .await;
8775 let response = WorktreeStore::handle_rename_project_entry(
8776 worktree_store,
8777 envelope.payload,
8778 cx.clone(),
8779 )
8780 .await;
8781 this.read_with(&cx, |this, _| {
8782 this.did_rename_entry(
8783 old_worktree_id,
8784 &old_abs_path,
8785 &new_abs_path,
8786 old_entry.is_dir(),
8787 );
8788 })
8789 .ok();
8790 response
8791 }
8792
8793 async fn handle_update_diagnostic_summary(
8794 this: Entity<Self>,
8795 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8796 mut cx: AsyncApp,
8797 ) -> Result<()> {
8798 this.update(&mut cx, |lsp_store, cx| {
8799 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8800 let mut updated_diagnostics_paths = HashMap::default();
8801 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8802 for message_summary in envelope
8803 .payload
8804 .summary
8805 .into_iter()
8806 .chain(envelope.payload.more_summaries)
8807 {
8808 let project_path = ProjectPath {
8809 worktree_id,
8810 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8811 };
8812 let path = project_path.path.clone();
8813 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8814 let summary = DiagnosticSummary {
8815 error_count: message_summary.error_count as usize,
8816 warning_count: message_summary.warning_count as usize,
8817 };
8818
8819 if summary.is_empty() {
8820 if let Some(worktree_summaries) =
8821 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8822 && let Some(summaries) = worktree_summaries.get_mut(&path)
8823 {
8824 summaries.remove(&server_id);
8825 if summaries.is_empty() {
8826 worktree_summaries.remove(&path);
8827 }
8828 }
8829 } else {
8830 lsp_store
8831 .diagnostic_summaries
8832 .entry(worktree_id)
8833 .or_default()
8834 .entry(path)
8835 .or_default()
8836 .insert(server_id, summary);
8837 }
8838
8839 if let Some((_, project_id)) = &lsp_store.downstream_client {
8840 match &mut diagnostics_summary {
8841 Some(diagnostics_summary) => {
8842 diagnostics_summary
8843 .more_summaries
8844 .push(proto::DiagnosticSummary {
8845 path: project_path.path.as_ref().to_proto(),
8846 language_server_id: server_id.0 as u64,
8847 error_count: summary.error_count as u32,
8848 warning_count: summary.warning_count as u32,
8849 })
8850 }
8851 None => {
8852 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8853 project_id: *project_id,
8854 worktree_id: worktree_id.to_proto(),
8855 summary: Some(proto::DiagnosticSummary {
8856 path: project_path.path.as_ref().to_proto(),
8857 language_server_id: server_id.0 as u64,
8858 error_count: summary.error_count as u32,
8859 warning_count: summary.warning_count as u32,
8860 }),
8861 more_summaries: Vec::new(),
8862 })
8863 }
8864 }
8865 }
8866 updated_diagnostics_paths
8867 .entry(server_id)
8868 .or_insert_with(Vec::new)
8869 .push(project_path);
8870 }
8871
8872 if let Some((diagnostics_summary, (downstream_client, _))) =
8873 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8874 {
8875 downstream_client.send(diagnostics_summary).log_err();
8876 }
8877 for (server_id, paths) in updated_diagnostics_paths {
8878 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8879 }
8880 Ok(())
8881 })?
8882 }
8883
8884 async fn handle_start_language_server(
8885 lsp_store: Entity<Self>,
8886 envelope: TypedEnvelope<proto::StartLanguageServer>,
8887 mut cx: AsyncApp,
8888 ) -> Result<()> {
8889 let server = envelope.payload.server.context("invalid server")?;
8890 let server_capabilities =
8891 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8892 .with_context(|| {
8893 format!(
8894 "incorrect server capabilities {}",
8895 envelope.payload.capabilities
8896 )
8897 })?;
8898 lsp_store.update(&mut cx, |lsp_store, cx| {
8899 let server_id = LanguageServerId(server.id as usize);
8900 let server_name = LanguageServerName::from_proto(server.name.clone());
8901 lsp_store
8902 .lsp_server_capabilities
8903 .insert(server_id, server_capabilities);
8904 lsp_store.language_server_statuses.insert(
8905 server_id,
8906 LanguageServerStatus {
8907 name: server_name.clone(),
8908 pending_work: Default::default(),
8909 has_pending_diagnostic_updates: false,
8910 progress_tokens: Default::default(),
8911 worktree: server.worktree_id.map(WorktreeId::from_proto),
8912 },
8913 );
8914 cx.emit(LspStoreEvent::LanguageServerAdded(
8915 server_id,
8916 server_name,
8917 server.worktree_id.map(WorktreeId::from_proto),
8918 ));
8919 cx.notify();
8920 })?;
8921 Ok(())
8922 }
8923
8924 async fn handle_update_language_server(
8925 lsp_store: Entity<Self>,
8926 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8927 mut cx: AsyncApp,
8928 ) -> Result<()> {
8929 lsp_store.update(&mut cx, |lsp_store, cx| {
8930 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8931
8932 match envelope.payload.variant.context("invalid variant")? {
8933 proto::update_language_server::Variant::WorkStart(payload) => {
8934 lsp_store.on_lsp_work_start(
8935 language_server_id,
8936 payload.token,
8937 LanguageServerProgress {
8938 title: payload.title,
8939 is_disk_based_diagnostics_progress: false,
8940 is_cancellable: payload.is_cancellable.unwrap_or(false),
8941 message: payload.message,
8942 percentage: payload.percentage.map(|p| p as usize),
8943 last_update_at: cx.background_executor().now(),
8944 },
8945 cx,
8946 );
8947 }
8948 proto::update_language_server::Variant::WorkProgress(payload) => {
8949 lsp_store.on_lsp_work_progress(
8950 language_server_id,
8951 payload.token,
8952 LanguageServerProgress {
8953 title: None,
8954 is_disk_based_diagnostics_progress: false,
8955 is_cancellable: payload.is_cancellable.unwrap_or(false),
8956 message: payload.message,
8957 percentage: payload.percentage.map(|p| p as usize),
8958 last_update_at: cx.background_executor().now(),
8959 },
8960 cx,
8961 );
8962 }
8963
8964 proto::update_language_server::Variant::WorkEnd(payload) => {
8965 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8966 }
8967
8968 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8969 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8970 }
8971
8972 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8973 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8974 }
8975
8976 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8977 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8978 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8979 cx.emit(LspStoreEvent::LanguageServerUpdate {
8980 language_server_id,
8981 name: envelope
8982 .payload
8983 .server_name
8984 .map(SharedString::new)
8985 .map(LanguageServerName),
8986 message: non_lsp,
8987 });
8988 }
8989 }
8990
8991 Ok(())
8992 })?
8993 }
8994
8995 async fn handle_language_server_log(
8996 this: Entity<Self>,
8997 envelope: TypedEnvelope<proto::LanguageServerLog>,
8998 mut cx: AsyncApp,
8999 ) -> Result<()> {
9000 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9001 let log_type = envelope
9002 .payload
9003 .log_type
9004 .map(LanguageServerLogType::from_proto)
9005 .context("invalid language server log type")?;
9006
9007 let message = envelope.payload.message;
9008
9009 this.update(&mut cx, |_, cx| {
9010 cx.emit(LspStoreEvent::LanguageServerLog(
9011 language_server_id,
9012 log_type,
9013 message,
9014 ));
9015 })
9016 }
9017
9018 async fn handle_lsp_ext_cancel_flycheck(
9019 lsp_store: Entity<Self>,
9020 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9021 cx: AsyncApp,
9022 ) -> Result<proto::Ack> {
9023 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9024 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9025 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9026 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9027 } else {
9028 None
9029 }
9030 })?;
9031 if let Some(task) = task {
9032 task.context("handling lsp ext cancel flycheck")?;
9033 }
9034
9035 Ok(proto::Ack {})
9036 }
9037
9038 async fn handle_lsp_ext_run_flycheck(
9039 lsp_store: Entity<Self>,
9040 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9041 mut cx: AsyncApp,
9042 ) -> Result<proto::Ack> {
9043 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9044 lsp_store.update(&mut cx, |lsp_store, cx| {
9045 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9046 let text_document = if envelope.payload.current_file_only {
9047 let buffer_id = envelope
9048 .payload
9049 .buffer_id
9050 .map(|id| BufferId::new(id))
9051 .transpose()?;
9052 buffer_id
9053 .and_then(|buffer_id| {
9054 lsp_store
9055 .buffer_store()
9056 .read(cx)
9057 .get(buffer_id)
9058 .and_then(|buffer| {
9059 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9060 })
9061 .map(|path| make_text_document_identifier(&path))
9062 })
9063 .transpose()?
9064 } else {
9065 None
9066 };
9067 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9068 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9069 )?;
9070 }
9071 anyhow::Ok(())
9072 })??;
9073
9074 Ok(proto::Ack {})
9075 }
9076
9077 async fn handle_lsp_ext_clear_flycheck(
9078 lsp_store: Entity<Self>,
9079 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9080 cx: AsyncApp,
9081 ) -> Result<proto::Ack> {
9082 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9083 lsp_store
9084 .read_with(&cx, |lsp_store, _| {
9085 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9086 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9087 } else {
9088 None
9089 }
9090 })
9091 .context("handling lsp ext clear flycheck")?;
9092
9093 Ok(proto::Ack {})
9094 }
9095
9096 pub fn disk_based_diagnostics_started(
9097 &mut self,
9098 language_server_id: LanguageServerId,
9099 cx: &mut Context<Self>,
9100 ) {
9101 if let Some(language_server_status) =
9102 self.language_server_statuses.get_mut(&language_server_id)
9103 {
9104 language_server_status.has_pending_diagnostic_updates = true;
9105 }
9106
9107 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9108 cx.emit(LspStoreEvent::LanguageServerUpdate {
9109 language_server_id,
9110 name: self
9111 .language_server_adapter_for_id(language_server_id)
9112 .map(|adapter| adapter.name()),
9113 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9114 Default::default(),
9115 ),
9116 })
9117 }
9118
9119 pub fn disk_based_diagnostics_finished(
9120 &mut self,
9121 language_server_id: LanguageServerId,
9122 cx: &mut Context<Self>,
9123 ) {
9124 if let Some(language_server_status) =
9125 self.language_server_statuses.get_mut(&language_server_id)
9126 {
9127 language_server_status.has_pending_diagnostic_updates = false;
9128 }
9129
9130 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9131 cx.emit(LspStoreEvent::LanguageServerUpdate {
9132 language_server_id,
9133 name: self
9134 .language_server_adapter_for_id(language_server_id)
9135 .map(|adapter| adapter.name()),
9136 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9137 Default::default(),
9138 ),
9139 })
9140 }
9141
9142 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9143 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9144 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9145 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9146 // the language server might take some time to publish diagnostics.
9147 fn simulate_disk_based_diagnostics_events_if_needed(
9148 &mut self,
9149 language_server_id: LanguageServerId,
9150 cx: &mut Context<Self>,
9151 ) {
9152 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9153
9154 let Some(LanguageServerState::Running {
9155 simulate_disk_based_diagnostics_completion,
9156 adapter,
9157 ..
9158 }) = self
9159 .as_local_mut()
9160 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9161 else {
9162 return;
9163 };
9164
9165 if adapter.disk_based_diagnostics_progress_token.is_some() {
9166 return;
9167 }
9168
9169 let prev_task =
9170 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9171 cx.background_executor()
9172 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9173 .await;
9174
9175 this.update(cx, |this, cx| {
9176 this.disk_based_diagnostics_finished(language_server_id, cx);
9177
9178 if let Some(LanguageServerState::Running {
9179 simulate_disk_based_diagnostics_completion,
9180 ..
9181 }) = this.as_local_mut().and_then(|local_store| {
9182 local_store.language_servers.get_mut(&language_server_id)
9183 }) {
9184 *simulate_disk_based_diagnostics_completion = None;
9185 }
9186 })
9187 .ok();
9188 }));
9189
9190 if prev_task.is_none() {
9191 self.disk_based_diagnostics_started(language_server_id, cx);
9192 }
9193 }
9194
9195 pub fn language_server_statuses(
9196 &self,
9197 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9198 self.language_server_statuses
9199 .iter()
9200 .map(|(key, value)| (*key, value))
9201 }
9202
9203 pub(super) fn did_rename_entry(
9204 &self,
9205 worktree_id: WorktreeId,
9206 old_path: &Path,
9207 new_path: &Path,
9208 is_dir: bool,
9209 ) {
9210 maybe!({
9211 let local_store = self.as_local()?;
9212
9213 let old_uri = lsp::Uri::from_file_path(old_path)
9214 .ok()
9215 .map(|uri| uri.to_string())?;
9216 let new_uri = lsp::Uri::from_file_path(new_path)
9217 .ok()
9218 .map(|uri| uri.to_string())?;
9219
9220 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9221 let Some(filter) = local_store
9222 .language_server_paths_watched_for_rename
9223 .get(&language_server.server_id())
9224 else {
9225 continue;
9226 };
9227
9228 if filter.should_send_did_rename(&old_uri, is_dir) {
9229 language_server
9230 .notify::<DidRenameFiles>(RenameFilesParams {
9231 files: vec![FileRename {
9232 old_uri: old_uri.clone(),
9233 new_uri: new_uri.clone(),
9234 }],
9235 })
9236 .ok();
9237 }
9238 }
9239 Some(())
9240 });
9241 }
9242
9243 pub(super) fn will_rename_entry(
9244 this: WeakEntity<Self>,
9245 worktree_id: WorktreeId,
9246 old_path: &Path,
9247 new_path: &Path,
9248 is_dir: bool,
9249 cx: AsyncApp,
9250 ) -> Task<ProjectTransaction> {
9251 let old_uri = lsp::Uri::from_file_path(old_path)
9252 .ok()
9253 .map(|uri| uri.to_string());
9254 let new_uri = lsp::Uri::from_file_path(new_path)
9255 .ok()
9256 .map(|uri| uri.to_string());
9257 cx.spawn(async move |cx| {
9258 let mut tasks = vec![];
9259 this.update(cx, |this, cx| {
9260 let local_store = this.as_local()?;
9261 let old_uri = old_uri?;
9262 let new_uri = new_uri?;
9263 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9264 let Some(filter) = local_store
9265 .language_server_paths_watched_for_rename
9266 .get(&language_server.server_id())
9267 else {
9268 continue;
9269 };
9270
9271 if filter.should_send_will_rename(&old_uri, is_dir) {
9272 let apply_edit = cx.spawn({
9273 let old_uri = old_uri.clone();
9274 let new_uri = new_uri.clone();
9275 let language_server = language_server.clone();
9276 async move |this, cx| {
9277 let edit = language_server
9278 .request::<WillRenameFiles>(RenameFilesParams {
9279 files: vec![FileRename { old_uri, new_uri }],
9280 })
9281 .await
9282 .into_response()
9283 .context("will rename files")
9284 .log_err()
9285 .flatten()?;
9286
9287 let transaction = LocalLspStore::deserialize_workspace_edit(
9288 this.upgrade()?,
9289 edit,
9290 false,
9291 language_server.clone(),
9292 cx,
9293 )
9294 .await
9295 .ok()?;
9296 Some(transaction)
9297 }
9298 });
9299 tasks.push(apply_edit);
9300 }
9301 }
9302 Some(())
9303 })
9304 .ok()
9305 .flatten();
9306 let mut merged_transaction = ProjectTransaction::default();
9307 for task in tasks {
9308 // Await on tasks sequentially so that the order of application of edits is deterministic
9309 // (at least with regards to the order of registration of language servers)
9310 if let Some(transaction) = task.await {
9311 for (buffer, buffer_transaction) in transaction.0 {
9312 merged_transaction.0.insert(buffer, buffer_transaction);
9313 }
9314 }
9315 }
9316 merged_transaction
9317 })
9318 }
9319
9320 fn lsp_notify_abs_paths_changed(
9321 &mut self,
9322 server_id: LanguageServerId,
9323 changes: Vec<PathEvent>,
9324 ) {
9325 maybe!({
9326 let server = self.language_server_for_id(server_id)?;
9327 let changes = changes
9328 .into_iter()
9329 .filter_map(|event| {
9330 let typ = match event.kind? {
9331 PathEventKind::Created => lsp::FileChangeType::CREATED,
9332 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9333 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9334 };
9335 Some(lsp::FileEvent {
9336 uri: file_path_to_lsp_url(&event.path).log_err()?,
9337 typ,
9338 })
9339 })
9340 .collect::<Vec<_>>();
9341 if !changes.is_empty() {
9342 server
9343 .notify::<lsp::notification::DidChangeWatchedFiles>(
9344 lsp::DidChangeWatchedFilesParams { changes },
9345 )
9346 .ok();
9347 }
9348 Some(())
9349 });
9350 }
9351
9352 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9353 self.as_local()?.language_server_for_id(id)
9354 }
9355
9356 fn on_lsp_progress(
9357 &mut self,
9358 progress: lsp::ProgressParams,
9359 language_server_id: LanguageServerId,
9360 disk_based_diagnostics_progress_token: Option<String>,
9361 cx: &mut Context<Self>,
9362 ) {
9363 let token = match progress.token {
9364 lsp::NumberOrString::String(token) => token,
9365 lsp::NumberOrString::Number(token) => {
9366 log::info!("skipping numeric progress token {}", token);
9367 return;
9368 }
9369 };
9370
9371 match progress.value {
9372 lsp::ProgressParamsValue::WorkDone(progress) => {
9373 self.handle_work_done_progress(
9374 progress,
9375 language_server_id,
9376 disk_based_diagnostics_progress_token,
9377 token,
9378 cx,
9379 );
9380 }
9381 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9382 let identifier = token.split_once("id:").map(|(_, id)| id.to_owned());
9383 if let Some(LanguageServerState::Running {
9384 workspace_diagnostics_refresh_tasks,
9385 ..
9386 }) = self
9387 .as_local_mut()
9388 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9389 && let Some(workspace_diagnostics) =
9390 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9391 {
9392 workspace_diagnostics.progress_tx.try_send(()).ok();
9393 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9394 }
9395 }
9396 }
9397 }
9398
9399 fn handle_work_done_progress(
9400 &mut self,
9401 progress: lsp::WorkDoneProgress,
9402 language_server_id: LanguageServerId,
9403 disk_based_diagnostics_progress_token: Option<String>,
9404 token: String,
9405 cx: &mut Context<Self>,
9406 ) {
9407 let language_server_status =
9408 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9409 status
9410 } else {
9411 return;
9412 };
9413
9414 if !language_server_status.progress_tokens.contains(&token) {
9415 return;
9416 }
9417
9418 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9419 .as_ref()
9420 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9421
9422 match progress {
9423 lsp::WorkDoneProgress::Begin(report) => {
9424 if is_disk_based_diagnostics_progress {
9425 self.disk_based_diagnostics_started(language_server_id, cx);
9426 }
9427 self.on_lsp_work_start(
9428 language_server_id,
9429 token.clone(),
9430 LanguageServerProgress {
9431 title: Some(report.title),
9432 is_disk_based_diagnostics_progress,
9433 is_cancellable: report.cancellable.unwrap_or(false),
9434 message: report.message.clone(),
9435 percentage: report.percentage.map(|p| p as usize),
9436 last_update_at: cx.background_executor().now(),
9437 },
9438 cx,
9439 );
9440 }
9441 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9442 language_server_id,
9443 token,
9444 LanguageServerProgress {
9445 title: None,
9446 is_disk_based_diagnostics_progress,
9447 is_cancellable: report.cancellable.unwrap_or(false),
9448 message: report.message,
9449 percentage: report.percentage.map(|p| p as usize),
9450 last_update_at: cx.background_executor().now(),
9451 },
9452 cx,
9453 ),
9454 lsp::WorkDoneProgress::End(_) => {
9455 language_server_status.progress_tokens.remove(&token);
9456 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9457 if is_disk_based_diagnostics_progress {
9458 self.disk_based_diagnostics_finished(language_server_id, cx);
9459 }
9460 }
9461 }
9462 }
9463
9464 fn on_lsp_work_start(
9465 &mut self,
9466 language_server_id: LanguageServerId,
9467 token: String,
9468 progress: LanguageServerProgress,
9469 cx: &mut Context<Self>,
9470 ) {
9471 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9472 status.pending_work.insert(token.clone(), progress.clone());
9473 cx.notify();
9474 }
9475 cx.emit(LspStoreEvent::LanguageServerUpdate {
9476 language_server_id,
9477 name: self
9478 .language_server_adapter_for_id(language_server_id)
9479 .map(|adapter| adapter.name()),
9480 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9481 token,
9482 title: progress.title,
9483 message: progress.message,
9484 percentage: progress.percentage.map(|p| p as u32),
9485 is_cancellable: Some(progress.is_cancellable),
9486 }),
9487 })
9488 }
9489
9490 fn on_lsp_work_progress(
9491 &mut self,
9492 language_server_id: LanguageServerId,
9493 token: String,
9494 progress: LanguageServerProgress,
9495 cx: &mut Context<Self>,
9496 ) {
9497 let mut did_update = false;
9498 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9499 match status.pending_work.entry(token.clone()) {
9500 btree_map::Entry::Vacant(entry) => {
9501 entry.insert(progress.clone());
9502 did_update = true;
9503 }
9504 btree_map::Entry::Occupied(mut entry) => {
9505 let entry = entry.get_mut();
9506 if (progress.last_update_at - entry.last_update_at)
9507 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9508 {
9509 entry.last_update_at = progress.last_update_at;
9510 if progress.message.is_some() {
9511 entry.message = progress.message.clone();
9512 }
9513 if progress.percentage.is_some() {
9514 entry.percentage = progress.percentage;
9515 }
9516 if progress.is_cancellable != entry.is_cancellable {
9517 entry.is_cancellable = progress.is_cancellable;
9518 }
9519 did_update = true;
9520 }
9521 }
9522 }
9523 }
9524
9525 if did_update {
9526 cx.emit(LspStoreEvent::LanguageServerUpdate {
9527 language_server_id,
9528 name: self
9529 .language_server_adapter_for_id(language_server_id)
9530 .map(|adapter| adapter.name()),
9531 message: proto::update_language_server::Variant::WorkProgress(
9532 proto::LspWorkProgress {
9533 token,
9534 message: progress.message,
9535 percentage: progress.percentage.map(|p| p as u32),
9536 is_cancellable: Some(progress.is_cancellable),
9537 },
9538 ),
9539 })
9540 }
9541 }
9542
9543 fn on_lsp_work_end(
9544 &mut self,
9545 language_server_id: LanguageServerId,
9546 token: String,
9547 cx: &mut Context<Self>,
9548 ) {
9549 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9550 if let Some(work) = status.pending_work.remove(&token)
9551 && !work.is_disk_based_diagnostics_progress
9552 {
9553 cx.emit(LspStoreEvent::RefreshInlayHints(language_server_id));
9554 }
9555 cx.notify();
9556 }
9557
9558 cx.emit(LspStoreEvent::LanguageServerUpdate {
9559 language_server_id,
9560 name: self
9561 .language_server_adapter_for_id(language_server_id)
9562 .map(|adapter| adapter.name()),
9563 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9564 })
9565 }
9566
9567 pub async fn handle_resolve_completion_documentation(
9568 this: Entity<Self>,
9569 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9570 mut cx: AsyncApp,
9571 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9572 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9573
9574 let completion = this
9575 .read_with(&cx, |this, cx| {
9576 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9577 let server = this
9578 .language_server_for_id(id)
9579 .with_context(|| format!("No language server {id}"))?;
9580
9581 anyhow::Ok(cx.background_spawn(async move {
9582 let can_resolve = server
9583 .capabilities()
9584 .completion_provider
9585 .as_ref()
9586 .and_then(|options| options.resolve_provider)
9587 .unwrap_or(false);
9588 if can_resolve {
9589 server
9590 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9591 .await
9592 .into_response()
9593 .context("resolve completion item")
9594 } else {
9595 anyhow::Ok(lsp_completion)
9596 }
9597 }))
9598 })??
9599 .await?;
9600
9601 let mut documentation_is_markdown = false;
9602 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9603 let documentation = match completion.documentation {
9604 Some(lsp::Documentation::String(text)) => text,
9605
9606 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9607 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9608 value
9609 }
9610
9611 _ => String::new(),
9612 };
9613
9614 // If we have a new buffer_id, that means we're talking to a new client
9615 // and want to check for new text_edits in the completion too.
9616 let mut old_replace_start = None;
9617 let mut old_replace_end = None;
9618 let mut old_insert_start = None;
9619 let mut old_insert_end = None;
9620 let mut new_text = String::default();
9621 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9622 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9623 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9624 anyhow::Ok(buffer.read(cx).snapshot())
9625 })??;
9626
9627 if let Some(text_edit) = completion.text_edit.as_ref() {
9628 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9629
9630 if let Some(mut edit) = edit {
9631 LineEnding::normalize(&mut edit.new_text);
9632
9633 new_text = edit.new_text;
9634 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9635 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9636 if let Some(insert_range) = edit.insert_range {
9637 old_insert_start = Some(serialize_anchor(&insert_range.start));
9638 old_insert_end = Some(serialize_anchor(&insert_range.end));
9639 }
9640 }
9641 }
9642 }
9643
9644 Ok(proto::ResolveCompletionDocumentationResponse {
9645 documentation,
9646 documentation_is_markdown,
9647 old_replace_start,
9648 old_replace_end,
9649 new_text,
9650 lsp_completion,
9651 old_insert_start,
9652 old_insert_end,
9653 })
9654 }
9655
9656 async fn handle_on_type_formatting(
9657 this: Entity<Self>,
9658 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9659 mut cx: AsyncApp,
9660 ) -> Result<proto::OnTypeFormattingResponse> {
9661 let on_type_formatting = this.update(&mut cx, |this, cx| {
9662 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9663 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9664 let position = envelope
9665 .payload
9666 .position
9667 .and_then(deserialize_anchor)
9668 .context("invalid position")?;
9669 anyhow::Ok(this.apply_on_type_formatting(
9670 buffer,
9671 position,
9672 envelope.payload.trigger.clone(),
9673 cx,
9674 ))
9675 })??;
9676
9677 let transaction = on_type_formatting
9678 .await?
9679 .as_ref()
9680 .map(language::proto::serialize_transaction);
9681 Ok(proto::OnTypeFormattingResponse { transaction })
9682 }
9683
9684 async fn handle_refresh_inlay_hints(
9685 lsp_store: Entity<Self>,
9686 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9687 mut cx: AsyncApp,
9688 ) -> Result<proto::Ack> {
9689 lsp_store.update(&mut cx, |_, cx| {
9690 cx.emit(LspStoreEvent::RefreshInlayHints(
9691 LanguageServerId::from_proto(envelope.payload.server_id),
9692 ));
9693 })?;
9694 Ok(proto::Ack {})
9695 }
9696
9697 async fn handle_pull_workspace_diagnostics(
9698 lsp_store: Entity<Self>,
9699 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9700 mut cx: AsyncApp,
9701 ) -> Result<proto::Ack> {
9702 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9703 lsp_store.update(&mut cx, |lsp_store, _| {
9704 lsp_store.pull_workspace_diagnostics(server_id);
9705 })?;
9706 Ok(proto::Ack {})
9707 }
9708
9709 async fn handle_get_color_presentation(
9710 lsp_store: Entity<Self>,
9711 envelope: TypedEnvelope<proto::GetColorPresentation>,
9712 mut cx: AsyncApp,
9713 ) -> Result<proto::GetColorPresentationResponse> {
9714 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9715 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9716 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9717 })??;
9718
9719 let color = envelope
9720 .payload
9721 .color
9722 .context("invalid color resolve request")?;
9723 let start = color
9724 .lsp_range_start
9725 .context("invalid color resolve request")?;
9726 let end = color
9727 .lsp_range_end
9728 .context("invalid color resolve request")?;
9729
9730 let color = DocumentColor {
9731 lsp_range: lsp::Range {
9732 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9733 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9734 },
9735 color: lsp::Color {
9736 red: color.red,
9737 green: color.green,
9738 blue: color.blue,
9739 alpha: color.alpha,
9740 },
9741 resolved: false,
9742 color_presentations: Vec::new(),
9743 };
9744 let resolved_color = lsp_store
9745 .update(&mut cx, |lsp_store, cx| {
9746 lsp_store.resolve_color_presentation(
9747 color,
9748 buffer.clone(),
9749 LanguageServerId(envelope.payload.server_id as usize),
9750 cx,
9751 )
9752 })?
9753 .await
9754 .context("resolving color presentation")?;
9755
9756 Ok(proto::GetColorPresentationResponse {
9757 presentations: resolved_color
9758 .color_presentations
9759 .into_iter()
9760 .map(|presentation| proto::ColorPresentation {
9761 label: presentation.label.to_string(),
9762 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9763 additional_text_edits: presentation
9764 .additional_text_edits
9765 .into_iter()
9766 .map(serialize_lsp_edit)
9767 .collect(),
9768 })
9769 .collect(),
9770 })
9771 }
9772
9773 async fn handle_resolve_inlay_hint(
9774 lsp_store: Entity<Self>,
9775 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9776 mut cx: AsyncApp,
9777 ) -> Result<proto::ResolveInlayHintResponse> {
9778 let proto_hint = envelope
9779 .payload
9780 .hint
9781 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9782 let hint = InlayHints::proto_to_project_hint(proto_hint)
9783 .context("resolved proto inlay hint conversion")?;
9784 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9785 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9786 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9787 })??;
9788 let response_hint = lsp_store
9789 .update(&mut cx, |lsp_store, cx| {
9790 lsp_store.resolve_inlay_hint(
9791 hint,
9792 buffer,
9793 LanguageServerId(envelope.payload.language_server_id as usize),
9794 cx,
9795 )
9796 })?
9797 .await
9798 .context("inlay hints fetch")?;
9799 Ok(proto::ResolveInlayHintResponse {
9800 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9801 })
9802 }
9803
9804 async fn handle_refresh_code_lens(
9805 this: Entity<Self>,
9806 _: TypedEnvelope<proto::RefreshCodeLens>,
9807 mut cx: AsyncApp,
9808 ) -> Result<proto::Ack> {
9809 this.update(&mut cx, |_, cx| {
9810 cx.emit(LspStoreEvent::RefreshCodeLens);
9811 })?;
9812 Ok(proto::Ack {})
9813 }
9814
9815 async fn handle_open_buffer_for_symbol(
9816 this: Entity<Self>,
9817 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9818 mut cx: AsyncApp,
9819 ) -> Result<proto::OpenBufferForSymbolResponse> {
9820 let peer_id = envelope.original_sender_id().unwrap_or_default();
9821 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9822 let symbol = Self::deserialize_symbol(symbol)?;
9823 this.read_with(&cx, |this, _| {
9824 if let SymbolLocation::OutsideProject {
9825 abs_path,
9826 signature,
9827 } = &symbol.path
9828 {
9829 let new_signature = this.symbol_signature(&abs_path);
9830 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9831 }
9832 Ok(())
9833 })??;
9834 let buffer = this
9835 .update(&mut cx, |this, cx| {
9836 this.open_buffer_for_symbol(
9837 &Symbol {
9838 language_server_name: symbol.language_server_name,
9839 source_worktree_id: symbol.source_worktree_id,
9840 source_language_server_id: symbol.source_language_server_id,
9841 path: symbol.path,
9842 name: symbol.name,
9843 kind: symbol.kind,
9844 range: symbol.range,
9845 label: CodeLabel::default(),
9846 },
9847 cx,
9848 )
9849 })?
9850 .await?;
9851
9852 this.update(&mut cx, |this, cx| {
9853 let is_private = buffer
9854 .read(cx)
9855 .file()
9856 .map(|f| f.is_private())
9857 .unwrap_or_default();
9858 if is_private {
9859 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9860 } else {
9861 this.buffer_store
9862 .update(cx, |buffer_store, cx| {
9863 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9864 })
9865 .detach_and_log_err(cx);
9866 let buffer_id = buffer.read(cx).remote_id().to_proto();
9867 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9868 }
9869 })?
9870 }
9871
9872 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9873 let mut hasher = Sha256::new();
9874 hasher.update(abs_path.to_string_lossy().as_bytes());
9875 hasher.update(self.nonce.to_be_bytes());
9876 hasher.finalize().as_slice().try_into().unwrap()
9877 }
9878
9879 pub async fn handle_get_project_symbols(
9880 this: Entity<Self>,
9881 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9882 mut cx: AsyncApp,
9883 ) -> Result<proto::GetProjectSymbolsResponse> {
9884 let symbols = this
9885 .update(&mut cx, |this, cx| {
9886 this.symbols(&envelope.payload.query, cx)
9887 })?
9888 .await?;
9889
9890 Ok(proto::GetProjectSymbolsResponse {
9891 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9892 })
9893 }
9894
9895 pub async fn handle_restart_language_servers(
9896 this: Entity<Self>,
9897 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9898 mut cx: AsyncApp,
9899 ) -> Result<proto::Ack> {
9900 this.update(&mut cx, |lsp_store, cx| {
9901 let buffers =
9902 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9903 lsp_store.restart_language_servers_for_buffers(
9904 buffers,
9905 envelope
9906 .payload
9907 .only_servers
9908 .into_iter()
9909 .filter_map(|selector| {
9910 Some(match selector.selector? {
9911 proto::language_server_selector::Selector::ServerId(server_id) => {
9912 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9913 }
9914 proto::language_server_selector::Selector::Name(name) => {
9915 LanguageServerSelector::Name(LanguageServerName(
9916 SharedString::from(name),
9917 ))
9918 }
9919 })
9920 })
9921 .collect(),
9922 cx,
9923 );
9924 })?;
9925
9926 Ok(proto::Ack {})
9927 }
9928
9929 pub async fn handle_stop_language_servers(
9930 lsp_store: Entity<Self>,
9931 envelope: TypedEnvelope<proto::StopLanguageServers>,
9932 mut cx: AsyncApp,
9933 ) -> Result<proto::Ack> {
9934 lsp_store.update(&mut cx, |lsp_store, cx| {
9935 if envelope.payload.all
9936 && envelope.payload.also_servers.is_empty()
9937 && envelope.payload.buffer_ids.is_empty()
9938 {
9939 lsp_store.stop_all_language_servers(cx);
9940 } else {
9941 let buffers =
9942 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9943 lsp_store
9944 .stop_language_servers_for_buffers(
9945 buffers,
9946 envelope
9947 .payload
9948 .also_servers
9949 .into_iter()
9950 .filter_map(|selector| {
9951 Some(match selector.selector? {
9952 proto::language_server_selector::Selector::ServerId(
9953 server_id,
9954 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9955 server_id,
9956 )),
9957 proto::language_server_selector::Selector::Name(name) => {
9958 LanguageServerSelector::Name(LanguageServerName(
9959 SharedString::from(name),
9960 ))
9961 }
9962 })
9963 })
9964 .collect(),
9965 cx,
9966 )
9967 .detach_and_log_err(cx);
9968 }
9969 })?;
9970
9971 Ok(proto::Ack {})
9972 }
9973
9974 pub async fn handle_cancel_language_server_work(
9975 this: Entity<Self>,
9976 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9977 mut cx: AsyncApp,
9978 ) -> Result<proto::Ack> {
9979 this.update(&mut cx, |this, cx| {
9980 if let Some(work) = envelope.payload.work {
9981 match work {
9982 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9983 let buffers =
9984 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9985 this.cancel_language_server_work_for_buffers(buffers, cx);
9986 }
9987 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9988 let server_id = LanguageServerId::from_proto(work.language_server_id);
9989 this.cancel_language_server_work(server_id, work.token, cx);
9990 }
9991 }
9992 }
9993 })?;
9994
9995 Ok(proto::Ack {})
9996 }
9997
9998 fn buffer_ids_to_buffers(
9999 &mut self,
10000 buffer_ids: impl Iterator<Item = u64>,
10001 cx: &mut Context<Self>,
10002 ) -> Vec<Entity<Buffer>> {
10003 buffer_ids
10004 .into_iter()
10005 .flat_map(|buffer_id| {
10006 self.buffer_store
10007 .read(cx)
10008 .get(BufferId::new(buffer_id).log_err()?)
10009 })
10010 .collect::<Vec<_>>()
10011 }
10012
10013 async fn handle_apply_additional_edits_for_completion(
10014 this: Entity<Self>,
10015 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10016 mut cx: AsyncApp,
10017 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10018 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10019 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10020 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10021 let completion = Self::deserialize_completion(
10022 envelope.payload.completion.context("invalid completion")?,
10023 )?;
10024 anyhow::Ok((buffer, completion))
10025 })??;
10026
10027 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10028 this.apply_additional_edits_for_completion(
10029 buffer,
10030 Rc::new(RefCell::new(Box::new([Completion {
10031 replace_range: completion.replace_range,
10032 new_text: completion.new_text,
10033 source: completion.source,
10034 documentation: None,
10035 label: CodeLabel::default(),
10036 insert_text_mode: None,
10037 icon_path: None,
10038 confirm: None,
10039 }]))),
10040 0,
10041 false,
10042 cx,
10043 )
10044 })?;
10045
10046 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10047 transaction: apply_additional_edits
10048 .await?
10049 .as_ref()
10050 .map(language::proto::serialize_transaction),
10051 })
10052 }
10053
10054 pub fn last_formatting_failure(&self) -> Option<&str> {
10055 self.last_formatting_failure.as_deref()
10056 }
10057
10058 pub fn reset_last_formatting_failure(&mut self) {
10059 self.last_formatting_failure = None;
10060 }
10061
10062 pub fn environment_for_buffer(
10063 &self,
10064 buffer: &Entity<Buffer>,
10065 cx: &mut Context<Self>,
10066 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10067 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10068 environment.update(cx, |env, cx| {
10069 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10070 })
10071 } else {
10072 Task::ready(None).shared()
10073 }
10074 }
10075
10076 pub fn format(
10077 &mut self,
10078 buffers: HashSet<Entity<Buffer>>,
10079 target: LspFormatTarget,
10080 push_to_history: bool,
10081 trigger: FormatTrigger,
10082 cx: &mut Context<Self>,
10083 ) -> Task<anyhow::Result<ProjectTransaction>> {
10084 let logger = zlog::scoped!("format");
10085 if self.as_local().is_some() {
10086 zlog::trace!(logger => "Formatting locally");
10087 let logger = zlog::scoped!(logger => "local");
10088 let buffers = buffers
10089 .into_iter()
10090 .map(|buffer_handle| {
10091 let buffer = buffer_handle.read(cx);
10092 let buffer_abs_path = File::from_dyn(buffer.file())
10093 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10094
10095 (buffer_handle, buffer_abs_path, buffer.remote_id())
10096 })
10097 .collect::<Vec<_>>();
10098
10099 cx.spawn(async move |lsp_store, cx| {
10100 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10101
10102 for (handle, abs_path, id) in buffers {
10103 let env = lsp_store
10104 .update(cx, |lsp_store, cx| {
10105 lsp_store.environment_for_buffer(&handle, cx)
10106 })?
10107 .await;
10108
10109 let ranges = match &target {
10110 LspFormatTarget::Buffers => None,
10111 LspFormatTarget::Ranges(ranges) => {
10112 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10113 }
10114 };
10115
10116 formattable_buffers.push(FormattableBuffer {
10117 handle,
10118 abs_path,
10119 env,
10120 ranges,
10121 });
10122 }
10123 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10124
10125 let format_timer = zlog::time!(logger => "Formatting buffers");
10126 let result = LocalLspStore::format_locally(
10127 lsp_store.clone(),
10128 formattable_buffers,
10129 push_to_history,
10130 trigger,
10131 logger,
10132 cx,
10133 )
10134 .await;
10135 format_timer.end();
10136
10137 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10138
10139 lsp_store.update(cx, |lsp_store, _| {
10140 lsp_store.update_last_formatting_failure(&result);
10141 })?;
10142
10143 result
10144 })
10145 } else if let Some((client, project_id)) = self.upstream_client() {
10146 zlog::trace!(logger => "Formatting remotely");
10147 let logger = zlog::scoped!(logger => "remote");
10148 // Don't support formatting ranges via remote
10149 match target {
10150 LspFormatTarget::Buffers => {}
10151 LspFormatTarget::Ranges(_) => {
10152 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10153 return Task::ready(Ok(ProjectTransaction::default()));
10154 }
10155 }
10156
10157 let buffer_store = self.buffer_store();
10158 cx.spawn(async move |lsp_store, cx| {
10159 zlog::trace!(logger => "Sending remote format request");
10160 let request_timer = zlog::time!(logger => "remote format request");
10161 let result = client
10162 .request(proto::FormatBuffers {
10163 project_id,
10164 trigger: trigger as i32,
10165 buffer_ids: buffers
10166 .iter()
10167 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10168 .collect::<Result<_>>()?,
10169 })
10170 .await
10171 .and_then(|result| result.transaction.context("missing transaction"));
10172 request_timer.end();
10173
10174 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10175
10176 lsp_store.update(cx, |lsp_store, _| {
10177 lsp_store.update_last_formatting_failure(&result);
10178 })?;
10179
10180 let transaction_response = result?;
10181 let _timer = zlog::time!(logger => "deserializing project transaction");
10182 buffer_store
10183 .update(cx, |buffer_store, cx| {
10184 buffer_store.deserialize_project_transaction(
10185 transaction_response,
10186 push_to_history,
10187 cx,
10188 )
10189 })?
10190 .await
10191 })
10192 } else {
10193 zlog::trace!(logger => "Not formatting");
10194 Task::ready(Ok(ProjectTransaction::default()))
10195 }
10196 }
10197
10198 async fn handle_format_buffers(
10199 this: Entity<Self>,
10200 envelope: TypedEnvelope<proto::FormatBuffers>,
10201 mut cx: AsyncApp,
10202 ) -> Result<proto::FormatBuffersResponse> {
10203 let sender_id = envelope.original_sender_id().unwrap_or_default();
10204 let format = this.update(&mut cx, |this, cx| {
10205 let mut buffers = HashSet::default();
10206 for buffer_id in &envelope.payload.buffer_ids {
10207 let buffer_id = BufferId::new(*buffer_id)?;
10208 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10209 }
10210 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10211 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10212 })??;
10213
10214 let project_transaction = format.await?;
10215 let project_transaction = this.update(&mut cx, |this, cx| {
10216 this.buffer_store.update(cx, |buffer_store, cx| {
10217 buffer_store.serialize_project_transaction_for_peer(
10218 project_transaction,
10219 sender_id,
10220 cx,
10221 )
10222 })
10223 })?;
10224 Ok(proto::FormatBuffersResponse {
10225 transaction: Some(project_transaction),
10226 })
10227 }
10228
10229 async fn handle_apply_code_action_kind(
10230 this: Entity<Self>,
10231 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10232 mut cx: AsyncApp,
10233 ) -> Result<proto::ApplyCodeActionKindResponse> {
10234 let sender_id = envelope.original_sender_id().unwrap_or_default();
10235 let format = this.update(&mut cx, |this, cx| {
10236 let mut buffers = HashSet::default();
10237 for buffer_id in &envelope.payload.buffer_ids {
10238 let buffer_id = BufferId::new(*buffer_id)?;
10239 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10240 }
10241 let kind = match envelope.payload.kind.as_str() {
10242 "" => CodeActionKind::EMPTY,
10243 "quickfix" => CodeActionKind::QUICKFIX,
10244 "refactor" => CodeActionKind::REFACTOR,
10245 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10246 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10247 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10248 "source" => CodeActionKind::SOURCE,
10249 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10250 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10251 _ => anyhow::bail!(
10252 "Invalid code action kind {}",
10253 envelope.payload.kind.as_str()
10254 ),
10255 };
10256 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10257 })??;
10258
10259 let project_transaction = format.await?;
10260 let project_transaction = this.update(&mut cx, |this, cx| {
10261 this.buffer_store.update(cx, |buffer_store, cx| {
10262 buffer_store.serialize_project_transaction_for_peer(
10263 project_transaction,
10264 sender_id,
10265 cx,
10266 )
10267 })
10268 })?;
10269 Ok(proto::ApplyCodeActionKindResponse {
10270 transaction: Some(project_transaction),
10271 })
10272 }
10273
10274 async fn shutdown_language_server(
10275 server_state: Option<LanguageServerState>,
10276 name: LanguageServerName,
10277 cx: &mut AsyncApp,
10278 ) {
10279 let server = match server_state {
10280 Some(LanguageServerState::Starting { startup, .. }) => {
10281 let mut timer = cx
10282 .background_executor()
10283 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10284 .fuse();
10285
10286 select! {
10287 server = startup.fuse() => server,
10288 () = timer => {
10289 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10290 None
10291 },
10292 }
10293 }
10294
10295 Some(LanguageServerState::Running { server, .. }) => Some(server),
10296
10297 None => None,
10298 };
10299
10300 if let Some(server) = server
10301 && let Some(shutdown) = server.shutdown()
10302 {
10303 shutdown.await;
10304 }
10305 }
10306
10307 // Returns a list of all of the worktrees which no longer have a language server and the root path
10308 // for the stopped server
10309 fn stop_local_language_server(
10310 &mut self,
10311 server_id: LanguageServerId,
10312 cx: &mut Context<Self>,
10313 ) -> Task<()> {
10314 let local = match &mut self.mode {
10315 LspStoreMode::Local(local) => local,
10316 _ => {
10317 return Task::ready(());
10318 }
10319 };
10320
10321 // Remove this server ID from all entries in the given worktree.
10322 local
10323 .language_server_ids
10324 .retain(|_, state| state.id != server_id);
10325 self.buffer_store.update(cx, |buffer_store, cx| {
10326 for buffer in buffer_store.buffers() {
10327 buffer.update(cx, |buffer, cx| {
10328 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10329 buffer.set_completion_triggers(server_id, Default::default(), cx);
10330 });
10331 }
10332 });
10333
10334 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10335 summaries.retain(|path, summaries_by_server_id| {
10336 if summaries_by_server_id.remove(&server_id).is_some() {
10337 if let Some((client, project_id)) = self.downstream_client.clone() {
10338 client
10339 .send(proto::UpdateDiagnosticSummary {
10340 project_id,
10341 worktree_id: worktree_id.to_proto(),
10342 summary: Some(proto::DiagnosticSummary {
10343 path: path.as_ref().to_proto(),
10344 language_server_id: server_id.0 as u64,
10345 error_count: 0,
10346 warning_count: 0,
10347 }),
10348 more_summaries: Vec::new(),
10349 })
10350 .log_err();
10351 }
10352 !summaries_by_server_id.is_empty()
10353 } else {
10354 true
10355 }
10356 });
10357 }
10358
10359 let local = self.as_local_mut().unwrap();
10360 for diagnostics in local.diagnostics.values_mut() {
10361 diagnostics.retain(|_, diagnostics_by_server_id| {
10362 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10363 diagnostics_by_server_id.remove(ix);
10364 !diagnostics_by_server_id.is_empty()
10365 } else {
10366 true
10367 }
10368 });
10369 }
10370 local.language_server_watched_paths.remove(&server_id);
10371
10372 let server_state = local.language_servers.remove(&server_id);
10373 self.cleanup_lsp_data(server_id);
10374 let name = self
10375 .language_server_statuses
10376 .remove(&server_id)
10377 .map(|status| status.name)
10378 .or_else(|| {
10379 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10380 Some(adapter.name())
10381 } else {
10382 None
10383 }
10384 });
10385
10386 if let Some(name) = name {
10387 log::info!("stopping language server {name}");
10388 self.languages
10389 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10390 cx.notify();
10391
10392 return cx.spawn(async move |lsp_store, cx| {
10393 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10394 lsp_store
10395 .update(cx, |lsp_store, cx| {
10396 lsp_store
10397 .languages
10398 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10399 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10400 cx.notify();
10401 })
10402 .ok();
10403 });
10404 }
10405
10406 if server_state.is_some() {
10407 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10408 }
10409 Task::ready(())
10410 }
10411
10412 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10413 if let Some((client, project_id)) = self.upstream_client() {
10414 let request = client.request(proto::StopLanguageServers {
10415 project_id,
10416 buffer_ids: Vec::new(),
10417 also_servers: Vec::new(),
10418 all: true,
10419 });
10420 cx.background_spawn(request).detach_and_log_err(cx);
10421 } else {
10422 let Some(local) = self.as_local_mut() else {
10423 return;
10424 };
10425 let language_servers_to_stop = local
10426 .language_server_ids
10427 .values()
10428 .map(|state| state.id)
10429 .collect();
10430 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10431 let tasks = language_servers_to_stop
10432 .into_iter()
10433 .map(|server| self.stop_local_language_server(server, cx))
10434 .collect::<Vec<_>>();
10435 cx.background_spawn(async move {
10436 futures::future::join_all(tasks).await;
10437 })
10438 .detach();
10439 }
10440 }
10441
10442 pub fn restart_language_servers_for_buffers(
10443 &mut self,
10444 buffers: Vec<Entity<Buffer>>,
10445 only_restart_servers: HashSet<LanguageServerSelector>,
10446 cx: &mut Context<Self>,
10447 ) {
10448 if let Some((client, project_id)) = self.upstream_client() {
10449 let request = client.request(proto::RestartLanguageServers {
10450 project_id,
10451 buffer_ids: buffers
10452 .into_iter()
10453 .map(|b| b.read(cx).remote_id().to_proto())
10454 .collect(),
10455 only_servers: only_restart_servers
10456 .into_iter()
10457 .map(|selector| {
10458 let selector = match selector {
10459 LanguageServerSelector::Id(language_server_id) => {
10460 proto::language_server_selector::Selector::ServerId(
10461 language_server_id.to_proto(),
10462 )
10463 }
10464 LanguageServerSelector::Name(language_server_name) => {
10465 proto::language_server_selector::Selector::Name(
10466 language_server_name.to_string(),
10467 )
10468 }
10469 };
10470 proto::LanguageServerSelector {
10471 selector: Some(selector),
10472 }
10473 })
10474 .collect(),
10475 all: false,
10476 });
10477 cx.background_spawn(request).detach_and_log_err(cx);
10478 } else {
10479 let stop_task = if only_restart_servers.is_empty() {
10480 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10481 } else {
10482 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10483 };
10484 cx.spawn(async move |lsp_store, cx| {
10485 stop_task.await;
10486 lsp_store
10487 .update(cx, |lsp_store, cx| {
10488 for buffer in buffers {
10489 lsp_store.register_buffer_with_language_servers(
10490 &buffer,
10491 only_restart_servers.clone(),
10492 true,
10493 cx,
10494 );
10495 }
10496 })
10497 .ok()
10498 })
10499 .detach();
10500 }
10501 }
10502
10503 pub fn stop_language_servers_for_buffers(
10504 &mut self,
10505 buffers: Vec<Entity<Buffer>>,
10506 also_stop_servers: HashSet<LanguageServerSelector>,
10507 cx: &mut Context<Self>,
10508 ) -> Task<Result<()>> {
10509 if let Some((client, project_id)) = self.upstream_client() {
10510 let request = client.request(proto::StopLanguageServers {
10511 project_id,
10512 buffer_ids: buffers
10513 .into_iter()
10514 .map(|b| b.read(cx).remote_id().to_proto())
10515 .collect(),
10516 also_servers: also_stop_servers
10517 .into_iter()
10518 .map(|selector| {
10519 let selector = match selector {
10520 LanguageServerSelector::Id(language_server_id) => {
10521 proto::language_server_selector::Selector::ServerId(
10522 language_server_id.to_proto(),
10523 )
10524 }
10525 LanguageServerSelector::Name(language_server_name) => {
10526 proto::language_server_selector::Selector::Name(
10527 language_server_name.to_string(),
10528 )
10529 }
10530 };
10531 proto::LanguageServerSelector {
10532 selector: Some(selector),
10533 }
10534 })
10535 .collect(),
10536 all: false,
10537 });
10538 cx.background_spawn(async move {
10539 let _ = request.await?;
10540 Ok(())
10541 })
10542 } else {
10543 let task =
10544 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10545 cx.background_spawn(async move {
10546 task.await;
10547 Ok(())
10548 })
10549 }
10550 }
10551
10552 fn stop_local_language_servers_for_buffers(
10553 &mut self,
10554 buffers: &[Entity<Buffer>],
10555 also_stop_servers: HashSet<LanguageServerSelector>,
10556 cx: &mut Context<Self>,
10557 ) -> Task<()> {
10558 let Some(local) = self.as_local_mut() else {
10559 return Task::ready(());
10560 };
10561 let mut language_server_names_to_stop = BTreeSet::default();
10562 let mut language_servers_to_stop = also_stop_servers
10563 .into_iter()
10564 .flat_map(|selector| match selector {
10565 LanguageServerSelector::Id(id) => Some(id),
10566 LanguageServerSelector::Name(name) => {
10567 language_server_names_to_stop.insert(name);
10568 None
10569 }
10570 })
10571 .collect::<BTreeSet<_>>();
10572
10573 let mut covered_worktrees = HashSet::default();
10574 for buffer in buffers {
10575 buffer.update(cx, |buffer, cx| {
10576 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10577 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10578 && covered_worktrees.insert(worktree_id)
10579 {
10580 language_server_names_to_stop.retain(|name| {
10581 let old_ids_count = language_servers_to_stop.len();
10582 let all_language_servers_with_this_name = local
10583 .language_server_ids
10584 .iter()
10585 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10586 language_servers_to_stop.extend(all_language_servers_with_this_name);
10587 old_ids_count == language_servers_to_stop.len()
10588 });
10589 }
10590 });
10591 }
10592 for name in language_server_names_to_stop {
10593 language_servers_to_stop.extend(
10594 local
10595 .language_server_ids
10596 .iter()
10597 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10598 );
10599 }
10600
10601 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10602 let tasks = language_servers_to_stop
10603 .into_iter()
10604 .map(|server| self.stop_local_language_server(server, cx))
10605 .collect::<Vec<_>>();
10606
10607 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10608 }
10609
10610 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10611 let (worktree, relative_path) =
10612 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10613
10614 let project_path = ProjectPath {
10615 worktree_id: worktree.read(cx).id(),
10616 path: relative_path,
10617 };
10618
10619 Some(
10620 self.buffer_store()
10621 .read(cx)
10622 .get_by_path(&project_path)?
10623 .read(cx),
10624 )
10625 }
10626
10627 #[cfg(any(test, feature = "test-support"))]
10628 pub fn update_diagnostics(
10629 &mut self,
10630 server_id: LanguageServerId,
10631 diagnostics: lsp::PublishDiagnosticsParams,
10632 result_id: Option<String>,
10633 source_kind: DiagnosticSourceKind,
10634 disk_based_sources: &[String],
10635 cx: &mut Context<Self>,
10636 ) -> Result<()> {
10637 self.merge_lsp_diagnostics(
10638 source_kind,
10639 vec![DocumentDiagnosticsUpdate {
10640 diagnostics,
10641 result_id,
10642 server_id,
10643 disk_based_sources: Cow::Borrowed(disk_based_sources),
10644 }],
10645 |_, _, _| false,
10646 cx,
10647 )
10648 }
10649
10650 pub fn merge_lsp_diagnostics(
10651 &mut self,
10652 source_kind: DiagnosticSourceKind,
10653 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10654 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10655 cx: &mut Context<Self>,
10656 ) -> Result<()> {
10657 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10658 let updates = lsp_diagnostics
10659 .into_iter()
10660 .filter_map(|update| {
10661 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10662 Some(DocumentDiagnosticsUpdate {
10663 diagnostics: self.lsp_to_document_diagnostics(
10664 abs_path,
10665 source_kind,
10666 update.server_id,
10667 update.diagnostics,
10668 &update.disk_based_sources,
10669 ),
10670 result_id: update.result_id,
10671 server_id: update.server_id,
10672 disk_based_sources: update.disk_based_sources,
10673 })
10674 })
10675 .collect();
10676 self.merge_diagnostic_entries(updates, merge, cx)?;
10677 Ok(())
10678 }
10679
10680 fn lsp_to_document_diagnostics(
10681 &mut self,
10682 document_abs_path: PathBuf,
10683 source_kind: DiagnosticSourceKind,
10684 server_id: LanguageServerId,
10685 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10686 disk_based_sources: &[String],
10687 ) -> DocumentDiagnostics {
10688 let mut diagnostics = Vec::default();
10689 let mut primary_diagnostic_group_ids = HashMap::default();
10690 let mut sources_by_group_id = HashMap::default();
10691 let mut supporting_diagnostics = HashMap::default();
10692
10693 let adapter = self.language_server_adapter_for_id(server_id);
10694
10695 // Ensure that primary diagnostics are always the most severe
10696 lsp_diagnostics
10697 .diagnostics
10698 .sort_by_key(|item| item.severity);
10699
10700 for diagnostic in &lsp_diagnostics.diagnostics {
10701 let source = diagnostic.source.as_ref();
10702 let range = range_from_lsp(diagnostic.range);
10703 let is_supporting = diagnostic
10704 .related_information
10705 .as_ref()
10706 .is_some_and(|infos| {
10707 infos.iter().any(|info| {
10708 primary_diagnostic_group_ids.contains_key(&(
10709 source,
10710 diagnostic.code.clone(),
10711 range_from_lsp(info.location.range),
10712 ))
10713 })
10714 });
10715
10716 let is_unnecessary = diagnostic
10717 .tags
10718 .as_ref()
10719 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10720
10721 let underline = self
10722 .language_server_adapter_for_id(server_id)
10723 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10724
10725 if is_supporting {
10726 supporting_diagnostics.insert(
10727 (source, diagnostic.code.clone(), range),
10728 (diagnostic.severity, is_unnecessary),
10729 );
10730 } else {
10731 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10732 let is_disk_based =
10733 source.is_some_and(|source| disk_based_sources.contains(source));
10734
10735 sources_by_group_id.insert(group_id, source);
10736 primary_diagnostic_group_ids
10737 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10738
10739 diagnostics.push(DiagnosticEntry {
10740 range,
10741 diagnostic: Diagnostic {
10742 source: diagnostic.source.clone(),
10743 source_kind,
10744 code: diagnostic.code.clone(),
10745 code_description: diagnostic
10746 .code_description
10747 .as_ref()
10748 .and_then(|d| d.href.clone()),
10749 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10750 markdown: adapter.as_ref().and_then(|adapter| {
10751 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10752 }),
10753 message: diagnostic.message.trim().to_string(),
10754 group_id,
10755 is_primary: true,
10756 is_disk_based,
10757 is_unnecessary,
10758 underline,
10759 data: diagnostic.data.clone(),
10760 },
10761 });
10762 if let Some(infos) = &diagnostic.related_information {
10763 for info in infos {
10764 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10765 let range = range_from_lsp(info.location.range);
10766 diagnostics.push(DiagnosticEntry {
10767 range,
10768 diagnostic: Diagnostic {
10769 source: diagnostic.source.clone(),
10770 source_kind,
10771 code: diagnostic.code.clone(),
10772 code_description: diagnostic
10773 .code_description
10774 .as_ref()
10775 .and_then(|d| d.href.clone()),
10776 severity: DiagnosticSeverity::INFORMATION,
10777 markdown: adapter.as_ref().and_then(|adapter| {
10778 adapter.diagnostic_message_to_markdown(&info.message)
10779 }),
10780 message: info.message.trim().to_string(),
10781 group_id,
10782 is_primary: false,
10783 is_disk_based,
10784 is_unnecessary: false,
10785 underline,
10786 data: diagnostic.data.clone(),
10787 },
10788 });
10789 }
10790 }
10791 }
10792 }
10793 }
10794
10795 for entry in &mut diagnostics {
10796 let diagnostic = &mut entry.diagnostic;
10797 if !diagnostic.is_primary {
10798 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10799 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10800 source,
10801 diagnostic.code.clone(),
10802 entry.range.clone(),
10803 )) {
10804 if let Some(severity) = severity {
10805 diagnostic.severity = severity;
10806 }
10807 diagnostic.is_unnecessary = is_unnecessary;
10808 }
10809 }
10810 }
10811
10812 DocumentDiagnostics {
10813 diagnostics,
10814 document_abs_path,
10815 version: lsp_diagnostics.version,
10816 }
10817 }
10818
10819 fn insert_newly_running_language_server(
10820 &mut self,
10821 adapter: Arc<CachedLspAdapter>,
10822 language_server: Arc<LanguageServer>,
10823 server_id: LanguageServerId,
10824 key: LanguageServerSeed,
10825 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10826 cx: &mut Context<Self>,
10827 ) {
10828 let Some(local) = self.as_local_mut() else {
10829 return;
10830 };
10831 // If the language server for this key doesn't match the server id, don't store the
10832 // server. Which will cause it to be dropped, killing the process
10833 if local
10834 .language_server_ids
10835 .get(&key)
10836 .map(|state| state.id != server_id)
10837 .unwrap_or(false)
10838 {
10839 return;
10840 }
10841
10842 // Update language_servers collection with Running variant of LanguageServerState
10843 // indicating that the server is up and running and ready
10844 let workspace_folders = workspace_folders.lock().clone();
10845 language_server.set_workspace_folders(workspace_folders);
10846
10847 let workspace_diagnostics_refresh_tasks = language_server
10848 .capabilities()
10849 .diagnostic_provider
10850 .and_then(|provider| {
10851 let workspace_refresher = lsp_workspace_diagnostics_refresh(
10852 None,
10853 provider.clone(),
10854 language_server.clone(),
10855 cx,
10856 )?;
10857 local
10858 .language_server_dynamic_registrations
10859 .entry(server_id)
10860 .or_default()
10861 .diagnostics
10862 .entry(None)
10863 .or_insert(provider);
10864 Some((None, workspace_refresher))
10865 })
10866 .into_iter()
10867 .collect();
10868 local.language_servers.insert(
10869 server_id,
10870 LanguageServerState::Running {
10871 workspace_diagnostics_refresh_tasks,
10872 adapter: adapter.clone(),
10873 server: language_server.clone(),
10874 simulate_disk_based_diagnostics_completion: None,
10875 },
10876 );
10877 local
10878 .languages
10879 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10880 if let Some(file_ops_caps) = language_server
10881 .capabilities()
10882 .workspace
10883 .as_ref()
10884 .and_then(|ws| ws.file_operations.as_ref())
10885 {
10886 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10887 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10888 if did_rename_caps.or(will_rename_caps).is_some() {
10889 let watcher = RenamePathsWatchedForServer::default()
10890 .with_did_rename_patterns(did_rename_caps)
10891 .with_will_rename_patterns(will_rename_caps);
10892 local
10893 .language_server_paths_watched_for_rename
10894 .insert(server_id, watcher);
10895 }
10896 }
10897
10898 self.language_server_statuses.insert(
10899 server_id,
10900 LanguageServerStatus {
10901 name: language_server.name(),
10902 pending_work: Default::default(),
10903 has_pending_diagnostic_updates: false,
10904 progress_tokens: Default::default(),
10905 worktree: Some(key.worktree_id),
10906 },
10907 );
10908
10909 cx.emit(LspStoreEvent::LanguageServerAdded(
10910 server_id,
10911 language_server.name(),
10912 Some(key.worktree_id),
10913 ));
10914 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
10915
10916 let server_capabilities = language_server.capabilities();
10917 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10918 downstream_client
10919 .send(proto::StartLanguageServer {
10920 project_id: *project_id,
10921 server: Some(proto::LanguageServer {
10922 id: server_id.to_proto(),
10923 name: language_server.name().to_string(),
10924 worktree_id: Some(key.worktree_id.to_proto()),
10925 }),
10926 capabilities: serde_json::to_string(&server_capabilities)
10927 .expect("serializing server LSP capabilities"),
10928 })
10929 .log_err();
10930 }
10931 self.lsp_server_capabilities
10932 .insert(server_id, server_capabilities);
10933
10934 // Tell the language server about every open buffer in the worktree that matches the language.
10935 // Also check for buffers in worktrees that reused this server
10936 let mut worktrees_using_server = vec![key.worktree_id];
10937 if let Some(local) = self.as_local() {
10938 // Find all worktrees that have this server in their language server tree
10939 for (worktree_id, servers) in &local.lsp_tree.instances {
10940 if *worktree_id != key.worktree_id {
10941 for server_map in servers.roots.values() {
10942 if server_map
10943 .values()
10944 .any(|(node, _)| node.id() == Some(server_id))
10945 {
10946 worktrees_using_server.push(*worktree_id);
10947 }
10948 }
10949 }
10950 }
10951 }
10952
10953 let mut buffer_paths_registered = Vec::new();
10954 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10955 let mut lsp_adapters = HashMap::default();
10956 for buffer_handle in buffer_store.buffers() {
10957 let buffer = buffer_handle.read(cx);
10958 let file = match File::from_dyn(buffer.file()) {
10959 Some(file) => file,
10960 None => continue,
10961 };
10962 let language = match buffer.language() {
10963 Some(language) => language,
10964 None => continue,
10965 };
10966
10967 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10968 || !lsp_adapters
10969 .entry(language.name())
10970 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
10971 .iter()
10972 .any(|a| a.name == key.name)
10973 {
10974 continue;
10975 }
10976 // didOpen
10977 let file = match file.as_local() {
10978 Some(file) => file,
10979 None => continue,
10980 };
10981
10982 let local = self.as_local_mut().unwrap();
10983
10984 let buffer_id = buffer.remote_id();
10985 if local.registered_buffers.contains_key(&buffer_id) {
10986 let versions = local
10987 .buffer_snapshots
10988 .entry(buffer_id)
10989 .or_default()
10990 .entry(server_id)
10991 .and_modify(|_| {
10992 assert!(
10993 false,
10994 "There should not be an existing snapshot for a newly inserted buffer"
10995 )
10996 })
10997 .or_insert_with(|| {
10998 vec![LspBufferSnapshot {
10999 version: 0,
11000 snapshot: buffer.text_snapshot(),
11001 }]
11002 });
11003
11004 let snapshot = versions.last().unwrap();
11005 let version = snapshot.version;
11006 let initial_snapshot = &snapshot.snapshot;
11007 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11008 language_server.register_buffer(
11009 uri,
11010 adapter.language_id(&language.name()),
11011 version,
11012 initial_snapshot.text(),
11013 );
11014 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11015 local
11016 .buffers_opened_in_servers
11017 .entry(buffer_id)
11018 .or_default()
11019 .insert(server_id);
11020 }
11021 buffer_handle.update(cx, |buffer, cx| {
11022 buffer.set_completion_triggers(
11023 server_id,
11024 language_server
11025 .capabilities()
11026 .completion_provider
11027 .as_ref()
11028 .and_then(|provider| {
11029 provider
11030 .trigger_characters
11031 .as_ref()
11032 .map(|characters| characters.iter().cloned().collect())
11033 })
11034 .unwrap_or_default(),
11035 cx,
11036 )
11037 });
11038 }
11039 });
11040
11041 for (buffer_id, abs_path) in buffer_paths_registered {
11042 cx.emit(LspStoreEvent::LanguageServerUpdate {
11043 language_server_id: server_id,
11044 name: Some(adapter.name()),
11045 message: proto::update_language_server::Variant::RegisteredForBuffer(
11046 proto::RegisteredForBuffer {
11047 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11048 buffer_id: buffer_id.to_proto(),
11049 },
11050 ),
11051 });
11052 }
11053
11054 cx.notify();
11055 }
11056
11057 pub fn language_servers_running_disk_based_diagnostics(
11058 &self,
11059 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11060 self.language_server_statuses
11061 .iter()
11062 .filter_map(|(id, status)| {
11063 if status.has_pending_diagnostic_updates {
11064 Some(*id)
11065 } else {
11066 None
11067 }
11068 })
11069 }
11070
11071 pub(crate) fn cancel_language_server_work_for_buffers(
11072 &mut self,
11073 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11074 cx: &mut Context<Self>,
11075 ) {
11076 if let Some((client, project_id)) = self.upstream_client() {
11077 let request = client.request(proto::CancelLanguageServerWork {
11078 project_id,
11079 work: Some(proto::cancel_language_server_work::Work::Buffers(
11080 proto::cancel_language_server_work::Buffers {
11081 buffer_ids: buffers
11082 .into_iter()
11083 .map(|b| b.read(cx).remote_id().to_proto())
11084 .collect(),
11085 },
11086 )),
11087 });
11088 cx.background_spawn(request).detach_and_log_err(cx);
11089 } else if let Some(local) = self.as_local() {
11090 let servers = buffers
11091 .into_iter()
11092 .flat_map(|buffer| {
11093 buffer.update(cx, |buffer, cx| {
11094 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11095 })
11096 })
11097 .collect::<HashSet<_>>();
11098 for server_id in servers {
11099 self.cancel_language_server_work(server_id, None, cx);
11100 }
11101 }
11102 }
11103
11104 pub(crate) fn cancel_language_server_work(
11105 &mut self,
11106 server_id: LanguageServerId,
11107 token_to_cancel: Option<String>,
11108 cx: &mut Context<Self>,
11109 ) {
11110 if let Some(local) = self.as_local() {
11111 let status = self.language_server_statuses.get(&server_id);
11112 let server = local.language_servers.get(&server_id);
11113 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11114 {
11115 for (token, progress) in &status.pending_work {
11116 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11117 && token != token_to_cancel
11118 {
11119 continue;
11120 }
11121 if progress.is_cancellable {
11122 server
11123 .notify::<lsp::notification::WorkDoneProgressCancel>(
11124 WorkDoneProgressCancelParams {
11125 token: lsp::NumberOrString::String(token.clone()),
11126 },
11127 )
11128 .ok();
11129 }
11130 }
11131 }
11132 } else if let Some((client, project_id)) = self.upstream_client() {
11133 let request = client.request(proto::CancelLanguageServerWork {
11134 project_id,
11135 work: Some(
11136 proto::cancel_language_server_work::Work::LanguageServerWork(
11137 proto::cancel_language_server_work::LanguageServerWork {
11138 language_server_id: server_id.to_proto(),
11139 token: token_to_cancel,
11140 },
11141 ),
11142 ),
11143 });
11144 cx.background_spawn(request).detach_and_log_err(cx);
11145 }
11146 }
11147
11148 fn register_supplementary_language_server(
11149 &mut self,
11150 id: LanguageServerId,
11151 name: LanguageServerName,
11152 server: Arc<LanguageServer>,
11153 cx: &mut Context<Self>,
11154 ) {
11155 if let Some(local) = self.as_local_mut() {
11156 local
11157 .supplementary_language_servers
11158 .insert(id, (name.clone(), server));
11159 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11160 }
11161 }
11162
11163 fn unregister_supplementary_language_server(
11164 &mut self,
11165 id: LanguageServerId,
11166 cx: &mut Context<Self>,
11167 ) {
11168 if let Some(local) = self.as_local_mut() {
11169 local.supplementary_language_servers.remove(&id);
11170 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11171 }
11172 }
11173
11174 pub(crate) fn supplementary_language_servers(
11175 &self,
11176 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11177 self.as_local().into_iter().flat_map(|local| {
11178 local
11179 .supplementary_language_servers
11180 .iter()
11181 .map(|(id, (name, _))| (*id, name.clone()))
11182 })
11183 }
11184
11185 pub fn language_server_adapter_for_id(
11186 &self,
11187 id: LanguageServerId,
11188 ) -> Option<Arc<CachedLspAdapter>> {
11189 self.as_local()
11190 .and_then(|local| local.language_servers.get(&id))
11191 .and_then(|language_server_state| match language_server_state {
11192 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11193 _ => None,
11194 })
11195 }
11196
11197 pub(super) fn update_local_worktree_language_servers(
11198 &mut self,
11199 worktree_handle: &Entity<Worktree>,
11200 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11201 cx: &mut Context<Self>,
11202 ) {
11203 if changes.is_empty() {
11204 return;
11205 }
11206
11207 let Some(local) = self.as_local() else { return };
11208
11209 local.prettier_store.update(cx, |prettier_store, cx| {
11210 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11211 });
11212
11213 let worktree_id = worktree_handle.read(cx).id();
11214 let mut language_server_ids = local
11215 .language_server_ids
11216 .iter()
11217 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11218 .collect::<Vec<_>>();
11219 language_server_ids.sort();
11220 language_server_ids.dedup();
11221
11222 // let abs_path = worktree_handle.read(cx).abs_path();
11223 for server_id in &language_server_ids {
11224 if let Some(LanguageServerState::Running { server, .. }) =
11225 local.language_servers.get(server_id)
11226 && let Some(watched_paths) = local
11227 .language_server_watched_paths
11228 .get(server_id)
11229 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11230 {
11231 let params = lsp::DidChangeWatchedFilesParams {
11232 changes: changes
11233 .iter()
11234 .filter_map(|(path, _, change)| {
11235 if !watched_paths.is_match(path.as_std_path()) {
11236 return None;
11237 }
11238 let typ = match change {
11239 PathChange::Loaded => return None,
11240 PathChange::Added => lsp::FileChangeType::CREATED,
11241 PathChange::Removed => lsp::FileChangeType::DELETED,
11242 PathChange::Updated => lsp::FileChangeType::CHANGED,
11243 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11244 };
11245 let uri = lsp::Uri::from_file_path(
11246 worktree_handle.read(cx).absolutize(&path),
11247 )
11248 .ok()?;
11249 Some(lsp::FileEvent { uri, typ })
11250 })
11251 .collect(),
11252 };
11253 if !params.changes.is_empty() {
11254 server
11255 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11256 .ok();
11257 }
11258 }
11259 }
11260 for (path, _, _) in changes {
11261 if let Some(file_name) = path.file_name()
11262 && local.watched_manifest_filenames.contains(file_name)
11263 {
11264 self.request_workspace_config_refresh();
11265 break;
11266 }
11267 }
11268 }
11269
11270 pub fn wait_for_remote_buffer(
11271 &mut self,
11272 id: BufferId,
11273 cx: &mut Context<Self>,
11274 ) -> Task<Result<Entity<Buffer>>> {
11275 self.buffer_store.update(cx, |buffer_store, cx| {
11276 buffer_store.wait_for_remote_buffer(id, cx)
11277 })
11278 }
11279
11280 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11281 let mut result = proto::Symbol {
11282 language_server_name: symbol.language_server_name.0.to_string(),
11283 source_worktree_id: symbol.source_worktree_id.to_proto(),
11284 language_server_id: symbol.source_language_server_id.to_proto(),
11285 name: symbol.name.clone(),
11286 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11287 start: Some(proto::PointUtf16 {
11288 row: symbol.range.start.0.row,
11289 column: symbol.range.start.0.column,
11290 }),
11291 end: Some(proto::PointUtf16 {
11292 row: symbol.range.end.0.row,
11293 column: symbol.range.end.0.column,
11294 }),
11295 worktree_id: Default::default(),
11296 path: Default::default(),
11297 signature: Default::default(),
11298 };
11299 match &symbol.path {
11300 SymbolLocation::InProject(path) => {
11301 result.worktree_id = path.worktree_id.to_proto();
11302 result.path = path.path.to_proto();
11303 }
11304 SymbolLocation::OutsideProject {
11305 abs_path,
11306 signature,
11307 } => {
11308 result.path = abs_path.to_string_lossy().into_owned();
11309 result.signature = signature.to_vec();
11310 }
11311 }
11312 result
11313 }
11314
11315 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11316 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11317 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11318 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11319
11320 let path = if serialized_symbol.signature.is_empty() {
11321 SymbolLocation::InProject(ProjectPath {
11322 worktree_id,
11323 path: RelPath::from_proto(&serialized_symbol.path)
11324 .context("invalid symbol path")?,
11325 })
11326 } else {
11327 SymbolLocation::OutsideProject {
11328 abs_path: Path::new(&serialized_symbol.path).into(),
11329 signature: serialized_symbol
11330 .signature
11331 .try_into()
11332 .map_err(|_| anyhow!("invalid signature"))?,
11333 }
11334 };
11335
11336 let start = serialized_symbol.start.context("invalid start")?;
11337 let end = serialized_symbol.end.context("invalid end")?;
11338 Ok(CoreSymbol {
11339 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11340 source_worktree_id,
11341 source_language_server_id: LanguageServerId::from_proto(
11342 serialized_symbol.language_server_id,
11343 ),
11344 path,
11345 name: serialized_symbol.name,
11346 range: Unclipped(PointUtf16::new(start.row, start.column))
11347 ..Unclipped(PointUtf16::new(end.row, end.column)),
11348 kind,
11349 })
11350 }
11351
11352 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11353 let mut serialized_completion = proto::Completion {
11354 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11355 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11356 new_text: completion.new_text.clone(),
11357 ..proto::Completion::default()
11358 };
11359 match &completion.source {
11360 CompletionSource::Lsp {
11361 insert_range,
11362 server_id,
11363 lsp_completion,
11364 lsp_defaults,
11365 resolved,
11366 } => {
11367 let (old_insert_start, old_insert_end) = insert_range
11368 .as_ref()
11369 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11370 .unzip();
11371
11372 serialized_completion.old_insert_start = old_insert_start;
11373 serialized_completion.old_insert_end = old_insert_end;
11374 serialized_completion.source = proto::completion::Source::Lsp as i32;
11375 serialized_completion.server_id = server_id.0 as u64;
11376 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11377 serialized_completion.lsp_defaults = lsp_defaults
11378 .as_deref()
11379 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11380 serialized_completion.resolved = *resolved;
11381 }
11382 CompletionSource::BufferWord {
11383 word_range,
11384 resolved,
11385 } => {
11386 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11387 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11388 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11389 serialized_completion.resolved = *resolved;
11390 }
11391 CompletionSource::Custom => {
11392 serialized_completion.source = proto::completion::Source::Custom as i32;
11393 serialized_completion.resolved = true;
11394 }
11395 CompletionSource::Dap { sort_text } => {
11396 serialized_completion.source = proto::completion::Source::Dap as i32;
11397 serialized_completion.sort_text = Some(sort_text.clone());
11398 }
11399 }
11400
11401 serialized_completion
11402 }
11403
11404 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11405 let old_replace_start = completion
11406 .old_replace_start
11407 .and_then(deserialize_anchor)
11408 .context("invalid old start")?;
11409 let old_replace_end = completion
11410 .old_replace_end
11411 .and_then(deserialize_anchor)
11412 .context("invalid old end")?;
11413 let insert_range = {
11414 match completion.old_insert_start.zip(completion.old_insert_end) {
11415 Some((start, end)) => {
11416 let start = deserialize_anchor(start).context("invalid insert old start")?;
11417 let end = deserialize_anchor(end).context("invalid insert old end")?;
11418 Some(start..end)
11419 }
11420 None => None,
11421 }
11422 };
11423 Ok(CoreCompletion {
11424 replace_range: old_replace_start..old_replace_end,
11425 new_text: completion.new_text,
11426 source: match proto::completion::Source::from_i32(completion.source) {
11427 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11428 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11429 insert_range,
11430 server_id: LanguageServerId::from_proto(completion.server_id),
11431 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11432 lsp_defaults: completion
11433 .lsp_defaults
11434 .as_deref()
11435 .map(serde_json::from_slice)
11436 .transpose()?,
11437 resolved: completion.resolved,
11438 },
11439 Some(proto::completion::Source::BufferWord) => {
11440 let word_range = completion
11441 .buffer_word_start
11442 .and_then(deserialize_anchor)
11443 .context("invalid buffer word start")?
11444 ..completion
11445 .buffer_word_end
11446 .and_then(deserialize_anchor)
11447 .context("invalid buffer word end")?;
11448 CompletionSource::BufferWord {
11449 word_range,
11450 resolved: completion.resolved,
11451 }
11452 }
11453 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11454 sort_text: completion
11455 .sort_text
11456 .context("expected sort text to exist")?,
11457 },
11458 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11459 },
11460 })
11461 }
11462
11463 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11464 let (kind, lsp_action) = match &action.lsp_action {
11465 LspAction::Action(code_action) => (
11466 proto::code_action::Kind::Action as i32,
11467 serde_json::to_vec(code_action).unwrap(),
11468 ),
11469 LspAction::Command(command) => (
11470 proto::code_action::Kind::Command as i32,
11471 serde_json::to_vec(command).unwrap(),
11472 ),
11473 LspAction::CodeLens(code_lens) => (
11474 proto::code_action::Kind::CodeLens as i32,
11475 serde_json::to_vec(code_lens).unwrap(),
11476 ),
11477 };
11478
11479 proto::CodeAction {
11480 server_id: action.server_id.0 as u64,
11481 start: Some(serialize_anchor(&action.range.start)),
11482 end: Some(serialize_anchor(&action.range.end)),
11483 lsp_action,
11484 kind,
11485 resolved: action.resolved,
11486 }
11487 }
11488
11489 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11490 let start = action
11491 .start
11492 .and_then(deserialize_anchor)
11493 .context("invalid start")?;
11494 let end = action
11495 .end
11496 .and_then(deserialize_anchor)
11497 .context("invalid end")?;
11498 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11499 Some(proto::code_action::Kind::Action) => {
11500 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11501 }
11502 Some(proto::code_action::Kind::Command) => {
11503 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11504 }
11505 Some(proto::code_action::Kind::CodeLens) => {
11506 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11507 }
11508 None => anyhow::bail!("Unknown action kind {}", action.kind),
11509 };
11510 Ok(CodeAction {
11511 server_id: LanguageServerId(action.server_id as usize),
11512 range: start..end,
11513 resolved: action.resolved,
11514 lsp_action,
11515 })
11516 }
11517
11518 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11519 match &formatting_result {
11520 Ok(_) => self.last_formatting_failure = None,
11521 Err(error) => {
11522 let error_string = format!("{error:#}");
11523 log::error!("Formatting failed: {error_string}");
11524 self.last_formatting_failure
11525 .replace(error_string.lines().join(" "));
11526 }
11527 }
11528 }
11529
11530 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11531 self.lsp_server_capabilities.remove(&for_server);
11532 for lsp_data in self.lsp_data.values_mut() {
11533 lsp_data.remove_server_data(for_server);
11534 }
11535 if let Some(local) = self.as_local_mut() {
11536 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11537 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11538 buffer_servers.remove(&for_server);
11539 }
11540 }
11541 }
11542
11543 pub fn result_id(
11544 &self,
11545 server_id: LanguageServerId,
11546 buffer_id: BufferId,
11547 cx: &App,
11548 ) -> Option<String> {
11549 let abs_path = self
11550 .buffer_store
11551 .read(cx)
11552 .get(buffer_id)
11553 .and_then(|b| File::from_dyn(b.read(cx).file()))
11554 .map(|f| f.abs_path(cx))?;
11555 self.as_local()?
11556 .buffer_pull_diagnostics_result_ids
11557 .get(&server_id)?
11558 .get(&abs_path)?
11559 .clone()
11560 }
11561
11562 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11563 let Some(local) = self.as_local() else {
11564 return HashMap::default();
11565 };
11566 local
11567 .buffer_pull_diagnostics_result_ids
11568 .get(&server_id)
11569 .into_iter()
11570 .flatten()
11571 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11572 .collect()
11573 }
11574
11575 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11576 if let Some(LanguageServerState::Running {
11577 workspace_diagnostics_refresh_tasks,
11578 ..
11579 }) = self
11580 .as_local_mut()
11581 .and_then(|local| local.language_servers.get_mut(&server_id))
11582 {
11583 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11584 diagnostics.refresh_tx.try_send(()).ok();
11585 }
11586 }
11587 }
11588
11589 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11590 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11591 return;
11592 };
11593 let Some(local) = self.as_local_mut() else {
11594 return;
11595 };
11596
11597 for server_id in buffer.update(cx, |buffer, cx| {
11598 local.language_server_ids_for_buffer(buffer, cx)
11599 }) {
11600 if let Some(LanguageServerState::Running {
11601 workspace_diagnostics_refresh_tasks,
11602 ..
11603 }) = local.language_servers.get_mut(&server_id)
11604 {
11605 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11606 diagnostics.refresh_tx.try_send(()).ok();
11607 }
11608 }
11609 }
11610 }
11611
11612 fn apply_workspace_diagnostic_report(
11613 &mut self,
11614 server_id: LanguageServerId,
11615 report: lsp::WorkspaceDiagnosticReportResult,
11616 cx: &mut Context<Self>,
11617 ) {
11618 let workspace_diagnostics =
11619 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11620 let mut unchanged_buffers = HashSet::default();
11621 let mut changed_buffers = HashSet::default();
11622 let workspace_diagnostics_updates = workspace_diagnostics
11623 .into_iter()
11624 .filter_map(
11625 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11626 LspPullDiagnostics::Response {
11627 server_id,
11628 uri,
11629 diagnostics,
11630 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11631 LspPullDiagnostics::Default => None,
11632 },
11633 )
11634 .fold(
11635 HashMap::default(),
11636 |mut acc, (server_id, uri, diagnostics, version)| {
11637 let (result_id, diagnostics) = match diagnostics {
11638 PulledDiagnostics::Unchanged { result_id } => {
11639 unchanged_buffers.insert(uri.clone());
11640 (Some(result_id), Vec::new())
11641 }
11642 PulledDiagnostics::Changed {
11643 result_id,
11644 diagnostics,
11645 } => {
11646 changed_buffers.insert(uri.clone());
11647 (result_id, diagnostics)
11648 }
11649 };
11650 let disk_based_sources = Cow::Owned(
11651 self.language_server_adapter_for_id(server_id)
11652 .as_ref()
11653 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11654 .unwrap_or(&[])
11655 .to_vec(),
11656 );
11657 acc.entry(server_id)
11658 .or_insert_with(Vec::new)
11659 .push(DocumentDiagnosticsUpdate {
11660 server_id,
11661 diagnostics: lsp::PublishDiagnosticsParams {
11662 uri,
11663 diagnostics,
11664 version,
11665 },
11666 result_id,
11667 disk_based_sources,
11668 });
11669 acc
11670 },
11671 );
11672
11673 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11674 self.merge_lsp_diagnostics(
11675 DiagnosticSourceKind::Pulled,
11676 diagnostic_updates,
11677 |buffer, old_diagnostic, cx| {
11678 File::from_dyn(buffer.file())
11679 .and_then(|file| {
11680 let abs_path = file.as_local()?.abs_path(cx);
11681 lsp::Uri::from_file_path(abs_path).ok()
11682 })
11683 .is_none_or(|buffer_uri| {
11684 unchanged_buffers.contains(&buffer_uri)
11685 || match old_diagnostic.source_kind {
11686 DiagnosticSourceKind::Pulled => {
11687 !changed_buffers.contains(&buffer_uri)
11688 }
11689 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11690 true
11691 }
11692 }
11693 })
11694 },
11695 cx,
11696 )
11697 .log_err();
11698 }
11699 }
11700
11701 fn register_server_capabilities(
11702 &mut self,
11703 server_id: LanguageServerId,
11704 params: lsp::RegistrationParams,
11705 cx: &mut Context<Self>,
11706 ) -> anyhow::Result<()> {
11707 let server = self
11708 .language_server_for_id(server_id)
11709 .with_context(|| format!("no server {server_id} found"))?;
11710 for reg in params.registrations {
11711 match reg.method.as_str() {
11712 "workspace/didChangeWatchedFiles" => {
11713 if let Some(options) = reg.register_options {
11714 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11715 let caps = serde_json::from_value(options)?;
11716 local_lsp_store
11717 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11718 true
11719 } else {
11720 false
11721 };
11722 if notify {
11723 notify_server_capabilities_updated(&server, cx);
11724 }
11725 }
11726 }
11727 "workspace/didChangeConfiguration" => {
11728 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11729 }
11730 "workspace/didChangeWorkspaceFolders" => {
11731 // In this case register options is an empty object, we can ignore it
11732 let caps = lsp::WorkspaceFoldersServerCapabilities {
11733 supported: Some(true),
11734 change_notifications: Some(OneOf::Right(reg.id)),
11735 };
11736 server.update_capabilities(|capabilities| {
11737 capabilities
11738 .workspace
11739 .get_or_insert_default()
11740 .workspace_folders = Some(caps);
11741 });
11742 notify_server_capabilities_updated(&server, cx);
11743 }
11744 "workspace/symbol" => {
11745 let options = parse_register_capabilities(reg)?;
11746 server.update_capabilities(|capabilities| {
11747 capabilities.workspace_symbol_provider = Some(options);
11748 });
11749 notify_server_capabilities_updated(&server, cx);
11750 }
11751 "workspace/fileOperations" => {
11752 if let Some(options) = reg.register_options {
11753 let caps = serde_json::from_value(options)?;
11754 server.update_capabilities(|capabilities| {
11755 capabilities
11756 .workspace
11757 .get_or_insert_default()
11758 .file_operations = Some(caps);
11759 });
11760 notify_server_capabilities_updated(&server, cx);
11761 }
11762 }
11763 "workspace/executeCommand" => {
11764 if let Some(options) = reg.register_options {
11765 let options = serde_json::from_value(options)?;
11766 server.update_capabilities(|capabilities| {
11767 capabilities.execute_command_provider = Some(options);
11768 });
11769 notify_server_capabilities_updated(&server, cx);
11770 }
11771 }
11772 "textDocument/rangeFormatting" => {
11773 let options = parse_register_capabilities(reg)?;
11774 server.update_capabilities(|capabilities| {
11775 capabilities.document_range_formatting_provider = Some(options);
11776 });
11777 notify_server_capabilities_updated(&server, cx);
11778 }
11779 "textDocument/onTypeFormatting" => {
11780 if let Some(options) = reg
11781 .register_options
11782 .map(serde_json::from_value)
11783 .transpose()?
11784 {
11785 server.update_capabilities(|capabilities| {
11786 capabilities.document_on_type_formatting_provider = Some(options);
11787 });
11788 notify_server_capabilities_updated(&server, cx);
11789 }
11790 }
11791 "textDocument/formatting" => {
11792 let options = parse_register_capabilities(reg)?;
11793 server.update_capabilities(|capabilities| {
11794 capabilities.document_formatting_provider = Some(options);
11795 });
11796 notify_server_capabilities_updated(&server, cx);
11797 }
11798 "textDocument/rename" => {
11799 let options = parse_register_capabilities(reg)?;
11800 server.update_capabilities(|capabilities| {
11801 capabilities.rename_provider = Some(options);
11802 });
11803 notify_server_capabilities_updated(&server, cx);
11804 }
11805 "textDocument/inlayHint" => {
11806 let options = parse_register_capabilities(reg)?;
11807 server.update_capabilities(|capabilities| {
11808 capabilities.inlay_hint_provider = Some(options);
11809 });
11810 notify_server_capabilities_updated(&server, cx);
11811 }
11812 "textDocument/documentSymbol" => {
11813 let options = parse_register_capabilities(reg)?;
11814 server.update_capabilities(|capabilities| {
11815 capabilities.document_symbol_provider = Some(options);
11816 });
11817 notify_server_capabilities_updated(&server, cx);
11818 }
11819 "textDocument/codeAction" => {
11820 let options = parse_register_capabilities(reg)?;
11821 let provider = match options {
11822 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11823 OneOf::Right(caps) => caps,
11824 };
11825 server.update_capabilities(|capabilities| {
11826 capabilities.code_action_provider = Some(provider);
11827 });
11828 notify_server_capabilities_updated(&server, cx);
11829 }
11830 "textDocument/definition" => {
11831 let options = parse_register_capabilities(reg)?;
11832 server.update_capabilities(|capabilities| {
11833 capabilities.definition_provider = Some(options);
11834 });
11835 notify_server_capabilities_updated(&server, cx);
11836 }
11837 "textDocument/completion" => {
11838 if let Some(caps) = reg
11839 .register_options
11840 .map(serde_json::from_value)
11841 .transpose()?
11842 {
11843 server.update_capabilities(|capabilities| {
11844 capabilities.completion_provider = Some(caps);
11845 });
11846 notify_server_capabilities_updated(&server, cx);
11847 }
11848 }
11849 "textDocument/hover" => {
11850 let options = parse_register_capabilities(reg)?;
11851 let provider = match options {
11852 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11853 OneOf::Right(caps) => caps,
11854 };
11855 server.update_capabilities(|capabilities| {
11856 capabilities.hover_provider = Some(provider);
11857 });
11858 notify_server_capabilities_updated(&server, cx);
11859 }
11860 "textDocument/signatureHelp" => {
11861 if let Some(caps) = reg
11862 .register_options
11863 .map(serde_json::from_value)
11864 .transpose()?
11865 {
11866 server.update_capabilities(|capabilities| {
11867 capabilities.signature_help_provider = Some(caps);
11868 });
11869 notify_server_capabilities_updated(&server, cx);
11870 }
11871 }
11872 "textDocument/didChange" => {
11873 if let Some(sync_kind) = reg
11874 .register_options
11875 .and_then(|opts| opts.get("syncKind").cloned())
11876 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11877 .transpose()?
11878 {
11879 server.update_capabilities(|capabilities| {
11880 let mut sync_options =
11881 Self::take_text_document_sync_options(capabilities);
11882 sync_options.change = Some(sync_kind);
11883 capabilities.text_document_sync =
11884 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11885 });
11886 notify_server_capabilities_updated(&server, cx);
11887 }
11888 }
11889 "textDocument/didSave" => {
11890 if let Some(include_text) = reg
11891 .register_options
11892 .map(|opts| {
11893 let transpose = opts
11894 .get("includeText")
11895 .cloned()
11896 .map(serde_json::from_value::<Option<bool>>)
11897 .transpose();
11898 match transpose {
11899 Ok(value) => Ok(value.flatten()),
11900 Err(e) => Err(e),
11901 }
11902 })
11903 .transpose()?
11904 {
11905 server.update_capabilities(|capabilities| {
11906 let mut sync_options =
11907 Self::take_text_document_sync_options(capabilities);
11908 sync_options.save =
11909 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11910 include_text,
11911 }));
11912 capabilities.text_document_sync =
11913 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11914 });
11915 notify_server_capabilities_updated(&server, cx);
11916 }
11917 }
11918 "textDocument/codeLens" => {
11919 if let Some(caps) = reg
11920 .register_options
11921 .map(serde_json::from_value)
11922 .transpose()?
11923 {
11924 server.update_capabilities(|capabilities| {
11925 capabilities.code_lens_provider = Some(caps);
11926 });
11927 notify_server_capabilities_updated(&server, cx);
11928 }
11929 }
11930 "textDocument/diagnostic" => {
11931 if let Some(caps) = reg
11932 .register_options
11933 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
11934 .transpose()?
11935 {
11936 let local = self
11937 .as_local_mut()
11938 .context("Expected LSP Store to be local")?;
11939 let state = local
11940 .language_servers
11941 .get_mut(&server_id)
11942 .context("Could not obtain Language Servers state")?;
11943 local
11944 .language_server_dynamic_registrations
11945 .get_mut(&server_id)
11946 .and_then(|registrations| {
11947 registrations
11948 .diagnostics
11949 .insert(Some(reg.id.clone()), caps.clone())
11950 });
11951
11952 let mut can_now_provide_diagnostics = false;
11953 if let LanguageServerState::Running {
11954 workspace_diagnostics_refresh_tasks,
11955 ..
11956 } = state
11957 && let Some(task) = lsp_workspace_diagnostics_refresh(
11958 Some(reg.id.clone()),
11959 caps.clone(),
11960 server.clone(),
11961 cx,
11962 )
11963 {
11964 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
11965 can_now_provide_diagnostics = true;
11966 }
11967
11968 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
11969 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
11970 // as it'll think that they're not supported.
11971 if can_now_provide_diagnostics {
11972 server.update_capabilities(|capabilities| {
11973 debug_assert!(capabilities.diagnostic_provider.is_none());
11974 capabilities.diagnostic_provider = Some(caps);
11975 });
11976 }
11977
11978 notify_server_capabilities_updated(&server, cx);
11979 }
11980 }
11981 "textDocument/documentColor" => {
11982 let options = parse_register_capabilities(reg)?;
11983 let provider = match options {
11984 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11985 OneOf::Right(caps) => caps,
11986 };
11987 server.update_capabilities(|capabilities| {
11988 capabilities.color_provider = Some(provider);
11989 });
11990 notify_server_capabilities_updated(&server, cx);
11991 }
11992 _ => log::warn!("unhandled capability registration: {reg:?}"),
11993 }
11994 }
11995
11996 Ok(())
11997 }
11998
11999 fn unregister_server_capabilities(
12000 &mut self,
12001 server_id: LanguageServerId,
12002 params: lsp::UnregistrationParams,
12003 cx: &mut Context<Self>,
12004 ) -> anyhow::Result<()> {
12005 let server = self
12006 .language_server_for_id(server_id)
12007 .with_context(|| format!("no server {server_id} found"))?;
12008 for unreg in params.unregisterations.iter() {
12009 match unreg.method.as_str() {
12010 "workspace/didChangeWatchedFiles" => {
12011 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12012 local_lsp_store
12013 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12014 true
12015 } else {
12016 false
12017 };
12018 if notify {
12019 notify_server_capabilities_updated(&server, cx);
12020 }
12021 }
12022 "workspace/didChangeConfiguration" => {
12023 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12024 }
12025 "workspace/didChangeWorkspaceFolders" => {
12026 server.update_capabilities(|capabilities| {
12027 capabilities
12028 .workspace
12029 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12030 workspace_folders: None,
12031 file_operations: None,
12032 })
12033 .workspace_folders = None;
12034 });
12035 notify_server_capabilities_updated(&server, cx);
12036 }
12037 "workspace/symbol" => {
12038 server.update_capabilities(|capabilities| {
12039 capabilities.workspace_symbol_provider = None
12040 });
12041 notify_server_capabilities_updated(&server, cx);
12042 }
12043 "workspace/fileOperations" => {
12044 server.update_capabilities(|capabilities| {
12045 capabilities
12046 .workspace
12047 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12048 workspace_folders: None,
12049 file_operations: None,
12050 })
12051 .file_operations = None;
12052 });
12053 notify_server_capabilities_updated(&server, cx);
12054 }
12055 "workspace/executeCommand" => {
12056 server.update_capabilities(|capabilities| {
12057 capabilities.execute_command_provider = None;
12058 });
12059 notify_server_capabilities_updated(&server, cx);
12060 }
12061 "textDocument/rangeFormatting" => {
12062 server.update_capabilities(|capabilities| {
12063 capabilities.document_range_formatting_provider = None
12064 });
12065 notify_server_capabilities_updated(&server, cx);
12066 }
12067 "textDocument/onTypeFormatting" => {
12068 server.update_capabilities(|capabilities| {
12069 capabilities.document_on_type_formatting_provider = None;
12070 });
12071 notify_server_capabilities_updated(&server, cx);
12072 }
12073 "textDocument/formatting" => {
12074 server.update_capabilities(|capabilities| {
12075 capabilities.document_formatting_provider = None;
12076 });
12077 notify_server_capabilities_updated(&server, cx);
12078 }
12079 "textDocument/rename" => {
12080 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12081 notify_server_capabilities_updated(&server, cx);
12082 }
12083 "textDocument/codeAction" => {
12084 server.update_capabilities(|capabilities| {
12085 capabilities.code_action_provider = None;
12086 });
12087 notify_server_capabilities_updated(&server, cx);
12088 }
12089 "textDocument/definition" => {
12090 server.update_capabilities(|capabilities| {
12091 capabilities.definition_provider = None;
12092 });
12093 notify_server_capabilities_updated(&server, cx);
12094 }
12095 "textDocument/completion" => {
12096 server.update_capabilities(|capabilities| {
12097 capabilities.completion_provider = None;
12098 });
12099 notify_server_capabilities_updated(&server, cx);
12100 }
12101 "textDocument/hover" => {
12102 server.update_capabilities(|capabilities| {
12103 capabilities.hover_provider = None;
12104 });
12105 notify_server_capabilities_updated(&server, cx);
12106 }
12107 "textDocument/signatureHelp" => {
12108 server.update_capabilities(|capabilities| {
12109 capabilities.signature_help_provider = None;
12110 });
12111 notify_server_capabilities_updated(&server, cx);
12112 }
12113 "textDocument/didChange" => {
12114 server.update_capabilities(|capabilities| {
12115 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12116 sync_options.change = None;
12117 capabilities.text_document_sync =
12118 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12119 });
12120 notify_server_capabilities_updated(&server, cx);
12121 }
12122 "textDocument/didSave" => {
12123 server.update_capabilities(|capabilities| {
12124 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12125 sync_options.save = None;
12126 capabilities.text_document_sync =
12127 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12128 });
12129 notify_server_capabilities_updated(&server, cx);
12130 }
12131 "textDocument/codeLens" => {
12132 server.update_capabilities(|capabilities| {
12133 capabilities.code_lens_provider = None;
12134 });
12135 notify_server_capabilities_updated(&server, cx);
12136 }
12137 "textDocument/diagnostic" => {
12138 let local = self
12139 .as_local_mut()
12140 .context("Expected LSP Store to be local")?;
12141
12142 let state = local
12143 .language_servers
12144 .get_mut(&server_id)
12145 .context("Could not obtain Language Servers state")?;
12146 let options = local
12147 .language_server_dynamic_registrations
12148 .get_mut(&server_id)
12149 .with_context(|| {
12150 format!("Expected dynamic registration to exist for server {server_id}")
12151 })?.diagnostics
12152 .remove(&Some(unreg.id.clone()))
12153 .with_context(|| format!(
12154 "Attempted to unregister non-existent diagnostic registration with ID {}",
12155 unreg.id)
12156 )?;
12157
12158 let mut has_any_diagnostic_providers_still = true;
12159 if let Some(identifier) = diagnostic_identifier(&options)
12160 && let LanguageServerState::Running {
12161 workspace_diagnostics_refresh_tasks,
12162 ..
12163 } = state
12164 {
12165 workspace_diagnostics_refresh_tasks.remove(&identifier);
12166 has_any_diagnostic_providers_still =
12167 !workspace_diagnostics_refresh_tasks.is_empty();
12168 }
12169
12170 if !has_any_diagnostic_providers_still {
12171 server.update_capabilities(|capabilities| {
12172 debug_assert!(capabilities.diagnostic_provider.is_some());
12173 capabilities.diagnostic_provider = None;
12174 });
12175 }
12176
12177 notify_server_capabilities_updated(&server, cx);
12178 }
12179 "textDocument/documentColor" => {
12180 server.update_capabilities(|capabilities| {
12181 capabilities.color_provider = None;
12182 });
12183 notify_server_capabilities_updated(&server, cx);
12184 }
12185 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12186 }
12187 }
12188
12189 Ok(())
12190 }
12191
12192 async fn deduplicate_range_based_lsp_requests<T>(
12193 lsp_store: &Entity<Self>,
12194 server_id: Option<LanguageServerId>,
12195 lsp_request_id: LspRequestId,
12196 proto_request: &T::ProtoRequest,
12197 range: Range<Anchor>,
12198 cx: &mut AsyncApp,
12199 ) -> Result<()>
12200 where
12201 T: LspCommand,
12202 T::ProtoRequest: proto::LspRequestMessage,
12203 {
12204 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12205 let version = deserialize_version(proto_request.buffer_version());
12206 let buffer = lsp_store.update(cx, |this, cx| {
12207 this.buffer_store.read(cx).get_existing(buffer_id)
12208 })??;
12209 buffer
12210 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12211 .await?;
12212 lsp_store.update(cx, |lsp_store, cx| {
12213 let lsp_data = lsp_store
12214 .lsp_data
12215 .entry(buffer_id)
12216 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12217 let chunks_queried_for = lsp_data
12218 .inlay_hints
12219 .applicable_chunks(&[range])
12220 .collect::<Vec<_>>();
12221 match chunks_queried_for.as_slice() {
12222 &[chunk] => {
12223 let key = LspKey {
12224 request_type: TypeId::of::<T>(),
12225 server_queried: server_id,
12226 };
12227 let previous_request = lsp_data
12228 .chunk_lsp_requests
12229 .entry(key)
12230 .or_default()
12231 .insert(chunk, lsp_request_id);
12232 if let Some((previous_request, running_requests)) =
12233 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12234 {
12235 running_requests.remove(&previous_request);
12236 }
12237 }
12238 _ambiguous_chunks => {
12239 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12240 // there, a buffer version-based check will be performed and outdated requests discarded.
12241 }
12242 }
12243 anyhow::Ok(())
12244 })??;
12245
12246 Ok(())
12247 }
12248
12249 async fn query_lsp_locally<T>(
12250 lsp_store: Entity<Self>,
12251 for_server_id: Option<LanguageServerId>,
12252 sender_id: proto::PeerId,
12253 lsp_request_id: LspRequestId,
12254 proto_request: T::ProtoRequest,
12255 position: Option<Anchor>,
12256 cx: &mut AsyncApp,
12257 ) -> Result<()>
12258 where
12259 T: LspCommand + Clone,
12260 T::ProtoRequest: proto::LspRequestMessage,
12261 <T::ProtoRequest as proto::RequestMessage>::Response:
12262 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12263 {
12264 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12265 let version = deserialize_version(proto_request.buffer_version());
12266 let buffer = lsp_store.update(cx, |this, cx| {
12267 this.buffer_store.read(cx).get_existing(buffer_id)
12268 })??;
12269 buffer
12270 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12271 .await?;
12272 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12273 let request =
12274 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12275 let key = LspKey {
12276 request_type: TypeId::of::<T>(),
12277 server_queried: for_server_id,
12278 };
12279 lsp_store.update(cx, |lsp_store, cx| {
12280 let request_task = match for_server_id {
12281 Some(server_id) => {
12282 let server_task = lsp_store.request_lsp(
12283 buffer.clone(),
12284 LanguageServerToQuery::Other(server_id),
12285 request.clone(),
12286 cx,
12287 );
12288 cx.background_spawn(async move {
12289 let mut responses = Vec::new();
12290 match server_task.await {
12291 Ok(response) => responses.push((server_id, response)),
12292 Err(e) => log::error!(
12293 "Error handling response for request {request:?}: {e:#}"
12294 ),
12295 }
12296 responses
12297 })
12298 }
12299 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12300 };
12301 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12302 if T::ProtoRequest::stop_previous_requests() {
12303 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12304 lsp_requests.clear();
12305 }
12306 }
12307 lsp_data.lsp_requests.entry(key).or_default().insert(
12308 lsp_request_id,
12309 cx.spawn(async move |lsp_store, cx| {
12310 let response = request_task.await;
12311 lsp_store
12312 .update(cx, |lsp_store, cx| {
12313 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12314 {
12315 let response = response
12316 .into_iter()
12317 .map(|(server_id, response)| {
12318 (
12319 server_id.to_proto(),
12320 T::response_to_proto(
12321 response,
12322 lsp_store,
12323 sender_id,
12324 &buffer_version,
12325 cx,
12326 )
12327 .into(),
12328 )
12329 })
12330 .collect::<HashMap<_, _>>();
12331 match client.send_lsp_response::<T::ProtoRequest>(
12332 project_id,
12333 lsp_request_id,
12334 response,
12335 ) {
12336 Ok(()) => {}
12337 Err(e) => {
12338 log::error!("Failed to send LSP response: {e:#}",)
12339 }
12340 }
12341 }
12342 })
12343 .ok();
12344 }),
12345 );
12346 })?;
12347 Ok(())
12348 }
12349
12350 fn take_text_document_sync_options(
12351 capabilities: &mut lsp::ServerCapabilities,
12352 ) -> lsp::TextDocumentSyncOptions {
12353 match capabilities.text_document_sync.take() {
12354 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12355 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12356 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12357 sync_options.change = Some(sync_kind);
12358 sync_options
12359 }
12360 None => lsp::TextDocumentSyncOptions::default(),
12361 }
12362 }
12363
12364 #[cfg(any(test, feature = "test-support"))]
12365 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12366 Some(
12367 self.lsp_data
12368 .get_mut(&buffer_id)?
12369 .code_lens
12370 .take()?
12371 .update
12372 .take()?
12373 .1,
12374 )
12375 }
12376
12377 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12378 self.downstream_client.clone()
12379 }
12380
12381 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12382 self.worktree_store.clone()
12383 }
12384
12385 /// Gets what's stored in the LSP data for the given buffer.
12386 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12387 self.lsp_data.get_mut(&buffer_id)
12388 }
12389
12390 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12391 /// new [`BufferLspData`] will be created to replace the previous state.
12392 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12393 let (buffer_id, buffer_version) =
12394 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12395 let lsp_data = self
12396 .lsp_data
12397 .entry(buffer_id)
12398 .or_insert_with(|| BufferLspData::new(buffer, cx));
12399 if buffer_version.changed_since(&lsp_data.buffer_version) {
12400 *lsp_data = BufferLspData::new(buffer, cx);
12401 }
12402 lsp_data
12403 }
12404}
12405
12406// Registration with registerOptions as null, should fallback to true.
12407// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12408fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12409 reg: lsp::Registration,
12410) -> Result<OneOf<bool, T>> {
12411 Ok(match reg.register_options {
12412 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12413 None => OneOf::Left(true),
12414 })
12415}
12416
12417fn subscribe_to_binary_statuses(
12418 languages: &Arc<LanguageRegistry>,
12419 cx: &mut Context<'_, LspStore>,
12420) -> Task<()> {
12421 let mut server_statuses = languages.language_server_binary_statuses();
12422 cx.spawn(async move |lsp_store, cx| {
12423 while let Some((server_name, binary_status)) = server_statuses.next().await {
12424 if lsp_store
12425 .update(cx, |_, cx| {
12426 let mut message = None;
12427 let binary_status = match binary_status {
12428 BinaryStatus::None => proto::ServerBinaryStatus::None,
12429 BinaryStatus::CheckingForUpdate => {
12430 proto::ServerBinaryStatus::CheckingForUpdate
12431 }
12432 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12433 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12434 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12435 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12436 BinaryStatus::Failed { error } => {
12437 message = Some(error);
12438 proto::ServerBinaryStatus::Failed
12439 }
12440 };
12441 cx.emit(LspStoreEvent::LanguageServerUpdate {
12442 // Binary updates are about the binary that might not have any language server id at that point.
12443 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12444 language_server_id: LanguageServerId(0),
12445 name: Some(server_name),
12446 message: proto::update_language_server::Variant::StatusUpdate(
12447 proto::StatusUpdate {
12448 message,
12449 status: Some(proto::status_update::Status::Binary(
12450 binary_status as i32,
12451 )),
12452 },
12453 ),
12454 });
12455 })
12456 .is_err()
12457 {
12458 break;
12459 }
12460 }
12461 })
12462}
12463
12464fn lsp_workspace_diagnostics_refresh(
12465 registration_id: Option<String>,
12466 options: DiagnosticServerCapabilities,
12467 server: Arc<LanguageServer>,
12468 cx: &mut Context<'_, LspStore>,
12469) -> Option<WorkspaceRefreshTask> {
12470 let identifier = diagnostic_identifier(&options)?;
12471
12472 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12473 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12474 refresh_tx.try_send(()).ok();
12475
12476 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12477 let mut attempts = 0;
12478 let max_attempts = 50;
12479 let mut requests = 0;
12480
12481 loop {
12482 let Some(()) = refresh_rx.recv().await else {
12483 return;
12484 };
12485
12486 'request: loop {
12487 requests += 1;
12488 if attempts > max_attempts {
12489 log::error!(
12490 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12491 );
12492 return;
12493 }
12494 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12495 cx.background_executor()
12496 .timer(Duration::from_millis(backoff_millis))
12497 .await;
12498 attempts += 1;
12499
12500 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12501 lsp_store
12502 .all_result_ids(server.server_id())
12503 .into_iter()
12504 .filter_map(|(abs_path, result_id)| {
12505 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12506 Some(lsp::PreviousResultId {
12507 uri,
12508 value: result_id,
12509 })
12510 })
12511 .collect()
12512 }) else {
12513 return;
12514 };
12515
12516 let token = if let Some(identifier) = ®istration_id {
12517 format!(
12518 "workspace/diagnostic/{}/{requests}/id:{identifier}",
12519 server.server_id(),
12520 )
12521 } else {
12522 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12523 };
12524
12525 progress_rx.try_recv().ok();
12526 let timer =
12527 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12528 let progress = pin!(progress_rx.recv().fuse());
12529 let response_result = server
12530 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12531 lsp::WorkspaceDiagnosticParams {
12532 previous_result_ids,
12533 identifier: identifier.clone(),
12534 work_done_progress_params: Default::default(),
12535 partial_result_params: lsp::PartialResultParams {
12536 partial_result_token: Some(lsp::ProgressToken::String(token)),
12537 },
12538 },
12539 select(timer, progress).then(|either| match either {
12540 Either::Left((message, ..)) => ready(message).left_future(),
12541 Either::Right(..) => pending::<String>().right_future(),
12542 }),
12543 )
12544 .await;
12545
12546 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12547 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12548 match response_result {
12549 ConnectionResult::Timeout => {
12550 log::error!("Timeout during workspace diagnostics pull");
12551 continue 'request;
12552 }
12553 ConnectionResult::ConnectionReset => {
12554 log::error!("Server closed a workspace diagnostics pull request");
12555 continue 'request;
12556 }
12557 ConnectionResult::Result(Err(e)) => {
12558 log::error!("Error during workspace diagnostics pull: {e:#}");
12559 break 'request;
12560 }
12561 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12562 attempts = 0;
12563 if lsp_store
12564 .update(cx, |lsp_store, cx| {
12565 lsp_store.apply_workspace_diagnostic_report(
12566 server.server_id(),
12567 pulled_diagnostics,
12568 cx,
12569 )
12570 })
12571 .is_err()
12572 {
12573 return;
12574 }
12575 break 'request;
12576 }
12577 }
12578 }
12579 }
12580 });
12581
12582 Some(WorkspaceRefreshTask {
12583 refresh_tx,
12584 progress_tx,
12585 task: workspace_query_language_server,
12586 })
12587}
12588
12589fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12590 match &options {
12591 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12592 if !diagnostic_options.workspace_diagnostics {
12593 return None;
12594 }
12595 Some(diagnostic_options.identifier.clone())
12596 }
12597 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12598 let diagnostic_options = ®istration_options.diagnostic_options;
12599 if !diagnostic_options.workspace_diagnostics {
12600 return None;
12601 }
12602 Some(diagnostic_options.identifier.clone())
12603 }
12604 }
12605}
12606
12607fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12608 let CompletionSource::BufferWord {
12609 word_range,
12610 resolved,
12611 } = &mut completion.source
12612 else {
12613 return;
12614 };
12615 if *resolved {
12616 return;
12617 }
12618
12619 if completion.new_text
12620 != snapshot
12621 .text_for_range(word_range.clone())
12622 .collect::<String>()
12623 {
12624 return;
12625 }
12626
12627 let mut offset = 0;
12628 for chunk in snapshot.chunks(word_range.clone(), true) {
12629 let end_offset = offset + chunk.text.len();
12630 if let Some(highlight_id) = chunk.syntax_highlight_id {
12631 completion
12632 .label
12633 .runs
12634 .push((offset..end_offset, highlight_id));
12635 }
12636 offset = end_offset;
12637 }
12638 *resolved = true;
12639}
12640
12641impl EventEmitter<LspStoreEvent> for LspStore {}
12642
12643fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12644 hover
12645 .contents
12646 .retain(|hover_block| !hover_block.text.trim().is_empty());
12647 if hover.contents.is_empty() {
12648 None
12649 } else {
12650 Some(hover)
12651 }
12652}
12653
12654async fn populate_labels_for_completions(
12655 new_completions: Vec<CoreCompletion>,
12656 language: Option<Arc<Language>>,
12657 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12658) -> Vec<Completion> {
12659 let lsp_completions = new_completions
12660 .iter()
12661 .filter_map(|new_completion| {
12662 new_completion
12663 .source
12664 .lsp_completion(true)
12665 .map(|lsp_completion| lsp_completion.into_owned())
12666 })
12667 .collect::<Vec<_>>();
12668
12669 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12670 lsp_adapter
12671 .labels_for_completions(&lsp_completions, language)
12672 .await
12673 .log_err()
12674 .unwrap_or_default()
12675 } else {
12676 Vec::new()
12677 }
12678 .into_iter()
12679 .fuse();
12680
12681 let mut completions = Vec::new();
12682 for completion in new_completions {
12683 match completion.source.lsp_completion(true) {
12684 Some(lsp_completion) => {
12685 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12686
12687 let mut label = labels.next().flatten().unwrap_or_else(|| {
12688 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12689 });
12690 ensure_uniform_list_compatible_label(&mut label);
12691 completions.push(Completion {
12692 label,
12693 documentation,
12694 replace_range: completion.replace_range,
12695 new_text: completion.new_text,
12696 insert_text_mode: lsp_completion.insert_text_mode,
12697 source: completion.source,
12698 icon_path: None,
12699 confirm: None,
12700 });
12701 }
12702 None => {
12703 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12704 ensure_uniform_list_compatible_label(&mut label);
12705 completions.push(Completion {
12706 label,
12707 documentation: None,
12708 replace_range: completion.replace_range,
12709 new_text: completion.new_text,
12710 source: completion.source,
12711 insert_text_mode: None,
12712 icon_path: None,
12713 confirm: None,
12714 });
12715 }
12716 }
12717 }
12718 completions
12719}
12720
12721#[derive(Debug)]
12722pub enum LanguageServerToQuery {
12723 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12724 FirstCapable,
12725 /// Query a specific language server.
12726 Other(LanguageServerId),
12727}
12728
12729#[derive(Default)]
12730struct RenamePathsWatchedForServer {
12731 did_rename: Vec<RenameActionPredicate>,
12732 will_rename: Vec<RenameActionPredicate>,
12733}
12734
12735impl RenamePathsWatchedForServer {
12736 fn with_did_rename_patterns(
12737 mut self,
12738 did_rename: Option<&FileOperationRegistrationOptions>,
12739 ) -> Self {
12740 if let Some(did_rename) = did_rename {
12741 self.did_rename = did_rename
12742 .filters
12743 .iter()
12744 .filter_map(|filter| filter.try_into().log_err())
12745 .collect();
12746 }
12747 self
12748 }
12749 fn with_will_rename_patterns(
12750 mut self,
12751 will_rename: Option<&FileOperationRegistrationOptions>,
12752 ) -> Self {
12753 if let Some(will_rename) = will_rename {
12754 self.will_rename = will_rename
12755 .filters
12756 .iter()
12757 .filter_map(|filter| filter.try_into().log_err())
12758 .collect();
12759 }
12760 self
12761 }
12762
12763 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12764 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12765 }
12766 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12767 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12768 }
12769}
12770
12771impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12772 type Error = globset::Error;
12773 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12774 Ok(Self {
12775 kind: ops.pattern.matches.clone(),
12776 glob: GlobBuilder::new(&ops.pattern.glob)
12777 .case_insensitive(
12778 ops.pattern
12779 .options
12780 .as_ref()
12781 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12782 )
12783 .build()?
12784 .compile_matcher(),
12785 })
12786 }
12787}
12788struct RenameActionPredicate {
12789 glob: GlobMatcher,
12790 kind: Option<FileOperationPatternKind>,
12791}
12792
12793impl RenameActionPredicate {
12794 // Returns true if language server should be notified
12795 fn eval(&self, path: &str, is_dir: bool) -> bool {
12796 self.kind.as_ref().is_none_or(|kind| {
12797 let expected_kind = if is_dir {
12798 FileOperationPatternKind::Folder
12799 } else {
12800 FileOperationPatternKind::File
12801 };
12802 kind == &expected_kind
12803 }) && self.glob.is_match(path)
12804 }
12805}
12806
12807#[derive(Default)]
12808struct LanguageServerWatchedPaths {
12809 worktree_paths: HashMap<WorktreeId, GlobSet>,
12810 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12811}
12812
12813#[derive(Default)]
12814struct LanguageServerWatchedPathsBuilder {
12815 worktree_paths: HashMap<WorktreeId, GlobSet>,
12816 abs_paths: HashMap<Arc<Path>, GlobSet>,
12817}
12818
12819impl LanguageServerWatchedPathsBuilder {
12820 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12821 self.worktree_paths.insert(worktree_id, glob_set);
12822 }
12823 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12824 self.abs_paths.insert(path, glob_set);
12825 }
12826 fn build(
12827 self,
12828 fs: Arc<dyn Fs>,
12829 language_server_id: LanguageServerId,
12830 cx: &mut Context<LspStore>,
12831 ) -> LanguageServerWatchedPaths {
12832 let project = cx.weak_entity();
12833
12834 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12835 let abs_paths = self
12836 .abs_paths
12837 .into_iter()
12838 .map(|(abs_path, globset)| {
12839 let task = cx.spawn({
12840 let abs_path = abs_path.clone();
12841 let fs = fs.clone();
12842
12843 let lsp_store = project.clone();
12844 async move |_, cx| {
12845 maybe!(async move {
12846 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12847 while let Some(update) = push_updates.0.next().await {
12848 let action = lsp_store
12849 .update(cx, |this, _| {
12850 let Some(local) = this.as_local() else {
12851 return ControlFlow::Break(());
12852 };
12853 let Some(watcher) = local
12854 .language_server_watched_paths
12855 .get(&language_server_id)
12856 else {
12857 return ControlFlow::Break(());
12858 };
12859 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12860 "Watched abs path is not registered with a watcher",
12861 );
12862 let matching_entries = update
12863 .into_iter()
12864 .filter(|event| globs.is_match(&event.path))
12865 .collect::<Vec<_>>();
12866 this.lsp_notify_abs_paths_changed(
12867 language_server_id,
12868 matching_entries,
12869 );
12870 ControlFlow::Continue(())
12871 })
12872 .ok()?;
12873
12874 if action.is_break() {
12875 break;
12876 }
12877 }
12878 Some(())
12879 })
12880 .await;
12881 }
12882 });
12883 (abs_path, (globset, task))
12884 })
12885 .collect();
12886 LanguageServerWatchedPaths {
12887 worktree_paths: self.worktree_paths,
12888 abs_paths,
12889 }
12890 }
12891}
12892
12893struct LspBufferSnapshot {
12894 version: i32,
12895 snapshot: TextBufferSnapshot,
12896}
12897
12898/// A prompt requested by LSP server.
12899#[derive(Clone, Debug)]
12900pub struct LanguageServerPromptRequest {
12901 pub level: PromptLevel,
12902 pub message: String,
12903 pub actions: Vec<MessageActionItem>,
12904 pub lsp_name: String,
12905 pub(crate) response_channel: Sender<MessageActionItem>,
12906}
12907
12908impl LanguageServerPromptRequest {
12909 pub async fn respond(self, index: usize) -> Option<()> {
12910 if let Some(response) = self.actions.into_iter().nth(index) {
12911 self.response_channel.send(response).await.ok()
12912 } else {
12913 None
12914 }
12915 }
12916}
12917impl PartialEq for LanguageServerPromptRequest {
12918 fn eq(&self, other: &Self) -> bool {
12919 self.message == other.message && self.actions == other.actions
12920 }
12921}
12922
12923#[derive(Clone, Debug, PartialEq)]
12924pub enum LanguageServerLogType {
12925 Log(MessageType),
12926 Trace { verbose_info: Option<String> },
12927 Rpc { received: bool },
12928}
12929
12930impl LanguageServerLogType {
12931 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12932 match self {
12933 Self::Log(log_type) => {
12934 use proto::log_message::LogLevel;
12935 let level = match *log_type {
12936 MessageType::ERROR => LogLevel::Error,
12937 MessageType::WARNING => LogLevel::Warning,
12938 MessageType::INFO => LogLevel::Info,
12939 MessageType::LOG => LogLevel::Log,
12940 other => {
12941 log::warn!("Unknown lsp log message type: {other:?}");
12942 LogLevel::Log
12943 }
12944 };
12945 proto::language_server_log::LogType::Log(proto::LogMessage {
12946 level: level as i32,
12947 })
12948 }
12949 Self::Trace { verbose_info } => {
12950 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12951 verbose_info: verbose_info.to_owned(),
12952 })
12953 }
12954 Self::Rpc { received } => {
12955 let kind = if *received {
12956 proto::rpc_message::Kind::Received
12957 } else {
12958 proto::rpc_message::Kind::Sent
12959 };
12960 let kind = kind as i32;
12961 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12962 }
12963 }
12964 }
12965
12966 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12967 use proto::log_message::LogLevel;
12968 use proto::rpc_message;
12969 match log_type {
12970 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12971 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12972 LogLevel::Error => MessageType::ERROR,
12973 LogLevel::Warning => MessageType::WARNING,
12974 LogLevel::Info => MessageType::INFO,
12975 LogLevel::Log => MessageType::LOG,
12976 },
12977 ),
12978 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12979 verbose_info: trace_message.verbose_info,
12980 },
12981 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12982 received: match rpc_message::Kind::from_i32(message.kind)
12983 .unwrap_or(rpc_message::Kind::Received)
12984 {
12985 rpc_message::Kind::Received => true,
12986 rpc_message::Kind::Sent => false,
12987 },
12988 },
12989 }
12990 }
12991}
12992
12993pub struct WorkspaceRefreshTask {
12994 refresh_tx: mpsc::Sender<()>,
12995 progress_tx: mpsc::Sender<()>,
12996 #[allow(dead_code)]
12997 task: Task<()>,
12998}
12999
13000pub enum LanguageServerState {
13001 Starting {
13002 startup: Task<Option<Arc<LanguageServer>>>,
13003 /// List of language servers that will be added to the workspace once it's initialization completes.
13004 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13005 },
13006
13007 Running {
13008 adapter: Arc<CachedLspAdapter>,
13009 server: Arc<LanguageServer>,
13010 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13011 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13012 },
13013}
13014
13015impl LanguageServerState {
13016 fn add_workspace_folder(&self, uri: Uri) {
13017 match self {
13018 LanguageServerState::Starting {
13019 pending_workspace_folders,
13020 ..
13021 } => {
13022 pending_workspace_folders.lock().insert(uri);
13023 }
13024 LanguageServerState::Running { server, .. } => {
13025 server.add_workspace_folder(uri);
13026 }
13027 }
13028 }
13029 fn _remove_workspace_folder(&self, uri: Uri) {
13030 match self {
13031 LanguageServerState::Starting {
13032 pending_workspace_folders,
13033 ..
13034 } => {
13035 pending_workspace_folders.lock().remove(&uri);
13036 }
13037 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13038 }
13039 }
13040}
13041
13042impl std::fmt::Debug for LanguageServerState {
13043 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13044 match self {
13045 LanguageServerState::Starting { .. } => {
13046 f.debug_struct("LanguageServerState::Starting").finish()
13047 }
13048 LanguageServerState::Running { .. } => {
13049 f.debug_struct("LanguageServerState::Running").finish()
13050 }
13051 }
13052 }
13053}
13054
13055#[derive(Clone, Debug, Serialize)]
13056pub struct LanguageServerProgress {
13057 pub is_disk_based_diagnostics_progress: bool,
13058 pub is_cancellable: bool,
13059 pub title: Option<String>,
13060 pub message: Option<String>,
13061 pub percentage: Option<usize>,
13062 #[serde(skip_serializing)]
13063 pub last_update_at: Instant,
13064}
13065
13066#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13067pub struct DiagnosticSummary {
13068 pub error_count: usize,
13069 pub warning_count: usize,
13070}
13071
13072impl DiagnosticSummary {
13073 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13074 let mut this = Self {
13075 error_count: 0,
13076 warning_count: 0,
13077 };
13078
13079 for entry in diagnostics {
13080 if entry.diagnostic.is_primary {
13081 match entry.diagnostic.severity {
13082 DiagnosticSeverity::ERROR => this.error_count += 1,
13083 DiagnosticSeverity::WARNING => this.warning_count += 1,
13084 _ => {}
13085 }
13086 }
13087 }
13088
13089 this
13090 }
13091
13092 pub fn is_empty(&self) -> bool {
13093 self.error_count == 0 && self.warning_count == 0
13094 }
13095
13096 pub fn to_proto(
13097 self,
13098 language_server_id: LanguageServerId,
13099 path: &RelPath,
13100 ) -> proto::DiagnosticSummary {
13101 proto::DiagnosticSummary {
13102 path: path.to_proto(),
13103 language_server_id: language_server_id.0 as u64,
13104 error_count: self.error_count as u32,
13105 warning_count: self.warning_count as u32,
13106 }
13107 }
13108}
13109
13110#[derive(Clone, Debug)]
13111pub enum CompletionDocumentation {
13112 /// There is no documentation for this completion.
13113 Undocumented,
13114 /// A single line of documentation.
13115 SingleLine(SharedString),
13116 /// Multiple lines of plain text documentation.
13117 MultiLinePlainText(SharedString),
13118 /// Markdown documentation.
13119 MultiLineMarkdown(SharedString),
13120 /// Both single line and multiple lines of plain text documentation.
13121 SingleLineAndMultiLinePlainText {
13122 single_line: SharedString,
13123 plain_text: Option<SharedString>,
13124 },
13125}
13126
13127impl CompletionDocumentation {
13128 #[cfg(any(test, feature = "test-support"))]
13129 pub fn text(&self) -> SharedString {
13130 match self {
13131 CompletionDocumentation::Undocumented => "".into(),
13132 CompletionDocumentation::SingleLine(s) => s.clone(),
13133 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13134 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13135 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13136 single_line.clone()
13137 }
13138 }
13139 }
13140}
13141
13142impl From<lsp::Documentation> for CompletionDocumentation {
13143 fn from(docs: lsp::Documentation) -> Self {
13144 match docs {
13145 lsp::Documentation::String(text) => {
13146 if text.lines().count() <= 1 {
13147 CompletionDocumentation::SingleLine(text.into())
13148 } else {
13149 CompletionDocumentation::MultiLinePlainText(text.into())
13150 }
13151 }
13152
13153 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13154 lsp::MarkupKind::PlainText => {
13155 if value.lines().count() <= 1 {
13156 CompletionDocumentation::SingleLine(value.into())
13157 } else {
13158 CompletionDocumentation::MultiLinePlainText(value.into())
13159 }
13160 }
13161
13162 lsp::MarkupKind::Markdown => {
13163 CompletionDocumentation::MultiLineMarkdown(value.into())
13164 }
13165 },
13166 }
13167 }
13168}
13169
13170pub enum ResolvedHint {
13171 Resolved(InlayHint),
13172 Resolving(Shared<Task<()>>),
13173}
13174
13175fn glob_literal_prefix(glob: &Path) -> PathBuf {
13176 glob.components()
13177 .take_while(|component| match component {
13178 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13179 _ => true,
13180 })
13181 .collect()
13182}
13183
13184pub struct SshLspAdapter {
13185 name: LanguageServerName,
13186 binary: LanguageServerBinary,
13187 initialization_options: Option<String>,
13188 code_action_kinds: Option<Vec<CodeActionKind>>,
13189}
13190
13191impl SshLspAdapter {
13192 pub fn new(
13193 name: LanguageServerName,
13194 binary: LanguageServerBinary,
13195 initialization_options: Option<String>,
13196 code_action_kinds: Option<String>,
13197 ) -> Self {
13198 Self {
13199 name,
13200 binary,
13201 initialization_options,
13202 code_action_kinds: code_action_kinds
13203 .as_ref()
13204 .and_then(|c| serde_json::from_str(c).ok()),
13205 }
13206 }
13207}
13208
13209impl LspInstaller for SshLspAdapter {
13210 type BinaryVersion = ();
13211 async fn check_if_user_installed(
13212 &self,
13213 _: &dyn LspAdapterDelegate,
13214 _: Option<Toolchain>,
13215 _: &AsyncApp,
13216 ) -> Option<LanguageServerBinary> {
13217 Some(self.binary.clone())
13218 }
13219
13220 async fn cached_server_binary(
13221 &self,
13222 _: PathBuf,
13223 _: &dyn LspAdapterDelegate,
13224 ) -> Option<LanguageServerBinary> {
13225 None
13226 }
13227
13228 async fn fetch_latest_server_version(
13229 &self,
13230 _: &dyn LspAdapterDelegate,
13231 _: bool,
13232 _: &mut AsyncApp,
13233 ) -> Result<()> {
13234 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13235 }
13236
13237 async fn fetch_server_binary(
13238 &self,
13239 _: (),
13240 _: PathBuf,
13241 _: &dyn LspAdapterDelegate,
13242 ) -> Result<LanguageServerBinary> {
13243 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13244 }
13245}
13246
13247#[async_trait(?Send)]
13248impl LspAdapter for SshLspAdapter {
13249 fn name(&self) -> LanguageServerName {
13250 self.name.clone()
13251 }
13252
13253 async fn initialization_options(
13254 self: Arc<Self>,
13255 _: &Arc<dyn LspAdapterDelegate>,
13256 ) -> Result<Option<serde_json::Value>> {
13257 let Some(options) = &self.initialization_options else {
13258 return Ok(None);
13259 };
13260 let result = serde_json::from_str(options)?;
13261 Ok(result)
13262 }
13263
13264 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13265 self.code_action_kinds.clone()
13266 }
13267}
13268
13269pub fn language_server_settings<'a>(
13270 delegate: &'a dyn LspAdapterDelegate,
13271 language: &LanguageServerName,
13272 cx: &'a App,
13273) -> Option<&'a LspSettings> {
13274 language_server_settings_for(
13275 SettingsLocation {
13276 worktree_id: delegate.worktree_id(),
13277 path: RelPath::empty(),
13278 },
13279 language,
13280 cx,
13281 )
13282}
13283
13284pub(crate) fn language_server_settings_for<'a>(
13285 location: SettingsLocation<'a>,
13286 language: &LanguageServerName,
13287 cx: &'a App,
13288) -> Option<&'a LspSettings> {
13289 ProjectSettings::get(Some(location), cx).lsp.get(language)
13290}
13291
13292pub struct LocalLspAdapterDelegate {
13293 lsp_store: WeakEntity<LspStore>,
13294 worktree: worktree::Snapshot,
13295 fs: Arc<dyn Fs>,
13296 http_client: Arc<dyn HttpClient>,
13297 language_registry: Arc<LanguageRegistry>,
13298 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13299}
13300
13301impl LocalLspAdapterDelegate {
13302 pub fn new(
13303 language_registry: Arc<LanguageRegistry>,
13304 environment: &Entity<ProjectEnvironment>,
13305 lsp_store: WeakEntity<LspStore>,
13306 worktree: &Entity<Worktree>,
13307 http_client: Arc<dyn HttpClient>,
13308 fs: Arc<dyn Fs>,
13309 cx: &mut App,
13310 ) -> Arc<Self> {
13311 let load_shell_env_task = environment.update(cx, |env, cx| {
13312 env.get_worktree_environment(worktree.clone(), cx)
13313 });
13314
13315 Arc::new(Self {
13316 lsp_store,
13317 worktree: worktree.read(cx).snapshot(),
13318 fs,
13319 http_client,
13320 language_registry,
13321 load_shell_env_task,
13322 })
13323 }
13324
13325 fn from_local_lsp(
13326 local: &LocalLspStore,
13327 worktree: &Entity<Worktree>,
13328 cx: &mut App,
13329 ) -> Arc<Self> {
13330 Self::new(
13331 local.languages.clone(),
13332 &local.environment,
13333 local.weak.clone(),
13334 worktree,
13335 local.http_client.clone(),
13336 local.fs.clone(),
13337 cx,
13338 )
13339 }
13340}
13341
13342#[async_trait]
13343impl LspAdapterDelegate for LocalLspAdapterDelegate {
13344 fn show_notification(&self, message: &str, cx: &mut App) {
13345 self.lsp_store
13346 .update(cx, |_, cx| {
13347 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13348 })
13349 .ok();
13350 }
13351
13352 fn http_client(&self) -> Arc<dyn HttpClient> {
13353 self.http_client.clone()
13354 }
13355
13356 fn worktree_id(&self) -> WorktreeId {
13357 self.worktree.id()
13358 }
13359
13360 fn worktree_root_path(&self) -> &Path {
13361 self.worktree.abs_path().as_ref()
13362 }
13363
13364 async fn shell_env(&self) -> HashMap<String, String> {
13365 let task = self.load_shell_env_task.clone();
13366 task.await.unwrap_or_default()
13367 }
13368
13369 async fn npm_package_installed_version(
13370 &self,
13371 package_name: &str,
13372 ) -> Result<Option<(PathBuf, String)>> {
13373 let local_package_directory = self.worktree_root_path();
13374 let node_modules_directory = local_package_directory.join("node_modules");
13375
13376 if let Some(version) =
13377 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13378 {
13379 return Ok(Some((node_modules_directory, version)));
13380 }
13381 let Some(npm) = self.which("npm".as_ref()).await else {
13382 log::warn!(
13383 "Failed to find npm executable for {:?}",
13384 local_package_directory
13385 );
13386 return Ok(None);
13387 };
13388
13389 let env = self.shell_env().await;
13390 let output = util::command::new_smol_command(&npm)
13391 .args(["root", "-g"])
13392 .envs(env)
13393 .current_dir(local_package_directory)
13394 .output()
13395 .await?;
13396 let global_node_modules =
13397 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13398
13399 if let Some(version) =
13400 read_package_installed_version(global_node_modules.clone(), package_name).await?
13401 {
13402 return Ok(Some((global_node_modules, version)));
13403 }
13404 return Ok(None);
13405 }
13406
13407 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13408 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13409 if self.fs.is_file(&worktree_abs_path).await {
13410 worktree_abs_path.pop();
13411 }
13412
13413 let env = self.shell_env().await;
13414
13415 let shell_path = env.get("PATH").cloned();
13416
13417 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13418 }
13419
13420 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13421 let mut working_dir = self.worktree_root_path().to_path_buf();
13422 if self.fs.is_file(&working_dir).await {
13423 working_dir.pop();
13424 }
13425 let output = util::command::new_smol_command(&command.path)
13426 .args(command.arguments)
13427 .envs(command.env.clone().unwrap_or_default())
13428 .current_dir(working_dir)
13429 .output()
13430 .await?;
13431
13432 anyhow::ensure!(
13433 output.status.success(),
13434 "{}, stdout: {:?}, stderr: {:?}",
13435 output.status,
13436 String::from_utf8_lossy(&output.stdout),
13437 String::from_utf8_lossy(&output.stderr)
13438 );
13439 Ok(())
13440 }
13441
13442 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13443 self.language_registry
13444 .update_lsp_binary_status(server_name, status);
13445 }
13446
13447 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13448 self.language_registry
13449 .all_lsp_adapters()
13450 .into_iter()
13451 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13452 .collect()
13453 }
13454
13455 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13456 let dir = self.language_registry.language_server_download_dir(name)?;
13457
13458 if !dir.exists() {
13459 smol::fs::create_dir_all(&dir)
13460 .await
13461 .context("failed to create container directory")
13462 .log_err()?;
13463 }
13464
13465 Some(dir)
13466 }
13467
13468 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13469 let entry = self
13470 .worktree
13471 .entry_for_path(path)
13472 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13473 let abs_path = self.worktree.absolutize(&entry.path);
13474 self.fs.load(&abs_path).await
13475 }
13476}
13477
13478async fn populate_labels_for_symbols(
13479 symbols: Vec<CoreSymbol>,
13480 language_registry: &Arc<LanguageRegistry>,
13481 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13482 output: &mut Vec<Symbol>,
13483) {
13484 #[allow(clippy::mutable_key_type)]
13485 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13486
13487 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13488 for symbol in symbols {
13489 let Some(file_name) = symbol.path.file_name() else {
13490 continue;
13491 };
13492 let language = language_registry
13493 .load_language_for_file_path(Path::new(file_name))
13494 .await
13495 .ok()
13496 .or_else(|| {
13497 unknown_paths.insert(file_name.into());
13498 None
13499 });
13500 symbols_by_language
13501 .entry(language)
13502 .or_default()
13503 .push(symbol);
13504 }
13505
13506 for unknown_path in unknown_paths {
13507 log::info!("no language found for symbol in file {unknown_path:?}");
13508 }
13509
13510 let mut label_params = Vec::new();
13511 for (language, mut symbols) in symbols_by_language {
13512 label_params.clear();
13513 label_params.extend(
13514 symbols
13515 .iter_mut()
13516 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13517 );
13518
13519 let mut labels = Vec::new();
13520 if let Some(language) = language {
13521 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13522 language_registry
13523 .lsp_adapters(&language.name())
13524 .first()
13525 .cloned()
13526 });
13527 if let Some(lsp_adapter) = lsp_adapter {
13528 labels = lsp_adapter
13529 .labels_for_symbols(&label_params, &language)
13530 .await
13531 .log_err()
13532 .unwrap_or_default();
13533 }
13534 }
13535
13536 for ((symbol, (name, _)), label) in symbols
13537 .into_iter()
13538 .zip(label_params.drain(..))
13539 .zip(labels.into_iter().chain(iter::repeat(None)))
13540 {
13541 output.push(Symbol {
13542 language_server_name: symbol.language_server_name,
13543 source_worktree_id: symbol.source_worktree_id,
13544 source_language_server_id: symbol.source_language_server_id,
13545 path: symbol.path,
13546 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13547 name,
13548 kind: symbol.kind,
13549 range: symbol.range,
13550 });
13551 }
13552 }
13553}
13554
13555fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13556 match server.capabilities().text_document_sync.as_ref()? {
13557 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13558 // Server wants didSave but didn't specify includeText.
13559 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13560 // Server doesn't want didSave at all.
13561 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13562 // Server provided SaveOptions.
13563 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13564 Some(save_options.include_text.unwrap_or(false))
13565 }
13566 },
13567 // We do not have any save info. Kind affects didChange only.
13568 lsp::TextDocumentSyncCapability::Kind(_) => None,
13569 }
13570}
13571
13572/// Completion items are displayed in a `UniformList`.
13573/// Usually, those items are single-line strings, but in LSP responses,
13574/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13575/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13576/// 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,
13577/// breaking the completions menu presentation.
13578///
13579/// 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.
13580fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13581 let mut new_text = String::with_capacity(label.text.len());
13582 let mut offset_map = vec![0; label.text.len() + 1];
13583 let mut last_char_was_space = false;
13584 let mut new_idx = 0;
13585 let chars = label.text.char_indices().fuse();
13586 let mut newlines_removed = false;
13587
13588 for (idx, c) in chars {
13589 offset_map[idx] = new_idx;
13590
13591 match c {
13592 '\n' if last_char_was_space => {
13593 newlines_removed = true;
13594 }
13595 '\t' | ' ' if last_char_was_space => {}
13596 '\n' if !last_char_was_space => {
13597 new_text.push(' ');
13598 new_idx += 1;
13599 last_char_was_space = true;
13600 newlines_removed = true;
13601 }
13602 ' ' | '\t' => {
13603 new_text.push(' ');
13604 new_idx += 1;
13605 last_char_was_space = true;
13606 }
13607 _ => {
13608 new_text.push(c);
13609 new_idx += c.len_utf8();
13610 last_char_was_space = false;
13611 }
13612 }
13613 }
13614 offset_map[label.text.len()] = new_idx;
13615
13616 // Only modify the label if newlines were removed.
13617 if !newlines_removed {
13618 return;
13619 }
13620
13621 let last_index = new_idx;
13622 let mut run_ranges_errors = Vec::new();
13623 label.runs.retain_mut(|(range, _)| {
13624 match offset_map.get(range.start) {
13625 Some(&start) => range.start = start,
13626 None => {
13627 run_ranges_errors.push(range.clone());
13628 return false;
13629 }
13630 }
13631
13632 match offset_map.get(range.end) {
13633 Some(&end) => range.end = end,
13634 None => {
13635 run_ranges_errors.push(range.clone());
13636 range.end = last_index;
13637 }
13638 }
13639 true
13640 });
13641 if !run_ranges_errors.is_empty() {
13642 log::error!(
13643 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13644 label.text
13645 );
13646 }
13647
13648 let mut wrong_filter_range = None;
13649 if label.filter_range == (0..label.text.len()) {
13650 label.filter_range = 0..new_text.len();
13651 } else {
13652 let mut original_filter_range = Some(label.filter_range.clone());
13653 match offset_map.get(label.filter_range.start) {
13654 Some(&start) => label.filter_range.start = start,
13655 None => {
13656 wrong_filter_range = original_filter_range.take();
13657 label.filter_range.start = last_index;
13658 }
13659 }
13660
13661 match offset_map.get(label.filter_range.end) {
13662 Some(&end) => label.filter_range.end = end,
13663 None => {
13664 wrong_filter_range = original_filter_range.take();
13665 label.filter_range.end = last_index;
13666 }
13667 }
13668 }
13669 if let Some(wrong_filter_range) = wrong_filter_range {
13670 log::error!(
13671 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13672 label.text
13673 );
13674 }
13675
13676 label.text = new_text;
13677}
13678
13679#[cfg(test)]
13680mod tests {
13681 use language::HighlightId;
13682
13683 use super::*;
13684
13685 #[test]
13686 fn test_glob_literal_prefix() {
13687 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13688 assert_eq!(
13689 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13690 Path::new("node_modules")
13691 );
13692 assert_eq!(
13693 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13694 Path::new("foo")
13695 );
13696 assert_eq!(
13697 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13698 Path::new("foo/bar/baz.js")
13699 );
13700
13701 #[cfg(target_os = "windows")]
13702 {
13703 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13704 assert_eq!(
13705 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13706 Path::new("node_modules")
13707 );
13708 assert_eq!(
13709 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13710 Path::new("foo")
13711 );
13712 assert_eq!(
13713 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13714 Path::new("foo/bar/baz.js")
13715 );
13716 }
13717 }
13718
13719 #[test]
13720 fn test_multi_len_chars_normalization() {
13721 let mut label = CodeLabel::new(
13722 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13723 0..6,
13724 vec![(0..6, HighlightId(1))],
13725 );
13726 ensure_uniform_list_compatible_label(&mut label);
13727 assert_eq!(
13728 label,
13729 CodeLabel::new(
13730 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13731 0..6,
13732 vec![(0..6, HighlightId(1))],
13733 )
13734 );
13735 }
13736}