add untracked files

[?]
Feb 12, 2025, 11:54 AM
EC3TVL4X6VZZVLOKUN63LC73ADPHBHMZO7QMDXGX2ZPURVI4B4XQC

Dependencies

  • [2] 6YZAVBWU Initial commit
  • [3] KLR5FRIB add fs state read/write of repos
  • [4] IQDCHWCP load a pijul repo
  • [5] SWWE2R6M display basic repo stuff
  • [6] WT3GA27P add cursor with selection
  • [7] DVKSPF7R track selected file path together with an index
  • [8] UB2ITZJS refresh changed files on FS changes

Change contents

  • edit in crates/libflowers_client/src/repo.rs at line 1
    [5.7]
    [5.8]
    use std::borrow::Cow;
  • replacement in crates/libflowers_client/src/repo.rs at line 3
    [5.40][5.40:91]()
    use std::{borrow::Cow, ops::Deref, path::PathBuf};
    [5.40]
    [5.91]
    use std::ops::Deref;
    use std::path::PathBuf;
  • edit in crates/libflowers_client/src/repo.rs at line 6
    [5.92]
    [5.92]
    use canonical_path::CanonicalPathBuf;
  • replacement in crates/libflowers_client/src/repo.rs at line 9
    [5.148][5.148:265]()
    use pijul::change::{Author, ChangeHeader, Hunk, Local};
    use pijul::change::{BaseHunk, LocalChange};
    use pijul::Hash;
    [5.148]
    [5.265]
    use pijul::change::{Author, BaseHunk, ChangeHeader, Hunk, Local, LocalChange};
    use pijul::{Hash, MutTxnT, TxnT, TxnTExt};
  • edit in crates/libflowers_client/src/repo.rs at line 17
    [5.425]
    [5.425]
    pub untracked_files: BTreeSet<String>,
  • edit in crates/libflowers_client/src/repo.rs at line 34
    [5.797]
    [5.797]
    let untracked_files = untracked_files(&state);
  • edit in crates/libflowers_client/src/repo.rs at line 38
    [5.870]
    [5.870]
    untracked_files,
  • edit in crates/libflowers_client/src/repo.rs at line 44
    [8.46]
    [8.46]
    // TODO: Optimize by using the notify event info about what file has changed
    state.untracked_files = untracked_files(&state);
  • replacement in crates/libflowers_client/src/repo.rs at line 47
    [8.74][8.74:161]()
    let changed_files = changed_files(&diff);
    state.changed_files = changed_files;
    [8.74]
    [5.899]
    state.changed_files = changed_files(&diff);
  • edit in crates/libflowers_client/src/repo.rs at line 55
    [5.1081][5.1081:1103]()
    use pijul::TxnT;
  • edit in crates/libflowers_client/src/repo.rs at line 64
    [5.1347][5.1347:1393]()
    use pijul::MutTxnT;
    use pijul::TxnT;
  • edit in crates/libflowers_client/src/repo.rs at line 170
    [5.4415]
    [5.4415]
    })
    .collect()
    }
    fn untracked_files(repo: &pijul::Repository) -> BTreeSet<String> {
    let repo_path = CanonicalPathBuf::canonicalize(&repo.path).unwrap();
    let txn = repo.pristine.arc_txn_begin().unwrap();
    let threads = std::thread::available_parallelism().unwrap().get();
    let txn_ = txn.clone();
    repo.working_copy
    .iterate_prefix_rec(
    repo_path.clone(),
    repo_path.clone(),
    false,
    threads,
    move |path, _| {
    use path_slash::PathExt;
    let path_str = path.to_slash_lossy();
    path_str.is_empty() || txn.read().is_tracked(&path_str).unwrap()
    },
    )
    .unwrap()
    .filter_map(move |path| {
    let (path, _) = path.unwrap();
    use path_slash::PathExt;
    let path_str = path.to_slash_lossy();
    if !txn_.read().is_tracked(&path_str).unwrap() {
    Some(path_str.into_owned())
    } else {
    None
    }
  • replacement in crates/libflowers_client/src/cursor.rs at line 8
    [6.158][6.158:171](),[6.171][7.9:47]()
    Channel,
    File { ix: usize, path: String },
    [6.158]
    [6.188]
    UntrackedFile { ix: usize, path: String },
    ChangedFile { ix: usize, path: String },
  • edit in crates/libflowers_client/Cargo.toml at line 18
    [4.554]
    [4.554]
    [dependencies.canonical-path]
    workspace = true
  • edit in crates/libflowers_client/Cargo.toml at line 21
    [4.580]
    [4.580]
    workspace = true
    [dependencies.path-slash]
  • edit in crates/flowers_ui/src/main.rs at line 24
    [4.1181][8.468:514](),[8.514][5.5009:5041](),[5.5009][5.5009:5041](),[5.5041][6.538:581]()
    let repo = repo::load(repo_path.clone());
    // dbg!(repo::diff(&repo));
    let cursor = cursor::State::default();
  • replacement in crates/flowers_ui/src/main.rs at line 46
    [8.1242][8.1242:1308]()
    fs_watch.watch(repo_path, RecursiveMode::Recursive).unwrap();
    [8.1242]
    [8.1308]
    fs_watch
    .watch(&repo_path, RecursiveMode::Recursive)
    .unwrap();
  • edit in crates/flowers_ui/src/main.rs at line 52
    [8.1438]
    [8.1438]
    let repo = repo::load(repo_path);
    // dbg!(repo::diff(&repo));
    let cursor = cursor::State::default();
  • replacement in crates/flowers_ui/src/main.rs at line 58
    [8.1460][8.1460:1482]()
    fs_watch,
    [8.1460]
    [8.1482]
    _fs_watch: fs_watch,
  • replacement in crates/flowers_ui/src/main.rs at line 68
    [4.1363][8.1552:1615]()
    fs_watch: Debouncer<RecommendedWatcher, RecommendedCache>,
    [4.1363]
    [5.5077]
    _fs_watch: Debouncer<RecommendedWatcher, RecommendedCache>,
  • replacement in crates/flowers_ui/src/main.rs at line 86
    [4.1455][7.61:160]()
    let changed_file_path =
    |ix| state.repo.changed_files.iter().nth(ix).unwrap().clone();
    [4.1455]
    [6.738]
    let untracked_file_selection = |ix: usize| -> cursor::Selection {
    let path = state.repo.untracked_files.iter().nth(ix).unwrap().clone();
    cursor::Selection::UntrackedFile { ix, path }
    };
    let changed_file_selection = |ix: usize| -> cursor::Selection {
    let path = state.repo.changed_files.iter().nth(ix).unwrap().clone();
    cursor::Selection::ChangedFile { ix, path }
    };
  • edit in crates/flowers_ui/src/main.rs at line 98
    [8.1714]
    [8.1714]
    // Re-index cursor selection
    if let Some(selection) = state.cursor.selection.as_ref() {
    // Try to find the file with the same name. If not found, remove
    // selection
    state.cursor.selection = match selection {
    cursor::Selection::UntrackedFile { ix: _, path } => state
    .repo
    .untracked_files
    .iter()
    .enumerate()
    .find(|(_ix, file_path)| *file_path == path)
    .map(|(ix, path)| cursor::Selection::UntrackedFile {
    ix,
    path: path.clone(),
    }),
    cursor::Selection::ChangedFile { ix: _, path } => state
    .repo
    .changed_files
    .iter()
    .enumerate()
    .find(|(_ix, file_path)| *file_path == path)
    .map(|(ix, path)| cursor::Selection::ChangedFile {
    ix,
    path: path.clone(),
    }),
    };
    }
  • replacement in crates/flowers_ui/src/main.rs at line 127
    [6.791][6.791:1067]()
    state.cursor.selection =
    Some(match state.cursor.selection.as_ref() {
    Some(cursor::Selection::Channel) => {
    if state.repo.changed_files.is_empty() {
    cursor::Selection::Channel
    [6.791]
    [6.1067]
    state.cursor.selection = match state.cursor.selection.as_ref() {
    Some(cursor::Selection::UntrackedFile { ix, path: _ }) => {
    let new_selection =
    if state.repo.untracked_files.len().saturating_sub(1)
    == *ix
    {
    if state.repo.changed_files.is_empty() {
    let ix = 0;
    untracked_file_selection(ix)
    } else {
    let ix = 0;
    changed_file_selection(ix)
    }
  • replacement in crates/flowers_ui/src/main.rs at line 141
    [6.1100][7.161:328](),[7.328][6.1155:1203](),[6.1155][6.1155:1203](),[6.1203][7.329:400]()
    let ix = 0;
    let path = changed_file_path(ix);
    cursor::Selection::File { ix, path }
    }
    }
    Some(cursor::Selection::File { ix, path: _ }) => {
    [6.1100]
    [6.1262]
    let ix = ix + 1;
    untracked_file_selection(ix)
    };
    Some(new_selection)
    }
    Some(cursor::Selection::ChangedFile { ix, path: _ }) => {
    let new_selection =
  • replacement in crates/flowers_ui/src/main.rs at line 151
    [6.1399][6.1399:1454]()
    cursor::Selection::Channel
    [6.1399]
    [6.1454]
    if state.repo.untracked_files.is_empty() {
    let ix = 0;
    changed_file_selection(ix)
    } else {
    let ix = 0;
    untracked_file_selection(ix)
    }
  • replacement in crates/flowers_ui/src/main.rs at line 160
    [7.446][7.446:573]()
    let path = changed_file_path(ix);
    cursor::Selection::File { ix, path }
    [7.446]
    [6.1547]
    changed_file_selection(ix)
    };
    Some(new_selection)
    }
    None => {
    if state.repo.untracked_files.is_empty() {
    if state.repo.changed_files.is_empty() {
    None
    } else {
    let ix = 0;
    Some(changed_file_selection(ix))
  • edit in crates/flowers_ui/src/main.rs at line 172
    [6.1573]
    [6.1573]
    } else {
    let ix = 0;
    Some(untracked_file_selection(ix))
  • replacement in crates/flowers_ui/src/main.rs at line 176
    [6.1595][6.1595:1670]()
    None => cursor::Selection::Channel,
    })
    [6.1595]
    [6.1670]
    }
    }
  • replacement in crates/flowers_ui/src/main.rs at line 180
    [6.1711][6.1711:1874]()
    state.cursor.selection =
    Some(match state.cursor.selection.as_ref() {
    Some(cursor::Selection::Channel) | None => {
    [6.1711]
    [6.1874]
    state.cursor.selection = match state.cursor.selection.as_ref() {
    Some(cursor::Selection::UntrackedFile { ix, path: _ }) => {
    let new_selection = if 0 == *ix {
  • replacement in crates/flowers_ui/src/main.rs at line 184
    [6.1939][6.1939:1994]()
    cursor::Selection::Channel
    [6.1939]
    [6.1994]
    let ix = state.repo.untracked_files.len() - 1;
    untracked_file_selection(ix)
  • replacement in crates/flowers_ui/src/main.rs at line 188
    [7.647][7.647:774]()
    let path = changed_file_path(ix);
    cursor::Selection::File { ix, path }
    [7.647]
    [6.2178]
    changed_file_selection(ix)
  • replacement in crates/flowers_ui/src/main.rs at line 190
    [6.2204][6.2204:2226](),[6.2226][7.775:846](),[7.846][6.2285:2378](),[6.2285][6.2285:2378]()
    }
    Some(cursor::Selection::File { ix, path: _ }) => {
    if 0 == *ix {
    cursor::Selection::Channel
    [6.2204]
    [6.2378]
    } else {
    let ix = ix - 1;
    untracked_file_selection(ix)
    };
    Some(new_selection)
    }
    Some(cursor::Selection::ChangedFile { ix, path: _ }) => {
    let new_selection = if 0 == *ix {
    if state.repo.untracked_files.is_empty() {
    let ix = state.repo.changed_files.len() - 1;
    changed_file_selection(ix)
  • replacement in crates/flowers_ui/src/main.rs at line 202
    [6.2411][7.847:1020]()
    let ix = *ix - 1;
    let path = changed_file_path(ix);
    cursor::Selection::File { ix, path }
    [6.2411]
    [6.2471]
    let ix = state.repo.untracked_files.len() - 1;
    untracked_file_selection(ix)
    }
    } else {
    let ix = ix - 1;
    changed_file_selection(ix)
    };
    Some(new_selection)
    }
    None => {
    if state.repo.changed_files.is_empty() {
    if state.repo.untracked_files.is_empty() {
    None
    } else {
    let ix = state.repo.untracked_files.len() - 1;
    Some(untracked_file_selection(ix))
  • edit in crates/flowers_ui/src/main.rs at line 219
    [6.2497]
    [6.2497]
    } else {
    let ix = state.repo.changed_files.len() - 1;
    Some(changed_file_selection(ix))
  • replacement in crates/flowers_ui/src/main.rs at line 223
    [6.2519][6.2519:2538]()
    })
    [6.2519]
    [6.2538]
    }
    }
  • edit in crates/flowers_ui/src/main.rs at line 254
    [5.5242][6.3184:3313]()
    let is_channel_selected = matches!(
    state.cursor.selection.as_ref(),
    Some(cursor::Selection::Channel)
    );
  • replacement in crates/flowers_ui/src/main.rs at line 258
    [6.3337][6.3337:3518]()
    button(text(channel))
    .on_press(Message::CursorSelect(cursor::Selection::Channel))
    .style(selectable_button_style(is_channel_selected)),
    [6.3337]
    [6.3518]
    button(text(channel)), /* TODO
    * .on_press(Message) */
  • edit in crates/flowers_ui/src/main.rs at line 263
    [6.3531]
    [6.3531]
    let untracked_files =
    Element::from(column(state.repo.untracked_files.iter().enumerate().map(
    |(ix, path)| {
    let is_selected = matches!(state.cursor.selection.as_ref() ,
    Some(cursor::Selection::UntrackedFile{ix: selected_ix, path:_}) if &ix == selected_ix
    );
    Element::from(
    button(text(path))
    .on_press(Message::CursorSelect(
    cursor::Selection::UntrackedFile{ix, path: path.clone()},
    ))
    .style(selectable_button_style(is_selected)),
    )
    },
    )));
  • replacement in crates/flowers_ui/src/main.rs at line 283
    [6.3737][7.1021:1118]()
    Some(cursor::Selection::File{ix: selected_ix, path:_}) if &ix == selected_ix
    [6.3737]
    [6.3822]
    Some(cursor::Selection::ChangedFile{ix: selected_ix, path:_}) if &ix == selected_ix
  • replacement in crates/flowers_ui/src/main.rs at line 288
    [6.3968][7.1119:1196]()
    cursor::Selection::File{ix, path: path.clone()},
    [6.3968]
    [6.4025]
    cursor::Selection::ChangedFile{ix, path: path.clone()},
  • edit in crates/flowers_ui/src/main.rs at line 305
    [5.5826]
    [5.5826]
    Element::from(horizontal_rule(1)),
    Element::from(text("Untracked:")),
    untracked_files,
  • edit in crates/flowers_ui/src/main.rs at line 309
    [5.5877]
    [5.5877]
    Element::from(text("Changed:")),
  • edit in Cargo.toml at line 23
    [3.5966]
    [4.1644]
    [workspace.dependencies.canonical-path]
    version = "2.0"
  • edit in Cargo.toml at line 38
    [8.1899]
    [4.1760]
    [workspace.dependencies.path-slash]
    version = "0.2"
  • edit in Cargo.lock at line 2163
    [2.45029]
    [4.12318]
    "canonical-path",
  • edit in Cargo.lock at line 2166
    [2.45044]
    [2.45044]
    "path-slash 0.2.1",
  • replacement in Cargo.lock at line 2216
    [4.12790][4.12790:12805]()
    "path-slash",
    [4.12790]
    [4.12805]
    "path-slash 0.1.5",
  • edit in Cargo.lock at line 2902
    [4.14322]
    [2.59467]
    [[package]]
    name = "path-slash"
    version = "0.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"