11use std:: {
22 default:: Default ,
3+ fs,
34 path:: { Path , PathBuf } ,
45 rc:: Rc ,
56 sync:: {
@@ -9,16 +10,18 @@ use std::{
910 time:: Duration ,
1011} ;
1112
12- use globset:: { Glob , GlobSet , GlobSetBuilder } ;
13+ use filetime:: FileTime ;
14+ use globset:: { Glob , GlobSet } ;
1315use notify:: { RecursiveMode , Watcher } ;
1416use time:: UtcOffset ;
1517
1618use crate :: {
1719 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 ,
2024 } ,
21- jobs:: { objdiff:: start_build, Job , JobQueue , JobResult , JobStatus } ,
2225 views:: {
2326 appearance:: { appearance_window, Appearance } ,
2427 config:: { config_ui, project_window, ConfigViewState , DEFAULT_WATCH_PATTERNS } ,
@@ -51,6 +54,12 @@ pub struct ObjectConfig {
5154 pub complete : Option < bool > ,
5255}
5356
57+ #[ derive( Clone , Eq , PartialEq ) ]
58+ pub struct ProjectConfigInfo {
59+ pub path : PathBuf ,
60+ pub timestamp : FileTime ,
61+ }
62+
5463#[ inline]
5564fn bool_true ( ) -> bool { true }
5665
@@ -77,6 +86,8 @@ pub struct AppConfig {
7786 pub base_obj_dir : Option < PathBuf > ,
7887 #[ serde( default ) ]
7988 pub selected_obj : Option < ObjectConfig > ,
89+ #[ serde( default = "bool_true" ) ]
90+ pub build_base : bool ,
8091 #[ serde( default ) ]
8192 pub build_target : bool ,
8293 #[ serde( default = "bool_true" ) ]
@@ -101,7 +112,9 @@ pub struct AppConfig {
101112 #[ serde( skip) ]
102113 pub queue_build : bool ,
103114 #[ serde( skip) ]
104- pub project_config_loaded : bool ,
115+ pub queue_reload : bool ,
116+ #[ serde( skip) ]
117+ pub project_config_info : Option < ProjectConfigInfo > ,
105118}
106119
107120impl Default for AppConfig {
@@ -114,6 +127,7 @@ impl Default for AppConfig {
114127 target_obj_dir : None ,
115128 base_obj_dir : None ,
116129 selected_obj : None ,
130+ build_base : true ,
117131 build_target : false ,
118132 rebuild_on_changes : true ,
119133 auto_update_check : true ,
@@ -125,7 +139,8 @@ impl Default for AppConfig {
125139 config_change : false ,
126140 obj_change : false ,
127141 queue_build : false ,
128- project_config_loaded : false ,
142+ queue_reload : false ,
143+ project_config_info : None ,
129144 }
130145 }
131146}
@@ -148,7 +163,7 @@ impl AppConfig {
148163 self . config_change = true ;
149164 self . obj_change = true ;
150165 self . queue_build = false ;
151- self . project_config_loaded = false ;
166+ self . project_config_info = None ;
152167 }
153168
154169 pub fn set_target_obj_dir ( & mut self , path : PathBuf ) {
@@ -180,7 +195,6 @@ pub struct App {
180195 view_state : ViewState ,
181196 config : AppConfigRef ,
182197 modified : Arc < AtomicBool > ,
183- config_modified : Arc < AtomicBool > ,
184198 watcher : Option < notify:: RecommendedWatcher > ,
185199 relaunch_path : Rc < Mutex < Option < PathBuf > > > ,
186200 should_relaunch : bool ,
@@ -286,8 +300,10 @@ impl App {
286300 } ;
287301 let config = & mut * config;
288302
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+ }
291307 }
292308
293309 if config. config_change {
@@ -305,21 +321,14 @@ impl App {
305321 drop ( self . watcher . take ( ) ) ;
306322
307323 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)
318327 . 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}" ) ,
323332 }
324333 config. watcher_change = false ;
325334 }
@@ -337,11 +346,32 @@ impl App {
337346 config. queue_build = true ;
338347 }
339348
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+
340362 // Don't clear `queue_build` if a build is running. A file may have been modified during
341363 // the build, so we'll start another build after the current one finishes.
342364 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 ) ) ) ;
344366 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 ;
345375 }
346376 }
347377}
@@ -486,16 +516,9 @@ impl eframe::App for App {
486516
487517fn create_watcher (
488518 modified : Arc < AtomicBool > ,
489- config_modified : Arc < AtomicBool > ,
490519 project_dir : & Path ,
491520 patterns : GlobSet ,
492521) -> 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-
499522 let base_dir = project_dir. to_owned ( ) ;
500523 let mut watcher =
501524 notify:: recommended_watcher ( move |res : notify:: Result < notify:: Event > | match res {
@@ -510,9 +533,7 @@ fn create_watcher(
510533 let Ok ( path) = path. strip_prefix ( & base_dir) else {
511534 continue ;
512535 } ;
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) {
516537 modified. store ( true , Ordering :: Relaxed ) ;
517538 }
518539 }
@@ -523,3 +544,12 @@ fn create_watcher(
523544 watcher. watch ( project_dir, RecursiveMode :: Recursive ) ?;
524545 Ok ( watcher)
525546}
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