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