1
1
use std:: {
2
2
default:: Default ,
3
+ fs,
3
4
path:: { Path , PathBuf } ,
4
5
rc:: Rc ,
5
6
sync:: {
@@ -9,16 +10,18 @@ use std::{
9
10
time:: Duration ,
10
11
} ;
11
12
12
- use globset:: { Glob , GlobSet , GlobSetBuilder } ;
13
+ use filetime:: FileTime ;
14
+ use globset:: { Glob , GlobSet } ;
13
15
use notify:: { RecursiveMode , Watcher } ;
14
16
use time:: UtcOffset ;
15
17
16
18
use crate :: {
17
19
app_config:: { deserialize_config, AppConfigVersion } ,
18
- config:: {
19
- build_globset, load_project_config, ProjectObject , ProjectObjectNode , CONFIG_FILENAMES ,
20
+ config:: { build_globset, load_project_config, ProjectObject , ProjectObjectNode } ,
21
+ jobs:: {
22
+ objdiff:: { start_build, ObjDiffConfig } ,
23
+ Job , JobQueue , JobResult , JobStatus ,
20
24
} ,
21
- jobs:: { objdiff:: start_build, Job , JobQueue , JobResult , JobStatus } ,
22
25
views:: {
23
26
appearance:: { appearance_window, Appearance } ,
24
27
config:: { config_ui, project_window, ConfigViewState , DEFAULT_WATCH_PATTERNS } ,
@@ -51,6 +54,12 @@ pub struct ObjectConfig {
51
54
pub complete : Option < bool > ,
52
55
}
53
56
57
+ #[ derive( Clone , Eq , PartialEq ) ]
58
+ pub struct ProjectConfigInfo {
59
+ pub path : PathBuf ,
60
+ pub timestamp : FileTime ,
61
+ }
62
+
54
63
#[ inline]
55
64
fn bool_true ( ) -> bool { true }
56
65
@@ -77,6 +86,8 @@ pub struct AppConfig {
77
86
pub base_obj_dir : Option < PathBuf > ,
78
87
#[ serde( default ) ]
79
88
pub selected_obj : Option < ObjectConfig > ,
89
+ #[ serde( default = "bool_true" ) ]
90
+ pub build_base : bool ,
80
91
#[ serde( default ) ]
81
92
pub build_target : bool ,
82
93
#[ serde( default = "bool_true" ) ]
@@ -101,7 +112,9 @@ pub struct AppConfig {
101
112
#[ serde( skip) ]
102
113
pub queue_build : bool ,
103
114
#[ serde( skip) ]
104
- pub project_config_loaded : bool ,
115
+ pub queue_reload : bool ,
116
+ #[ serde( skip) ]
117
+ pub project_config_info : Option < ProjectConfigInfo > ,
105
118
}
106
119
107
120
impl Default for AppConfig {
@@ -114,6 +127,7 @@ impl Default for AppConfig {
114
127
target_obj_dir : None ,
115
128
base_obj_dir : None ,
116
129
selected_obj : None ,
130
+ build_base : true ,
117
131
build_target : false ,
118
132
rebuild_on_changes : true ,
119
133
auto_update_check : true ,
@@ -125,7 +139,8 @@ impl Default for AppConfig {
125
139
config_change : false ,
126
140
obj_change : false ,
127
141
queue_build : false ,
128
- project_config_loaded : false ,
142
+ queue_reload : false ,
143
+ project_config_info : None ,
129
144
}
130
145
}
131
146
}
@@ -148,7 +163,7 @@ impl AppConfig {
148
163
self . config_change = true ;
149
164
self . obj_change = true ;
150
165
self . queue_build = false ;
151
- self . project_config_loaded = false ;
166
+ self . project_config_info = None ;
152
167
}
153
168
154
169
pub fn set_target_obj_dir ( & mut self , path : PathBuf ) {
@@ -180,7 +195,6 @@ pub struct App {
180
195
view_state : ViewState ,
181
196
config : AppConfigRef ,
182
197
modified : Arc < AtomicBool > ,
183
- config_modified : Arc < AtomicBool > ,
184
198
watcher : Option < notify:: RecommendedWatcher > ,
185
199
relaunch_path : Rc < Mutex < Option < PathBuf > > > ,
186
200
should_relaunch : bool ,
@@ -286,8 +300,10 @@ impl App {
286
300
} ;
287
301
let config = & mut * config;
288
302
289
- if self . config_modified . swap ( false , Ordering :: Relaxed ) {
290
- config. config_change = true ;
303
+ if let Some ( info) = & config. project_config_info {
304
+ if file_modified ( & info. path , info. timestamp ) {
305
+ config. config_change = true ;
306
+ }
291
307
}
292
308
293
309
if config. config_change {
@@ -305,21 +321,14 @@ impl App {
305
321
drop ( self . watcher . take ( ) ) ;
306
322
307
323
if let Some ( project_dir) = & config. project_dir {
308
- if !config. watch_patterns . is_empty ( ) {
309
- match build_globset ( & config. watch_patterns )
310
- . map_err ( anyhow:: Error :: new)
311
- . and_then ( |globset| {
312
- create_watcher (
313
- self . modified . clone ( ) ,
314
- self . config_modified . clone ( ) ,
315
- project_dir,
316
- globset,
317
- )
324
+ match build_globset ( & config. watch_patterns ) . map_err ( anyhow:: Error :: new) . and_then (
325
+ |globset| {
326
+ create_watcher ( self . modified . clone ( ) , project_dir, globset)
318
327
. map_err ( anyhow:: Error :: new)
319
- } ) {
320
- Ok ( watcher ) => self . watcher = Some ( watcher ) ,
321
- Err ( e ) => log :: error! ( "Failed to create watcher: {e}" ) ,
322
- }
328
+ } ,
329
+ ) {
330
+ Ok ( watcher ) => self . watcher = Some ( watcher) ,
331
+ Err ( e ) => log :: error! ( "Failed to create watcher: {e}" ) ,
323
332
}
324
333
config. watcher_change = false ;
325
334
}
@@ -337,11 +346,32 @@ impl App {
337
346
config. queue_build = true ;
338
347
}
339
348
349
+ if let Some ( result) = & diff_state. build {
350
+ if let Some ( obj) = & result. first_obj {
351
+ if file_modified ( & obj. path , obj. timestamp ) {
352
+ config. queue_reload = true ;
353
+ }
354
+ }
355
+ if let Some ( obj) = & result. second_obj {
356
+ if file_modified ( & obj. path , obj. timestamp ) {
357
+ config. queue_reload = true ;
358
+ }
359
+ }
360
+ }
361
+
340
362
// Don't clear `queue_build` if a build is running. A file may have been modified during
341
363
// the build, so we'll start another build after the current one finishes.
342
364
if config. queue_build && config. selected_obj . is_some ( ) && !jobs. is_running ( Job :: ObjDiff ) {
343
- jobs. push ( start_build ( self . config . clone ( ) ) ) ;
365
+ jobs. push ( start_build ( ObjDiffConfig :: from_config ( config ) ) ) ;
344
366
config. queue_build = false ;
367
+ config. queue_reload = false ;
368
+ } else if config. queue_reload && !jobs. is_running ( Job :: ObjDiff ) {
369
+ let mut diff_config = ObjDiffConfig :: from_config ( config) ;
370
+ // Don't build, just reload the current files
371
+ diff_config. build_base = false ;
372
+ diff_config. build_target = false ;
373
+ jobs. push ( start_build ( diff_config) ) ;
374
+ config. queue_reload = false ;
345
375
}
346
376
}
347
377
}
@@ -486,16 +516,9 @@ impl eframe::App for App {
486
516
487
517
fn create_watcher (
488
518
modified : Arc < AtomicBool > ,
489
- config_modified : Arc < AtomicBool > ,
490
519
project_dir : & Path ,
491
520
patterns : GlobSet ,
492
521
) -> notify:: Result < notify:: RecommendedWatcher > {
493
- let mut config_patterns = GlobSetBuilder :: new ( ) ;
494
- for filename in CONFIG_FILENAMES {
495
- config_patterns. add ( Glob :: new ( filename) . unwrap ( ) ) ;
496
- }
497
- let config_patterns = config_patterns. build ( ) . unwrap ( ) ;
498
-
499
522
let base_dir = project_dir. to_owned ( ) ;
500
523
let mut watcher =
501
524
notify:: recommended_watcher ( move |res : notify:: Result < notify:: Event > | match res {
@@ -510,9 +533,7 @@ fn create_watcher(
510
533
let Ok ( path) = path. strip_prefix ( & base_dir) else {
511
534
continue ;
512
535
} ;
513
- if config_patterns. is_match ( path) {
514
- config_modified. store ( true , Ordering :: Relaxed ) ;
515
- } else if patterns. is_match ( path) {
536
+ if patterns. is_match ( path) {
516
537
modified. store ( true , Ordering :: Relaxed ) ;
517
538
}
518
539
}
@@ -523,3 +544,12 @@ fn create_watcher(
523
544
watcher. watch ( project_dir, RecursiveMode :: Recursive ) ?;
524
545
Ok ( watcher)
525
546
}
547
+
548
+ #[ inline]
549
+ fn file_modified ( path : & Path , last_ts : FileTime ) -> bool {
550
+ if let Ok ( metadata) = fs:: metadata ( path) {
551
+ FileTime :: from_last_modification_time ( & metadata) != last_ts
552
+ } else {
553
+ false
554
+ }
555
+ }
0 commit comments