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