Skip to content

Commit 52c138b

Browse files
committed
Add "ignore_patterns" option to config
This allows explicitly ignoring changes to certain files or directories, even if the changed file ends up matching `watch_patterns`. The default value, `build/**/*` will ensure that changes in the build directory will not trigger a duplicate rebuild. Resolves encounter#143 Resolves encounter#215
1 parent 813c8aa commit 52c138b

File tree

9 files changed

+119
-28
lines changed

9 files changed

+119
-28
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ file as well. You can then add `objdiff.json` to your `.gitignore` to prevent it
106106
"*.txt",
107107
"*.json"
108108
],
109+
"ignore_patterns": [
110+
"build/**/*"
111+
],
109112
"units": [
110113
{
111114
"name": "main/MetroTRK/mslsupp",
@@ -141,6 +144,10 @@ It's unlikely you'll want to disable this, unless you're using an external tool
141144
If any of these files change, objdiff will automatically rebuild the objects and re-compare them.
142145
If not specified, objdiff will use the default patterns listed above.
143146

147+
`ignore_patterns` _(optional)_: A list of glob patterns to explicitly ignore when watching for changes.
148+
([Supported syntax](https://docs.rs/globset/latest/globset/#syntax))
149+
If not specified, objdiff will use the default patterns listed above.
150+
144151
`units` _(optional)_: If specified, objdiff will display a list of objects in the sidebar for easy navigation.
145152

146153
> `name` _(optional)_: The name of the object in the UI. If not specified, the object's `path` will be used.

config.schema.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@
7474
"*.json"
7575
]
7676
},
77+
"ignore_patterns": {
78+
"type": "array",
79+
"description": "List of glob patterns to explicitly ignore when watching for changes.\nFiles matching these patterns will not trigger a rebuild.\nSupported syntax: https://docs.rs/globset/latest/globset/#syntax",
80+
"items": {
81+
"type": "string"
82+
},
83+
"default": [
84+
"build/**/*"
85+
]
86+
},
7787
"objects": {
7888
"type": "array",
7989
"description": "Use units instead.",

objdiff-cli/src/cmd/diff.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,12 @@ fn run_interactive(
342342
};
343343
if let (Some(project_dir), Some(project_config)) = (&state.project_dir, &state.project_config) {
344344
let watch_patterns = project_config.build_watch_patterns()?;
345+
let ignore_patterns = project_config.build_ignore_patterns()?;
345346
state.watcher = Some(create_watcher(
346347
state.modified.clone(),
347348
project_dir.as_ref(),
348349
build_globset(&watch_patterns)?,
350+
build_globset(&ignore_patterns)?,
349351
Waker::from(state.waker.clone()),
350352
)?);
351353
}

objdiff-core/src/build/watcher.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub fn create_watcher(
2929
modified: Arc<AtomicBool>,
3030
project_dir: &Path,
3131
patterns: GlobSet,
32+
ignore_patterns: GlobSet,
3233
waker: Waker,
3334
) -> notify::Result<Watcher> {
3435
let base_dir = fs::canonicalize(project_dir)?;
@@ -54,8 +55,8 @@ pub fn create_watcher(
5455
let Ok(path) = path.strip_prefix(&base_dir_clone) else {
5556
continue;
5657
};
57-
if patterns.is_match(path) {
58-
// log::info!("File modified: {}", path.display());
58+
if patterns.is_match(path) && !ignore_patterns.is_match(path) {
59+
log::info!("File modified: {}", path.display());
5960
any_match = true;
6061
}
6162
}

objdiff-core/src/config/mod.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ pub struct ProjectConfig {
3636
pub build_target: Option<bool>,
3737
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
3838
pub watch_patterns: Option<Vec<String>>,
39+
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
40+
pub ignore_patterns: Option<Vec<String>>,
3941
#[cfg_attr(
4042
feature = "serde",
4143
serde(alias = "objects", skip_serializing_if = "Option::is_none")
@@ -66,7 +68,18 @@ impl ProjectConfig {
6668
.map(|s| Glob::new(s))
6769
.collect::<Result<Vec<Glob>, globset::Error>>()?
6870
} else {
69-
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
71+
default_watch_patterns()
72+
})
73+
}
74+
75+
pub fn build_ignore_patterns(&self) -> Result<Vec<Glob>, globset::Error> {
76+
Ok(if let Some(ignore_patterns) = &self.ignore_patterns {
77+
ignore_patterns
78+
.iter()
79+
.map(|s| Glob::new(s))
80+
.collect::<Result<Vec<Glob>, globset::Error>>()?
81+
} else {
82+
default_ignore_patterns()
7083
})
7184
}
7285
}
@@ -195,10 +208,16 @@ pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
195208
"*.inc", "*.py", "*.yml", "*.txt", "*.json",
196209
];
197210

211+
pub const DEFAULT_IGNORE_PATTERNS: &[&str] = &["build/**/*"];
212+
198213
pub fn default_watch_patterns() -> Vec<Glob> {
199214
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
200215
}
201216

217+
pub fn default_ignore_patterns() -> Vec<Glob> {
218+
DEFAULT_IGNORE_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
219+
}
220+
202221
#[cfg(feature = "std")]
203222
#[derive(Clone, Eq, PartialEq)]
204223
pub struct ProjectConfigInfo {

objdiff-gui/src/app.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use globset::Glob;
1616
use objdiff_core::{
1717
build::watcher::{Watcher, create_watcher},
1818
config::{
19-
DEFAULT_WATCH_PATTERNS, ProjectConfig, ProjectConfigInfo, ProjectObject, ScratchConfig,
20-
build_globset, default_watch_patterns, path::platform_path_serde_option,
19+
ProjectConfig, ProjectConfigInfo, ProjectObject, ScratchConfig, build_globset,
20+
default_ignore_patterns, default_watch_patterns, path::platform_path_serde_option,
2121
save_project_config,
2222
},
2323
diff::DiffObjConfig,
@@ -219,6 +219,8 @@ pub struct AppConfig {
219219
#[serde(default = "default_watch_patterns")]
220220
pub watch_patterns: Vec<Glob>,
221221
#[serde(default)]
222+
pub ignore_patterns: Vec<Glob>,
223+
#[serde(default)]
222224
pub recent_projects: Vec<String>,
223225
#[serde(default)]
224226
pub diff_obj_config: DiffObjConfig,
@@ -239,7 +241,8 @@ impl Default for AppConfig {
239241
build_target: false,
240242
rebuild_on_changes: true,
241243
auto_update_check: true,
242-
watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(),
244+
watch_patterns: default_watch_patterns(),
245+
ignore_patterns: default_ignore_patterns(),
243246
recent_projects: vec![],
244247
diff_obj_config: Default::default(),
245248
}
@@ -560,11 +563,17 @@ impl App {
560563
if let Some(project_dir) = &state.config.project_dir {
561564
match build_globset(&state.config.watch_patterns)
562565
.map_err(anyhow::Error::new)
563-
.and_then(|globset| {
566+
.and_then(|patterns| {
567+
build_globset(&state.config.ignore_patterns)
568+
.map(|ignore_patterns| (patterns, ignore_patterns))
569+
.map_err(anyhow::Error::new)
570+
})
571+
.and_then(|(patterns, ignore_patterns)| {
564572
create_watcher(
565573
self.modified.clone(),
566574
project_dir.as_ref(),
567-
globset,
575+
patterns,
576+
ignore_patterns,
568577
egui_waker(ctx),
569578
)
570579
.map_err(anyhow::Error::new)

objdiff-gui/src/config.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::Result;
22
use globset::Glob;
3-
use objdiff_core::config::{DEFAULT_WATCH_PATTERNS, try_project_config};
3+
use objdiff_core::config::{default_ignore_patterns, default_watch_patterns, try_project_config};
44
use typed_path::{Utf8UnixComponent, Utf8UnixPath};
55

66
use crate::app::{AppState, ObjectConfig};
@@ -96,8 +96,15 @@ pub fn load_project_config(state: &mut AppState) -> Result<()> {
9696
.map(|s| Glob::new(s))
9797
.collect::<Result<Vec<Glob>, globset::Error>>()?;
9898
} else {
99-
state.config.watch_patterns =
100-
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect();
99+
state.config.watch_patterns = default_watch_patterns();
100+
}
101+
if let Some(ignore_patterns) = &project_config.ignore_patterns {
102+
state.config.ignore_patterns = ignore_patterns
103+
.iter()
104+
.map(|s| Glob::new(s))
105+
.collect::<Result<Vec<Glob>, globset::Error>>()?;
106+
} else {
107+
state.config.ignore_patterns = default_ignore_patterns();
101108
}
102109
state.watcher_change = true;
103110
state.objects = project_config

objdiff-gui/src/views/config.rs

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use egui::{
1010
};
1111
use globset::Glob;
1212
use objdiff_core::{
13-
config::{DEFAULT_WATCH_PATTERNS, path::check_path_buf},
13+
config::{default_ignore_patterns, default_watch_patterns, path::check_path_buf},
1414
diff::{
1515
CONFIG_GROUPS, ConfigEnum, ConfigEnumVariantInfo, ConfigPropertyId, ConfigPropertyKind,
1616
ConfigPropertyValue,
@@ -41,6 +41,7 @@ pub struct ConfigViewState {
4141
pub build_running: bool,
4242
pub queue_build: bool,
4343
pub watch_pattern_text: String,
44+
pub ignore_pattern_text: String,
4445
pub object_search: String,
4546
pub filter_diffable: bool,
4647
pub filter_incomplete: bool,
@@ -790,28 +791,57 @@ fn split_obj_config_ui(
790791
state.watcher_change = true;
791792
};
792793

794+
state.watcher_change |= patterns_ui(
795+
ui,
796+
"File patterns",
797+
&mut state.config.watch_patterns,
798+
&mut config_state.watch_pattern_text,
799+
appearance,
800+
state.project_config_info.is_some(),
801+
default_watch_patterns,
802+
);
803+
state.watcher_change |= patterns_ui(
804+
ui,
805+
"Ignore patterns",
806+
&mut state.config.ignore_patterns,
807+
&mut config_state.ignore_pattern_text,
808+
appearance,
809+
state.project_config_info.is_some(),
810+
default_ignore_patterns,
811+
);
812+
}
813+
814+
fn patterns_ui(
815+
ui: &mut egui::Ui,
816+
text: &str,
817+
patterns: &mut Vec<Glob>,
818+
pattern_text: &mut String,
819+
appearance: &Appearance,
820+
has_project_config: bool,
821+
on_reset: impl FnOnce() -> Vec<Glob>,
822+
) -> bool {
823+
let mut change = false;
793824
ui.horizontal(|ui| {
794-
ui.label(RichText::new("File patterns").color(appearance.text_color));
825+
ui.label(RichText::new(text).color(appearance.text_color));
795826
if ui
796-
.add_enabled(state.project_config_info.is_none(), egui::Button::new("Reset"))
827+
.add_enabled(!has_project_config, egui::Button::new("Reset"))
797828
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
798829
.clicked()
799830
{
800-
state.config.watch_patterns =
801-
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect();
802-
state.watcher_change = true;
831+
*patterns = on_reset();
832+
change = true;
803833
}
804834
});
805835
let mut remove_at: Option<usize> = None;
806-
for (idx, glob) in state.config.watch_patterns.iter().enumerate() {
836+
for (idx, glob) in patterns.iter().enumerate() {
807837
ui.horizontal(|ui| {
808838
ui.label(
809839
RichText::new(glob.to_string())
810840
.color(appearance.text_color)
811841
.family(FontFamily::Monospace),
812842
);
813843
if ui
814-
.add_enabled(state.project_config_info.is_none(), egui::Button::new("-").small())
844+
.add_enabled(!has_project_config, egui::Button::new("-").small())
815845
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
816846
.clicked()
817847
{
@@ -820,26 +850,27 @@ fn split_obj_config_ui(
820850
});
821851
}
822852
if let Some(idx) = remove_at {
823-
state.config.watch_patterns.remove(idx);
824-
state.watcher_change = true;
853+
patterns.remove(idx);
854+
change = true;
825855
}
826856
ui.horizontal(|ui| {
827857
ui.add_enabled(
828-
state.project_config_info.is_none(),
829-
egui::TextEdit::singleline(&mut config_state.watch_pattern_text).desired_width(100.0),
858+
!has_project_config,
859+
egui::TextEdit::singleline(pattern_text).desired_width(100.0),
830860
)
831861
.on_disabled_hover_text(CONFIG_DISABLED_TEXT);
832862
if ui
833-
.add_enabled(state.project_config_info.is_none(), egui::Button::new("+").small())
863+
.add_enabled(!has_project_config, egui::Button::new("+").small())
834864
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
835865
.clicked()
836-
&& let Ok(glob) = Glob::new(&config_state.watch_pattern_text)
866+
&& let Ok(glob) = Glob::new(pattern_text)
837867
{
838-
state.config.watch_patterns.push(glob);
839-
state.watcher_change = true;
840-
config_state.watch_pattern_text.clear();
868+
patterns.push(glob);
869+
change = true;
870+
pattern_text.clear();
841871
}
842872
});
873+
change
843874
}
844875

845876
pub fn arch_config_window(

objdiff-gui/src/views/symbol_diff.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ impl DiffViewState {
142142
JobResult::ObjDiff(result) => {
143143
self.build = take(result);
144144

145+
// Clear reload flag so that we don't reload the view immediately
146+
if let Ok(mut state) = state.write() {
147+
state.queue_reload = false;
148+
}
149+
145150
// TODO: where should this go?
146151
if let Some(result) = self.post_build_nav.take() {
147152
self.current_view = result.view;

0 commit comments

Comments
 (0)