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 #143
Resolves #215
This commit is contained in:
2025-08-15 16:24:26 -06:00
parent 813c8aa539
commit 52c138bf06
9 changed files with 119 additions and 28 deletions

View File

@@ -16,8 +16,8 @@ use globset::Glob;
use objdiff_core::{
build::watcher::{Watcher, create_watcher},
config::{
DEFAULT_WATCH_PATTERNS, ProjectConfig, ProjectConfigInfo, ProjectObject, ScratchConfig,
build_globset, default_watch_patterns, path::platform_path_serde_option,
ProjectConfig, ProjectConfigInfo, ProjectObject, ScratchConfig, build_globset,
default_ignore_patterns, default_watch_patterns, path::platform_path_serde_option,
save_project_config,
},
diff::DiffObjConfig,
@@ -219,6 +219,8 @@ pub struct AppConfig {
#[serde(default = "default_watch_patterns")]
pub watch_patterns: Vec<Glob>,
#[serde(default)]
pub ignore_patterns: Vec<Glob>,
#[serde(default)]
pub recent_projects: Vec<String>,
#[serde(default)]
pub diff_obj_config: DiffObjConfig,
@@ -239,7 +241,8 @@ impl Default for AppConfig {
build_target: false,
rebuild_on_changes: true,
auto_update_check: true,
watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(),
watch_patterns: default_watch_patterns(),
ignore_patterns: default_ignore_patterns(),
recent_projects: vec![],
diff_obj_config: Default::default(),
}
@@ -560,11 +563,17 @@ impl App {
if let Some(project_dir) = &state.config.project_dir {
match build_globset(&state.config.watch_patterns)
.map_err(anyhow::Error::new)
.and_then(|globset| {
.and_then(|patterns| {
build_globset(&state.config.ignore_patterns)
.map(|ignore_patterns| (patterns, ignore_patterns))
.map_err(anyhow::Error::new)
})
.and_then(|(patterns, ignore_patterns)| {
create_watcher(
self.modified.clone(),
project_dir.as_ref(),
globset,
patterns,
ignore_patterns,
egui_waker(ctx),
)
.map_err(anyhow::Error::new)

View File

@@ -1,6 +1,6 @@
use anyhow::Result;
use globset::Glob;
use objdiff_core::config::{DEFAULT_WATCH_PATTERNS, try_project_config};
use objdiff_core::config::{default_ignore_patterns, default_watch_patterns, try_project_config};
use typed_path::{Utf8UnixComponent, Utf8UnixPath};
use crate::app::{AppState, ObjectConfig};
@@ -96,8 +96,15 @@ pub fn load_project_config(state: &mut AppState) -> Result<()> {
.map(|s| Glob::new(s))
.collect::<Result<Vec<Glob>, globset::Error>>()?;
} else {
state.config.watch_patterns =
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect();
state.config.watch_patterns = default_watch_patterns();
}
if let Some(ignore_patterns) = &project_config.ignore_patterns {
state.config.ignore_patterns = ignore_patterns
.iter()
.map(|s| Glob::new(s))
.collect::<Result<Vec<Glob>, globset::Error>>()?;
} else {
state.config.ignore_patterns = default_ignore_patterns();
}
state.watcher_change = true;
state.objects = project_config

View File

@@ -10,7 +10,7 @@ use egui::{
};
use globset::Glob;
use objdiff_core::{
config::{DEFAULT_WATCH_PATTERNS, path::check_path_buf},
config::{default_ignore_patterns, default_watch_patterns, path::check_path_buf},
diff::{
CONFIG_GROUPS, ConfigEnum, ConfigEnumVariantInfo, ConfigPropertyId, ConfigPropertyKind,
ConfigPropertyValue,
@@ -41,6 +41,7 @@ pub struct ConfigViewState {
pub build_running: bool,
pub queue_build: bool,
pub watch_pattern_text: String,
pub ignore_pattern_text: String,
pub object_search: String,
pub filter_diffable: bool,
pub filter_incomplete: bool,
@@ -790,20 +791,49 @@ fn split_obj_config_ui(
state.watcher_change = true;
};
state.watcher_change |= patterns_ui(
ui,
"File patterns",
&mut state.config.watch_patterns,
&mut config_state.watch_pattern_text,
appearance,
state.project_config_info.is_some(),
default_watch_patterns,
);
state.watcher_change |= patterns_ui(
ui,
"Ignore patterns",
&mut state.config.ignore_patterns,
&mut config_state.ignore_pattern_text,
appearance,
state.project_config_info.is_some(),
default_ignore_patterns,
);
}
fn patterns_ui(
ui: &mut egui::Ui,
text: &str,
patterns: &mut Vec<Glob>,
pattern_text: &mut String,
appearance: &Appearance,
has_project_config: bool,
on_reset: impl FnOnce() -> Vec<Glob>,
) -> bool {
let mut change = false;
ui.horizontal(|ui| {
ui.label(RichText::new("File patterns").color(appearance.text_color));
ui.label(RichText::new(text).color(appearance.text_color));
if ui
.add_enabled(state.project_config_info.is_none(), egui::Button::new("Reset"))
.add_enabled(!has_project_config, egui::Button::new("Reset"))
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
.clicked()
{
state.config.watch_patterns =
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect();
state.watcher_change = true;
*patterns = on_reset();
change = true;
}
});
let mut remove_at: Option<usize> = None;
for (idx, glob) in state.config.watch_patterns.iter().enumerate() {
for (idx, glob) in patterns.iter().enumerate() {
ui.horizontal(|ui| {
ui.label(
RichText::new(glob.to_string())
@@ -811,7 +841,7 @@ fn split_obj_config_ui(
.family(FontFamily::Monospace),
);
if ui
.add_enabled(state.project_config_info.is_none(), egui::Button::new("-").small())
.add_enabled(!has_project_config, egui::Button::new("-").small())
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
.clicked()
{
@@ -820,26 +850,27 @@ fn split_obj_config_ui(
});
}
if let Some(idx) = remove_at {
state.config.watch_patterns.remove(idx);
state.watcher_change = true;
patterns.remove(idx);
change = true;
}
ui.horizontal(|ui| {
ui.add_enabled(
state.project_config_info.is_none(),
egui::TextEdit::singleline(&mut config_state.watch_pattern_text).desired_width(100.0),
!has_project_config,
egui::TextEdit::singleline(pattern_text).desired_width(100.0),
)
.on_disabled_hover_text(CONFIG_DISABLED_TEXT);
if ui
.add_enabled(state.project_config_info.is_none(), egui::Button::new("+").small())
.add_enabled(!has_project_config, egui::Button::new("+").small())
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
.clicked()
&& let Ok(glob) = Glob::new(&config_state.watch_pattern_text)
&& let Ok(glob) = Glob::new(pattern_text)
{
state.config.watch_patterns.push(glob);
state.watcher_change = true;
config_state.watch_pattern_text.clear();
patterns.push(glob);
change = true;
pattern_text.clear();
}
});
change
}
pub fn arch_config_window(

View File

@@ -142,6 +142,11 @@ impl DiffViewState {
JobResult::ObjDiff(result) => {
self.build = take(result);
// Clear reload flag so that we don't reload the view immediately
if let Ok(mut state) = state.write() {
state.queue_reload = false;
}
// TODO: where should this go?
if let Some(result) = self.post_build_nav.take() {
self.current_view = result.view;