Skip to content

Commit 9dc3a2c

Browse files
committed
chore: share TaskMonitor between prompt and spinner
1 parent 1f870e3 commit 9dc3a2c

File tree

1 file changed

+41
-54
lines changed

1 file changed

+41
-54
lines changed

examples/byop/src/byop.rs

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// BYOP (Bring Your Own Preset) example for promkit.
12
use std::{collections::HashSet, sync::Arc, time::Duration};
23

34
use anyhow::Result;
@@ -18,7 +19,8 @@ use promkit::{
1819
render::{Renderer, SharedRenderer},
1920
PaneFactory,
2021
},
21-
spinner, text_editor,
22+
spinner::{self, State},
23+
text_editor,
2224
},
2325
Prompt, Signal,
2426
};
@@ -27,8 +29,6 @@ use tokio::{
2729
task::JoinHandle,
2830
};
2931

30-
/// BYOP (Bring Your Own Preset) example for promkit.
31-
3232
/// Represents the indices of various components in BYOP.
3333
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
3434
enum Index {
@@ -47,15 +47,30 @@ enum TaskEvent {
4747
/// Task monitor daemon for managing background tasks
4848
struct TaskMonitor {
4949
event_sender: mpsc::UnboundedSender<TaskEvent>,
50-
_monitor_handle: JoinHandle<()>,
51-
_task_handle: Arc<RwLock<Option<JoinHandle<Result<String>>>>>,
50+
monitor_handle: JoinHandle<()>,
51+
task_handle: Arc<RwLock<Option<JoinHandle<Result<String>>>>>,
52+
}
53+
54+
impl spinner::State for TaskMonitor {
55+
async fn is_idle(&self) -> bool {
56+
// Check if the task is currently running
57+
let running = self.task_handle.read().await;
58+
running.is_none() || running.as_ref().map_or(true, |handle| handle.is_finished())
59+
}
60+
}
61+
62+
impl spinner::State for &TaskMonitor {
63+
async fn is_idle(&self) -> bool {
64+
// Delegate to the TaskMonitor
65+
(*self).is_idle().await
66+
}
5267
}
5368

5469
impl TaskMonitor {
55-
fn new(renderer: SharedRenderer<Index>, shared_task_handle: SharedTaskHandle) -> Self {
70+
fn new(renderer: SharedRenderer<Index>) -> Self {
5671
let (event_sender, mut event_receiver) = mpsc::unbounded_channel();
5772
let task_handle = Arc::new(RwLock::new(None));
58-
let task_handle_clone = task_handle.clone();
73+
let task_handle_internal = task_handle.clone();
5974

6075
// Event handling daemon
6176
let monitor_handle = tokio::spawn(async move {
@@ -64,26 +79,16 @@ impl TaskMonitor {
6479
TaskEvent::TaskStarted { handle } => {
6580
// Store the handle for task management
6681
{
67-
let mut handle_guard = task_handle_clone.write().await;
82+
let mut handle_guard = task_handle_internal.write().await;
6883
*handle_guard = Some(handle);
6984
}
70-
// Update shared state to indicate task is running
71-
{
72-
let mut running_guard = shared_task_handle.0.write().await;
73-
*running_guard = true;
74-
}
7585
}
7686
TaskEvent::TaskCompleted { result } => {
7787
// Clear the task handle
7888
{
79-
let mut handle_guard = task_handle_clone.write().await;
89+
let mut handle_guard = task_handle_internal.write().await;
8090
*handle_guard = None;
8191
}
82-
// Update shared state to indicate task is idle
83-
{
84-
let mut running_guard = shared_task_handle.0.write().await;
85-
*running_guard = false;
86-
}
8792

8893
// Update UI based on result
8994
match result {
@@ -128,39 +133,27 @@ impl TaskMonitor {
128133

129134
Self {
130135
event_sender,
131-
_monitor_handle: monitor_handle,
132-
_task_handle: task_handle,
136+
monitor_handle,
137+
task_handle,
133138
}
134139
}
135140

141+
fn abort_all(&self) {
142+
self.monitor_handle.abort();
143+
self.abort_task();
144+
}
145+
136146
fn abort_task(&self) {
137-
if let Some(handle) = self._task_handle.blocking_read().as_ref() {
147+
if let Some(handle) = self.task_handle.blocking_read().as_ref() {
138148
handle.abort();
139149
}
140150
}
141151
}
142152

143-
/// Shared task state for managing task execution status.
144-
#[derive(Clone)]
145-
struct SharedTaskHandle(Arc<RwLock<bool>>);
146-
147-
impl SharedTaskHandle {
148-
fn new() -> Self {
149-
Self(Arc::new(RwLock::new(false)))
150-
}
151-
}
152-
153-
impl spinner::State for SharedTaskHandle {
154-
async fn is_idle(&self) -> bool {
155-
!*self.0.read().await
156-
}
157-
}
158-
159153
/// Bring Your Own Prompt
160154
struct BYOP {
161155
renderer: SharedRenderer<Index>,
162-
shared_task_handle: SharedTaskHandle,
163-
task_monitor: TaskMonitor,
156+
task_monitor: Arc<TaskMonitor>,
164157
readline: text_editor::State,
165158
}
166159

@@ -182,8 +175,8 @@ impl Prompt for BYOP {
182175
fn finalize(&mut self) -> anyhow::Result<Self::Return> {
183176
let ret = self.readline.texteditor.text_without_cursor().to_string();
184177

185-
// Clean up any running task
186-
self.task_monitor.abort_task();
178+
// Abort any running tasks and clear the task monitor
179+
self.task_monitor.abort_all();
187180

188181
// Reset the text editor state for the next prompt.
189182
self.readline.texteditor.erase_all();
@@ -218,20 +211,16 @@ impl BYOP {
218211
.await?,
219212
);
220213

221-
let shared_task_handle = SharedTaskHandle::new();
222-
let task_monitor = TaskMonitor::new(renderer.clone(), shared_task_handle.clone());
223-
224214
Ok(Self {
215+
task_monitor: Arc::new(TaskMonitor::new(renderer.clone())),
225216
renderer,
226-
shared_task_handle,
227-
task_monitor,
228217
readline,
229218
})
230219
}
231220

232221
async fn start_heavy_task(&mut self) -> anyhow::Result<()> {
233222
// Check if task is already running
234-
if *self.shared_task_handle.0.read().await {
223+
if !self.task_monitor.is_idle().await {
235224
return Ok(());
236225
}
237226

@@ -278,7 +267,7 @@ impl BYOP {
278267
kind: KeyEventKind::Press,
279268
state: KeyEventState::NONE,
280269
}) => {
281-
let is_running = *self.shared_task_handle.0.read().await;
270+
let is_running = !self.task_monitor.is_idle().await;
282271
if !is_running {
283272
// Start the heavy task in background
284273
self.start_heavy_task().await?;
@@ -417,14 +406,14 @@ impl BYOP {
417406
}
418407

419408
async fn spawn(&mut self) -> anyhow::Result<()> {
420-
let shared_task_handle = self.shared_task_handle.clone();
421409
let renderer = self.renderer.clone();
410+
let task_monitor = Arc::clone(&self.task_monitor);
422411
let spinner_task = tokio::spawn(async move {
423412
spinner::run(
424413
spinner::frame::DOTS.clone(),
425414
"Executing...",
426415
Duration::from_millis(100),
427-
shared_task_handle.clone(),
416+
task_monitor.as_ref(),
428417
Index::Spinner,
429418
renderer.clone(),
430419
)
@@ -440,7 +429,5 @@ impl BYOP {
440429

441430
#[tokio::main]
442431
async fn main() -> anyhow::Result<()> {
443-
loop {
444-
BYOP::try_default().await?.spawn().await?
445-
}
432+
BYOP::try_default().await?.spawn().await
446433
}

0 commit comments

Comments
 (0)