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