1+ /// BYOP (Bring Your Own Preset) example for promkit.
12use std:: { collections:: HashSet , sync:: Arc , time:: Duration } ;
23
34use 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 ) ]
3434enum Index {
@@ -47,15 +47,30 @@ enum TaskEvent {
4747/// Task monitor daemon for managing background tasks
4848struct 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
5469impl 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
160154struct 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]
442431async 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