improve file watcher to respect .ignore file

tzemanovic
Feb 7, 2026, 2:50 PM
SEJXDXPWV6XND6XIH5XZ3IK4CZDF3EJKLEXNIKOMPNHO5UKUVY3AC

Dependencies

  • [2] 6YZAVBWU Initial commit
  • [3] WT3GA27P add cursor with selection
  • [4] UB2ITZJS refresh changed files on FS changes
  • [5] A5YBC77V record!
  • [6] AXSXZQDG fix updating changed file contents, styling
  • [7] ZVI4AWER woot contents_diff
  • [8] 23SFYK4Q big view refactor into a new crate
  • [9] WGID4LS4 absolutely slayed testing with iced task
  • [10] ACDXXAX2 refactor main's updates into smaller fns
  • [11] I56UGW7U make record test, fix log update
  • [12] X6AK4QPX finish recording test
  • [13] YYKXNBFL test: add untracked file
  • [14] WAOGSCOJ very nice refactor, wip adding channels logs
  • [15] EJPSD5XO shared allowed actions conditions between update and view
  • [16] AZ5D2LQU allow to set record description
  • [17] PKLUHYE4 allow to copy change hash
  • [18] IN2JREDB add window name on linux
  • [19] YGZ3VCW4 add push
  • [20] XQTT6NDF respect .ignore in file watch
  • [21] YRGDFHAB project dir picker
  • [22] LPSUBGUB add projects picker
  • [23] TMDH7GPV dir picker scrollables handling + confirmation
  • [24] T4UECD3S picking projects key nav and scrollable
  • [25] B4RMW5AE add syntax highlighter to untracked files contents
  • [26] IQDCHWCP load a pijul repo
  • [27] BFN2VHZS refactor file stuff into sub-mod
  • [28] I2AG42PA new cols layout
  • [29] KWTBNTO3 diffs selection and scrolling
  • [30] PTWZYQFR use nav-scrollable for repo status
  • [31] YK3MOJJL chonky refactor, wip other channels logs & diffs
  • [32] S2NVIFXR allow to enter record msg
  • [33] AMPZ2BXK show changed files diffs (only Edit atm)
  • [34] K5YUSV2W auto-scroll to last offset
  • [35] Z2CJPWZE focus record message text_editor on spawn
  • [36] 3SYSJKYL add app icon
  • [37] FU6P5QLG indicate when a file is a dir with appended '/'
  • [38] YBJRDOTC make all repo actions async
  • [*] VCNKFNUF app init test

Change contents

  • replacement in inflorescence/src/test.rs at line 116
    [11.2601][21.3594914:3595033]()
    Msg::ManagingRepo(ManagingRepoMsg::ToRepo(
    repo::MsgIn::RefreshChangedAndUntrackedFiles
    ))
    [11.2601]
    [11.2705]
    Msg::ManagingRepo(ManagingRepoMsg::WatchedFileChange(
    path
    )) if path == &repo_path.join(file_to_record)
  • replacement in inflorescence/src/test.rs at line 226
    [12.484][21.3595351:3595470]()
    Msg::ManagingRepo(ManagingRepoMsg::ToRepo(
    repo::MsgIn::RefreshChangedAndUntrackedFiles
    ))
    [12.484]
    [12.588]
    Msg::ManagingRepo(ManagingRepoMsg::WatchedFileChange(
    path
    )) if path == &repo_path.join(file_to_record)
  • replacement in inflorescence/src/test.rs at line 527
    [13.865][21.3595858:3595977]()
    Msg::ManagingRepo(ManagingRepoMsg::ToRepo(
    repo::MsgIn::RefreshChangedAndUntrackedFiles
    ))
    [13.865]
    [13.969]
    Msg::ManagingRepo(ManagingRepoMsg::WatchedFileChange(
    path
    )) if path == &repo_path.join(file_to_record)
  • replacement in inflorescence/src/main.rs at line 23
    [6.112][5.4438:4510](),[18.634][5.4438:4510](),[9.5322][5.4438:4510](),[8.25516][5.4438:4510](),[3.508][5.4438:4510]()
    use notify_debouncer_full::notify::{RecommendedWatcher, RecursiveMode};
    [18.634]
    [4.250]
    use notify_debouncer_full::notify::{self, RecommendedWatcher, RecursiveMode};
  • replacement in inflorescence/src/main.rs at line 25
    [4.279][20.373:450]()
    new_debouncer, notify, DebounceEventResult, Debouncer, RecommendedCache,
    [4.279]
    [4.348]
    new_debouncer, DebounceEventResult, Debouncer, RecommendedCache,
  • edit in inflorescence/src/main.rs at line 94
    [17.1897]
    [19.5097]
    /// ".ignore" file loaded to memory
    ignore: Gitignore,
  • edit in inflorescence/src/main.rs at line 115
    [17.2135]
    [2.2959]
    WatchedFileChange(PathBuf),
  • replacement in inflorescence/src/main.rs at line 130
    [21.3609881][21.3609881:3609928]()
    let report = report::Container::default();
    [21.3609881]
    [21.3609928]
    let mut report = report::Container::default();
  • replacement in inflorescence/src/main.rs at line 134
    [21.3610025][21.3610025:3610068]()
    init_managing_repo(repo_path);
    [21.3610025]
    [21.3610068]
    init_managing_repo(repo_path, &mut report);
  • edit in inflorescence/src/main.rs at line 212
    [21.3611437]
    [21.3611437]
    report: &mut report::Container,
  • edit in inflorescence/src/main.rs at line 230
    [7.965]
    [21.3611699]
    // Load `.ignore` file
    let (ignore, ignore_err) = Gitignore::new(repo_path.join(".ignore"));
    if let Some(err) = ignore_err {
    let msg = format!("Error loading .ignore file {err:?}");
    error!("{msg}");
    report::show_err(report, msg);
    }
  • edit in inflorescence/src/main.rs at line 249
    [21.3611899]
    [21.3611899]
    ignore,
  • replacement in inflorescence/src/main.rs at line 260
    [21.3612079][21.3612079:3612123](),[21.3612123][22.17443:17510]()
    let (task, new_sub_state) =
    update_picking_repo_dir_from_view(model, msg);
    [21.3612079]
    [21.3612186]
    let (task, new_sub_state) = update_picking_repo_dir_from_view(
    model,
    msg,
    &mut state.model.report,
    );
  • replacement in inflorescence/src/main.rs at line 285
    [22.17626][22.17626:17692]()
    update_picking_project_from_view(model, msg);
    [22.17626]
    [22.17692]
    update_picking_project_from_view(
    model,
    msg,
    &mut state.model.report,
    );
  • edit in inflorescence/src/main.rs at line 389
    [22.20556]
    [22.20556]
    report: &mut report::Container,
  • replacement in inflorescence/src/main.rs at line 411
    [24.3481][24.3481:3543]()
    init_managing_repo(path.clone());
    [24.3481]
    [24.3543]
    init_managing_repo(path.clone(), report);
  • replacement in inflorescence/src/main.rs at line 445
    [22.20861][22.20861:20902]()
    init_managing_repo(dir);
    [22.20861]
    [22.20902]
    init_managing_repo(dir, report);
  • edit in inflorescence/src/main.rs at line 586
    [22.21903]
    [22.21903]
    ManagingRepoMsg::WatchedFileChange(path) => {
    let is_dir = path.metadata().map(|md| md.is_dir()).unwrap_or(false);
    if !state
    .ignore
    .matched_path_or_any_parents(&path, is_dir)
    .is_ignore()
    && let Some(fs_watch) = state.repo_fs_watch.as_mut()
    {
    // Refresh repo
    state
    .repo_tx_in
    .send(repo::MsgIn::RefreshChangedAndUntrackedFiles)
    .unwrap();
    // Start watching it in case it's a new file
    if let Err(err) =
    fs_watch.watch(&path, RecursiveMode::NonRecursive)
    {
    match &err.kind {
    // Ignore path not found as this might be triggered on a
    // watched file that's been removed
    notify::ErrorKind::PathNotFound => {}
    notify::ErrorKind::Generic(_)
    | notify::ErrorKind::Io(_)
    | notify::ErrorKind::WatchNotFound
    | notify::ErrorKind::InvalidConfig(_)
    | notify::ErrorKind::MaxFilesWatch => {
    let msg = format!(
    "Error setting up file watch for path {}: {err:?}",
    path.to_string_lossy()
    );
    error!("{msg}");
    report::show_err(report, msg)
    }
    }
    }
    }
    Task::none()
    }
  • edit in inflorescence/src/main.rs at line 735
    [21.3615377]
    [21.3615377]
    report: &mut report::Container,
  • replacement in inflorescence/src/main.rs at line 758
    [23.12210][23.12210:12251]()
    init_managing_repo(dir);
    [23.12210]
    [23.12251]
    init_managing_repo(dir, report);
  • edit in inflorescence/src/main.rs at line 1845
    [10.8018][20.521:549](),[20.549][21.3624314:3624394](),[21.3624394][20.643:679](),[20.643][20.643:679](),[20.679][22.26557:26622](),[22.26622][20.742:767](),[20.742][20.742:767](),[20.767][21.3624395:3624434](),[21.3624434][20.823:829](),[20.823][20.823:829]()
    // Load `.ignore` file
    let (ignore, ignore_err) = Gitignore::new(model.repo_path.join(".ignore"));
    if let Some(err) = ignore_err {
    let msg = format!("Error loading .ignore file {err:?}");
    error!("{msg}");
    report::show_err(report, msg);
    }
  • replacement in inflorescence/src/main.rs at line 1847
    [10.8068][10.8068:8125]()
    let (fs_watch_tx, fs_watch_rx) = watch::channel(());
    [10.8068]
    [10.8125]
    let (fs_watch_tx, fs_watch_rx) = watch::channel(model.repo_path.clone());
  • edit in inflorescence/src/main.rs at line 1853
    [10.8326][10.8326:8380]()
    // TODO: distinguish ".pijul" changes
  • replacement in inflorescence/src/main.rs at line 1858
    [10.8564][20.830:1490]()
    let is_dir = matches!(
    event.kind,
    notify::EventKind::Create(
    notify::event::CreateKind::Folder,
    ) | notify::EventKind::Remove(
    notify::event::RemoveKind::Folder,
    )
    );
    if event.paths.iter().any(|path| {
    !ignore
    .matched_path_or_any_parents(path, is_dir)
    .is_ignore()
    }) {
    let _ = fs_watch_tx.send(());
    }
    [10.8564]
    [10.8614]
    event.paths.iter().for_each(|path| {
    let _ = fs_watch_tx.send(path.clone());
    })
  • replacement in inflorescence/src/main.rs at line 1869
    [10.8794][10.8794:8807](),[10.8807][21.3624435:3624494](),[16.14517][10.8866:8885](),[14.91804][10.8866:8885](),[21.3624494][10.8866:8885](),[10.8866][10.8866:8885]()
    fs_watch
    .watch(&model.repo_path, RecursiveMode::Recursive)
    .unwrap();
    [10.8794]
    [10.8885]
    for entry in ignore::WalkBuilder::new(&model.repo_path)
    .standard_filters(false) // disable git related stuff
    .ignore(true) // use ".ignore" file
    .build()
    // ignore errors
    .flatten()
    {
    if let Err(err) =
    fs_watch.watch(entry.path(), RecursiveMode::NonRecursive)
    {
    let msg = format!(
    "Error setting up file watch for path {}: {err:?}",
    entry.path().to_string_lossy()
    );
    error!("{msg}");
    report::show_err(report, msg)
    }
    }
  • replacement in inflorescence/src/main.rs at line 1889
    [10.8947][10.8947:8998](),[10.8998][21.3624495:3624573](),[15.26723][10.9103:9111](),[21.3624573][10.9103:9111](),[10.9103][10.9103:9111]()
    let watch_task = Task::run(fs_watch_rx, |()| {
    ManagingRepoMsg::ToRepo(repo::MsgIn::RefreshChangedAndUntrackedFiles)
    });
    [10.8947]
    [10.9111]
    let watch_task = Task::run(fs_watch_rx, ManagingRepoMsg::WatchedFileChange);