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