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_lt()
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 local
10844 .language_server_dynamic_registrations
10845 .entry(server_id)
10846 .or_default()
10847 .diagnostics
10848 .entry(None)
10849 .or_insert(provider.clone());
10850 let workspace_refresher =
10851 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10852
10853 Some((None, workspace_refresher))
10854 })
10855 .into_iter()
10856 .collect();
10857 local.language_servers.insert(
10858 server_id,
10859 LanguageServerState::Running {
10860 workspace_diagnostics_refresh_tasks,
10861 adapter: adapter.clone(),
10862 server: language_server.clone(),
10863 simulate_disk_based_diagnostics_completion: None,
10864 },
10865 );
10866 local
10867 .languages
10868 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10869 if let Some(file_ops_caps) = language_server
10870 .capabilities()
10871 .workspace
10872 .as_ref()
10873 .and_then(|ws| ws.file_operations.as_ref())
10874 {
10875 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10876 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10877 if did_rename_caps.or(will_rename_caps).is_some() {
10878 let watcher = RenamePathsWatchedForServer::default()
10879 .with_did_rename_patterns(did_rename_caps)
10880 .with_will_rename_patterns(will_rename_caps);
10881 local
10882 .language_server_paths_watched_for_rename
10883 .insert(server_id, watcher);
10884 }
10885 }
10886
10887 self.language_server_statuses.insert(
10888 server_id,
10889 LanguageServerStatus {
10890 name: language_server.name(),
10891 pending_work: Default::default(),
10892 has_pending_diagnostic_updates: false,
10893 progress_tokens: Default::default(),
10894 worktree: Some(key.worktree_id),
10895 },
10896 );
10897
10898 cx.emit(LspStoreEvent::LanguageServerAdded(
10899 server_id,
10900 language_server.name(),
10901 Some(key.worktree_id),
10902 ));
10903 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
10904
10905 let server_capabilities = language_server.capabilities();
10906 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10907 downstream_client
10908 .send(proto::StartLanguageServer {
10909 project_id: *project_id,
10910 server: Some(proto::LanguageServer {
10911 id: server_id.to_proto(),
10912 name: language_server.name().to_string(),
10913 worktree_id: Some(key.worktree_id.to_proto()),
10914 }),
10915 capabilities: serde_json::to_string(&server_capabilities)
10916 .expect("serializing server LSP capabilities"),
10917 })
10918 .log_err();
10919 }
10920 self.lsp_server_capabilities
10921 .insert(server_id, server_capabilities);
10922
10923 // Tell the language server about every open buffer in the worktree that matches the language.
10924 // Also check for buffers in worktrees that reused this server
10925 let mut worktrees_using_server = vec![key.worktree_id];
10926 if let Some(local) = self.as_local() {
10927 // Find all worktrees that have this server in their language server tree
10928 for (worktree_id, servers) in &local.lsp_tree.instances {
10929 if *worktree_id != key.worktree_id {
10930 for server_map in servers.roots.values() {
10931 if server_map
10932 .values()
10933 .any(|(node, _)| node.id() == Some(server_id))
10934 {
10935 worktrees_using_server.push(*worktree_id);
10936 }
10937 }
10938 }
10939 }
10940 }
10941
10942 let mut buffer_paths_registered = Vec::new();
10943 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10944 let mut lsp_adapters = HashMap::default();
10945 for buffer_handle in buffer_store.buffers() {
10946 let buffer = buffer_handle.read(cx);
10947 let file = match File::from_dyn(buffer.file()) {
10948 Some(file) => file,
10949 None => continue,
10950 };
10951 let language = match buffer.language() {
10952 Some(language) => language,
10953 None => continue,
10954 };
10955
10956 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10957 || !lsp_adapters
10958 .entry(language.name())
10959 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
10960 .iter()
10961 .any(|a| a.name == key.name)
10962 {
10963 continue;
10964 }
10965 // didOpen
10966 let file = match file.as_local() {
10967 Some(file) => file,
10968 None => continue,
10969 };
10970
10971 let local = self.as_local_mut().unwrap();
10972
10973 let buffer_id = buffer.remote_id();
10974 if local.registered_buffers.contains_key(&buffer_id) {
10975 let versions = local
10976 .buffer_snapshots
10977 .entry(buffer_id)
10978 .or_default()
10979 .entry(server_id)
10980 .and_modify(|_| {
10981 assert!(
10982 false,
10983 "There should not be an existing snapshot for a newly inserted buffer"
10984 )
10985 })
10986 .or_insert_with(|| {
10987 vec![LspBufferSnapshot {
10988 version: 0,
10989 snapshot: buffer.text_snapshot(),
10990 }]
10991 });
10992
10993 let snapshot = versions.last().unwrap();
10994 let version = snapshot.version;
10995 let initial_snapshot = &snapshot.snapshot;
10996 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
10997 language_server.register_buffer(
10998 uri,
10999 adapter.language_id(&language.name()),
11000 version,
11001 initial_snapshot.text(),
11002 );
11003 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11004 local
11005 .buffers_opened_in_servers
11006 .entry(buffer_id)
11007 .or_default()
11008 .insert(server_id);
11009 }
11010 buffer_handle.update(cx, |buffer, cx| {
11011 buffer.set_completion_triggers(
11012 server_id,
11013 language_server
11014 .capabilities()
11015 .completion_provider
11016 .as_ref()
11017 .and_then(|provider| {
11018 provider
11019 .trigger_characters
11020 .as_ref()
11021 .map(|characters| characters.iter().cloned().collect())
11022 })
11023 .unwrap_or_default(),
11024 cx,
11025 )
11026 });
11027 }
11028 });
11029
11030 for (buffer_id, abs_path) in buffer_paths_registered {
11031 cx.emit(LspStoreEvent::LanguageServerUpdate {
11032 language_server_id: server_id,
11033 name: Some(adapter.name()),
11034 message: proto::update_language_server::Variant::RegisteredForBuffer(
11035 proto::RegisteredForBuffer {
11036 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11037 buffer_id: buffer_id.to_proto(),
11038 },
11039 ),
11040 });
11041 }
11042
11043 cx.notify();
11044 }
11045
11046 pub fn language_servers_running_disk_based_diagnostics(
11047 &self,
11048 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11049 self.language_server_statuses
11050 .iter()
11051 .filter_map(|(id, status)| {
11052 if status.has_pending_diagnostic_updates {
11053 Some(*id)
11054 } else {
11055 None
11056 }
11057 })
11058 }
11059
11060 pub(crate) fn cancel_language_server_work_for_buffers(
11061 &mut self,
11062 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11063 cx: &mut Context<Self>,
11064 ) {
11065 if let Some((client, project_id)) = self.upstream_client() {
11066 let request = client.request(proto::CancelLanguageServerWork {
11067 project_id,
11068 work: Some(proto::cancel_language_server_work::Work::Buffers(
11069 proto::cancel_language_server_work::Buffers {
11070 buffer_ids: buffers
11071 .into_iter()
11072 .map(|b| b.read(cx).remote_id().to_proto())
11073 .collect(),
11074 },
11075 )),
11076 });
11077 cx.background_spawn(request).detach_and_log_err(cx);
11078 } else if let Some(local) = self.as_local() {
11079 let servers = buffers
11080 .into_iter()
11081 .flat_map(|buffer| {
11082 buffer.update(cx, |buffer, cx| {
11083 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11084 })
11085 })
11086 .collect::<HashSet<_>>();
11087 for server_id in servers {
11088 self.cancel_language_server_work(server_id, None, cx);
11089 }
11090 }
11091 }
11092
11093 pub(crate) fn cancel_language_server_work(
11094 &mut self,
11095 server_id: LanguageServerId,
11096 token_to_cancel: Option<String>,
11097 cx: &mut Context<Self>,
11098 ) {
11099 if let Some(local) = self.as_local() {
11100 let status = self.language_server_statuses.get(&server_id);
11101 let server = local.language_servers.get(&server_id);
11102 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11103 {
11104 for (token, progress) in &status.pending_work {
11105 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11106 && token != token_to_cancel
11107 {
11108 continue;
11109 }
11110 if progress.is_cancellable {
11111 server
11112 .notify::<lsp::notification::WorkDoneProgressCancel>(
11113 WorkDoneProgressCancelParams {
11114 token: lsp::NumberOrString::String(token.clone()),
11115 },
11116 )
11117 .ok();
11118 }
11119 }
11120 }
11121 } else if let Some((client, project_id)) = self.upstream_client() {
11122 let request = client.request(proto::CancelLanguageServerWork {
11123 project_id,
11124 work: Some(
11125 proto::cancel_language_server_work::Work::LanguageServerWork(
11126 proto::cancel_language_server_work::LanguageServerWork {
11127 language_server_id: server_id.to_proto(),
11128 token: token_to_cancel,
11129 },
11130 ),
11131 ),
11132 });
11133 cx.background_spawn(request).detach_and_log_err(cx);
11134 }
11135 }
11136
11137 fn register_supplementary_language_server(
11138 &mut self,
11139 id: LanguageServerId,
11140 name: LanguageServerName,
11141 server: Arc<LanguageServer>,
11142 cx: &mut Context<Self>,
11143 ) {
11144 if let Some(local) = self.as_local_mut() {
11145 local
11146 .supplementary_language_servers
11147 .insert(id, (name.clone(), server));
11148 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11149 }
11150 }
11151
11152 fn unregister_supplementary_language_server(
11153 &mut self,
11154 id: LanguageServerId,
11155 cx: &mut Context<Self>,
11156 ) {
11157 if let Some(local) = self.as_local_mut() {
11158 local.supplementary_language_servers.remove(&id);
11159 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11160 }
11161 }
11162
11163 pub(crate) fn supplementary_language_servers(
11164 &self,
11165 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11166 self.as_local().into_iter().flat_map(|local| {
11167 local
11168 .supplementary_language_servers
11169 .iter()
11170 .map(|(id, (name, _))| (*id, name.clone()))
11171 })
11172 }
11173
11174 pub fn language_server_adapter_for_id(
11175 &self,
11176 id: LanguageServerId,
11177 ) -> Option<Arc<CachedLspAdapter>> {
11178 self.as_local()
11179 .and_then(|local| local.language_servers.get(&id))
11180 .and_then(|language_server_state| match language_server_state {
11181 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11182 _ => None,
11183 })
11184 }
11185
11186 pub(super) fn update_local_worktree_language_servers(
11187 &mut self,
11188 worktree_handle: &Entity<Worktree>,
11189 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11190 cx: &mut Context<Self>,
11191 ) {
11192 if changes.is_empty() {
11193 return;
11194 }
11195
11196 let Some(local) = self.as_local() else { return };
11197
11198 local.prettier_store.update(cx, |prettier_store, cx| {
11199 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11200 });
11201
11202 let worktree_id = worktree_handle.read(cx).id();
11203 let mut language_server_ids = local
11204 .language_server_ids
11205 .iter()
11206 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11207 .collect::<Vec<_>>();
11208 language_server_ids.sort();
11209 language_server_ids.dedup();
11210
11211 // let abs_path = worktree_handle.read(cx).abs_path();
11212 for server_id in &language_server_ids {
11213 if let Some(LanguageServerState::Running { server, .. }) =
11214 local.language_servers.get(server_id)
11215 && let Some(watched_paths) = local
11216 .language_server_watched_paths
11217 .get(server_id)
11218 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11219 {
11220 let params = lsp::DidChangeWatchedFilesParams {
11221 changes: changes
11222 .iter()
11223 .filter_map(|(path, _, change)| {
11224 if !watched_paths.is_match(path.as_std_path()) {
11225 return None;
11226 }
11227 let typ = match change {
11228 PathChange::Loaded => return None,
11229 PathChange::Added => lsp::FileChangeType::CREATED,
11230 PathChange::Removed => lsp::FileChangeType::DELETED,
11231 PathChange::Updated => lsp::FileChangeType::CHANGED,
11232 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11233 };
11234 let uri = lsp::Uri::from_file_path(
11235 worktree_handle.read(cx).absolutize(&path),
11236 )
11237 .ok()?;
11238 Some(lsp::FileEvent { uri, typ })
11239 })
11240 .collect(),
11241 };
11242 if !params.changes.is_empty() {
11243 server
11244 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11245 .ok();
11246 }
11247 }
11248 }
11249 for (path, _, _) in changes {
11250 if let Some(file_name) = path.file_name()
11251 && local.watched_manifest_filenames.contains(file_name)
11252 {
11253 self.request_workspace_config_refresh();
11254 break;
11255 }
11256 }
11257 }
11258
11259 pub fn wait_for_remote_buffer(
11260 &mut self,
11261 id: BufferId,
11262 cx: &mut Context<Self>,
11263 ) -> Task<Result<Entity<Buffer>>> {
11264 self.buffer_store.update(cx, |buffer_store, cx| {
11265 buffer_store.wait_for_remote_buffer(id, cx)
11266 })
11267 }
11268
11269 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11270 let mut result = proto::Symbol {
11271 language_server_name: symbol.language_server_name.0.to_string(),
11272 source_worktree_id: symbol.source_worktree_id.to_proto(),
11273 language_server_id: symbol.source_language_server_id.to_proto(),
11274 name: symbol.name.clone(),
11275 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11276 start: Some(proto::PointUtf16 {
11277 row: symbol.range.start.0.row,
11278 column: symbol.range.start.0.column,
11279 }),
11280 end: Some(proto::PointUtf16 {
11281 row: symbol.range.end.0.row,
11282 column: symbol.range.end.0.column,
11283 }),
11284 worktree_id: Default::default(),
11285 path: Default::default(),
11286 signature: Default::default(),
11287 };
11288 match &symbol.path {
11289 SymbolLocation::InProject(path) => {
11290 result.worktree_id = path.worktree_id.to_proto();
11291 result.path = path.path.to_proto();
11292 }
11293 SymbolLocation::OutsideProject {
11294 abs_path,
11295 signature,
11296 } => {
11297 result.path = abs_path.to_string_lossy().into_owned();
11298 result.signature = signature.to_vec();
11299 }
11300 }
11301 result
11302 }
11303
11304 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11305 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11306 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11307 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11308
11309 let path = if serialized_symbol.signature.is_empty() {
11310 SymbolLocation::InProject(ProjectPath {
11311 worktree_id,
11312 path: RelPath::from_proto(&serialized_symbol.path)
11313 .context("invalid symbol path")?,
11314 })
11315 } else {
11316 SymbolLocation::OutsideProject {
11317 abs_path: Path::new(&serialized_symbol.path).into(),
11318 signature: serialized_symbol
11319 .signature
11320 .try_into()
11321 .map_err(|_| anyhow!("invalid signature"))?,
11322 }
11323 };
11324
11325 let start = serialized_symbol.start.context("invalid start")?;
11326 let end = serialized_symbol.end.context("invalid end")?;
11327 Ok(CoreSymbol {
11328 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11329 source_worktree_id,
11330 source_language_server_id: LanguageServerId::from_proto(
11331 serialized_symbol.language_server_id,
11332 ),
11333 path,
11334 name: serialized_symbol.name,
11335 range: Unclipped(PointUtf16::new(start.row, start.column))
11336 ..Unclipped(PointUtf16::new(end.row, end.column)),
11337 kind,
11338 })
11339 }
11340
11341 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11342 let mut serialized_completion = proto::Completion {
11343 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11344 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11345 new_text: completion.new_text.clone(),
11346 ..proto::Completion::default()
11347 };
11348 match &completion.source {
11349 CompletionSource::Lsp {
11350 insert_range,
11351 server_id,
11352 lsp_completion,
11353 lsp_defaults,
11354 resolved,
11355 } => {
11356 let (old_insert_start, old_insert_end) = insert_range
11357 .as_ref()
11358 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11359 .unzip();
11360
11361 serialized_completion.old_insert_start = old_insert_start;
11362 serialized_completion.old_insert_end = old_insert_end;
11363 serialized_completion.source = proto::completion::Source::Lsp as i32;
11364 serialized_completion.server_id = server_id.0 as u64;
11365 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11366 serialized_completion.lsp_defaults = lsp_defaults
11367 .as_deref()
11368 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11369 serialized_completion.resolved = *resolved;
11370 }
11371 CompletionSource::BufferWord {
11372 word_range,
11373 resolved,
11374 } => {
11375 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11376 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11377 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11378 serialized_completion.resolved = *resolved;
11379 }
11380 CompletionSource::Custom => {
11381 serialized_completion.source = proto::completion::Source::Custom as i32;
11382 serialized_completion.resolved = true;
11383 }
11384 CompletionSource::Dap { sort_text } => {
11385 serialized_completion.source = proto::completion::Source::Dap as i32;
11386 serialized_completion.sort_text = Some(sort_text.clone());
11387 }
11388 }
11389
11390 serialized_completion
11391 }
11392
11393 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11394 let old_replace_start = completion
11395 .old_replace_start
11396 .and_then(deserialize_anchor)
11397 .context("invalid old start")?;
11398 let old_replace_end = completion
11399 .old_replace_end
11400 .and_then(deserialize_anchor)
11401 .context("invalid old end")?;
11402 let insert_range = {
11403 match completion.old_insert_start.zip(completion.old_insert_end) {
11404 Some((start, end)) => {
11405 let start = deserialize_anchor(start).context("invalid insert old start")?;
11406 let end = deserialize_anchor(end).context("invalid insert old end")?;
11407 Some(start..end)
11408 }
11409 None => None,
11410 }
11411 };
11412 Ok(CoreCompletion {
11413 replace_range: old_replace_start..old_replace_end,
11414 new_text: completion.new_text,
11415 source: match proto::completion::Source::from_i32(completion.source) {
11416 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11417 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11418 insert_range,
11419 server_id: LanguageServerId::from_proto(completion.server_id),
11420 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11421 lsp_defaults: completion
11422 .lsp_defaults
11423 .as_deref()
11424 .map(serde_json::from_slice)
11425 .transpose()?,
11426 resolved: completion.resolved,
11427 },
11428 Some(proto::completion::Source::BufferWord) => {
11429 let word_range = completion
11430 .buffer_word_start
11431 .and_then(deserialize_anchor)
11432 .context("invalid buffer word start")?
11433 ..completion
11434 .buffer_word_end
11435 .and_then(deserialize_anchor)
11436 .context("invalid buffer word end")?;
11437 CompletionSource::BufferWord {
11438 word_range,
11439 resolved: completion.resolved,
11440 }
11441 }
11442 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11443 sort_text: completion
11444 .sort_text
11445 .context("expected sort text to exist")?,
11446 },
11447 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11448 },
11449 })
11450 }
11451
11452 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11453 let (kind, lsp_action) = match &action.lsp_action {
11454 LspAction::Action(code_action) => (
11455 proto::code_action::Kind::Action as i32,
11456 serde_json::to_vec(code_action).unwrap(),
11457 ),
11458 LspAction::Command(command) => (
11459 proto::code_action::Kind::Command as i32,
11460 serde_json::to_vec(command).unwrap(),
11461 ),
11462 LspAction::CodeLens(code_lens) => (
11463 proto::code_action::Kind::CodeLens as i32,
11464 serde_json::to_vec(code_lens).unwrap(),
11465 ),
11466 };
11467
11468 proto::CodeAction {
11469 server_id: action.server_id.0 as u64,
11470 start: Some(serialize_anchor(&action.range.start)),
11471 end: Some(serialize_anchor(&action.range.end)),
11472 lsp_action,
11473 kind,
11474 resolved: action.resolved,
11475 }
11476 }
11477
11478 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11479 let start = action
11480 .start
11481 .and_then(deserialize_anchor)
11482 .context("invalid start")?;
11483 let end = action
11484 .end
11485 .and_then(deserialize_anchor)
11486 .context("invalid end")?;
11487 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11488 Some(proto::code_action::Kind::Action) => {
11489 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11490 }
11491 Some(proto::code_action::Kind::Command) => {
11492 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11493 }
11494 Some(proto::code_action::Kind::CodeLens) => {
11495 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11496 }
11497 None => anyhow::bail!("Unknown action kind {}", action.kind),
11498 };
11499 Ok(CodeAction {
11500 server_id: LanguageServerId(action.server_id as usize),
11501 range: start..end,
11502 resolved: action.resolved,
11503 lsp_action,
11504 })
11505 }
11506
11507 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11508 match &formatting_result {
11509 Ok(_) => self.last_formatting_failure = None,
11510 Err(error) => {
11511 let error_string = format!("{error:#}");
11512 log::error!("Formatting failed: {error_string}");
11513 self.last_formatting_failure
11514 .replace(error_string.lines().join(" "));
11515 }
11516 }
11517 }
11518
11519 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11520 self.lsp_server_capabilities.remove(&for_server);
11521 for lsp_data in self.lsp_data.values_mut() {
11522 lsp_data.remove_server_data(for_server);
11523 }
11524 if let Some(local) = self.as_local_mut() {
11525 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11526 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11527 buffer_servers.remove(&for_server);
11528 }
11529 }
11530 }
11531
11532 pub fn result_id(
11533 &self,
11534 server_id: LanguageServerId,
11535 buffer_id: BufferId,
11536 cx: &App,
11537 ) -> Option<String> {
11538 let abs_path = self
11539 .buffer_store
11540 .read(cx)
11541 .get(buffer_id)
11542 .and_then(|b| File::from_dyn(b.read(cx).file()))
11543 .map(|f| f.abs_path(cx))?;
11544 self.as_local()?
11545 .buffer_pull_diagnostics_result_ids
11546 .get(&server_id)?
11547 .get(&abs_path)?
11548 .clone()
11549 }
11550
11551 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11552 let Some(local) = self.as_local() else {
11553 return HashMap::default();
11554 };
11555 local
11556 .buffer_pull_diagnostics_result_ids
11557 .get(&server_id)
11558 .into_iter()
11559 .flatten()
11560 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11561 .collect()
11562 }
11563
11564 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11565 if let Some(LanguageServerState::Running {
11566 workspace_diagnostics_refresh_tasks,
11567 ..
11568 }) = self
11569 .as_local_mut()
11570 .and_then(|local| local.language_servers.get_mut(&server_id))
11571 {
11572 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11573 diagnostics.refresh_tx.try_send(()).ok();
11574 }
11575 }
11576 }
11577
11578 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11579 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11580 return;
11581 };
11582 let Some(local) = self.as_local_mut() else {
11583 return;
11584 };
11585
11586 for server_id in buffer.update(cx, |buffer, cx| {
11587 local.language_server_ids_for_buffer(buffer, cx)
11588 }) {
11589 if let Some(LanguageServerState::Running {
11590 workspace_diagnostics_refresh_tasks,
11591 ..
11592 }) = local.language_servers.get_mut(&server_id)
11593 {
11594 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11595 diagnostics.refresh_tx.try_send(()).ok();
11596 }
11597 }
11598 }
11599 }
11600
11601 fn apply_workspace_diagnostic_report(
11602 &mut self,
11603 server_id: LanguageServerId,
11604 report: lsp::WorkspaceDiagnosticReportResult,
11605 cx: &mut Context<Self>,
11606 ) {
11607 let workspace_diagnostics =
11608 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11609 let mut unchanged_buffers = HashSet::default();
11610 let mut changed_buffers = HashSet::default();
11611 let workspace_diagnostics_updates = workspace_diagnostics
11612 .into_iter()
11613 .filter_map(
11614 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11615 LspPullDiagnostics::Response {
11616 server_id,
11617 uri,
11618 diagnostics,
11619 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11620 LspPullDiagnostics::Default => None,
11621 },
11622 )
11623 .fold(
11624 HashMap::default(),
11625 |mut acc, (server_id, uri, diagnostics, version)| {
11626 let (result_id, diagnostics) = match diagnostics {
11627 PulledDiagnostics::Unchanged { result_id } => {
11628 unchanged_buffers.insert(uri.clone());
11629 (Some(result_id), Vec::new())
11630 }
11631 PulledDiagnostics::Changed {
11632 result_id,
11633 diagnostics,
11634 } => {
11635 changed_buffers.insert(uri.clone());
11636 (result_id, diagnostics)
11637 }
11638 };
11639 let disk_based_sources = Cow::Owned(
11640 self.language_server_adapter_for_id(server_id)
11641 .as_ref()
11642 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11643 .unwrap_or(&[])
11644 .to_vec(),
11645 );
11646 acc.entry(server_id)
11647 .or_insert_with(Vec::new)
11648 .push(DocumentDiagnosticsUpdate {
11649 server_id,
11650 diagnostics: lsp::PublishDiagnosticsParams {
11651 uri,
11652 diagnostics,
11653 version,
11654 },
11655 result_id,
11656 disk_based_sources,
11657 });
11658 acc
11659 },
11660 );
11661
11662 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11663 self.merge_lsp_diagnostics(
11664 DiagnosticSourceKind::Pulled,
11665 diagnostic_updates,
11666 |buffer, old_diagnostic, cx| {
11667 File::from_dyn(buffer.file())
11668 .and_then(|file| {
11669 let abs_path = file.as_local()?.abs_path(cx);
11670 lsp::Uri::from_file_path(abs_path).ok()
11671 })
11672 .is_none_or(|buffer_uri| {
11673 unchanged_buffers.contains(&buffer_uri)
11674 || match old_diagnostic.source_kind {
11675 DiagnosticSourceKind::Pulled => {
11676 !changed_buffers.contains(&buffer_uri)
11677 }
11678 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11679 true
11680 }
11681 }
11682 })
11683 },
11684 cx,
11685 )
11686 .log_err();
11687 }
11688 }
11689
11690 fn register_server_capabilities(
11691 &mut self,
11692 server_id: LanguageServerId,
11693 params: lsp::RegistrationParams,
11694 cx: &mut Context<Self>,
11695 ) -> anyhow::Result<()> {
11696 let server = self
11697 .language_server_for_id(server_id)
11698 .with_context(|| format!("no server {server_id} found"))?;
11699 for reg in params.registrations {
11700 match reg.method.as_str() {
11701 "workspace/didChangeWatchedFiles" => {
11702 if let Some(options) = reg.register_options {
11703 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11704 let caps = serde_json::from_value(options)?;
11705 local_lsp_store
11706 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11707 true
11708 } else {
11709 false
11710 };
11711 if notify {
11712 notify_server_capabilities_updated(&server, cx);
11713 }
11714 }
11715 }
11716 "workspace/didChangeConfiguration" => {
11717 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11718 }
11719 "workspace/didChangeWorkspaceFolders" => {
11720 // In this case register options is an empty object, we can ignore it
11721 let caps = lsp::WorkspaceFoldersServerCapabilities {
11722 supported: Some(true),
11723 change_notifications: Some(OneOf::Right(reg.id)),
11724 };
11725 server.update_capabilities(|capabilities| {
11726 capabilities
11727 .workspace
11728 .get_or_insert_default()
11729 .workspace_folders = Some(caps);
11730 });
11731 notify_server_capabilities_updated(&server, cx);
11732 }
11733 "workspace/symbol" => {
11734 let options = parse_register_capabilities(reg)?;
11735 server.update_capabilities(|capabilities| {
11736 capabilities.workspace_symbol_provider = Some(options);
11737 });
11738 notify_server_capabilities_updated(&server, cx);
11739 }
11740 "workspace/fileOperations" => {
11741 if let Some(options) = reg.register_options {
11742 let caps = serde_json::from_value(options)?;
11743 server.update_capabilities(|capabilities| {
11744 capabilities
11745 .workspace
11746 .get_or_insert_default()
11747 .file_operations = Some(caps);
11748 });
11749 notify_server_capabilities_updated(&server, cx);
11750 }
11751 }
11752 "workspace/executeCommand" => {
11753 if let Some(options) = reg.register_options {
11754 let options = serde_json::from_value(options)?;
11755 server.update_capabilities(|capabilities| {
11756 capabilities.execute_command_provider = Some(options);
11757 });
11758 notify_server_capabilities_updated(&server, cx);
11759 }
11760 }
11761 "textDocument/rangeFormatting" => {
11762 let options = parse_register_capabilities(reg)?;
11763 server.update_capabilities(|capabilities| {
11764 capabilities.document_range_formatting_provider = Some(options);
11765 });
11766 notify_server_capabilities_updated(&server, cx);
11767 }
11768 "textDocument/onTypeFormatting" => {
11769 if let Some(options) = reg
11770 .register_options
11771 .map(serde_json::from_value)
11772 .transpose()?
11773 {
11774 server.update_capabilities(|capabilities| {
11775 capabilities.document_on_type_formatting_provider = Some(options);
11776 });
11777 notify_server_capabilities_updated(&server, cx);
11778 }
11779 }
11780 "textDocument/formatting" => {
11781 let options = parse_register_capabilities(reg)?;
11782 server.update_capabilities(|capabilities| {
11783 capabilities.document_formatting_provider = Some(options);
11784 });
11785 notify_server_capabilities_updated(&server, cx);
11786 }
11787 "textDocument/rename" => {
11788 let options = parse_register_capabilities(reg)?;
11789 server.update_capabilities(|capabilities| {
11790 capabilities.rename_provider = Some(options);
11791 });
11792 notify_server_capabilities_updated(&server, cx);
11793 }
11794 "textDocument/inlayHint" => {
11795 let options = parse_register_capabilities(reg)?;
11796 server.update_capabilities(|capabilities| {
11797 capabilities.inlay_hint_provider = Some(options);
11798 });
11799 notify_server_capabilities_updated(&server, cx);
11800 }
11801 "textDocument/documentSymbol" => {
11802 let options = parse_register_capabilities(reg)?;
11803 server.update_capabilities(|capabilities| {
11804 capabilities.document_symbol_provider = Some(options);
11805 });
11806 notify_server_capabilities_updated(&server, cx);
11807 }
11808 "textDocument/codeAction" => {
11809 let options = parse_register_capabilities(reg)?;
11810 let provider = match options {
11811 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11812 OneOf::Right(caps) => caps,
11813 };
11814 server.update_capabilities(|capabilities| {
11815 capabilities.code_action_provider = Some(provider);
11816 });
11817 notify_server_capabilities_updated(&server, cx);
11818 }
11819 "textDocument/definition" => {
11820 let options = parse_register_capabilities(reg)?;
11821 server.update_capabilities(|capabilities| {
11822 capabilities.definition_provider = Some(options);
11823 });
11824 notify_server_capabilities_updated(&server, cx);
11825 }
11826 "textDocument/completion" => {
11827 if let Some(caps) = reg
11828 .register_options
11829 .map(serde_json::from_value)
11830 .transpose()?
11831 {
11832 server.update_capabilities(|capabilities| {
11833 capabilities.completion_provider = Some(caps);
11834 });
11835 notify_server_capabilities_updated(&server, cx);
11836 }
11837 }
11838 "textDocument/hover" => {
11839 let options = parse_register_capabilities(reg)?;
11840 let provider = match options {
11841 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11842 OneOf::Right(caps) => caps,
11843 };
11844 server.update_capabilities(|capabilities| {
11845 capabilities.hover_provider = Some(provider);
11846 });
11847 notify_server_capabilities_updated(&server, cx);
11848 }
11849 "textDocument/signatureHelp" => {
11850 if let Some(caps) = reg
11851 .register_options
11852 .map(serde_json::from_value)
11853 .transpose()?
11854 {
11855 server.update_capabilities(|capabilities| {
11856 capabilities.signature_help_provider = Some(caps);
11857 });
11858 notify_server_capabilities_updated(&server, cx);
11859 }
11860 }
11861 "textDocument/didChange" => {
11862 if let Some(sync_kind) = reg
11863 .register_options
11864 .and_then(|opts| opts.get("syncKind").cloned())
11865 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11866 .transpose()?
11867 {
11868 server.update_capabilities(|capabilities| {
11869 let mut sync_options =
11870 Self::take_text_document_sync_options(capabilities);
11871 sync_options.change = Some(sync_kind);
11872 capabilities.text_document_sync =
11873 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11874 });
11875 notify_server_capabilities_updated(&server, cx);
11876 }
11877 }
11878 "textDocument/didSave" => {
11879 if let Some(include_text) = reg
11880 .register_options
11881 .map(|opts| {
11882 let transpose = opts
11883 .get("includeText")
11884 .cloned()
11885 .map(serde_json::from_value::<Option<bool>>)
11886 .transpose();
11887 match transpose {
11888 Ok(value) => Ok(value.flatten()),
11889 Err(e) => Err(e),
11890 }
11891 })
11892 .transpose()?
11893 {
11894 server.update_capabilities(|capabilities| {
11895 let mut sync_options =
11896 Self::take_text_document_sync_options(capabilities);
11897 sync_options.save =
11898 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11899 include_text,
11900 }));
11901 capabilities.text_document_sync =
11902 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11903 });
11904 notify_server_capabilities_updated(&server, cx);
11905 }
11906 }
11907 "textDocument/codeLens" => {
11908 if let Some(caps) = reg
11909 .register_options
11910 .map(serde_json::from_value)
11911 .transpose()?
11912 {
11913 server.update_capabilities(|capabilities| {
11914 capabilities.code_lens_provider = Some(caps);
11915 });
11916 notify_server_capabilities_updated(&server, cx);
11917 }
11918 }
11919 "textDocument/diagnostic" => {
11920 if let Some(caps) = reg
11921 .register_options
11922 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
11923 .transpose()?
11924 {
11925 let local = self
11926 .as_local_mut()
11927 .context("Expected LSP Store to be local")?;
11928 let state = local
11929 .language_servers
11930 .get_mut(&server_id)
11931 .context("Could not obtain Language Servers state")?;
11932 local
11933 .language_server_dynamic_registrations
11934 .get_mut(&server_id)
11935 .and_then(|registrations| {
11936 registrations
11937 .diagnostics
11938 .insert(Some(reg.id.clone()), caps.clone())
11939 });
11940
11941 let mut can_now_provide_diagnostics = false;
11942 if let LanguageServerState::Running {
11943 workspace_diagnostics_refresh_tasks,
11944 ..
11945 } = state
11946 && let Some(task) = lsp_workspace_diagnostics_refresh(
11947 Some(reg.id.clone()),
11948 caps.clone(),
11949 server.clone(),
11950 cx,
11951 )
11952 {
11953 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
11954 can_now_provide_diagnostics = true;
11955 }
11956
11957 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
11958 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
11959 // as it'll think that they're not supported.
11960 if can_now_provide_diagnostics {
11961 server.update_capabilities(|capabilities| {
11962 debug_assert!(capabilities.diagnostic_provider.is_none());
11963 capabilities.diagnostic_provider = Some(caps);
11964 });
11965 }
11966
11967 notify_server_capabilities_updated(&server, cx);
11968 }
11969 }
11970 "textDocument/documentColor" => {
11971 let options = parse_register_capabilities(reg)?;
11972 let provider = match options {
11973 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11974 OneOf::Right(caps) => caps,
11975 };
11976 server.update_capabilities(|capabilities| {
11977 capabilities.color_provider = Some(provider);
11978 });
11979 notify_server_capabilities_updated(&server, cx);
11980 }
11981 _ => log::warn!("unhandled capability registration: {reg:?}"),
11982 }
11983 }
11984
11985 Ok(())
11986 }
11987
11988 fn unregister_server_capabilities(
11989 &mut self,
11990 server_id: LanguageServerId,
11991 params: lsp::UnregistrationParams,
11992 cx: &mut Context<Self>,
11993 ) -> anyhow::Result<()> {
11994 let server = self
11995 .language_server_for_id(server_id)
11996 .with_context(|| format!("no server {server_id} found"))?;
11997 for unreg in params.unregisterations.iter() {
11998 match unreg.method.as_str() {
11999 "workspace/didChangeWatchedFiles" => {
12000 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12001 local_lsp_store
12002 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12003 true
12004 } else {
12005 false
12006 };
12007 if notify {
12008 notify_server_capabilities_updated(&server, cx);
12009 }
12010 }
12011 "workspace/didChangeConfiguration" => {
12012 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12013 }
12014 "workspace/didChangeWorkspaceFolders" => {
12015 server.update_capabilities(|capabilities| {
12016 capabilities
12017 .workspace
12018 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12019 workspace_folders: None,
12020 file_operations: None,
12021 })
12022 .workspace_folders = None;
12023 });
12024 notify_server_capabilities_updated(&server, cx);
12025 }
12026 "workspace/symbol" => {
12027 server.update_capabilities(|capabilities| {
12028 capabilities.workspace_symbol_provider = None
12029 });
12030 notify_server_capabilities_updated(&server, cx);
12031 }
12032 "workspace/fileOperations" => {
12033 server.update_capabilities(|capabilities| {
12034 capabilities
12035 .workspace
12036 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12037 workspace_folders: None,
12038 file_operations: None,
12039 })
12040 .file_operations = None;
12041 });
12042 notify_server_capabilities_updated(&server, cx);
12043 }
12044 "workspace/executeCommand" => {
12045 server.update_capabilities(|capabilities| {
12046 capabilities.execute_command_provider = None;
12047 });
12048 notify_server_capabilities_updated(&server, cx);
12049 }
12050 "textDocument/rangeFormatting" => {
12051 server.update_capabilities(|capabilities| {
12052 capabilities.document_range_formatting_provider = None
12053 });
12054 notify_server_capabilities_updated(&server, cx);
12055 }
12056 "textDocument/onTypeFormatting" => {
12057 server.update_capabilities(|capabilities| {
12058 capabilities.document_on_type_formatting_provider = None;
12059 });
12060 notify_server_capabilities_updated(&server, cx);
12061 }
12062 "textDocument/formatting" => {
12063 server.update_capabilities(|capabilities| {
12064 capabilities.document_formatting_provider = None;
12065 });
12066 notify_server_capabilities_updated(&server, cx);
12067 }
12068 "textDocument/rename" => {
12069 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12070 notify_server_capabilities_updated(&server, cx);
12071 }
12072 "textDocument/codeAction" => {
12073 server.update_capabilities(|capabilities| {
12074 capabilities.code_action_provider = None;
12075 });
12076 notify_server_capabilities_updated(&server, cx);
12077 }
12078 "textDocument/definition" => {
12079 server.update_capabilities(|capabilities| {
12080 capabilities.definition_provider = None;
12081 });
12082 notify_server_capabilities_updated(&server, cx);
12083 }
12084 "textDocument/completion" => {
12085 server.update_capabilities(|capabilities| {
12086 capabilities.completion_provider = None;
12087 });
12088 notify_server_capabilities_updated(&server, cx);
12089 }
12090 "textDocument/hover" => {
12091 server.update_capabilities(|capabilities| {
12092 capabilities.hover_provider = None;
12093 });
12094 notify_server_capabilities_updated(&server, cx);
12095 }
12096 "textDocument/signatureHelp" => {
12097 server.update_capabilities(|capabilities| {
12098 capabilities.signature_help_provider = None;
12099 });
12100 notify_server_capabilities_updated(&server, cx);
12101 }
12102 "textDocument/didChange" => {
12103 server.update_capabilities(|capabilities| {
12104 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12105 sync_options.change = None;
12106 capabilities.text_document_sync =
12107 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12108 });
12109 notify_server_capabilities_updated(&server, cx);
12110 }
12111 "textDocument/didSave" => {
12112 server.update_capabilities(|capabilities| {
12113 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12114 sync_options.save = None;
12115 capabilities.text_document_sync =
12116 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12117 });
12118 notify_server_capabilities_updated(&server, cx);
12119 }
12120 "textDocument/codeLens" => {
12121 server.update_capabilities(|capabilities| {
12122 capabilities.code_lens_provider = None;
12123 });
12124 notify_server_capabilities_updated(&server, cx);
12125 }
12126 "textDocument/diagnostic" => {
12127 let local = self
12128 .as_local_mut()
12129 .context("Expected LSP Store to be local")?;
12130
12131 let state = local
12132 .language_servers
12133 .get_mut(&server_id)
12134 .context("Could not obtain Language Servers state")?;
12135 let options = local
12136 .language_server_dynamic_registrations
12137 .get_mut(&server_id)
12138 .with_context(|| {
12139 format!("Expected dynamic registration to exist for server {server_id}")
12140 })?.diagnostics
12141 .remove(&Some(unreg.id.clone()))
12142 .with_context(|| format!(
12143 "Attempted to unregister non-existent diagnostic registration with ID {}",
12144 unreg.id)
12145 )?;
12146
12147 let mut has_any_diagnostic_providers_still = true;
12148 if let Some(identifier) = diagnostic_identifier(&options)
12149 && let LanguageServerState::Running {
12150 workspace_diagnostics_refresh_tasks,
12151 ..
12152 } = state
12153 {
12154 workspace_diagnostics_refresh_tasks.remove(&identifier);
12155 has_any_diagnostic_providers_still =
12156 !workspace_diagnostics_refresh_tasks.is_empty();
12157 }
12158
12159 if !has_any_diagnostic_providers_still {
12160 server.update_capabilities(|capabilities| {
12161 debug_assert!(capabilities.diagnostic_provider.is_some());
12162 capabilities.diagnostic_provider = None;
12163 });
12164 }
12165
12166 notify_server_capabilities_updated(&server, cx);
12167 }
12168 "textDocument/documentColor" => {
12169 server.update_capabilities(|capabilities| {
12170 capabilities.color_provider = None;
12171 });
12172 notify_server_capabilities_updated(&server, cx);
12173 }
12174 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12175 }
12176 }
12177
12178 Ok(())
12179 }
12180
12181 async fn deduplicate_range_based_lsp_requests<T>(
12182 lsp_store: &Entity<Self>,
12183 server_id: Option<LanguageServerId>,
12184 lsp_request_id: LspRequestId,
12185 proto_request: &T::ProtoRequest,
12186 range: Range<Anchor>,
12187 cx: &mut AsyncApp,
12188 ) -> Result<()>
12189 where
12190 T: LspCommand,
12191 T::ProtoRequest: proto::LspRequestMessage,
12192 {
12193 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12194 let version = deserialize_version(proto_request.buffer_version());
12195 let buffer = lsp_store.update(cx, |this, cx| {
12196 this.buffer_store.read(cx).get_existing(buffer_id)
12197 })??;
12198 buffer
12199 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12200 .await?;
12201 lsp_store.update(cx, |lsp_store, cx| {
12202 let lsp_data = lsp_store
12203 .lsp_data
12204 .entry(buffer_id)
12205 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12206 let chunks_queried_for = lsp_data
12207 .inlay_hints
12208 .applicable_chunks(&[range])
12209 .collect::<Vec<_>>();
12210 match chunks_queried_for.as_slice() {
12211 &[chunk] => {
12212 let key = LspKey {
12213 request_type: TypeId::of::<T>(),
12214 server_queried: server_id,
12215 };
12216 let previous_request = lsp_data
12217 .chunk_lsp_requests
12218 .entry(key)
12219 .or_default()
12220 .insert(chunk, lsp_request_id);
12221 if let Some((previous_request, running_requests)) =
12222 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12223 {
12224 running_requests.remove(&previous_request);
12225 }
12226 }
12227 _ambiguous_chunks => {
12228 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12229 // there, a buffer version-based check will be performed and outdated requests discarded.
12230 }
12231 }
12232 anyhow::Ok(())
12233 })??;
12234
12235 Ok(())
12236 }
12237
12238 async fn query_lsp_locally<T>(
12239 lsp_store: Entity<Self>,
12240 for_server_id: Option<LanguageServerId>,
12241 sender_id: proto::PeerId,
12242 lsp_request_id: LspRequestId,
12243 proto_request: T::ProtoRequest,
12244 position: Option<Anchor>,
12245 cx: &mut AsyncApp,
12246 ) -> Result<()>
12247 where
12248 T: LspCommand + Clone,
12249 T::ProtoRequest: proto::LspRequestMessage,
12250 <T::ProtoRequest as proto::RequestMessage>::Response:
12251 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12252 {
12253 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12254 let version = deserialize_version(proto_request.buffer_version());
12255 let buffer = lsp_store.update(cx, |this, cx| {
12256 this.buffer_store.read(cx).get_existing(buffer_id)
12257 })??;
12258 buffer
12259 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12260 .await?;
12261 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12262 let request =
12263 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12264 let key = LspKey {
12265 request_type: TypeId::of::<T>(),
12266 server_queried: for_server_id,
12267 };
12268 lsp_store.update(cx, |lsp_store, cx| {
12269 let request_task = match for_server_id {
12270 Some(server_id) => {
12271 let server_task = lsp_store.request_lsp(
12272 buffer.clone(),
12273 LanguageServerToQuery::Other(server_id),
12274 request.clone(),
12275 cx,
12276 );
12277 cx.background_spawn(async move {
12278 let mut responses = Vec::new();
12279 match server_task.await {
12280 Ok(response) => responses.push((server_id, response)),
12281 Err(e) => log::error!(
12282 "Error handling response for request {request:?}: {e:#}"
12283 ),
12284 }
12285 responses
12286 })
12287 }
12288 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12289 };
12290 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12291 if T::ProtoRequest::stop_previous_requests() {
12292 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12293 lsp_requests.clear();
12294 }
12295 }
12296 lsp_data.lsp_requests.entry(key).or_default().insert(
12297 lsp_request_id,
12298 cx.spawn(async move |lsp_store, cx| {
12299 let response = request_task.await;
12300 lsp_store
12301 .update(cx, |lsp_store, cx| {
12302 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12303 {
12304 let response = response
12305 .into_iter()
12306 .map(|(server_id, response)| {
12307 (
12308 server_id.to_proto(),
12309 T::response_to_proto(
12310 response,
12311 lsp_store,
12312 sender_id,
12313 &buffer_version,
12314 cx,
12315 )
12316 .into(),
12317 )
12318 })
12319 .collect::<HashMap<_, _>>();
12320 match client.send_lsp_response::<T::ProtoRequest>(
12321 project_id,
12322 lsp_request_id,
12323 response,
12324 ) {
12325 Ok(()) => {}
12326 Err(e) => {
12327 log::error!("Failed to send LSP response: {e:#}",)
12328 }
12329 }
12330 }
12331 })
12332 .ok();
12333 }),
12334 );
12335 })?;
12336 Ok(())
12337 }
12338
12339 fn take_text_document_sync_options(
12340 capabilities: &mut lsp::ServerCapabilities,
12341 ) -> lsp::TextDocumentSyncOptions {
12342 match capabilities.text_document_sync.take() {
12343 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12344 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12345 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12346 sync_options.change = Some(sync_kind);
12347 sync_options
12348 }
12349 None => lsp::TextDocumentSyncOptions::default(),
12350 }
12351 }
12352
12353 #[cfg(any(test, feature = "test-support"))]
12354 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12355 Some(
12356 self.lsp_data
12357 .get_mut(&buffer_id)?
12358 .code_lens
12359 .take()?
12360 .update
12361 .take()?
12362 .1,
12363 )
12364 }
12365
12366 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12367 self.downstream_client.clone()
12368 }
12369
12370 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12371 self.worktree_store.clone()
12372 }
12373
12374 /// Gets what's stored in the LSP data for the given buffer.
12375 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12376 self.lsp_data.get_mut(&buffer_id)
12377 }
12378
12379 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12380 /// new [`BufferLspData`] will be created to replace the previous state.
12381 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12382 let (buffer_id, buffer_version) =
12383 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12384 let lsp_data = self
12385 .lsp_data
12386 .entry(buffer_id)
12387 .or_insert_with(|| BufferLspData::new(buffer, cx));
12388 if buffer_version.changed_since(&lsp_data.buffer_version) {
12389 *lsp_data = BufferLspData::new(buffer, cx);
12390 }
12391 lsp_data
12392 }
12393}
12394
12395// Registration with registerOptions as null, should fallback to true.
12396// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12397fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12398 reg: lsp::Registration,
12399) -> Result<OneOf<bool, T>> {
12400 Ok(match reg.register_options {
12401 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12402 None => OneOf::Left(true),
12403 })
12404}
12405
12406fn subscribe_to_binary_statuses(
12407 languages: &Arc<LanguageRegistry>,
12408 cx: &mut Context<'_, LspStore>,
12409) -> Task<()> {
12410 let mut server_statuses = languages.language_server_binary_statuses();
12411 cx.spawn(async move |lsp_store, cx| {
12412 while let Some((server_name, binary_status)) = server_statuses.next().await {
12413 if lsp_store
12414 .update(cx, |_, cx| {
12415 let mut message = None;
12416 let binary_status = match binary_status {
12417 BinaryStatus::None => proto::ServerBinaryStatus::None,
12418 BinaryStatus::CheckingForUpdate => {
12419 proto::ServerBinaryStatus::CheckingForUpdate
12420 }
12421 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12422 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12423 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12424 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12425 BinaryStatus::Failed { error } => {
12426 message = Some(error);
12427 proto::ServerBinaryStatus::Failed
12428 }
12429 };
12430 cx.emit(LspStoreEvent::LanguageServerUpdate {
12431 // Binary updates are about the binary that might not have any language server id at that point.
12432 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12433 language_server_id: LanguageServerId(0),
12434 name: Some(server_name),
12435 message: proto::update_language_server::Variant::StatusUpdate(
12436 proto::StatusUpdate {
12437 message,
12438 status: Some(proto::status_update::Status::Binary(
12439 binary_status as i32,
12440 )),
12441 },
12442 ),
12443 });
12444 })
12445 .is_err()
12446 {
12447 break;
12448 }
12449 }
12450 })
12451}
12452
12453fn lsp_workspace_diagnostics_refresh(
12454 registration_id: Option<String>,
12455 options: DiagnosticServerCapabilities,
12456 server: Arc<LanguageServer>,
12457 cx: &mut Context<'_, LspStore>,
12458) -> Option<WorkspaceRefreshTask> {
12459 let identifier = diagnostic_identifier(&options)?;
12460
12461 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12462 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12463 refresh_tx.try_send(()).ok();
12464
12465 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12466 let mut attempts = 0;
12467 let max_attempts = 50;
12468 let mut requests = 0;
12469
12470 loop {
12471 let Some(()) = refresh_rx.recv().await else {
12472 return;
12473 };
12474
12475 'request: loop {
12476 requests += 1;
12477 if attempts > max_attempts {
12478 log::error!(
12479 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12480 );
12481 return;
12482 }
12483 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12484 cx.background_executor()
12485 .timer(Duration::from_millis(backoff_millis))
12486 .await;
12487 attempts += 1;
12488
12489 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12490 lsp_store
12491 .all_result_ids(server.server_id())
12492 .into_iter()
12493 .filter_map(|(abs_path, result_id)| {
12494 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12495 Some(lsp::PreviousResultId {
12496 uri,
12497 value: result_id,
12498 })
12499 })
12500 .collect()
12501 }) else {
12502 return;
12503 };
12504
12505 let token = if let Some(identifier) = ®istration_id {
12506 format!(
12507 "workspace/diagnostic/{}/{requests}/id:{identifier}",
12508 server.server_id(),
12509 )
12510 } else {
12511 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12512 };
12513
12514 progress_rx.try_recv().ok();
12515 let timer =
12516 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12517 let progress = pin!(progress_rx.recv().fuse());
12518 let response_result = server
12519 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12520 lsp::WorkspaceDiagnosticParams {
12521 previous_result_ids,
12522 identifier: identifier.clone(),
12523 work_done_progress_params: Default::default(),
12524 partial_result_params: lsp::PartialResultParams {
12525 partial_result_token: Some(lsp::ProgressToken::String(token)),
12526 },
12527 },
12528 select(timer, progress).then(|either| match either {
12529 Either::Left((message, ..)) => ready(message).left_future(),
12530 Either::Right(..) => pending::<String>().right_future(),
12531 }),
12532 )
12533 .await;
12534
12535 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12536 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12537 match response_result {
12538 ConnectionResult::Timeout => {
12539 log::error!("Timeout during workspace diagnostics pull");
12540 continue 'request;
12541 }
12542 ConnectionResult::ConnectionReset => {
12543 log::error!("Server closed a workspace diagnostics pull request");
12544 continue 'request;
12545 }
12546 ConnectionResult::Result(Err(e)) => {
12547 log::error!("Error during workspace diagnostics pull: {e:#}");
12548 break 'request;
12549 }
12550 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12551 attempts = 0;
12552 if lsp_store
12553 .update(cx, |lsp_store, cx| {
12554 lsp_store.apply_workspace_diagnostic_report(
12555 server.server_id(),
12556 pulled_diagnostics,
12557 cx,
12558 )
12559 })
12560 .is_err()
12561 {
12562 return;
12563 }
12564 break 'request;
12565 }
12566 }
12567 }
12568 }
12569 });
12570
12571 Some(WorkspaceRefreshTask {
12572 refresh_tx,
12573 progress_tx,
12574 task: workspace_query_language_server,
12575 })
12576}
12577
12578fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12579 match &options {
12580 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12581 if !diagnostic_options.workspace_diagnostics {
12582 return None;
12583 }
12584 Some(diagnostic_options.identifier.clone())
12585 }
12586 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12587 let diagnostic_options = ®istration_options.diagnostic_options;
12588 if !diagnostic_options.workspace_diagnostics {
12589 return None;
12590 }
12591 Some(diagnostic_options.identifier.clone())
12592 }
12593 }
12594}
12595
12596fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12597 let CompletionSource::BufferWord {
12598 word_range,
12599 resolved,
12600 } = &mut completion.source
12601 else {
12602 return;
12603 };
12604 if *resolved {
12605 return;
12606 }
12607
12608 if completion.new_text
12609 != snapshot
12610 .text_for_range(word_range.clone())
12611 .collect::<String>()
12612 {
12613 return;
12614 }
12615
12616 let mut offset = 0;
12617 for chunk in snapshot.chunks(word_range.clone(), true) {
12618 let end_offset = offset + chunk.text.len();
12619 if let Some(highlight_id) = chunk.syntax_highlight_id {
12620 completion
12621 .label
12622 .runs
12623 .push((offset..end_offset, highlight_id));
12624 }
12625 offset = end_offset;
12626 }
12627 *resolved = true;
12628}
12629
12630impl EventEmitter<LspStoreEvent> for LspStore {}
12631
12632fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12633 hover
12634 .contents
12635 .retain(|hover_block| !hover_block.text.trim().is_empty());
12636 if hover.contents.is_empty() {
12637 None
12638 } else {
12639 Some(hover)
12640 }
12641}
12642
12643async fn populate_labels_for_completions(
12644 new_completions: Vec<CoreCompletion>,
12645 language: Option<Arc<Language>>,
12646 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12647) -> Vec<Completion> {
12648 let lsp_completions = new_completions
12649 .iter()
12650 .filter_map(|new_completion| {
12651 new_completion
12652 .source
12653 .lsp_completion(true)
12654 .map(|lsp_completion| lsp_completion.into_owned())
12655 })
12656 .collect::<Vec<_>>();
12657
12658 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12659 lsp_adapter
12660 .labels_for_completions(&lsp_completions, language)
12661 .await
12662 .log_err()
12663 .unwrap_or_default()
12664 } else {
12665 Vec::new()
12666 }
12667 .into_iter()
12668 .fuse();
12669
12670 let mut completions = Vec::new();
12671 for completion in new_completions {
12672 match completion.source.lsp_completion(true) {
12673 Some(lsp_completion) => {
12674 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12675
12676 let mut label = labels.next().flatten().unwrap_or_else(|| {
12677 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12678 });
12679 ensure_uniform_list_compatible_label(&mut label);
12680 completions.push(Completion {
12681 label,
12682 documentation,
12683 replace_range: completion.replace_range,
12684 new_text: completion.new_text,
12685 insert_text_mode: lsp_completion.insert_text_mode,
12686 source: completion.source,
12687 icon_path: None,
12688 confirm: None,
12689 });
12690 }
12691 None => {
12692 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12693 ensure_uniform_list_compatible_label(&mut label);
12694 completions.push(Completion {
12695 label,
12696 documentation: None,
12697 replace_range: completion.replace_range,
12698 new_text: completion.new_text,
12699 source: completion.source,
12700 insert_text_mode: None,
12701 icon_path: None,
12702 confirm: None,
12703 });
12704 }
12705 }
12706 }
12707 completions
12708}
12709
12710#[derive(Debug)]
12711pub enum LanguageServerToQuery {
12712 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12713 FirstCapable,
12714 /// Query a specific language server.
12715 Other(LanguageServerId),
12716}
12717
12718#[derive(Default)]
12719struct RenamePathsWatchedForServer {
12720 did_rename: Vec<RenameActionPredicate>,
12721 will_rename: Vec<RenameActionPredicate>,
12722}
12723
12724impl RenamePathsWatchedForServer {
12725 fn with_did_rename_patterns(
12726 mut self,
12727 did_rename: Option<&FileOperationRegistrationOptions>,
12728 ) -> Self {
12729 if let Some(did_rename) = did_rename {
12730 self.did_rename = did_rename
12731 .filters
12732 .iter()
12733 .filter_map(|filter| filter.try_into().log_err())
12734 .collect();
12735 }
12736 self
12737 }
12738 fn with_will_rename_patterns(
12739 mut self,
12740 will_rename: Option<&FileOperationRegistrationOptions>,
12741 ) -> Self {
12742 if let Some(will_rename) = will_rename {
12743 self.will_rename = will_rename
12744 .filters
12745 .iter()
12746 .filter_map(|filter| filter.try_into().log_err())
12747 .collect();
12748 }
12749 self
12750 }
12751
12752 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12753 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12754 }
12755 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12756 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12757 }
12758}
12759
12760impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12761 type Error = globset::Error;
12762 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12763 Ok(Self {
12764 kind: ops.pattern.matches.clone(),
12765 glob: GlobBuilder::new(&ops.pattern.glob)
12766 .case_insensitive(
12767 ops.pattern
12768 .options
12769 .as_ref()
12770 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12771 )
12772 .build()?
12773 .compile_matcher(),
12774 })
12775 }
12776}
12777struct RenameActionPredicate {
12778 glob: GlobMatcher,
12779 kind: Option<FileOperationPatternKind>,
12780}
12781
12782impl RenameActionPredicate {
12783 // Returns true if language server should be notified
12784 fn eval(&self, path: &str, is_dir: bool) -> bool {
12785 self.kind.as_ref().is_none_or(|kind| {
12786 let expected_kind = if is_dir {
12787 FileOperationPatternKind::Folder
12788 } else {
12789 FileOperationPatternKind::File
12790 };
12791 kind == &expected_kind
12792 }) && self.glob.is_match(path)
12793 }
12794}
12795
12796#[derive(Default)]
12797struct LanguageServerWatchedPaths {
12798 worktree_paths: HashMap<WorktreeId, GlobSet>,
12799 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12800}
12801
12802#[derive(Default)]
12803struct LanguageServerWatchedPathsBuilder {
12804 worktree_paths: HashMap<WorktreeId, GlobSet>,
12805 abs_paths: HashMap<Arc<Path>, GlobSet>,
12806}
12807
12808impl LanguageServerWatchedPathsBuilder {
12809 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12810 self.worktree_paths.insert(worktree_id, glob_set);
12811 }
12812 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12813 self.abs_paths.insert(path, glob_set);
12814 }
12815 fn build(
12816 self,
12817 fs: Arc<dyn Fs>,
12818 language_server_id: LanguageServerId,
12819 cx: &mut Context<LspStore>,
12820 ) -> LanguageServerWatchedPaths {
12821 let project = cx.weak_entity();
12822
12823 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12824 let abs_paths = self
12825 .abs_paths
12826 .into_iter()
12827 .map(|(abs_path, globset)| {
12828 let task = cx.spawn({
12829 let abs_path = abs_path.clone();
12830 let fs = fs.clone();
12831
12832 let lsp_store = project.clone();
12833 async move |_, cx| {
12834 maybe!(async move {
12835 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12836 while let Some(update) = push_updates.0.next().await {
12837 let action = lsp_store
12838 .update(cx, |this, _| {
12839 let Some(local) = this.as_local() else {
12840 return ControlFlow::Break(());
12841 };
12842 let Some(watcher) = local
12843 .language_server_watched_paths
12844 .get(&language_server_id)
12845 else {
12846 return ControlFlow::Break(());
12847 };
12848 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12849 "Watched abs path is not registered with a watcher",
12850 );
12851 let matching_entries = update
12852 .into_iter()
12853 .filter(|event| globs.is_match(&event.path))
12854 .collect::<Vec<_>>();
12855 this.lsp_notify_abs_paths_changed(
12856 language_server_id,
12857 matching_entries,
12858 );
12859 ControlFlow::Continue(())
12860 })
12861 .ok()?;
12862
12863 if action.is_break() {
12864 break;
12865 }
12866 }
12867 Some(())
12868 })
12869 .await;
12870 }
12871 });
12872 (abs_path, (globset, task))
12873 })
12874 .collect();
12875 LanguageServerWatchedPaths {
12876 worktree_paths: self.worktree_paths,
12877 abs_paths,
12878 }
12879 }
12880}
12881
12882struct LspBufferSnapshot {
12883 version: i32,
12884 snapshot: TextBufferSnapshot,
12885}
12886
12887/// A prompt requested by LSP server.
12888#[derive(Clone, Debug)]
12889pub struct LanguageServerPromptRequest {
12890 pub level: PromptLevel,
12891 pub message: String,
12892 pub actions: Vec<MessageActionItem>,
12893 pub lsp_name: String,
12894 pub(crate) response_channel: Sender<MessageActionItem>,
12895}
12896
12897impl LanguageServerPromptRequest {
12898 pub async fn respond(self, index: usize) -> Option<()> {
12899 if let Some(response) = self.actions.into_iter().nth(index) {
12900 self.response_channel.send(response).await.ok()
12901 } else {
12902 None
12903 }
12904 }
12905}
12906impl PartialEq for LanguageServerPromptRequest {
12907 fn eq(&self, other: &Self) -> bool {
12908 self.message == other.message && self.actions == other.actions
12909 }
12910}
12911
12912#[derive(Clone, Debug, PartialEq)]
12913pub enum LanguageServerLogType {
12914 Log(MessageType),
12915 Trace { verbose_info: Option<String> },
12916 Rpc { received: bool },
12917}
12918
12919impl LanguageServerLogType {
12920 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12921 match self {
12922 Self::Log(log_type) => {
12923 use proto::log_message::LogLevel;
12924 let level = match *log_type {
12925 MessageType::ERROR => LogLevel::Error,
12926 MessageType::WARNING => LogLevel::Warning,
12927 MessageType::INFO => LogLevel::Info,
12928 MessageType::LOG => LogLevel::Log,
12929 other => {
12930 log::warn!("Unknown lsp log message type: {other:?}");
12931 LogLevel::Log
12932 }
12933 };
12934 proto::language_server_log::LogType::Log(proto::LogMessage {
12935 level: level as i32,
12936 })
12937 }
12938 Self::Trace { verbose_info } => {
12939 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12940 verbose_info: verbose_info.to_owned(),
12941 })
12942 }
12943 Self::Rpc { received } => {
12944 let kind = if *received {
12945 proto::rpc_message::Kind::Received
12946 } else {
12947 proto::rpc_message::Kind::Sent
12948 };
12949 let kind = kind as i32;
12950 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12951 }
12952 }
12953 }
12954
12955 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12956 use proto::log_message::LogLevel;
12957 use proto::rpc_message;
12958 match log_type {
12959 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12960 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12961 LogLevel::Error => MessageType::ERROR,
12962 LogLevel::Warning => MessageType::WARNING,
12963 LogLevel::Info => MessageType::INFO,
12964 LogLevel::Log => MessageType::LOG,
12965 },
12966 ),
12967 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12968 verbose_info: trace_message.verbose_info,
12969 },
12970 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12971 received: match rpc_message::Kind::from_i32(message.kind)
12972 .unwrap_or(rpc_message::Kind::Received)
12973 {
12974 rpc_message::Kind::Received => true,
12975 rpc_message::Kind::Sent => false,
12976 },
12977 },
12978 }
12979 }
12980}
12981
12982pub struct WorkspaceRefreshTask {
12983 refresh_tx: mpsc::Sender<()>,
12984 progress_tx: mpsc::Sender<()>,
12985 #[allow(dead_code)]
12986 task: Task<()>,
12987}
12988
12989pub enum LanguageServerState {
12990 Starting {
12991 startup: Task<Option<Arc<LanguageServer>>>,
12992 /// List of language servers that will be added to the workspace once it's initialization completes.
12993 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12994 },
12995
12996 Running {
12997 adapter: Arc<CachedLspAdapter>,
12998 server: Arc<LanguageServer>,
12999 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13000 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13001 },
13002}
13003
13004impl LanguageServerState {
13005 fn add_workspace_folder(&self, uri: Uri) {
13006 match self {
13007 LanguageServerState::Starting {
13008 pending_workspace_folders,
13009 ..
13010 } => {
13011 pending_workspace_folders.lock().insert(uri);
13012 }
13013 LanguageServerState::Running { server, .. } => {
13014 server.add_workspace_folder(uri);
13015 }
13016 }
13017 }
13018 fn _remove_workspace_folder(&self, uri: Uri) {
13019 match self {
13020 LanguageServerState::Starting {
13021 pending_workspace_folders,
13022 ..
13023 } => {
13024 pending_workspace_folders.lock().remove(&uri);
13025 }
13026 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13027 }
13028 }
13029}
13030
13031impl std::fmt::Debug for LanguageServerState {
13032 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13033 match self {
13034 LanguageServerState::Starting { .. } => {
13035 f.debug_struct("LanguageServerState::Starting").finish()
13036 }
13037 LanguageServerState::Running { .. } => {
13038 f.debug_struct("LanguageServerState::Running").finish()
13039 }
13040 }
13041 }
13042}
13043
13044#[derive(Clone, Debug, Serialize)]
13045pub struct LanguageServerProgress {
13046 pub is_disk_based_diagnostics_progress: bool,
13047 pub is_cancellable: bool,
13048 pub title: Option<String>,
13049 pub message: Option<String>,
13050 pub percentage: Option<usize>,
13051 #[serde(skip_serializing)]
13052 pub last_update_at: Instant,
13053}
13054
13055#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13056pub struct DiagnosticSummary {
13057 pub error_count: usize,
13058 pub warning_count: usize,
13059}
13060
13061impl DiagnosticSummary {
13062 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13063 let mut this = Self {
13064 error_count: 0,
13065 warning_count: 0,
13066 };
13067
13068 for entry in diagnostics {
13069 if entry.diagnostic.is_primary {
13070 match entry.diagnostic.severity {
13071 DiagnosticSeverity::ERROR => this.error_count += 1,
13072 DiagnosticSeverity::WARNING => this.warning_count += 1,
13073 _ => {}
13074 }
13075 }
13076 }
13077
13078 this
13079 }
13080
13081 pub fn is_empty(&self) -> bool {
13082 self.error_count == 0 && self.warning_count == 0
13083 }
13084
13085 pub fn to_proto(
13086 self,
13087 language_server_id: LanguageServerId,
13088 path: &RelPath,
13089 ) -> proto::DiagnosticSummary {
13090 proto::DiagnosticSummary {
13091 path: path.to_proto(),
13092 language_server_id: language_server_id.0 as u64,
13093 error_count: self.error_count as u32,
13094 warning_count: self.warning_count as u32,
13095 }
13096 }
13097}
13098
13099#[derive(Clone, Debug)]
13100pub enum CompletionDocumentation {
13101 /// There is no documentation for this completion.
13102 Undocumented,
13103 /// A single line of documentation.
13104 SingleLine(SharedString),
13105 /// Multiple lines of plain text documentation.
13106 MultiLinePlainText(SharedString),
13107 /// Markdown documentation.
13108 MultiLineMarkdown(SharedString),
13109 /// Both single line and multiple lines of plain text documentation.
13110 SingleLineAndMultiLinePlainText {
13111 single_line: SharedString,
13112 plain_text: Option<SharedString>,
13113 },
13114}
13115
13116impl CompletionDocumentation {
13117 #[cfg(any(test, feature = "test-support"))]
13118 pub fn text(&self) -> SharedString {
13119 match self {
13120 CompletionDocumentation::Undocumented => "".into(),
13121 CompletionDocumentation::SingleLine(s) => s.clone(),
13122 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13123 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13124 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13125 single_line.clone()
13126 }
13127 }
13128 }
13129}
13130
13131impl From<lsp::Documentation> for CompletionDocumentation {
13132 fn from(docs: lsp::Documentation) -> Self {
13133 match docs {
13134 lsp::Documentation::String(text) => {
13135 if text.lines().count() <= 1 {
13136 CompletionDocumentation::SingleLine(text.into())
13137 } else {
13138 CompletionDocumentation::MultiLinePlainText(text.into())
13139 }
13140 }
13141
13142 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13143 lsp::MarkupKind::PlainText => {
13144 if value.lines().count() <= 1 {
13145 CompletionDocumentation::SingleLine(value.into())
13146 } else {
13147 CompletionDocumentation::MultiLinePlainText(value.into())
13148 }
13149 }
13150
13151 lsp::MarkupKind::Markdown => {
13152 CompletionDocumentation::MultiLineMarkdown(value.into())
13153 }
13154 },
13155 }
13156 }
13157}
13158
13159pub enum ResolvedHint {
13160 Resolved(InlayHint),
13161 Resolving(Shared<Task<()>>),
13162}
13163
13164fn glob_literal_prefix(glob: &Path) -> PathBuf {
13165 glob.components()
13166 .take_while(|component| match component {
13167 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13168 _ => true,
13169 })
13170 .collect()
13171}
13172
13173pub struct SshLspAdapter {
13174 name: LanguageServerName,
13175 binary: LanguageServerBinary,
13176 initialization_options: Option<String>,
13177 code_action_kinds: Option<Vec<CodeActionKind>>,
13178}
13179
13180impl SshLspAdapter {
13181 pub fn new(
13182 name: LanguageServerName,
13183 binary: LanguageServerBinary,
13184 initialization_options: Option<String>,
13185 code_action_kinds: Option<String>,
13186 ) -> Self {
13187 Self {
13188 name,
13189 binary,
13190 initialization_options,
13191 code_action_kinds: code_action_kinds
13192 .as_ref()
13193 .and_then(|c| serde_json::from_str(c).ok()),
13194 }
13195 }
13196}
13197
13198impl LspInstaller for SshLspAdapter {
13199 type BinaryVersion = ();
13200 async fn check_if_user_installed(
13201 &self,
13202 _: &dyn LspAdapterDelegate,
13203 _: Option<Toolchain>,
13204 _: &AsyncApp,
13205 ) -> Option<LanguageServerBinary> {
13206 Some(self.binary.clone())
13207 }
13208
13209 async fn cached_server_binary(
13210 &self,
13211 _: PathBuf,
13212 _: &dyn LspAdapterDelegate,
13213 ) -> Option<LanguageServerBinary> {
13214 None
13215 }
13216
13217 async fn fetch_latest_server_version(
13218 &self,
13219 _: &dyn LspAdapterDelegate,
13220 _: bool,
13221 _: &mut AsyncApp,
13222 ) -> Result<()> {
13223 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13224 }
13225
13226 async fn fetch_server_binary(
13227 &self,
13228 _: (),
13229 _: PathBuf,
13230 _: &dyn LspAdapterDelegate,
13231 ) -> Result<LanguageServerBinary> {
13232 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13233 }
13234}
13235
13236#[async_trait(?Send)]
13237impl LspAdapter for SshLspAdapter {
13238 fn name(&self) -> LanguageServerName {
13239 self.name.clone()
13240 }
13241
13242 async fn initialization_options(
13243 self: Arc<Self>,
13244 _: &Arc<dyn LspAdapterDelegate>,
13245 ) -> Result<Option<serde_json::Value>> {
13246 let Some(options) = &self.initialization_options else {
13247 return Ok(None);
13248 };
13249 let result = serde_json::from_str(options)?;
13250 Ok(result)
13251 }
13252
13253 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13254 self.code_action_kinds.clone()
13255 }
13256}
13257
13258pub fn language_server_settings<'a>(
13259 delegate: &'a dyn LspAdapterDelegate,
13260 language: &LanguageServerName,
13261 cx: &'a App,
13262) -> Option<&'a LspSettings> {
13263 language_server_settings_for(
13264 SettingsLocation {
13265 worktree_id: delegate.worktree_id(),
13266 path: RelPath::empty(),
13267 },
13268 language,
13269 cx,
13270 )
13271}
13272
13273pub(crate) fn language_server_settings_for<'a>(
13274 location: SettingsLocation<'a>,
13275 language: &LanguageServerName,
13276 cx: &'a App,
13277) -> Option<&'a LspSettings> {
13278 ProjectSettings::get(Some(location), cx).lsp.get(language)
13279}
13280
13281pub struct LocalLspAdapterDelegate {
13282 lsp_store: WeakEntity<LspStore>,
13283 worktree: worktree::Snapshot,
13284 fs: Arc<dyn Fs>,
13285 http_client: Arc<dyn HttpClient>,
13286 language_registry: Arc<LanguageRegistry>,
13287 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13288}
13289
13290impl LocalLspAdapterDelegate {
13291 pub fn new(
13292 language_registry: Arc<LanguageRegistry>,
13293 environment: &Entity<ProjectEnvironment>,
13294 lsp_store: WeakEntity<LspStore>,
13295 worktree: &Entity<Worktree>,
13296 http_client: Arc<dyn HttpClient>,
13297 fs: Arc<dyn Fs>,
13298 cx: &mut App,
13299 ) -> Arc<Self> {
13300 let load_shell_env_task = environment.update(cx, |env, cx| {
13301 env.get_worktree_environment(worktree.clone(), cx)
13302 });
13303
13304 Arc::new(Self {
13305 lsp_store,
13306 worktree: worktree.read(cx).snapshot(),
13307 fs,
13308 http_client,
13309 language_registry,
13310 load_shell_env_task,
13311 })
13312 }
13313
13314 fn from_local_lsp(
13315 local: &LocalLspStore,
13316 worktree: &Entity<Worktree>,
13317 cx: &mut App,
13318 ) -> Arc<Self> {
13319 Self::new(
13320 local.languages.clone(),
13321 &local.environment,
13322 local.weak.clone(),
13323 worktree,
13324 local.http_client.clone(),
13325 local.fs.clone(),
13326 cx,
13327 )
13328 }
13329}
13330
13331#[async_trait]
13332impl LspAdapterDelegate for LocalLspAdapterDelegate {
13333 fn show_notification(&self, message: &str, cx: &mut App) {
13334 self.lsp_store
13335 .update(cx, |_, cx| {
13336 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13337 })
13338 .ok();
13339 }
13340
13341 fn http_client(&self) -> Arc<dyn HttpClient> {
13342 self.http_client.clone()
13343 }
13344
13345 fn worktree_id(&self) -> WorktreeId {
13346 self.worktree.id()
13347 }
13348
13349 fn worktree_root_path(&self) -> &Path {
13350 self.worktree.abs_path().as_ref()
13351 }
13352
13353 async fn shell_env(&self) -> HashMap<String, String> {
13354 let task = self.load_shell_env_task.clone();
13355 task.await.unwrap_or_default()
13356 }
13357
13358 async fn npm_package_installed_version(
13359 &self,
13360 package_name: &str,
13361 ) -> Result<Option<(PathBuf, String)>> {
13362 let local_package_directory = self.worktree_root_path();
13363 let node_modules_directory = local_package_directory.join("node_modules");
13364
13365 if let Some(version) =
13366 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13367 {
13368 return Ok(Some((node_modules_directory, version)));
13369 }
13370 let Some(npm) = self.which("npm".as_ref()).await else {
13371 log::warn!(
13372 "Failed to find npm executable for {:?}",
13373 local_package_directory
13374 );
13375 return Ok(None);
13376 };
13377
13378 let env = self.shell_env().await;
13379 let output = util::command::new_smol_command(&npm)
13380 .args(["root", "-g"])
13381 .envs(env)
13382 .current_dir(local_package_directory)
13383 .output()
13384 .await?;
13385 let global_node_modules =
13386 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13387
13388 if let Some(version) =
13389 read_package_installed_version(global_node_modules.clone(), package_name).await?
13390 {
13391 return Ok(Some((global_node_modules, version)));
13392 }
13393 return Ok(None);
13394 }
13395
13396 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13397 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13398 if self.fs.is_file(&worktree_abs_path).await {
13399 worktree_abs_path.pop();
13400 }
13401
13402 let env = self.shell_env().await;
13403
13404 let shell_path = env.get("PATH").cloned();
13405
13406 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13407 }
13408
13409 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13410 let mut working_dir = self.worktree_root_path().to_path_buf();
13411 if self.fs.is_file(&working_dir).await {
13412 working_dir.pop();
13413 }
13414 let output = util::command::new_smol_command(&command.path)
13415 .args(command.arguments)
13416 .envs(command.env.clone().unwrap_or_default())
13417 .current_dir(working_dir)
13418 .output()
13419 .await?;
13420
13421 anyhow::ensure!(
13422 output.status.success(),
13423 "{}, stdout: {:?}, stderr: {:?}",
13424 output.status,
13425 String::from_utf8_lossy(&output.stdout),
13426 String::from_utf8_lossy(&output.stderr)
13427 );
13428 Ok(())
13429 }
13430
13431 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13432 self.language_registry
13433 .update_lsp_binary_status(server_name, status);
13434 }
13435
13436 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13437 self.language_registry
13438 .all_lsp_adapters()
13439 .into_iter()
13440 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13441 .collect()
13442 }
13443
13444 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13445 let dir = self.language_registry.language_server_download_dir(name)?;
13446
13447 if !dir.exists() {
13448 smol::fs::create_dir_all(&dir)
13449 .await
13450 .context("failed to create container directory")
13451 .log_err()?;
13452 }
13453
13454 Some(dir)
13455 }
13456
13457 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13458 let entry = self
13459 .worktree
13460 .entry_for_path(path)
13461 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13462 let abs_path = self.worktree.absolutize(&entry.path);
13463 self.fs.load(&abs_path).await
13464 }
13465}
13466
13467async fn populate_labels_for_symbols(
13468 symbols: Vec<CoreSymbol>,
13469 language_registry: &Arc<LanguageRegistry>,
13470 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13471 output: &mut Vec<Symbol>,
13472) {
13473 #[allow(clippy::mutable_key_type)]
13474 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13475
13476 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13477 for symbol in symbols {
13478 let Some(file_name) = symbol.path.file_name() else {
13479 continue;
13480 };
13481 let language = language_registry
13482 .load_language_for_file_path(Path::new(file_name))
13483 .await
13484 .ok()
13485 .or_else(|| {
13486 unknown_paths.insert(file_name.into());
13487 None
13488 });
13489 symbols_by_language
13490 .entry(language)
13491 .or_default()
13492 .push(symbol);
13493 }
13494
13495 for unknown_path in unknown_paths {
13496 log::info!("no language found for symbol in file {unknown_path:?}");
13497 }
13498
13499 let mut label_params = Vec::new();
13500 for (language, mut symbols) in symbols_by_language {
13501 label_params.clear();
13502 label_params.extend(
13503 symbols
13504 .iter_mut()
13505 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13506 );
13507
13508 let mut labels = Vec::new();
13509 if let Some(language) = language {
13510 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13511 language_registry
13512 .lsp_adapters(&language.name())
13513 .first()
13514 .cloned()
13515 });
13516 if let Some(lsp_adapter) = lsp_adapter {
13517 labels = lsp_adapter
13518 .labels_for_symbols(&label_params, &language)
13519 .await
13520 .log_err()
13521 .unwrap_or_default();
13522 }
13523 }
13524
13525 for ((symbol, (name, _)), label) in symbols
13526 .into_iter()
13527 .zip(label_params.drain(..))
13528 .zip(labels.into_iter().chain(iter::repeat(None)))
13529 {
13530 output.push(Symbol {
13531 language_server_name: symbol.language_server_name,
13532 source_worktree_id: symbol.source_worktree_id,
13533 source_language_server_id: symbol.source_language_server_id,
13534 path: symbol.path,
13535 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13536 name,
13537 kind: symbol.kind,
13538 range: symbol.range,
13539 });
13540 }
13541 }
13542}
13543
13544fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13545 match server.capabilities().text_document_sync.as_ref()? {
13546 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13547 // Server wants didSave but didn't specify includeText.
13548 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13549 // Server doesn't want didSave at all.
13550 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13551 // Server provided SaveOptions.
13552 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13553 Some(save_options.include_text.unwrap_or(false))
13554 }
13555 },
13556 // We do not have any save info. Kind affects didChange only.
13557 lsp::TextDocumentSyncCapability::Kind(_) => None,
13558 }
13559}
13560
13561/// Completion items are displayed in a `UniformList`.
13562/// Usually, those items are single-line strings, but in LSP responses,
13563/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13564/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13565/// 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,
13566/// breaking the completions menu presentation.
13567///
13568/// 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.
13569fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13570 let mut new_text = String::with_capacity(label.text.len());
13571 let mut offset_map = vec![0; label.text.len() + 1];
13572 let mut last_char_was_space = false;
13573 let mut new_idx = 0;
13574 let chars = label.text.char_indices().fuse();
13575 let mut newlines_removed = false;
13576
13577 for (idx, c) in chars {
13578 offset_map[idx] = new_idx;
13579
13580 match c {
13581 '\n' if last_char_was_space => {
13582 newlines_removed = true;
13583 }
13584 '\t' | ' ' if last_char_was_space => {}
13585 '\n' if !last_char_was_space => {
13586 new_text.push(' ');
13587 new_idx += 1;
13588 last_char_was_space = true;
13589 newlines_removed = true;
13590 }
13591 ' ' | '\t' => {
13592 new_text.push(' ');
13593 new_idx += 1;
13594 last_char_was_space = true;
13595 }
13596 _ => {
13597 new_text.push(c);
13598 new_idx += c.len_utf8();
13599 last_char_was_space = false;
13600 }
13601 }
13602 }
13603 offset_map[label.text.len()] = new_idx;
13604
13605 // Only modify the label if newlines were removed.
13606 if !newlines_removed {
13607 return;
13608 }
13609
13610 let last_index = new_idx;
13611 let mut run_ranges_errors = Vec::new();
13612 label.runs.retain_mut(|(range, _)| {
13613 match offset_map.get(range.start) {
13614 Some(&start) => range.start = start,
13615 None => {
13616 run_ranges_errors.push(range.clone());
13617 return false;
13618 }
13619 }
13620
13621 match offset_map.get(range.end) {
13622 Some(&end) => range.end = end,
13623 None => {
13624 run_ranges_errors.push(range.clone());
13625 range.end = last_index;
13626 }
13627 }
13628 true
13629 });
13630 if !run_ranges_errors.is_empty() {
13631 log::error!(
13632 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13633 label.text
13634 );
13635 }
13636
13637 let mut wrong_filter_range = None;
13638 if label.filter_range == (0..label.text.len()) {
13639 label.filter_range = 0..new_text.len();
13640 } else {
13641 let mut original_filter_range = Some(label.filter_range.clone());
13642 match offset_map.get(label.filter_range.start) {
13643 Some(&start) => label.filter_range.start = start,
13644 None => {
13645 wrong_filter_range = original_filter_range.take();
13646 label.filter_range.start = last_index;
13647 }
13648 }
13649
13650 match offset_map.get(label.filter_range.end) {
13651 Some(&end) => label.filter_range.end = end,
13652 None => {
13653 wrong_filter_range = original_filter_range.take();
13654 label.filter_range.end = last_index;
13655 }
13656 }
13657 }
13658 if let Some(wrong_filter_range) = wrong_filter_range {
13659 log::error!(
13660 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13661 label.text
13662 );
13663 }
13664
13665 label.text = new_text;
13666}
13667
13668#[cfg(test)]
13669mod tests {
13670 use language::HighlightId;
13671
13672 use super::*;
13673
13674 #[test]
13675 fn test_glob_literal_prefix() {
13676 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13677 assert_eq!(
13678 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13679 Path::new("node_modules")
13680 );
13681 assert_eq!(
13682 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13683 Path::new("foo")
13684 );
13685 assert_eq!(
13686 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13687 Path::new("foo/bar/baz.js")
13688 );
13689
13690 #[cfg(target_os = "windows")]
13691 {
13692 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13693 assert_eq!(
13694 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13695 Path::new("node_modules")
13696 );
13697 assert_eq!(
13698 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13699 Path::new("foo")
13700 );
13701 assert_eq!(
13702 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13703 Path::new("foo/bar/baz.js")
13704 );
13705 }
13706 }
13707
13708 #[test]
13709 fn test_multi_len_chars_normalization() {
13710 let mut label = CodeLabel::new(
13711 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13712 0..6,
13713 vec![(0..6, HighlightId(1))],
13714 );
13715 ensure_uniform_list_compatible_label(&mut label);
13716 assert_eq!(
13717 label,
13718 CodeLabel::new(
13719 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13720 0..6,
13721 vec![(0..6, HighlightId(1))],
13722 )
13723 );
13724 }
13725}