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