1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticServerCapabilities,
79 DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit,
80 FileOperationFilter, FileOperationPatternKind, FileOperationRegistrationOptions, FileRename,
81 FileSystemWatcher, LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary,
82 LanguageServerBinaryOptions, LanguageServerId, LanguageServerName, LanguageServerSelector,
83 LspRequestFuture, MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
84 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
85 WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum FormatTrigger {
144 Save,
145 Manual,
146}
147
148pub enum LspFormatTarget {
149 Buffers,
150 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
151}
152
153pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
154
155impl FormatTrigger {
156 fn from_proto(value: i32) -> FormatTrigger {
157 match value {
158 0 => FormatTrigger::Save,
159 1 => FormatTrigger::Manual,
160 _ => FormatTrigger::Save,
161 }
162 }
163}
164
165#[derive(Clone)]
166struct UnifiedLanguageServer {
167 id: LanguageServerId,
168 project_roots: HashSet<Arc<RelPath>>,
169}
170
171#[derive(Clone, Hash, PartialEq, Eq)]
172struct LanguageServerSeed {
173 worktree_id: WorktreeId,
174 name: LanguageServerName,
175 toolchain: Option<Toolchain>,
176 settings: Arc<LspSettings>,
177}
178
179#[derive(Debug)]
180pub struct DocumentDiagnosticsUpdate<'a, D> {
181 pub diagnostics: D,
182 pub result_id: Option<String>,
183 pub server_id: LanguageServerId,
184 pub disk_based_sources: Cow<'a, [String]>,
185}
186
187pub struct DocumentDiagnostics {
188 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
189 document_abs_path: PathBuf,
190 version: Option<i32>,
191}
192
193#[derive(Default)]
194struct DynamicRegistrations {
195 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
196 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
197}
198
199pub struct LocalLspStore {
200 weak: WeakEntity<LspStore>,
201 worktree_store: Entity<WorktreeStore>,
202 toolchain_store: Entity<LocalToolchainStore>,
203 http_client: Arc<dyn HttpClient>,
204 environment: Entity<ProjectEnvironment>,
205 fs: Arc<dyn Fs>,
206 languages: Arc<LanguageRegistry>,
207 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
208 yarn: Entity<YarnPathStore>,
209 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
210 buffers_being_formatted: HashSet<BufferId>,
211 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
212 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
213 watched_manifest_filenames: HashSet<ManifestName>,
214 language_server_paths_watched_for_rename:
215 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
216 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
217 supplementary_language_servers:
218 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
219 prettier_store: Entity<PrettierStore>,
220 next_diagnostic_group_id: usize,
221 diagnostics: HashMap<
222 WorktreeId,
223 HashMap<
224 Arc<RelPath>,
225 Vec<(
226 LanguageServerId,
227 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
228 )>,
229 >,
230 >,
231 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
232 _subscription: gpui::Subscription,
233 lsp_tree: LanguageServerTree,
234 registered_buffers: HashMap<BufferId, usize>,
235 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
236 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
237}
238
239impl LocalLspStore {
240 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
241 pub fn running_language_server_for_id(
242 &self,
243 id: LanguageServerId,
244 ) -> Option<&Arc<LanguageServer>> {
245 let language_server_state = self.language_servers.get(&id)?;
246
247 match language_server_state {
248 LanguageServerState::Running { server, .. } => Some(server),
249 LanguageServerState::Starting { .. } => None,
250 }
251 }
252
253 fn get_or_insert_language_server(
254 &mut self,
255 worktree_handle: &Entity<Worktree>,
256 delegate: Arc<LocalLspAdapterDelegate>,
257 disposition: &Arc<LaunchDisposition>,
258 language_name: &LanguageName,
259 cx: &mut App,
260 ) -> LanguageServerId {
261 let key = LanguageServerSeed {
262 worktree_id: worktree_handle.read(cx).id(),
263 name: disposition.server_name.clone(),
264 settings: disposition.settings.clone(),
265 toolchain: disposition.toolchain.clone(),
266 };
267 if let Some(state) = self.language_server_ids.get_mut(&key) {
268 state.project_roots.insert(disposition.path.path.clone());
269 state.id
270 } else {
271 let adapter = self
272 .languages
273 .lsp_adapters(language_name)
274 .into_iter()
275 .find(|adapter| adapter.name() == disposition.server_name)
276 .expect("To find LSP adapter");
277 let new_language_server_id = self.start_language_server(
278 worktree_handle,
279 delegate,
280 adapter,
281 disposition.settings.clone(),
282 key.clone(),
283 cx,
284 );
285 if let Some(state) = self.language_server_ids.get_mut(&key) {
286 state.project_roots.insert(disposition.path.path.clone());
287 } else {
288 debug_assert!(
289 false,
290 "Expected `start_language_server` to ensure that `key` exists in a map"
291 );
292 }
293 new_language_server_id
294 }
295 }
296
297 fn start_language_server(
298 &mut self,
299 worktree_handle: &Entity<Worktree>,
300 delegate: Arc<LocalLspAdapterDelegate>,
301 adapter: Arc<CachedLspAdapter>,
302 settings: Arc<LspSettings>,
303 key: LanguageServerSeed,
304 cx: &mut App,
305 ) -> LanguageServerId {
306 let worktree = worktree_handle.read(cx);
307
308 let root_path = worktree.abs_path();
309 let toolchain = key.toolchain.clone();
310 let override_options = settings.initialization_options.clone();
311
312 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
313
314 let server_id = self.languages.next_language_server_id();
315 log::trace!(
316 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
317 adapter.name.0
318 );
319
320 let binary = self.get_language_server_binary(
321 adapter.clone(),
322 settings,
323 toolchain.clone(),
324 delegate.clone(),
325 true,
326 cx,
327 );
328 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
329
330 let pending_server = cx.spawn({
331 let adapter = adapter.clone();
332 let server_name = adapter.name.clone();
333 let stderr_capture = stderr_capture.clone();
334 #[cfg(any(test, feature = "test-support"))]
335 let lsp_store = self.weak.clone();
336 let pending_workspace_folders = pending_workspace_folders.clone();
337 async move |cx| {
338 let binary = binary.await?;
339 #[cfg(any(test, feature = "test-support"))]
340 if let Some(server) = lsp_store
341 .update(&mut cx.clone(), |this, cx| {
342 this.languages.create_fake_language_server(
343 server_id,
344 &server_name,
345 binary.clone(),
346 &mut cx.to_async(),
347 )
348 })
349 .ok()
350 .flatten()
351 {
352 return Ok(server);
353 }
354
355 let code_action_kinds = adapter.code_action_kinds();
356 lsp::LanguageServer::new(
357 stderr_capture,
358 server_id,
359 server_name,
360 binary,
361 &root_path,
362 code_action_kinds,
363 Some(pending_workspace_folders),
364 cx,
365 )
366 }
367 });
368
369 let startup = {
370 let server_name = adapter.name.0.clone();
371 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
372 let key = key.clone();
373 let adapter = adapter.clone();
374 let lsp_store = self.weak.clone();
375 let pending_workspace_folders = pending_workspace_folders.clone();
376
377 let pull_diagnostics = ProjectSettings::get_global(cx)
378 .diagnostics
379 .lsp_pull_diagnostics
380 .enabled;
381 cx.spawn(async move |cx| {
382 let result = async {
383 let language_server = pending_server.await?;
384
385 let workspace_config = Self::workspace_configuration_for_adapter(
386 adapter.adapter.clone(),
387 &delegate,
388 toolchain,
389 cx,
390 )
391 .await?;
392
393 let mut initialization_options = Self::initialization_options_for_adapter(
394 adapter.adapter.clone(),
395 &delegate,
396 )
397 .await?;
398
399 match (&mut initialization_options, override_options) {
400 (Some(initialization_options), Some(override_options)) => {
401 merge_json_value_into(override_options, initialization_options);
402 }
403 (None, override_options) => initialization_options = override_options,
404 _ => {}
405 }
406
407 let initialization_params = cx.update(|cx| {
408 let mut params =
409 language_server.default_initialize_params(pull_diagnostics, cx);
410 params.initialization_options = initialization_options;
411 adapter.adapter.prepare_initialize_params(params, cx)
412 })??;
413
414 Self::setup_lsp_messages(
415 lsp_store.clone(),
416 &language_server,
417 delegate.clone(),
418 adapter.clone(),
419 );
420
421 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
422 settings: workspace_config,
423 };
424 let language_server = cx
425 .update(|cx| {
426 language_server.initialize(
427 initialization_params,
428 Arc::new(did_change_configuration_params.clone()),
429 cx,
430 )
431 })?
432 .await
433 .inspect_err(|_| {
434 if let Some(lsp_store) = lsp_store.upgrade() {
435 lsp_store
436 .update(cx, |lsp_store, cx| {
437 lsp_store.cleanup_lsp_data(server_id);
438 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
439 })
440 .ok();
441 }
442 })?;
443
444 language_server.notify::<lsp::notification::DidChangeConfiguration>(
445 did_change_configuration_params,
446 )?;
447
448 anyhow::Ok(language_server)
449 }
450 .await;
451
452 match result {
453 Ok(server) => {
454 lsp_store
455 .update(cx, |lsp_store, cx| {
456 lsp_store.insert_newly_running_language_server(
457 adapter,
458 server.clone(),
459 server_id,
460 key,
461 pending_workspace_folders,
462 cx,
463 );
464 })
465 .ok();
466 stderr_capture.lock().take();
467 Some(server)
468 }
469
470 Err(err) => {
471 let log = stderr_capture.lock().take().unwrap_or_default();
472 delegate.update_status(
473 adapter.name(),
474 BinaryStatus::Failed {
475 error: if log.is_empty() {
476 format!("{err:#}")
477 } else {
478 format!("{err:#}\n-- stderr --\n{log}")
479 },
480 },
481 );
482 log::error!("Failed to start language server {server_name:?}: {err:?}");
483 if !log.is_empty() {
484 log::error!("server stderr: {log}");
485 }
486 None
487 }
488 }
489 })
490 };
491 let state = LanguageServerState::Starting {
492 startup,
493 pending_workspace_folders,
494 };
495
496 self.languages
497 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
498
499 self.language_servers.insert(server_id, state);
500 self.language_server_ids
501 .entry(key)
502 .or_insert(UnifiedLanguageServer {
503 id: server_id,
504 project_roots: Default::default(),
505 });
506 server_id
507 }
508
509 fn get_language_server_binary(
510 &self,
511 adapter: Arc<CachedLspAdapter>,
512 settings: Arc<LspSettings>,
513 toolchain: Option<Toolchain>,
514 delegate: Arc<dyn LspAdapterDelegate>,
515 allow_binary_download: bool,
516 cx: &mut App,
517 ) -> Task<Result<LanguageServerBinary>> {
518 if let Some(settings) = settings.binary.as_ref()
519 && settings.path.is_some()
520 {
521 let settings = settings.clone();
522
523 return cx.background_spawn(async move {
524 let mut env = delegate.shell_env().await;
525 env.extend(settings.env.unwrap_or_default());
526
527 Ok(LanguageServerBinary {
528 path: PathBuf::from(&settings.path.unwrap()),
529 env: Some(env),
530 arguments: settings
531 .arguments
532 .unwrap_or_default()
533 .iter()
534 .map(Into::into)
535 .collect(),
536 })
537 });
538 }
539 let lsp_binary_options = LanguageServerBinaryOptions {
540 allow_path_lookup: !settings
541 .binary
542 .as_ref()
543 .and_then(|b| b.ignore_system_version)
544 .unwrap_or_default(),
545 allow_binary_download,
546 pre_release: settings
547 .fetch
548 .as_ref()
549 .and_then(|f| f.pre_release)
550 .unwrap_or(false),
551 };
552
553 cx.spawn(async move |cx| {
554 let binary_result = adapter
555 .clone()
556 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
557 .await;
558
559 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
560
561 let mut binary = binary_result?;
562 let mut shell_env = delegate.shell_env().await;
563
564 shell_env.extend(binary.env.unwrap_or_default());
565
566 if let Some(settings) = settings.binary.as_ref() {
567 if let Some(arguments) = &settings.arguments {
568 binary.arguments = arguments.iter().map(Into::into).collect();
569 }
570 if let Some(env) = &settings.env {
571 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
572 }
573 }
574
575 binary.env = Some(shell_env);
576 Ok(binary)
577 })
578 }
579
580 fn setup_lsp_messages(
581 lsp_store: WeakEntity<LspStore>,
582 language_server: &LanguageServer,
583 delegate: Arc<dyn LspAdapterDelegate>,
584 adapter: Arc<CachedLspAdapter>,
585 ) {
586 let name = language_server.name();
587 let server_id = language_server.server_id();
588 language_server
589 .on_notification::<lsp::notification::PublishDiagnostics, _>({
590 let adapter = adapter.clone();
591 let this = lsp_store.clone();
592 move |mut params, cx| {
593 let adapter = adapter.clone();
594 if let Some(this) = this.upgrade() {
595 this.update(cx, |this, cx| {
596 {
597 let buffer = params
598 .uri
599 .to_file_path()
600 .map(|file_path| this.get_buffer(&file_path, cx))
601 .ok()
602 .flatten();
603 adapter.process_diagnostics(&mut params, server_id, buffer);
604 }
605
606 this.merge_lsp_diagnostics(
607 DiagnosticSourceKind::Pushed,
608 vec![DocumentDiagnosticsUpdate {
609 server_id,
610 diagnostics: params,
611 result_id: None,
612 disk_based_sources: Cow::Borrowed(
613 &adapter.disk_based_diagnostic_sources,
614 ),
615 }],
616 |_, diagnostic, cx| match diagnostic.source_kind {
617 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
618 adapter.retain_old_diagnostic(diagnostic, cx)
619 }
620 DiagnosticSourceKind::Pulled => true,
621 },
622 cx,
623 )
624 .log_err();
625 })
626 .ok();
627 }
628 }
629 })
630 .detach();
631 language_server
632 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
633 let adapter = adapter.adapter.clone();
634 let delegate = delegate.clone();
635 let this = lsp_store.clone();
636 move |params, cx| {
637 let adapter = adapter.clone();
638 let delegate = delegate.clone();
639 let this = this.clone();
640 let mut cx = cx.clone();
641 async move {
642 let toolchain_for_id = this
643 .update(&mut cx, |this, _| {
644 this.as_local()?.language_server_ids.iter().find_map(
645 |(seed, value)| {
646 (value.id == server_id).then(|| seed.toolchain.clone())
647 },
648 )
649 })?
650 .context("Expected the LSP store to be in a local mode")?;
651 let workspace_config = Self::workspace_configuration_for_adapter(
652 adapter.clone(),
653 &delegate,
654 toolchain_for_id,
655 &mut cx,
656 )
657 .await?;
658
659 Ok(params
660 .items
661 .into_iter()
662 .map(|item| {
663 if let Some(section) = &item.section {
664 workspace_config
665 .get(section)
666 .cloned()
667 .unwrap_or(serde_json::Value::Null)
668 } else {
669 workspace_config.clone()
670 }
671 })
672 .collect())
673 }
674 }
675 })
676 .detach();
677
678 language_server
679 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
680 let this = lsp_store.clone();
681 move |_, cx| {
682 let this = this.clone();
683 let cx = cx.clone();
684 async move {
685 let Some(server) =
686 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
687 else {
688 return Ok(None);
689 };
690 let root = server.workspace_folders();
691 Ok(Some(
692 root.into_iter()
693 .map(|uri| WorkspaceFolder {
694 uri,
695 name: Default::default(),
696 })
697 .collect(),
698 ))
699 }
700 }
701 })
702 .detach();
703 // Even though we don't have handling for these requests, respond to them to
704 // avoid stalling any language server like `gopls` which waits for a response
705 // to these requests when initializing.
706 language_server
707 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
708 let this = lsp_store.clone();
709 move |params, cx| {
710 let this = this.clone();
711 let mut cx = cx.clone();
712 async move {
713 this.update(&mut cx, |this, _| {
714 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
715 && let lsp::NumberOrString::String(token) = params.token
716 {
717 status.progress_tokens.insert(token);
718 }
719 })?;
720
721 Ok(())
722 }
723 }
724 })
725 .detach();
726
727 language_server
728 .on_request::<lsp::request::RegisterCapability, _, _>({
729 let lsp_store = lsp_store.clone();
730 move |params, cx| {
731 let lsp_store = lsp_store.clone();
732 let mut cx = cx.clone();
733 async move {
734 lsp_store
735 .update(&mut cx, |lsp_store, cx| {
736 if lsp_store.as_local().is_some() {
737 match lsp_store
738 .register_server_capabilities(server_id, params, cx)
739 {
740 Ok(()) => {}
741 Err(e) => {
742 log::error!(
743 "Failed to register server capabilities: {e:#}"
744 );
745 }
746 };
747 }
748 })
749 .ok();
750 Ok(())
751 }
752 }
753 })
754 .detach();
755
756 language_server
757 .on_request::<lsp::request::UnregisterCapability, _, _>({
758 let lsp_store = lsp_store.clone();
759 move |params, cx| {
760 let lsp_store = lsp_store.clone();
761 let mut cx = cx.clone();
762 async move {
763 lsp_store
764 .update(&mut cx, |lsp_store, cx| {
765 if lsp_store.as_local().is_some() {
766 match lsp_store
767 .unregister_server_capabilities(server_id, params, cx)
768 {
769 Ok(()) => {}
770 Err(e) => {
771 log::error!(
772 "Failed to unregister server capabilities: {e:#}"
773 );
774 }
775 }
776 }
777 })
778 .ok();
779 Ok(())
780 }
781 }
782 })
783 .detach();
784
785 language_server
786 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
787 let this = lsp_store.clone();
788 move |params, cx| {
789 let mut cx = cx.clone();
790 let this = this.clone();
791 async move {
792 LocalLspStore::on_lsp_workspace_edit(
793 this.clone(),
794 params,
795 server_id,
796 &mut cx,
797 )
798 .await
799 }
800 }
801 })
802 .detach();
803
804 language_server
805 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
806 let lsp_store = lsp_store.clone();
807 move |(), cx| {
808 let this = lsp_store.clone();
809 let mut cx = cx.clone();
810 async move {
811 this.update(&mut cx, |lsp_store, cx| {
812 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
813 lsp_store
814 .downstream_client
815 .as_ref()
816 .map(|(client, project_id)| {
817 client.send(proto::RefreshInlayHints {
818 project_id: *project_id,
819 server_id: server_id.to_proto(),
820 })
821 })
822 })?
823 .transpose()?;
824 Ok(())
825 }
826 }
827 })
828 .detach();
829
830 language_server
831 .on_request::<lsp::request::CodeLensRefresh, _, _>({
832 let this = lsp_store.clone();
833 move |(), cx| {
834 let this = this.clone();
835 let mut cx = cx.clone();
836 async move {
837 this.update(&mut cx, |this, cx| {
838 cx.emit(LspStoreEvent::RefreshCodeLens);
839 this.downstream_client.as_ref().map(|(client, project_id)| {
840 client.send(proto::RefreshCodeLens {
841 project_id: *project_id,
842 })
843 })
844 })?
845 .transpose()?;
846 Ok(())
847 }
848 }
849 })
850 .detach();
851
852 language_server
853 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
854 let this = lsp_store.clone();
855 move |(), cx| {
856 let this = this.clone();
857 let mut cx = cx.clone();
858 async move {
859 this.update(&mut cx, |lsp_store, _| {
860 lsp_store.pull_workspace_diagnostics(server_id);
861 lsp_store
862 .downstream_client
863 .as_ref()
864 .map(|(client, project_id)| {
865 client.send(proto::PullWorkspaceDiagnostics {
866 project_id: *project_id,
867 server_id: server_id.to_proto(),
868 })
869 })
870 })?
871 .transpose()?;
872 Ok(())
873 }
874 }
875 })
876 .detach();
877
878 language_server
879 .on_request::<lsp::request::ShowMessageRequest, _, _>({
880 let this = lsp_store.clone();
881 let name = name.to_string();
882 move |params, cx| {
883 let this = this.clone();
884 let name = name.to_string();
885 let mut cx = cx.clone();
886 async move {
887 let actions = params.actions.unwrap_or_default();
888 let (tx, rx) = smol::channel::bounded(1);
889 let request = LanguageServerPromptRequest {
890 level: match params.typ {
891 lsp::MessageType::ERROR => PromptLevel::Critical,
892 lsp::MessageType::WARNING => PromptLevel::Warning,
893 _ => PromptLevel::Info,
894 },
895 message: params.message,
896 actions,
897 response_channel: tx,
898 lsp_name: name.clone(),
899 };
900
901 let did_update = this
902 .update(&mut cx, |_, cx| {
903 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
904 })
905 .is_ok();
906 if did_update {
907 let response = rx.recv().await.ok();
908 Ok(response)
909 } else {
910 Ok(None)
911 }
912 }
913 }
914 })
915 .detach();
916 language_server
917 .on_notification::<lsp::notification::ShowMessage, _>({
918 let this = lsp_store.clone();
919 let name = name.to_string();
920 move |params, cx| {
921 let this = this.clone();
922 let name = name.to_string();
923 let mut cx = cx.clone();
924
925 let (tx, _) = smol::channel::bounded(1);
926 let request = LanguageServerPromptRequest {
927 level: match params.typ {
928 lsp::MessageType::ERROR => PromptLevel::Critical,
929 lsp::MessageType::WARNING => PromptLevel::Warning,
930 _ => PromptLevel::Info,
931 },
932 message: params.message,
933 actions: vec![],
934 response_channel: tx,
935 lsp_name: name,
936 };
937
938 let _ = this.update(&mut cx, |_, cx| {
939 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
940 });
941 }
942 })
943 .detach();
944
945 let disk_based_diagnostics_progress_token =
946 adapter.disk_based_diagnostics_progress_token.clone();
947
948 language_server
949 .on_notification::<lsp::notification::Progress, _>({
950 let this = lsp_store.clone();
951 move |params, cx| {
952 if let Some(this) = this.upgrade() {
953 this.update(cx, |this, cx| {
954 this.on_lsp_progress(
955 params,
956 server_id,
957 disk_based_diagnostics_progress_token.clone(),
958 cx,
959 );
960 })
961 .ok();
962 }
963 }
964 })
965 .detach();
966
967 language_server
968 .on_notification::<lsp::notification::LogMessage, _>({
969 let this = lsp_store.clone();
970 move |params, cx| {
971 if let Some(this) = this.upgrade() {
972 this.update(cx, |_, cx| {
973 cx.emit(LspStoreEvent::LanguageServerLog(
974 server_id,
975 LanguageServerLogType::Log(params.typ),
976 params.message,
977 ));
978 })
979 .ok();
980 }
981 }
982 })
983 .detach();
984
985 language_server
986 .on_notification::<lsp::notification::LogTrace, _>({
987 let this = lsp_store.clone();
988 move |params, cx| {
989 let mut cx = cx.clone();
990 if let Some(this) = this.upgrade() {
991 this.update(&mut cx, |_, cx| {
992 cx.emit(LspStoreEvent::LanguageServerLog(
993 server_id,
994 LanguageServerLogType::Trace {
995 verbose_info: params.verbose,
996 },
997 params.message,
998 ));
999 })
1000 .ok();
1001 }
1002 }
1003 })
1004 .detach();
1005
1006 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1007 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1008 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1009 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1010 }
1011
1012 fn shutdown_language_servers_on_quit(
1013 &mut self,
1014 _: &mut Context<LspStore>,
1015 ) -> impl Future<Output = ()> + use<> {
1016 let shutdown_futures = self
1017 .language_servers
1018 .drain()
1019 .map(|(_, server_state)| Self::shutdown_server(server_state))
1020 .collect::<Vec<_>>();
1021
1022 async move {
1023 join_all(shutdown_futures).await;
1024 }
1025 }
1026
1027 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1028 match server_state {
1029 LanguageServerState::Running { server, .. } => {
1030 if let Some(shutdown) = server.shutdown() {
1031 shutdown.await;
1032 }
1033 }
1034 LanguageServerState::Starting { startup, .. } => {
1035 if let Some(server) = startup.await
1036 && let Some(shutdown) = server.shutdown()
1037 {
1038 shutdown.await;
1039 }
1040 }
1041 }
1042 Ok(())
1043 }
1044
1045 fn language_servers_for_worktree(
1046 &self,
1047 worktree_id: WorktreeId,
1048 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1049 self.language_server_ids
1050 .iter()
1051 .filter_map(move |(seed, state)| {
1052 if seed.worktree_id != worktree_id {
1053 return None;
1054 }
1055
1056 if let Some(LanguageServerState::Running { server, .. }) =
1057 self.language_servers.get(&state.id)
1058 {
1059 Some(server)
1060 } else {
1061 None
1062 }
1063 })
1064 }
1065
1066 fn language_server_ids_for_project_path(
1067 &self,
1068 project_path: ProjectPath,
1069 language: &Language,
1070 cx: &mut App,
1071 ) -> Vec<LanguageServerId> {
1072 let Some(worktree) = self
1073 .worktree_store
1074 .read(cx)
1075 .worktree_for_id(project_path.worktree_id, cx)
1076 else {
1077 return Vec::new();
1078 };
1079 let delegate: Arc<dyn ManifestDelegate> =
1080 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1081
1082 self.lsp_tree
1083 .get(
1084 project_path,
1085 language.name(),
1086 language.manifest(),
1087 &delegate,
1088 cx,
1089 )
1090 .collect::<Vec<_>>()
1091 }
1092
1093 fn language_server_ids_for_buffer(
1094 &self,
1095 buffer: &Buffer,
1096 cx: &mut App,
1097 ) -> Vec<LanguageServerId> {
1098 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1099 let worktree_id = file.worktree_id(cx);
1100
1101 let path: Arc<RelPath> = file
1102 .path()
1103 .parent()
1104 .map(Arc::from)
1105 .unwrap_or_else(|| file.path().clone());
1106 let worktree_path = ProjectPath { worktree_id, path };
1107 self.language_server_ids_for_project_path(worktree_path, language, cx)
1108 } else {
1109 Vec::new()
1110 }
1111 }
1112
1113 fn language_servers_for_buffer<'a>(
1114 &'a self,
1115 buffer: &'a Buffer,
1116 cx: &'a mut App,
1117 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1118 self.language_server_ids_for_buffer(buffer, cx)
1119 .into_iter()
1120 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1121 LanguageServerState::Running {
1122 adapter, server, ..
1123 } => Some((adapter, server)),
1124 _ => None,
1125 })
1126 }
1127
1128 async fn execute_code_action_kind_locally(
1129 lsp_store: WeakEntity<LspStore>,
1130 mut buffers: Vec<Entity<Buffer>>,
1131 kind: CodeActionKind,
1132 push_to_history: bool,
1133 cx: &mut AsyncApp,
1134 ) -> anyhow::Result<ProjectTransaction> {
1135 // Do not allow multiple concurrent code actions requests for the
1136 // same buffer.
1137 lsp_store.update(cx, |this, cx| {
1138 let this = this.as_local_mut().unwrap();
1139 buffers.retain(|buffer| {
1140 this.buffers_being_formatted
1141 .insert(buffer.read(cx).remote_id())
1142 });
1143 })?;
1144 let _cleanup = defer({
1145 let this = lsp_store.clone();
1146 let mut cx = cx.clone();
1147 let buffers = &buffers;
1148 move || {
1149 this.update(&mut cx, |this, cx| {
1150 let this = this.as_local_mut().unwrap();
1151 for buffer in buffers {
1152 this.buffers_being_formatted
1153 .remove(&buffer.read(cx).remote_id());
1154 }
1155 })
1156 .ok();
1157 }
1158 });
1159 let mut project_transaction = ProjectTransaction::default();
1160
1161 for buffer in &buffers {
1162 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1163 buffer.update(cx, |buffer, cx| {
1164 lsp_store
1165 .as_local()
1166 .unwrap()
1167 .language_servers_for_buffer(buffer, cx)
1168 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1169 .collect::<Vec<_>>()
1170 })
1171 })?;
1172 for (_, language_server) in adapters_and_servers.iter() {
1173 let actions = Self::get_server_code_actions_from_action_kinds(
1174 &lsp_store,
1175 language_server.server_id(),
1176 vec![kind.clone()],
1177 buffer,
1178 cx,
1179 )
1180 .await?;
1181 Self::execute_code_actions_on_server(
1182 &lsp_store,
1183 language_server,
1184 actions,
1185 push_to_history,
1186 &mut project_transaction,
1187 cx,
1188 )
1189 .await?;
1190 }
1191 }
1192 Ok(project_transaction)
1193 }
1194
1195 async fn format_locally(
1196 lsp_store: WeakEntity<LspStore>,
1197 mut buffers: Vec<FormattableBuffer>,
1198 push_to_history: bool,
1199 trigger: FormatTrigger,
1200 logger: zlog::Logger,
1201 cx: &mut AsyncApp,
1202 ) -> anyhow::Result<ProjectTransaction> {
1203 // Do not allow multiple concurrent formatting requests for the
1204 // same buffer.
1205 lsp_store.update(cx, |this, cx| {
1206 let this = this.as_local_mut().unwrap();
1207 buffers.retain(|buffer| {
1208 this.buffers_being_formatted
1209 .insert(buffer.handle.read(cx).remote_id())
1210 });
1211 })?;
1212
1213 let _cleanup = defer({
1214 let this = lsp_store.clone();
1215 let mut cx = cx.clone();
1216 let buffers = &buffers;
1217 move || {
1218 this.update(&mut cx, |this, cx| {
1219 let this = this.as_local_mut().unwrap();
1220 for buffer in buffers {
1221 this.buffers_being_formatted
1222 .remove(&buffer.handle.read(cx).remote_id());
1223 }
1224 })
1225 .ok();
1226 }
1227 });
1228
1229 let mut project_transaction = ProjectTransaction::default();
1230
1231 for buffer in &buffers {
1232 zlog::debug!(
1233 logger =>
1234 "formatting buffer '{:?}'",
1235 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1236 );
1237 // Create an empty transaction to hold all of the formatting edits.
1238 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1239 // ensure no transactions created while formatting are
1240 // grouped with the previous transaction in the history
1241 // based on the transaction group interval
1242 buffer.finalize_last_transaction();
1243 buffer
1244 .start_transaction()
1245 .context("transaction already open")?;
1246 buffer.end_transaction(cx);
1247 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1248 buffer.finalize_last_transaction();
1249 anyhow::Ok(transaction_id)
1250 })??;
1251
1252 let result = Self::format_buffer_locally(
1253 lsp_store.clone(),
1254 buffer,
1255 formatting_transaction_id,
1256 trigger,
1257 logger,
1258 cx,
1259 )
1260 .await;
1261
1262 buffer.handle.update(cx, |buffer, cx| {
1263 let Some(formatting_transaction) =
1264 buffer.get_transaction(formatting_transaction_id).cloned()
1265 else {
1266 zlog::warn!(logger => "no formatting transaction");
1267 return;
1268 };
1269 if formatting_transaction.edit_ids.is_empty() {
1270 zlog::debug!(logger => "no changes made while formatting");
1271 buffer.forget_transaction(formatting_transaction_id);
1272 return;
1273 }
1274 if !push_to_history {
1275 zlog::trace!(logger => "forgetting format transaction");
1276 buffer.forget_transaction(formatting_transaction.id);
1277 }
1278 project_transaction
1279 .0
1280 .insert(cx.entity(), formatting_transaction);
1281 })?;
1282
1283 result?;
1284 }
1285
1286 Ok(project_transaction)
1287 }
1288
1289 async fn format_buffer_locally(
1290 lsp_store: WeakEntity<LspStore>,
1291 buffer: &FormattableBuffer,
1292 formatting_transaction_id: clock::Lamport,
1293 trigger: FormatTrigger,
1294 logger: zlog::Logger,
1295 cx: &mut AsyncApp,
1296 ) -> Result<()> {
1297 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1298 buffer.handle.update(cx, |buffer, cx| {
1299 let adapters_and_servers = lsp_store
1300 .as_local()
1301 .unwrap()
1302 .language_servers_for_buffer(buffer, cx)
1303 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1304 .collect::<Vec<_>>();
1305 let settings =
1306 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1307 .into_owned();
1308 (adapters_and_servers, settings)
1309 })
1310 })?;
1311
1312 /// Apply edits to the buffer that will become part of the formatting transaction.
1313 /// Fails if the buffer has been edited since the start of that transaction.
1314 fn extend_formatting_transaction(
1315 buffer: &FormattableBuffer,
1316 formatting_transaction_id: text::TransactionId,
1317 cx: &mut AsyncApp,
1318 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1319 ) -> anyhow::Result<()> {
1320 buffer.handle.update(cx, |buffer, cx| {
1321 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1322 if last_transaction_id != Some(formatting_transaction_id) {
1323 anyhow::bail!("Buffer edited while formatting. Aborting")
1324 }
1325 buffer.start_transaction();
1326 operation(buffer, cx);
1327 if let Some(transaction_id) = buffer.end_transaction(cx) {
1328 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1329 }
1330 Ok(())
1331 })?
1332 }
1333
1334 // handle whitespace formatting
1335 if settings.remove_trailing_whitespace_on_save {
1336 zlog::trace!(logger => "removing trailing whitespace");
1337 let diff = buffer
1338 .handle
1339 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1340 .await;
1341 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1342 buffer.apply_diff(diff, cx);
1343 })?;
1344 }
1345
1346 if settings.ensure_final_newline_on_save {
1347 zlog::trace!(logger => "ensuring final newline");
1348 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1349 buffer.ensure_final_newline(cx);
1350 })?;
1351 }
1352
1353 // Formatter for `code_actions_on_format` that runs before
1354 // the rest of the formatters
1355 let mut code_actions_on_format_formatters = None;
1356 let should_run_code_actions_on_format = !matches!(
1357 (trigger, &settings.format_on_save),
1358 (FormatTrigger::Save, &FormatOnSave::Off)
1359 );
1360 if should_run_code_actions_on_format {
1361 let have_code_actions_to_run_on_format = settings
1362 .code_actions_on_format
1363 .values()
1364 .any(|enabled| *enabled);
1365 if have_code_actions_to_run_on_format {
1366 zlog::trace!(logger => "going to run code actions on format");
1367 code_actions_on_format_formatters = Some(
1368 settings
1369 .code_actions_on_format
1370 .iter()
1371 .filter_map(|(action, enabled)| enabled.then_some(action))
1372 .cloned()
1373 .map(Formatter::CodeAction)
1374 .collect::<Vec<_>>(),
1375 );
1376 }
1377 }
1378
1379 let formatters = match (trigger, &settings.format_on_save) {
1380 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1381 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1382 settings.formatter.as_ref()
1383 }
1384 };
1385
1386 let formatters = code_actions_on_format_formatters
1387 .iter()
1388 .flatten()
1389 .chain(formatters);
1390
1391 for formatter in formatters {
1392 let formatter = if formatter == &Formatter::Auto {
1393 if settings.prettier.allowed {
1394 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1395 &Formatter::Prettier
1396 } else {
1397 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1398 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1399 }
1400 } else {
1401 formatter
1402 };
1403 match formatter {
1404 Formatter::Auto => unreachable!("Auto resolved above"),
1405 Formatter::Prettier => {
1406 let logger = zlog::scoped!(logger => "prettier");
1407 zlog::trace!(logger => "formatting");
1408 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1409
1410 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1411 lsp_store.prettier_store().unwrap().downgrade()
1412 })?;
1413 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1414 .await
1415 .transpose()?;
1416 let Some(diff) = diff else {
1417 zlog::trace!(logger => "No changes");
1418 continue;
1419 };
1420
1421 extend_formatting_transaction(
1422 buffer,
1423 formatting_transaction_id,
1424 cx,
1425 |buffer, cx| {
1426 buffer.apply_diff(diff, cx);
1427 },
1428 )?;
1429 }
1430 Formatter::External { command, arguments } => {
1431 let logger = zlog::scoped!(logger => "command");
1432 zlog::trace!(logger => "formatting");
1433 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1434
1435 let diff = Self::format_via_external_command(
1436 buffer,
1437 command.as_ref(),
1438 arguments.as_deref(),
1439 cx,
1440 )
1441 .await
1442 .with_context(|| {
1443 format!("Failed to format buffer via external command: {}", command)
1444 })?;
1445 let Some(diff) = diff else {
1446 zlog::trace!(logger => "No changes");
1447 continue;
1448 };
1449
1450 extend_formatting_transaction(
1451 buffer,
1452 formatting_transaction_id,
1453 cx,
1454 |buffer, cx| {
1455 buffer.apply_diff(diff, cx);
1456 },
1457 )?;
1458 }
1459 Formatter::LanguageServer(specifier) => {
1460 let logger = zlog::scoped!(logger => "language-server");
1461 zlog::trace!(logger => "formatting");
1462 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1463
1464 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1465 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1466 continue;
1467 };
1468
1469 let language_server = match specifier {
1470 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1471 adapters_and_servers.iter().find_map(|(adapter, server)| {
1472 if adapter.name.0.as_ref() == name {
1473 Some(server.clone())
1474 } else {
1475 None
1476 }
1477 })
1478 }
1479 settings::LanguageServerFormatterSpecifier::Current => {
1480 adapters_and_servers.first().map(|e| e.1.clone())
1481 }
1482 };
1483
1484 let Some(language_server) = language_server else {
1485 log::debug!(
1486 "No language server found to format buffer '{:?}'. Skipping",
1487 buffer_path_abs.as_path().to_string_lossy()
1488 );
1489 continue;
1490 };
1491
1492 zlog::trace!(
1493 logger =>
1494 "Formatting buffer '{:?}' using language server '{:?}'",
1495 buffer_path_abs.as_path().to_string_lossy(),
1496 language_server.name()
1497 );
1498
1499 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1500 zlog::trace!(logger => "formatting ranges");
1501 Self::format_ranges_via_lsp(
1502 &lsp_store,
1503 &buffer.handle,
1504 ranges,
1505 buffer_path_abs,
1506 &language_server,
1507 &settings,
1508 cx,
1509 )
1510 .await
1511 .context("Failed to format ranges via language server")?
1512 } else {
1513 zlog::trace!(logger => "formatting full");
1514 Self::format_via_lsp(
1515 &lsp_store,
1516 &buffer.handle,
1517 buffer_path_abs,
1518 &language_server,
1519 &settings,
1520 cx,
1521 )
1522 .await
1523 .context("failed to format via language server")?
1524 };
1525
1526 if edits.is_empty() {
1527 zlog::trace!(logger => "No changes");
1528 continue;
1529 }
1530 extend_formatting_transaction(
1531 buffer,
1532 formatting_transaction_id,
1533 cx,
1534 |buffer, cx| {
1535 buffer.edit(edits, None, cx);
1536 },
1537 )?;
1538 }
1539 Formatter::CodeAction(code_action_name) => {
1540 let logger = zlog::scoped!(logger => "code-actions");
1541 zlog::trace!(logger => "formatting");
1542 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1543
1544 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1545 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1546 continue;
1547 };
1548
1549 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1550 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1551
1552 let mut actions_and_servers = Vec::new();
1553
1554 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1555 let actions_result = Self::get_server_code_actions_from_action_kinds(
1556 &lsp_store,
1557 language_server.server_id(),
1558 vec![code_action_kind.clone()],
1559 &buffer.handle,
1560 cx,
1561 )
1562 .await
1563 .with_context(|| {
1564 format!(
1565 "Failed to resolve code action {:?} with language server {}",
1566 code_action_kind,
1567 language_server.name()
1568 )
1569 });
1570 let Ok(actions) = actions_result else {
1571 // note: it may be better to set result to the error and break formatters here
1572 // but for now we try to execute the actions that we can resolve and skip the rest
1573 zlog::error!(
1574 logger =>
1575 "Failed to resolve code action {:?} with language server {}",
1576 code_action_kind,
1577 language_server.name()
1578 );
1579 continue;
1580 };
1581 for action in actions {
1582 actions_and_servers.push((action, index));
1583 }
1584 }
1585
1586 if actions_and_servers.is_empty() {
1587 zlog::warn!(logger => "No code actions were resolved, continuing");
1588 continue;
1589 }
1590
1591 'actions: for (mut action, server_index) in actions_and_servers {
1592 let server = &adapters_and_servers[server_index].1;
1593
1594 let describe_code_action = |action: &CodeAction| {
1595 format!(
1596 "code action '{}' with title \"{}\" on server {}",
1597 action
1598 .lsp_action
1599 .action_kind()
1600 .unwrap_or("unknown".into())
1601 .as_str(),
1602 action.lsp_action.title(),
1603 server.name(),
1604 )
1605 };
1606
1607 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1608
1609 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1610 zlog::error!(
1611 logger =>
1612 "Failed to resolve {}. Error: {}",
1613 describe_code_action(&action),
1614 err
1615 );
1616 continue;
1617 }
1618
1619 if let Some(edit) = action.lsp_action.edit().cloned() {
1620 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1621 // but filters out and logs warnings for code actions that require unreasonably
1622 // difficult handling on our part, such as:
1623 // - applying edits that call commands
1624 // which can result in arbitrary workspace edits being sent from the server that
1625 // have no way of being tied back to the command that initiated them (i.e. we
1626 // can't know which edits are part of the format request, or if the server is done sending
1627 // actions in response to the command)
1628 // - actions that create/delete/modify/rename files other than the one we are formatting
1629 // as we then would need to handle such changes correctly in the local history as well
1630 // as the remote history through the ProjectTransaction
1631 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1632 // Supporting these actions is not impossible, but not supported as of yet.
1633 if edit.changes.is_none() && edit.document_changes.is_none() {
1634 zlog::trace!(
1635 logger =>
1636 "No changes for code action. Skipping {}",
1637 describe_code_action(&action),
1638 );
1639 continue;
1640 }
1641
1642 let mut operations = Vec::new();
1643 if let Some(document_changes) = edit.document_changes {
1644 match document_changes {
1645 lsp::DocumentChanges::Edits(edits) => operations.extend(
1646 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1647 ),
1648 lsp::DocumentChanges::Operations(ops) => operations = ops,
1649 }
1650 } else if let Some(changes) = edit.changes {
1651 operations.extend(changes.into_iter().map(|(uri, edits)| {
1652 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1653 text_document:
1654 lsp::OptionalVersionedTextDocumentIdentifier {
1655 uri,
1656 version: None,
1657 },
1658 edits: edits.into_iter().map(Edit::Plain).collect(),
1659 })
1660 }));
1661 }
1662
1663 let mut edits = Vec::with_capacity(operations.len());
1664
1665 if operations.is_empty() {
1666 zlog::trace!(
1667 logger =>
1668 "No changes for code action. Skipping {}",
1669 describe_code_action(&action),
1670 );
1671 continue;
1672 }
1673 for operation in operations {
1674 let op = match operation {
1675 lsp::DocumentChangeOperation::Edit(op) => op,
1676 lsp::DocumentChangeOperation::Op(_) => {
1677 zlog::warn!(
1678 logger =>
1679 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1680 describe_code_action(&action),
1681 );
1682 continue 'actions;
1683 }
1684 };
1685 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1686 zlog::warn!(
1687 logger =>
1688 "Failed to convert URI '{:?}' to file path. Skipping {}",
1689 &op.text_document.uri,
1690 describe_code_action(&action),
1691 );
1692 continue 'actions;
1693 };
1694 if &file_path != buffer_path_abs {
1695 zlog::warn!(
1696 logger =>
1697 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1698 file_path,
1699 buffer_path_abs,
1700 describe_code_action(&action),
1701 );
1702 continue 'actions;
1703 }
1704
1705 let mut lsp_edits = Vec::new();
1706 for edit in op.edits {
1707 match edit {
1708 Edit::Plain(edit) => {
1709 if !lsp_edits.contains(&edit) {
1710 lsp_edits.push(edit);
1711 }
1712 }
1713 Edit::Annotated(edit) => {
1714 if !lsp_edits.contains(&edit.text_edit) {
1715 lsp_edits.push(edit.text_edit);
1716 }
1717 }
1718 Edit::Snippet(_) => {
1719 zlog::warn!(
1720 logger =>
1721 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1722 describe_code_action(&action),
1723 );
1724 continue 'actions;
1725 }
1726 }
1727 }
1728 let edits_result = lsp_store
1729 .update(cx, |lsp_store, cx| {
1730 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1731 &buffer.handle,
1732 lsp_edits,
1733 server.server_id(),
1734 op.text_document.version,
1735 cx,
1736 )
1737 })?
1738 .await;
1739 let Ok(resolved_edits) = edits_result else {
1740 zlog::warn!(
1741 logger =>
1742 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1743 buffer_path_abs.as_path(),
1744 describe_code_action(&action),
1745 );
1746 continue 'actions;
1747 };
1748 edits.extend(resolved_edits);
1749 }
1750
1751 if edits.is_empty() {
1752 zlog::warn!(logger => "No edits resolved from LSP");
1753 continue;
1754 }
1755
1756 extend_formatting_transaction(
1757 buffer,
1758 formatting_transaction_id,
1759 cx,
1760 |buffer, cx| {
1761 zlog::info!(
1762 "Applying edits {edits:?}. Content: {:?}",
1763 buffer.text()
1764 );
1765 buffer.edit(edits, None, cx);
1766 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1767 },
1768 )?;
1769 }
1770
1771 if let Some(command) = action.lsp_action.command() {
1772 zlog::warn!(
1773 logger =>
1774 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1775 &command.command,
1776 );
1777
1778 // bail early if command is invalid
1779 let server_capabilities = server.capabilities();
1780 let available_commands = server_capabilities
1781 .execute_command_provider
1782 .as_ref()
1783 .map(|options| options.commands.as_slice())
1784 .unwrap_or_default();
1785 if !available_commands.contains(&command.command) {
1786 zlog::warn!(
1787 logger =>
1788 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1789 command.command,
1790 server.name(),
1791 );
1792 continue;
1793 }
1794
1795 // noop so we just ensure buffer hasn't been edited since resolving code actions
1796 extend_formatting_transaction(
1797 buffer,
1798 formatting_transaction_id,
1799 cx,
1800 |_, _| {},
1801 )?;
1802 zlog::info!(logger => "Executing command {}", &command.command);
1803
1804 lsp_store.update(cx, |this, _| {
1805 this.as_local_mut()
1806 .unwrap()
1807 .last_workspace_edits_by_language_server
1808 .remove(&server.server_id());
1809 })?;
1810
1811 let execute_command_result = server
1812 .request::<lsp::request::ExecuteCommand>(
1813 lsp::ExecuteCommandParams {
1814 command: command.command.clone(),
1815 arguments: command.arguments.clone().unwrap_or_default(),
1816 ..Default::default()
1817 },
1818 )
1819 .await
1820 .into_response();
1821
1822 if execute_command_result.is_err() {
1823 zlog::error!(
1824 logger =>
1825 "Failed to execute command '{}' as part of {}",
1826 &command.command,
1827 describe_code_action(&action),
1828 );
1829 continue 'actions;
1830 }
1831
1832 let mut project_transaction_command =
1833 lsp_store.update(cx, |this, _| {
1834 this.as_local_mut()
1835 .unwrap()
1836 .last_workspace_edits_by_language_server
1837 .remove(&server.server_id())
1838 .unwrap_or_default()
1839 })?;
1840
1841 if let Some(transaction) =
1842 project_transaction_command.0.remove(&buffer.handle)
1843 {
1844 zlog::trace!(
1845 logger =>
1846 "Successfully captured {} edits that resulted from command {}",
1847 transaction.edit_ids.len(),
1848 &command.command,
1849 );
1850 let transaction_id_project_transaction = transaction.id;
1851 buffer.handle.update(cx, |buffer, _| {
1852 // it may have been removed from history if push_to_history was
1853 // false in deserialize_workspace_edit. If so push it so we
1854 // can merge it with the format transaction
1855 // and pop the combined transaction off the history stack
1856 // later if push_to_history is false
1857 if buffer.get_transaction(transaction.id).is_none() {
1858 buffer.push_transaction(transaction, Instant::now());
1859 }
1860 buffer.merge_transactions(
1861 transaction_id_project_transaction,
1862 formatting_transaction_id,
1863 );
1864 })?;
1865 }
1866
1867 if !project_transaction_command.0.is_empty() {
1868 let mut extra_buffers = String::new();
1869 for buffer in project_transaction_command.0.keys() {
1870 buffer
1871 .read_with(cx, |b, cx| {
1872 if let Some(path) = b.project_path(cx) {
1873 if !extra_buffers.is_empty() {
1874 extra_buffers.push_str(", ");
1875 }
1876 extra_buffers.push_str(path.path.as_unix_str());
1877 }
1878 })
1879 .ok();
1880 }
1881 zlog::warn!(
1882 logger =>
1883 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1884 &command.command,
1885 extra_buffers,
1886 );
1887 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1888 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1889 // add it so it's included, and merge it into the format transaction when its created later
1890 }
1891 }
1892 }
1893 }
1894 }
1895 }
1896
1897 Ok(())
1898 }
1899
1900 pub async fn format_ranges_via_lsp(
1901 this: &WeakEntity<LspStore>,
1902 buffer_handle: &Entity<Buffer>,
1903 ranges: &[Range<Anchor>],
1904 abs_path: &Path,
1905 language_server: &Arc<LanguageServer>,
1906 settings: &LanguageSettings,
1907 cx: &mut AsyncApp,
1908 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1909 let capabilities = &language_server.capabilities();
1910 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1911 if range_formatting_provider == Some(&OneOf::Left(false)) {
1912 anyhow::bail!(
1913 "{} language server does not support range formatting",
1914 language_server.name()
1915 );
1916 }
1917
1918 let uri = file_path_to_lsp_url(abs_path)?;
1919 let text_document = lsp::TextDocumentIdentifier::new(uri);
1920
1921 let lsp_edits = {
1922 let mut lsp_ranges = Vec::new();
1923 this.update(cx, |_this, cx| {
1924 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1925 // not have been sent to the language server. This seems like a fairly systemic
1926 // issue, though, the resolution probably is not specific to formatting.
1927 //
1928 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1929 // LSP.
1930 let snapshot = buffer_handle.read(cx).snapshot();
1931 for range in ranges {
1932 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1933 }
1934 anyhow::Ok(())
1935 })??;
1936
1937 let mut edits = None;
1938 for range in lsp_ranges {
1939 if let Some(mut edit) = language_server
1940 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1941 text_document: text_document.clone(),
1942 range,
1943 options: lsp_command::lsp_formatting_options(settings),
1944 work_done_progress_params: Default::default(),
1945 })
1946 .await
1947 .into_response()?
1948 {
1949 edits.get_or_insert_with(Vec::new).append(&mut edit);
1950 }
1951 }
1952 edits
1953 };
1954
1955 if let Some(lsp_edits) = lsp_edits {
1956 this.update(cx, |this, cx| {
1957 this.as_local_mut().unwrap().edits_from_lsp(
1958 buffer_handle,
1959 lsp_edits,
1960 language_server.server_id(),
1961 None,
1962 cx,
1963 )
1964 })?
1965 .await
1966 } else {
1967 Ok(Vec::with_capacity(0))
1968 }
1969 }
1970
1971 async fn format_via_lsp(
1972 this: &WeakEntity<LspStore>,
1973 buffer: &Entity<Buffer>,
1974 abs_path: &Path,
1975 language_server: &Arc<LanguageServer>,
1976 settings: &LanguageSettings,
1977 cx: &mut AsyncApp,
1978 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1979 let logger = zlog::scoped!("lsp_format");
1980 zlog::info!(logger => "Formatting via LSP");
1981
1982 let uri = file_path_to_lsp_url(abs_path)?;
1983 let text_document = lsp::TextDocumentIdentifier::new(uri);
1984 let capabilities = &language_server.capabilities();
1985
1986 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1987 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1988
1989 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1990 let _timer = zlog::time!(logger => "format-full");
1991 language_server
1992 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1993 text_document,
1994 options: lsp_command::lsp_formatting_options(settings),
1995 work_done_progress_params: Default::default(),
1996 })
1997 .await
1998 .into_response()?
1999 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2000 let _timer = zlog::time!(logger => "format-range");
2001 let buffer_start = lsp::Position::new(0, 0);
2002 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2003 language_server
2004 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2005 text_document: text_document.clone(),
2006 range: lsp::Range::new(buffer_start, buffer_end),
2007 options: lsp_command::lsp_formatting_options(settings),
2008 work_done_progress_params: Default::default(),
2009 })
2010 .await
2011 .into_response()?
2012 } else {
2013 None
2014 };
2015
2016 if let Some(lsp_edits) = lsp_edits {
2017 this.update(cx, |this, cx| {
2018 this.as_local_mut().unwrap().edits_from_lsp(
2019 buffer,
2020 lsp_edits,
2021 language_server.server_id(),
2022 None,
2023 cx,
2024 )
2025 })?
2026 .await
2027 } else {
2028 Ok(Vec::with_capacity(0))
2029 }
2030 }
2031
2032 async fn format_via_external_command(
2033 buffer: &FormattableBuffer,
2034 command: &str,
2035 arguments: Option<&[String]>,
2036 cx: &mut AsyncApp,
2037 ) -> Result<Option<Diff>> {
2038 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2039 let file = File::from_dyn(buffer.file())?;
2040 let worktree = file.worktree.read(cx);
2041 let mut worktree_path = worktree.abs_path().to_path_buf();
2042 if worktree.root_entry()?.is_file() {
2043 worktree_path.pop();
2044 }
2045 Some(worktree_path)
2046 })?;
2047
2048 let mut child = util::command::new_smol_command(command);
2049
2050 if let Some(buffer_env) = buffer.env.as_ref() {
2051 child.envs(buffer_env);
2052 }
2053
2054 if let Some(working_dir_path) = working_dir_path {
2055 child.current_dir(working_dir_path);
2056 }
2057
2058 if let Some(arguments) = arguments {
2059 child.args(arguments.iter().map(|arg| {
2060 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2061 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2062 } else {
2063 arg.replace("{buffer_path}", "Untitled")
2064 }
2065 }));
2066 }
2067
2068 let mut child = child
2069 .stdin(smol::process::Stdio::piped())
2070 .stdout(smol::process::Stdio::piped())
2071 .stderr(smol::process::Stdio::piped())
2072 .spawn()?;
2073
2074 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2075 let text = buffer
2076 .handle
2077 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2078 for chunk in text.chunks() {
2079 stdin.write_all(chunk.as_bytes()).await?;
2080 }
2081 stdin.flush().await?;
2082
2083 let output = child.output().await?;
2084 anyhow::ensure!(
2085 output.status.success(),
2086 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2087 output.status.code(),
2088 String::from_utf8_lossy(&output.stdout),
2089 String::from_utf8_lossy(&output.stderr),
2090 );
2091
2092 let stdout = String::from_utf8(output.stdout)?;
2093 Ok(Some(
2094 buffer
2095 .handle
2096 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2097 .await,
2098 ))
2099 }
2100
2101 async fn try_resolve_code_action(
2102 lang_server: &LanguageServer,
2103 action: &mut CodeAction,
2104 ) -> anyhow::Result<()> {
2105 match &mut action.lsp_action {
2106 LspAction::Action(lsp_action) => {
2107 if !action.resolved
2108 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2109 && lsp_action.data.is_some()
2110 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2111 {
2112 *lsp_action = Box::new(
2113 lang_server
2114 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2115 .await
2116 .into_response()?,
2117 );
2118 }
2119 }
2120 LspAction::CodeLens(lens) => {
2121 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2122 *lens = lang_server
2123 .request::<lsp::request::CodeLensResolve>(lens.clone())
2124 .await
2125 .into_response()?;
2126 }
2127 }
2128 LspAction::Command(_) => {}
2129 }
2130
2131 action.resolved = true;
2132 anyhow::Ok(())
2133 }
2134
2135 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2136 let buffer = buffer_handle.read(cx);
2137
2138 let file = buffer.file().cloned();
2139
2140 let Some(file) = File::from_dyn(file.as_ref()) else {
2141 return;
2142 };
2143 if !file.is_local() {
2144 return;
2145 }
2146 let path = ProjectPath::from_file(file, cx);
2147 let worktree_id = file.worktree_id(cx);
2148 let language = buffer.language().cloned();
2149
2150 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2151 for (server_id, diagnostics) in
2152 diagnostics.get(file.path()).cloned().unwrap_or_default()
2153 {
2154 self.update_buffer_diagnostics(
2155 buffer_handle,
2156 server_id,
2157 None,
2158 None,
2159 diagnostics,
2160 Vec::new(),
2161 cx,
2162 )
2163 .log_err();
2164 }
2165 }
2166 let Some(language) = language else {
2167 return;
2168 };
2169 let Some(snapshot) = self
2170 .worktree_store
2171 .read(cx)
2172 .worktree_for_id(worktree_id, cx)
2173 .map(|worktree| worktree.read(cx).snapshot())
2174 else {
2175 return;
2176 };
2177 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2178
2179 for server_id in
2180 self.lsp_tree
2181 .get(path, language.name(), language.manifest(), &delegate, cx)
2182 {
2183 let server = self
2184 .language_servers
2185 .get(&server_id)
2186 .and_then(|server_state| {
2187 if let LanguageServerState::Running { server, .. } = server_state {
2188 Some(server.clone())
2189 } else {
2190 None
2191 }
2192 });
2193 let server = match server {
2194 Some(server) => server,
2195 None => continue,
2196 };
2197
2198 buffer_handle.update(cx, |buffer, cx| {
2199 buffer.set_completion_triggers(
2200 server.server_id(),
2201 server
2202 .capabilities()
2203 .completion_provider
2204 .as_ref()
2205 .and_then(|provider| {
2206 provider
2207 .trigger_characters
2208 .as_ref()
2209 .map(|characters| characters.iter().cloned().collect())
2210 })
2211 .unwrap_or_default(),
2212 cx,
2213 );
2214 });
2215 }
2216 }
2217
2218 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2219 buffer.update(cx, |buffer, cx| {
2220 let Some(language) = buffer.language() else {
2221 return;
2222 };
2223 let path = ProjectPath {
2224 worktree_id: old_file.worktree_id(cx),
2225 path: old_file.path.clone(),
2226 };
2227 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2228 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2229 buffer.set_completion_triggers(server_id, Default::default(), cx);
2230 }
2231 });
2232 }
2233
2234 fn update_buffer_diagnostics(
2235 &mut self,
2236 buffer: &Entity<Buffer>,
2237 server_id: LanguageServerId,
2238 result_id: Option<String>,
2239 version: Option<i32>,
2240 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2241 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2242 cx: &mut Context<LspStore>,
2243 ) -> Result<()> {
2244 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2245 Ordering::Equal
2246 .then_with(|| b.is_primary.cmp(&a.is_primary))
2247 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2248 .then_with(|| a.severity.cmp(&b.severity))
2249 .then_with(|| a.message.cmp(&b.message))
2250 }
2251
2252 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2253 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2254 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2255
2256 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2257 Ordering::Equal
2258 .then_with(|| a.range.start.cmp(&b.range.start))
2259 .then_with(|| b.range.end.cmp(&a.range.end))
2260 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2261 });
2262
2263 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2264
2265 let edits_since_save = std::cell::LazyCell::new(|| {
2266 let saved_version = buffer.read(cx).saved_version();
2267 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2268 });
2269
2270 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2271
2272 for (new_diagnostic, entry) in diagnostics {
2273 let start;
2274 let end;
2275 if new_diagnostic && entry.diagnostic.is_disk_based {
2276 // Some diagnostics are based on files on disk instead of buffers'
2277 // current contents. Adjust these diagnostics' ranges to reflect
2278 // any unsaved edits.
2279 // Do not alter the reused ones though, as their coordinates were stored as anchors
2280 // and were properly adjusted on reuse.
2281 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2282 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2283 } else {
2284 start = entry.range.start;
2285 end = entry.range.end;
2286 }
2287
2288 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2289 ..snapshot.clip_point_utf16(end, Bias::Right);
2290
2291 // Expand empty ranges by one codepoint
2292 if range.start == range.end {
2293 // This will be go to the next boundary when being clipped
2294 range.end.column += 1;
2295 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2296 if range.start == range.end && range.end.column > 0 {
2297 range.start.column -= 1;
2298 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2299 }
2300 }
2301
2302 sanitized_diagnostics.push(DiagnosticEntry {
2303 range,
2304 diagnostic: entry.diagnostic,
2305 });
2306 }
2307 drop(edits_since_save);
2308
2309 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2310 buffer.update(cx, |buffer, cx| {
2311 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2312 self.buffer_pull_diagnostics_result_ids
2313 .entry(server_id)
2314 .or_default()
2315 .insert(abs_path, result_id);
2316 }
2317
2318 buffer.update_diagnostics(server_id, set, cx)
2319 });
2320
2321 Ok(())
2322 }
2323
2324 fn register_language_server_for_invisible_worktree(
2325 &mut self,
2326 worktree: &Entity<Worktree>,
2327 language_server_id: LanguageServerId,
2328 cx: &mut App,
2329 ) {
2330 let worktree = worktree.read(cx);
2331 let worktree_id = worktree.id();
2332 debug_assert!(!worktree.is_visible());
2333 let Some(mut origin_seed) = self
2334 .language_server_ids
2335 .iter()
2336 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2337 else {
2338 return;
2339 };
2340 origin_seed.worktree_id = worktree_id;
2341 self.language_server_ids
2342 .entry(origin_seed)
2343 .or_insert_with(|| UnifiedLanguageServer {
2344 id: language_server_id,
2345 project_roots: Default::default(),
2346 });
2347 }
2348
2349 fn register_buffer_with_language_servers(
2350 &mut self,
2351 buffer_handle: &Entity<Buffer>,
2352 only_register_servers: HashSet<LanguageServerSelector>,
2353 cx: &mut Context<LspStore>,
2354 ) {
2355 let buffer = buffer_handle.read(cx);
2356 let buffer_id = buffer.remote_id();
2357
2358 let Some(file) = File::from_dyn(buffer.file()) else {
2359 return;
2360 };
2361 if !file.is_local() {
2362 return;
2363 }
2364
2365 let abs_path = file.abs_path(cx);
2366 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2367 return;
2368 };
2369 let initial_snapshot = buffer.text_snapshot();
2370 let worktree_id = file.worktree_id(cx);
2371
2372 let Some(language) = buffer.language().cloned() else {
2373 return;
2374 };
2375 let path: Arc<RelPath> = file
2376 .path()
2377 .parent()
2378 .map(Arc::from)
2379 .unwrap_or_else(|| file.path().clone());
2380 let Some(worktree) = self
2381 .worktree_store
2382 .read(cx)
2383 .worktree_for_id(worktree_id, cx)
2384 else {
2385 return;
2386 };
2387 let language_name = language.name();
2388 let (reused, delegate, servers) = self
2389 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2390 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2391 .unwrap_or_else(|| {
2392 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2393 let delegate: Arc<dyn ManifestDelegate> =
2394 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2395
2396 let servers = self
2397 .lsp_tree
2398 .walk(
2399 ProjectPath { worktree_id, path },
2400 language.name(),
2401 language.manifest(),
2402 &delegate,
2403 cx,
2404 )
2405 .collect::<Vec<_>>();
2406 (false, lsp_delegate, servers)
2407 });
2408 let servers_and_adapters = servers
2409 .into_iter()
2410 .filter_map(|server_node| {
2411 if reused && server_node.server_id().is_none() {
2412 return None;
2413 }
2414 if !only_register_servers.is_empty() {
2415 if let Some(server_id) = server_node.server_id()
2416 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2417 {
2418 return None;
2419 }
2420 if let Some(name) = server_node.name()
2421 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2422 {
2423 return None;
2424 }
2425 }
2426
2427 let server_id = server_node.server_id_or_init(|disposition| {
2428 let path = &disposition.path;
2429
2430 {
2431 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2432
2433 let server_id = self.get_or_insert_language_server(
2434 &worktree,
2435 delegate.clone(),
2436 disposition,
2437 &language_name,
2438 cx,
2439 );
2440
2441 if let Some(state) = self.language_servers.get(&server_id)
2442 && let Ok(uri) = uri
2443 {
2444 state.add_workspace_folder(uri);
2445 };
2446 server_id
2447 }
2448 })?;
2449 let server_state = self.language_servers.get(&server_id)?;
2450 if let LanguageServerState::Running {
2451 server, adapter, ..
2452 } = server_state
2453 {
2454 Some((server.clone(), adapter.clone()))
2455 } else {
2456 None
2457 }
2458 })
2459 .collect::<Vec<_>>();
2460 for (server, adapter) in servers_and_adapters {
2461 buffer_handle.update(cx, |buffer, cx| {
2462 buffer.set_completion_triggers(
2463 server.server_id(),
2464 server
2465 .capabilities()
2466 .completion_provider
2467 .as_ref()
2468 .and_then(|provider| {
2469 provider
2470 .trigger_characters
2471 .as_ref()
2472 .map(|characters| characters.iter().cloned().collect())
2473 })
2474 .unwrap_or_default(),
2475 cx,
2476 );
2477 });
2478
2479 let snapshot = LspBufferSnapshot {
2480 version: 0,
2481 snapshot: initial_snapshot.clone(),
2482 };
2483
2484 let mut registered = false;
2485 self.buffer_snapshots
2486 .entry(buffer_id)
2487 .or_default()
2488 .entry(server.server_id())
2489 .or_insert_with(|| {
2490 registered = true;
2491 server.register_buffer(
2492 uri.clone(),
2493 adapter.language_id(&language.name()),
2494 0,
2495 initial_snapshot.text(),
2496 );
2497
2498 vec![snapshot]
2499 });
2500
2501 self.buffers_opened_in_servers
2502 .entry(buffer_id)
2503 .or_default()
2504 .insert(server.server_id());
2505 if registered {
2506 cx.emit(LspStoreEvent::LanguageServerUpdate {
2507 language_server_id: server.server_id(),
2508 name: None,
2509 message: proto::update_language_server::Variant::RegisteredForBuffer(
2510 proto::RegisteredForBuffer {
2511 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2512 buffer_id: buffer_id.to_proto(),
2513 },
2514 ),
2515 });
2516 }
2517 }
2518 }
2519
2520 fn reuse_existing_language_server<'lang_name>(
2521 &self,
2522 server_tree: &LanguageServerTree,
2523 worktree: &Entity<Worktree>,
2524 language_name: &'lang_name LanguageName,
2525 cx: &mut App,
2526 ) -> Option<(
2527 Arc<LocalLspAdapterDelegate>,
2528 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2529 )> {
2530 if worktree.read(cx).is_visible() {
2531 return None;
2532 }
2533
2534 let worktree_store = self.worktree_store.read(cx);
2535 let servers = server_tree
2536 .instances
2537 .iter()
2538 .filter(|(worktree_id, _)| {
2539 worktree_store
2540 .worktree_for_id(**worktree_id, cx)
2541 .is_some_and(|worktree| worktree.read(cx).is_visible())
2542 })
2543 .flat_map(|(worktree_id, servers)| {
2544 servers
2545 .roots
2546 .iter()
2547 .flat_map(|(_, language_servers)| language_servers)
2548 .map(move |(_, (server_node, server_languages))| {
2549 (worktree_id, server_node, server_languages)
2550 })
2551 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2552 .map(|(worktree_id, server_node, _)| {
2553 (
2554 *worktree_id,
2555 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2556 )
2557 })
2558 })
2559 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2560 acc.entry(worktree_id)
2561 .or_insert_with(Vec::new)
2562 .push(server_node);
2563 acc
2564 })
2565 .into_values()
2566 .max_by_key(|servers| servers.len())?;
2567
2568 let worktree_id = worktree.read(cx).id();
2569 let apply = move |tree: &mut LanguageServerTree| {
2570 for server_node in &servers {
2571 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2572 }
2573 servers
2574 };
2575
2576 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2577 Some((delegate, apply))
2578 }
2579
2580 pub(crate) fn unregister_old_buffer_from_language_servers(
2581 &mut self,
2582 buffer: &Entity<Buffer>,
2583 old_file: &File,
2584 cx: &mut App,
2585 ) {
2586 let old_path = match old_file.as_local() {
2587 Some(local) => local.abs_path(cx),
2588 None => return,
2589 };
2590
2591 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2592 debug_panic!("{old_path:?} is not parseable as an URI");
2593 return;
2594 };
2595 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2596 }
2597
2598 pub(crate) fn unregister_buffer_from_language_servers(
2599 &mut self,
2600 buffer: &Entity<Buffer>,
2601 file_url: &lsp::Uri,
2602 cx: &mut App,
2603 ) {
2604 buffer.update(cx, |buffer, cx| {
2605 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2606
2607 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2608 language_server.unregister_buffer(file_url.clone());
2609 }
2610 });
2611 }
2612
2613 fn buffer_snapshot_for_lsp_version(
2614 &mut self,
2615 buffer: &Entity<Buffer>,
2616 server_id: LanguageServerId,
2617 version: Option<i32>,
2618 cx: &App,
2619 ) -> Result<TextBufferSnapshot> {
2620 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2621
2622 if let Some(version) = version {
2623 let buffer_id = buffer.read(cx).remote_id();
2624 let snapshots = if let Some(snapshots) = self
2625 .buffer_snapshots
2626 .get_mut(&buffer_id)
2627 .and_then(|m| m.get_mut(&server_id))
2628 {
2629 snapshots
2630 } else if version == 0 {
2631 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2632 // We detect this case and treat it as if the version was `None`.
2633 return Ok(buffer.read(cx).text_snapshot());
2634 } else {
2635 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2636 };
2637
2638 let found_snapshot = snapshots
2639 .binary_search_by_key(&version, |e| e.version)
2640 .map(|ix| snapshots[ix].snapshot.clone())
2641 .map_err(|_| {
2642 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2643 })?;
2644
2645 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2646 Ok(found_snapshot)
2647 } else {
2648 Ok((buffer.read(cx)).text_snapshot())
2649 }
2650 }
2651
2652 async fn get_server_code_actions_from_action_kinds(
2653 lsp_store: &WeakEntity<LspStore>,
2654 language_server_id: LanguageServerId,
2655 code_action_kinds: Vec<lsp::CodeActionKind>,
2656 buffer: &Entity<Buffer>,
2657 cx: &mut AsyncApp,
2658 ) -> Result<Vec<CodeAction>> {
2659 let actions = lsp_store
2660 .update(cx, move |this, cx| {
2661 let request = GetCodeActions {
2662 range: text::Anchor::MIN..text::Anchor::MAX,
2663 kinds: Some(code_action_kinds),
2664 };
2665 let server = LanguageServerToQuery::Other(language_server_id);
2666 this.request_lsp(buffer.clone(), server, request, cx)
2667 })?
2668 .await?;
2669 Ok(actions)
2670 }
2671
2672 pub async fn execute_code_actions_on_server(
2673 lsp_store: &WeakEntity<LspStore>,
2674 language_server: &Arc<LanguageServer>,
2675
2676 actions: Vec<CodeAction>,
2677 push_to_history: bool,
2678 project_transaction: &mut ProjectTransaction,
2679 cx: &mut AsyncApp,
2680 ) -> anyhow::Result<()> {
2681 for mut action in actions {
2682 Self::try_resolve_code_action(language_server, &mut action)
2683 .await
2684 .context("resolving a formatting code action")?;
2685
2686 if let Some(edit) = action.lsp_action.edit() {
2687 if edit.changes.is_none() && edit.document_changes.is_none() {
2688 continue;
2689 }
2690
2691 let new = Self::deserialize_workspace_edit(
2692 lsp_store.upgrade().context("project dropped")?,
2693 edit.clone(),
2694 push_to_history,
2695 language_server.clone(),
2696 cx,
2697 )
2698 .await?;
2699 project_transaction.0.extend(new.0);
2700 }
2701
2702 if let Some(command) = action.lsp_action.command() {
2703 let server_capabilities = language_server.capabilities();
2704 let available_commands = server_capabilities
2705 .execute_command_provider
2706 .as_ref()
2707 .map(|options| options.commands.as_slice())
2708 .unwrap_or_default();
2709 if available_commands.contains(&command.command) {
2710 lsp_store.update(cx, |lsp_store, _| {
2711 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2712 mode.last_workspace_edits_by_language_server
2713 .remove(&language_server.server_id());
2714 }
2715 })?;
2716
2717 language_server
2718 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2719 command: command.command.clone(),
2720 arguments: command.arguments.clone().unwrap_or_default(),
2721 ..Default::default()
2722 })
2723 .await
2724 .into_response()
2725 .context("execute command")?;
2726
2727 lsp_store.update(cx, |this, _| {
2728 if let LspStoreMode::Local(mode) = &mut this.mode {
2729 project_transaction.0.extend(
2730 mode.last_workspace_edits_by_language_server
2731 .remove(&language_server.server_id())
2732 .unwrap_or_default()
2733 .0,
2734 )
2735 }
2736 })?;
2737 } else {
2738 log::warn!(
2739 "Cannot execute a command {} not listed in the language server capabilities",
2740 command.command
2741 )
2742 }
2743 }
2744 }
2745 Ok(())
2746 }
2747
2748 pub async fn deserialize_text_edits(
2749 this: Entity<LspStore>,
2750 buffer_to_edit: Entity<Buffer>,
2751 edits: Vec<lsp::TextEdit>,
2752 push_to_history: bool,
2753 _: Arc<CachedLspAdapter>,
2754 language_server: Arc<LanguageServer>,
2755 cx: &mut AsyncApp,
2756 ) -> Result<Option<Transaction>> {
2757 let edits = this
2758 .update(cx, |this, cx| {
2759 this.as_local_mut().unwrap().edits_from_lsp(
2760 &buffer_to_edit,
2761 edits,
2762 language_server.server_id(),
2763 None,
2764 cx,
2765 )
2766 })?
2767 .await?;
2768
2769 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2770 buffer.finalize_last_transaction();
2771 buffer.start_transaction();
2772 for (range, text) in edits {
2773 buffer.edit([(range, text)], None, cx);
2774 }
2775
2776 if buffer.end_transaction(cx).is_some() {
2777 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2778 if !push_to_history {
2779 buffer.forget_transaction(transaction.id);
2780 }
2781 Some(transaction)
2782 } else {
2783 None
2784 }
2785 })?;
2786
2787 Ok(transaction)
2788 }
2789
2790 #[allow(clippy::type_complexity)]
2791 pub(crate) fn edits_from_lsp(
2792 &mut self,
2793 buffer: &Entity<Buffer>,
2794 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2795 server_id: LanguageServerId,
2796 version: Option<i32>,
2797 cx: &mut Context<LspStore>,
2798 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2799 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2800 cx.background_spawn(async move {
2801 let snapshot = snapshot?;
2802 let mut lsp_edits = lsp_edits
2803 .into_iter()
2804 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2805 .collect::<Vec<_>>();
2806
2807 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2808
2809 let mut lsp_edits = lsp_edits.into_iter().peekable();
2810 let mut edits = Vec::new();
2811 while let Some((range, mut new_text)) = lsp_edits.next() {
2812 // Clip invalid ranges provided by the language server.
2813 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2814 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2815
2816 // Combine any LSP edits that are adjacent.
2817 //
2818 // Also, combine LSP edits that are separated from each other by only
2819 // a newline. This is important because for some code actions,
2820 // Rust-analyzer rewrites the entire buffer via a series of edits that
2821 // are separated by unchanged newline characters.
2822 //
2823 // In order for the diffing logic below to work properly, any edits that
2824 // cancel each other out must be combined into one.
2825 while let Some((next_range, next_text)) = lsp_edits.peek() {
2826 if next_range.start.0 > range.end {
2827 if next_range.start.0.row > range.end.row + 1
2828 || next_range.start.0.column > 0
2829 || snapshot.clip_point_utf16(
2830 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2831 Bias::Left,
2832 ) > range.end
2833 {
2834 break;
2835 }
2836 new_text.push('\n');
2837 }
2838 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2839 new_text.push_str(next_text);
2840 lsp_edits.next();
2841 }
2842
2843 // For multiline edits, perform a diff of the old and new text so that
2844 // we can identify the changes more precisely, preserving the locations
2845 // of any anchors positioned in the unchanged regions.
2846 if range.end.row > range.start.row {
2847 let offset = range.start.to_offset(&snapshot);
2848 let old_text = snapshot.text_for_range(range).collect::<String>();
2849 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2850 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2851 (
2852 snapshot.anchor_after(offset + range.start)
2853 ..snapshot.anchor_before(offset + range.end),
2854 replacement,
2855 )
2856 }));
2857 } else if range.end == range.start {
2858 let anchor = snapshot.anchor_after(range.start);
2859 edits.push((anchor..anchor, new_text.into()));
2860 } else {
2861 let edit_start = snapshot.anchor_after(range.start);
2862 let edit_end = snapshot.anchor_before(range.end);
2863 edits.push((edit_start..edit_end, new_text.into()));
2864 }
2865 }
2866
2867 Ok(edits)
2868 })
2869 }
2870
2871 pub(crate) async fn deserialize_workspace_edit(
2872 this: Entity<LspStore>,
2873 edit: lsp::WorkspaceEdit,
2874 push_to_history: bool,
2875 language_server: Arc<LanguageServer>,
2876 cx: &mut AsyncApp,
2877 ) -> Result<ProjectTransaction> {
2878 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2879
2880 let mut operations = Vec::new();
2881 if let Some(document_changes) = edit.document_changes {
2882 match document_changes {
2883 lsp::DocumentChanges::Edits(edits) => {
2884 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2885 }
2886 lsp::DocumentChanges::Operations(ops) => operations = ops,
2887 }
2888 } else if let Some(changes) = edit.changes {
2889 operations.extend(changes.into_iter().map(|(uri, edits)| {
2890 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2891 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2892 uri,
2893 version: None,
2894 },
2895 edits: edits.into_iter().map(Edit::Plain).collect(),
2896 })
2897 }));
2898 }
2899
2900 let mut project_transaction = ProjectTransaction::default();
2901 for operation in operations {
2902 match operation {
2903 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2904 let abs_path = op
2905 .uri
2906 .to_file_path()
2907 .map_err(|()| anyhow!("can't convert URI to path"))?;
2908
2909 if let Some(parent_path) = abs_path.parent() {
2910 fs.create_dir(parent_path).await?;
2911 }
2912 if abs_path.ends_with("/") {
2913 fs.create_dir(&abs_path).await?;
2914 } else {
2915 fs.create_file(
2916 &abs_path,
2917 op.options
2918 .map(|options| fs::CreateOptions {
2919 overwrite: options.overwrite.unwrap_or(false),
2920 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2921 })
2922 .unwrap_or_default(),
2923 )
2924 .await?;
2925 }
2926 }
2927
2928 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2929 let source_abs_path = op
2930 .old_uri
2931 .to_file_path()
2932 .map_err(|()| anyhow!("can't convert URI to path"))?;
2933 let target_abs_path = op
2934 .new_uri
2935 .to_file_path()
2936 .map_err(|()| anyhow!("can't convert URI to path"))?;
2937 fs.rename(
2938 &source_abs_path,
2939 &target_abs_path,
2940 op.options
2941 .map(|options| fs::RenameOptions {
2942 overwrite: options.overwrite.unwrap_or(false),
2943 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2944 })
2945 .unwrap_or_default(),
2946 )
2947 .await?;
2948 }
2949
2950 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2951 let abs_path = op
2952 .uri
2953 .to_file_path()
2954 .map_err(|()| anyhow!("can't convert URI to path"))?;
2955 let options = op
2956 .options
2957 .map(|options| fs::RemoveOptions {
2958 recursive: options.recursive.unwrap_or(false),
2959 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
2960 })
2961 .unwrap_or_default();
2962 if abs_path.ends_with("/") {
2963 fs.remove_dir(&abs_path, options).await?;
2964 } else {
2965 fs.remove_file(&abs_path, options).await?;
2966 }
2967 }
2968
2969 lsp::DocumentChangeOperation::Edit(op) => {
2970 let buffer_to_edit = this
2971 .update(cx, |this, cx| {
2972 this.open_local_buffer_via_lsp(
2973 op.text_document.uri.clone(),
2974 language_server.server_id(),
2975 cx,
2976 )
2977 })?
2978 .await?;
2979
2980 let edits = this
2981 .update(cx, |this, cx| {
2982 let path = buffer_to_edit.read(cx).project_path(cx);
2983 let active_entry = this.active_entry;
2984 let is_active_entry = path.is_some_and(|project_path| {
2985 this.worktree_store
2986 .read(cx)
2987 .entry_for_path(&project_path, cx)
2988 .is_some_and(|entry| Some(entry.id) == active_entry)
2989 });
2990 let local = this.as_local_mut().unwrap();
2991
2992 let (mut edits, mut snippet_edits) = (vec![], vec![]);
2993 for edit in op.edits {
2994 match edit {
2995 Edit::Plain(edit) => {
2996 if !edits.contains(&edit) {
2997 edits.push(edit)
2998 }
2999 }
3000 Edit::Annotated(edit) => {
3001 if !edits.contains(&edit.text_edit) {
3002 edits.push(edit.text_edit)
3003 }
3004 }
3005 Edit::Snippet(edit) => {
3006 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3007 else {
3008 continue;
3009 };
3010
3011 if is_active_entry {
3012 snippet_edits.push((edit.range, snippet));
3013 } else {
3014 // Since this buffer is not focused, apply a normal edit.
3015 let new_edit = TextEdit {
3016 range: edit.range,
3017 new_text: snippet.text,
3018 };
3019 if !edits.contains(&new_edit) {
3020 edits.push(new_edit);
3021 }
3022 }
3023 }
3024 }
3025 }
3026 if !snippet_edits.is_empty() {
3027 let buffer_id = buffer_to_edit.read(cx).remote_id();
3028 let version = if let Some(buffer_version) = op.text_document.version
3029 {
3030 local
3031 .buffer_snapshot_for_lsp_version(
3032 &buffer_to_edit,
3033 language_server.server_id(),
3034 Some(buffer_version),
3035 cx,
3036 )
3037 .ok()
3038 .map(|snapshot| snapshot.version)
3039 } else {
3040 Some(buffer_to_edit.read(cx).saved_version().clone())
3041 };
3042
3043 let most_recent_edit =
3044 version.and_then(|version| version.most_recent());
3045 // Check if the edit that triggered that edit has been made by this participant.
3046
3047 if let Some(most_recent_edit) = most_recent_edit {
3048 cx.emit(LspStoreEvent::SnippetEdit {
3049 buffer_id,
3050 edits: snippet_edits,
3051 most_recent_edit,
3052 });
3053 }
3054 }
3055
3056 local.edits_from_lsp(
3057 &buffer_to_edit,
3058 edits,
3059 language_server.server_id(),
3060 op.text_document.version,
3061 cx,
3062 )
3063 })?
3064 .await?;
3065
3066 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3067 buffer.finalize_last_transaction();
3068 buffer.start_transaction();
3069 for (range, text) in edits {
3070 buffer.edit([(range, text)], None, cx);
3071 }
3072
3073 buffer.end_transaction(cx).and_then(|transaction_id| {
3074 if push_to_history {
3075 buffer.finalize_last_transaction();
3076 buffer.get_transaction(transaction_id).cloned()
3077 } else {
3078 buffer.forget_transaction(transaction_id)
3079 }
3080 })
3081 })?;
3082 if let Some(transaction) = transaction {
3083 project_transaction.0.insert(buffer_to_edit, transaction);
3084 }
3085 }
3086 }
3087 }
3088
3089 Ok(project_transaction)
3090 }
3091
3092 async fn on_lsp_workspace_edit(
3093 this: WeakEntity<LspStore>,
3094 params: lsp::ApplyWorkspaceEditParams,
3095 server_id: LanguageServerId,
3096 cx: &mut AsyncApp,
3097 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3098 let this = this.upgrade().context("project project closed")?;
3099 let language_server = this
3100 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3101 .context("language server not found")?;
3102 let transaction = Self::deserialize_workspace_edit(
3103 this.clone(),
3104 params.edit,
3105 true,
3106 language_server.clone(),
3107 cx,
3108 )
3109 .await
3110 .log_err();
3111 this.update(cx, |this, _| {
3112 if let Some(transaction) = transaction {
3113 this.as_local_mut()
3114 .unwrap()
3115 .last_workspace_edits_by_language_server
3116 .insert(server_id, transaction);
3117 }
3118 })?;
3119 Ok(lsp::ApplyWorkspaceEditResponse {
3120 applied: true,
3121 failed_change: None,
3122 failure_reason: None,
3123 })
3124 }
3125
3126 fn remove_worktree(
3127 &mut self,
3128 id_to_remove: WorktreeId,
3129 cx: &mut Context<LspStore>,
3130 ) -> Vec<LanguageServerId> {
3131 self.diagnostics.remove(&id_to_remove);
3132 self.prettier_store.update(cx, |prettier_store, cx| {
3133 prettier_store.remove_worktree(id_to_remove, cx);
3134 });
3135
3136 let mut servers_to_remove = BTreeSet::default();
3137 let mut servers_to_preserve = HashSet::default();
3138 for (seed, state) in &self.language_server_ids {
3139 if seed.worktree_id == id_to_remove {
3140 servers_to_remove.insert(state.id);
3141 } else {
3142 servers_to_preserve.insert(state.id);
3143 }
3144 }
3145 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3146 self.language_server_ids
3147 .retain(|_, state| !servers_to_remove.contains(&state.id));
3148 for server_id_to_remove in &servers_to_remove {
3149 self.language_server_watched_paths
3150 .remove(server_id_to_remove);
3151 self.language_server_paths_watched_for_rename
3152 .remove(server_id_to_remove);
3153 self.last_workspace_edits_by_language_server
3154 .remove(server_id_to_remove);
3155 self.language_servers.remove(server_id_to_remove);
3156 self.buffer_pull_diagnostics_result_ids
3157 .remove(server_id_to_remove);
3158 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3159 buffer_servers.remove(server_id_to_remove);
3160 }
3161 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3162 }
3163 servers_to_remove.into_iter().collect()
3164 }
3165
3166 fn rebuild_watched_paths_inner<'a>(
3167 &'a self,
3168 language_server_id: LanguageServerId,
3169 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3170 cx: &mut Context<LspStore>,
3171 ) -> LanguageServerWatchedPathsBuilder {
3172 let worktrees = self
3173 .worktree_store
3174 .read(cx)
3175 .worktrees()
3176 .filter_map(|worktree| {
3177 self.language_servers_for_worktree(worktree.read(cx).id())
3178 .find(|server| server.server_id() == language_server_id)
3179 .map(|_| worktree)
3180 })
3181 .collect::<Vec<_>>();
3182
3183 let mut worktree_globs = HashMap::default();
3184 let mut abs_globs = HashMap::default();
3185 log::trace!(
3186 "Processing new watcher paths for language server with id {}",
3187 language_server_id
3188 );
3189
3190 for watcher in watchers {
3191 if let Some((worktree, literal_prefix, pattern)) =
3192 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3193 {
3194 worktree.update(cx, |worktree, _| {
3195 if let Some((tree, glob)) =
3196 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3197 {
3198 tree.add_path_prefix_to_scan(literal_prefix);
3199 worktree_globs
3200 .entry(tree.id())
3201 .or_insert_with(GlobSetBuilder::new)
3202 .add(glob);
3203 }
3204 });
3205 } else {
3206 let (path, pattern) = match &watcher.glob_pattern {
3207 lsp::GlobPattern::String(s) => {
3208 let watcher_path = SanitizedPath::new(s);
3209 let path = glob_literal_prefix(watcher_path.as_path());
3210 let pattern = watcher_path
3211 .as_path()
3212 .strip_prefix(&path)
3213 .map(|p| p.to_string_lossy().into_owned())
3214 .unwrap_or_else(|e| {
3215 debug_panic!(
3216 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3217 s,
3218 path.display(),
3219 e
3220 );
3221 watcher_path.as_path().to_string_lossy().into_owned()
3222 });
3223 (path, pattern)
3224 }
3225 lsp::GlobPattern::Relative(rp) => {
3226 let Ok(mut base_uri) = match &rp.base_uri {
3227 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3228 lsp::OneOf::Right(base_uri) => base_uri,
3229 }
3230 .to_file_path() else {
3231 continue;
3232 };
3233
3234 let path = glob_literal_prefix(Path::new(&rp.pattern));
3235 let pattern = Path::new(&rp.pattern)
3236 .strip_prefix(&path)
3237 .map(|p| p.to_string_lossy().into_owned())
3238 .unwrap_or_else(|e| {
3239 debug_panic!(
3240 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3241 rp.pattern,
3242 path.display(),
3243 e
3244 );
3245 rp.pattern.clone()
3246 });
3247 base_uri.push(path);
3248 (base_uri, pattern)
3249 }
3250 };
3251
3252 if let Some(glob) = Glob::new(&pattern).log_err() {
3253 if !path
3254 .components()
3255 .any(|c| matches!(c, path::Component::Normal(_)))
3256 {
3257 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3258 // rather than adding a new watcher for `/`.
3259 for worktree in &worktrees {
3260 worktree_globs
3261 .entry(worktree.read(cx).id())
3262 .or_insert_with(GlobSetBuilder::new)
3263 .add(glob.clone());
3264 }
3265 } else {
3266 abs_globs
3267 .entry(path.into())
3268 .or_insert_with(GlobSetBuilder::new)
3269 .add(glob);
3270 }
3271 }
3272 }
3273 }
3274
3275 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3276 for (worktree_id, builder) in worktree_globs {
3277 if let Ok(globset) = builder.build() {
3278 watch_builder.watch_worktree(worktree_id, globset);
3279 }
3280 }
3281 for (abs_path, builder) in abs_globs {
3282 if let Ok(globset) = builder.build() {
3283 watch_builder.watch_abs_path(abs_path, globset);
3284 }
3285 }
3286 watch_builder
3287 }
3288
3289 fn worktree_and_path_for_file_watcher(
3290 worktrees: &[Entity<Worktree>],
3291 watcher: &FileSystemWatcher,
3292 cx: &App,
3293 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3294 worktrees.iter().find_map(|worktree| {
3295 let tree = worktree.read(cx);
3296 let worktree_root_path = tree.abs_path();
3297 let path_style = tree.path_style();
3298 match &watcher.glob_pattern {
3299 lsp::GlobPattern::String(s) => {
3300 let watcher_path = SanitizedPath::new(s);
3301 let relative = watcher_path
3302 .as_path()
3303 .strip_prefix(&worktree_root_path)
3304 .ok()?;
3305 let literal_prefix = glob_literal_prefix(relative);
3306 Some((
3307 worktree.clone(),
3308 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3309 relative.to_string_lossy().into_owned(),
3310 ))
3311 }
3312 lsp::GlobPattern::Relative(rp) => {
3313 let base_uri = match &rp.base_uri {
3314 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3315 lsp::OneOf::Right(base_uri) => base_uri,
3316 }
3317 .to_file_path()
3318 .ok()?;
3319 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3320 let mut literal_prefix = relative.to_owned();
3321 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3322 Some((
3323 worktree.clone(),
3324 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3325 rp.pattern.clone(),
3326 ))
3327 }
3328 }
3329 })
3330 }
3331
3332 fn rebuild_watched_paths(
3333 &mut self,
3334 language_server_id: LanguageServerId,
3335 cx: &mut Context<LspStore>,
3336 ) {
3337 let Some(registrations) = self
3338 .language_server_dynamic_registrations
3339 .get(&language_server_id)
3340 else {
3341 return;
3342 };
3343
3344 let watch_builder = self.rebuild_watched_paths_inner(
3345 language_server_id,
3346 registrations.did_change_watched_files.values().flatten(),
3347 cx,
3348 );
3349 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3350 self.language_server_watched_paths
3351 .insert(language_server_id, watcher);
3352
3353 cx.notify();
3354 }
3355
3356 fn on_lsp_did_change_watched_files(
3357 &mut self,
3358 language_server_id: LanguageServerId,
3359 registration_id: &str,
3360 params: DidChangeWatchedFilesRegistrationOptions,
3361 cx: &mut Context<LspStore>,
3362 ) {
3363 let registrations = self
3364 .language_server_dynamic_registrations
3365 .entry(language_server_id)
3366 .or_default();
3367
3368 registrations
3369 .did_change_watched_files
3370 .insert(registration_id.to_string(), params.watchers);
3371
3372 self.rebuild_watched_paths(language_server_id, cx);
3373 }
3374
3375 fn on_lsp_unregister_did_change_watched_files(
3376 &mut self,
3377 language_server_id: LanguageServerId,
3378 registration_id: &str,
3379 cx: &mut Context<LspStore>,
3380 ) {
3381 let registrations = self
3382 .language_server_dynamic_registrations
3383 .entry(language_server_id)
3384 .or_default();
3385
3386 if registrations
3387 .did_change_watched_files
3388 .remove(registration_id)
3389 .is_some()
3390 {
3391 log::info!(
3392 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3393 language_server_id,
3394 registration_id
3395 );
3396 } else {
3397 log::warn!(
3398 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3399 language_server_id,
3400 registration_id
3401 );
3402 }
3403
3404 self.rebuild_watched_paths(language_server_id, cx);
3405 }
3406
3407 async fn initialization_options_for_adapter(
3408 adapter: Arc<dyn LspAdapter>,
3409 delegate: &Arc<dyn LspAdapterDelegate>,
3410 ) -> Result<Option<serde_json::Value>> {
3411 let Some(mut initialization_config) =
3412 adapter.clone().initialization_options(delegate).await?
3413 else {
3414 return Ok(None);
3415 };
3416
3417 for other_adapter in delegate.registered_lsp_adapters() {
3418 if other_adapter.name() == adapter.name() {
3419 continue;
3420 }
3421 if let Ok(Some(target_config)) = other_adapter
3422 .clone()
3423 .additional_initialization_options(adapter.name(), delegate)
3424 .await
3425 {
3426 merge_json_value_into(target_config.clone(), &mut initialization_config);
3427 }
3428 }
3429
3430 Ok(Some(initialization_config))
3431 }
3432
3433 async fn workspace_configuration_for_adapter(
3434 adapter: Arc<dyn LspAdapter>,
3435 delegate: &Arc<dyn LspAdapterDelegate>,
3436 toolchain: Option<Toolchain>,
3437 cx: &mut AsyncApp,
3438 ) -> Result<serde_json::Value> {
3439 let mut workspace_config = adapter
3440 .clone()
3441 .workspace_configuration(delegate, toolchain, cx)
3442 .await?;
3443
3444 for other_adapter in delegate.registered_lsp_adapters() {
3445 if other_adapter.name() == adapter.name() {
3446 continue;
3447 }
3448 if let Ok(Some(target_config)) = other_adapter
3449 .clone()
3450 .additional_workspace_configuration(adapter.name(), delegate, cx)
3451 .await
3452 {
3453 merge_json_value_into(target_config.clone(), &mut workspace_config);
3454 }
3455 }
3456
3457 Ok(workspace_config)
3458 }
3459
3460 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3461 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3462 Some(server.clone())
3463 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3464 Some(Arc::clone(server))
3465 } else {
3466 None
3467 }
3468 }
3469}
3470
3471fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3472 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3473 cx.emit(LspStoreEvent::LanguageServerUpdate {
3474 language_server_id: server.server_id(),
3475 name: Some(server.name()),
3476 message: proto::update_language_server::Variant::MetadataUpdated(
3477 proto::ServerMetadataUpdated {
3478 capabilities: Some(capabilities),
3479 },
3480 ),
3481 });
3482 }
3483}
3484
3485#[derive(Debug)]
3486pub struct FormattableBuffer {
3487 handle: Entity<Buffer>,
3488 abs_path: Option<PathBuf>,
3489 env: Option<HashMap<String, String>>,
3490 ranges: Option<Vec<Range<Anchor>>>,
3491}
3492
3493pub struct RemoteLspStore {
3494 upstream_client: Option<AnyProtoClient>,
3495 upstream_project_id: u64,
3496}
3497
3498pub(crate) enum LspStoreMode {
3499 Local(LocalLspStore), // ssh host and collab host
3500 Remote(RemoteLspStore), // collab guest
3501}
3502
3503impl LspStoreMode {
3504 fn is_local(&self) -> bool {
3505 matches!(self, LspStoreMode::Local(_))
3506 }
3507}
3508
3509pub struct LspStore {
3510 mode: LspStoreMode,
3511 last_formatting_failure: Option<String>,
3512 downstream_client: Option<(AnyProtoClient, u64)>,
3513 nonce: u128,
3514 buffer_store: Entity<BufferStore>,
3515 worktree_store: Entity<WorktreeStore>,
3516 pub languages: Arc<LanguageRegistry>,
3517 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3518 active_entry: Option<ProjectEntryId>,
3519 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3520 _maintain_buffer_languages: Task<()>,
3521 diagnostic_summaries:
3522 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3523 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3524 lsp_data: HashMap<BufferId, BufferLspData>,
3525 next_hint_id: Arc<AtomicUsize>,
3526}
3527
3528#[derive(Debug)]
3529pub struct BufferLspData {
3530 buffer_version: Global,
3531 document_colors: Option<DocumentColorData>,
3532 code_lens: Option<CodeLensData>,
3533 inlay_hints: BufferInlayHints,
3534 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3535 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3536}
3537
3538#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3539struct LspKey {
3540 request_type: TypeId,
3541 server_queried: Option<LanguageServerId>,
3542}
3543
3544impl BufferLspData {
3545 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3546 Self {
3547 buffer_version: buffer.read(cx).version(),
3548 document_colors: None,
3549 code_lens: None,
3550 inlay_hints: BufferInlayHints::new(buffer, cx),
3551 lsp_requests: HashMap::default(),
3552 chunk_lsp_requests: HashMap::default(),
3553 }
3554 }
3555
3556 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3557 if let Some(document_colors) = &mut self.document_colors {
3558 document_colors.colors.remove(&for_server);
3559 document_colors.cache_version += 1;
3560 }
3561
3562 if let Some(code_lens) = &mut self.code_lens {
3563 code_lens.lens.remove(&for_server);
3564 }
3565
3566 self.inlay_hints.remove_server_data(for_server);
3567 }
3568
3569 #[cfg(any(test, feature = "test-support"))]
3570 pub fn inlay_hints(&self) -> &BufferInlayHints {
3571 &self.inlay_hints
3572 }
3573}
3574
3575#[derive(Debug, Default, Clone)]
3576pub struct DocumentColors {
3577 pub colors: HashSet<DocumentColor>,
3578 pub cache_version: Option<usize>,
3579}
3580
3581type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3582type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3583
3584#[derive(Debug, Default)]
3585struct DocumentColorData {
3586 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3587 cache_version: usize,
3588 colors_update: Option<(Global, DocumentColorTask)>,
3589}
3590
3591#[derive(Debug, Default)]
3592struct CodeLensData {
3593 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3594 update: Option<(Global, CodeLensTask)>,
3595}
3596
3597#[derive(Debug)]
3598pub enum LspStoreEvent {
3599 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3600 LanguageServerRemoved(LanguageServerId),
3601 LanguageServerUpdate {
3602 language_server_id: LanguageServerId,
3603 name: Option<LanguageServerName>,
3604 message: proto::update_language_server::Variant,
3605 },
3606 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3607 LanguageServerPrompt(LanguageServerPromptRequest),
3608 LanguageDetected {
3609 buffer: Entity<Buffer>,
3610 new_language: Option<Arc<Language>>,
3611 },
3612 Notification(String),
3613 RefreshInlayHints(LanguageServerId),
3614 RefreshCodeLens,
3615 DiagnosticsUpdated {
3616 server_id: LanguageServerId,
3617 paths: Vec<ProjectPath>,
3618 },
3619 DiskBasedDiagnosticsStarted {
3620 language_server_id: LanguageServerId,
3621 },
3622 DiskBasedDiagnosticsFinished {
3623 language_server_id: LanguageServerId,
3624 },
3625 SnippetEdit {
3626 buffer_id: BufferId,
3627 edits: Vec<(lsp::Range, Snippet)>,
3628 most_recent_edit: clock::Lamport,
3629 },
3630}
3631
3632#[derive(Clone, Debug, Serialize)]
3633pub struct LanguageServerStatus {
3634 pub name: LanguageServerName,
3635 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3636 pub has_pending_diagnostic_updates: bool,
3637 progress_tokens: HashSet<String>,
3638 pub worktree: Option<WorktreeId>,
3639}
3640
3641#[derive(Clone, Debug)]
3642struct CoreSymbol {
3643 pub language_server_name: LanguageServerName,
3644 pub source_worktree_id: WorktreeId,
3645 pub source_language_server_id: LanguageServerId,
3646 pub path: SymbolLocation,
3647 pub name: String,
3648 pub kind: lsp::SymbolKind,
3649 pub range: Range<Unclipped<PointUtf16>>,
3650}
3651
3652#[derive(Clone, Debug, PartialEq, Eq)]
3653pub enum SymbolLocation {
3654 InProject(ProjectPath),
3655 OutsideProject {
3656 abs_path: Arc<Path>,
3657 signature: [u8; 32],
3658 },
3659}
3660
3661impl SymbolLocation {
3662 fn file_name(&self) -> Option<&str> {
3663 match self {
3664 Self::InProject(path) => path.path.file_name(),
3665 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3666 }
3667 }
3668}
3669
3670impl LspStore {
3671 pub fn init(client: &AnyProtoClient) {
3672 client.add_entity_request_handler(Self::handle_lsp_query);
3673 client.add_entity_message_handler(Self::handle_lsp_query_response);
3674 client.add_entity_request_handler(Self::handle_restart_language_servers);
3675 client.add_entity_request_handler(Self::handle_stop_language_servers);
3676 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3677 client.add_entity_message_handler(Self::handle_start_language_server);
3678 client.add_entity_message_handler(Self::handle_update_language_server);
3679 client.add_entity_message_handler(Self::handle_language_server_log);
3680 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3681 client.add_entity_request_handler(Self::handle_format_buffers);
3682 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3683 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3684 client.add_entity_request_handler(Self::handle_apply_code_action);
3685 client.add_entity_request_handler(Self::handle_get_project_symbols);
3686 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3687 client.add_entity_request_handler(Self::handle_get_color_presentation);
3688 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3689 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3690 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3691 client.add_entity_request_handler(Self::handle_on_type_formatting);
3692 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3693 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3694 client.add_entity_request_handler(Self::handle_rename_project_entry);
3695 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3696 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3697 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3698 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3699 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3700 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3701 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3702
3703 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3704 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3705 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3706 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3707 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3708 client.add_entity_request_handler(
3709 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3710 );
3711 client.add_entity_request_handler(
3712 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3713 );
3714 client.add_entity_request_handler(
3715 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3716 );
3717 }
3718
3719 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3720 match &self.mode {
3721 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3722 _ => None,
3723 }
3724 }
3725
3726 pub fn as_local(&self) -> Option<&LocalLspStore> {
3727 match &self.mode {
3728 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3729 _ => None,
3730 }
3731 }
3732
3733 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3734 match &mut self.mode {
3735 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3736 _ => None,
3737 }
3738 }
3739
3740 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3741 match &self.mode {
3742 LspStoreMode::Remote(RemoteLspStore {
3743 upstream_client: Some(upstream_client),
3744 upstream_project_id,
3745 ..
3746 }) => Some((upstream_client.clone(), *upstream_project_id)),
3747
3748 LspStoreMode::Remote(RemoteLspStore {
3749 upstream_client: None,
3750 ..
3751 }) => None,
3752 LspStoreMode::Local(_) => None,
3753 }
3754 }
3755
3756 pub fn new_local(
3757 buffer_store: Entity<BufferStore>,
3758 worktree_store: Entity<WorktreeStore>,
3759 prettier_store: Entity<PrettierStore>,
3760 toolchain_store: Entity<LocalToolchainStore>,
3761 environment: Entity<ProjectEnvironment>,
3762 manifest_tree: Entity<ManifestTree>,
3763 languages: Arc<LanguageRegistry>,
3764 http_client: Arc<dyn HttpClient>,
3765 fs: Arc<dyn Fs>,
3766 cx: &mut Context<Self>,
3767 ) -> Self {
3768 let yarn = YarnPathStore::new(fs.clone(), cx);
3769 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3770 .detach();
3771 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3772 .detach();
3773 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3774 .detach();
3775 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3776 .detach();
3777 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3778 .detach();
3779 subscribe_to_binary_statuses(&languages, cx).detach();
3780
3781 let _maintain_workspace_config = {
3782 let (sender, receiver) = watch::channel();
3783 (Self::maintain_workspace_config(receiver, cx), sender)
3784 };
3785
3786 Self {
3787 mode: LspStoreMode::Local(LocalLspStore {
3788 weak: cx.weak_entity(),
3789 worktree_store: worktree_store.clone(),
3790
3791 supplementary_language_servers: Default::default(),
3792 languages: languages.clone(),
3793 language_server_ids: Default::default(),
3794 language_servers: Default::default(),
3795 last_workspace_edits_by_language_server: Default::default(),
3796 language_server_watched_paths: Default::default(),
3797 language_server_paths_watched_for_rename: Default::default(),
3798 language_server_dynamic_registrations: Default::default(),
3799 buffers_being_formatted: Default::default(),
3800 buffer_snapshots: Default::default(),
3801 prettier_store,
3802 environment,
3803 http_client,
3804 fs,
3805 yarn,
3806 next_diagnostic_group_id: Default::default(),
3807 diagnostics: Default::default(),
3808 _subscription: cx.on_app_quit(|this, cx| {
3809 this.as_local_mut()
3810 .unwrap()
3811 .shutdown_language_servers_on_quit(cx)
3812 }),
3813 lsp_tree: LanguageServerTree::new(
3814 manifest_tree,
3815 languages.clone(),
3816 toolchain_store.clone(),
3817 ),
3818 toolchain_store,
3819 registered_buffers: HashMap::default(),
3820 buffers_opened_in_servers: HashMap::default(),
3821 buffer_pull_diagnostics_result_ids: HashMap::default(),
3822 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3823 .manifest_file_names(),
3824 }),
3825 last_formatting_failure: None,
3826 downstream_client: None,
3827 buffer_store,
3828 worktree_store,
3829 languages: languages.clone(),
3830 language_server_statuses: Default::default(),
3831 nonce: StdRng::from_os_rng().random(),
3832 diagnostic_summaries: HashMap::default(),
3833 lsp_server_capabilities: HashMap::default(),
3834 lsp_data: HashMap::default(),
3835 next_hint_id: Arc::default(),
3836 active_entry: None,
3837 _maintain_workspace_config,
3838 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3839 }
3840 }
3841
3842 fn send_lsp_proto_request<R: LspCommand>(
3843 &self,
3844 buffer: Entity<Buffer>,
3845 client: AnyProtoClient,
3846 upstream_project_id: u64,
3847 request: R,
3848 cx: &mut Context<LspStore>,
3849 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3850 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3851 return Task::ready(Ok(R::Response::default()));
3852 }
3853 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3854 cx.spawn(async move |this, cx| {
3855 let response = client.request(message).await?;
3856 let this = this.upgrade().context("project dropped")?;
3857 request
3858 .response_from_proto(response, this, buffer, cx.clone())
3859 .await
3860 })
3861 }
3862
3863 pub(super) fn new_remote(
3864 buffer_store: Entity<BufferStore>,
3865 worktree_store: Entity<WorktreeStore>,
3866 languages: Arc<LanguageRegistry>,
3867 upstream_client: AnyProtoClient,
3868 project_id: u64,
3869 cx: &mut Context<Self>,
3870 ) -> Self {
3871 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3872 .detach();
3873 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3874 .detach();
3875 subscribe_to_binary_statuses(&languages, cx).detach();
3876 let _maintain_workspace_config = {
3877 let (sender, receiver) = watch::channel();
3878 (Self::maintain_workspace_config(receiver, cx), sender)
3879 };
3880 Self {
3881 mode: LspStoreMode::Remote(RemoteLspStore {
3882 upstream_client: Some(upstream_client),
3883 upstream_project_id: project_id,
3884 }),
3885 downstream_client: None,
3886 last_formatting_failure: None,
3887 buffer_store,
3888 worktree_store,
3889 languages: languages.clone(),
3890 language_server_statuses: Default::default(),
3891 nonce: StdRng::from_os_rng().random(),
3892 diagnostic_summaries: HashMap::default(),
3893 lsp_server_capabilities: HashMap::default(),
3894 next_hint_id: Arc::default(),
3895 lsp_data: HashMap::default(),
3896 active_entry: None,
3897
3898 _maintain_workspace_config,
3899 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3900 }
3901 }
3902
3903 fn on_buffer_store_event(
3904 &mut self,
3905 _: Entity<BufferStore>,
3906 event: &BufferStoreEvent,
3907 cx: &mut Context<Self>,
3908 ) {
3909 match event {
3910 BufferStoreEvent::BufferAdded(buffer) => {
3911 self.on_buffer_added(buffer, cx).log_err();
3912 }
3913 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3914 let buffer_id = buffer.read(cx).remote_id();
3915 if let Some(local) = self.as_local_mut()
3916 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3917 {
3918 local.reset_buffer(buffer, old_file, cx);
3919
3920 if local.registered_buffers.contains_key(&buffer_id) {
3921 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3922 }
3923 }
3924
3925 self.detect_language_for_buffer(buffer, cx);
3926 if let Some(local) = self.as_local_mut() {
3927 local.initialize_buffer(buffer, cx);
3928 if local.registered_buffers.contains_key(&buffer_id) {
3929 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3930 }
3931 }
3932 }
3933 _ => {}
3934 }
3935 }
3936
3937 fn on_worktree_store_event(
3938 &mut self,
3939 _: Entity<WorktreeStore>,
3940 event: &WorktreeStoreEvent,
3941 cx: &mut Context<Self>,
3942 ) {
3943 match event {
3944 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3945 if !worktree.read(cx).is_local() {
3946 return;
3947 }
3948 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3949 worktree::Event::UpdatedEntries(changes) => {
3950 this.update_local_worktree_language_servers(&worktree, changes, cx);
3951 }
3952 worktree::Event::UpdatedGitRepositories(_)
3953 | worktree::Event::DeletedEntry(_) => {}
3954 })
3955 .detach()
3956 }
3957 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3958 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3959 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3960 }
3961 WorktreeStoreEvent::WorktreeReleased(..)
3962 | WorktreeStoreEvent::WorktreeOrderChanged
3963 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3964 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3965 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3966 }
3967 }
3968
3969 fn on_prettier_store_event(
3970 &mut self,
3971 _: Entity<PrettierStore>,
3972 event: &PrettierStoreEvent,
3973 cx: &mut Context<Self>,
3974 ) {
3975 match event {
3976 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3977 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3978 }
3979 PrettierStoreEvent::LanguageServerAdded {
3980 new_server_id,
3981 name,
3982 prettier_server,
3983 } => {
3984 self.register_supplementary_language_server(
3985 *new_server_id,
3986 name.clone(),
3987 prettier_server.clone(),
3988 cx,
3989 );
3990 }
3991 }
3992 }
3993
3994 fn on_toolchain_store_event(
3995 &mut self,
3996 _: Entity<LocalToolchainStore>,
3997 event: &ToolchainStoreEvent,
3998 _: &mut Context<Self>,
3999 ) {
4000 if let ToolchainStoreEvent::ToolchainActivated = event {
4001 self.request_workspace_config_refresh()
4002 }
4003 }
4004
4005 fn request_workspace_config_refresh(&mut self) {
4006 *self._maintain_workspace_config.1.borrow_mut() = ();
4007 }
4008
4009 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4010 self.as_local().map(|local| local.prettier_store.clone())
4011 }
4012
4013 fn on_buffer_event(
4014 &mut self,
4015 buffer: Entity<Buffer>,
4016 event: &language::BufferEvent,
4017 cx: &mut Context<Self>,
4018 ) {
4019 match event {
4020 language::BufferEvent::Edited => {
4021 self.on_buffer_edited(buffer, cx);
4022 }
4023
4024 language::BufferEvent::Saved => {
4025 self.on_buffer_saved(buffer, cx);
4026 }
4027
4028 _ => {}
4029 }
4030 }
4031
4032 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4033 buffer
4034 .read(cx)
4035 .set_language_registry(self.languages.clone());
4036
4037 cx.subscribe(buffer, |this, buffer, event, cx| {
4038 this.on_buffer_event(buffer, event, cx);
4039 })
4040 .detach();
4041
4042 self.detect_language_for_buffer(buffer, cx);
4043 if let Some(local) = self.as_local_mut() {
4044 local.initialize_buffer(buffer, cx);
4045 }
4046
4047 Ok(())
4048 }
4049
4050 pub(crate) fn register_buffer_with_language_servers(
4051 &mut self,
4052 buffer: &Entity<Buffer>,
4053 only_register_servers: HashSet<LanguageServerSelector>,
4054 ignore_refcounts: bool,
4055 cx: &mut Context<Self>,
4056 ) -> OpenLspBufferHandle {
4057 let buffer_id = buffer.read(cx).remote_id();
4058 let handle = cx.new(|_| buffer.clone());
4059 if let Some(local) = self.as_local_mut() {
4060 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4061 if !ignore_refcounts {
4062 *refcount += 1;
4063 }
4064
4065 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4066 // 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
4067 // 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
4068 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4069 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4070 return handle;
4071 };
4072 if !file.is_local() {
4073 return handle;
4074 }
4075
4076 if ignore_refcounts || *refcount == 1 {
4077 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4078 }
4079 if !ignore_refcounts {
4080 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4081 let refcount = {
4082 let local = lsp_store.as_local_mut().unwrap();
4083 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4084 debug_panic!("bad refcounting");
4085 return;
4086 };
4087
4088 *refcount -= 1;
4089 *refcount
4090 };
4091 if refcount == 0 {
4092 lsp_store.lsp_data.remove(&buffer_id);
4093 let local = lsp_store.as_local_mut().unwrap();
4094 local.registered_buffers.remove(&buffer_id);
4095 local.buffers_opened_in_servers.remove(&buffer_id);
4096 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4097 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4098 }
4099 }
4100 })
4101 .detach();
4102 }
4103 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4104 let buffer_id = buffer.read(cx).remote_id().to_proto();
4105 cx.background_spawn(async move {
4106 upstream_client
4107 .request(proto::RegisterBufferWithLanguageServers {
4108 project_id: upstream_project_id,
4109 buffer_id,
4110 only_servers: only_register_servers
4111 .into_iter()
4112 .map(|selector| {
4113 let selector = match selector {
4114 LanguageServerSelector::Id(language_server_id) => {
4115 proto::language_server_selector::Selector::ServerId(
4116 language_server_id.to_proto(),
4117 )
4118 }
4119 LanguageServerSelector::Name(language_server_name) => {
4120 proto::language_server_selector::Selector::Name(
4121 language_server_name.to_string(),
4122 )
4123 }
4124 };
4125 proto::LanguageServerSelector {
4126 selector: Some(selector),
4127 }
4128 })
4129 .collect(),
4130 })
4131 .await
4132 })
4133 .detach();
4134 } else {
4135 panic!("oops!");
4136 }
4137 handle
4138 }
4139
4140 fn maintain_buffer_languages(
4141 languages: Arc<LanguageRegistry>,
4142 cx: &mut Context<Self>,
4143 ) -> Task<()> {
4144 let mut subscription = languages.subscribe();
4145 let mut prev_reload_count = languages.reload_count();
4146 cx.spawn(async move |this, cx| {
4147 while let Some(()) = subscription.next().await {
4148 if let Some(this) = this.upgrade() {
4149 // If the language registry has been reloaded, then remove and
4150 // re-assign the languages on all open buffers.
4151 let reload_count = languages.reload_count();
4152 if reload_count > prev_reload_count {
4153 prev_reload_count = reload_count;
4154 this.update(cx, |this, cx| {
4155 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4156 for buffer in buffer_store.buffers() {
4157 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4158 {
4159 buffer
4160 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4161 if let Some(local) = this.as_local_mut() {
4162 local.reset_buffer(&buffer, &f, cx);
4163
4164 if local
4165 .registered_buffers
4166 .contains_key(&buffer.read(cx).remote_id())
4167 && let Some(file_url) =
4168 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4169 {
4170 local.unregister_buffer_from_language_servers(
4171 &buffer, &file_url, cx,
4172 );
4173 }
4174 }
4175 }
4176 }
4177 });
4178 })
4179 .ok();
4180 }
4181
4182 this.update(cx, |this, cx| {
4183 let mut plain_text_buffers = Vec::new();
4184 let mut buffers_with_unknown_injections = Vec::new();
4185 for handle in this.buffer_store.read(cx).buffers() {
4186 let buffer = handle.read(cx);
4187 if buffer.language().is_none()
4188 || buffer.language() == Some(&*language::PLAIN_TEXT)
4189 {
4190 plain_text_buffers.push(handle);
4191 } else if buffer.contains_unknown_injections() {
4192 buffers_with_unknown_injections.push(handle);
4193 }
4194 }
4195
4196 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4197 // and reused later in the invisible worktrees.
4198 plain_text_buffers.sort_by_key(|buffer| {
4199 Reverse(
4200 File::from_dyn(buffer.read(cx).file())
4201 .map(|file| file.worktree.read(cx).is_visible()),
4202 )
4203 });
4204
4205 for buffer in plain_text_buffers {
4206 this.detect_language_for_buffer(&buffer, cx);
4207 if let Some(local) = this.as_local_mut() {
4208 local.initialize_buffer(&buffer, cx);
4209 if local
4210 .registered_buffers
4211 .contains_key(&buffer.read(cx).remote_id())
4212 {
4213 local.register_buffer_with_language_servers(
4214 &buffer,
4215 HashSet::default(),
4216 cx,
4217 );
4218 }
4219 }
4220 }
4221
4222 for buffer in buffers_with_unknown_injections {
4223 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4224 }
4225 })
4226 .ok();
4227 }
4228 }
4229 })
4230 }
4231
4232 fn detect_language_for_buffer(
4233 &mut self,
4234 buffer_handle: &Entity<Buffer>,
4235 cx: &mut Context<Self>,
4236 ) -> Option<language::AvailableLanguage> {
4237 // If the buffer has a language, set it and start the language server if we haven't already.
4238 let buffer = buffer_handle.read(cx);
4239 let file = buffer.file()?;
4240
4241 let content = buffer.as_rope();
4242 let available_language = self.languages.language_for_file(file, Some(content), cx);
4243 if let Some(available_language) = &available_language {
4244 if let Some(Ok(Ok(new_language))) = self
4245 .languages
4246 .load_language(available_language)
4247 .now_or_never()
4248 {
4249 self.set_language_for_buffer(buffer_handle, new_language, cx);
4250 }
4251 } else {
4252 cx.emit(LspStoreEvent::LanguageDetected {
4253 buffer: buffer_handle.clone(),
4254 new_language: None,
4255 });
4256 }
4257
4258 available_language
4259 }
4260
4261 pub(crate) fn set_language_for_buffer(
4262 &mut self,
4263 buffer_entity: &Entity<Buffer>,
4264 new_language: Arc<Language>,
4265 cx: &mut Context<Self>,
4266 ) {
4267 let buffer = buffer_entity.read(cx);
4268 let buffer_file = buffer.file().cloned();
4269 let buffer_id = buffer.remote_id();
4270 if let Some(local_store) = self.as_local_mut()
4271 && local_store.registered_buffers.contains_key(&buffer_id)
4272 && let Some(abs_path) =
4273 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4274 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4275 {
4276 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4277 }
4278 buffer_entity.update(cx, |buffer, cx| {
4279 if buffer
4280 .language()
4281 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4282 {
4283 buffer.set_language(Some(new_language.clone()), cx);
4284 }
4285 });
4286
4287 let settings =
4288 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4289 let buffer_file = File::from_dyn(buffer_file.as_ref());
4290
4291 let worktree_id = if let Some(file) = buffer_file {
4292 let worktree = file.worktree.clone();
4293
4294 if let Some(local) = self.as_local_mut()
4295 && local.registered_buffers.contains_key(&buffer_id)
4296 {
4297 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4298 }
4299 Some(worktree.read(cx).id())
4300 } else {
4301 None
4302 };
4303
4304 if settings.prettier.allowed
4305 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4306 {
4307 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4308 if let Some(prettier_store) = prettier_store {
4309 prettier_store.update(cx, |prettier_store, cx| {
4310 prettier_store.install_default_prettier(
4311 worktree_id,
4312 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4313 cx,
4314 )
4315 })
4316 }
4317 }
4318
4319 cx.emit(LspStoreEvent::LanguageDetected {
4320 buffer: buffer_entity.clone(),
4321 new_language: Some(new_language),
4322 })
4323 }
4324
4325 pub fn buffer_store(&self) -> Entity<BufferStore> {
4326 self.buffer_store.clone()
4327 }
4328
4329 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4330 self.active_entry = active_entry;
4331 }
4332
4333 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4334 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4335 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4336 {
4337 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4338 summaries
4339 .iter()
4340 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4341 });
4342 if let Some(summary) = summaries.next() {
4343 client
4344 .send(proto::UpdateDiagnosticSummary {
4345 project_id: downstream_project_id,
4346 worktree_id: worktree.id().to_proto(),
4347 summary: Some(summary),
4348 more_summaries: summaries.collect(),
4349 })
4350 .log_err();
4351 }
4352 }
4353 }
4354
4355 fn is_capable_for_proto_request<R>(
4356 &self,
4357 buffer: &Entity<Buffer>,
4358 request: &R,
4359 cx: &App,
4360 ) -> bool
4361 where
4362 R: LspCommand,
4363 {
4364 self.check_if_capable_for_proto_request(
4365 buffer,
4366 |capabilities| {
4367 request.check_capabilities(AdapterServerCapabilities {
4368 server_capabilities: capabilities.clone(),
4369 code_action_kinds: None,
4370 })
4371 },
4372 cx,
4373 )
4374 }
4375
4376 fn check_if_capable_for_proto_request<F>(
4377 &self,
4378 buffer: &Entity<Buffer>,
4379 check: F,
4380 cx: &App,
4381 ) -> bool
4382 where
4383 F: FnMut(&lsp::ServerCapabilities) -> bool,
4384 {
4385 let Some(language) = buffer.read(cx).language().cloned() else {
4386 return false;
4387 };
4388 let relevant_language_servers = self
4389 .languages
4390 .lsp_adapters(&language.name())
4391 .into_iter()
4392 .map(|lsp_adapter| lsp_adapter.name())
4393 .collect::<HashSet<_>>();
4394 self.language_server_statuses
4395 .iter()
4396 .filter_map(|(server_id, server_status)| {
4397 relevant_language_servers
4398 .contains(&server_status.name)
4399 .then_some(server_id)
4400 })
4401 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4402 .any(check)
4403 }
4404
4405 pub fn request_lsp<R>(
4406 &mut self,
4407 buffer: Entity<Buffer>,
4408 server: LanguageServerToQuery,
4409 request: R,
4410 cx: &mut Context<Self>,
4411 ) -> Task<Result<R::Response>>
4412 where
4413 R: LspCommand,
4414 <R::LspRequest as lsp::request::Request>::Result: Send,
4415 <R::LspRequest as lsp::request::Request>::Params: Send,
4416 {
4417 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4418 return self.send_lsp_proto_request(
4419 buffer,
4420 upstream_client,
4421 upstream_project_id,
4422 request,
4423 cx,
4424 );
4425 }
4426
4427 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4428 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4429 local
4430 .language_servers_for_buffer(buffer, cx)
4431 .find(|(_, server)| {
4432 request.check_capabilities(server.adapter_server_capabilities())
4433 })
4434 .map(|(_, server)| server.clone())
4435 }),
4436 LanguageServerToQuery::Other(id) => self
4437 .language_server_for_local_buffer(buffer, id, cx)
4438 .and_then(|(_, server)| {
4439 request
4440 .check_capabilities(server.adapter_server_capabilities())
4441 .then(|| Arc::clone(server))
4442 }),
4443 }) else {
4444 return Task::ready(Ok(Default::default()));
4445 };
4446
4447 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4448
4449 let Some(file) = file else {
4450 return Task::ready(Ok(Default::default()));
4451 };
4452
4453 let lsp_params = match request.to_lsp_params_or_response(
4454 &file.abs_path(cx),
4455 buffer.read(cx),
4456 &language_server,
4457 cx,
4458 ) {
4459 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4460 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4461
4462 Err(err) => {
4463 let message = format!(
4464 "{} via {} failed: {}",
4465 request.display_name(),
4466 language_server.name(),
4467 err
4468 );
4469 log::warn!("{message}");
4470 return Task::ready(Err(anyhow!(message)));
4471 }
4472 };
4473
4474 let status = request.status();
4475 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4476 return Task::ready(Ok(Default::default()));
4477 }
4478 cx.spawn(async move |this, cx| {
4479 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4480
4481 let id = lsp_request.id();
4482 let _cleanup = if status.is_some() {
4483 cx.update(|cx| {
4484 this.update(cx, |this, cx| {
4485 this.on_lsp_work_start(
4486 language_server.server_id(),
4487 id.to_string(),
4488 LanguageServerProgress {
4489 is_disk_based_diagnostics_progress: false,
4490 is_cancellable: false,
4491 title: None,
4492 message: status.clone(),
4493 percentage: None,
4494 last_update_at: cx.background_executor().now(),
4495 },
4496 cx,
4497 );
4498 })
4499 })
4500 .log_err();
4501
4502 Some(defer(|| {
4503 cx.update(|cx| {
4504 this.update(cx, |this, cx| {
4505 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4506 })
4507 })
4508 .log_err();
4509 }))
4510 } else {
4511 None
4512 };
4513
4514 let result = lsp_request.await.into_response();
4515
4516 let response = result.map_err(|err| {
4517 let message = format!(
4518 "{} via {} failed: {}",
4519 request.display_name(),
4520 language_server.name(),
4521 err
4522 );
4523 log::warn!("{message}");
4524 anyhow::anyhow!(message)
4525 })?;
4526
4527 request
4528 .response_from_lsp(
4529 response,
4530 this.upgrade().context("no app context")?,
4531 buffer,
4532 language_server.server_id(),
4533 cx.clone(),
4534 )
4535 .await
4536 })
4537 }
4538
4539 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4540 let mut language_formatters_to_check = Vec::new();
4541 for buffer in self.buffer_store.read(cx).buffers() {
4542 let buffer = buffer.read(cx);
4543 let buffer_file = File::from_dyn(buffer.file());
4544 let buffer_language = buffer.language();
4545 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4546 if buffer_language.is_some() {
4547 language_formatters_to_check.push((
4548 buffer_file.map(|f| f.worktree_id(cx)),
4549 settings.into_owned(),
4550 ));
4551 }
4552 }
4553
4554 self.request_workspace_config_refresh();
4555
4556 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4557 prettier_store.update(cx, |prettier_store, cx| {
4558 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4559 })
4560 }
4561
4562 cx.notify();
4563 }
4564
4565 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4566 let buffer_store = self.buffer_store.clone();
4567 let Some(local) = self.as_local_mut() else {
4568 return;
4569 };
4570 let mut adapters = BTreeMap::default();
4571 let get_adapter = {
4572 let languages = local.languages.clone();
4573 let environment = local.environment.clone();
4574 let weak = local.weak.clone();
4575 let worktree_store = local.worktree_store.clone();
4576 let http_client = local.http_client.clone();
4577 let fs = local.fs.clone();
4578 move |worktree_id, cx: &mut App| {
4579 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4580 Some(LocalLspAdapterDelegate::new(
4581 languages.clone(),
4582 &environment,
4583 weak.clone(),
4584 &worktree,
4585 http_client.clone(),
4586 fs.clone(),
4587 cx,
4588 ))
4589 }
4590 };
4591
4592 let mut messages_to_report = Vec::new();
4593 let (new_tree, to_stop) = {
4594 let mut rebase = local.lsp_tree.rebase();
4595 let buffers = buffer_store
4596 .read(cx)
4597 .buffers()
4598 .filter_map(|buffer| {
4599 let raw_buffer = buffer.read(cx);
4600 if !local
4601 .registered_buffers
4602 .contains_key(&raw_buffer.remote_id())
4603 {
4604 return None;
4605 }
4606 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4607 let language = raw_buffer.language().cloned()?;
4608 Some((file, language, raw_buffer.remote_id()))
4609 })
4610 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4611 for (file, language, buffer_id) in buffers {
4612 let worktree_id = file.worktree_id(cx);
4613 let Some(worktree) = local
4614 .worktree_store
4615 .read(cx)
4616 .worktree_for_id(worktree_id, cx)
4617 else {
4618 continue;
4619 };
4620
4621 if let Some((_, apply)) = local.reuse_existing_language_server(
4622 rebase.server_tree(),
4623 &worktree,
4624 &language.name(),
4625 cx,
4626 ) {
4627 (apply)(rebase.server_tree());
4628 } else if let Some(lsp_delegate) = adapters
4629 .entry(worktree_id)
4630 .or_insert_with(|| get_adapter(worktree_id, cx))
4631 .clone()
4632 {
4633 let delegate =
4634 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4635 let path = file
4636 .path()
4637 .parent()
4638 .map(Arc::from)
4639 .unwrap_or_else(|| file.path().clone());
4640 let worktree_path = ProjectPath { worktree_id, path };
4641 let abs_path = file.abs_path(cx);
4642 let nodes = rebase
4643 .walk(
4644 worktree_path,
4645 language.name(),
4646 language.manifest(),
4647 delegate.clone(),
4648 cx,
4649 )
4650 .collect::<Vec<_>>();
4651 for node in nodes {
4652 let server_id = node.server_id_or_init(|disposition| {
4653 let path = &disposition.path;
4654 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4655 let key = LanguageServerSeed {
4656 worktree_id,
4657 name: disposition.server_name.clone(),
4658 settings: disposition.settings.clone(),
4659 toolchain: local.toolchain_store.read(cx).active_toolchain(
4660 path.worktree_id,
4661 &path.path,
4662 language.name(),
4663 ),
4664 };
4665 local.language_server_ids.remove(&key);
4666
4667 let server_id = local.get_or_insert_language_server(
4668 &worktree,
4669 lsp_delegate.clone(),
4670 disposition,
4671 &language.name(),
4672 cx,
4673 );
4674 if let Some(state) = local.language_servers.get(&server_id)
4675 && let Ok(uri) = uri
4676 {
4677 state.add_workspace_folder(uri);
4678 };
4679 server_id
4680 });
4681
4682 if let Some(language_server_id) = server_id {
4683 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4684 language_server_id,
4685 name: node.name(),
4686 message:
4687 proto::update_language_server::Variant::RegisteredForBuffer(
4688 proto::RegisteredForBuffer {
4689 buffer_abs_path: abs_path
4690 .to_string_lossy()
4691 .into_owned(),
4692 buffer_id: buffer_id.to_proto(),
4693 },
4694 ),
4695 });
4696 }
4697 }
4698 } else {
4699 continue;
4700 }
4701 }
4702 rebase.finish()
4703 };
4704 for message in messages_to_report {
4705 cx.emit(message);
4706 }
4707 local.lsp_tree = new_tree;
4708 for (id, _) in to_stop {
4709 self.stop_local_language_server(id, cx).detach();
4710 }
4711 }
4712
4713 pub fn apply_code_action(
4714 &self,
4715 buffer_handle: Entity<Buffer>,
4716 mut action: CodeAction,
4717 push_to_history: bool,
4718 cx: &mut Context<Self>,
4719 ) -> Task<Result<ProjectTransaction>> {
4720 if let Some((upstream_client, project_id)) = self.upstream_client() {
4721 let request = proto::ApplyCodeAction {
4722 project_id,
4723 buffer_id: buffer_handle.read(cx).remote_id().into(),
4724 action: Some(Self::serialize_code_action(&action)),
4725 };
4726 let buffer_store = self.buffer_store();
4727 cx.spawn(async move |_, cx| {
4728 let response = upstream_client
4729 .request(request)
4730 .await?
4731 .transaction
4732 .context("missing transaction")?;
4733
4734 buffer_store
4735 .update(cx, |buffer_store, cx| {
4736 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4737 })?
4738 .await
4739 })
4740 } else if self.mode.is_local() {
4741 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4742 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4743 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4744 }) else {
4745 return Task::ready(Ok(ProjectTransaction::default()));
4746 };
4747 cx.spawn(async move |this, cx| {
4748 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4749 .await
4750 .context("resolving a code action")?;
4751 if let Some(edit) = action.lsp_action.edit()
4752 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4753 return LocalLspStore::deserialize_workspace_edit(
4754 this.upgrade().context("no app present")?,
4755 edit.clone(),
4756 push_to_history,
4757
4758 lang_server.clone(),
4759 cx,
4760 )
4761 .await;
4762 }
4763
4764 if let Some(command) = action.lsp_action.command() {
4765 let server_capabilities = lang_server.capabilities();
4766 let available_commands = server_capabilities
4767 .execute_command_provider
4768 .as_ref()
4769 .map(|options| options.commands.as_slice())
4770 .unwrap_or_default();
4771 if available_commands.contains(&command.command) {
4772 this.update(cx, |this, _| {
4773 this.as_local_mut()
4774 .unwrap()
4775 .last_workspace_edits_by_language_server
4776 .remove(&lang_server.server_id());
4777 })?;
4778
4779 let _result = lang_server
4780 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4781 command: command.command.clone(),
4782 arguments: command.arguments.clone().unwrap_or_default(),
4783 ..lsp::ExecuteCommandParams::default()
4784 })
4785 .await.into_response()
4786 .context("execute command")?;
4787
4788 return this.update(cx, |this, _| {
4789 this.as_local_mut()
4790 .unwrap()
4791 .last_workspace_edits_by_language_server
4792 .remove(&lang_server.server_id())
4793 .unwrap_or_default()
4794 });
4795 } else {
4796 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4797 }
4798 }
4799
4800 Ok(ProjectTransaction::default())
4801 })
4802 } else {
4803 Task::ready(Err(anyhow!("no upstream client and not local")))
4804 }
4805 }
4806
4807 pub fn apply_code_action_kind(
4808 &mut self,
4809 buffers: HashSet<Entity<Buffer>>,
4810 kind: CodeActionKind,
4811 push_to_history: bool,
4812 cx: &mut Context<Self>,
4813 ) -> Task<anyhow::Result<ProjectTransaction>> {
4814 if self.as_local().is_some() {
4815 cx.spawn(async move |lsp_store, cx| {
4816 let buffers = buffers.into_iter().collect::<Vec<_>>();
4817 let result = LocalLspStore::execute_code_action_kind_locally(
4818 lsp_store.clone(),
4819 buffers,
4820 kind,
4821 push_to_history,
4822 cx,
4823 )
4824 .await;
4825 lsp_store.update(cx, |lsp_store, _| {
4826 lsp_store.update_last_formatting_failure(&result);
4827 })?;
4828 result
4829 })
4830 } else if let Some((client, project_id)) = self.upstream_client() {
4831 let buffer_store = self.buffer_store();
4832 cx.spawn(async move |lsp_store, cx| {
4833 let result = client
4834 .request(proto::ApplyCodeActionKind {
4835 project_id,
4836 kind: kind.as_str().to_owned(),
4837 buffer_ids: buffers
4838 .iter()
4839 .map(|buffer| {
4840 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4841 })
4842 .collect::<Result<_>>()?,
4843 })
4844 .await
4845 .and_then(|result| result.transaction.context("missing transaction"));
4846 lsp_store.update(cx, |lsp_store, _| {
4847 lsp_store.update_last_formatting_failure(&result);
4848 })?;
4849
4850 let transaction_response = result?;
4851 buffer_store
4852 .update(cx, |buffer_store, cx| {
4853 buffer_store.deserialize_project_transaction(
4854 transaction_response,
4855 push_to_history,
4856 cx,
4857 )
4858 })?
4859 .await
4860 })
4861 } else {
4862 Task::ready(Ok(ProjectTransaction::default()))
4863 }
4864 }
4865
4866 pub fn resolved_hint(
4867 &mut self,
4868 buffer_id: BufferId,
4869 id: InlayId,
4870 cx: &mut Context<Self>,
4871 ) -> Option<ResolvedHint> {
4872 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4873
4874 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4875 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4876 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4877 let (server_id, resolve_data) = match &hint.resolve_state {
4878 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4879 ResolveState::Resolving => {
4880 return Some(ResolvedHint::Resolving(
4881 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4882 ));
4883 }
4884 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4885 };
4886
4887 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4888 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4889 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4890 id,
4891 cx.spawn(async move |lsp_store, cx| {
4892 let resolved_hint = resolve_task.await;
4893 lsp_store
4894 .update(cx, |lsp_store, _| {
4895 if let Some(old_inlay_hint) = lsp_store
4896 .lsp_data
4897 .get_mut(&buffer_id)
4898 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4899 {
4900 match resolved_hint {
4901 Ok(resolved_hint) => {
4902 *old_inlay_hint = resolved_hint;
4903 }
4904 Err(e) => {
4905 old_inlay_hint.resolve_state =
4906 ResolveState::CanResolve(server_id, resolve_data);
4907 log::error!("Inlay hint resolve failed: {e:#}");
4908 }
4909 }
4910 }
4911 })
4912 .ok();
4913 })
4914 .shared(),
4915 );
4916 debug_assert!(
4917 previous_task.is_none(),
4918 "Did not change hint's resolve state after spawning its resolve"
4919 );
4920 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4921 None
4922 }
4923
4924 fn resolve_inlay_hint(
4925 &self,
4926 mut hint: InlayHint,
4927 buffer: Entity<Buffer>,
4928 server_id: LanguageServerId,
4929 cx: &mut Context<Self>,
4930 ) -> Task<anyhow::Result<InlayHint>> {
4931 if let Some((upstream_client, project_id)) = self.upstream_client() {
4932 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4933 {
4934 hint.resolve_state = ResolveState::Resolved;
4935 return Task::ready(Ok(hint));
4936 }
4937 let request = proto::ResolveInlayHint {
4938 project_id,
4939 buffer_id: buffer.read(cx).remote_id().into(),
4940 language_server_id: server_id.0 as u64,
4941 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4942 };
4943 cx.background_spawn(async move {
4944 let response = upstream_client
4945 .request(request)
4946 .await
4947 .context("inlay hints proto request")?;
4948 match response.hint {
4949 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4950 .context("inlay hints proto resolve response conversion"),
4951 None => Ok(hint),
4952 }
4953 })
4954 } else {
4955 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4956 self.language_server_for_local_buffer(buffer, server_id, cx)
4957 .map(|(_, server)| server.clone())
4958 }) else {
4959 return Task::ready(Ok(hint));
4960 };
4961 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4962 return Task::ready(Ok(hint));
4963 }
4964 let buffer_snapshot = buffer.read(cx).snapshot();
4965 cx.spawn(async move |_, cx| {
4966 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4967 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4968 );
4969 let resolved_hint = resolve_task
4970 .await
4971 .into_response()
4972 .context("inlay hint resolve LSP request")?;
4973 let resolved_hint = InlayHints::lsp_to_project_hint(
4974 resolved_hint,
4975 &buffer,
4976 server_id,
4977 ResolveState::Resolved,
4978 false,
4979 cx,
4980 )
4981 .await?;
4982 Ok(resolved_hint)
4983 })
4984 }
4985 }
4986
4987 pub fn resolve_color_presentation(
4988 &mut self,
4989 mut color: DocumentColor,
4990 buffer: Entity<Buffer>,
4991 server_id: LanguageServerId,
4992 cx: &mut Context<Self>,
4993 ) -> Task<Result<DocumentColor>> {
4994 if color.resolved {
4995 return Task::ready(Ok(color));
4996 }
4997
4998 if let Some((upstream_client, project_id)) = self.upstream_client() {
4999 let start = color.lsp_range.start;
5000 let end = color.lsp_range.end;
5001 let request = proto::GetColorPresentation {
5002 project_id,
5003 server_id: server_id.to_proto(),
5004 buffer_id: buffer.read(cx).remote_id().into(),
5005 color: Some(proto::ColorInformation {
5006 red: color.color.red,
5007 green: color.color.green,
5008 blue: color.color.blue,
5009 alpha: color.color.alpha,
5010 lsp_range_start: Some(proto::PointUtf16 {
5011 row: start.line,
5012 column: start.character,
5013 }),
5014 lsp_range_end: Some(proto::PointUtf16 {
5015 row: end.line,
5016 column: end.character,
5017 }),
5018 }),
5019 };
5020 cx.background_spawn(async move {
5021 let response = upstream_client
5022 .request(request)
5023 .await
5024 .context("color presentation proto request")?;
5025 color.resolved = true;
5026 color.color_presentations = response
5027 .presentations
5028 .into_iter()
5029 .map(|presentation| ColorPresentation {
5030 label: SharedString::from(presentation.label),
5031 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5032 additional_text_edits: presentation
5033 .additional_text_edits
5034 .into_iter()
5035 .filter_map(deserialize_lsp_edit)
5036 .collect(),
5037 })
5038 .collect();
5039 Ok(color)
5040 })
5041 } else {
5042 let path = match buffer
5043 .update(cx, |buffer, cx| {
5044 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5045 })
5046 .context("buffer with the missing path")
5047 {
5048 Ok(path) => path,
5049 Err(e) => return Task::ready(Err(e)),
5050 };
5051 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5052 self.language_server_for_local_buffer(buffer, server_id, cx)
5053 .map(|(_, server)| server.clone())
5054 }) else {
5055 return Task::ready(Ok(color));
5056 };
5057 cx.background_spawn(async move {
5058 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5059 lsp::ColorPresentationParams {
5060 text_document: make_text_document_identifier(&path)?,
5061 color: color.color,
5062 range: color.lsp_range,
5063 work_done_progress_params: Default::default(),
5064 partial_result_params: Default::default(),
5065 },
5066 );
5067 color.color_presentations = resolve_task
5068 .await
5069 .into_response()
5070 .context("color presentation resolve LSP request")?
5071 .into_iter()
5072 .map(|presentation| ColorPresentation {
5073 label: SharedString::from(presentation.label),
5074 text_edit: presentation.text_edit,
5075 additional_text_edits: presentation
5076 .additional_text_edits
5077 .unwrap_or_default(),
5078 })
5079 .collect();
5080 color.resolved = true;
5081 Ok(color)
5082 })
5083 }
5084 }
5085
5086 pub(crate) fn linked_edits(
5087 &mut self,
5088 buffer: &Entity<Buffer>,
5089 position: Anchor,
5090 cx: &mut Context<Self>,
5091 ) -> Task<Result<Vec<Range<Anchor>>>> {
5092 let snapshot = buffer.read(cx).snapshot();
5093 let scope = snapshot.language_scope_at(position);
5094 let Some(server_id) = self
5095 .as_local()
5096 .and_then(|local| {
5097 buffer.update(cx, |buffer, cx| {
5098 local
5099 .language_servers_for_buffer(buffer, cx)
5100 .filter(|(_, server)| {
5101 LinkedEditingRange::check_server_capabilities(server.capabilities())
5102 })
5103 .filter(|(adapter, _)| {
5104 scope
5105 .as_ref()
5106 .map(|scope| scope.language_allowed(&adapter.name))
5107 .unwrap_or(true)
5108 })
5109 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5110 .next()
5111 })
5112 })
5113 .or_else(|| {
5114 self.upstream_client()
5115 .is_some()
5116 .then_some(LanguageServerToQuery::FirstCapable)
5117 })
5118 .filter(|_| {
5119 maybe!({
5120 let language = buffer.read(cx).language_at(position)?;
5121 Some(
5122 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5123 .linked_edits,
5124 )
5125 }) == Some(true)
5126 })
5127 else {
5128 return Task::ready(Ok(Vec::new()));
5129 };
5130
5131 self.request_lsp(
5132 buffer.clone(),
5133 server_id,
5134 LinkedEditingRange { position },
5135 cx,
5136 )
5137 }
5138
5139 fn apply_on_type_formatting(
5140 &mut self,
5141 buffer: Entity<Buffer>,
5142 position: Anchor,
5143 trigger: String,
5144 cx: &mut Context<Self>,
5145 ) -> Task<Result<Option<Transaction>>> {
5146 if let Some((client, project_id)) = self.upstream_client() {
5147 if !self.check_if_capable_for_proto_request(
5148 &buffer,
5149 |capabilities| {
5150 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5151 },
5152 cx,
5153 ) {
5154 return Task::ready(Ok(None));
5155 }
5156 let request = proto::OnTypeFormatting {
5157 project_id,
5158 buffer_id: buffer.read(cx).remote_id().into(),
5159 position: Some(serialize_anchor(&position)),
5160 trigger,
5161 version: serialize_version(&buffer.read(cx).version()),
5162 };
5163 cx.background_spawn(async move {
5164 client
5165 .request(request)
5166 .await?
5167 .transaction
5168 .map(language::proto::deserialize_transaction)
5169 .transpose()
5170 })
5171 } else if let Some(local) = self.as_local_mut() {
5172 let buffer_id = buffer.read(cx).remote_id();
5173 local.buffers_being_formatted.insert(buffer_id);
5174 cx.spawn(async move |this, cx| {
5175 let _cleanup = defer({
5176 let this = this.clone();
5177 let mut cx = cx.clone();
5178 move || {
5179 this.update(&mut cx, |this, _| {
5180 if let Some(local) = this.as_local_mut() {
5181 local.buffers_being_formatted.remove(&buffer_id);
5182 }
5183 })
5184 .ok();
5185 }
5186 });
5187
5188 buffer
5189 .update(cx, |buffer, _| {
5190 buffer.wait_for_edits(Some(position.timestamp))
5191 })?
5192 .await?;
5193 this.update(cx, |this, cx| {
5194 let position = position.to_point_utf16(buffer.read(cx));
5195 this.on_type_format(buffer, position, trigger, false, cx)
5196 })?
5197 .await
5198 })
5199 } else {
5200 Task::ready(Err(anyhow!("No upstream client or local language server")))
5201 }
5202 }
5203
5204 pub fn on_type_format<T: ToPointUtf16>(
5205 &mut self,
5206 buffer: Entity<Buffer>,
5207 position: T,
5208 trigger: String,
5209 push_to_history: bool,
5210 cx: &mut Context<Self>,
5211 ) -> Task<Result<Option<Transaction>>> {
5212 let position = position.to_point_utf16(buffer.read(cx));
5213 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5214 }
5215
5216 fn on_type_format_impl(
5217 &mut self,
5218 buffer: Entity<Buffer>,
5219 position: PointUtf16,
5220 trigger: String,
5221 push_to_history: bool,
5222 cx: &mut Context<Self>,
5223 ) -> Task<Result<Option<Transaction>>> {
5224 let options = buffer.update(cx, |buffer, cx| {
5225 lsp_command::lsp_formatting_options(
5226 language_settings(
5227 buffer.language_at(position).map(|l| l.name()),
5228 buffer.file(),
5229 cx,
5230 )
5231 .as_ref(),
5232 )
5233 });
5234
5235 cx.spawn(async move |this, cx| {
5236 if let Some(waiter) =
5237 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5238 {
5239 waiter.await?;
5240 }
5241 cx.update(|cx| {
5242 this.update(cx, |this, cx| {
5243 this.request_lsp(
5244 buffer.clone(),
5245 LanguageServerToQuery::FirstCapable,
5246 OnTypeFormatting {
5247 position,
5248 trigger,
5249 options,
5250 push_to_history,
5251 },
5252 cx,
5253 )
5254 })
5255 })??
5256 .await
5257 })
5258 }
5259
5260 pub fn definitions(
5261 &mut self,
5262 buffer: &Entity<Buffer>,
5263 position: PointUtf16,
5264 cx: &mut Context<Self>,
5265 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5266 if let Some((upstream_client, project_id)) = self.upstream_client() {
5267 let request = GetDefinitions { position };
5268 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5269 return Task::ready(Ok(None));
5270 }
5271 let request_task = upstream_client.request_lsp(
5272 project_id,
5273 None,
5274 LSP_REQUEST_TIMEOUT,
5275 cx.background_executor().clone(),
5276 request.to_proto(project_id, buffer.read(cx)),
5277 );
5278 let buffer = buffer.clone();
5279 cx.spawn(async move |weak_project, cx| {
5280 let Some(project) = weak_project.upgrade() else {
5281 return Ok(None);
5282 };
5283 let Some(responses) = request_task.await? else {
5284 return Ok(None);
5285 };
5286 let actions = join_all(responses.payload.into_iter().map(|response| {
5287 GetDefinitions { position }.response_from_proto(
5288 response.response,
5289 project.clone(),
5290 buffer.clone(),
5291 cx.clone(),
5292 )
5293 }))
5294 .await;
5295
5296 Ok(Some(
5297 actions
5298 .into_iter()
5299 .collect::<Result<Vec<Vec<_>>>>()?
5300 .into_iter()
5301 .flatten()
5302 .dedup()
5303 .collect(),
5304 ))
5305 })
5306 } else {
5307 let definitions_task = self.request_multiple_lsp_locally(
5308 buffer,
5309 Some(position),
5310 GetDefinitions { position },
5311 cx,
5312 );
5313 cx.background_spawn(async move {
5314 Ok(Some(
5315 definitions_task
5316 .await
5317 .into_iter()
5318 .flat_map(|(_, definitions)| definitions)
5319 .dedup()
5320 .collect(),
5321 ))
5322 })
5323 }
5324 }
5325
5326 pub fn declarations(
5327 &mut self,
5328 buffer: &Entity<Buffer>,
5329 position: PointUtf16,
5330 cx: &mut Context<Self>,
5331 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5332 if let Some((upstream_client, project_id)) = self.upstream_client() {
5333 let request = GetDeclarations { position };
5334 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5335 return Task::ready(Ok(None));
5336 }
5337 let request_task = upstream_client.request_lsp(
5338 project_id,
5339 None,
5340 LSP_REQUEST_TIMEOUT,
5341 cx.background_executor().clone(),
5342 request.to_proto(project_id, buffer.read(cx)),
5343 );
5344 let buffer = buffer.clone();
5345 cx.spawn(async move |weak_project, cx| {
5346 let Some(project) = weak_project.upgrade() else {
5347 return Ok(None);
5348 };
5349 let Some(responses) = request_task.await? else {
5350 return Ok(None);
5351 };
5352 let actions = join_all(responses.payload.into_iter().map(|response| {
5353 GetDeclarations { position }.response_from_proto(
5354 response.response,
5355 project.clone(),
5356 buffer.clone(),
5357 cx.clone(),
5358 )
5359 }))
5360 .await;
5361
5362 Ok(Some(
5363 actions
5364 .into_iter()
5365 .collect::<Result<Vec<Vec<_>>>>()?
5366 .into_iter()
5367 .flatten()
5368 .dedup()
5369 .collect(),
5370 ))
5371 })
5372 } else {
5373 let declarations_task = self.request_multiple_lsp_locally(
5374 buffer,
5375 Some(position),
5376 GetDeclarations { position },
5377 cx,
5378 );
5379 cx.background_spawn(async move {
5380 Ok(Some(
5381 declarations_task
5382 .await
5383 .into_iter()
5384 .flat_map(|(_, declarations)| declarations)
5385 .dedup()
5386 .collect(),
5387 ))
5388 })
5389 }
5390 }
5391
5392 pub fn type_definitions(
5393 &mut self,
5394 buffer: &Entity<Buffer>,
5395 position: PointUtf16,
5396 cx: &mut Context<Self>,
5397 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5398 if let Some((upstream_client, project_id)) = self.upstream_client() {
5399 let request = GetTypeDefinitions { position };
5400 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5401 return Task::ready(Ok(None));
5402 }
5403 let request_task = upstream_client.request_lsp(
5404 project_id,
5405 None,
5406 LSP_REQUEST_TIMEOUT,
5407 cx.background_executor().clone(),
5408 request.to_proto(project_id, buffer.read(cx)),
5409 );
5410 let buffer = buffer.clone();
5411 cx.spawn(async move |weak_project, cx| {
5412 let Some(project) = weak_project.upgrade() else {
5413 return Ok(None);
5414 };
5415 let Some(responses) = request_task.await? else {
5416 return Ok(None);
5417 };
5418 let actions = join_all(responses.payload.into_iter().map(|response| {
5419 GetTypeDefinitions { position }.response_from_proto(
5420 response.response,
5421 project.clone(),
5422 buffer.clone(),
5423 cx.clone(),
5424 )
5425 }))
5426 .await;
5427
5428 Ok(Some(
5429 actions
5430 .into_iter()
5431 .collect::<Result<Vec<Vec<_>>>>()?
5432 .into_iter()
5433 .flatten()
5434 .dedup()
5435 .collect(),
5436 ))
5437 })
5438 } else {
5439 let type_definitions_task = self.request_multiple_lsp_locally(
5440 buffer,
5441 Some(position),
5442 GetTypeDefinitions { position },
5443 cx,
5444 );
5445 cx.background_spawn(async move {
5446 Ok(Some(
5447 type_definitions_task
5448 .await
5449 .into_iter()
5450 .flat_map(|(_, type_definitions)| type_definitions)
5451 .dedup()
5452 .collect(),
5453 ))
5454 })
5455 }
5456 }
5457
5458 pub fn implementations(
5459 &mut self,
5460 buffer: &Entity<Buffer>,
5461 position: PointUtf16,
5462 cx: &mut Context<Self>,
5463 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5464 if let Some((upstream_client, project_id)) = self.upstream_client() {
5465 let request = GetImplementations { position };
5466 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5467 return Task::ready(Ok(None));
5468 }
5469 let request_task = upstream_client.request_lsp(
5470 project_id,
5471 None,
5472 LSP_REQUEST_TIMEOUT,
5473 cx.background_executor().clone(),
5474 request.to_proto(project_id, buffer.read(cx)),
5475 );
5476 let buffer = buffer.clone();
5477 cx.spawn(async move |weak_project, cx| {
5478 let Some(project) = weak_project.upgrade() else {
5479 return Ok(None);
5480 };
5481 let Some(responses) = request_task.await? else {
5482 return Ok(None);
5483 };
5484 let actions = join_all(responses.payload.into_iter().map(|response| {
5485 GetImplementations { position }.response_from_proto(
5486 response.response,
5487 project.clone(),
5488 buffer.clone(),
5489 cx.clone(),
5490 )
5491 }))
5492 .await;
5493
5494 Ok(Some(
5495 actions
5496 .into_iter()
5497 .collect::<Result<Vec<Vec<_>>>>()?
5498 .into_iter()
5499 .flatten()
5500 .dedup()
5501 .collect(),
5502 ))
5503 })
5504 } else {
5505 let implementations_task = self.request_multiple_lsp_locally(
5506 buffer,
5507 Some(position),
5508 GetImplementations { position },
5509 cx,
5510 );
5511 cx.background_spawn(async move {
5512 Ok(Some(
5513 implementations_task
5514 .await
5515 .into_iter()
5516 .flat_map(|(_, implementations)| implementations)
5517 .dedup()
5518 .collect(),
5519 ))
5520 })
5521 }
5522 }
5523
5524 pub fn references(
5525 &mut self,
5526 buffer: &Entity<Buffer>,
5527 position: PointUtf16,
5528 cx: &mut Context<Self>,
5529 ) -> Task<Result<Option<Vec<Location>>>> {
5530 if let Some((upstream_client, project_id)) = self.upstream_client() {
5531 let request = GetReferences { position };
5532 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5533 return Task::ready(Ok(None));
5534 }
5535
5536 let request_task = upstream_client.request_lsp(
5537 project_id,
5538 None,
5539 LSP_REQUEST_TIMEOUT,
5540 cx.background_executor().clone(),
5541 request.to_proto(project_id, buffer.read(cx)),
5542 );
5543 let buffer = buffer.clone();
5544 cx.spawn(async move |weak_project, cx| {
5545 let Some(project) = weak_project.upgrade() else {
5546 return Ok(None);
5547 };
5548 let Some(responses) = request_task.await? else {
5549 return Ok(None);
5550 };
5551
5552 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5553 GetReferences { position }.response_from_proto(
5554 lsp_response.response,
5555 project.clone(),
5556 buffer.clone(),
5557 cx.clone(),
5558 )
5559 }))
5560 .await
5561 .into_iter()
5562 .collect::<Result<Vec<Vec<_>>>>()?
5563 .into_iter()
5564 .flatten()
5565 .dedup()
5566 .collect();
5567 Ok(Some(locations))
5568 })
5569 } else {
5570 let references_task = self.request_multiple_lsp_locally(
5571 buffer,
5572 Some(position),
5573 GetReferences { position },
5574 cx,
5575 );
5576 cx.background_spawn(async move {
5577 Ok(Some(
5578 references_task
5579 .await
5580 .into_iter()
5581 .flat_map(|(_, references)| references)
5582 .dedup()
5583 .collect(),
5584 ))
5585 })
5586 }
5587 }
5588
5589 pub fn code_actions(
5590 &mut self,
5591 buffer: &Entity<Buffer>,
5592 range: Range<Anchor>,
5593 kinds: Option<Vec<CodeActionKind>>,
5594 cx: &mut Context<Self>,
5595 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5596 if let Some((upstream_client, project_id)) = self.upstream_client() {
5597 let request = GetCodeActions {
5598 range: range.clone(),
5599 kinds: kinds.clone(),
5600 };
5601 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5602 return Task::ready(Ok(None));
5603 }
5604 let request_task = upstream_client.request_lsp(
5605 project_id,
5606 None,
5607 LSP_REQUEST_TIMEOUT,
5608 cx.background_executor().clone(),
5609 request.to_proto(project_id, buffer.read(cx)),
5610 );
5611 let buffer = buffer.clone();
5612 cx.spawn(async move |weak_project, cx| {
5613 let Some(project) = weak_project.upgrade() else {
5614 return Ok(None);
5615 };
5616 let Some(responses) = request_task.await? else {
5617 return Ok(None);
5618 };
5619 let actions = join_all(responses.payload.into_iter().map(|response| {
5620 GetCodeActions {
5621 range: range.clone(),
5622 kinds: kinds.clone(),
5623 }
5624 .response_from_proto(
5625 response.response,
5626 project.clone(),
5627 buffer.clone(),
5628 cx.clone(),
5629 )
5630 }))
5631 .await;
5632
5633 Ok(Some(
5634 actions
5635 .into_iter()
5636 .collect::<Result<Vec<Vec<_>>>>()?
5637 .into_iter()
5638 .flatten()
5639 .collect(),
5640 ))
5641 })
5642 } else {
5643 let all_actions_task = self.request_multiple_lsp_locally(
5644 buffer,
5645 Some(range.start),
5646 GetCodeActions { range, kinds },
5647 cx,
5648 );
5649 cx.background_spawn(async move {
5650 Ok(Some(
5651 all_actions_task
5652 .await
5653 .into_iter()
5654 .flat_map(|(_, actions)| actions)
5655 .collect(),
5656 ))
5657 })
5658 }
5659 }
5660
5661 pub fn code_lens_actions(
5662 &mut self,
5663 buffer: &Entity<Buffer>,
5664 cx: &mut Context<Self>,
5665 ) -> CodeLensTask {
5666 let version_queried_for = buffer.read(cx).version();
5667 let buffer_id = buffer.read(cx).remote_id();
5668 let existing_servers = self.as_local().map(|local| {
5669 local
5670 .buffers_opened_in_servers
5671 .get(&buffer_id)
5672 .cloned()
5673 .unwrap_or_default()
5674 });
5675
5676 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5677 if let Some(cached_lens) = &lsp_data.code_lens {
5678 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5679 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5680 existing_servers != cached_lens.lens.keys().copied().collect()
5681 });
5682 if !has_different_servers {
5683 return Task::ready(Ok(Some(
5684 cached_lens.lens.values().flatten().cloned().collect(),
5685 )))
5686 .shared();
5687 }
5688 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5689 if !version_queried_for.changed_since(updating_for) {
5690 return running_update.clone();
5691 }
5692 }
5693 }
5694 }
5695
5696 let lens_lsp_data = self
5697 .latest_lsp_data(buffer, cx)
5698 .code_lens
5699 .get_or_insert_default();
5700 let buffer = buffer.clone();
5701 let query_version_queried_for = version_queried_for.clone();
5702 let new_task = cx
5703 .spawn(async move |lsp_store, cx| {
5704 cx.background_executor()
5705 .timer(Duration::from_millis(30))
5706 .await;
5707 let fetched_lens = lsp_store
5708 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5709 .map_err(Arc::new)?
5710 .await
5711 .context("fetching code lens")
5712 .map_err(Arc::new);
5713 let fetched_lens = match fetched_lens {
5714 Ok(fetched_lens) => fetched_lens,
5715 Err(e) => {
5716 lsp_store
5717 .update(cx, |lsp_store, _| {
5718 if let Some(lens_lsp_data) = lsp_store
5719 .lsp_data
5720 .get_mut(&buffer_id)
5721 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5722 {
5723 lens_lsp_data.update = None;
5724 }
5725 })
5726 .ok();
5727 return Err(e);
5728 }
5729 };
5730
5731 lsp_store
5732 .update(cx, |lsp_store, _| {
5733 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5734 let code_lens = lsp_data.code_lens.as_mut()?;
5735 if let Some(fetched_lens) = fetched_lens {
5736 if lsp_data.buffer_version == query_version_queried_for {
5737 code_lens.lens.extend(fetched_lens);
5738 } else if !lsp_data
5739 .buffer_version
5740 .changed_since(&query_version_queried_for)
5741 {
5742 lsp_data.buffer_version = query_version_queried_for;
5743 code_lens.lens = fetched_lens;
5744 }
5745 }
5746 code_lens.update = None;
5747 Some(code_lens.lens.values().flatten().cloned().collect())
5748 })
5749 .map_err(Arc::new)
5750 })
5751 .shared();
5752 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5753 new_task
5754 }
5755
5756 fn fetch_code_lens(
5757 &mut self,
5758 buffer: &Entity<Buffer>,
5759 cx: &mut Context<Self>,
5760 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5761 if let Some((upstream_client, project_id)) = self.upstream_client() {
5762 let request = GetCodeLens;
5763 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5764 return Task::ready(Ok(None));
5765 }
5766 let request_task = upstream_client.request_lsp(
5767 project_id,
5768 None,
5769 LSP_REQUEST_TIMEOUT,
5770 cx.background_executor().clone(),
5771 request.to_proto(project_id, buffer.read(cx)),
5772 );
5773 let buffer = buffer.clone();
5774 cx.spawn(async move |weak_lsp_store, cx| {
5775 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5776 return Ok(None);
5777 };
5778 let Some(responses) = request_task.await? else {
5779 return Ok(None);
5780 };
5781
5782 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5783 let lsp_store = lsp_store.clone();
5784 let buffer = buffer.clone();
5785 let cx = cx.clone();
5786 async move {
5787 (
5788 LanguageServerId::from_proto(response.server_id),
5789 GetCodeLens
5790 .response_from_proto(response.response, lsp_store, buffer, cx)
5791 .await,
5792 )
5793 }
5794 }))
5795 .await;
5796
5797 let mut has_errors = false;
5798 let code_lens_actions = code_lens_actions
5799 .into_iter()
5800 .filter_map(|(server_id, code_lens)| match code_lens {
5801 Ok(code_lens) => Some((server_id, code_lens)),
5802 Err(e) => {
5803 has_errors = true;
5804 log::error!("{e:#}");
5805 None
5806 }
5807 })
5808 .collect::<HashMap<_, _>>();
5809 anyhow::ensure!(
5810 !has_errors || !code_lens_actions.is_empty(),
5811 "Failed to fetch code lens"
5812 );
5813 Ok(Some(code_lens_actions))
5814 })
5815 } else {
5816 let code_lens_actions_task =
5817 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5818 cx.background_spawn(async move {
5819 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5820 })
5821 }
5822 }
5823
5824 #[inline(never)]
5825 pub fn completions(
5826 &self,
5827 buffer: &Entity<Buffer>,
5828 position: PointUtf16,
5829 context: CompletionContext,
5830 cx: &mut Context<Self>,
5831 ) -> Task<Result<Vec<CompletionResponse>>> {
5832 let language_registry = self.languages.clone();
5833
5834 if let Some((upstream_client, project_id)) = self.upstream_client() {
5835 let request = GetCompletions { position, context };
5836 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5837 return Task::ready(Ok(Vec::new()));
5838 }
5839 let task = self.send_lsp_proto_request(
5840 buffer.clone(),
5841 upstream_client,
5842 project_id,
5843 request,
5844 cx,
5845 );
5846 let language = buffer.read(cx).language().cloned();
5847
5848 // In the future, we should provide project guests with the names of LSP adapters,
5849 // so that they can use the correct LSP adapter when computing labels. For now,
5850 // guests just use the first LSP adapter associated with the buffer's language.
5851 let lsp_adapter = language.as_ref().and_then(|language| {
5852 language_registry
5853 .lsp_adapters(&language.name())
5854 .first()
5855 .cloned()
5856 });
5857
5858 cx.foreground_executor().spawn(async move {
5859 let completion_response = task.await?;
5860 let completions = populate_labels_for_completions(
5861 completion_response.completions,
5862 language,
5863 lsp_adapter,
5864 )
5865 .await;
5866 Ok(vec![CompletionResponse {
5867 completions,
5868 display_options: CompletionDisplayOptions::default(),
5869 is_incomplete: completion_response.is_incomplete,
5870 }])
5871 })
5872 } else if let Some(local) = self.as_local() {
5873 let snapshot = buffer.read(cx).snapshot();
5874 let offset = position.to_offset(&snapshot);
5875 let scope = snapshot.language_scope_at(offset);
5876 let language = snapshot.language().cloned();
5877 let completion_settings = language_settings(
5878 language.as_ref().map(|language| language.name()),
5879 buffer.read(cx).file(),
5880 cx,
5881 )
5882 .completions
5883 .clone();
5884 if !completion_settings.lsp {
5885 return Task::ready(Ok(Vec::new()));
5886 }
5887
5888 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5889 local
5890 .language_servers_for_buffer(buffer, cx)
5891 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5892 .filter(|(adapter, _)| {
5893 scope
5894 .as_ref()
5895 .map(|scope| scope.language_allowed(&adapter.name))
5896 .unwrap_or(true)
5897 })
5898 .map(|(_, server)| server.server_id())
5899 .collect()
5900 });
5901
5902 let buffer = buffer.clone();
5903 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5904 let lsp_timeout = if lsp_timeout > 0 {
5905 Some(Duration::from_millis(lsp_timeout))
5906 } else {
5907 None
5908 };
5909 cx.spawn(async move |this, cx| {
5910 let mut tasks = Vec::with_capacity(server_ids.len());
5911 this.update(cx, |lsp_store, cx| {
5912 for server_id in server_ids {
5913 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5914 let lsp_timeout = lsp_timeout
5915 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5916 let mut timeout = cx.background_spawn(async move {
5917 match lsp_timeout {
5918 Some(lsp_timeout) => {
5919 lsp_timeout.await;
5920 true
5921 },
5922 None => false,
5923 }
5924 }).fuse();
5925 let mut lsp_request = lsp_store.request_lsp(
5926 buffer.clone(),
5927 LanguageServerToQuery::Other(server_id),
5928 GetCompletions {
5929 position,
5930 context: context.clone(),
5931 },
5932 cx,
5933 ).fuse();
5934 let new_task = cx.background_spawn(async move {
5935 select_biased! {
5936 response = lsp_request => anyhow::Ok(Some(response?)),
5937 timeout_happened = timeout => {
5938 if timeout_happened {
5939 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5940 Ok(None)
5941 } else {
5942 let completions = lsp_request.await?;
5943 Ok(Some(completions))
5944 }
5945 },
5946 }
5947 });
5948 tasks.push((lsp_adapter, new_task));
5949 }
5950 })?;
5951
5952 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5953 let completion_response = task.await.ok()??;
5954 let completions = populate_labels_for_completions(
5955 completion_response.completions,
5956 language.clone(),
5957 lsp_adapter,
5958 )
5959 .await;
5960 Some(CompletionResponse {
5961 completions,
5962 display_options: CompletionDisplayOptions::default(),
5963 is_incomplete: completion_response.is_incomplete,
5964 })
5965 });
5966
5967 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5968
5969 Ok(responses.into_iter().flatten().collect())
5970 })
5971 } else {
5972 Task::ready(Err(anyhow!("No upstream client or local language server")))
5973 }
5974 }
5975
5976 pub fn resolve_completions(
5977 &self,
5978 buffer: Entity<Buffer>,
5979 completion_indices: Vec<usize>,
5980 completions: Rc<RefCell<Box<[Completion]>>>,
5981 cx: &mut Context<Self>,
5982 ) -> Task<Result<bool>> {
5983 let client = self.upstream_client();
5984 let buffer_id = buffer.read(cx).remote_id();
5985 let buffer_snapshot = buffer.read(cx).snapshot();
5986
5987 if !self.check_if_capable_for_proto_request(
5988 &buffer,
5989 GetCompletions::can_resolve_completions,
5990 cx,
5991 ) {
5992 return Task::ready(Ok(false));
5993 }
5994 cx.spawn(async move |lsp_store, cx| {
5995 let mut did_resolve = false;
5996 if let Some((client, project_id)) = client {
5997 for completion_index in completion_indices {
5998 let server_id = {
5999 let completion = &completions.borrow()[completion_index];
6000 completion.source.server_id()
6001 };
6002 if let Some(server_id) = server_id {
6003 if Self::resolve_completion_remote(
6004 project_id,
6005 server_id,
6006 buffer_id,
6007 completions.clone(),
6008 completion_index,
6009 client.clone(),
6010 )
6011 .await
6012 .log_err()
6013 .is_some()
6014 {
6015 did_resolve = true;
6016 }
6017 } else {
6018 resolve_word_completion(
6019 &buffer_snapshot,
6020 &mut completions.borrow_mut()[completion_index],
6021 );
6022 }
6023 }
6024 } else {
6025 for completion_index in completion_indices {
6026 let server_id = {
6027 let completion = &completions.borrow()[completion_index];
6028 completion.source.server_id()
6029 };
6030 if let Some(server_id) = server_id {
6031 let server_and_adapter = lsp_store
6032 .read_with(cx, |lsp_store, _| {
6033 let server = lsp_store.language_server_for_id(server_id)?;
6034 let adapter =
6035 lsp_store.language_server_adapter_for_id(server.server_id())?;
6036 Some((server, adapter))
6037 })
6038 .ok()
6039 .flatten();
6040 let Some((server, adapter)) = server_and_adapter else {
6041 continue;
6042 };
6043
6044 let resolved = Self::resolve_completion_local(
6045 server,
6046 completions.clone(),
6047 completion_index,
6048 )
6049 .await
6050 .log_err()
6051 .is_some();
6052 if resolved {
6053 Self::regenerate_completion_labels(
6054 adapter,
6055 &buffer_snapshot,
6056 completions.clone(),
6057 completion_index,
6058 )
6059 .await
6060 .log_err();
6061 did_resolve = true;
6062 }
6063 } else {
6064 resolve_word_completion(
6065 &buffer_snapshot,
6066 &mut completions.borrow_mut()[completion_index],
6067 );
6068 }
6069 }
6070 }
6071
6072 Ok(did_resolve)
6073 })
6074 }
6075
6076 async fn resolve_completion_local(
6077 server: Arc<lsp::LanguageServer>,
6078 completions: Rc<RefCell<Box<[Completion]>>>,
6079 completion_index: usize,
6080 ) -> Result<()> {
6081 let server_id = server.server_id();
6082 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6083 return Ok(());
6084 }
6085
6086 let request = {
6087 let completion = &completions.borrow()[completion_index];
6088 match &completion.source {
6089 CompletionSource::Lsp {
6090 lsp_completion,
6091 resolved,
6092 server_id: completion_server_id,
6093 ..
6094 } => {
6095 if *resolved {
6096 return Ok(());
6097 }
6098 anyhow::ensure!(
6099 server_id == *completion_server_id,
6100 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6101 );
6102 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6103 }
6104 CompletionSource::BufferWord { .. }
6105 | CompletionSource::Dap { .. }
6106 | CompletionSource::Custom => {
6107 return Ok(());
6108 }
6109 }
6110 };
6111 let resolved_completion = request
6112 .await
6113 .into_response()
6114 .context("resolve completion")?;
6115
6116 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6117 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6118
6119 let mut completions = completions.borrow_mut();
6120 let completion = &mut completions[completion_index];
6121 if let CompletionSource::Lsp {
6122 lsp_completion,
6123 resolved,
6124 server_id: completion_server_id,
6125 ..
6126 } = &mut completion.source
6127 {
6128 if *resolved {
6129 return Ok(());
6130 }
6131 anyhow::ensure!(
6132 server_id == *completion_server_id,
6133 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6134 );
6135 *lsp_completion = Box::new(resolved_completion);
6136 *resolved = true;
6137 }
6138 Ok(())
6139 }
6140
6141 async fn regenerate_completion_labels(
6142 adapter: Arc<CachedLspAdapter>,
6143 snapshot: &BufferSnapshot,
6144 completions: Rc<RefCell<Box<[Completion]>>>,
6145 completion_index: usize,
6146 ) -> Result<()> {
6147 let completion_item = completions.borrow()[completion_index]
6148 .source
6149 .lsp_completion(true)
6150 .map(Cow::into_owned);
6151 if let Some(lsp_documentation) = completion_item
6152 .as_ref()
6153 .and_then(|completion_item| completion_item.documentation.clone())
6154 {
6155 let mut completions = completions.borrow_mut();
6156 let completion = &mut completions[completion_index];
6157 completion.documentation = Some(lsp_documentation.into());
6158 } else {
6159 let mut completions = completions.borrow_mut();
6160 let completion = &mut completions[completion_index];
6161 completion.documentation = Some(CompletionDocumentation::Undocumented);
6162 }
6163
6164 let mut new_label = match completion_item {
6165 Some(completion_item) => {
6166 // 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
6167 // So we have to update the label here anyway...
6168 let language = snapshot.language();
6169 match language {
6170 Some(language) => {
6171 adapter
6172 .labels_for_completions(
6173 std::slice::from_ref(&completion_item),
6174 language,
6175 )
6176 .await?
6177 }
6178 None => Vec::new(),
6179 }
6180 .pop()
6181 .flatten()
6182 .unwrap_or_else(|| {
6183 CodeLabel::fallback_for_completion(
6184 &completion_item,
6185 language.map(|language| language.as_ref()),
6186 )
6187 })
6188 }
6189 None => CodeLabel::plain(
6190 completions.borrow()[completion_index].new_text.clone(),
6191 None,
6192 ),
6193 };
6194 ensure_uniform_list_compatible_label(&mut new_label);
6195
6196 let mut completions = completions.borrow_mut();
6197 let completion = &mut completions[completion_index];
6198 if completion.label.filter_text() == new_label.filter_text() {
6199 completion.label = new_label;
6200 } else {
6201 log::error!(
6202 "Resolved completion changed display label from {} to {}. \
6203 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6204 completion.label.text(),
6205 new_label.text(),
6206 completion.label.filter_text(),
6207 new_label.filter_text()
6208 );
6209 }
6210
6211 Ok(())
6212 }
6213
6214 async fn resolve_completion_remote(
6215 project_id: u64,
6216 server_id: LanguageServerId,
6217 buffer_id: BufferId,
6218 completions: Rc<RefCell<Box<[Completion]>>>,
6219 completion_index: usize,
6220 client: AnyProtoClient,
6221 ) -> Result<()> {
6222 let lsp_completion = {
6223 let completion = &completions.borrow()[completion_index];
6224 match &completion.source {
6225 CompletionSource::Lsp {
6226 lsp_completion,
6227 resolved,
6228 server_id: completion_server_id,
6229 ..
6230 } => {
6231 anyhow::ensure!(
6232 server_id == *completion_server_id,
6233 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6234 );
6235 if *resolved {
6236 return Ok(());
6237 }
6238 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6239 }
6240 CompletionSource::Custom
6241 | CompletionSource::Dap { .. }
6242 | CompletionSource::BufferWord { .. } => {
6243 return Ok(());
6244 }
6245 }
6246 };
6247 let request = proto::ResolveCompletionDocumentation {
6248 project_id,
6249 language_server_id: server_id.0 as u64,
6250 lsp_completion,
6251 buffer_id: buffer_id.into(),
6252 };
6253
6254 let response = client
6255 .request(request)
6256 .await
6257 .context("completion documentation resolve proto request")?;
6258 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6259
6260 let documentation = if response.documentation.is_empty() {
6261 CompletionDocumentation::Undocumented
6262 } else if response.documentation_is_markdown {
6263 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6264 } else if response.documentation.lines().count() <= 1 {
6265 CompletionDocumentation::SingleLine(response.documentation.into())
6266 } else {
6267 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6268 };
6269
6270 let mut completions = completions.borrow_mut();
6271 let completion = &mut completions[completion_index];
6272 completion.documentation = Some(documentation);
6273 if let CompletionSource::Lsp {
6274 insert_range,
6275 lsp_completion,
6276 resolved,
6277 server_id: completion_server_id,
6278 lsp_defaults: _,
6279 } = &mut completion.source
6280 {
6281 let completion_insert_range = response
6282 .old_insert_start
6283 .and_then(deserialize_anchor)
6284 .zip(response.old_insert_end.and_then(deserialize_anchor));
6285 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6286
6287 if *resolved {
6288 return Ok(());
6289 }
6290 anyhow::ensure!(
6291 server_id == *completion_server_id,
6292 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6293 );
6294 *lsp_completion = Box::new(resolved_lsp_completion);
6295 *resolved = true;
6296 }
6297
6298 let replace_range = response
6299 .old_replace_start
6300 .and_then(deserialize_anchor)
6301 .zip(response.old_replace_end.and_then(deserialize_anchor));
6302 if let Some((old_replace_start, old_replace_end)) = replace_range
6303 && !response.new_text.is_empty()
6304 {
6305 completion.new_text = response.new_text;
6306 completion.replace_range = old_replace_start..old_replace_end;
6307 }
6308
6309 Ok(())
6310 }
6311
6312 pub fn apply_additional_edits_for_completion(
6313 &self,
6314 buffer_handle: Entity<Buffer>,
6315 completions: Rc<RefCell<Box<[Completion]>>>,
6316 completion_index: usize,
6317 push_to_history: bool,
6318 cx: &mut Context<Self>,
6319 ) -> Task<Result<Option<Transaction>>> {
6320 if let Some((client, project_id)) = self.upstream_client() {
6321 let buffer = buffer_handle.read(cx);
6322 let buffer_id = buffer.remote_id();
6323 cx.spawn(async move |_, cx| {
6324 let request = {
6325 let completion = completions.borrow()[completion_index].clone();
6326 proto::ApplyCompletionAdditionalEdits {
6327 project_id,
6328 buffer_id: buffer_id.into(),
6329 completion: Some(Self::serialize_completion(&CoreCompletion {
6330 replace_range: completion.replace_range,
6331 new_text: completion.new_text,
6332 source: completion.source,
6333 })),
6334 }
6335 };
6336
6337 if let Some(transaction) = client.request(request).await?.transaction {
6338 let transaction = language::proto::deserialize_transaction(transaction)?;
6339 buffer_handle
6340 .update(cx, |buffer, _| {
6341 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6342 })?
6343 .await?;
6344 if push_to_history {
6345 buffer_handle.update(cx, |buffer, _| {
6346 buffer.push_transaction(transaction.clone(), Instant::now());
6347 buffer.finalize_last_transaction();
6348 })?;
6349 }
6350 Ok(Some(transaction))
6351 } else {
6352 Ok(None)
6353 }
6354 })
6355 } else {
6356 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6357 let completion = &completions.borrow()[completion_index];
6358 let server_id = completion.source.server_id()?;
6359 Some(
6360 self.language_server_for_local_buffer(buffer, server_id, cx)?
6361 .1
6362 .clone(),
6363 )
6364 }) else {
6365 return Task::ready(Ok(None));
6366 };
6367
6368 cx.spawn(async move |this, cx| {
6369 Self::resolve_completion_local(
6370 server.clone(),
6371 completions.clone(),
6372 completion_index,
6373 )
6374 .await
6375 .context("resolving completion")?;
6376 let completion = completions.borrow()[completion_index].clone();
6377 let additional_text_edits = completion
6378 .source
6379 .lsp_completion(true)
6380 .as_ref()
6381 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6382 if let Some(edits) = additional_text_edits {
6383 let edits = this
6384 .update(cx, |this, cx| {
6385 this.as_local_mut().unwrap().edits_from_lsp(
6386 &buffer_handle,
6387 edits,
6388 server.server_id(),
6389 None,
6390 cx,
6391 )
6392 })?
6393 .await?;
6394
6395 buffer_handle.update(cx, |buffer, cx| {
6396 buffer.finalize_last_transaction();
6397 buffer.start_transaction();
6398
6399 for (range, text) in edits {
6400 let primary = &completion.replace_range;
6401
6402 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6403 // and the primary completion is just an insertion (empty range), then this is likely
6404 // an auto-import scenario and should not be considered overlapping
6405 // https://github.com/zed-industries/zed/issues/26136
6406 let is_file_start_auto_import = {
6407 let snapshot = buffer.snapshot();
6408 let primary_start_point = primary.start.to_point(&snapshot);
6409 let range_start_point = range.start.to_point(&snapshot);
6410
6411 let result = primary_start_point.row == 0
6412 && primary_start_point.column == 0
6413 && range_start_point.row == 0
6414 && range_start_point.column == 0;
6415
6416 result
6417 };
6418
6419 let has_overlap = if is_file_start_auto_import {
6420 false
6421 } else {
6422 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6423 && primary.end.cmp(&range.start, buffer).is_ge();
6424 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6425 && range.end.cmp(&primary.end, buffer).is_ge();
6426 let result = start_within || end_within;
6427 result
6428 };
6429
6430 //Skip additional edits which overlap with the primary completion edit
6431 //https://github.com/zed-industries/zed/pull/1871
6432 if !has_overlap {
6433 buffer.edit([(range, text)], None, cx);
6434 }
6435 }
6436
6437 let transaction = if buffer.end_transaction(cx).is_some() {
6438 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6439 if !push_to_history {
6440 buffer.forget_transaction(transaction.id);
6441 }
6442 Some(transaction)
6443 } else {
6444 None
6445 };
6446 Ok(transaction)
6447 })?
6448 } else {
6449 Ok(None)
6450 }
6451 })
6452 }
6453 }
6454
6455 pub fn pull_diagnostics(
6456 &mut self,
6457 buffer: Entity<Buffer>,
6458 cx: &mut Context<Self>,
6459 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6460 let buffer_id = buffer.read(cx).remote_id();
6461
6462 if let Some((client, upstream_project_id)) = self.upstream_client() {
6463 let mut suitable_capabilities = None;
6464 // Are we capable for proto request?
6465 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6466 &buffer,
6467 |capabilities| {
6468 if let Some(caps) = &capabilities.diagnostic_provider {
6469 suitable_capabilities = Some(caps.clone());
6470 true
6471 } else {
6472 false
6473 }
6474 },
6475 cx,
6476 );
6477 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6478 let Some(dynamic_caps) = suitable_capabilities else {
6479 return Task::ready(Ok(None));
6480 };
6481 assert!(any_server_has_diagnostics_provider);
6482
6483 let request = GetDocumentDiagnostics {
6484 previous_result_id: None,
6485 dynamic_caps,
6486 };
6487 let request_task = client.request_lsp(
6488 upstream_project_id,
6489 None,
6490 LSP_REQUEST_TIMEOUT,
6491 cx.background_executor().clone(),
6492 request.to_proto(upstream_project_id, buffer.read(cx)),
6493 );
6494 cx.background_spawn(async move {
6495 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6496 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6497 // Do not attempt to further process the dummy responses here.
6498 let _response = request_task.await?;
6499 Ok(None)
6500 })
6501 } else {
6502 let servers = buffer.update(cx, |buffer, cx| {
6503 self.language_servers_for_local_buffer(buffer, cx)
6504 .map(|(_, server)| server.clone())
6505 .collect::<Vec<_>>()
6506 });
6507
6508 let pull_diagnostics = servers
6509 .into_iter()
6510 .flat_map(|server| {
6511 let result = maybe!({
6512 let local = self.as_local()?;
6513 let server_id = server.server_id();
6514 let providers_with_identifiers = local
6515 .language_server_dynamic_registrations
6516 .get(&server_id)
6517 .into_iter()
6518 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6519 .collect::<Vec<_>>();
6520 Some(
6521 providers_with_identifiers
6522 .into_iter()
6523 .map(|dynamic_caps| {
6524 let result_id = self.result_id(server_id, buffer_id, cx);
6525 self.request_lsp(
6526 buffer.clone(),
6527 LanguageServerToQuery::Other(server_id),
6528 GetDocumentDiagnostics {
6529 previous_result_id: result_id,
6530 dynamic_caps,
6531 },
6532 cx,
6533 )
6534 })
6535 .collect::<Vec<_>>(),
6536 )
6537 });
6538
6539 result.unwrap_or_default()
6540 })
6541 .collect::<Vec<_>>();
6542
6543 cx.background_spawn(async move {
6544 let mut responses = Vec::new();
6545 for diagnostics in join_all(pull_diagnostics).await {
6546 responses.extend(diagnostics?);
6547 }
6548 Ok(Some(responses))
6549 })
6550 }
6551 }
6552
6553 pub fn applicable_inlay_chunks(
6554 &mut self,
6555 buffer: &Entity<Buffer>,
6556 ranges: &[Range<text::Anchor>],
6557 cx: &mut Context<Self>,
6558 ) -> Vec<Range<BufferRow>> {
6559 self.latest_lsp_data(buffer, cx)
6560 .inlay_hints
6561 .applicable_chunks(ranges)
6562 .map(|chunk| chunk.start..chunk.end)
6563 .collect()
6564 }
6565
6566 pub fn invalidate_inlay_hints<'a>(
6567 &'a mut self,
6568 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6569 ) {
6570 for buffer_id in for_buffers {
6571 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6572 lsp_data.inlay_hints.clear();
6573 }
6574 }
6575 }
6576
6577 pub fn inlay_hints(
6578 &mut self,
6579 invalidate: InvalidationStrategy,
6580 buffer: Entity<Buffer>,
6581 ranges: Vec<Range<text::Anchor>>,
6582 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6583 cx: &mut Context<Self>,
6584 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6585 let buffer_snapshot = buffer.read(cx).snapshot();
6586 let for_server = if let InvalidationStrategy::RefreshRequested(server_id) = invalidate {
6587 Some(server_id)
6588 } else {
6589 None
6590 };
6591 let invalidate_cache = invalidate.should_invalidate();
6592 let next_hint_id = self.next_hint_id.clone();
6593 let lsp_data = self.latest_lsp_data(&buffer, cx);
6594 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6595 let known_chunks = known_chunks
6596 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6597 .map(|(_, known_chunks)| known_chunks)
6598 .unwrap_or_default();
6599
6600 let mut hint_fetch_tasks = Vec::new();
6601 let mut cached_inlay_hints = HashMap::default();
6602 let mut ranges_to_query = Vec::new();
6603 let applicable_chunks = existing_inlay_hints
6604 .applicable_chunks(ranges.as_slice())
6605 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6606 .collect::<Vec<_>>();
6607 if applicable_chunks.is_empty() {
6608 return HashMap::default();
6609 }
6610
6611 let last_chunk_number = applicable_chunks.len() - 1;
6612
6613 for (i, row_chunk) in applicable_chunks.into_iter().enumerate() {
6614 match (
6615 existing_inlay_hints
6616 .cached_hints(&row_chunk)
6617 .filter(|_| !invalidate_cache)
6618 .cloned(),
6619 existing_inlay_hints
6620 .fetched_hints(&row_chunk)
6621 .as_ref()
6622 .filter(|_| !invalidate_cache)
6623 .cloned(),
6624 ) {
6625 (None, None) => {
6626 let end = if last_chunk_number == i {
6627 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6628 } else {
6629 Point::new(row_chunk.end, 0)
6630 };
6631 ranges_to_query.push((
6632 row_chunk,
6633 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6634 ..buffer_snapshot.anchor_after(end),
6635 ));
6636 }
6637 (None, Some(fetched_hints)) => {
6638 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()))
6639 }
6640 (Some(cached_hints), None) => {
6641 for (server_id, cached_hints) in cached_hints {
6642 if for_server.is_none_or(|for_server| for_server == server_id) {
6643 cached_inlay_hints
6644 .entry(row_chunk.start..row_chunk.end)
6645 .or_insert_with(HashMap::default)
6646 .entry(server_id)
6647 .or_insert_with(Vec::new)
6648 .extend(cached_hints);
6649 }
6650 }
6651 }
6652 (Some(cached_hints), Some(fetched_hints)) => {
6653 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()));
6654 for (server_id, cached_hints) in cached_hints {
6655 if for_server.is_none_or(|for_server| for_server == server_id) {
6656 cached_inlay_hints
6657 .entry(row_chunk.start..row_chunk.end)
6658 .or_insert_with(HashMap::default)
6659 .entry(server_id)
6660 .or_insert_with(Vec::new)
6661 .extend(cached_hints);
6662 }
6663 }
6664 }
6665 }
6666 }
6667
6668 let cached_chunk_data = cached_inlay_hints
6669 .into_iter()
6670 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6671 .collect();
6672 if hint_fetch_tasks.is_empty() && ranges_to_query.is_empty() {
6673 cached_chunk_data
6674 } else {
6675 if invalidate_cache {
6676 lsp_data.inlay_hints.clear();
6677 }
6678
6679 for (chunk, range_to_query) in ranges_to_query {
6680 let next_hint_id = next_hint_id.clone();
6681 let buffer = buffer.clone();
6682 let new_inlay_hints = cx
6683 .spawn(async move |lsp_store, cx| {
6684 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6685 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6686 })?;
6687 new_fetch_task
6688 .await
6689 .and_then(|new_hints_by_server| {
6690 lsp_store.update(cx, |lsp_store, cx| {
6691 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6692 let update_cache = !lsp_data
6693 .buffer_version
6694 .changed_since(&buffer.read(cx).version());
6695 new_hints_by_server
6696 .into_iter()
6697 .map(|(server_id, new_hints)| {
6698 let new_hints = new_hints
6699 .into_iter()
6700 .map(|new_hint| {
6701 (
6702 InlayId::Hint(next_hint_id.fetch_add(
6703 1,
6704 atomic::Ordering::AcqRel,
6705 )),
6706 new_hint,
6707 )
6708 })
6709 .collect::<Vec<_>>();
6710 if update_cache {
6711 lsp_data.inlay_hints.insert_new_hints(
6712 chunk,
6713 server_id,
6714 new_hints.clone(),
6715 );
6716 }
6717 (server_id, new_hints)
6718 })
6719 .collect()
6720 })
6721 })
6722 .map_err(Arc::new)
6723 })
6724 .shared();
6725
6726 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6727 *fetch_task = Some(new_inlay_hints.clone());
6728 hint_fetch_tasks.push((chunk, new_inlay_hints));
6729 }
6730
6731 let mut combined_data = cached_chunk_data;
6732 combined_data.extend(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6733 (
6734 chunk.start..chunk.end,
6735 cx.spawn(async move |_, _| {
6736 hints_fetch.await.map_err(|e| {
6737 if e.error_code() != ErrorCode::Internal {
6738 anyhow!(e.error_code())
6739 } else {
6740 anyhow!("{e:#}")
6741 }
6742 })
6743 }),
6744 )
6745 }));
6746 combined_data
6747 }
6748 }
6749
6750 fn fetch_inlay_hints(
6751 &mut self,
6752 for_server: Option<LanguageServerId>,
6753 buffer: &Entity<Buffer>,
6754 range: Range<Anchor>,
6755 cx: &mut Context<Self>,
6756 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6757 let request = InlayHints {
6758 range: range.clone(),
6759 };
6760 if let Some((upstream_client, project_id)) = self.upstream_client() {
6761 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6762 return Task::ready(Ok(HashMap::default()));
6763 }
6764 let request_task = upstream_client.request_lsp(
6765 project_id,
6766 for_server.map(|id| id.to_proto()),
6767 LSP_REQUEST_TIMEOUT,
6768 cx.background_executor().clone(),
6769 request.to_proto(project_id, buffer.read(cx)),
6770 );
6771 let buffer = buffer.clone();
6772 cx.spawn(async move |weak_lsp_store, cx| {
6773 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6774 return Ok(HashMap::default());
6775 };
6776 let Some(responses) = request_task.await? else {
6777 return Ok(HashMap::default());
6778 };
6779
6780 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6781 let lsp_store = lsp_store.clone();
6782 let buffer = buffer.clone();
6783 let cx = cx.clone();
6784 let request = request.clone();
6785 async move {
6786 (
6787 LanguageServerId::from_proto(response.server_id),
6788 request
6789 .response_from_proto(response.response, lsp_store, buffer, cx)
6790 .await,
6791 )
6792 }
6793 }))
6794 .await;
6795
6796 let mut has_errors = false;
6797 let inlay_hints = inlay_hints
6798 .into_iter()
6799 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6800 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6801 Err(e) => {
6802 has_errors = true;
6803 log::error!("{e:#}");
6804 None
6805 }
6806 })
6807 .collect::<HashMap<_, _>>();
6808 anyhow::ensure!(
6809 !has_errors || !inlay_hints.is_empty(),
6810 "Failed to fetch inlay hints"
6811 );
6812 Ok(inlay_hints)
6813 })
6814 } else {
6815 let inlay_hints_task = match for_server {
6816 Some(server_id) => {
6817 let server_task = self.request_lsp(
6818 buffer.clone(),
6819 LanguageServerToQuery::Other(server_id),
6820 request,
6821 cx,
6822 );
6823 cx.background_spawn(async move {
6824 let mut responses = Vec::new();
6825 match server_task.await {
6826 Ok(response) => responses.push((server_id, response)),
6827 Err(e) => log::error!(
6828 "Error handling response for inlay hints request: {e:#}"
6829 ),
6830 }
6831 responses
6832 })
6833 }
6834 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6835 };
6836 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6837 cx.background_spawn(async move {
6838 Ok(inlay_hints_task
6839 .await
6840 .into_iter()
6841 .map(|(server_id, mut new_hints)| {
6842 new_hints.retain(|hint| {
6843 hint.position.is_valid(&buffer_snapshot)
6844 && range.start.is_valid(&buffer_snapshot)
6845 && range.end.is_valid(&buffer_snapshot)
6846 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6847 && hint.position.cmp(&range.end, &buffer_snapshot).is_le()
6848 });
6849 (server_id, new_hints)
6850 })
6851 .collect())
6852 })
6853 }
6854 }
6855
6856 pub fn pull_diagnostics_for_buffer(
6857 &mut self,
6858 buffer: Entity<Buffer>,
6859 cx: &mut Context<Self>,
6860 ) -> Task<anyhow::Result<()>> {
6861 let diagnostics = self.pull_diagnostics(buffer, cx);
6862 cx.spawn(async move |lsp_store, cx| {
6863 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6864 return Ok(());
6865 };
6866 lsp_store.update(cx, |lsp_store, cx| {
6867 if lsp_store.as_local().is_none() {
6868 return;
6869 }
6870
6871 let mut unchanged_buffers = HashSet::default();
6872 let mut changed_buffers = HashSet::default();
6873 let server_diagnostics_updates = diagnostics
6874 .into_iter()
6875 .filter_map(|diagnostics_set| match diagnostics_set {
6876 LspPullDiagnostics::Response {
6877 server_id,
6878 uri,
6879 diagnostics,
6880 } => Some((server_id, uri, diagnostics)),
6881 LspPullDiagnostics::Default => None,
6882 })
6883 .fold(
6884 HashMap::default(),
6885 |mut acc, (server_id, uri, diagnostics)| {
6886 let (result_id, diagnostics) = match diagnostics {
6887 PulledDiagnostics::Unchanged { result_id } => {
6888 unchanged_buffers.insert(uri.clone());
6889 (Some(result_id), Vec::new())
6890 }
6891 PulledDiagnostics::Changed {
6892 result_id,
6893 diagnostics,
6894 } => {
6895 changed_buffers.insert(uri.clone());
6896 (result_id, diagnostics)
6897 }
6898 };
6899 let disk_based_sources = Cow::Owned(
6900 lsp_store
6901 .language_server_adapter_for_id(server_id)
6902 .as_ref()
6903 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6904 .unwrap_or(&[])
6905 .to_vec(),
6906 );
6907 acc.entry(server_id).or_insert_with(Vec::new).push(
6908 DocumentDiagnosticsUpdate {
6909 server_id,
6910 diagnostics: lsp::PublishDiagnosticsParams {
6911 uri,
6912 diagnostics,
6913 version: None,
6914 },
6915 result_id,
6916 disk_based_sources,
6917 },
6918 );
6919 acc
6920 },
6921 );
6922
6923 for diagnostic_updates in server_diagnostics_updates.into_values() {
6924 lsp_store
6925 .merge_lsp_diagnostics(
6926 DiagnosticSourceKind::Pulled,
6927 diagnostic_updates,
6928 |buffer, old_diagnostic, cx| {
6929 File::from_dyn(buffer.file())
6930 .and_then(|file| {
6931 let abs_path = file.as_local()?.abs_path(cx);
6932 lsp::Uri::from_file_path(abs_path).ok()
6933 })
6934 .is_none_or(|buffer_uri| {
6935 unchanged_buffers.contains(&buffer_uri)
6936 || match old_diagnostic.source_kind {
6937 DiagnosticSourceKind::Pulled => {
6938 !changed_buffers.contains(&buffer_uri)
6939 }
6940 DiagnosticSourceKind::Other
6941 | DiagnosticSourceKind::Pushed => true,
6942 }
6943 })
6944 },
6945 cx,
6946 )
6947 .log_err();
6948 }
6949 })
6950 })
6951 }
6952
6953 pub fn document_colors(
6954 &mut self,
6955 known_cache_version: Option<usize>,
6956 buffer: Entity<Buffer>,
6957 cx: &mut Context<Self>,
6958 ) -> Option<DocumentColorTask> {
6959 let version_queried_for = buffer.read(cx).version();
6960 let buffer_id = buffer.read(cx).remote_id();
6961
6962 let current_language_servers = self.as_local().map(|local| {
6963 local
6964 .buffers_opened_in_servers
6965 .get(&buffer_id)
6966 .cloned()
6967 .unwrap_or_default()
6968 });
6969
6970 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6971 if let Some(cached_colors) = &lsp_data.document_colors {
6972 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6973 let has_different_servers =
6974 current_language_servers.is_some_and(|current_language_servers| {
6975 current_language_servers
6976 != cached_colors.colors.keys().copied().collect()
6977 });
6978 if !has_different_servers {
6979 let cache_version = cached_colors.cache_version;
6980 if Some(cache_version) == known_cache_version {
6981 return None;
6982 } else {
6983 return Some(
6984 Task::ready(Ok(DocumentColors {
6985 colors: cached_colors
6986 .colors
6987 .values()
6988 .flatten()
6989 .cloned()
6990 .collect(),
6991 cache_version: Some(cache_version),
6992 }))
6993 .shared(),
6994 );
6995 }
6996 }
6997 }
6998 }
6999 }
7000
7001 let color_lsp_data = self
7002 .latest_lsp_data(&buffer, cx)
7003 .document_colors
7004 .get_or_insert_default();
7005 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7006 && !version_queried_for.changed_since(updating_for)
7007 {
7008 return Some(running_update.clone());
7009 }
7010 let buffer_version_queried_for = version_queried_for.clone();
7011 let new_task = cx
7012 .spawn(async move |lsp_store, cx| {
7013 cx.background_executor()
7014 .timer(Duration::from_millis(30))
7015 .await;
7016 let fetched_colors = lsp_store
7017 .update(cx, |lsp_store, cx| {
7018 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7019 })?
7020 .await
7021 .context("fetching document colors")
7022 .map_err(Arc::new);
7023 let fetched_colors = match fetched_colors {
7024 Ok(fetched_colors) => {
7025 if Some(true)
7026 == buffer
7027 .update(cx, |buffer, _| {
7028 buffer.version() != buffer_version_queried_for
7029 })
7030 .ok()
7031 {
7032 return Ok(DocumentColors::default());
7033 }
7034 fetched_colors
7035 }
7036 Err(e) => {
7037 lsp_store
7038 .update(cx, |lsp_store, _| {
7039 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7040 if let Some(document_colors) = &mut lsp_data.document_colors {
7041 document_colors.colors_update = None;
7042 }
7043 }
7044 })
7045 .ok();
7046 return Err(e);
7047 }
7048 };
7049
7050 lsp_store
7051 .update(cx, |lsp_store, cx| {
7052 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7053 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7054
7055 if let Some(fetched_colors) = fetched_colors {
7056 if lsp_data.buffer_version == buffer_version_queried_for {
7057 lsp_colors.colors.extend(fetched_colors);
7058 lsp_colors.cache_version += 1;
7059 } else if !lsp_data
7060 .buffer_version
7061 .changed_since(&buffer_version_queried_for)
7062 {
7063 lsp_data.buffer_version = buffer_version_queried_for;
7064 lsp_colors.colors = fetched_colors;
7065 lsp_colors.cache_version += 1;
7066 }
7067 }
7068 lsp_colors.colors_update = None;
7069 let colors = lsp_colors
7070 .colors
7071 .values()
7072 .flatten()
7073 .cloned()
7074 .collect::<HashSet<_>>();
7075 DocumentColors {
7076 colors,
7077 cache_version: Some(lsp_colors.cache_version),
7078 }
7079 })
7080 .map_err(Arc::new)
7081 })
7082 .shared();
7083 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7084 Some(new_task)
7085 }
7086
7087 fn fetch_document_colors_for_buffer(
7088 &mut self,
7089 buffer: &Entity<Buffer>,
7090 cx: &mut Context<Self>,
7091 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7092 if let Some((client, project_id)) = self.upstream_client() {
7093 let request = GetDocumentColor {};
7094 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7095 return Task::ready(Ok(None));
7096 }
7097
7098 let request_task = client.request_lsp(
7099 project_id,
7100 None,
7101 LSP_REQUEST_TIMEOUT,
7102 cx.background_executor().clone(),
7103 request.to_proto(project_id, buffer.read(cx)),
7104 );
7105 let buffer = buffer.clone();
7106 cx.spawn(async move |lsp_store, cx| {
7107 let Some(project) = lsp_store.upgrade() else {
7108 return Ok(None);
7109 };
7110 let colors = join_all(
7111 request_task
7112 .await
7113 .log_err()
7114 .flatten()
7115 .map(|response| response.payload)
7116 .unwrap_or_default()
7117 .into_iter()
7118 .map(|color_response| {
7119 let response = request.response_from_proto(
7120 color_response.response,
7121 project.clone(),
7122 buffer.clone(),
7123 cx.clone(),
7124 );
7125 async move {
7126 (
7127 LanguageServerId::from_proto(color_response.server_id),
7128 response.await.log_err().unwrap_or_default(),
7129 )
7130 }
7131 }),
7132 )
7133 .await
7134 .into_iter()
7135 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7136 acc.entry(server_id)
7137 .or_insert_with(HashSet::default)
7138 .extend(colors);
7139 acc
7140 });
7141 Ok(Some(colors))
7142 })
7143 } else {
7144 let document_colors_task =
7145 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7146 cx.background_spawn(async move {
7147 Ok(Some(
7148 document_colors_task
7149 .await
7150 .into_iter()
7151 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7152 acc.entry(server_id)
7153 .or_insert_with(HashSet::default)
7154 .extend(colors);
7155 acc
7156 })
7157 .into_iter()
7158 .collect(),
7159 ))
7160 })
7161 }
7162 }
7163
7164 pub fn signature_help<T: ToPointUtf16>(
7165 &mut self,
7166 buffer: &Entity<Buffer>,
7167 position: T,
7168 cx: &mut Context<Self>,
7169 ) -> Task<Option<Vec<SignatureHelp>>> {
7170 let position = position.to_point_utf16(buffer.read(cx));
7171
7172 if let Some((client, upstream_project_id)) = self.upstream_client() {
7173 let request = GetSignatureHelp { position };
7174 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7175 return Task::ready(None);
7176 }
7177 let request_task = client.request_lsp(
7178 upstream_project_id,
7179 None,
7180 LSP_REQUEST_TIMEOUT,
7181 cx.background_executor().clone(),
7182 request.to_proto(upstream_project_id, buffer.read(cx)),
7183 );
7184 let buffer = buffer.clone();
7185 cx.spawn(async move |weak_project, cx| {
7186 let project = weak_project.upgrade()?;
7187 let signatures = join_all(
7188 request_task
7189 .await
7190 .log_err()
7191 .flatten()
7192 .map(|response| response.payload)
7193 .unwrap_or_default()
7194 .into_iter()
7195 .map(|response| {
7196 let response = GetSignatureHelp { position }.response_from_proto(
7197 response.response,
7198 project.clone(),
7199 buffer.clone(),
7200 cx.clone(),
7201 );
7202 async move { response.await.log_err().flatten() }
7203 }),
7204 )
7205 .await
7206 .into_iter()
7207 .flatten()
7208 .collect();
7209 Some(signatures)
7210 })
7211 } else {
7212 let all_actions_task = self.request_multiple_lsp_locally(
7213 buffer,
7214 Some(position),
7215 GetSignatureHelp { position },
7216 cx,
7217 );
7218 cx.background_spawn(async move {
7219 Some(
7220 all_actions_task
7221 .await
7222 .into_iter()
7223 .flat_map(|(_, actions)| actions)
7224 .collect::<Vec<_>>(),
7225 )
7226 })
7227 }
7228 }
7229
7230 pub fn hover(
7231 &mut self,
7232 buffer: &Entity<Buffer>,
7233 position: PointUtf16,
7234 cx: &mut Context<Self>,
7235 ) -> Task<Option<Vec<Hover>>> {
7236 if let Some((client, upstream_project_id)) = self.upstream_client() {
7237 let request = GetHover { position };
7238 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7239 return Task::ready(None);
7240 }
7241 let request_task = client.request_lsp(
7242 upstream_project_id,
7243 None,
7244 LSP_REQUEST_TIMEOUT,
7245 cx.background_executor().clone(),
7246 request.to_proto(upstream_project_id, buffer.read(cx)),
7247 );
7248 let buffer = buffer.clone();
7249 cx.spawn(async move |weak_project, cx| {
7250 let project = weak_project.upgrade()?;
7251 let hovers = join_all(
7252 request_task
7253 .await
7254 .log_err()
7255 .flatten()
7256 .map(|response| response.payload)
7257 .unwrap_or_default()
7258 .into_iter()
7259 .map(|response| {
7260 let response = GetHover { position }.response_from_proto(
7261 response.response,
7262 project.clone(),
7263 buffer.clone(),
7264 cx.clone(),
7265 );
7266 async move {
7267 response
7268 .await
7269 .log_err()
7270 .flatten()
7271 .and_then(remove_empty_hover_blocks)
7272 }
7273 }),
7274 )
7275 .await
7276 .into_iter()
7277 .flatten()
7278 .collect();
7279 Some(hovers)
7280 })
7281 } else {
7282 let all_actions_task = self.request_multiple_lsp_locally(
7283 buffer,
7284 Some(position),
7285 GetHover { position },
7286 cx,
7287 );
7288 cx.background_spawn(async move {
7289 Some(
7290 all_actions_task
7291 .await
7292 .into_iter()
7293 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7294 .collect::<Vec<Hover>>(),
7295 )
7296 })
7297 }
7298 }
7299
7300 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7301 let language_registry = self.languages.clone();
7302
7303 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7304 let request = upstream_client.request(proto::GetProjectSymbols {
7305 project_id: *project_id,
7306 query: query.to_string(),
7307 });
7308 cx.foreground_executor().spawn(async move {
7309 let response = request.await?;
7310 let mut symbols = Vec::new();
7311 let core_symbols = response
7312 .symbols
7313 .into_iter()
7314 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7315 .collect::<Vec<_>>();
7316 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7317 .await;
7318 Ok(symbols)
7319 })
7320 } else if let Some(local) = self.as_local() {
7321 struct WorkspaceSymbolsResult {
7322 server_id: LanguageServerId,
7323 lsp_adapter: Arc<CachedLspAdapter>,
7324 worktree: WeakEntity<Worktree>,
7325 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7326 }
7327
7328 let mut requests = Vec::new();
7329 let mut requested_servers = BTreeSet::new();
7330 for (seed, state) in local.language_server_ids.iter() {
7331 let Some(worktree_handle) = self
7332 .worktree_store
7333 .read(cx)
7334 .worktree_for_id(seed.worktree_id, cx)
7335 else {
7336 continue;
7337 };
7338 let worktree = worktree_handle.read(cx);
7339 if !worktree.is_visible() {
7340 continue;
7341 }
7342
7343 if !requested_servers.insert(state.id) {
7344 continue;
7345 }
7346
7347 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7348 Some(LanguageServerState::Running {
7349 adapter, server, ..
7350 }) => (adapter.clone(), server),
7351
7352 _ => continue,
7353 };
7354 let supports_workspace_symbol_request =
7355 match server.capabilities().workspace_symbol_provider {
7356 Some(OneOf::Left(supported)) => supported,
7357 Some(OneOf::Right(_)) => true,
7358 None => false,
7359 };
7360 if !supports_workspace_symbol_request {
7361 continue;
7362 }
7363 let worktree_handle = worktree_handle.clone();
7364 let server_id = server.server_id();
7365 requests.push(
7366 server
7367 .request::<lsp::request::WorkspaceSymbolRequest>(
7368 lsp::WorkspaceSymbolParams {
7369 query: query.to_string(),
7370 ..Default::default()
7371 },
7372 )
7373 .map(move |response| {
7374 let lsp_symbols = response.into_response()
7375 .context("workspace symbols request")
7376 .log_err()
7377 .flatten()
7378 .map(|symbol_response| match symbol_response {
7379 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7380 flat_responses.into_iter().map(|lsp_symbol| {
7381 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7382 }).collect::<Vec<_>>()
7383 }
7384 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7385 nested_responses.into_iter().filter_map(|lsp_symbol| {
7386 let location = match lsp_symbol.location {
7387 OneOf::Left(location) => location,
7388 OneOf::Right(_) => {
7389 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7390 return None
7391 }
7392 };
7393 Some((lsp_symbol.name, lsp_symbol.kind, location))
7394 }).collect::<Vec<_>>()
7395 }
7396 }).unwrap_or_default();
7397
7398 WorkspaceSymbolsResult {
7399 server_id,
7400 lsp_adapter,
7401 worktree: worktree_handle.downgrade(),
7402 lsp_symbols,
7403 }
7404 }),
7405 );
7406 }
7407
7408 cx.spawn(async move |this, cx| {
7409 let responses = futures::future::join_all(requests).await;
7410 let this = match this.upgrade() {
7411 Some(this) => this,
7412 None => return Ok(Vec::new()),
7413 };
7414
7415 let mut symbols = Vec::new();
7416 for result in responses {
7417 let core_symbols = this.update(cx, |this, cx| {
7418 result
7419 .lsp_symbols
7420 .into_iter()
7421 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7422 let abs_path = symbol_location.uri.to_file_path().ok()?;
7423 let source_worktree = result.worktree.upgrade()?;
7424 let source_worktree_id = source_worktree.read(cx).id();
7425
7426 let path = if let Some((tree, rel_path)) =
7427 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7428 {
7429 let worktree_id = tree.read(cx).id();
7430 SymbolLocation::InProject(ProjectPath {
7431 worktree_id,
7432 path: rel_path,
7433 })
7434 } else {
7435 SymbolLocation::OutsideProject {
7436 signature: this.symbol_signature(&abs_path),
7437 abs_path: abs_path.into(),
7438 }
7439 };
7440
7441 Some(CoreSymbol {
7442 source_language_server_id: result.server_id,
7443 language_server_name: result.lsp_adapter.name.clone(),
7444 source_worktree_id,
7445 path,
7446 kind: symbol_kind,
7447 name: symbol_name,
7448 range: range_from_lsp(symbol_location.range),
7449 })
7450 })
7451 .collect()
7452 })?;
7453
7454 populate_labels_for_symbols(
7455 core_symbols,
7456 &language_registry,
7457 Some(result.lsp_adapter),
7458 &mut symbols,
7459 )
7460 .await;
7461 }
7462
7463 Ok(symbols)
7464 })
7465 } else {
7466 Task::ready(Err(anyhow!("No upstream client or local language server")))
7467 }
7468 }
7469
7470 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7471 let mut summary = DiagnosticSummary::default();
7472 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7473 summary.error_count += path_summary.error_count;
7474 summary.warning_count += path_summary.warning_count;
7475 }
7476 summary
7477 }
7478
7479 /// Returns the diagnostic summary for a specific project path.
7480 pub fn diagnostic_summary_for_path(
7481 &self,
7482 project_path: &ProjectPath,
7483 _: &App,
7484 ) -> DiagnosticSummary {
7485 if let Some(summaries) = self
7486 .diagnostic_summaries
7487 .get(&project_path.worktree_id)
7488 .and_then(|map| map.get(&project_path.path))
7489 {
7490 let (error_count, warning_count) = summaries.iter().fold(
7491 (0, 0),
7492 |(error_count, warning_count), (_language_server_id, summary)| {
7493 (
7494 error_count + summary.error_count,
7495 warning_count + summary.warning_count,
7496 )
7497 },
7498 );
7499
7500 DiagnosticSummary {
7501 error_count,
7502 warning_count,
7503 }
7504 } else {
7505 DiagnosticSummary::default()
7506 }
7507 }
7508
7509 pub fn diagnostic_summaries<'a>(
7510 &'a self,
7511 include_ignored: bool,
7512 cx: &'a App,
7513 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7514 self.worktree_store
7515 .read(cx)
7516 .visible_worktrees(cx)
7517 .filter_map(|worktree| {
7518 let worktree = worktree.read(cx);
7519 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7520 })
7521 .flat_map(move |(worktree, summaries)| {
7522 let worktree_id = worktree.id();
7523 summaries
7524 .iter()
7525 .filter(move |(path, _)| {
7526 include_ignored
7527 || worktree
7528 .entry_for_path(path.as_ref())
7529 .is_some_and(|entry| !entry.is_ignored)
7530 })
7531 .flat_map(move |(path, summaries)| {
7532 summaries.iter().map(move |(server_id, summary)| {
7533 (
7534 ProjectPath {
7535 worktree_id,
7536 path: path.clone(),
7537 },
7538 *server_id,
7539 *summary,
7540 )
7541 })
7542 })
7543 })
7544 }
7545
7546 pub fn on_buffer_edited(
7547 &mut self,
7548 buffer: Entity<Buffer>,
7549 cx: &mut Context<Self>,
7550 ) -> Option<()> {
7551 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7552 Some(
7553 self.as_local()?
7554 .language_servers_for_buffer(buffer, cx)
7555 .map(|i| i.1.clone())
7556 .collect(),
7557 )
7558 })?;
7559
7560 let buffer = buffer.read(cx);
7561 let file = File::from_dyn(buffer.file())?;
7562 let abs_path = file.as_local()?.abs_path(cx);
7563 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7564 let next_snapshot = buffer.text_snapshot();
7565 for language_server in language_servers {
7566 let language_server = language_server.clone();
7567
7568 let buffer_snapshots = self
7569 .as_local_mut()
7570 .unwrap()
7571 .buffer_snapshots
7572 .get_mut(&buffer.remote_id())
7573 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7574 let previous_snapshot = buffer_snapshots.last()?;
7575
7576 let build_incremental_change = || {
7577 buffer
7578 .edits_since::<Dimensions<PointUtf16, usize>>(
7579 previous_snapshot.snapshot.version(),
7580 )
7581 .map(|edit| {
7582 let edit_start = edit.new.start.0;
7583 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7584 let new_text = next_snapshot
7585 .text_for_range(edit.new.start.1..edit.new.end.1)
7586 .collect();
7587 lsp::TextDocumentContentChangeEvent {
7588 range: Some(lsp::Range::new(
7589 point_to_lsp(edit_start),
7590 point_to_lsp(edit_end),
7591 )),
7592 range_length: None,
7593 text: new_text,
7594 }
7595 })
7596 .collect()
7597 };
7598
7599 let document_sync_kind = language_server
7600 .capabilities()
7601 .text_document_sync
7602 .as_ref()
7603 .and_then(|sync| match sync {
7604 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7605 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7606 });
7607
7608 let content_changes: Vec<_> = match document_sync_kind {
7609 Some(lsp::TextDocumentSyncKind::FULL) => {
7610 vec![lsp::TextDocumentContentChangeEvent {
7611 range: None,
7612 range_length: None,
7613 text: next_snapshot.text(),
7614 }]
7615 }
7616 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7617 _ => {
7618 #[cfg(any(test, feature = "test-support"))]
7619 {
7620 build_incremental_change()
7621 }
7622
7623 #[cfg(not(any(test, feature = "test-support")))]
7624 {
7625 continue;
7626 }
7627 }
7628 };
7629
7630 let next_version = previous_snapshot.version + 1;
7631 buffer_snapshots.push(LspBufferSnapshot {
7632 version: next_version,
7633 snapshot: next_snapshot.clone(),
7634 });
7635
7636 language_server
7637 .notify::<lsp::notification::DidChangeTextDocument>(
7638 lsp::DidChangeTextDocumentParams {
7639 text_document: lsp::VersionedTextDocumentIdentifier::new(
7640 uri.clone(),
7641 next_version,
7642 ),
7643 content_changes,
7644 },
7645 )
7646 .ok();
7647 self.pull_workspace_diagnostics(language_server.server_id());
7648 }
7649
7650 None
7651 }
7652
7653 pub fn on_buffer_saved(
7654 &mut self,
7655 buffer: Entity<Buffer>,
7656 cx: &mut Context<Self>,
7657 ) -> Option<()> {
7658 let file = File::from_dyn(buffer.read(cx).file())?;
7659 let worktree_id = file.worktree_id(cx);
7660 let abs_path = file.as_local()?.abs_path(cx);
7661 let text_document = lsp::TextDocumentIdentifier {
7662 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7663 };
7664 let local = self.as_local()?;
7665
7666 for server in local.language_servers_for_worktree(worktree_id) {
7667 if let Some(include_text) = include_text(server.as_ref()) {
7668 let text = if include_text {
7669 Some(buffer.read(cx).text())
7670 } else {
7671 None
7672 };
7673 server
7674 .notify::<lsp::notification::DidSaveTextDocument>(
7675 lsp::DidSaveTextDocumentParams {
7676 text_document: text_document.clone(),
7677 text,
7678 },
7679 )
7680 .ok();
7681 }
7682 }
7683
7684 let language_servers = buffer.update(cx, |buffer, cx| {
7685 local.language_server_ids_for_buffer(buffer, cx)
7686 });
7687 for language_server_id in language_servers {
7688 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7689 }
7690
7691 None
7692 }
7693
7694 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7695 maybe!(async move {
7696 let mut refreshed_servers = HashSet::default();
7697 let servers = lsp_store
7698 .update(cx, |lsp_store, cx| {
7699 let local = lsp_store.as_local()?;
7700
7701 let servers = local
7702 .language_server_ids
7703 .iter()
7704 .filter_map(|(seed, state)| {
7705 let worktree = lsp_store
7706 .worktree_store
7707 .read(cx)
7708 .worktree_for_id(seed.worktree_id, cx);
7709 let delegate: Arc<dyn LspAdapterDelegate> =
7710 worktree.map(|worktree| {
7711 LocalLspAdapterDelegate::new(
7712 local.languages.clone(),
7713 &local.environment,
7714 cx.weak_entity(),
7715 &worktree,
7716 local.http_client.clone(),
7717 local.fs.clone(),
7718 cx,
7719 )
7720 })?;
7721 let server_id = state.id;
7722
7723 let states = local.language_servers.get(&server_id)?;
7724
7725 match states {
7726 LanguageServerState::Starting { .. } => None,
7727 LanguageServerState::Running {
7728 adapter, server, ..
7729 } => {
7730 let adapter = adapter.clone();
7731 let server = server.clone();
7732 refreshed_servers.insert(server.name());
7733 let toolchain = seed.toolchain.clone();
7734 Some(cx.spawn(async move |_, cx| {
7735 let settings =
7736 LocalLspStore::workspace_configuration_for_adapter(
7737 adapter.adapter.clone(),
7738 &delegate,
7739 toolchain,
7740 cx,
7741 )
7742 .await
7743 .ok()?;
7744 server
7745 .notify::<lsp::notification::DidChangeConfiguration>(
7746 lsp::DidChangeConfigurationParams { settings },
7747 )
7748 .ok()?;
7749 Some(())
7750 }))
7751 }
7752 }
7753 })
7754 .collect::<Vec<_>>();
7755
7756 Some(servers)
7757 })
7758 .ok()
7759 .flatten()?;
7760
7761 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7762 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7763 // to stop and unregister its language server wrapper.
7764 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7765 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7766 let _: Vec<Option<()>> = join_all(servers).await;
7767
7768 Some(())
7769 })
7770 .await;
7771 }
7772
7773 fn maintain_workspace_config(
7774 external_refresh_requests: watch::Receiver<()>,
7775 cx: &mut Context<Self>,
7776 ) -> Task<Result<()>> {
7777 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7778 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7779
7780 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7781 *settings_changed_tx.borrow_mut() = ();
7782 });
7783
7784 let mut joint_future =
7785 futures::stream::select(settings_changed_rx, external_refresh_requests);
7786 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7787 // - 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).
7788 // - 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.
7789 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7790 // - 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,
7791 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7792 cx.spawn(async move |this, cx| {
7793 while let Some(()) = joint_future.next().await {
7794 this.update(cx, |this, cx| {
7795 this.refresh_server_tree(cx);
7796 })
7797 .ok();
7798
7799 Self::refresh_workspace_configurations(&this, cx).await;
7800 }
7801
7802 drop(settings_observation);
7803 anyhow::Ok(())
7804 })
7805 }
7806
7807 pub fn language_servers_for_local_buffer<'a>(
7808 &'a self,
7809 buffer: &Buffer,
7810 cx: &mut App,
7811 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7812 let local = self.as_local();
7813 let language_server_ids = local
7814 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7815 .unwrap_or_default();
7816
7817 language_server_ids
7818 .into_iter()
7819 .filter_map(
7820 move |server_id| match local?.language_servers.get(&server_id)? {
7821 LanguageServerState::Running {
7822 adapter, server, ..
7823 } => Some((adapter, server)),
7824 _ => None,
7825 },
7826 )
7827 }
7828
7829 pub fn language_server_for_local_buffer<'a>(
7830 &'a self,
7831 buffer: &'a Buffer,
7832 server_id: LanguageServerId,
7833 cx: &'a mut App,
7834 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7835 self.as_local()?
7836 .language_servers_for_buffer(buffer, cx)
7837 .find(|(_, s)| s.server_id() == server_id)
7838 }
7839
7840 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7841 self.diagnostic_summaries.remove(&id_to_remove);
7842 if let Some(local) = self.as_local_mut() {
7843 let to_remove = local.remove_worktree(id_to_remove, cx);
7844 for server in to_remove {
7845 self.language_server_statuses.remove(&server);
7846 }
7847 }
7848 }
7849
7850 pub fn shared(
7851 &mut self,
7852 project_id: u64,
7853 downstream_client: AnyProtoClient,
7854 _: &mut Context<Self>,
7855 ) {
7856 self.downstream_client = Some((downstream_client.clone(), project_id));
7857
7858 for (server_id, status) in &self.language_server_statuses {
7859 if let Some(server) = self.language_server_for_id(*server_id) {
7860 downstream_client
7861 .send(proto::StartLanguageServer {
7862 project_id,
7863 server: Some(proto::LanguageServer {
7864 id: server_id.to_proto(),
7865 name: status.name.to_string(),
7866 worktree_id: status.worktree.map(|id| id.to_proto()),
7867 }),
7868 capabilities: serde_json::to_string(&server.capabilities())
7869 .expect("serializing server LSP capabilities"),
7870 })
7871 .log_err();
7872 }
7873 }
7874 }
7875
7876 pub fn disconnected_from_host(&mut self) {
7877 self.downstream_client.take();
7878 }
7879
7880 pub fn disconnected_from_ssh_remote(&mut self) {
7881 if let LspStoreMode::Remote(RemoteLspStore {
7882 upstream_client, ..
7883 }) = &mut self.mode
7884 {
7885 upstream_client.take();
7886 }
7887 }
7888
7889 pub(crate) fn set_language_server_statuses_from_proto(
7890 &mut self,
7891 project: WeakEntity<Project>,
7892 language_servers: Vec<proto::LanguageServer>,
7893 server_capabilities: Vec<String>,
7894 cx: &mut Context<Self>,
7895 ) {
7896 let lsp_logs = cx
7897 .try_global::<GlobalLogStore>()
7898 .map(|lsp_store| lsp_store.0.clone());
7899
7900 self.language_server_statuses = language_servers
7901 .into_iter()
7902 .zip(server_capabilities)
7903 .map(|(server, server_capabilities)| {
7904 let server_id = LanguageServerId(server.id as usize);
7905 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7906 self.lsp_server_capabilities
7907 .insert(server_id, server_capabilities);
7908 }
7909
7910 let name = LanguageServerName::from_proto(server.name);
7911 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7912
7913 if let Some(lsp_logs) = &lsp_logs {
7914 lsp_logs.update(cx, |lsp_logs, cx| {
7915 lsp_logs.add_language_server(
7916 // Only remote clients get their language servers set from proto
7917 LanguageServerKind::Remote {
7918 project: project.clone(),
7919 },
7920 server_id,
7921 Some(name.clone()),
7922 worktree,
7923 None,
7924 cx,
7925 );
7926 });
7927 }
7928
7929 (
7930 server_id,
7931 LanguageServerStatus {
7932 name,
7933 pending_work: Default::default(),
7934 has_pending_diagnostic_updates: false,
7935 progress_tokens: Default::default(),
7936 worktree,
7937 },
7938 )
7939 })
7940 .collect();
7941 }
7942
7943 #[cfg(test)]
7944 pub fn update_diagnostic_entries(
7945 &mut self,
7946 server_id: LanguageServerId,
7947 abs_path: PathBuf,
7948 result_id: Option<String>,
7949 version: Option<i32>,
7950 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7951 cx: &mut Context<Self>,
7952 ) -> anyhow::Result<()> {
7953 self.merge_diagnostic_entries(
7954 vec![DocumentDiagnosticsUpdate {
7955 diagnostics: DocumentDiagnostics {
7956 diagnostics,
7957 document_abs_path: abs_path,
7958 version,
7959 },
7960 result_id,
7961 server_id,
7962 disk_based_sources: Cow::Borrowed(&[]),
7963 }],
7964 |_, _, _| false,
7965 cx,
7966 )?;
7967 Ok(())
7968 }
7969
7970 pub fn merge_diagnostic_entries<'a>(
7971 &mut self,
7972 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7973 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7974 cx: &mut Context<Self>,
7975 ) -> anyhow::Result<()> {
7976 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7977 let mut updated_diagnostics_paths = HashMap::default();
7978 for mut update in diagnostic_updates {
7979 let abs_path = &update.diagnostics.document_abs_path;
7980 let server_id = update.server_id;
7981 let Some((worktree, relative_path)) =
7982 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7983 else {
7984 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7985 return Ok(());
7986 };
7987
7988 let worktree_id = worktree.read(cx).id();
7989 let project_path = ProjectPath {
7990 worktree_id,
7991 path: relative_path,
7992 };
7993
7994 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7995 let snapshot = buffer_handle.read(cx).snapshot();
7996 let buffer = buffer_handle.read(cx);
7997 let reused_diagnostics = buffer
7998 .buffer_diagnostics(Some(server_id))
7999 .iter()
8000 .filter(|v| merge(buffer, &v.diagnostic, cx))
8001 .map(|v| {
8002 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8003 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8004 DiagnosticEntry {
8005 range: start..end,
8006 diagnostic: v.diagnostic.clone(),
8007 }
8008 })
8009 .collect::<Vec<_>>();
8010
8011 self.as_local_mut()
8012 .context("cannot merge diagnostics on a remote LspStore")?
8013 .update_buffer_diagnostics(
8014 &buffer_handle,
8015 server_id,
8016 update.result_id,
8017 update.diagnostics.version,
8018 update.diagnostics.diagnostics.clone(),
8019 reused_diagnostics.clone(),
8020 cx,
8021 )?;
8022
8023 update.diagnostics.diagnostics.extend(reused_diagnostics);
8024 }
8025
8026 let updated = worktree.update(cx, |worktree, cx| {
8027 self.update_worktree_diagnostics(
8028 worktree.id(),
8029 server_id,
8030 project_path.path.clone(),
8031 update.diagnostics.diagnostics,
8032 cx,
8033 )
8034 })?;
8035 match updated {
8036 ControlFlow::Continue(new_summary) => {
8037 if let Some((project_id, new_summary)) = new_summary {
8038 match &mut diagnostics_summary {
8039 Some(diagnostics_summary) => {
8040 diagnostics_summary
8041 .more_summaries
8042 .push(proto::DiagnosticSummary {
8043 path: project_path.path.as_ref().to_proto(),
8044 language_server_id: server_id.0 as u64,
8045 error_count: new_summary.error_count,
8046 warning_count: new_summary.warning_count,
8047 })
8048 }
8049 None => {
8050 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8051 project_id,
8052 worktree_id: worktree_id.to_proto(),
8053 summary: Some(proto::DiagnosticSummary {
8054 path: project_path.path.as_ref().to_proto(),
8055 language_server_id: server_id.0 as u64,
8056 error_count: new_summary.error_count,
8057 warning_count: new_summary.warning_count,
8058 }),
8059 more_summaries: Vec::new(),
8060 })
8061 }
8062 }
8063 }
8064 updated_diagnostics_paths
8065 .entry(server_id)
8066 .or_insert_with(Vec::new)
8067 .push(project_path);
8068 }
8069 ControlFlow::Break(()) => {}
8070 }
8071 }
8072
8073 if let Some((diagnostics_summary, (downstream_client, _))) =
8074 diagnostics_summary.zip(self.downstream_client.as_ref())
8075 {
8076 downstream_client.send(diagnostics_summary).log_err();
8077 }
8078 for (server_id, paths) in updated_diagnostics_paths {
8079 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8080 }
8081 Ok(())
8082 }
8083
8084 fn update_worktree_diagnostics(
8085 &mut self,
8086 worktree_id: WorktreeId,
8087 server_id: LanguageServerId,
8088 path_in_worktree: Arc<RelPath>,
8089 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8090 _: &mut Context<Worktree>,
8091 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8092 let local = match &mut self.mode {
8093 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8094 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8095 };
8096
8097 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8098 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8099 let summaries_by_server_id = summaries_for_tree
8100 .entry(path_in_worktree.clone())
8101 .or_default();
8102
8103 let old_summary = summaries_by_server_id
8104 .remove(&server_id)
8105 .unwrap_or_default();
8106
8107 let new_summary = DiagnosticSummary::new(&diagnostics);
8108 if new_summary.is_empty() {
8109 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8110 {
8111 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8112 diagnostics_by_server_id.remove(ix);
8113 }
8114 if diagnostics_by_server_id.is_empty() {
8115 diagnostics_for_tree.remove(&path_in_worktree);
8116 }
8117 }
8118 } else {
8119 summaries_by_server_id.insert(server_id, new_summary);
8120 let diagnostics_by_server_id = diagnostics_for_tree
8121 .entry(path_in_worktree.clone())
8122 .or_default();
8123 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8124 Ok(ix) => {
8125 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8126 }
8127 Err(ix) => {
8128 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8129 }
8130 }
8131 }
8132
8133 if !old_summary.is_empty() || !new_summary.is_empty() {
8134 if let Some((_, project_id)) = &self.downstream_client {
8135 Ok(ControlFlow::Continue(Some((
8136 *project_id,
8137 proto::DiagnosticSummary {
8138 path: path_in_worktree.to_proto(),
8139 language_server_id: server_id.0 as u64,
8140 error_count: new_summary.error_count as u32,
8141 warning_count: new_summary.warning_count as u32,
8142 },
8143 ))))
8144 } else {
8145 Ok(ControlFlow::Continue(None))
8146 }
8147 } else {
8148 Ok(ControlFlow::Break(()))
8149 }
8150 }
8151
8152 pub fn open_buffer_for_symbol(
8153 &mut self,
8154 symbol: &Symbol,
8155 cx: &mut Context<Self>,
8156 ) -> Task<Result<Entity<Buffer>>> {
8157 if let Some((client, project_id)) = self.upstream_client() {
8158 let request = client.request(proto::OpenBufferForSymbol {
8159 project_id,
8160 symbol: Some(Self::serialize_symbol(symbol)),
8161 });
8162 cx.spawn(async move |this, cx| {
8163 let response = request.await?;
8164 let buffer_id = BufferId::new(response.buffer_id)?;
8165 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8166 .await
8167 })
8168 } else if let Some(local) = self.as_local() {
8169 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8170 seed.worktree_id == symbol.source_worktree_id
8171 && state.id == symbol.source_language_server_id
8172 && symbol.language_server_name == seed.name
8173 });
8174 if !is_valid {
8175 return Task::ready(Err(anyhow!(
8176 "language server for worktree and language not found"
8177 )));
8178 };
8179
8180 let symbol_abs_path = match &symbol.path {
8181 SymbolLocation::InProject(project_path) => self
8182 .worktree_store
8183 .read(cx)
8184 .absolutize(&project_path, cx)
8185 .context("no such worktree"),
8186 SymbolLocation::OutsideProject {
8187 abs_path,
8188 signature: _,
8189 } => Ok(abs_path.to_path_buf()),
8190 };
8191 let symbol_abs_path = match symbol_abs_path {
8192 Ok(abs_path) => abs_path,
8193 Err(err) => return Task::ready(Err(err)),
8194 };
8195 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8196 uri
8197 } else {
8198 return Task::ready(Err(anyhow!("invalid symbol path")));
8199 };
8200
8201 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8202 } else {
8203 Task::ready(Err(anyhow!("no upstream client or local store")))
8204 }
8205 }
8206
8207 pub(crate) fn open_local_buffer_via_lsp(
8208 &mut self,
8209 abs_path: lsp::Uri,
8210 language_server_id: LanguageServerId,
8211 cx: &mut Context<Self>,
8212 ) -> Task<Result<Entity<Buffer>>> {
8213 cx.spawn(async move |lsp_store, cx| {
8214 // Escape percent-encoded string.
8215 let current_scheme = abs_path.scheme().to_owned();
8216 // Uri is immutable, so we can't modify the scheme
8217
8218 let abs_path = abs_path
8219 .to_file_path()
8220 .map_err(|()| anyhow!("can't convert URI to path"))?;
8221 let p = abs_path.clone();
8222 let yarn_worktree = lsp_store
8223 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8224 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8225 cx.spawn(async move |this, cx| {
8226 let t = this
8227 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8228 .ok()?;
8229 t.await
8230 })
8231 }),
8232 None => Task::ready(None),
8233 })?
8234 .await;
8235 let (worktree_root_target, known_relative_path) =
8236 if let Some((zip_root, relative_path)) = yarn_worktree {
8237 (zip_root, Some(relative_path))
8238 } else {
8239 (Arc::<Path>::from(abs_path.as_path()), None)
8240 };
8241 let (worktree, relative_path) = if let Some(result) =
8242 lsp_store.update(cx, |lsp_store, cx| {
8243 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8244 worktree_store.find_worktree(&worktree_root_target, cx)
8245 })
8246 })? {
8247 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8248 (result.0, relative_path)
8249 } else {
8250 let worktree = lsp_store
8251 .update(cx, |lsp_store, cx| {
8252 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8253 worktree_store.create_worktree(&worktree_root_target, false, cx)
8254 })
8255 })?
8256 .await?;
8257 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8258 lsp_store
8259 .update(cx, |lsp_store, cx| {
8260 if let Some(local) = lsp_store.as_local_mut() {
8261 local.register_language_server_for_invisible_worktree(
8262 &worktree,
8263 language_server_id,
8264 cx,
8265 )
8266 }
8267 })
8268 .ok();
8269 }
8270 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8271 let relative_path = if let Some(known_path) = known_relative_path {
8272 known_path
8273 } else {
8274 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8275 .into_arc()
8276 };
8277 (worktree, relative_path)
8278 };
8279 let project_path = ProjectPath {
8280 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8281 path: relative_path,
8282 };
8283 lsp_store
8284 .update(cx, |lsp_store, cx| {
8285 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8286 buffer_store.open_buffer(project_path, cx)
8287 })
8288 })?
8289 .await
8290 })
8291 }
8292
8293 fn request_multiple_lsp_locally<P, R>(
8294 &mut self,
8295 buffer: &Entity<Buffer>,
8296 position: Option<P>,
8297 request: R,
8298 cx: &mut Context<Self>,
8299 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8300 where
8301 P: ToOffset,
8302 R: LspCommand + Clone,
8303 <R::LspRequest as lsp::request::Request>::Result: Send,
8304 <R::LspRequest as lsp::request::Request>::Params: Send,
8305 {
8306 let Some(local) = self.as_local() else {
8307 return Task::ready(Vec::new());
8308 };
8309
8310 let snapshot = buffer.read(cx).snapshot();
8311 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8312
8313 let server_ids = buffer.update(cx, |buffer, cx| {
8314 local
8315 .language_servers_for_buffer(buffer, cx)
8316 .filter(|(adapter, _)| {
8317 scope
8318 .as_ref()
8319 .map(|scope| scope.language_allowed(&adapter.name))
8320 .unwrap_or(true)
8321 })
8322 .map(|(_, server)| server.server_id())
8323 .filter(|server_id| {
8324 self.as_local().is_none_or(|local| {
8325 local
8326 .buffers_opened_in_servers
8327 .get(&snapshot.remote_id())
8328 .is_some_and(|servers| servers.contains(server_id))
8329 })
8330 })
8331 .collect::<Vec<_>>()
8332 });
8333
8334 let mut response_results = server_ids
8335 .into_iter()
8336 .map(|server_id| {
8337 let task = self.request_lsp(
8338 buffer.clone(),
8339 LanguageServerToQuery::Other(server_id),
8340 request.clone(),
8341 cx,
8342 );
8343 async move { (server_id, task.await) }
8344 })
8345 .collect::<FuturesUnordered<_>>();
8346
8347 cx.background_spawn(async move {
8348 let mut responses = Vec::with_capacity(response_results.len());
8349 while let Some((server_id, response_result)) = response_results.next().await {
8350 match response_result {
8351 Ok(response) => responses.push((server_id, response)),
8352 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8353 }
8354 }
8355 responses
8356 })
8357 }
8358
8359 async fn handle_lsp_command<T: LspCommand>(
8360 this: Entity<Self>,
8361 envelope: TypedEnvelope<T::ProtoRequest>,
8362 mut cx: AsyncApp,
8363 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8364 where
8365 <T::LspRequest as lsp::request::Request>::Params: Send,
8366 <T::LspRequest as lsp::request::Request>::Result: Send,
8367 {
8368 let sender_id = envelope.original_sender_id().unwrap_or_default();
8369 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8370 let buffer_handle = this.update(&mut cx, |this, cx| {
8371 this.buffer_store.read(cx).get_existing(buffer_id)
8372 })??;
8373 let request = T::from_proto(
8374 envelope.payload,
8375 this.clone(),
8376 buffer_handle.clone(),
8377 cx.clone(),
8378 )
8379 .await?;
8380 let response = this
8381 .update(&mut cx, |this, cx| {
8382 this.request_lsp(
8383 buffer_handle.clone(),
8384 LanguageServerToQuery::FirstCapable,
8385 request,
8386 cx,
8387 )
8388 })?
8389 .await?;
8390 this.update(&mut cx, |this, cx| {
8391 Ok(T::response_to_proto(
8392 response,
8393 this,
8394 sender_id,
8395 &buffer_handle.read(cx).version(),
8396 cx,
8397 ))
8398 })?
8399 }
8400
8401 async fn handle_lsp_query(
8402 lsp_store: Entity<Self>,
8403 envelope: TypedEnvelope<proto::LspQuery>,
8404 mut cx: AsyncApp,
8405 ) -> Result<proto::Ack> {
8406 use proto::lsp_query::Request;
8407 let sender_id = envelope.original_sender_id().unwrap_or_default();
8408 let lsp_query = envelope.payload;
8409 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8410 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8411 match lsp_query.request.context("invalid LSP query request")? {
8412 Request::GetReferences(get_references) => {
8413 let position = get_references.position.clone().and_then(deserialize_anchor);
8414 Self::query_lsp_locally::<GetReferences>(
8415 lsp_store,
8416 server_id,
8417 sender_id,
8418 lsp_request_id,
8419 get_references,
8420 position,
8421 &mut cx,
8422 )
8423 .await?;
8424 }
8425 Request::GetDocumentColor(get_document_color) => {
8426 Self::query_lsp_locally::<GetDocumentColor>(
8427 lsp_store,
8428 server_id,
8429 sender_id,
8430 lsp_request_id,
8431 get_document_color,
8432 None,
8433 &mut cx,
8434 )
8435 .await?;
8436 }
8437 Request::GetHover(get_hover) => {
8438 let position = get_hover.position.clone().and_then(deserialize_anchor);
8439 Self::query_lsp_locally::<GetHover>(
8440 lsp_store,
8441 server_id,
8442 sender_id,
8443 lsp_request_id,
8444 get_hover,
8445 position,
8446 &mut cx,
8447 )
8448 .await?;
8449 }
8450 Request::GetCodeActions(get_code_actions) => {
8451 Self::query_lsp_locally::<GetCodeActions>(
8452 lsp_store,
8453 server_id,
8454 sender_id,
8455 lsp_request_id,
8456 get_code_actions,
8457 None,
8458 &mut cx,
8459 )
8460 .await?;
8461 }
8462 Request::GetSignatureHelp(get_signature_help) => {
8463 let position = get_signature_help
8464 .position
8465 .clone()
8466 .and_then(deserialize_anchor);
8467 Self::query_lsp_locally::<GetSignatureHelp>(
8468 lsp_store,
8469 server_id,
8470 sender_id,
8471 lsp_request_id,
8472 get_signature_help,
8473 position,
8474 &mut cx,
8475 )
8476 .await?;
8477 }
8478 Request::GetCodeLens(get_code_lens) => {
8479 Self::query_lsp_locally::<GetCodeLens>(
8480 lsp_store,
8481 server_id,
8482 sender_id,
8483 lsp_request_id,
8484 get_code_lens,
8485 None,
8486 &mut cx,
8487 )
8488 .await?;
8489 }
8490 Request::GetDefinition(get_definition) => {
8491 let position = get_definition.position.clone().and_then(deserialize_anchor);
8492 Self::query_lsp_locally::<GetDefinitions>(
8493 lsp_store,
8494 server_id,
8495 sender_id,
8496 lsp_request_id,
8497 get_definition,
8498 position,
8499 &mut cx,
8500 )
8501 .await?;
8502 }
8503 Request::GetDeclaration(get_declaration) => {
8504 let position = get_declaration
8505 .position
8506 .clone()
8507 .and_then(deserialize_anchor);
8508 Self::query_lsp_locally::<GetDeclarations>(
8509 lsp_store,
8510 server_id,
8511 sender_id,
8512 lsp_request_id,
8513 get_declaration,
8514 position,
8515 &mut cx,
8516 )
8517 .await?;
8518 }
8519 Request::GetTypeDefinition(get_type_definition) => {
8520 let position = get_type_definition
8521 .position
8522 .clone()
8523 .and_then(deserialize_anchor);
8524 Self::query_lsp_locally::<GetTypeDefinitions>(
8525 lsp_store,
8526 server_id,
8527 sender_id,
8528 lsp_request_id,
8529 get_type_definition,
8530 position,
8531 &mut cx,
8532 )
8533 .await?;
8534 }
8535 Request::GetImplementation(get_implementation) => {
8536 let position = get_implementation
8537 .position
8538 .clone()
8539 .and_then(deserialize_anchor);
8540 Self::query_lsp_locally::<GetImplementations>(
8541 lsp_store,
8542 server_id,
8543 sender_id,
8544 lsp_request_id,
8545 get_implementation,
8546 position,
8547 &mut cx,
8548 )
8549 .await?;
8550 }
8551 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8552 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8553 let version = deserialize_version(get_document_diagnostics.buffer_version());
8554 let buffer = lsp_store.update(&mut cx, |this, cx| {
8555 this.buffer_store.read(cx).get_existing(buffer_id)
8556 })??;
8557 buffer
8558 .update(&mut cx, |buffer, _| {
8559 buffer.wait_for_version(version.clone())
8560 })?
8561 .await?;
8562 lsp_store.update(&mut cx, |lsp_store, cx| {
8563 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8564 let key = LspKey {
8565 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8566 server_queried: server_id,
8567 };
8568 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8569 ) {
8570 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8571 lsp_requests.clear();
8572 };
8573 }
8574
8575 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8576 existing_queries.insert(
8577 lsp_request_id,
8578 cx.spawn(async move |lsp_store, cx| {
8579 let diagnostics_pull = lsp_store
8580 .update(cx, |lsp_store, cx| {
8581 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8582 })
8583 .ok();
8584 if let Some(diagnostics_pull) = diagnostics_pull {
8585 match diagnostics_pull.await {
8586 Ok(()) => {}
8587 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8588 };
8589 }
8590 }),
8591 );
8592 })?;
8593 }
8594 Request::InlayHints(inlay_hints) => {
8595 let query_start = inlay_hints
8596 .start
8597 .clone()
8598 .and_then(deserialize_anchor)
8599 .context("invalid inlay hints range start")?;
8600 let query_end = inlay_hints
8601 .end
8602 .clone()
8603 .and_then(deserialize_anchor)
8604 .context("invalid inlay hints range end")?;
8605 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8606 &lsp_store,
8607 server_id,
8608 lsp_request_id,
8609 &inlay_hints,
8610 query_start..query_end,
8611 &mut cx,
8612 )
8613 .await
8614 .context("preparing inlay hints request")?;
8615 Self::query_lsp_locally::<InlayHints>(
8616 lsp_store,
8617 server_id,
8618 sender_id,
8619 lsp_request_id,
8620 inlay_hints,
8621 None,
8622 &mut cx,
8623 )
8624 .await
8625 .context("querying for inlay hints")?
8626 }
8627 }
8628 Ok(proto::Ack {})
8629 }
8630
8631 async fn handle_lsp_query_response(
8632 lsp_store: Entity<Self>,
8633 envelope: TypedEnvelope<proto::LspQueryResponse>,
8634 cx: AsyncApp,
8635 ) -> Result<()> {
8636 lsp_store.read_with(&cx, |lsp_store, _| {
8637 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8638 upstream_client.handle_lsp_response(envelope.clone());
8639 }
8640 })?;
8641 Ok(())
8642 }
8643
8644 async fn handle_apply_code_action(
8645 this: Entity<Self>,
8646 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8647 mut cx: AsyncApp,
8648 ) -> Result<proto::ApplyCodeActionResponse> {
8649 let sender_id = envelope.original_sender_id().unwrap_or_default();
8650 let action =
8651 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8652 let apply_code_action = this.update(&mut cx, |this, cx| {
8653 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8654 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8655 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8656 })??;
8657
8658 let project_transaction = apply_code_action.await?;
8659 let project_transaction = this.update(&mut cx, |this, cx| {
8660 this.buffer_store.update(cx, |buffer_store, cx| {
8661 buffer_store.serialize_project_transaction_for_peer(
8662 project_transaction,
8663 sender_id,
8664 cx,
8665 )
8666 })
8667 })?;
8668 Ok(proto::ApplyCodeActionResponse {
8669 transaction: Some(project_transaction),
8670 })
8671 }
8672
8673 async fn handle_register_buffer_with_language_servers(
8674 this: Entity<Self>,
8675 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8676 mut cx: AsyncApp,
8677 ) -> Result<proto::Ack> {
8678 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8679 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8680 this.update(&mut cx, |this, cx| {
8681 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8682 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8683 project_id: upstream_project_id,
8684 buffer_id: buffer_id.to_proto(),
8685 only_servers: envelope.payload.only_servers,
8686 });
8687 }
8688
8689 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8690 anyhow::bail!("buffer is not open");
8691 };
8692
8693 let handle = this.register_buffer_with_language_servers(
8694 &buffer,
8695 envelope
8696 .payload
8697 .only_servers
8698 .into_iter()
8699 .filter_map(|selector| {
8700 Some(match selector.selector? {
8701 proto::language_server_selector::Selector::ServerId(server_id) => {
8702 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8703 }
8704 proto::language_server_selector::Selector::Name(name) => {
8705 LanguageServerSelector::Name(LanguageServerName(
8706 SharedString::from(name),
8707 ))
8708 }
8709 })
8710 })
8711 .collect(),
8712 false,
8713 cx,
8714 );
8715 this.buffer_store().update(cx, |buffer_store, _| {
8716 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8717 });
8718
8719 Ok(())
8720 })??;
8721 Ok(proto::Ack {})
8722 }
8723
8724 async fn handle_rename_project_entry(
8725 this: Entity<Self>,
8726 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8727 mut cx: AsyncApp,
8728 ) -> Result<proto::ProjectEntryResponse> {
8729 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8730 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8731 let new_path =
8732 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8733
8734 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8735 .update(&mut cx, |this, cx| {
8736 let (worktree, entry) = this
8737 .worktree_store
8738 .read(cx)
8739 .worktree_and_entry_for_id(entry_id, cx)?;
8740 let new_worktree = this
8741 .worktree_store
8742 .read(cx)
8743 .worktree_for_id(new_worktree_id, cx)?;
8744 Some((
8745 this.worktree_store.clone(),
8746 worktree,
8747 new_worktree,
8748 entry.clone(),
8749 ))
8750 })?
8751 .context("worktree not found")?;
8752 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8753 (worktree.absolutize(&old_entry.path), worktree.id())
8754 })?;
8755 let new_abs_path =
8756 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8757
8758 let _transaction = Self::will_rename_entry(
8759 this.downgrade(),
8760 old_worktree_id,
8761 &old_abs_path,
8762 &new_abs_path,
8763 old_entry.is_dir(),
8764 cx.clone(),
8765 )
8766 .await;
8767 let response = WorktreeStore::handle_rename_project_entry(
8768 worktree_store,
8769 envelope.payload,
8770 cx.clone(),
8771 )
8772 .await;
8773 this.read_with(&cx, |this, _| {
8774 this.did_rename_entry(
8775 old_worktree_id,
8776 &old_abs_path,
8777 &new_abs_path,
8778 old_entry.is_dir(),
8779 );
8780 })
8781 .ok();
8782 response
8783 }
8784
8785 async fn handle_update_diagnostic_summary(
8786 this: Entity<Self>,
8787 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8788 mut cx: AsyncApp,
8789 ) -> Result<()> {
8790 this.update(&mut cx, |lsp_store, cx| {
8791 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8792 let mut updated_diagnostics_paths = HashMap::default();
8793 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8794 for message_summary in envelope
8795 .payload
8796 .summary
8797 .into_iter()
8798 .chain(envelope.payload.more_summaries)
8799 {
8800 let project_path = ProjectPath {
8801 worktree_id,
8802 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8803 };
8804 let path = project_path.path.clone();
8805 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8806 let summary = DiagnosticSummary {
8807 error_count: message_summary.error_count as usize,
8808 warning_count: message_summary.warning_count as usize,
8809 };
8810
8811 if summary.is_empty() {
8812 if let Some(worktree_summaries) =
8813 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8814 && let Some(summaries) = worktree_summaries.get_mut(&path)
8815 {
8816 summaries.remove(&server_id);
8817 if summaries.is_empty() {
8818 worktree_summaries.remove(&path);
8819 }
8820 }
8821 } else {
8822 lsp_store
8823 .diagnostic_summaries
8824 .entry(worktree_id)
8825 .or_default()
8826 .entry(path)
8827 .or_default()
8828 .insert(server_id, summary);
8829 }
8830
8831 if let Some((_, project_id)) = &lsp_store.downstream_client {
8832 match &mut diagnostics_summary {
8833 Some(diagnostics_summary) => {
8834 diagnostics_summary
8835 .more_summaries
8836 .push(proto::DiagnosticSummary {
8837 path: project_path.path.as_ref().to_proto(),
8838 language_server_id: server_id.0 as u64,
8839 error_count: summary.error_count as u32,
8840 warning_count: summary.warning_count as u32,
8841 })
8842 }
8843 None => {
8844 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8845 project_id: *project_id,
8846 worktree_id: worktree_id.to_proto(),
8847 summary: Some(proto::DiagnosticSummary {
8848 path: project_path.path.as_ref().to_proto(),
8849 language_server_id: server_id.0 as u64,
8850 error_count: summary.error_count as u32,
8851 warning_count: summary.warning_count as u32,
8852 }),
8853 more_summaries: Vec::new(),
8854 })
8855 }
8856 }
8857 }
8858 updated_diagnostics_paths
8859 .entry(server_id)
8860 .or_insert_with(Vec::new)
8861 .push(project_path);
8862 }
8863
8864 if let Some((diagnostics_summary, (downstream_client, _))) =
8865 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8866 {
8867 downstream_client.send(diagnostics_summary).log_err();
8868 }
8869 for (server_id, paths) in updated_diagnostics_paths {
8870 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8871 }
8872 Ok(())
8873 })?
8874 }
8875
8876 async fn handle_start_language_server(
8877 lsp_store: Entity<Self>,
8878 envelope: TypedEnvelope<proto::StartLanguageServer>,
8879 mut cx: AsyncApp,
8880 ) -> Result<()> {
8881 let server = envelope.payload.server.context("invalid server")?;
8882 let server_capabilities =
8883 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8884 .with_context(|| {
8885 format!(
8886 "incorrect server capabilities {}",
8887 envelope.payload.capabilities
8888 )
8889 })?;
8890 lsp_store.update(&mut cx, |lsp_store, cx| {
8891 let server_id = LanguageServerId(server.id as usize);
8892 let server_name = LanguageServerName::from_proto(server.name.clone());
8893 lsp_store
8894 .lsp_server_capabilities
8895 .insert(server_id, server_capabilities);
8896 lsp_store.language_server_statuses.insert(
8897 server_id,
8898 LanguageServerStatus {
8899 name: server_name.clone(),
8900 pending_work: Default::default(),
8901 has_pending_diagnostic_updates: false,
8902 progress_tokens: Default::default(),
8903 worktree: server.worktree_id.map(WorktreeId::from_proto),
8904 },
8905 );
8906 cx.emit(LspStoreEvent::LanguageServerAdded(
8907 server_id,
8908 server_name,
8909 server.worktree_id.map(WorktreeId::from_proto),
8910 ));
8911 cx.notify();
8912 })?;
8913 Ok(())
8914 }
8915
8916 async fn handle_update_language_server(
8917 lsp_store: Entity<Self>,
8918 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8919 mut cx: AsyncApp,
8920 ) -> Result<()> {
8921 lsp_store.update(&mut cx, |lsp_store, cx| {
8922 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8923
8924 match envelope.payload.variant.context("invalid variant")? {
8925 proto::update_language_server::Variant::WorkStart(payload) => {
8926 lsp_store.on_lsp_work_start(
8927 language_server_id,
8928 payload.token,
8929 LanguageServerProgress {
8930 title: payload.title,
8931 is_disk_based_diagnostics_progress: false,
8932 is_cancellable: payload.is_cancellable.unwrap_or(false),
8933 message: payload.message,
8934 percentage: payload.percentage.map(|p| p as usize),
8935 last_update_at: cx.background_executor().now(),
8936 },
8937 cx,
8938 );
8939 }
8940 proto::update_language_server::Variant::WorkProgress(payload) => {
8941 lsp_store.on_lsp_work_progress(
8942 language_server_id,
8943 payload.token,
8944 LanguageServerProgress {
8945 title: None,
8946 is_disk_based_diagnostics_progress: false,
8947 is_cancellable: payload.is_cancellable.unwrap_or(false),
8948 message: payload.message,
8949 percentage: payload.percentage.map(|p| p as usize),
8950 last_update_at: cx.background_executor().now(),
8951 },
8952 cx,
8953 );
8954 }
8955
8956 proto::update_language_server::Variant::WorkEnd(payload) => {
8957 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8958 }
8959
8960 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8961 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8962 }
8963
8964 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8965 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8966 }
8967
8968 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8969 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8970 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8971 cx.emit(LspStoreEvent::LanguageServerUpdate {
8972 language_server_id,
8973 name: envelope
8974 .payload
8975 .server_name
8976 .map(SharedString::new)
8977 .map(LanguageServerName),
8978 message: non_lsp,
8979 });
8980 }
8981 }
8982
8983 Ok(())
8984 })?
8985 }
8986
8987 async fn handle_language_server_log(
8988 this: Entity<Self>,
8989 envelope: TypedEnvelope<proto::LanguageServerLog>,
8990 mut cx: AsyncApp,
8991 ) -> Result<()> {
8992 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8993 let log_type = envelope
8994 .payload
8995 .log_type
8996 .map(LanguageServerLogType::from_proto)
8997 .context("invalid language server log type")?;
8998
8999 let message = envelope.payload.message;
9000
9001 this.update(&mut cx, |_, cx| {
9002 cx.emit(LspStoreEvent::LanguageServerLog(
9003 language_server_id,
9004 log_type,
9005 message,
9006 ));
9007 })
9008 }
9009
9010 async fn handle_lsp_ext_cancel_flycheck(
9011 lsp_store: Entity<Self>,
9012 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9013 cx: AsyncApp,
9014 ) -> Result<proto::Ack> {
9015 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9016 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9017 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9018 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9019 } else {
9020 None
9021 }
9022 })?;
9023 if let Some(task) = task {
9024 task.context("handling lsp ext cancel flycheck")?;
9025 }
9026
9027 Ok(proto::Ack {})
9028 }
9029
9030 async fn handle_lsp_ext_run_flycheck(
9031 lsp_store: Entity<Self>,
9032 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9033 mut cx: AsyncApp,
9034 ) -> Result<proto::Ack> {
9035 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9036 lsp_store.update(&mut cx, |lsp_store, cx| {
9037 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9038 let text_document = if envelope.payload.current_file_only {
9039 let buffer_id = envelope
9040 .payload
9041 .buffer_id
9042 .map(|id| BufferId::new(id))
9043 .transpose()?;
9044 buffer_id
9045 .and_then(|buffer_id| {
9046 lsp_store
9047 .buffer_store()
9048 .read(cx)
9049 .get(buffer_id)
9050 .and_then(|buffer| {
9051 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9052 })
9053 .map(|path| make_text_document_identifier(&path))
9054 })
9055 .transpose()?
9056 } else {
9057 None
9058 };
9059 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9060 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9061 )?;
9062 }
9063 anyhow::Ok(())
9064 })??;
9065
9066 Ok(proto::Ack {})
9067 }
9068
9069 async fn handle_lsp_ext_clear_flycheck(
9070 lsp_store: Entity<Self>,
9071 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9072 cx: AsyncApp,
9073 ) -> Result<proto::Ack> {
9074 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9075 lsp_store
9076 .read_with(&cx, |lsp_store, _| {
9077 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9078 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9079 } else {
9080 None
9081 }
9082 })
9083 .context("handling lsp ext clear flycheck")?;
9084
9085 Ok(proto::Ack {})
9086 }
9087
9088 pub fn disk_based_diagnostics_started(
9089 &mut self,
9090 language_server_id: LanguageServerId,
9091 cx: &mut Context<Self>,
9092 ) {
9093 if let Some(language_server_status) =
9094 self.language_server_statuses.get_mut(&language_server_id)
9095 {
9096 language_server_status.has_pending_diagnostic_updates = true;
9097 }
9098
9099 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9100 cx.emit(LspStoreEvent::LanguageServerUpdate {
9101 language_server_id,
9102 name: self
9103 .language_server_adapter_for_id(language_server_id)
9104 .map(|adapter| adapter.name()),
9105 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9106 Default::default(),
9107 ),
9108 })
9109 }
9110
9111 pub fn disk_based_diagnostics_finished(
9112 &mut self,
9113 language_server_id: LanguageServerId,
9114 cx: &mut Context<Self>,
9115 ) {
9116 if let Some(language_server_status) =
9117 self.language_server_statuses.get_mut(&language_server_id)
9118 {
9119 language_server_status.has_pending_diagnostic_updates = false;
9120 }
9121
9122 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9123 cx.emit(LspStoreEvent::LanguageServerUpdate {
9124 language_server_id,
9125 name: self
9126 .language_server_adapter_for_id(language_server_id)
9127 .map(|adapter| adapter.name()),
9128 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9129 Default::default(),
9130 ),
9131 })
9132 }
9133
9134 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9135 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9136 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9137 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9138 // the language server might take some time to publish diagnostics.
9139 fn simulate_disk_based_diagnostics_events_if_needed(
9140 &mut self,
9141 language_server_id: LanguageServerId,
9142 cx: &mut Context<Self>,
9143 ) {
9144 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9145
9146 let Some(LanguageServerState::Running {
9147 simulate_disk_based_diagnostics_completion,
9148 adapter,
9149 ..
9150 }) = self
9151 .as_local_mut()
9152 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9153 else {
9154 return;
9155 };
9156
9157 if adapter.disk_based_diagnostics_progress_token.is_some() {
9158 return;
9159 }
9160
9161 let prev_task =
9162 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9163 cx.background_executor()
9164 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9165 .await;
9166
9167 this.update(cx, |this, cx| {
9168 this.disk_based_diagnostics_finished(language_server_id, cx);
9169
9170 if let Some(LanguageServerState::Running {
9171 simulate_disk_based_diagnostics_completion,
9172 ..
9173 }) = this.as_local_mut().and_then(|local_store| {
9174 local_store.language_servers.get_mut(&language_server_id)
9175 }) {
9176 *simulate_disk_based_diagnostics_completion = None;
9177 }
9178 })
9179 .ok();
9180 }));
9181
9182 if prev_task.is_none() {
9183 self.disk_based_diagnostics_started(language_server_id, cx);
9184 }
9185 }
9186
9187 pub fn language_server_statuses(
9188 &self,
9189 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9190 self.language_server_statuses
9191 .iter()
9192 .map(|(key, value)| (*key, value))
9193 }
9194
9195 pub(super) fn did_rename_entry(
9196 &self,
9197 worktree_id: WorktreeId,
9198 old_path: &Path,
9199 new_path: &Path,
9200 is_dir: bool,
9201 ) {
9202 maybe!({
9203 let local_store = self.as_local()?;
9204
9205 let old_uri = lsp::Uri::from_file_path(old_path)
9206 .ok()
9207 .map(|uri| uri.to_string())?;
9208 let new_uri = lsp::Uri::from_file_path(new_path)
9209 .ok()
9210 .map(|uri| uri.to_string())?;
9211
9212 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9213 let Some(filter) = local_store
9214 .language_server_paths_watched_for_rename
9215 .get(&language_server.server_id())
9216 else {
9217 continue;
9218 };
9219
9220 if filter.should_send_did_rename(&old_uri, is_dir) {
9221 language_server
9222 .notify::<DidRenameFiles>(RenameFilesParams {
9223 files: vec![FileRename {
9224 old_uri: old_uri.clone(),
9225 new_uri: new_uri.clone(),
9226 }],
9227 })
9228 .ok();
9229 }
9230 }
9231 Some(())
9232 });
9233 }
9234
9235 pub(super) fn will_rename_entry(
9236 this: WeakEntity<Self>,
9237 worktree_id: WorktreeId,
9238 old_path: &Path,
9239 new_path: &Path,
9240 is_dir: bool,
9241 cx: AsyncApp,
9242 ) -> Task<ProjectTransaction> {
9243 let old_uri = lsp::Uri::from_file_path(old_path)
9244 .ok()
9245 .map(|uri| uri.to_string());
9246 let new_uri = lsp::Uri::from_file_path(new_path)
9247 .ok()
9248 .map(|uri| uri.to_string());
9249 cx.spawn(async move |cx| {
9250 let mut tasks = vec![];
9251 this.update(cx, |this, cx| {
9252 let local_store = this.as_local()?;
9253 let old_uri = old_uri?;
9254 let new_uri = new_uri?;
9255 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9256 let Some(filter) = local_store
9257 .language_server_paths_watched_for_rename
9258 .get(&language_server.server_id())
9259 else {
9260 continue;
9261 };
9262
9263 if filter.should_send_will_rename(&old_uri, is_dir) {
9264 let apply_edit = cx.spawn({
9265 let old_uri = old_uri.clone();
9266 let new_uri = new_uri.clone();
9267 let language_server = language_server.clone();
9268 async move |this, cx| {
9269 let edit = language_server
9270 .request::<WillRenameFiles>(RenameFilesParams {
9271 files: vec![FileRename { old_uri, new_uri }],
9272 })
9273 .await
9274 .into_response()
9275 .context("will rename files")
9276 .log_err()
9277 .flatten()?;
9278
9279 let transaction = LocalLspStore::deserialize_workspace_edit(
9280 this.upgrade()?,
9281 edit,
9282 false,
9283 language_server.clone(),
9284 cx,
9285 )
9286 .await
9287 .ok()?;
9288 Some(transaction)
9289 }
9290 });
9291 tasks.push(apply_edit);
9292 }
9293 }
9294 Some(())
9295 })
9296 .ok()
9297 .flatten();
9298 let mut merged_transaction = ProjectTransaction::default();
9299 for task in tasks {
9300 // Await on tasks sequentially so that the order of application of edits is deterministic
9301 // (at least with regards to the order of registration of language servers)
9302 if let Some(transaction) = task.await {
9303 for (buffer, buffer_transaction) in transaction.0 {
9304 merged_transaction.0.insert(buffer, buffer_transaction);
9305 }
9306 }
9307 }
9308 merged_transaction
9309 })
9310 }
9311
9312 fn lsp_notify_abs_paths_changed(
9313 &mut self,
9314 server_id: LanguageServerId,
9315 changes: Vec<PathEvent>,
9316 ) {
9317 maybe!({
9318 let server = self.language_server_for_id(server_id)?;
9319 let changes = changes
9320 .into_iter()
9321 .filter_map(|event| {
9322 let typ = match event.kind? {
9323 PathEventKind::Created => lsp::FileChangeType::CREATED,
9324 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9325 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9326 };
9327 Some(lsp::FileEvent {
9328 uri: file_path_to_lsp_url(&event.path).log_err()?,
9329 typ,
9330 })
9331 })
9332 .collect::<Vec<_>>();
9333 if !changes.is_empty() {
9334 server
9335 .notify::<lsp::notification::DidChangeWatchedFiles>(
9336 lsp::DidChangeWatchedFilesParams { changes },
9337 )
9338 .ok();
9339 }
9340 Some(())
9341 });
9342 }
9343
9344 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9345 self.as_local()?.language_server_for_id(id)
9346 }
9347
9348 fn on_lsp_progress(
9349 &mut self,
9350 progress: lsp::ProgressParams,
9351 language_server_id: LanguageServerId,
9352 disk_based_diagnostics_progress_token: Option<String>,
9353 cx: &mut Context<Self>,
9354 ) {
9355 let token = match progress.token {
9356 lsp::NumberOrString::String(token) => token,
9357 lsp::NumberOrString::Number(token) => {
9358 log::info!("skipping numeric progress token {}", token);
9359 return;
9360 }
9361 };
9362
9363 match progress.value {
9364 lsp::ProgressParamsValue::WorkDone(progress) => {
9365 self.handle_work_done_progress(
9366 progress,
9367 language_server_id,
9368 disk_based_diagnostics_progress_token,
9369 token,
9370 cx,
9371 );
9372 }
9373 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9374 let identifier = token.split_once("id:").map(|(_, id)| id.to_owned());
9375 if let Some(LanguageServerState::Running {
9376 workspace_diagnostics_refresh_tasks,
9377 ..
9378 }) = self
9379 .as_local_mut()
9380 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9381 && let Some(workspace_diagnostics) =
9382 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9383 {
9384 workspace_diagnostics.progress_tx.try_send(()).ok();
9385 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9386 }
9387 }
9388 }
9389 }
9390
9391 fn handle_work_done_progress(
9392 &mut self,
9393 progress: lsp::WorkDoneProgress,
9394 language_server_id: LanguageServerId,
9395 disk_based_diagnostics_progress_token: Option<String>,
9396 token: String,
9397 cx: &mut Context<Self>,
9398 ) {
9399 let language_server_status =
9400 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9401 status
9402 } else {
9403 return;
9404 };
9405
9406 if !language_server_status.progress_tokens.contains(&token) {
9407 return;
9408 }
9409
9410 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9411 .as_ref()
9412 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9413
9414 match progress {
9415 lsp::WorkDoneProgress::Begin(report) => {
9416 if is_disk_based_diagnostics_progress {
9417 self.disk_based_diagnostics_started(language_server_id, cx);
9418 }
9419 self.on_lsp_work_start(
9420 language_server_id,
9421 token.clone(),
9422 LanguageServerProgress {
9423 title: Some(report.title),
9424 is_disk_based_diagnostics_progress,
9425 is_cancellable: report.cancellable.unwrap_or(false),
9426 message: report.message.clone(),
9427 percentage: report.percentage.map(|p| p as usize),
9428 last_update_at: cx.background_executor().now(),
9429 },
9430 cx,
9431 );
9432 }
9433 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9434 language_server_id,
9435 token,
9436 LanguageServerProgress {
9437 title: None,
9438 is_disk_based_diagnostics_progress,
9439 is_cancellable: report.cancellable.unwrap_or(false),
9440 message: report.message,
9441 percentage: report.percentage.map(|p| p as usize),
9442 last_update_at: cx.background_executor().now(),
9443 },
9444 cx,
9445 ),
9446 lsp::WorkDoneProgress::End(_) => {
9447 language_server_status.progress_tokens.remove(&token);
9448 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9449 if is_disk_based_diagnostics_progress {
9450 self.disk_based_diagnostics_finished(language_server_id, cx);
9451 }
9452 }
9453 }
9454 }
9455
9456 fn on_lsp_work_start(
9457 &mut self,
9458 language_server_id: LanguageServerId,
9459 token: String,
9460 progress: LanguageServerProgress,
9461 cx: &mut Context<Self>,
9462 ) {
9463 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9464 status.pending_work.insert(token.clone(), progress.clone());
9465 cx.notify();
9466 }
9467 cx.emit(LspStoreEvent::LanguageServerUpdate {
9468 language_server_id,
9469 name: self
9470 .language_server_adapter_for_id(language_server_id)
9471 .map(|adapter| adapter.name()),
9472 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9473 token,
9474 title: progress.title,
9475 message: progress.message,
9476 percentage: progress.percentage.map(|p| p as u32),
9477 is_cancellable: Some(progress.is_cancellable),
9478 }),
9479 })
9480 }
9481
9482 fn on_lsp_work_progress(
9483 &mut self,
9484 language_server_id: LanguageServerId,
9485 token: String,
9486 progress: LanguageServerProgress,
9487 cx: &mut Context<Self>,
9488 ) {
9489 let mut did_update = false;
9490 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9491 match status.pending_work.entry(token.clone()) {
9492 btree_map::Entry::Vacant(entry) => {
9493 entry.insert(progress.clone());
9494 did_update = true;
9495 }
9496 btree_map::Entry::Occupied(mut entry) => {
9497 let entry = entry.get_mut();
9498 if (progress.last_update_at - entry.last_update_at)
9499 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9500 {
9501 entry.last_update_at = progress.last_update_at;
9502 if progress.message.is_some() {
9503 entry.message = progress.message.clone();
9504 }
9505 if progress.percentage.is_some() {
9506 entry.percentage = progress.percentage;
9507 }
9508 if progress.is_cancellable != entry.is_cancellable {
9509 entry.is_cancellable = progress.is_cancellable;
9510 }
9511 did_update = true;
9512 }
9513 }
9514 }
9515 }
9516
9517 if did_update {
9518 cx.emit(LspStoreEvent::LanguageServerUpdate {
9519 language_server_id,
9520 name: self
9521 .language_server_adapter_for_id(language_server_id)
9522 .map(|adapter| adapter.name()),
9523 message: proto::update_language_server::Variant::WorkProgress(
9524 proto::LspWorkProgress {
9525 token,
9526 message: progress.message,
9527 percentage: progress.percentage.map(|p| p as u32),
9528 is_cancellable: Some(progress.is_cancellable),
9529 },
9530 ),
9531 })
9532 }
9533 }
9534
9535 fn on_lsp_work_end(
9536 &mut self,
9537 language_server_id: LanguageServerId,
9538 token: String,
9539 cx: &mut Context<Self>,
9540 ) {
9541 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9542 if let Some(work) = status.pending_work.remove(&token)
9543 && !work.is_disk_based_diagnostics_progress
9544 {
9545 cx.emit(LspStoreEvent::RefreshInlayHints(language_server_id));
9546 }
9547 cx.notify();
9548 }
9549
9550 cx.emit(LspStoreEvent::LanguageServerUpdate {
9551 language_server_id,
9552 name: self
9553 .language_server_adapter_for_id(language_server_id)
9554 .map(|adapter| adapter.name()),
9555 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9556 })
9557 }
9558
9559 pub async fn handle_resolve_completion_documentation(
9560 this: Entity<Self>,
9561 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9562 mut cx: AsyncApp,
9563 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9564 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9565
9566 let completion = this
9567 .read_with(&cx, |this, cx| {
9568 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9569 let server = this
9570 .language_server_for_id(id)
9571 .with_context(|| format!("No language server {id}"))?;
9572
9573 anyhow::Ok(cx.background_spawn(async move {
9574 let can_resolve = server
9575 .capabilities()
9576 .completion_provider
9577 .as_ref()
9578 .and_then(|options| options.resolve_provider)
9579 .unwrap_or(false);
9580 if can_resolve {
9581 server
9582 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9583 .await
9584 .into_response()
9585 .context("resolve completion item")
9586 } else {
9587 anyhow::Ok(lsp_completion)
9588 }
9589 }))
9590 })??
9591 .await?;
9592
9593 let mut documentation_is_markdown = false;
9594 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9595 let documentation = match completion.documentation {
9596 Some(lsp::Documentation::String(text)) => text,
9597
9598 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9599 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9600 value
9601 }
9602
9603 _ => String::new(),
9604 };
9605
9606 // If we have a new buffer_id, that means we're talking to a new client
9607 // and want to check for new text_edits in the completion too.
9608 let mut old_replace_start = None;
9609 let mut old_replace_end = None;
9610 let mut old_insert_start = None;
9611 let mut old_insert_end = None;
9612 let mut new_text = String::default();
9613 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9614 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9615 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9616 anyhow::Ok(buffer.read(cx).snapshot())
9617 })??;
9618
9619 if let Some(text_edit) = completion.text_edit.as_ref() {
9620 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9621
9622 if let Some(mut edit) = edit {
9623 LineEnding::normalize(&mut edit.new_text);
9624
9625 new_text = edit.new_text;
9626 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9627 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9628 if let Some(insert_range) = edit.insert_range {
9629 old_insert_start = Some(serialize_anchor(&insert_range.start));
9630 old_insert_end = Some(serialize_anchor(&insert_range.end));
9631 }
9632 }
9633 }
9634 }
9635
9636 Ok(proto::ResolveCompletionDocumentationResponse {
9637 documentation,
9638 documentation_is_markdown,
9639 old_replace_start,
9640 old_replace_end,
9641 new_text,
9642 lsp_completion,
9643 old_insert_start,
9644 old_insert_end,
9645 })
9646 }
9647
9648 async fn handle_on_type_formatting(
9649 this: Entity<Self>,
9650 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9651 mut cx: AsyncApp,
9652 ) -> Result<proto::OnTypeFormattingResponse> {
9653 let on_type_formatting = this.update(&mut cx, |this, cx| {
9654 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9655 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9656 let position = envelope
9657 .payload
9658 .position
9659 .and_then(deserialize_anchor)
9660 .context("invalid position")?;
9661 anyhow::Ok(this.apply_on_type_formatting(
9662 buffer,
9663 position,
9664 envelope.payload.trigger.clone(),
9665 cx,
9666 ))
9667 })??;
9668
9669 let transaction = on_type_formatting
9670 .await?
9671 .as_ref()
9672 .map(language::proto::serialize_transaction);
9673 Ok(proto::OnTypeFormattingResponse { transaction })
9674 }
9675
9676 async fn handle_refresh_inlay_hints(
9677 lsp_store: Entity<Self>,
9678 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9679 mut cx: AsyncApp,
9680 ) -> Result<proto::Ack> {
9681 lsp_store.update(&mut cx, |_, cx| {
9682 cx.emit(LspStoreEvent::RefreshInlayHints(
9683 LanguageServerId::from_proto(envelope.payload.server_id),
9684 ));
9685 })?;
9686 Ok(proto::Ack {})
9687 }
9688
9689 async fn handle_pull_workspace_diagnostics(
9690 lsp_store: Entity<Self>,
9691 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9692 mut cx: AsyncApp,
9693 ) -> Result<proto::Ack> {
9694 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9695 lsp_store.update(&mut cx, |lsp_store, _| {
9696 lsp_store.pull_workspace_diagnostics(server_id);
9697 })?;
9698 Ok(proto::Ack {})
9699 }
9700
9701 async fn handle_get_color_presentation(
9702 lsp_store: Entity<Self>,
9703 envelope: TypedEnvelope<proto::GetColorPresentation>,
9704 mut cx: AsyncApp,
9705 ) -> Result<proto::GetColorPresentationResponse> {
9706 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9707 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9708 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9709 })??;
9710
9711 let color = envelope
9712 .payload
9713 .color
9714 .context("invalid color resolve request")?;
9715 let start = color
9716 .lsp_range_start
9717 .context("invalid color resolve request")?;
9718 let end = color
9719 .lsp_range_end
9720 .context("invalid color resolve request")?;
9721
9722 let color = DocumentColor {
9723 lsp_range: lsp::Range {
9724 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9725 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9726 },
9727 color: lsp::Color {
9728 red: color.red,
9729 green: color.green,
9730 blue: color.blue,
9731 alpha: color.alpha,
9732 },
9733 resolved: false,
9734 color_presentations: Vec::new(),
9735 };
9736 let resolved_color = lsp_store
9737 .update(&mut cx, |lsp_store, cx| {
9738 lsp_store.resolve_color_presentation(
9739 color,
9740 buffer.clone(),
9741 LanguageServerId(envelope.payload.server_id as usize),
9742 cx,
9743 )
9744 })?
9745 .await
9746 .context("resolving color presentation")?;
9747
9748 Ok(proto::GetColorPresentationResponse {
9749 presentations: resolved_color
9750 .color_presentations
9751 .into_iter()
9752 .map(|presentation| proto::ColorPresentation {
9753 label: presentation.label.to_string(),
9754 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9755 additional_text_edits: presentation
9756 .additional_text_edits
9757 .into_iter()
9758 .map(serialize_lsp_edit)
9759 .collect(),
9760 })
9761 .collect(),
9762 })
9763 }
9764
9765 async fn handle_resolve_inlay_hint(
9766 lsp_store: Entity<Self>,
9767 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9768 mut cx: AsyncApp,
9769 ) -> Result<proto::ResolveInlayHintResponse> {
9770 let proto_hint = envelope
9771 .payload
9772 .hint
9773 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9774 let hint = InlayHints::proto_to_project_hint(proto_hint)
9775 .context("resolved proto inlay hint conversion")?;
9776 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9777 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9778 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9779 })??;
9780 let response_hint = lsp_store
9781 .update(&mut cx, |lsp_store, cx| {
9782 lsp_store.resolve_inlay_hint(
9783 hint,
9784 buffer,
9785 LanguageServerId(envelope.payload.language_server_id as usize),
9786 cx,
9787 )
9788 })?
9789 .await
9790 .context("inlay hints fetch")?;
9791 Ok(proto::ResolveInlayHintResponse {
9792 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9793 })
9794 }
9795
9796 async fn handle_refresh_code_lens(
9797 this: Entity<Self>,
9798 _: TypedEnvelope<proto::RefreshCodeLens>,
9799 mut cx: AsyncApp,
9800 ) -> Result<proto::Ack> {
9801 this.update(&mut cx, |_, cx| {
9802 cx.emit(LspStoreEvent::RefreshCodeLens);
9803 })?;
9804 Ok(proto::Ack {})
9805 }
9806
9807 async fn handle_open_buffer_for_symbol(
9808 this: Entity<Self>,
9809 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9810 mut cx: AsyncApp,
9811 ) -> Result<proto::OpenBufferForSymbolResponse> {
9812 let peer_id = envelope.original_sender_id().unwrap_or_default();
9813 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9814 let symbol = Self::deserialize_symbol(symbol)?;
9815 this.read_with(&cx, |this, _| {
9816 if let SymbolLocation::OutsideProject {
9817 abs_path,
9818 signature,
9819 } = &symbol.path
9820 {
9821 let new_signature = this.symbol_signature(&abs_path);
9822 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9823 }
9824 Ok(())
9825 })??;
9826 let buffer = this
9827 .update(&mut cx, |this, cx| {
9828 this.open_buffer_for_symbol(
9829 &Symbol {
9830 language_server_name: symbol.language_server_name,
9831 source_worktree_id: symbol.source_worktree_id,
9832 source_language_server_id: symbol.source_language_server_id,
9833 path: symbol.path,
9834 name: symbol.name,
9835 kind: symbol.kind,
9836 range: symbol.range,
9837 label: CodeLabel::default(),
9838 },
9839 cx,
9840 )
9841 })?
9842 .await?;
9843
9844 this.update(&mut cx, |this, cx| {
9845 let is_private = buffer
9846 .read(cx)
9847 .file()
9848 .map(|f| f.is_private())
9849 .unwrap_or_default();
9850 if is_private {
9851 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9852 } else {
9853 this.buffer_store
9854 .update(cx, |buffer_store, cx| {
9855 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9856 })
9857 .detach_and_log_err(cx);
9858 let buffer_id = buffer.read(cx).remote_id().to_proto();
9859 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9860 }
9861 })?
9862 }
9863
9864 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9865 let mut hasher = Sha256::new();
9866 hasher.update(abs_path.to_string_lossy().as_bytes());
9867 hasher.update(self.nonce.to_be_bytes());
9868 hasher.finalize().as_slice().try_into().unwrap()
9869 }
9870
9871 pub async fn handle_get_project_symbols(
9872 this: Entity<Self>,
9873 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9874 mut cx: AsyncApp,
9875 ) -> Result<proto::GetProjectSymbolsResponse> {
9876 let symbols = this
9877 .update(&mut cx, |this, cx| {
9878 this.symbols(&envelope.payload.query, cx)
9879 })?
9880 .await?;
9881
9882 Ok(proto::GetProjectSymbolsResponse {
9883 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9884 })
9885 }
9886
9887 pub async fn handle_restart_language_servers(
9888 this: Entity<Self>,
9889 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9890 mut cx: AsyncApp,
9891 ) -> Result<proto::Ack> {
9892 this.update(&mut cx, |lsp_store, cx| {
9893 let buffers =
9894 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9895 lsp_store.restart_language_servers_for_buffers(
9896 buffers,
9897 envelope
9898 .payload
9899 .only_servers
9900 .into_iter()
9901 .filter_map(|selector| {
9902 Some(match selector.selector? {
9903 proto::language_server_selector::Selector::ServerId(server_id) => {
9904 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9905 }
9906 proto::language_server_selector::Selector::Name(name) => {
9907 LanguageServerSelector::Name(LanguageServerName(
9908 SharedString::from(name),
9909 ))
9910 }
9911 })
9912 })
9913 .collect(),
9914 cx,
9915 );
9916 })?;
9917
9918 Ok(proto::Ack {})
9919 }
9920
9921 pub async fn handle_stop_language_servers(
9922 lsp_store: Entity<Self>,
9923 envelope: TypedEnvelope<proto::StopLanguageServers>,
9924 mut cx: AsyncApp,
9925 ) -> Result<proto::Ack> {
9926 lsp_store.update(&mut cx, |lsp_store, cx| {
9927 if envelope.payload.all
9928 && envelope.payload.also_servers.is_empty()
9929 && envelope.payload.buffer_ids.is_empty()
9930 {
9931 lsp_store.stop_all_language_servers(cx);
9932 } else {
9933 let buffers =
9934 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9935 lsp_store
9936 .stop_language_servers_for_buffers(
9937 buffers,
9938 envelope
9939 .payload
9940 .also_servers
9941 .into_iter()
9942 .filter_map(|selector| {
9943 Some(match selector.selector? {
9944 proto::language_server_selector::Selector::ServerId(
9945 server_id,
9946 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9947 server_id,
9948 )),
9949 proto::language_server_selector::Selector::Name(name) => {
9950 LanguageServerSelector::Name(LanguageServerName(
9951 SharedString::from(name),
9952 ))
9953 }
9954 })
9955 })
9956 .collect(),
9957 cx,
9958 )
9959 .detach_and_log_err(cx);
9960 }
9961 })?;
9962
9963 Ok(proto::Ack {})
9964 }
9965
9966 pub async fn handle_cancel_language_server_work(
9967 this: Entity<Self>,
9968 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9969 mut cx: AsyncApp,
9970 ) -> Result<proto::Ack> {
9971 this.update(&mut cx, |this, cx| {
9972 if let Some(work) = envelope.payload.work {
9973 match work {
9974 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9975 let buffers =
9976 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9977 this.cancel_language_server_work_for_buffers(buffers, cx);
9978 }
9979 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9980 let server_id = LanguageServerId::from_proto(work.language_server_id);
9981 this.cancel_language_server_work(server_id, work.token, cx);
9982 }
9983 }
9984 }
9985 })?;
9986
9987 Ok(proto::Ack {})
9988 }
9989
9990 fn buffer_ids_to_buffers(
9991 &mut self,
9992 buffer_ids: impl Iterator<Item = u64>,
9993 cx: &mut Context<Self>,
9994 ) -> Vec<Entity<Buffer>> {
9995 buffer_ids
9996 .into_iter()
9997 .flat_map(|buffer_id| {
9998 self.buffer_store
9999 .read(cx)
10000 .get(BufferId::new(buffer_id).log_err()?)
10001 })
10002 .collect::<Vec<_>>()
10003 }
10004
10005 async fn handle_apply_additional_edits_for_completion(
10006 this: Entity<Self>,
10007 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10008 mut cx: AsyncApp,
10009 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10010 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10011 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10012 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10013 let completion = Self::deserialize_completion(
10014 envelope.payload.completion.context("invalid completion")?,
10015 )?;
10016 anyhow::Ok((buffer, completion))
10017 })??;
10018
10019 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10020 this.apply_additional_edits_for_completion(
10021 buffer,
10022 Rc::new(RefCell::new(Box::new([Completion {
10023 replace_range: completion.replace_range,
10024 new_text: completion.new_text,
10025 source: completion.source,
10026 documentation: None,
10027 label: CodeLabel::default(),
10028 insert_text_mode: None,
10029 icon_path: None,
10030 confirm: None,
10031 }]))),
10032 0,
10033 false,
10034 cx,
10035 )
10036 })?;
10037
10038 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10039 transaction: apply_additional_edits
10040 .await?
10041 .as_ref()
10042 .map(language::proto::serialize_transaction),
10043 })
10044 }
10045
10046 pub fn last_formatting_failure(&self) -> Option<&str> {
10047 self.last_formatting_failure.as_deref()
10048 }
10049
10050 pub fn reset_last_formatting_failure(&mut self) {
10051 self.last_formatting_failure = None;
10052 }
10053
10054 pub fn environment_for_buffer(
10055 &self,
10056 buffer: &Entity<Buffer>,
10057 cx: &mut Context<Self>,
10058 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10059 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10060 environment.update(cx, |env, cx| {
10061 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10062 })
10063 } else {
10064 Task::ready(None).shared()
10065 }
10066 }
10067
10068 pub fn format(
10069 &mut self,
10070 buffers: HashSet<Entity<Buffer>>,
10071 target: LspFormatTarget,
10072 push_to_history: bool,
10073 trigger: FormatTrigger,
10074 cx: &mut Context<Self>,
10075 ) -> Task<anyhow::Result<ProjectTransaction>> {
10076 let logger = zlog::scoped!("format");
10077 if self.as_local().is_some() {
10078 zlog::trace!(logger => "Formatting locally");
10079 let logger = zlog::scoped!(logger => "local");
10080 let buffers = buffers
10081 .into_iter()
10082 .map(|buffer_handle| {
10083 let buffer = buffer_handle.read(cx);
10084 let buffer_abs_path = File::from_dyn(buffer.file())
10085 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10086
10087 (buffer_handle, buffer_abs_path, buffer.remote_id())
10088 })
10089 .collect::<Vec<_>>();
10090
10091 cx.spawn(async move |lsp_store, cx| {
10092 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10093
10094 for (handle, abs_path, id) in buffers {
10095 let env = lsp_store
10096 .update(cx, |lsp_store, cx| {
10097 lsp_store.environment_for_buffer(&handle, cx)
10098 })?
10099 .await;
10100
10101 let ranges = match &target {
10102 LspFormatTarget::Buffers => None,
10103 LspFormatTarget::Ranges(ranges) => {
10104 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10105 }
10106 };
10107
10108 formattable_buffers.push(FormattableBuffer {
10109 handle,
10110 abs_path,
10111 env,
10112 ranges,
10113 });
10114 }
10115 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10116
10117 let format_timer = zlog::time!(logger => "Formatting buffers");
10118 let result = LocalLspStore::format_locally(
10119 lsp_store.clone(),
10120 formattable_buffers,
10121 push_to_history,
10122 trigger,
10123 logger,
10124 cx,
10125 )
10126 .await;
10127 format_timer.end();
10128
10129 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10130
10131 lsp_store.update(cx, |lsp_store, _| {
10132 lsp_store.update_last_formatting_failure(&result);
10133 })?;
10134
10135 result
10136 })
10137 } else if let Some((client, project_id)) = self.upstream_client() {
10138 zlog::trace!(logger => "Formatting remotely");
10139 let logger = zlog::scoped!(logger => "remote");
10140 // Don't support formatting ranges via remote
10141 match target {
10142 LspFormatTarget::Buffers => {}
10143 LspFormatTarget::Ranges(_) => {
10144 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10145 return Task::ready(Ok(ProjectTransaction::default()));
10146 }
10147 }
10148
10149 let buffer_store = self.buffer_store();
10150 cx.spawn(async move |lsp_store, cx| {
10151 zlog::trace!(logger => "Sending remote format request");
10152 let request_timer = zlog::time!(logger => "remote format request");
10153 let result = client
10154 .request(proto::FormatBuffers {
10155 project_id,
10156 trigger: trigger as i32,
10157 buffer_ids: buffers
10158 .iter()
10159 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10160 .collect::<Result<_>>()?,
10161 })
10162 .await
10163 .and_then(|result| result.transaction.context("missing transaction"));
10164 request_timer.end();
10165
10166 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10167
10168 lsp_store.update(cx, |lsp_store, _| {
10169 lsp_store.update_last_formatting_failure(&result);
10170 })?;
10171
10172 let transaction_response = result?;
10173 let _timer = zlog::time!(logger => "deserializing project transaction");
10174 buffer_store
10175 .update(cx, |buffer_store, cx| {
10176 buffer_store.deserialize_project_transaction(
10177 transaction_response,
10178 push_to_history,
10179 cx,
10180 )
10181 })?
10182 .await
10183 })
10184 } else {
10185 zlog::trace!(logger => "Not formatting");
10186 Task::ready(Ok(ProjectTransaction::default()))
10187 }
10188 }
10189
10190 async fn handle_format_buffers(
10191 this: Entity<Self>,
10192 envelope: TypedEnvelope<proto::FormatBuffers>,
10193 mut cx: AsyncApp,
10194 ) -> Result<proto::FormatBuffersResponse> {
10195 let sender_id = envelope.original_sender_id().unwrap_or_default();
10196 let format = this.update(&mut cx, |this, cx| {
10197 let mut buffers = HashSet::default();
10198 for buffer_id in &envelope.payload.buffer_ids {
10199 let buffer_id = BufferId::new(*buffer_id)?;
10200 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10201 }
10202 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10203 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10204 })??;
10205
10206 let project_transaction = format.await?;
10207 let project_transaction = this.update(&mut cx, |this, cx| {
10208 this.buffer_store.update(cx, |buffer_store, cx| {
10209 buffer_store.serialize_project_transaction_for_peer(
10210 project_transaction,
10211 sender_id,
10212 cx,
10213 )
10214 })
10215 })?;
10216 Ok(proto::FormatBuffersResponse {
10217 transaction: Some(project_transaction),
10218 })
10219 }
10220
10221 async fn handle_apply_code_action_kind(
10222 this: Entity<Self>,
10223 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10224 mut cx: AsyncApp,
10225 ) -> Result<proto::ApplyCodeActionKindResponse> {
10226 let sender_id = envelope.original_sender_id().unwrap_or_default();
10227 let format = this.update(&mut cx, |this, cx| {
10228 let mut buffers = HashSet::default();
10229 for buffer_id in &envelope.payload.buffer_ids {
10230 let buffer_id = BufferId::new(*buffer_id)?;
10231 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10232 }
10233 let kind = match envelope.payload.kind.as_str() {
10234 "" => CodeActionKind::EMPTY,
10235 "quickfix" => CodeActionKind::QUICKFIX,
10236 "refactor" => CodeActionKind::REFACTOR,
10237 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10238 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10239 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10240 "source" => CodeActionKind::SOURCE,
10241 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10242 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10243 _ => anyhow::bail!(
10244 "Invalid code action kind {}",
10245 envelope.payload.kind.as_str()
10246 ),
10247 };
10248 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10249 })??;
10250
10251 let project_transaction = format.await?;
10252 let project_transaction = this.update(&mut cx, |this, cx| {
10253 this.buffer_store.update(cx, |buffer_store, cx| {
10254 buffer_store.serialize_project_transaction_for_peer(
10255 project_transaction,
10256 sender_id,
10257 cx,
10258 )
10259 })
10260 })?;
10261 Ok(proto::ApplyCodeActionKindResponse {
10262 transaction: Some(project_transaction),
10263 })
10264 }
10265
10266 async fn shutdown_language_server(
10267 server_state: Option<LanguageServerState>,
10268 name: LanguageServerName,
10269 cx: &mut AsyncApp,
10270 ) {
10271 let server = match server_state {
10272 Some(LanguageServerState::Starting { startup, .. }) => {
10273 let mut timer = cx
10274 .background_executor()
10275 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10276 .fuse();
10277
10278 select! {
10279 server = startup.fuse() => server,
10280 () = timer => {
10281 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10282 None
10283 },
10284 }
10285 }
10286
10287 Some(LanguageServerState::Running { server, .. }) => Some(server),
10288
10289 None => None,
10290 };
10291
10292 if let Some(server) = server
10293 && let Some(shutdown) = server.shutdown()
10294 {
10295 shutdown.await;
10296 }
10297 }
10298
10299 // Returns a list of all of the worktrees which no longer have a language server and the root path
10300 // for the stopped server
10301 fn stop_local_language_server(
10302 &mut self,
10303 server_id: LanguageServerId,
10304 cx: &mut Context<Self>,
10305 ) -> Task<()> {
10306 let local = match &mut self.mode {
10307 LspStoreMode::Local(local) => local,
10308 _ => {
10309 return Task::ready(());
10310 }
10311 };
10312
10313 // Remove this server ID from all entries in the given worktree.
10314 local
10315 .language_server_ids
10316 .retain(|_, state| state.id != server_id);
10317 self.buffer_store.update(cx, |buffer_store, cx| {
10318 for buffer in buffer_store.buffers() {
10319 buffer.update(cx, |buffer, cx| {
10320 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10321 buffer.set_completion_triggers(server_id, Default::default(), cx);
10322 });
10323 }
10324 });
10325
10326 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10327 summaries.retain(|path, summaries_by_server_id| {
10328 if summaries_by_server_id.remove(&server_id).is_some() {
10329 if let Some((client, project_id)) = self.downstream_client.clone() {
10330 client
10331 .send(proto::UpdateDiagnosticSummary {
10332 project_id,
10333 worktree_id: worktree_id.to_proto(),
10334 summary: Some(proto::DiagnosticSummary {
10335 path: path.as_ref().to_proto(),
10336 language_server_id: server_id.0 as u64,
10337 error_count: 0,
10338 warning_count: 0,
10339 }),
10340 more_summaries: Vec::new(),
10341 })
10342 .log_err();
10343 }
10344 !summaries_by_server_id.is_empty()
10345 } else {
10346 true
10347 }
10348 });
10349 }
10350
10351 let local = self.as_local_mut().unwrap();
10352 for diagnostics in local.diagnostics.values_mut() {
10353 diagnostics.retain(|_, diagnostics_by_server_id| {
10354 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10355 diagnostics_by_server_id.remove(ix);
10356 !diagnostics_by_server_id.is_empty()
10357 } else {
10358 true
10359 }
10360 });
10361 }
10362 local.language_server_watched_paths.remove(&server_id);
10363
10364 let server_state = local.language_servers.remove(&server_id);
10365 self.cleanup_lsp_data(server_id);
10366 let name = self
10367 .language_server_statuses
10368 .remove(&server_id)
10369 .map(|status| status.name)
10370 .or_else(|| {
10371 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10372 Some(adapter.name())
10373 } else {
10374 None
10375 }
10376 });
10377
10378 if let Some(name) = name {
10379 log::info!("stopping language server {name}");
10380 self.languages
10381 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10382 cx.notify();
10383
10384 return cx.spawn(async move |lsp_store, cx| {
10385 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10386 lsp_store
10387 .update(cx, |lsp_store, cx| {
10388 lsp_store
10389 .languages
10390 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10391 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10392 cx.notify();
10393 })
10394 .ok();
10395 });
10396 }
10397
10398 if server_state.is_some() {
10399 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10400 }
10401 Task::ready(())
10402 }
10403
10404 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10405 if let Some((client, project_id)) = self.upstream_client() {
10406 let request = client.request(proto::StopLanguageServers {
10407 project_id,
10408 buffer_ids: Vec::new(),
10409 also_servers: Vec::new(),
10410 all: true,
10411 });
10412 cx.background_spawn(request).detach_and_log_err(cx);
10413 } else {
10414 let Some(local) = self.as_local_mut() else {
10415 return;
10416 };
10417 let language_servers_to_stop = local
10418 .language_server_ids
10419 .values()
10420 .map(|state| state.id)
10421 .collect();
10422 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10423 let tasks = language_servers_to_stop
10424 .into_iter()
10425 .map(|server| self.stop_local_language_server(server, cx))
10426 .collect::<Vec<_>>();
10427 cx.background_spawn(async move {
10428 futures::future::join_all(tasks).await;
10429 })
10430 .detach();
10431 }
10432 }
10433
10434 pub fn restart_language_servers_for_buffers(
10435 &mut self,
10436 buffers: Vec<Entity<Buffer>>,
10437 only_restart_servers: HashSet<LanguageServerSelector>,
10438 cx: &mut Context<Self>,
10439 ) {
10440 if let Some((client, project_id)) = self.upstream_client() {
10441 let request = client.request(proto::RestartLanguageServers {
10442 project_id,
10443 buffer_ids: buffers
10444 .into_iter()
10445 .map(|b| b.read(cx).remote_id().to_proto())
10446 .collect(),
10447 only_servers: only_restart_servers
10448 .into_iter()
10449 .map(|selector| {
10450 let selector = match selector {
10451 LanguageServerSelector::Id(language_server_id) => {
10452 proto::language_server_selector::Selector::ServerId(
10453 language_server_id.to_proto(),
10454 )
10455 }
10456 LanguageServerSelector::Name(language_server_name) => {
10457 proto::language_server_selector::Selector::Name(
10458 language_server_name.to_string(),
10459 )
10460 }
10461 };
10462 proto::LanguageServerSelector {
10463 selector: Some(selector),
10464 }
10465 })
10466 .collect(),
10467 all: false,
10468 });
10469 cx.background_spawn(request).detach_and_log_err(cx);
10470 } else {
10471 let stop_task = if only_restart_servers.is_empty() {
10472 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10473 } else {
10474 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10475 };
10476 cx.spawn(async move |lsp_store, cx| {
10477 stop_task.await;
10478 lsp_store
10479 .update(cx, |lsp_store, cx| {
10480 for buffer in buffers {
10481 lsp_store.register_buffer_with_language_servers(
10482 &buffer,
10483 only_restart_servers.clone(),
10484 true,
10485 cx,
10486 );
10487 }
10488 })
10489 .ok()
10490 })
10491 .detach();
10492 }
10493 }
10494
10495 pub fn stop_language_servers_for_buffers(
10496 &mut self,
10497 buffers: Vec<Entity<Buffer>>,
10498 also_stop_servers: HashSet<LanguageServerSelector>,
10499 cx: &mut Context<Self>,
10500 ) -> Task<Result<()>> {
10501 if let Some((client, project_id)) = self.upstream_client() {
10502 let request = client.request(proto::StopLanguageServers {
10503 project_id,
10504 buffer_ids: buffers
10505 .into_iter()
10506 .map(|b| b.read(cx).remote_id().to_proto())
10507 .collect(),
10508 also_servers: also_stop_servers
10509 .into_iter()
10510 .map(|selector| {
10511 let selector = match selector {
10512 LanguageServerSelector::Id(language_server_id) => {
10513 proto::language_server_selector::Selector::ServerId(
10514 language_server_id.to_proto(),
10515 )
10516 }
10517 LanguageServerSelector::Name(language_server_name) => {
10518 proto::language_server_selector::Selector::Name(
10519 language_server_name.to_string(),
10520 )
10521 }
10522 };
10523 proto::LanguageServerSelector {
10524 selector: Some(selector),
10525 }
10526 })
10527 .collect(),
10528 all: false,
10529 });
10530 cx.background_spawn(async move {
10531 let _ = request.await?;
10532 Ok(())
10533 })
10534 } else {
10535 let task =
10536 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10537 cx.background_spawn(async move {
10538 task.await;
10539 Ok(())
10540 })
10541 }
10542 }
10543
10544 fn stop_local_language_servers_for_buffers(
10545 &mut self,
10546 buffers: &[Entity<Buffer>],
10547 also_stop_servers: HashSet<LanguageServerSelector>,
10548 cx: &mut Context<Self>,
10549 ) -> Task<()> {
10550 let Some(local) = self.as_local_mut() else {
10551 return Task::ready(());
10552 };
10553 let mut language_server_names_to_stop = BTreeSet::default();
10554 let mut language_servers_to_stop = also_stop_servers
10555 .into_iter()
10556 .flat_map(|selector| match selector {
10557 LanguageServerSelector::Id(id) => Some(id),
10558 LanguageServerSelector::Name(name) => {
10559 language_server_names_to_stop.insert(name);
10560 None
10561 }
10562 })
10563 .collect::<BTreeSet<_>>();
10564
10565 let mut covered_worktrees = HashSet::default();
10566 for buffer in buffers {
10567 buffer.update(cx, |buffer, cx| {
10568 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10569 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10570 && covered_worktrees.insert(worktree_id)
10571 {
10572 language_server_names_to_stop.retain(|name| {
10573 let old_ids_count = language_servers_to_stop.len();
10574 let all_language_servers_with_this_name = local
10575 .language_server_ids
10576 .iter()
10577 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10578 language_servers_to_stop.extend(all_language_servers_with_this_name);
10579 old_ids_count == language_servers_to_stop.len()
10580 });
10581 }
10582 });
10583 }
10584 for name in language_server_names_to_stop {
10585 language_servers_to_stop.extend(
10586 local
10587 .language_server_ids
10588 .iter()
10589 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10590 );
10591 }
10592
10593 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10594 let tasks = language_servers_to_stop
10595 .into_iter()
10596 .map(|server| self.stop_local_language_server(server, cx))
10597 .collect::<Vec<_>>();
10598
10599 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10600 }
10601
10602 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10603 let (worktree, relative_path) =
10604 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10605
10606 let project_path = ProjectPath {
10607 worktree_id: worktree.read(cx).id(),
10608 path: relative_path,
10609 };
10610
10611 Some(
10612 self.buffer_store()
10613 .read(cx)
10614 .get_by_path(&project_path)?
10615 .read(cx),
10616 )
10617 }
10618
10619 #[cfg(any(test, feature = "test-support"))]
10620 pub fn update_diagnostics(
10621 &mut self,
10622 server_id: LanguageServerId,
10623 diagnostics: lsp::PublishDiagnosticsParams,
10624 result_id: Option<String>,
10625 source_kind: DiagnosticSourceKind,
10626 disk_based_sources: &[String],
10627 cx: &mut Context<Self>,
10628 ) -> Result<()> {
10629 self.merge_lsp_diagnostics(
10630 source_kind,
10631 vec![DocumentDiagnosticsUpdate {
10632 diagnostics,
10633 result_id,
10634 server_id,
10635 disk_based_sources: Cow::Borrowed(disk_based_sources),
10636 }],
10637 |_, _, _| false,
10638 cx,
10639 )
10640 }
10641
10642 pub fn merge_lsp_diagnostics(
10643 &mut self,
10644 source_kind: DiagnosticSourceKind,
10645 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10646 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10647 cx: &mut Context<Self>,
10648 ) -> Result<()> {
10649 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10650 let updates = lsp_diagnostics
10651 .into_iter()
10652 .filter_map(|update| {
10653 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10654 Some(DocumentDiagnosticsUpdate {
10655 diagnostics: self.lsp_to_document_diagnostics(
10656 abs_path,
10657 source_kind,
10658 update.server_id,
10659 update.diagnostics,
10660 &update.disk_based_sources,
10661 ),
10662 result_id: update.result_id,
10663 server_id: update.server_id,
10664 disk_based_sources: update.disk_based_sources,
10665 })
10666 })
10667 .collect();
10668 self.merge_diagnostic_entries(updates, merge, cx)?;
10669 Ok(())
10670 }
10671
10672 fn lsp_to_document_diagnostics(
10673 &mut self,
10674 document_abs_path: PathBuf,
10675 source_kind: DiagnosticSourceKind,
10676 server_id: LanguageServerId,
10677 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10678 disk_based_sources: &[String],
10679 ) -> DocumentDiagnostics {
10680 let mut diagnostics = Vec::default();
10681 let mut primary_diagnostic_group_ids = HashMap::default();
10682 let mut sources_by_group_id = HashMap::default();
10683 let mut supporting_diagnostics = HashMap::default();
10684
10685 let adapter = self.language_server_adapter_for_id(server_id);
10686
10687 // Ensure that primary diagnostics are always the most severe
10688 lsp_diagnostics
10689 .diagnostics
10690 .sort_by_key(|item| item.severity);
10691
10692 for diagnostic in &lsp_diagnostics.diagnostics {
10693 let source = diagnostic.source.as_ref();
10694 let range = range_from_lsp(diagnostic.range);
10695 let is_supporting = diagnostic
10696 .related_information
10697 .as_ref()
10698 .is_some_and(|infos| {
10699 infos.iter().any(|info| {
10700 primary_diagnostic_group_ids.contains_key(&(
10701 source,
10702 diagnostic.code.clone(),
10703 range_from_lsp(info.location.range),
10704 ))
10705 })
10706 });
10707
10708 let is_unnecessary = diagnostic
10709 .tags
10710 .as_ref()
10711 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10712
10713 let underline = self
10714 .language_server_adapter_for_id(server_id)
10715 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10716
10717 if is_supporting {
10718 supporting_diagnostics.insert(
10719 (source, diagnostic.code.clone(), range),
10720 (diagnostic.severity, is_unnecessary),
10721 );
10722 } else {
10723 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10724 let is_disk_based =
10725 source.is_some_and(|source| disk_based_sources.contains(source));
10726
10727 sources_by_group_id.insert(group_id, source);
10728 primary_diagnostic_group_ids
10729 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10730
10731 diagnostics.push(DiagnosticEntry {
10732 range,
10733 diagnostic: Diagnostic {
10734 source: diagnostic.source.clone(),
10735 source_kind,
10736 code: diagnostic.code.clone(),
10737 code_description: diagnostic
10738 .code_description
10739 .as_ref()
10740 .and_then(|d| d.href.clone()),
10741 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10742 markdown: adapter.as_ref().and_then(|adapter| {
10743 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10744 }),
10745 message: diagnostic.message.trim().to_string(),
10746 group_id,
10747 is_primary: true,
10748 is_disk_based,
10749 is_unnecessary,
10750 underline,
10751 data: diagnostic.data.clone(),
10752 },
10753 });
10754 if let Some(infos) = &diagnostic.related_information {
10755 for info in infos {
10756 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10757 let range = range_from_lsp(info.location.range);
10758 diagnostics.push(DiagnosticEntry {
10759 range,
10760 diagnostic: Diagnostic {
10761 source: diagnostic.source.clone(),
10762 source_kind,
10763 code: diagnostic.code.clone(),
10764 code_description: diagnostic
10765 .code_description
10766 .as_ref()
10767 .and_then(|d| d.href.clone()),
10768 severity: DiagnosticSeverity::INFORMATION,
10769 markdown: adapter.as_ref().and_then(|adapter| {
10770 adapter.diagnostic_message_to_markdown(&info.message)
10771 }),
10772 message: info.message.trim().to_string(),
10773 group_id,
10774 is_primary: false,
10775 is_disk_based,
10776 is_unnecessary: false,
10777 underline,
10778 data: diagnostic.data.clone(),
10779 },
10780 });
10781 }
10782 }
10783 }
10784 }
10785 }
10786
10787 for entry in &mut diagnostics {
10788 let diagnostic = &mut entry.diagnostic;
10789 if !diagnostic.is_primary {
10790 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10791 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10792 source,
10793 diagnostic.code.clone(),
10794 entry.range.clone(),
10795 )) {
10796 if let Some(severity) = severity {
10797 diagnostic.severity = severity;
10798 }
10799 diagnostic.is_unnecessary = is_unnecessary;
10800 }
10801 }
10802 }
10803
10804 DocumentDiagnostics {
10805 diagnostics,
10806 document_abs_path,
10807 version: lsp_diagnostics.version,
10808 }
10809 }
10810
10811 fn insert_newly_running_language_server(
10812 &mut self,
10813 adapter: Arc<CachedLspAdapter>,
10814 language_server: Arc<LanguageServer>,
10815 server_id: LanguageServerId,
10816 key: LanguageServerSeed,
10817 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10818 cx: &mut Context<Self>,
10819 ) {
10820 let Some(local) = self.as_local_mut() else {
10821 return;
10822 };
10823 // If the language server for this key doesn't match the server id, don't store the
10824 // server. Which will cause it to be dropped, killing the process
10825 if local
10826 .language_server_ids
10827 .get(&key)
10828 .map(|state| state.id != server_id)
10829 .unwrap_or(false)
10830 {
10831 return;
10832 }
10833
10834 // Update language_servers collection with Running variant of LanguageServerState
10835 // indicating that the server is up and running and ready
10836 let workspace_folders = workspace_folders.lock().clone();
10837 language_server.set_workspace_folders(workspace_folders);
10838
10839 let workspace_diagnostics_refresh_tasks = language_server
10840 .capabilities()
10841 .diagnostic_provider
10842 .and_then(|provider| {
10843 let workspace_refresher = lsp_workspace_diagnostics_refresh(
10844 None,
10845 provider.clone(),
10846 language_server.clone(),
10847 cx,
10848 )?;
10849 local
10850 .language_server_dynamic_registrations
10851 .entry(server_id)
10852 .or_default()
10853 .diagnostics
10854 .entry(None)
10855 .or_insert(provider);
10856 Some((None, workspace_refresher))
10857 })
10858 .into_iter()
10859 .collect();
10860 local.language_servers.insert(
10861 server_id,
10862 LanguageServerState::Running {
10863 workspace_diagnostics_refresh_tasks,
10864 adapter: adapter.clone(),
10865 server: language_server.clone(),
10866 simulate_disk_based_diagnostics_completion: None,
10867 },
10868 );
10869 local
10870 .languages
10871 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10872 if let Some(file_ops_caps) = language_server
10873 .capabilities()
10874 .workspace
10875 .as_ref()
10876 .and_then(|ws| ws.file_operations.as_ref())
10877 {
10878 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10879 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10880 if did_rename_caps.or(will_rename_caps).is_some() {
10881 let watcher = RenamePathsWatchedForServer::default()
10882 .with_did_rename_patterns(did_rename_caps)
10883 .with_will_rename_patterns(will_rename_caps);
10884 local
10885 .language_server_paths_watched_for_rename
10886 .insert(server_id, watcher);
10887 }
10888 }
10889
10890 self.language_server_statuses.insert(
10891 server_id,
10892 LanguageServerStatus {
10893 name: language_server.name(),
10894 pending_work: Default::default(),
10895 has_pending_diagnostic_updates: false,
10896 progress_tokens: Default::default(),
10897 worktree: Some(key.worktree_id),
10898 },
10899 );
10900
10901 cx.emit(LspStoreEvent::LanguageServerAdded(
10902 server_id,
10903 language_server.name(),
10904 Some(key.worktree_id),
10905 ));
10906 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
10907
10908 let server_capabilities = language_server.capabilities();
10909 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10910 downstream_client
10911 .send(proto::StartLanguageServer {
10912 project_id: *project_id,
10913 server: Some(proto::LanguageServer {
10914 id: server_id.to_proto(),
10915 name: language_server.name().to_string(),
10916 worktree_id: Some(key.worktree_id.to_proto()),
10917 }),
10918 capabilities: serde_json::to_string(&server_capabilities)
10919 .expect("serializing server LSP capabilities"),
10920 })
10921 .log_err();
10922 }
10923 self.lsp_server_capabilities
10924 .insert(server_id, server_capabilities);
10925
10926 // Tell the language server about every open buffer in the worktree that matches the language.
10927 // Also check for buffers in worktrees that reused this server
10928 let mut worktrees_using_server = vec![key.worktree_id];
10929 if let Some(local) = self.as_local() {
10930 // Find all worktrees that have this server in their language server tree
10931 for (worktree_id, servers) in &local.lsp_tree.instances {
10932 if *worktree_id != key.worktree_id {
10933 for server_map in servers.roots.values() {
10934 if server_map
10935 .values()
10936 .any(|(node, _)| node.id() == Some(server_id))
10937 {
10938 worktrees_using_server.push(*worktree_id);
10939 }
10940 }
10941 }
10942 }
10943 }
10944
10945 let mut buffer_paths_registered = Vec::new();
10946 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10947 let mut lsp_adapters = HashMap::default();
10948 for buffer_handle in buffer_store.buffers() {
10949 let buffer = buffer_handle.read(cx);
10950 let file = match File::from_dyn(buffer.file()) {
10951 Some(file) => file,
10952 None => continue,
10953 };
10954 let language = match buffer.language() {
10955 Some(language) => language,
10956 None => continue,
10957 };
10958
10959 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10960 || !lsp_adapters
10961 .entry(language.name())
10962 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
10963 .iter()
10964 .any(|a| a.name == key.name)
10965 {
10966 continue;
10967 }
10968 // didOpen
10969 let file = match file.as_local() {
10970 Some(file) => file,
10971 None => continue,
10972 };
10973
10974 let local = self.as_local_mut().unwrap();
10975
10976 let buffer_id = buffer.remote_id();
10977 if local.registered_buffers.contains_key(&buffer_id) {
10978 let versions = local
10979 .buffer_snapshots
10980 .entry(buffer_id)
10981 .or_default()
10982 .entry(server_id)
10983 .and_modify(|_| {
10984 assert!(
10985 false,
10986 "There should not be an existing snapshot for a newly inserted buffer"
10987 )
10988 })
10989 .or_insert_with(|| {
10990 vec![LspBufferSnapshot {
10991 version: 0,
10992 snapshot: buffer.text_snapshot(),
10993 }]
10994 });
10995
10996 let snapshot = versions.last().unwrap();
10997 let version = snapshot.version;
10998 let initial_snapshot = &snapshot.snapshot;
10999 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11000 language_server.register_buffer(
11001 uri,
11002 adapter.language_id(&language.name()),
11003 version,
11004 initial_snapshot.text(),
11005 );
11006 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11007 local
11008 .buffers_opened_in_servers
11009 .entry(buffer_id)
11010 .or_default()
11011 .insert(server_id);
11012 }
11013 buffer_handle.update(cx, |buffer, cx| {
11014 buffer.set_completion_triggers(
11015 server_id,
11016 language_server
11017 .capabilities()
11018 .completion_provider
11019 .as_ref()
11020 .and_then(|provider| {
11021 provider
11022 .trigger_characters
11023 .as_ref()
11024 .map(|characters| characters.iter().cloned().collect())
11025 })
11026 .unwrap_or_default(),
11027 cx,
11028 )
11029 });
11030 }
11031 });
11032
11033 for (buffer_id, abs_path) in buffer_paths_registered {
11034 cx.emit(LspStoreEvent::LanguageServerUpdate {
11035 language_server_id: server_id,
11036 name: Some(adapter.name()),
11037 message: proto::update_language_server::Variant::RegisteredForBuffer(
11038 proto::RegisteredForBuffer {
11039 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11040 buffer_id: buffer_id.to_proto(),
11041 },
11042 ),
11043 });
11044 }
11045
11046 cx.notify();
11047 }
11048
11049 pub fn language_servers_running_disk_based_diagnostics(
11050 &self,
11051 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11052 self.language_server_statuses
11053 .iter()
11054 .filter_map(|(id, status)| {
11055 if status.has_pending_diagnostic_updates {
11056 Some(*id)
11057 } else {
11058 None
11059 }
11060 })
11061 }
11062
11063 pub(crate) fn cancel_language_server_work_for_buffers(
11064 &mut self,
11065 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11066 cx: &mut Context<Self>,
11067 ) {
11068 if let Some((client, project_id)) = self.upstream_client() {
11069 let request = client.request(proto::CancelLanguageServerWork {
11070 project_id,
11071 work: Some(proto::cancel_language_server_work::Work::Buffers(
11072 proto::cancel_language_server_work::Buffers {
11073 buffer_ids: buffers
11074 .into_iter()
11075 .map(|b| b.read(cx).remote_id().to_proto())
11076 .collect(),
11077 },
11078 )),
11079 });
11080 cx.background_spawn(request).detach_and_log_err(cx);
11081 } else if let Some(local) = self.as_local() {
11082 let servers = buffers
11083 .into_iter()
11084 .flat_map(|buffer| {
11085 buffer.update(cx, |buffer, cx| {
11086 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11087 })
11088 })
11089 .collect::<HashSet<_>>();
11090 for server_id in servers {
11091 self.cancel_language_server_work(server_id, None, cx);
11092 }
11093 }
11094 }
11095
11096 pub(crate) fn cancel_language_server_work(
11097 &mut self,
11098 server_id: LanguageServerId,
11099 token_to_cancel: Option<String>,
11100 cx: &mut Context<Self>,
11101 ) {
11102 if let Some(local) = self.as_local() {
11103 let status = self.language_server_statuses.get(&server_id);
11104 let server = local.language_servers.get(&server_id);
11105 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11106 {
11107 for (token, progress) in &status.pending_work {
11108 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11109 && token != token_to_cancel
11110 {
11111 continue;
11112 }
11113 if progress.is_cancellable {
11114 server
11115 .notify::<lsp::notification::WorkDoneProgressCancel>(
11116 WorkDoneProgressCancelParams {
11117 token: lsp::NumberOrString::String(token.clone()),
11118 },
11119 )
11120 .ok();
11121 }
11122 }
11123 }
11124 } else if let Some((client, project_id)) = self.upstream_client() {
11125 let request = client.request(proto::CancelLanguageServerWork {
11126 project_id,
11127 work: Some(
11128 proto::cancel_language_server_work::Work::LanguageServerWork(
11129 proto::cancel_language_server_work::LanguageServerWork {
11130 language_server_id: server_id.to_proto(),
11131 token: token_to_cancel,
11132 },
11133 ),
11134 ),
11135 });
11136 cx.background_spawn(request).detach_and_log_err(cx);
11137 }
11138 }
11139
11140 fn register_supplementary_language_server(
11141 &mut self,
11142 id: LanguageServerId,
11143 name: LanguageServerName,
11144 server: Arc<LanguageServer>,
11145 cx: &mut Context<Self>,
11146 ) {
11147 if let Some(local) = self.as_local_mut() {
11148 local
11149 .supplementary_language_servers
11150 .insert(id, (name.clone(), server));
11151 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11152 }
11153 }
11154
11155 fn unregister_supplementary_language_server(
11156 &mut self,
11157 id: LanguageServerId,
11158 cx: &mut Context<Self>,
11159 ) {
11160 if let Some(local) = self.as_local_mut() {
11161 local.supplementary_language_servers.remove(&id);
11162 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11163 }
11164 }
11165
11166 pub(crate) fn supplementary_language_servers(
11167 &self,
11168 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11169 self.as_local().into_iter().flat_map(|local| {
11170 local
11171 .supplementary_language_servers
11172 .iter()
11173 .map(|(id, (name, _))| (*id, name.clone()))
11174 })
11175 }
11176
11177 pub fn language_server_adapter_for_id(
11178 &self,
11179 id: LanguageServerId,
11180 ) -> Option<Arc<CachedLspAdapter>> {
11181 self.as_local()
11182 .and_then(|local| local.language_servers.get(&id))
11183 .and_then(|language_server_state| match language_server_state {
11184 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11185 _ => None,
11186 })
11187 }
11188
11189 pub(super) fn update_local_worktree_language_servers(
11190 &mut self,
11191 worktree_handle: &Entity<Worktree>,
11192 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11193 cx: &mut Context<Self>,
11194 ) {
11195 if changes.is_empty() {
11196 return;
11197 }
11198
11199 let Some(local) = self.as_local() else { return };
11200
11201 local.prettier_store.update(cx, |prettier_store, cx| {
11202 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11203 });
11204
11205 let worktree_id = worktree_handle.read(cx).id();
11206 let mut language_server_ids = local
11207 .language_server_ids
11208 .iter()
11209 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11210 .collect::<Vec<_>>();
11211 language_server_ids.sort();
11212 language_server_ids.dedup();
11213
11214 // let abs_path = worktree_handle.read(cx).abs_path();
11215 for server_id in &language_server_ids {
11216 if let Some(LanguageServerState::Running { server, .. }) =
11217 local.language_servers.get(server_id)
11218 && let Some(watched_paths) = local
11219 .language_server_watched_paths
11220 .get(server_id)
11221 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11222 {
11223 let params = lsp::DidChangeWatchedFilesParams {
11224 changes: changes
11225 .iter()
11226 .filter_map(|(path, _, change)| {
11227 if !watched_paths.is_match(path.as_std_path()) {
11228 return None;
11229 }
11230 let typ = match change {
11231 PathChange::Loaded => return None,
11232 PathChange::Added => lsp::FileChangeType::CREATED,
11233 PathChange::Removed => lsp::FileChangeType::DELETED,
11234 PathChange::Updated => lsp::FileChangeType::CHANGED,
11235 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11236 };
11237 let uri = lsp::Uri::from_file_path(
11238 worktree_handle.read(cx).absolutize(&path),
11239 )
11240 .ok()?;
11241 Some(lsp::FileEvent { uri, typ })
11242 })
11243 .collect(),
11244 };
11245 if !params.changes.is_empty() {
11246 server
11247 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11248 .ok();
11249 }
11250 }
11251 }
11252 for (path, _, _) in changes {
11253 if let Some(file_name) = path.file_name()
11254 && local.watched_manifest_filenames.contains(file_name)
11255 {
11256 self.request_workspace_config_refresh();
11257 break;
11258 }
11259 }
11260 }
11261
11262 pub fn wait_for_remote_buffer(
11263 &mut self,
11264 id: BufferId,
11265 cx: &mut Context<Self>,
11266 ) -> Task<Result<Entity<Buffer>>> {
11267 self.buffer_store.update(cx, |buffer_store, cx| {
11268 buffer_store.wait_for_remote_buffer(id, cx)
11269 })
11270 }
11271
11272 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11273 let mut result = proto::Symbol {
11274 language_server_name: symbol.language_server_name.0.to_string(),
11275 source_worktree_id: symbol.source_worktree_id.to_proto(),
11276 language_server_id: symbol.source_language_server_id.to_proto(),
11277 name: symbol.name.clone(),
11278 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11279 start: Some(proto::PointUtf16 {
11280 row: symbol.range.start.0.row,
11281 column: symbol.range.start.0.column,
11282 }),
11283 end: Some(proto::PointUtf16 {
11284 row: symbol.range.end.0.row,
11285 column: symbol.range.end.0.column,
11286 }),
11287 worktree_id: Default::default(),
11288 path: Default::default(),
11289 signature: Default::default(),
11290 };
11291 match &symbol.path {
11292 SymbolLocation::InProject(path) => {
11293 result.worktree_id = path.worktree_id.to_proto();
11294 result.path = path.path.to_proto();
11295 }
11296 SymbolLocation::OutsideProject {
11297 abs_path,
11298 signature,
11299 } => {
11300 result.path = abs_path.to_string_lossy().into_owned();
11301 result.signature = signature.to_vec();
11302 }
11303 }
11304 result
11305 }
11306
11307 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11308 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11309 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11310 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11311
11312 let path = if serialized_symbol.signature.is_empty() {
11313 SymbolLocation::InProject(ProjectPath {
11314 worktree_id,
11315 path: RelPath::from_proto(&serialized_symbol.path)
11316 .context("invalid symbol path")?,
11317 })
11318 } else {
11319 SymbolLocation::OutsideProject {
11320 abs_path: Path::new(&serialized_symbol.path).into(),
11321 signature: serialized_symbol
11322 .signature
11323 .try_into()
11324 .map_err(|_| anyhow!("invalid signature"))?,
11325 }
11326 };
11327
11328 let start = serialized_symbol.start.context("invalid start")?;
11329 let end = serialized_symbol.end.context("invalid end")?;
11330 Ok(CoreSymbol {
11331 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11332 source_worktree_id,
11333 source_language_server_id: LanguageServerId::from_proto(
11334 serialized_symbol.language_server_id,
11335 ),
11336 path,
11337 name: serialized_symbol.name,
11338 range: Unclipped(PointUtf16::new(start.row, start.column))
11339 ..Unclipped(PointUtf16::new(end.row, end.column)),
11340 kind,
11341 })
11342 }
11343
11344 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11345 let mut serialized_completion = proto::Completion {
11346 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11347 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11348 new_text: completion.new_text.clone(),
11349 ..proto::Completion::default()
11350 };
11351 match &completion.source {
11352 CompletionSource::Lsp {
11353 insert_range,
11354 server_id,
11355 lsp_completion,
11356 lsp_defaults,
11357 resolved,
11358 } => {
11359 let (old_insert_start, old_insert_end) = insert_range
11360 .as_ref()
11361 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11362 .unzip();
11363
11364 serialized_completion.old_insert_start = old_insert_start;
11365 serialized_completion.old_insert_end = old_insert_end;
11366 serialized_completion.source = proto::completion::Source::Lsp as i32;
11367 serialized_completion.server_id = server_id.0 as u64;
11368 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11369 serialized_completion.lsp_defaults = lsp_defaults
11370 .as_deref()
11371 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11372 serialized_completion.resolved = *resolved;
11373 }
11374 CompletionSource::BufferWord {
11375 word_range,
11376 resolved,
11377 } => {
11378 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11379 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11380 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11381 serialized_completion.resolved = *resolved;
11382 }
11383 CompletionSource::Custom => {
11384 serialized_completion.source = proto::completion::Source::Custom as i32;
11385 serialized_completion.resolved = true;
11386 }
11387 CompletionSource::Dap { sort_text } => {
11388 serialized_completion.source = proto::completion::Source::Dap as i32;
11389 serialized_completion.sort_text = Some(sort_text.clone());
11390 }
11391 }
11392
11393 serialized_completion
11394 }
11395
11396 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11397 let old_replace_start = completion
11398 .old_replace_start
11399 .and_then(deserialize_anchor)
11400 .context("invalid old start")?;
11401 let old_replace_end = completion
11402 .old_replace_end
11403 .and_then(deserialize_anchor)
11404 .context("invalid old end")?;
11405 let insert_range = {
11406 match completion.old_insert_start.zip(completion.old_insert_end) {
11407 Some((start, end)) => {
11408 let start = deserialize_anchor(start).context("invalid insert old start")?;
11409 let end = deserialize_anchor(end).context("invalid insert old end")?;
11410 Some(start..end)
11411 }
11412 None => None,
11413 }
11414 };
11415 Ok(CoreCompletion {
11416 replace_range: old_replace_start..old_replace_end,
11417 new_text: completion.new_text,
11418 source: match proto::completion::Source::from_i32(completion.source) {
11419 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11420 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11421 insert_range,
11422 server_id: LanguageServerId::from_proto(completion.server_id),
11423 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11424 lsp_defaults: completion
11425 .lsp_defaults
11426 .as_deref()
11427 .map(serde_json::from_slice)
11428 .transpose()?,
11429 resolved: completion.resolved,
11430 },
11431 Some(proto::completion::Source::BufferWord) => {
11432 let word_range = completion
11433 .buffer_word_start
11434 .and_then(deserialize_anchor)
11435 .context("invalid buffer word start")?
11436 ..completion
11437 .buffer_word_end
11438 .and_then(deserialize_anchor)
11439 .context("invalid buffer word end")?;
11440 CompletionSource::BufferWord {
11441 word_range,
11442 resolved: completion.resolved,
11443 }
11444 }
11445 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11446 sort_text: completion
11447 .sort_text
11448 .context("expected sort text to exist")?,
11449 },
11450 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11451 },
11452 })
11453 }
11454
11455 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11456 let (kind, lsp_action) = match &action.lsp_action {
11457 LspAction::Action(code_action) => (
11458 proto::code_action::Kind::Action as i32,
11459 serde_json::to_vec(code_action).unwrap(),
11460 ),
11461 LspAction::Command(command) => (
11462 proto::code_action::Kind::Command as i32,
11463 serde_json::to_vec(command).unwrap(),
11464 ),
11465 LspAction::CodeLens(code_lens) => (
11466 proto::code_action::Kind::CodeLens as i32,
11467 serde_json::to_vec(code_lens).unwrap(),
11468 ),
11469 };
11470
11471 proto::CodeAction {
11472 server_id: action.server_id.0 as u64,
11473 start: Some(serialize_anchor(&action.range.start)),
11474 end: Some(serialize_anchor(&action.range.end)),
11475 lsp_action,
11476 kind,
11477 resolved: action.resolved,
11478 }
11479 }
11480
11481 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11482 let start = action
11483 .start
11484 .and_then(deserialize_anchor)
11485 .context("invalid start")?;
11486 let end = action
11487 .end
11488 .and_then(deserialize_anchor)
11489 .context("invalid end")?;
11490 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11491 Some(proto::code_action::Kind::Action) => {
11492 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11493 }
11494 Some(proto::code_action::Kind::Command) => {
11495 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11496 }
11497 Some(proto::code_action::Kind::CodeLens) => {
11498 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11499 }
11500 None => anyhow::bail!("Unknown action kind {}", action.kind),
11501 };
11502 Ok(CodeAction {
11503 server_id: LanguageServerId(action.server_id as usize),
11504 range: start..end,
11505 resolved: action.resolved,
11506 lsp_action,
11507 })
11508 }
11509
11510 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11511 match &formatting_result {
11512 Ok(_) => self.last_formatting_failure = None,
11513 Err(error) => {
11514 let error_string = format!("{error:#}");
11515 log::error!("Formatting failed: {error_string}");
11516 self.last_formatting_failure
11517 .replace(error_string.lines().join(" "));
11518 }
11519 }
11520 }
11521
11522 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11523 self.lsp_server_capabilities.remove(&for_server);
11524 for lsp_data in self.lsp_data.values_mut() {
11525 lsp_data.remove_server_data(for_server);
11526 }
11527 if let Some(local) = self.as_local_mut() {
11528 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11529 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11530 buffer_servers.remove(&for_server);
11531 }
11532 }
11533 }
11534
11535 pub fn result_id(
11536 &self,
11537 server_id: LanguageServerId,
11538 buffer_id: BufferId,
11539 cx: &App,
11540 ) -> Option<String> {
11541 let abs_path = self
11542 .buffer_store
11543 .read(cx)
11544 .get(buffer_id)
11545 .and_then(|b| File::from_dyn(b.read(cx).file()))
11546 .map(|f| f.abs_path(cx))?;
11547 self.as_local()?
11548 .buffer_pull_diagnostics_result_ids
11549 .get(&server_id)?
11550 .get(&abs_path)?
11551 .clone()
11552 }
11553
11554 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11555 let Some(local) = self.as_local() else {
11556 return HashMap::default();
11557 };
11558 local
11559 .buffer_pull_diagnostics_result_ids
11560 .get(&server_id)
11561 .into_iter()
11562 .flatten()
11563 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11564 .collect()
11565 }
11566
11567 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11568 if let Some(LanguageServerState::Running {
11569 workspace_diagnostics_refresh_tasks,
11570 ..
11571 }) = self
11572 .as_local_mut()
11573 .and_then(|local| local.language_servers.get_mut(&server_id))
11574 {
11575 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11576 diagnostics.refresh_tx.try_send(()).ok();
11577 }
11578 }
11579 }
11580
11581 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11582 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11583 return;
11584 };
11585 let Some(local) = self.as_local_mut() else {
11586 return;
11587 };
11588
11589 for server_id in buffer.update(cx, |buffer, cx| {
11590 local.language_server_ids_for_buffer(buffer, cx)
11591 }) {
11592 if let Some(LanguageServerState::Running {
11593 workspace_diagnostics_refresh_tasks,
11594 ..
11595 }) = local.language_servers.get_mut(&server_id)
11596 {
11597 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11598 diagnostics.refresh_tx.try_send(()).ok();
11599 }
11600 }
11601 }
11602 }
11603
11604 fn apply_workspace_diagnostic_report(
11605 &mut self,
11606 server_id: LanguageServerId,
11607 report: lsp::WorkspaceDiagnosticReportResult,
11608 cx: &mut Context<Self>,
11609 ) {
11610 let workspace_diagnostics =
11611 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11612 let mut unchanged_buffers = HashSet::default();
11613 let mut changed_buffers = HashSet::default();
11614 let workspace_diagnostics_updates = workspace_diagnostics
11615 .into_iter()
11616 .filter_map(
11617 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11618 LspPullDiagnostics::Response {
11619 server_id,
11620 uri,
11621 diagnostics,
11622 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11623 LspPullDiagnostics::Default => None,
11624 },
11625 )
11626 .fold(
11627 HashMap::default(),
11628 |mut acc, (server_id, uri, diagnostics, version)| {
11629 let (result_id, diagnostics) = match diagnostics {
11630 PulledDiagnostics::Unchanged { result_id } => {
11631 unchanged_buffers.insert(uri.clone());
11632 (Some(result_id), Vec::new())
11633 }
11634 PulledDiagnostics::Changed {
11635 result_id,
11636 diagnostics,
11637 } => {
11638 changed_buffers.insert(uri.clone());
11639 (result_id, diagnostics)
11640 }
11641 };
11642 let disk_based_sources = Cow::Owned(
11643 self.language_server_adapter_for_id(server_id)
11644 .as_ref()
11645 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11646 .unwrap_or(&[])
11647 .to_vec(),
11648 );
11649 acc.entry(server_id)
11650 .or_insert_with(Vec::new)
11651 .push(DocumentDiagnosticsUpdate {
11652 server_id,
11653 diagnostics: lsp::PublishDiagnosticsParams {
11654 uri,
11655 diagnostics,
11656 version,
11657 },
11658 result_id,
11659 disk_based_sources,
11660 });
11661 acc
11662 },
11663 );
11664
11665 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11666 self.merge_lsp_diagnostics(
11667 DiagnosticSourceKind::Pulled,
11668 diagnostic_updates,
11669 |buffer, old_diagnostic, cx| {
11670 File::from_dyn(buffer.file())
11671 .and_then(|file| {
11672 let abs_path = file.as_local()?.abs_path(cx);
11673 lsp::Uri::from_file_path(abs_path).ok()
11674 })
11675 .is_none_or(|buffer_uri| {
11676 unchanged_buffers.contains(&buffer_uri)
11677 || match old_diagnostic.source_kind {
11678 DiagnosticSourceKind::Pulled => {
11679 !changed_buffers.contains(&buffer_uri)
11680 }
11681 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11682 true
11683 }
11684 }
11685 })
11686 },
11687 cx,
11688 )
11689 .log_err();
11690 }
11691 }
11692
11693 fn register_server_capabilities(
11694 &mut self,
11695 server_id: LanguageServerId,
11696 params: lsp::RegistrationParams,
11697 cx: &mut Context<Self>,
11698 ) -> anyhow::Result<()> {
11699 let server = self
11700 .language_server_for_id(server_id)
11701 .with_context(|| format!("no server {server_id} found"))?;
11702 for reg in params.registrations {
11703 match reg.method.as_str() {
11704 "workspace/didChangeWatchedFiles" => {
11705 if let Some(options) = reg.register_options {
11706 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11707 let caps = serde_json::from_value(options)?;
11708 local_lsp_store
11709 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11710 true
11711 } else {
11712 false
11713 };
11714 if notify {
11715 notify_server_capabilities_updated(&server, cx);
11716 }
11717 }
11718 }
11719 "workspace/didChangeConfiguration" => {
11720 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11721 }
11722 "workspace/didChangeWorkspaceFolders" => {
11723 // In this case register options is an empty object, we can ignore it
11724 let caps = lsp::WorkspaceFoldersServerCapabilities {
11725 supported: Some(true),
11726 change_notifications: Some(OneOf::Right(reg.id)),
11727 };
11728 server.update_capabilities(|capabilities| {
11729 capabilities
11730 .workspace
11731 .get_or_insert_default()
11732 .workspace_folders = Some(caps);
11733 });
11734 notify_server_capabilities_updated(&server, cx);
11735 }
11736 "workspace/symbol" => {
11737 let options = parse_register_capabilities(reg)?;
11738 server.update_capabilities(|capabilities| {
11739 capabilities.workspace_symbol_provider = Some(options);
11740 });
11741 notify_server_capabilities_updated(&server, cx);
11742 }
11743 "workspace/fileOperations" => {
11744 if let Some(options) = reg.register_options {
11745 let caps = serde_json::from_value(options)?;
11746 server.update_capabilities(|capabilities| {
11747 capabilities
11748 .workspace
11749 .get_or_insert_default()
11750 .file_operations = Some(caps);
11751 });
11752 notify_server_capabilities_updated(&server, cx);
11753 }
11754 }
11755 "workspace/executeCommand" => {
11756 if let Some(options) = reg.register_options {
11757 let options = serde_json::from_value(options)?;
11758 server.update_capabilities(|capabilities| {
11759 capabilities.execute_command_provider = Some(options);
11760 });
11761 notify_server_capabilities_updated(&server, cx);
11762 }
11763 }
11764 "textDocument/rangeFormatting" => {
11765 let options = parse_register_capabilities(reg)?;
11766 server.update_capabilities(|capabilities| {
11767 capabilities.document_range_formatting_provider = Some(options);
11768 });
11769 notify_server_capabilities_updated(&server, cx);
11770 }
11771 "textDocument/onTypeFormatting" => {
11772 if let Some(options) = reg
11773 .register_options
11774 .map(serde_json::from_value)
11775 .transpose()?
11776 {
11777 server.update_capabilities(|capabilities| {
11778 capabilities.document_on_type_formatting_provider = Some(options);
11779 });
11780 notify_server_capabilities_updated(&server, cx);
11781 }
11782 }
11783 "textDocument/formatting" => {
11784 let options = parse_register_capabilities(reg)?;
11785 server.update_capabilities(|capabilities| {
11786 capabilities.document_formatting_provider = Some(options);
11787 });
11788 notify_server_capabilities_updated(&server, cx);
11789 }
11790 "textDocument/rename" => {
11791 let options = parse_register_capabilities(reg)?;
11792 server.update_capabilities(|capabilities| {
11793 capabilities.rename_provider = Some(options);
11794 });
11795 notify_server_capabilities_updated(&server, cx);
11796 }
11797 "textDocument/inlayHint" => {
11798 let options = parse_register_capabilities(reg)?;
11799 server.update_capabilities(|capabilities| {
11800 capabilities.inlay_hint_provider = Some(options);
11801 });
11802 notify_server_capabilities_updated(&server, cx);
11803 }
11804 "textDocument/documentSymbol" => {
11805 let options = parse_register_capabilities(reg)?;
11806 server.update_capabilities(|capabilities| {
11807 capabilities.document_symbol_provider = Some(options);
11808 });
11809 notify_server_capabilities_updated(&server, cx);
11810 }
11811 "textDocument/codeAction" => {
11812 let options = parse_register_capabilities(reg)?;
11813 let provider = match options {
11814 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11815 OneOf::Right(caps) => caps,
11816 };
11817 server.update_capabilities(|capabilities| {
11818 capabilities.code_action_provider = Some(provider);
11819 });
11820 notify_server_capabilities_updated(&server, cx);
11821 }
11822 "textDocument/definition" => {
11823 let options = parse_register_capabilities(reg)?;
11824 server.update_capabilities(|capabilities| {
11825 capabilities.definition_provider = Some(options);
11826 });
11827 notify_server_capabilities_updated(&server, cx);
11828 }
11829 "textDocument/completion" => {
11830 if let Some(caps) = reg
11831 .register_options
11832 .map(serde_json::from_value)
11833 .transpose()?
11834 {
11835 server.update_capabilities(|capabilities| {
11836 capabilities.completion_provider = Some(caps);
11837 });
11838 notify_server_capabilities_updated(&server, cx);
11839 }
11840 }
11841 "textDocument/hover" => {
11842 let options = parse_register_capabilities(reg)?;
11843 let provider = match options {
11844 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11845 OneOf::Right(caps) => caps,
11846 };
11847 server.update_capabilities(|capabilities| {
11848 capabilities.hover_provider = Some(provider);
11849 });
11850 notify_server_capabilities_updated(&server, cx);
11851 }
11852 "textDocument/signatureHelp" => {
11853 if let Some(caps) = reg
11854 .register_options
11855 .map(serde_json::from_value)
11856 .transpose()?
11857 {
11858 server.update_capabilities(|capabilities| {
11859 capabilities.signature_help_provider = Some(caps);
11860 });
11861 notify_server_capabilities_updated(&server, cx);
11862 }
11863 }
11864 "textDocument/didChange" => {
11865 if let Some(sync_kind) = reg
11866 .register_options
11867 .and_then(|opts| opts.get("syncKind").cloned())
11868 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11869 .transpose()?
11870 {
11871 server.update_capabilities(|capabilities| {
11872 let mut sync_options =
11873 Self::take_text_document_sync_options(capabilities);
11874 sync_options.change = Some(sync_kind);
11875 capabilities.text_document_sync =
11876 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11877 });
11878 notify_server_capabilities_updated(&server, cx);
11879 }
11880 }
11881 "textDocument/didSave" => {
11882 if let Some(include_text) = reg
11883 .register_options
11884 .map(|opts| {
11885 let transpose = opts
11886 .get("includeText")
11887 .cloned()
11888 .map(serde_json::from_value::<Option<bool>>)
11889 .transpose();
11890 match transpose {
11891 Ok(value) => Ok(value.flatten()),
11892 Err(e) => Err(e),
11893 }
11894 })
11895 .transpose()?
11896 {
11897 server.update_capabilities(|capabilities| {
11898 let mut sync_options =
11899 Self::take_text_document_sync_options(capabilities);
11900 sync_options.save =
11901 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11902 include_text,
11903 }));
11904 capabilities.text_document_sync =
11905 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11906 });
11907 notify_server_capabilities_updated(&server, cx);
11908 }
11909 }
11910 "textDocument/codeLens" => {
11911 if let Some(caps) = reg
11912 .register_options
11913 .map(serde_json::from_value)
11914 .transpose()?
11915 {
11916 server.update_capabilities(|capabilities| {
11917 capabilities.code_lens_provider = Some(caps);
11918 });
11919 notify_server_capabilities_updated(&server, cx);
11920 }
11921 }
11922 "textDocument/diagnostic" => {
11923 if let Some(caps) = reg
11924 .register_options
11925 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
11926 .transpose()?
11927 {
11928 let local = self
11929 .as_local_mut()
11930 .context("Expected LSP Store to be local")?;
11931 let state = local
11932 .language_servers
11933 .get_mut(&server_id)
11934 .context("Could not obtain Language Servers state")?;
11935 local
11936 .language_server_dynamic_registrations
11937 .get_mut(&server_id)
11938 .and_then(|registrations| {
11939 registrations
11940 .diagnostics
11941 .insert(Some(reg.id.clone()), caps.clone())
11942 });
11943
11944 let mut can_now_provide_diagnostics = false;
11945 if let LanguageServerState::Running {
11946 workspace_diagnostics_refresh_tasks,
11947 ..
11948 } = state
11949 && let Some(task) = lsp_workspace_diagnostics_refresh(
11950 Some(reg.id.clone()),
11951 caps.clone(),
11952 server.clone(),
11953 cx,
11954 )
11955 {
11956 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
11957 can_now_provide_diagnostics = true;
11958 }
11959
11960 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
11961 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
11962 // as it'll think that they're not supported.
11963 if can_now_provide_diagnostics {
11964 server.update_capabilities(|capabilities| {
11965 debug_assert!(capabilities.diagnostic_provider.is_none());
11966 capabilities.diagnostic_provider = Some(caps);
11967 });
11968 }
11969
11970 notify_server_capabilities_updated(&server, cx);
11971 }
11972 }
11973 "textDocument/documentColor" => {
11974 let options = parse_register_capabilities(reg)?;
11975 let provider = match options {
11976 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11977 OneOf::Right(caps) => caps,
11978 };
11979 server.update_capabilities(|capabilities| {
11980 capabilities.color_provider = Some(provider);
11981 });
11982 notify_server_capabilities_updated(&server, cx);
11983 }
11984 _ => log::warn!("unhandled capability registration: {reg:?}"),
11985 }
11986 }
11987
11988 Ok(())
11989 }
11990
11991 fn unregister_server_capabilities(
11992 &mut self,
11993 server_id: LanguageServerId,
11994 params: lsp::UnregistrationParams,
11995 cx: &mut Context<Self>,
11996 ) -> anyhow::Result<()> {
11997 let server = self
11998 .language_server_for_id(server_id)
11999 .with_context(|| format!("no server {server_id} found"))?;
12000 for unreg in params.unregisterations.iter() {
12001 match unreg.method.as_str() {
12002 "workspace/didChangeWatchedFiles" => {
12003 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12004 local_lsp_store
12005 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12006 true
12007 } else {
12008 false
12009 };
12010 if notify {
12011 notify_server_capabilities_updated(&server, cx);
12012 }
12013 }
12014 "workspace/didChangeConfiguration" => {
12015 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12016 }
12017 "workspace/didChangeWorkspaceFolders" => {
12018 server.update_capabilities(|capabilities| {
12019 capabilities
12020 .workspace
12021 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12022 workspace_folders: None,
12023 file_operations: None,
12024 })
12025 .workspace_folders = None;
12026 });
12027 notify_server_capabilities_updated(&server, cx);
12028 }
12029 "workspace/symbol" => {
12030 server.update_capabilities(|capabilities| {
12031 capabilities.workspace_symbol_provider = None
12032 });
12033 notify_server_capabilities_updated(&server, cx);
12034 }
12035 "workspace/fileOperations" => {
12036 server.update_capabilities(|capabilities| {
12037 capabilities
12038 .workspace
12039 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12040 workspace_folders: None,
12041 file_operations: None,
12042 })
12043 .file_operations = None;
12044 });
12045 notify_server_capabilities_updated(&server, cx);
12046 }
12047 "workspace/executeCommand" => {
12048 server.update_capabilities(|capabilities| {
12049 capabilities.execute_command_provider = None;
12050 });
12051 notify_server_capabilities_updated(&server, cx);
12052 }
12053 "textDocument/rangeFormatting" => {
12054 server.update_capabilities(|capabilities| {
12055 capabilities.document_range_formatting_provider = None
12056 });
12057 notify_server_capabilities_updated(&server, cx);
12058 }
12059 "textDocument/onTypeFormatting" => {
12060 server.update_capabilities(|capabilities| {
12061 capabilities.document_on_type_formatting_provider = None;
12062 });
12063 notify_server_capabilities_updated(&server, cx);
12064 }
12065 "textDocument/formatting" => {
12066 server.update_capabilities(|capabilities| {
12067 capabilities.document_formatting_provider = None;
12068 });
12069 notify_server_capabilities_updated(&server, cx);
12070 }
12071 "textDocument/rename" => {
12072 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12073 notify_server_capabilities_updated(&server, cx);
12074 }
12075 "textDocument/codeAction" => {
12076 server.update_capabilities(|capabilities| {
12077 capabilities.code_action_provider = None;
12078 });
12079 notify_server_capabilities_updated(&server, cx);
12080 }
12081 "textDocument/definition" => {
12082 server.update_capabilities(|capabilities| {
12083 capabilities.definition_provider = None;
12084 });
12085 notify_server_capabilities_updated(&server, cx);
12086 }
12087 "textDocument/completion" => {
12088 server.update_capabilities(|capabilities| {
12089 capabilities.completion_provider = None;
12090 });
12091 notify_server_capabilities_updated(&server, cx);
12092 }
12093 "textDocument/hover" => {
12094 server.update_capabilities(|capabilities| {
12095 capabilities.hover_provider = None;
12096 });
12097 notify_server_capabilities_updated(&server, cx);
12098 }
12099 "textDocument/signatureHelp" => {
12100 server.update_capabilities(|capabilities| {
12101 capabilities.signature_help_provider = None;
12102 });
12103 notify_server_capabilities_updated(&server, cx);
12104 }
12105 "textDocument/didChange" => {
12106 server.update_capabilities(|capabilities| {
12107 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12108 sync_options.change = None;
12109 capabilities.text_document_sync =
12110 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12111 });
12112 notify_server_capabilities_updated(&server, cx);
12113 }
12114 "textDocument/didSave" => {
12115 server.update_capabilities(|capabilities| {
12116 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12117 sync_options.save = None;
12118 capabilities.text_document_sync =
12119 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12120 });
12121 notify_server_capabilities_updated(&server, cx);
12122 }
12123 "textDocument/codeLens" => {
12124 server.update_capabilities(|capabilities| {
12125 capabilities.code_lens_provider = None;
12126 });
12127 notify_server_capabilities_updated(&server, cx);
12128 }
12129 "textDocument/diagnostic" => {
12130 let local = self
12131 .as_local_mut()
12132 .context("Expected LSP Store to be local")?;
12133
12134 let state = local
12135 .language_servers
12136 .get_mut(&server_id)
12137 .context("Could not obtain Language Servers state")?;
12138 let options = local
12139 .language_server_dynamic_registrations
12140 .get_mut(&server_id)
12141 .with_context(|| {
12142 format!("Expected dynamic registration to exist for server {server_id}")
12143 })?.diagnostics
12144 .remove(&Some(unreg.id.clone()))
12145 .with_context(|| format!(
12146 "Attempted to unregister non-existent diagnostic registration with ID {}",
12147 unreg.id)
12148 )?;
12149
12150 let mut has_any_diagnostic_providers_still = true;
12151 if let Some(identifier) = diagnostic_identifier(&options)
12152 && let LanguageServerState::Running {
12153 workspace_diagnostics_refresh_tasks,
12154 ..
12155 } = state
12156 {
12157 workspace_diagnostics_refresh_tasks.remove(&identifier);
12158 has_any_diagnostic_providers_still =
12159 !workspace_diagnostics_refresh_tasks.is_empty();
12160 }
12161
12162 if !has_any_diagnostic_providers_still {
12163 server.update_capabilities(|capabilities| {
12164 debug_assert!(capabilities.diagnostic_provider.is_some());
12165 capabilities.diagnostic_provider = None;
12166 });
12167 }
12168
12169 notify_server_capabilities_updated(&server, cx);
12170 }
12171 "textDocument/documentColor" => {
12172 server.update_capabilities(|capabilities| {
12173 capabilities.color_provider = None;
12174 });
12175 notify_server_capabilities_updated(&server, cx);
12176 }
12177 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12178 }
12179 }
12180
12181 Ok(())
12182 }
12183
12184 async fn deduplicate_range_based_lsp_requests<T>(
12185 lsp_store: &Entity<Self>,
12186 server_id: Option<LanguageServerId>,
12187 lsp_request_id: LspRequestId,
12188 proto_request: &T::ProtoRequest,
12189 range: Range<Anchor>,
12190 cx: &mut AsyncApp,
12191 ) -> Result<()>
12192 where
12193 T: LspCommand,
12194 T::ProtoRequest: proto::LspRequestMessage,
12195 {
12196 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12197 let version = deserialize_version(proto_request.buffer_version());
12198 let buffer = lsp_store.update(cx, |this, cx| {
12199 this.buffer_store.read(cx).get_existing(buffer_id)
12200 })??;
12201 buffer
12202 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12203 .await?;
12204 lsp_store.update(cx, |lsp_store, cx| {
12205 let lsp_data = lsp_store
12206 .lsp_data
12207 .entry(buffer_id)
12208 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12209 let chunks_queried_for = lsp_data
12210 .inlay_hints
12211 .applicable_chunks(&[range])
12212 .collect::<Vec<_>>();
12213 match chunks_queried_for.as_slice() {
12214 &[chunk] => {
12215 let key = LspKey {
12216 request_type: TypeId::of::<T>(),
12217 server_queried: server_id,
12218 };
12219 let previous_request = lsp_data
12220 .chunk_lsp_requests
12221 .entry(key)
12222 .or_default()
12223 .insert(chunk, lsp_request_id);
12224 if let Some((previous_request, running_requests)) =
12225 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12226 {
12227 running_requests.remove(&previous_request);
12228 }
12229 }
12230 _ambiguous_chunks => {
12231 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12232 // there, a buffer version-based check will be performed and outdated requests discarded.
12233 }
12234 }
12235 anyhow::Ok(())
12236 })??;
12237
12238 Ok(())
12239 }
12240
12241 async fn query_lsp_locally<T>(
12242 lsp_store: Entity<Self>,
12243 for_server_id: Option<LanguageServerId>,
12244 sender_id: proto::PeerId,
12245 lsp_request_id: LspRequestId,
12246 proto_request: T::ProtoRequest,
12247 position: Option<Anchor>,
12248 cx: &mut AsyncApp,
12249 ) -> Result<()>
12250 where
12251 T: LspCommand + Clone,
12252 T::ProtoRequest: proto::LspRequestMessage,
12253 <T::ProtoRequest as proto::RequestMessage>::Response:
12254 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12255 {
12256 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12257 let version = deserialize_version(proto_request.buffer_version());
12258 let buffer = lsp_store.update(cx, |this, cx| {
12259 this.buffer_store.read(cx).get_existing(buffer_id)
12260 })??;
12261 buffer
12262 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12263 .await?;
12264 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12265 let request =
12266 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12267 let key = LspKey {
12268 request_type: TypeId::of::<T>(),
12269 server_queried: for_server_id,
12270 };
12271 lsp_store.update(cx, |lsp_store, cx| {
12272 let request_task = match for_server_id {
12273 Some(server_id) => {
12274 let server_task = lsp_store.request_lsp(
12275 buffer.clone(),
12276 LanguageServerToQuery::Other(server_id),
12277 request.clone(),
12278 cx,
12279 );
12280 cx.background_spawn(async move {
12281 let mut responses = Vec::new();
12282 match server_task.await {
12283 Ok(response) => responses.push((server_id, response)),
12284 Err(e) => log::error!(
12285 "Error handling response for request {request:?}: {e:#}"
12286 ),
12287 }
12288 responses
12289 })
12290 }
12291 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12292 };
12293 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12294 if T::ProtoRequest::stop_previous_requests() {
12295 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12296 lsp_requests.clear();
12297 }
12298 }
12299 lsp_data.lsp_requests.entry(key).or_default().insert(
12300 lsp_request_id,
12301 cx.spawn(async move |lsp_store, cx| {
12302 let response = request_task.await;
12303 lsp_store
12304 .update(cx, |lsp_store, cx| {
12305 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12306 {
12307 let response = response
12308 .into_iter()
12309 .map(|(server_id, response)| {
12310 (
12311 server_id.to_proto(),
12312 T::response_to_proto(
12313 response,
12314 lsp_store,
12315 sender_id,
12316 &buffer_version,
12317 cx,
12318 )
12319 .into(),
12320 )
12321 })
12322 .collect::<HashMap<_, _>>();
12323 match client.send_lsp_response::<T::ProtoRequest>(
12324 project_id,
12325 lsp_request_id,
12326 response,
12327 ) {
12328 Ok(()) => {}
12329 Err(e) => {
12330 log::error!("Failed to send LSP response: {e:#}",)
12331 }
12332 }
12333 }
12334 })
12335 .ok();
12336 }),
12337 );
12338 })?;
12339 Ok(())
12340 }
12341
12342 fn take_text_document_sync_options(
12343 capabilities: &mut lsp::ServerCapabilities,
12344 ) -> lsp::TextDocumentSyncOptions {
12345 match capabilities.text_document_sync.take() {
12346 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12347 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12348 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12349 sync_options.change = Some(sync_kind);
12350 sync_options
12351 }
12352 None => lsp::TextDocumentSyncOptions::default(),
12353 }
12354 }
12355
12356 #[cfg(any(test, feature = "test-support"))]
12357 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12358 Some(
12359 self.lsp_data
12360 .get_mut(&buffer_id)?
12361 .code_lens
12362 .take()?
12363 .update
12364 .take()?
12365 .1,
12366 )
12367 }
12368
12369 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12370 self.downstream_client.clone()
12371 }
12372
12373 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12374 self.worktree_store.clone()
12375 }
12376
12377 /// Gets what's stored in the LSP data for the given buffer.
12378 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12379 self.lsp_data.get_mut(&buffer_id)
12380 }
12381
12382 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12383 /// new [`BufferLspData`] will be created to replace the previous state.
12384 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12385 let (buffer_id, buffer_version) =
12386 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12387 let lsp_data = self
12388 .lsp_data
12389 .entry(buffer_id)
12390 .or_insert_with(|| BufferLspData::new(buffer, cx));
12391 if buffer_version.changed_since(&lsp_data.buffer_version) {
12392 *lsp_data = BufferLspData::new(buffer, cx);
12393 }
12394 lsp_data
12395 }
12396}
12397
12398// Registration with registerOptions as null, should fallback to true.
12399// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12400fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12401 reg: lsp::Registration,
12402) -> Result<OneOf<bool, T>> {
12403 Ok(match reg.register_options {
12404 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12405 None => OneOf::Left(true),
12406 })
12407}
12408
12409fn subscribe_to_binary_statuses(
12410 languages: &Arc<LanguageRegistry>,
12411 cx: &mut Context<'_, LspStore>,
12412) -> Task<()> {
12413 let mut server_statuses = languages.language_server_binary_statuses();
12414 cx.spawn(async move |lsp_store, cx| {
12415 while let Some((server_name, binary_status)) = server_statuses.next().await {
12416 if lsp_store
12417 .update(cx, |_, cx| {
12418 let mut message = None;
12419 let binary_status = match binary_status {
12420 BinaryStatus::None => proto::ServerBinaryStatus::None,
12421 BinaryStatus::CheckingForUpdate => {
12422 proto::ServerBinaryStatus::CheckingForUpdate
12423 }
12424 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12425 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12426 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12427 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12428 BinaryStatus::Failed { error } => {
12429 message = Some(error);
12430 proto::ServerBinaryStatus::Failed
12431 }
12432 };
12433 cx.emit(LspStoreEvent::LanguageServerUpdate {
12434 // Binary updates are about the binary that might not have any language server id at that point.
12435 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12436 language_server_id: LanguageServerId(0),
12437 name: Some(server_name),
12438 message: proto::update_language_server::Variant::StatusUpdate(
12439 proto::StatusUpdate {
12440 message,
12441 status: Some(proto::status_update::Status::Binary(
12442 binary_status as i32,
12443 )),
12444 },
12445 ),
12446 });
12447 })
12448 .is_err()
12449 {
12450 break;
12451 }
12452 }
12453 })
12454}
12455
12456fn lsp_workspace_diagnostics_refresh(
12457 registration_id: Option<String>,
12458 options: DiagnosticServerCapabilities,
12459 server: Arc<LanguageServer>,
12460 cx: &mut Context<'_, LspStore>,
12461) -> Option<WorkspaceRefreshTask> {
12462 let identifier = diagnostic_identifier(&options)?;
12463
12464 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12465 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12466 refresh_tx.try_send(()).ok();
12467
12468 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12469 let mut attempts = 0;
12470 let max_attempts = 50;
12471 let mut requests = 0;
12472
12473 loop {
12474 let Some(()) = refresh_rx.recv().await else {
12475 return;
12476 };
12477
12478 'request: loop {
12479 requests += 1;
12480 if attempts > max_attempts {
12481 log::error!(
12482 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12483 );
12484 return;
12485 }
12486 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12487 cx.background_executor()
12488 .timer(Duration::from_millis(backoff_millis))
12489 .await;
12490 attempts += 1;
12491
12492 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12493 lsp_store
12494 .all_result_ids(server.server_id())
12495 .into_iter()
12496 .filter_map(|(abs_path, result_id)| {
12497 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12498 Some(lsp::PreviousResultId {
12499 uri,
12500 value: result_id,
12501 })
12502 })
12503 .collect()
12504 }) else {
12505 return;
12506 };
12507
12508 let token = if let Some(identifier) = ®istration_id {
12509 format!(
12510 "workspace/diagnostic/{}/{requests}/id:{identifier}",
12511 server.server_id(),
12512 )
12513 } else {
12514 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12515 };
12516
12517 progress_rx.try_recv().ok();
12518 let timer =
12519 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12520 let progress = pin!(progress_rx.recv().fuse());
12521 let response_result = server
12522 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12523 lsp::WorkspaceDiagnosticParams {
12524 previous_result_ids,
12525 identifier: identifier.clone(),
12526 work_done_progress_params: Default::default(),
12527 partial_result_params: lsp::PartialResultParams {
12528 partial_result_token: Some(lsp::ProgressToken::String(token)),
12529 },
12530 },
12531 select(timer, progress).then(|either| match either {
12532 Either::Left((message, ..)) => ready(message).left_future(),
12533 Either::Right(..) => pending::<String>().right_future(),
12534 }),
12535 )
12536 .await;
12537
12538 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12539 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12540 match response_result {
12541 ConnectionResult::Timeout => {
12542 log::error!("Timeout during workspace diagnostics pull");
12543 continue 'request;
12544 }
12545 ConnectionResult::ConnectionReset => {
12546 log::error!("Server closed a workspace diagnostics pull request");
12547 continue 'request;
12548 }
12549 ConnectionResult::Result(Err(e)) => {
12550 log::error!("Error during workspace diagnostics pull: {e:#}");
12551 break 'request;
12552 }
12553 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12554 attempts = 0;
12555 if lsp_store
12556 .update(cx, |lsp_store, cx| {
12557 lsp_store.apply_workspace_diagnostic_report(
12558 server.server_id(),
12559 pulled_diagnostics,
12560 cx,
12561 )
12562 })
12563 .is_err()
12564 {
12565 return;
12566 }
12567 break 'request;
12568 }
12569 }
12570 }
12571 }
12572 });
12573
12574 Some(WorkspaceRefreshTask {
12575 refresh_tx,
12576 progress_tx,
12577 task: workspace_query_language_server,
12578 })
12579}
12580
12581fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12582 match &options {
12583 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12584 if !diagnostic_options.workspace_diagnostics {
12585 return None;
12586 }
12587 Some(diagnostic_options.identifier.clone())
12588 }
12589 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12590 let diagnostic_options = ®istration_options.diagnostic_options;
12591 if !diagnostic_options.workspace_diagnostics {
12592 return None;
12593 }
12594 Some(diagnostic_options.identifier.clone())
12595 }
12596 }
12597}
12598
12599fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12600 let CompletionSource::BufferWord {
12601 word_range,
12602 resolved,
12603 } = &mut completion.source
12604 else {
12605 return;
12606 };
12607 if *resolved {
12608 return;
12609 }
12610
12611 if completion.new_text
12612 != snapshot
12613 .text_for_range(word_range.clone())
12614 .collect::<String>()
12615 {
12616 return;
12617 }
12618
12619 let mut offset = 0;
12620 for chunk in snapshot.chunks(word_range.clone(), true) {
12621 let end_offset = offset + chunk.text.len();
12622 if let Some(highlight_id) = chunk.syntax_highlight_id {
12623 completion
12624 .label
12625 .runs
12626 .push((offset..end_offset, highlight_id));
12627 }
12628 offset = end_offset;
12629 }
12630 *resolved = true;
12631}
12632
12633impl EventEmitter<LspStoreEvent> for LspStore {}
12634
12635fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12636 hover
12637 .contents
12638 .retain(|hover_block| !hover_block.text.trim().is_empty());
12639 if hover.contents.is_empty() {
12640 None
12641 } else {
12642 Some(hover)
12643 }
12644}
12645
12646async fn populate_labels_for_completions(
12647 new_completions: Vec<CoreCompletion>,
12648 language: Option<Arc<Language>>,
12649 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12650) -> Vec<Completion> {
12651 let lsp_completions = new_completions
12652 .iter()
12653 .filter_map(|new_completion| {
12654 new_completion
12655 .source
12656 .lsp_completion(true)
12657 .map(|lsp_completion| lsp_completion.into_owned())
12658 })
12659 .collect::<Vec<_>>();
12660
12661 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12662 lsp_adapter
12663 .labels_for_completions(&lsp_completions, language)
12664 .await
12665 .log_err()
12666 .unwrap_or_default()
12667 } else {
12668 Vec::new()
12669 }
12670 .into_iter()
12671 .fuse();
12672
12673 let mut completions = Vec::new();
12674 for completion in new_completions {
12675 match completion.source.lsp_completion(true) {
12676 Some(lsp_completion) => {
12677 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12678
12679 let mut label = labels.next().flatten().unwrap_or_else(|| {
12680 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12681 });
12682 ensure_uniform_list_compatible_label(&mut label);
12683 completions.push(Completion {
12684 label,
12685 documentation,
12686 replace_range: completion.replace_range,
12687 new_text: completion.new_text,
12688 insert_text_mode: lsp_completion.insert_text_mode,
12689 source: completion.source,
12690 icon_path: None,
12691 confirm: None,
12692 });
12693 }
12694 None => {
12695 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12696 ensure_uniform_list_compatible_label(&mut label);
12697 completions.push(Completion {
12698 label,
12699 documentation: None,
12700 replace_range: completion.replace_range,
12701 new_text: completion.new_text,
12702 source: completion.source,
12703 insert_text_mode: None,
12704 icon_path: None,
12705 confirm: None,
12706 });
12707 }
12708 }
12709 }
12710 completions
12711}
12712
12713#[derive(Debug)]
12714pub enum LanguageServerToQuery {
12715 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12716 FirstCapable,
12717 /// Query a specific language server.
12718 Other(LanguageServerId),
12719}
12720
12721#[derive(Default)]
12722struct RenamePathsWatchedForServer {
12723 did_rename: Vec<RenameActionPredicate>,
12724 will_rename: Vec<RenameActionPredicate>,
12725}
12726
12727impl RenamePathsWatchedForServer {
12728 fn with_did_rename_patterns(
12729 mut self,
12730 did_rename: Option<&FileOperationRegistrationOptions>,
12731 ) -> Self {
12732 if let Some(did_rename) = did_rename {
12733 self.did_rename = did_rename
12734 .filters
12735 .iter()
12736 .filter_map(|filter| filter.try_into().log_err())
12737 .collect();
12738 }
12739 self
12740 }
12741 fn with_will_rename_patterns(
12742 mut self,
12743 will_rename: Option<&FileOperationRegistrationOptions>,
12744 ) -> Self {
12745 if let Some(will_rename) = will_rename {
12746 self.will_rename = will_rename
12747 .filters
12748 .iter()
12749 .filter_map(|filter| filter.try_into().log_err())
12750 .collect();
12751 }
12752 self
12753 }
12754
12755 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12756 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12757 }
12758 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12759 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12760 }
12761}
12762
12763impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12764 type Error = globset::Error;
12765 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12766 Ok(Self {
12767 kind: ops.pattern.matches.clone(),
12768 glob: GlobBuilder::new(&ops.pattern.glob)
12769 .case_insensitive(
12770 ops.pattern
12771 .options
12772 .as_ref()
12773 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12774 )
12775 .build()?
12776 .compile_matcher(),
12777 })
12778 }
12779}
12780struct RenameActionPredicate {
12781 glob: GlobMatcher,
12782 kind: Option<FileOperationPatternKind>,
12783}
12784
12785impl RenameActionPredicate {
12786 // Returns true if language server should be notified
12787 fn eval(&self, path: &str, is_dir: bool) -> bool {
12788 self.kind.as_ref().is_none_or(|kind| {
12789 let expected_kind = if is_dir {
12790 FileOperationPatternKind::Folder
12791 } else {
12792 FileOperationPatternKind::File
12793 };
12794 kind == &expected_kind
12795 }) && self.glob.is_match(path)
12796 }
12797}
12798
12799#[derive(Default)]
12800struct LanguageServerWatchedPaths {
12801 worktree_paths: HashMap<WorktreeId, GlobSet>,
12802 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12803}
12804
12805#[derive(Default)]
12806struct LanguageServerWatchedPathsBuilder {
12807 worktree_paths: HashMap<WorktreeId, GlobSet>,
12808 abs_paths: HashMap<Arc<Path>, GlobSet>,
12809}
12810
12811impl LanguageServerWatchedPathsBuilder {
12812 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12813 self.worktree_paths.insert(worktree_id, glob_set);
12814 }
12815 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12816 self.abs_paths.insert(path, glob_set);
12817 }
12818 fn build(
12819 self,
12820 fs: Arc<dyn Fs>,
12821 language_server_id: LanguageServerId,
12822 cx: &mut Context<LspStore>,
12823 ) -> LanguageServerWatchedPaths {
12824 let project = cx.weak_entity();
12825
12826 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12827 let abs_paths = self
12828 .abs_paths
12829 .into_iter()
12830 .map(|(abs_path, globset)| {
12831 let task = cx.spawn({
12832 let abs_path = abs_path.clone();
12833 let fs = fs.clone();
12834
12835 let lsp_store = project.clone();
12836 async move |_, cx| {
12837 maybe!(async move {
12838 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12839 while let Some(update) = push_updates.0.next().await {
12840 let action = lsp_store
12841 .update(cx, |this, _| {
12842 let Some(local) = this.as_local() else {
12843 return ControlFlow::Break(());
12844 };
12845 let Some(watcher) = local
12846 .language_server_watched_paths
12847 .get(&language_server_id)
12848 else {
12849 return ControlFlow::Break(());
12850 };
12851 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12852 "Watched abs path is not registered with a watcher",
12853 );
12854 let matching_entries = update
12855 .into_iter()
12856 .filter(|event| globs.is_match(&event.path))
12857 .collect::<Vec<_>>();
12858 this.lsp_notify_abs_paths_changed(
12859 language_server_id,
12860 matching_entries,
12861 );
12862 ControlFlow::Continue(())
12863 })
12864 .ok()?;
12865
12866 if action.is_break() {
12867 break;
12868 }
12869 }
12870 Some(())
12871 })
12872 .await;
12873 }
12874 });
12875 (abs_path, (globset, task))
12876 })
12877 .collect();
12878 LanguageServerWatchedPaths {
12879 worktree_paths: self.worktree_paths,
12880 abs_paths,
12881 }
12882 }
12883}
12884
12885struct LspBufferSnapshot {
12886 version: i32,
12887 snapshot: TextBufferSnapshot,
12888}
12889
12890/// A prompt requested by LSP server.
12891#[derive(Clone, Debug)]
12892pub struct LanguageServerPromptRequest {
12893 pub level: PromptLevel,
12894 pub message: String,
12895 pub actions: Vec<MessageActionItem>,
12896 pub lsp_name: String,
12897 pub(crate) response_channel: Sender<MessageActionItem>,
12898}
12899
12900impl LanguageServerPromptRequest {
12901 pub async fn respond(self, index: usize) -> Option<()> {
12902 if let Some(response) = self.actions.into_iter().nth(index) {
12903 self.response_channel.send(response).await.ok()
12904 } else {
12905 None
12906 }
12907 }
12908}
12909impl PartialEq for LanguageServerPromptRequest {
12910 fn eq(&self, other: &Self) -> bool {
12911 self.message == other.message && self.actions == other.actions
12912 }
12913}
12914
12915#[derive(Clone, Debug, PartialEq)]
12916pub enum LanguageServerLogType {
12917 Log(MessageType),
12918 Trace { verbose_info: Option<String> },
12919 Rpc { received: bool },
12920}
12921
12922impl LanguageServerLogType {
12923 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12924 match self {
12925 Self::Log(log_type) => {
12926 use proto::log_message::LogLevel;
12927 let level = match *log_type {
12928 MessageType::ERROR => LogLevel::Error,
12929 MessageType::WARNING => LogLevel::Warning,
12930 MessageType::INFO => LogLevel::Info,
12931 MessageType::LOG => LogLevel::Log,
12932 other => {
12933 log::warn!("Unknown lsp log message type: {other:?}");
12934 LogLevel::Log
12935 }
12936 };
12937 proto::language_server_log::LogType::Log(proto::LogMessage {
12938 level: level as i32,
12939 })
12940 }
12941 Self::Trace { verbose_info } => {
12942 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12943 verbose_info: verbose_info.to_owned(),
12944 })
12945 }
12946 Self::Rpc { received } => {
12947 let kind = if *received {
12948 proto::rpc_message::Kind::Received
12949 } else {
12950 proto::rpc_message::Kind::Sent
12951 };
12952 let kind = kind as i32;
12953 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12954 }
12955 }
12956 }
12957
12958 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12959 use proto::log_message::LogLevel;
12960 use proto::rpc_message;
12961 match log_type {
12962 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12963 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12964 LogLevel::Error => MessageType::ERROR,
12965 LogLevel::Warning => MessageType::WARNING,
12966 LogLevel::Info => MessageType::INFO,
12967 LogLevel::Log => MessageType::LOG,
12968 },
12969 ),
12970 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12971 verbose_info: trace_message.verbose_info,
12972 },
12973 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12974 received: match rpc_message::Kind::from_i32(message.kind)
12975 .unwrap_or(rpc_message::Kind::Received)
12976 {
12977 rpc_message::Kind::Received => true,
12978 rpc_message::Kind::Sent => false,
12979 },
12980 },
12981 }
12982 }
12983}
12984
12985pub struct WorkspaceRefreshTask {
12986 refresh_tx: mpsc::Sender<()>,
12987 progress_tx: mpsc::Sender<()>,
12988 #[allow(dead_code)]
12989 task: Task<()>,
12990}
12991
12992pub enum LanguageServerState {
12993 Starting {
12994 startup: Task<Option<Arc<LanguageServer>>>,
12995 /// List of language servers that will be added to the workspace once it's initialization completes.
12996 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12997 },
12998
12999 Running {
13000 adapter: Arc<CachedLspAdapter>,
13001 server: Arc<LanguageServer>,
13002 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13003 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13004 },
13005}
13006
13007impl LanguageServerState {
13008 fn add_workspace_folder(&self, uri: Uri) {
13009 match self {
13010 LanguageServerState::Starting {
13011 pending_workspace_folders,
13012 ..
13013 } => {
13014 pending_workspace_folders.lock().insert(uri);
13015 }
13016 LanguageServerState::Running { server, .. } => {
13017 server.add_workspace_folder(uri);
13018 }
13019 }
13020 }
13021 fn _remove_workspace_folder(&self, uri: Uri) {
13022 match self {
13023 LanguageServerState::Starting {
13024 pending_workspace_folders,
13025 ..
13026 } => {
13027 pending_workspace_folders.lock().remove(&uri);
13028 }
13029 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13030 }
13031 }
13032}
13033
13034impl std::fmt::Debug for LanguageServerState {
13035 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13036 match self {
13037 LanguageServerState::Starting { .. } => {
13038 f.debug_struct("LanguageServerState::Starting").finish()
13039 }
13040 LanguageServerState::Running { .. } => {
13041 f.debug_struct("LanguageServerState::Running").finish()
13042 }
13043 }
13044 }
13045}
13046
13047#[derive(Clone, Debug, Serialize)]
13048pub struct LanguageServerProgress {
13049 pub is_disk_based_diagnostics_progress: bool,
13050 pub is_cancellable: bool,
13051 pub title: Option<String>,
13052 pub message: Option<String>,
13053 pub percentage: Option<usize>,
13054 #[serde(skip_serializing)]
13055 pub last_update_at: Instant,
13056}
13057
13058#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13059pub struct DiagnosticSummary {
13060 pub error_count: usize,
13061 pub warning_count: usize,
13062}
13063
13064impl DiagnosticSummary {
13065 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13066 let mut this = Self {
13067 error_count: 0,
13068 warning_count: 0,
13069 };
13070
13071 for entry in diagnostics {
13072 if entry.diagnostic.is_primary {
13073 match entry.diagnostic.severity {
13074 DiagnosticSeverity::ERROR => this.error_count += 1,
13075 DiagnosticSeverity::WARNING => this.warning_count += 1,
13076 _ => {}
13077 }
13078 }
13079 }
13080
13081 this
13082 }
13083
13084 pub fn is_empty(&self) -> bool {
13085 self.error_count == 0 && self.warning_count == 0
13086 }
13087
13088 pub fn to_proto(
13089 self,
13090 language_server_id: LanguageServerId,
13091 path: &RelPath,
13092 ) -> proto::DiagnosticSummary {
13093 proto::DiagnosticSummary {
13094 path: path.to_proto(),
13095 language_server_id: language_server_id.0 as u64,
13096 error_count: self.error_count as u32,
13097 warning_count: self.warning_count as u32,
13098 }
13099 }
13100}
13101
13102#[derive(Clone, Debug)]
13103pub enum CompletionDocumentation {
13104 /// There is no documentation for this completion.
13105 Undocumented,
13106 /// A single line of documentation.
13107 SingleLine(SharedString),
13108 /// Multiple lines of plain text documentation.
13109 MultiLinePlainText(SharedString),
13110 /// Markdown documentation.
13111 MultiLineMarkdown(SharedString),
13112 /// Both single line and multiple lines of plain text documentation.
13113 SingleLineAndMultiLinePlainText {
13114 single_line: SharedString,
13115 plain_text: Option<SharedString>,
13116 },
13117}
13118
13119impl CompletionDocumentation {
13120 #[cfg(any(test, feature = "test-support"))]
13121 pub fn text(&self) -> SharedString {
13122 match self {
13123 CompletionDocumentation::Undocumented => "".into(),
13124 CompletionDocumentation::SingleLine(s) => s.clone(),
13125 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13126 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13127 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13128 single_line.clone()
13129 }
13130 }
13131 }
13132}
13133
13134impl From<lsp::Documentation> for CompletionDocumentation {
13135 fn from(docs: lsp::Documentation) -> Self {
13136 match docs {
13137 lsp::Documentation::String(text) => {
13138 if text.lines().count() <= 1 {
13139 CompletionDocumentation::SingleLine(text.into())
13140 } else {
13141 CompletionDocumentation::MultiLinePlainText(text.into())
13142 }
13143 }
13144
13145 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13146 lsp::MarkupKind::PlainText => {
13147 if value.lines().count() <= 1 {
13148 CompletionDocumentation::SingleLine(value.into())
13149 } else {
13150 CompletionDocumentation::MultiLinePlainText(value.into())
13151 }
13152 }
13153
13154 lsp::MarkupKind::Markdown => {
13155 CompletionDocumentation::MultiLineMarkdown(value.into())
13156 }
13157 },
13158 }
13159 }
13160}
13161
13162pub enum ResolvedHint {
13163 Resolved(InlayHint),
13164 Resolving(Shared<Task<()>>),
13165}
13166
13167fn glob_literal_prefix(glob: &Path) -> PathBuf {
13168 glob.components()
13169 .take_while(|component| match component {
13170 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13171 _ => true,
13172 })
13173 .collect()
13174}
13175
13176pub struct SshLspAdapter {
13177 name: LanguageServerName,
13178 binary: LanguageServerBinary,
13179 initialization_options: Option<String>,
13180 code_action_kinds: Option<Vec<CodeActionKind>>,
13181}
13182
13183impl SshLspAdapter {
13184 pub fn new(
13185 name: LanguageServerName,
13186 binary: LanguageServerBinary,
13187 initialization_options: Option<String>,
13188 code_action_kinds: Option<String>,
13189 ) -> Self {
13190 Self {
13191 name,
13192 binary,
13193 initialization_options,
13194 code_action_kinds: code_action_kinds
13195 .as_ref()
13196 .and_then(|c| serde_json::from_str(c).ok()),
13197 }
13198 }
13199}
13200
13201impl LspInstaller for SshLspAdapter {
13202 type BinaryVersion = ();
13203 async fn check_if_user_installed(
13204 &self,
13205 _: &dyn LspAdapterDelegate,
13206 _: Option<Toolchain>,
13207 _: &AsyncApp,
13208 ) -> Option<LanguageServerBinary> {
13209 Some(self.binary.clone())
13210 }
13211
13212 async fn cached_server_binary(
13213 &self,
13214 _: PathBuf,
13215 _: &dyn LspAdapterDelegate,
13216 ) -> Option<LanguageServerBinary> {
13217 None
13218 }
13219
13220 async fn fetch_latest_server_version(
13221 &self,
13222 _: &dyn LspAdapterDelegate,
13223 _: bool,
13224 _: &mut AsyncApp,
13225 ) -> Result<()> {
13226 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13227 }
13228
13229 async fn fetch_server_binary(
13230 &self,
13231 _: (),
13232 _: PathBuf,
13233 _: &dyn LspAdapterDelegate,
13234 ) -> Result<LanguageServerBinary> {
13235 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13236 }
13237}
13238
13239#[async_trait(?Send)]
13240impl LspAdapter for SshLspAdapter {
13241 fn name(&self) -> LanguageServerName {
13242 self.name.clone()
13243 }
13244
13245 async fn initialization_options(
13246 self: Arc<Self>,
13247 _: &Arc<dyn LspAdapterDelegate>,
13248 ) -> Result<Option<serde_json::Value>> {
13249 let Some(options) = &self.initialization_options else {
13250 return Ok(None);
13251 };
13252 let result = serde_json::from_str(options)?;
13253 Ok(result)
13254 }
13255
13256 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13257 self.code_action_kinds.clone()
13258 }
13259}
13260
13261pub fn language_server_settings<'a>(
13262 delegate: &'a dyn LspAdapterDelegate,
13263 language: &LanguageServerName,
13264 cx: &'a App,
13265) -> Option<&'a LspSettings> {
13266 language_server_settings_for(
13267 SettingsLocation {
13268 worktree_id: delegate.worktree_id(),
13269 path: RelPath::empty(),
13270 },
13271 language,
13272 cx,
13273 )
13274}
13275
13276pub(crate) fn language_server_settings_for<'a>(
13277 location: SettingsLocation<'a>,
13278 language: &LanguageServerName,
13279 cx: &'a App,
13280) -> Option<&'a LspSettings> {
13281 ProjectSettings::get(Some(location), cx).lsp.get(language)
13282}
13283
13284pub struct LocalLspAdapterDelegate {
13285 lsp_store: WeakEntity<LspStore>,
13286 worktree: worktree::Snapshot,
13287 fs: Arc<dyn Fs>,
13288 http_client: Arc<dyn HttpClient>,
13289 language_registry: Arc<LanguageRegistry>,
13290 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13291}
13292
13293impl LocalLspAdapterDelegate {
13294 pub fn new(
13295 language_registry: Arc<LanguageRegistry>,
13296 environment: &Entity<ProjectEnvironment>,
13297 lsp_store: WeakEntity<LspStore>,
13298 worktree: &Entity<Worktree>,
13299 http_client: Arc<dyn HttpClient>,
13300 fs: Arc<dyn Fs>,
13301 cx: &mut App,
13302 ) -> Arc<Self> {
13303 let load_shell_env_task = environment.update(cx, |env, cx| {
13304 env.get_worktree_environment(worktree.clone(), cx)
13305 });
13306
13307 Arc::new(Self {
13308 lsp_store,
13309 worktree: worktree.read(cx).snapshot(),
13310 fs,
13311 http_client,
13312 language_registry,
13313 load_shell_env_task,
13314 })
13315 }
13316
13317 fn from_local_lsp(
13318 local: &LocalLspStore,
13319 worktree: &Entity<Worktree>,
13320 cx: &mut App,
13321 ) -> Arc<Self> {
13322 Self::new(
13323 local.languages.clone(),
13324 &local.environment,
13325 local.weak.clone(),
13326 worktree,
13327 local.http_client.clone(),
13328 local.fs.clone(),
13329 cx,
13330 )
13331 }
13332}
13333
13334#[async_trait]
13335impl LspAdapterDelegate for LocalLspAdapterDelegate {
13336 fn show_notification(&self, message: &str, cx: &mut App) {
13337 self.lsp_store
13338 .update(cx, |_, cx| {
13339 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13340 })
13341 .ok();
13342 }
13343
13344 fn http_client(&self) -> Arc<dyn HttpClient> {
13345 self.http_client.clone()
13346 }
13347
13348 fn worktree_id(&self) -> WorktreeId {
13349 self.worktree.id()
13350 }
13351
13352 fn worktree_root_path(&self) -> &Path {
13353 self.worktree.abs_path().as_ref()
13354 }
13355
13356 async fn shell_env(&self) -> HashMap<String, String> {
13357 let task = self.load_shell_env_task.clone();
13358 task.await.unwrap_or_default()
13359 }
13360
13361 async fn npm_package_installed_version(
13362 &self,
13363 package_name: &str,
13364 ) -> Result<Option<(PathBuf, String)>> {
13365 let local_package_directory = self.worktree_root_path();
13366 let node_modules_directory = local_package_directory.join("node_modules");
13367
13368 if let Some(version) =
13369 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13370 {
13371 return Ok(Some((node_modules_directory, version)));
13372 }
13373 let Some(npm) = self.which("npm".as_ref()).await else {
13374 log::warn!(
13375 "Failed to find npm executable for {:?}",
13376 local_package_directory
13377 );
13378 return Ok(None);
13379 };
13380
13381 let env = self.shell_env().await;
13382 let output = util::command::new_smol_command(&npm)
13383 .args(["root", "-g"])
13384 .envs(env)
13385 .current_dir(local_package_directory)
13386 .output()
13387 .await?;
13388 let global_node_modules =
13389 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13390
13391 if let Some(version) =
13392 read_package_installed_version(global_node_modules.clone(), package_name).await?
13393 {
13394 return Ok(Some((global_node_modules, version)));
13395 }
13396 return Ok(None);
13397 }
13398
13399 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13400 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13401 if self.fs.is_file(&worktree_abs_path).await {
13402 worktree_abs_path.pop();
13403 }
13404
13405 let env = self.shell_env().await;
13406
13407 let shell_path = env.get("PATH").cloned();
13408
13409 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13410 }
13411
13412 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13413 let mut working_dir = self.worktree_root_path().to_path_buf();
13414 if self.fs.is_file(&working_dir).await {
13415 working_dir.pop();
13416 }
13417 let output = util::command::new_smol_command(&command.path)
13418 .args(command.arguments)
13419 .envs(command.env.clone().unwrap_or_default())
13420 .current_dir(working_dir)
13421 .output()
13422 .await?;
13423
13424 anyhow::ensure!(
13425 output.status.success(),
13426 "{}, stdout: {:?}, stderr: {:?}",
13427 output.status,
13428 String::from_utf8_lossy(&output.stdout),
13429 String::from_utf8_lossy(&output.stderr)
13430 );
13431 Ok(())
13432 }
13433
13434 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13435 self.language_registry
13436 .update_lsp_binary_status(server_name, status);
13437 }
13438
13439 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13440 self.language_registry
13441 .all_lsp_adapters()
13442 .into_iter()
13443 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13444 .collect()
13445 }
13446
13447 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13448 let dir = self.language_registry.language_server_download_dir(name)?;
13449
13450 if !dir.exists() {
13451 smol::fs::create_dir_all(&dir)
13452 .await
13453 .context("failed to create container directory")
13454 .log_err()?;
13455 }
13456
13457 Some(dir)
13458 }
13459
13460 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13461 let entry = self
13462 .worktree
13463 .entry_for_path(path)
13464 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13465 let abs_path = self.worktree.absolutize(&entry.path);
13466 self.fs.load(&abs_path).await
13467 }
13468}
13469
13470async fn populate_labels_for_symbols(
13471 symbols: Vec<CoreSymbol>,
13472 language_registry: &Arc<LanguageRegistry>,
13473 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13474 output: &mut Vec<Symbol>,
13475) {
13476 #[allow(clippy::mutable_key_type)]
13477 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13478
13479 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13480 for symbol in symbols {
13481 let Some(file_name) = symbol.path.file_name() else {
13482 continue;
13483 };
13484 let language = language_registry
13485 .load_language_for_file_path(Path::new(file_name))
13486 .await
13487 .ok()
13488 .or_else(|| {
13489 unknown_paths.insert(file_name.into());
13490 None
13491 });
13492 symbols_by_language
13493 .entry(language)
13494 .or_default()
13495 .push(symbol);
13496 }
13497
13498 for unknown_path in unknown_paths {
13499 log::info!("no language found for symbol in file {unknown_path:?}");
13500 }
13501
13502 let mut label_params = Vec::new();
13503 for (language, mut symbols) in symbols_by_language {
13504 label_params.clear();
13505 label_params.extend(
13506 symbols
13507 .iter_mut()
13508 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13509 );
13510
13511 let mut labels = Vec::new();
13512 if let Some(language) = language {
13513 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13514 language_registry
13515 .lsp_adapters(&language.name())
13516 .first()
13517 .cloned()
13518 });
13519 if let Some(lsp_adapter) = lsp_adapter {
13520 labels = lsp_adapter
13521 .labels_for_symbols(&label_params, &language)
13522 .await
13523 .log_err()
13524 .unwrap_or_default();
13525 }
13526 }
13527
13528 for ((symbol, (name, _)), label) in symbols
13529 .into_iter()
13530 .zip(label_params.drain(..))
13531 .zip(labels.into_iter().chain(iter::repeat(None)))
13532 {
13533 output.push(Symbol {
13534 language_server_name: symbol.language_server_name,
13535 source_worktree_id: symbol.source_worktree_id,
13536 source_language_server_id: symbol.source_language_server_id,
13537 path: symbol.path,
13538 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13539 name,
13540 kind: symbol.kind,
13541 range: symbol.range,
13542 });
13543 }
13544 }
13545}
13546
13547fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13548 match server.capabilities().text_document_sync.as_ref()? {
13549 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13550 // Server wants didSave but didn't specify includeText.
13551 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13552 // Server doesn't want didSave at all.
13553 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13554 // Server provided SaveOptions.
13555 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13556 Some(save_options.include_text.unwrap_or(false))
13557 }
13558 },
13559 // We do not have any save info. Kind affects didChange only.
13560 lsp::TextDocumentSyncCapability::Kind(_) => None,
13561 }
13562}
13563
13564/// Completion items are displayed in a `UniformList`.
13565/// Usually, those items are single-line strings, but in LSP responses,
13566/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13567/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13568/// 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,
13569/// breaking the completions menu presentation.
13570///
13571/// 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.
13572fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13573 let mut new_text = String::with_capacity(label.text.len());
13574 let mut offset_map = vec![0; label.text.len() + 1];
13575 let mut last_char_was_space = false;
13576 let mut new_idx = 0;
13577 let chars = label.text.char_indices().fuse();
13578 let mut newlines_removed = false;
13579
13580 for (idx, c) in chars {
13581 offset_map[idx] = new_idx;
13582
13583 match c {
13584 '\n' if last_char_was_space => {
13585 newlines_removed = true;
13586 }
13587 '\t' | ' ' if last_char_was_space => {}
13588 '\n' if !last_char_was_space => {
13589 new_text.push(' ');
13590 new_idx += 1;
13591 last_char_was_space = true;
13592 newlines_removed = true;
13593 }
13594 ' ' | '\t' => {
13595 new_text.push(' ');
13596 new_idx += 1;
13597 last_char_was_space = true;
13598 }
13599 _ => {
13600 new_text.push(c);
13601 new_idx += c.len_utf8();
13602 last_char_was_space = false;
13603 }
13604 }
13605 }
13606 offset_map[label.text.len()] = new_idx;
13607
13608 // Only modify the label if newlines were removed.
13609 if !newlines_removed {
13610 return;
13611 }
13612
13613 let last_index = new_idx;
13614 let mut run_ranges_errors = Vec::new();
13615 label.runs.retain_mut(|(range, _)| {
13616 match offset_map.get(range.start) {
13617 Some(&start) => range.start = start,
13618 None => {
13619 run_ranges_errors.push(range.clone());
13620 return false;
13621 }
13622 }
13623
13624 match offset_map.get(range.end) {
13625 Some(&end) => range.end = end,
13626 None => {
13627 run_ranges_errors.push(range.clone());
13628 range.end = last_index;
13629 }
13630 }
13631 true
13632 });
13633 if !run_ranges_errors.is_empty() {
13634 log::error!(
13635 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13636 label.text
13637 );
13638 }
13639
13640 let mut wrong_filter_range = None;
13641 if label.filter_range == (0..label.text.len()) {
13642 label.filter_range = 0..new_text.len();
13643 } else {
13644 let mut original_filter_range = Some(label.filter_range.clone());
13645 match offset_map.get(label.filter_range.start) {
13646 Some(&start) => label.filter_range.start = start,
13647 None => {
13648 wrong_filter_range = original_filter_range.take();
13649 label.filter_range.start = last_index;
13650 }
13651 }
13652
13653 match offset_map.get(label.filter_range.end) {
13654 Some(&end) => label.filter_range.end = end,
13655 None => {
13656 wrong_filter_range = original_filter_range.take();
13657 label.filter_range.end = last_index;
13658 }
13659 }
13660 }
13661 if let Some(wrong_filter_range) = wrong_filter_range {
13662 log::error!(
13663 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13664 label.text
13665 );
13666 }
13667
13668 label.text = new_text;
13669}
13670
13671#[cfg(test)]
13672mod tests {
13673 use language::HighlightId;
13674
13675 use super::*;
13676
13677 #[test]
13678 fn test_glob_literal_prefix() {
13679 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13680 assert_eq!(
13681 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13682 Path::new("node_modules")
13683 );
13684 assert_eq!(
13685 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13686 Path::new("foo")
13687 );
13688 assert_eq!(
13689 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13690 Path::new("foo/bar/baz.js")
13691 );
13692
13693 #[cfg(target_os = "windows")]
13694 {
13695 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13696 assert_eq!(
13697 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13698 Path::new("node_modules")
13699 );
13700 assert_eq!(
13701 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13702 Path::new("foo")
13703 );
13704 assert_eq!(
13705 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13706 Path::new("foo/bar/baz.js")
13707 );
13708 }
13709 }
13710
13711 #[test]
13712 fn test_multi_len_chars_normalization() {
13713 let mut label = CodeLabel::new(
13714 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13715 0..6,
13716 vec![(0..6, HighlightId(1))],
13717 );
13718 ensure_uniform_list_compatible_label(&mut label);
13719 assert_eq!(
13720 label,
13721 CodeLabel::new(
13722 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13723 0..6,
13724 vec![(0..6, HighlightId(1))],
13725 )
13726 );
13727 }
13728}