1use std::time::Duration;
2
3use anyhow::Result;
4
5use dap::client::SessionId;
6use gpui::{
7 Animation, AnimationExt, Entity, EventEmitter, FocusHandle, Focusable, Task, Transformation,
8 percentage,
9};
10use project::debugger::session::Session;
11use ui::{Color, Context, Icon, IconName, IntoElement, ParentElement, Render, Styled, v_flex};
12
13pub(crate) struct StartingState {
14 focus_handle: FocusHandle,
15 pub(super) session_id: SessionId,
16 _notify_parent: Task<()>,
17}
18
19pub(crate) enum StartingEvent {
20 Failed,
21 Finished(Entity<Session>),
22}
23
24impl EventEmitter<StartingEvent> for StartingState {}
25
26impl StartingState {
27 pub(crate) fn new(
28 session_id: SessionId,
29 task: Task<Result<Entity<Session>>>,
30 cx: &mut Context<Self>,
31 ) -> Self {
32 let _notify_parent = cx.spawn(async move |this, cx| {
33 let entity = task.await;
34
35 this.update(cx, |_, cx| {
36 if let Ok(entity) = entity {
37 cx.emit(StartingEvent::Finished(entity))
38 } else {
39 cx.emit(StartingEvent::Failed)
40 }
41 })
42 .ok();
43 });
44 Self {
45 session_id,
46 focus_handle: cx.focus_handle(),
47 _notify_parent,
48 }
49 }
50}
51
52impl Focusable for StartingState {
53 fn focus_handle(&self, _: &ui::App) -> FocusHandle {
54 self.focus_handle.clone()
55 }
56}
57
58impl Render for StartingState {
59 fn render(
60 &mut self,
61 _window: &mut ui::Window,
62 _cx: &mut ui::Context<'_, Self>,
63 ) -> impl ui::IntoElement {
64 v_flex()
65 .size_full()
66 .gap_1()
67 .items_center()
68 .child("Starting a debug adapter")
69 .child(
70 Icon::new(IconName::ArrowCircle)
71 .color(Color::Info)
72 .with_animation(
73 "arrow-circle",
74 Animation::new(Duration::from_secs(2)).repeat(),
75 |icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
76 )
77 .into_any_element(),
78 )
79 }
80}