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