@@ -11,9 +11,12 @@ use crate::{
11
11
} ;
12
12
use anyhow:: Result ;
13
13
use asyncgit:: {
14
+ asyncjob:: AsyncSingleJob ,
15
+ remotes:: AsyncRemoteTagsJob ,
14
16
sync:: { get_tags_with_metadata, TagWithMetadata } ,
15
- CWD ,
17
+ AsyncNotification , CWD ,
16
18
} ;
19
+ use crossbeam_channel:: Sender ;
17
20
use crossterm:: event:: Event ;
18
21
use std:: convert:: TryInto ;
19
22
use tui:: {
@@ -36,6 +39,9 @@ pub struct TagListComponent {
36
39
visible : bool ,
37
40
table_state : std:: cell:: Cell < TableState > ,
38
41
current_height : std:: cell:: Cell < usize > ,
42
+ missing_remote_tags : Option < Vec < String > > ,
43
+ async_remote_tags :
44
+ AsyncSingleJob < AsyncRemoteTagsJob , AsyncNotification > ,
39
45
key_config : SharedKeyConfig ,
40
46
}
41
47
@@ -65,6 +71,8 @@ impl DrawableComponent for TagListComponent {
65
71
} ) ;
66
72
67
73
let constraints = [
74
+ // symbol if tag is not yet on remote and can be pushed
75
+ Constraint :: Length ( 1 ) ,
68
76
// tag name
69
77
Constraint :: Length ( tag_name_width. try_into ( ) ?) ,
70
78
// commit date
@@ -228,6 +236,7 @@ impl Component for TagListComponent {
228
236
impl TagListComponent {
229
237
pub fn new (
230
238
queue : & Queue ,
239
+ sender : & Sender < AsyncNotification > ,
231
240
theme : SharedTheme ,
232
241
key_config : SharedKeyConfig ,
233
242
) -> Self {
@@ -238,6 +247,11 @@ impl TagListComponent {
238
247
visible : false ,
239
248
table_state : std:: cell:: Cell :: new ( TableState :: default ( ) ) ,
240
249
current_height : std:: cell:: Cell :: new ( 0 ) ,
250
+ missing_remote_tags : None ,
251
+ async_remote_tags : AsyncSingleJob :: new (
252
+ sender. clone ( ) ,
253
+ AsyncNotification :: RemoteTags ,
254
+ ) ,
241
255
key_config,
242
256
}
243
257
}
@@ -252,12 +266,33 @@ impl TagListComponent {
252
266
Ok ( ( ) )
253
267
}
254
268
269
+ ///
270
+ pub fn update ( & mut self , event : AsyncNotification ) {
271
+ if event == AsyncNotification :: RemoteTags {
272
+ if let Some ( job) = self . async_remote_tags . take_last ( ) {
273
+ if let Some ( Ok ( missing_remote_tags) ) = job. result ( ) {
274
+ self . missing_remote_tags =
275
+ Some ( missing_remote_tags) ;
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ ///
282
+ pub fn any_work_pending ( & self ) -> bool {
283
+ self . async_remote_tags . is_pending ( )
284
+ }
285
+
255
286
/// fetch list of tags
256
287
pub fn update_tags ( & mut self ) -> Result < ( ) > {
257
288
let tags = get_tags_with_metadata ( CWD ) ?;
258
289
259
290
self . tags = Some ( tags) ;
260
291
292
+ if self . missing_remote_tags . is_none ( ) {
293
+ self . async_remote_tags . spawn ( AsyncRemoteTagsJob :: new ( ) ) ;
294
+ }
295
+
261
296
Ok ( ( ) )
262
297
}
263
298
@@ -305,7 +340,27 @@ impl TagListComponent {
305
340
306
341
///
307
342
fn get_row ( & self , tag : & TagWithMetadata ) -> Row {
343
+ const UPSTREAM_SYMBOL : & str = "\u{2191} " ;
344
+ const EMPTY_SYMBOL : & str = " " ;
345
+
346
+ let is_tag_missing_on_remote = self
347
+ . missing_remote_tags
348
+ . as_ref ( )
349
+ . map_or ( false , |missing_remote_tags| {
350
+ let remote_tag = format ! ( "refs/tags/{}" , tag. name) ;
351
+
352
+ missing_remote_tags. contains ( & remote_tag)
353
+ } ) ;
354
+
355
+ let has_remote_str = if is_tag_missing_on_remote {
356
+ UPSTREAM_SYMBOL
357
+ } else {
358
+ EMPTY_SYMBOL
359
+ } ;
360
+
308
361
let cells: Vec < Cell > = vec ! [
362
+ Cell :: from( has_remote_str)
363
+ . style( self . theme. commit_author( false ) ) ,
309
364
Cell :: from( tag. name. clone( ) )
310
365
. style( self . theme. text( true , false ) ) ,
311
366
Cell :: from( utils:: time_to_string( tag. time, true ) )
0 commit comments