refactor file stuff into sub-mod

[?]
May 10, 2025, 7:16 PM
BFN2VHZS7VCBUHQ4S3CQ3LFQV2V4M6VANNAF32XMRFQVWRGYSZ6AC

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] UB2ITZJS refresh changed files on FS changes
  • [8] S2NVIFXR allow to enter record msg
  • [9] YBJRDOTC make all repo actions async
  • [10] KM5PSZ4A watch repo once loaded
  • [11] 2VUX5BTD load identity
  • [12] A5YBC77V record!
  • [13] D7A7MSIH allow to defer or abandon record, add buttons
  • [14] 4WO3ZJM2 show untracked files' contents
  • [15] PTFDJ567 add untracked files encoding
  • [16] AMPZ2BXK show changed files diffs (only Edit atm)
  • [17] V55EAIWQ add src file LRU cache
  • [18] NRCUG4R2 load changed files src when selected
  • [19] Y5ATDI2H convert changed file diffs and load src only if any needs it
  • [20] YBLPPHZN show contents for move, del and undel
  • [21] B4RMW5AE add syntax highlighter to untracked files contents
  • [22] MJDGPSHG WIP contents diff
  • [23] ZVI4AWER woot contents_diff
  • [24] QMAUTRB6 refactor diff
  • [25] TTKR4Q76 use wrapping_add for cache counter
  • [26] OQ6HSAWH show record log
  • [27] NWJD6VM6 mv libflowers libflorescence
  • [28] AHWWRC73 navigate log entries
  • [29] JE44NYHM display log files diffs
  • [30] ONRCENKT rm unnecessary state from repo's internal state
  • [31] 4ELJZGRJ load and store all change diffs at once
  • [32] HC7ROIBC move main diffs state out of cursor
  • [33] FR52XEMW add action for log change file diff
  • [34] CALXOZXA flatten crates dir
  • [35] L6KSEFQI move cursor related stuff into its module
  • [36] Z2CJPWZE focus record message text_editor on spawn
  • [37] KT5UYXGK fix selection after adding file, add changed file diffs
  • [38] EC3TVL4X add untracked files
  • [39] AXSXZQDG fix updating changed file contents, styling
  • [40] BJXUYQ2Y show untracked file contents in read-only text editor
  • [41] NOB64XMR fmt and clippy
  • [42] UMO6U2ZT partition the change files diffs on whether they have content
  • [43] WI2BVQ6J rm client lib crate
  • [44] TEI5NQ3S add log files selection
  • [45] 6SW7UVSH update iced version

Change contents

  • edit in inflorescence/src/main.rs at line 3
    [24.32]
    [16.1219]
    mod file;
  • edit in inflorescence/src/main.rs at line 6
    [21.41]
    [32.18]
    use std::cmp;
  • edit in inflorescence/src/main.rs at line 8
    [32.49][21.73:96](),[21.73][21.73:96]()
    use std::num::NonZero;
  • edit in inflorescence/src/main.rs at line 10
    [21.140][23.53:74]()
    use std::{cmp, mem};
  • edit in inflorescence/src/main.rs at line 15
    [4.1025][21.163:199]()
    use clru::{CLruCache, WeightScale};
  • edit in inflorescence/src/main.rs at line 28
    [9.4810][21.293:322](),[21.322][2.2834:2835](),[7.467][2.2834:2835](),[6.508][2.2834:2835](),[4.1060][2.2834:2835](),[9.4810][2.2834:2835](),[5.4970][2.2834:2835](),[3.5849][2.2834:2835](),[2.2834][2.2834:2835](),[2.2835][17.83:174]()
    use tokio_stream::StreamExt;
    // Invariant: Must be non-zero
    const SRC_FILES_CACHE_CAPACITY: usize = 1024 * 1024 * 1024;
  • edit in inflorescence/src/main.rs at line 71
    [11.677][11.677:678](),[11.678][23.151:412](),[17.333][14.1795:1840](),[23.412][14.1795:1840](),[14.1795][14.1795:1840](),[14.1840][23.413:747](),[17.515][14.2084:2126](),[23.747][14.2084:2126](),[14.2084][14.2084:2126](),[14.2126][17.516:608]()
    let (src_file_load_tx, src_file_load_rx) = watch::channel((
    FileId {
    path: "".to_string(),
    file_kind: FileKind::Untracked,
    },
    0,
    ));
    let src_file_load_rx = WatchStream::from_changes(src_file_load_rx);
    let repo_path_clone = repo_path.clone();
    let src_file_load_task = Task::run(
    src_file_load_rx
    .map(move |(id, cache_counter): (FileId, usize)| {
    (repo_path_clone.clone(), id, cache_counter)
    })
    .then(|(repo_path, id, cache_counter)| async move {
    load_src_file(repo_path, id, cache_counter).await
    }),
    |msg| msg,
    );
    let src_files_cache_capacity =
    NonZero::new(SRC_FILES_CACHE_CAPACITY).unwrap();
  • replacement in inflorescence/src/main.rs at line 72
    [14.2127][23.748:933]()
    let diffs_cache = DiffsCache {
    counter: 0,
    inner: DiffsCacheInner::with_scale(
    src_files_cache_capacity,
    DiffsCacheWeight,
    ),
    };
    [14.2127]
    [23.933]
    let (files, files_task) = file::init(repo_path.clone());
  • replacement in inflorescence/src/main.rs at line 78
    [14.2225][23.935:963]()
    src_file_load_task,
    [14.2225]
    [14.2259]
    files_task.map(Message::File),
  • replacement in inflorescence/src/main.rs at line 90
    [17.754][17.754:784](),[17.784][23.966:991]()
    src_file_load_tx,
    diffs_cache,
    [8.130]
    [32.50]
    files,
  • replacement in inflorescence/src/main.rs at line 106
    [13.58][23.992:1075](),[23.1075][32.92:139](),[32.139][13.58:60](),[23.1075][13.58:60](),[16.1620][13.58:60](),[14.2459][13.58:60](),[13.58][13.58:60](),[17.965][13.60:78](),[13.60][13.60:78](),[13.78][23.1076:1224]()
    src_file_load_tx: watch::Sender<(FileId, usize)>,
    diffs_cache: DiffsCache,
    diffs_state: HashMap<FileId, diff::State>,
    }
    #[derive(Debug)]
    struct DiffsCache {
    /// Used to prevent race-conditions between file loading and clearing cache
    counter: usize,
    inner: DiffsCacheInner,
    [13.58]
    [17.1025]
    files: file::State,
    diffs_state: HashMap<file::Id, diff::State>,
  • edit in inflorescence/src/main.rs at line 110
    [17.1028][23.1225:1323](),[23.1323][17.1072:1073](),[17.1072][17.1072:1073]()
    type DiffsCacheInner =
    CLruCache<FileId, FileDiff, std::hash::RandomState, DiffsCacheWeight>;
  • edit in inflorescence/src/main.rs at line 111
    [23.1341][23.1341:1370](),[23.1370][24.33:57](),[24.57][17.1770:1773](),[23.1403][17.1770:1773](),[17.1770][17.1770:1773](),[17.1773][23.1404:1508](),[23.1508][15.505:507](),[15.505][15.505:507](),[16.1689][17.1791:1792](),[19.259][19.259:276](),[19.276][23.1509:1534](),[19.401][18.134:135](),[23.1534][18.134:135](),[18.134][18.134:135](),[18.135][23.1535:1824](),[23.1824][24.58:114](),[24.114][23.1898:1928](),[23.1898][23.1898:1928](),[23.1928][24.115:156](),[24.156][23.1978:2338](),[23.1978][23.1978:2338](),[23.2338][24.157:330](),[24.330][23.2580:2787](),[23.2580][23.2580:2787](),[20.52][17.2139:2142](),[23.2787][17.2139:2142](),[17.2139][17.2139:2142](),[17.2142][23.2788:2883](),[23.2883][17.2378:2380](),[17.2378][17.2378:2380](),[16.1802][16.1802:1803](),[16.1803][15.508:525](),[15.508][15.508:525]()
    enum FileDiff {
    Loading,
    Loaded(diff::File),
    }
    #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    struct FileId {
    path: String,
    file_kind: FileKind,
    }
    #[derive(Debug)]
    struct DiffsCacheWeight;
    impl WeightScale<FileId, FileDiff> for DiffsCacheWeight {
    fn weight(&self, key: &FileId, value: &FileDiff) -> usize {
    let key_weight = key.path.len();
    let val_weight = match value {
    FileDiff::Loading => 0,
    FileDiff::Loaded(file) => match file {
    diff::File::Decoded(diff::DecodedFile {
    combined:
    diff::Combined {
    sections,
    max_line_num: _,
    },
    diffs_without_contents,
    }) => {
    mem::size_of_val(sections)
    + mem::size_of::<usize>()
    + mem::size_of_val(diffs_without_contents)
    }
    diff::File::Undecodable(diff::UndecodableFile {
    diffs_with_contents,
    diffs_without_contents,
    }) => {
    mem::size_of_val(diffs_with_contents)
    + mem::size_of_val(diffs_without_contents)
    }
    },
    };
    key_weight + val_weight
    }
    }
    #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
    enum FileKind {
    Untracked,
    Changed,
    }
    #[derive(Debug)]
  • edit in inflorescence/src/main.rs at line 118
    [6.668][14.2724:2734]()
    NoOp,
  • replacement in inflorescence/src/main.rs at line 130
    [13.216][17.2381:2401](),[17.2401][23.2919:3033](),[23.3033][15.574:640](),[15.574][15.574:640](),[17.2495][17.2495:2502]()
    LoadedSrcFile {
    /// The cache counter value when the file was requested
    cache_counter: usize,
    id: FileId,
    data: Vec<u8>,
    encoding: Option<pijul::Encoding>,
    },
    [13.216]
    [23.3034]
    File(file::Msg),
  • replacement in inflorescence/src/main.rs at line 132
    [23.3064][23.3064:3084]()
    id: FileId,
    [23.3064]
    [24.331]
    id: file::Id,
  • edit in inflorescence/src/main.rs at line 144
    [9.6718][14.3214:3253]()
    Message::NoOp => Task::none(),
  • replacement in inflorescence/src/main.rs at line 162
    [35.122][35.122:158]()
    &mut state.diffs_cache,
    [35.122]
    [35.158]
    &mut state.files,
  • edit in inflorescence/src/main.rs at line 164
    [35.191][35.191:228]()
    &state.src_file_load_tx,
  • replacement in inflorescence/src/main.rs at line 198
    [14.6371][23.11128:11180](),[23.11180][17.4301:4354](),[17.4301][17.4301:4354]()
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    [14.6371]
    [14.6494]
    &mut state.files,
  • replacement in inflorescence/src/main.rs at line 242
    [18.3535][23.11419:11479](),[23.11479][18.3599:3660](),[18.3599][18.3599:3660]()
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    [18.3535]
    [18.3660]
    &mut state.files,
  • edit in inflorescence/src/main.rs at line 330
    [13.1976][13.1976:1990](),[13.1990][11.1020:1055](),[12.5568][11.1020:1055](),[11.1020][11.1020:1055](),[11.1055][17.4355:4388](),[17.4388][23.11480:11523](),[23.11523][15.705:760](),[15.705][15.705:760](),[15.760][23.11524:11738](),[23.11738][24.570:630](),[24.630][15.1411:1433](),[23.11807][15.1411:1433](),[15.1411][15.1411:1433](),[15.1433][24.631:695](),[24.695][23.11881:11982](),[23.11881][23.11881:11982](),[23.11982][24.696:813](),[24.813][23.12117:12539](),[23.12117][23.12117:12539](),[23.12539][24.814:947](),[24.947][23.12797:13074](),[23.12797][23.12797:13074](),[17.5181][16.1995:2013](),[23.13074][16.1995:2013](),[15.1696][16.1995:2013]()
    }
    Task::none()
    }
    Message::LoadedSrcFile {
    cache_counter,
    id,
    data,
    encoding,
    } => {
    if state.diffs_cache.counter == cache_counter {
    let file_content = match encoding {
    Some(encoding) => {
    let decoded = encoding.decode(&data);
    diff::FileContent::Decoded(decoded)
    }
    None => diff::FileContent::UnknownEncoding,
    };
    match id.file_kind {
    FileKind::Untracked => {
    let file_diff: diff::File =
    diff::init_file(file_content, None);
    diffs_cache_put(
    &mut state.diffs_cache,
    id,
    FileDiff::Loaded(file_diff),
    );
    }
    FileKind::Changed => {
    if let Some(repo) = state.repo.as_ref() {
    let changed_file = repo.changed_files.get(&id.path);
    let file_diff: diff::File =
    diff::init_file(file_content, changed_file);
    diffs_cache_put(
    &mut state.diffs_cache,
    id,
    FileDiff::Loaded(file_diff),
    );
    }
    }
    }
  • edit in inflorescence/src/main.rs at line 331
    [16.2027][23.13075:13076]()
  • replacement in inflorescence/src/main.rs at line 338
    [32.1323][23.13362:13407](),[23.13362][23.13362:13407]()
    FileKind::Untracked,
    [32.1323]
    [23.13407]
    file::Kind::Untracked,
  • replacement in inflorescence/src/main.rs at line 345
    [32.1475][23.13639:13682](),[23.13639][23.13639:13682]()
    FileKind::Changed,
    [32.1475]
    [23.13682]
    file::Kind::Changed,
  • edit in inflorescence/src/main.rs at line 377
    [33.884]
    [9.14755]
    Message::File(msg) => {
    file::update(&mut state.files, state.repo.as_ref(), msg);
    Task::none()
    }
  • replacement in inflorescence/src/main.rs at line 388
    [9.14932][23.13912:13967]()
    diffs_cache_clear(&mut state.diffs_cache);
    [9.14932]
    [10.359]
    file::diffs_cache_clear(&mut state.files.diffs_cache);
  • replacement in inflorescence/src/main.rs at line 431
    [30.2245][23.13968:14023](),[28.9759][23.13968:14023](),[9.15249][23.13968:14023]()
    diffs_cache_clear(&mut state.diffs_cache);
    [30.2245]
    [9.15249]
    file::diffs_cache_clear(&mut state.files.diffs_cache);
  • replacement in inflorescence/src/main.rs at line 439
    [32.1629][17.5310:5363](),[23.14201][17.5310:5363](),[14.7479][17.5310:5363](),[17.5363][23.14202:14254](),[23.14254][17.5419:5472](),[17.5419][17.5419:5472](),[17.5472][23.14255:14292]()
    load_src_file_if_not_cached(
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    FileId {
    [32.1629]
    [23.14292]
    file::load_src_file_if_not_cached(
    &mut state.files,
    file::Id {
  • replacement in inflorescence/src/main.rs at line 443
    [23.14344][23.14344:14408]()
    file_kind: FileKind::Untracked,
    [23.14344]
    [23.14408]
    file_kind: file::Kind::Untracked,
  • replacement in inflorescence/src/main.rs at line 459
    [35.489][23.14830:15057](),[23.14830][23.14830:15057]()
    load_src_file_if_not_cached(
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    FileId {
    [35.489]
    [23.15057]
    file::load_src_file_if_not_cached(
    &mut state.files,
    file::Id {
  • replacement in inflorescence/src/main.rs at line 463
    [23.15117][23.15117:15187]()
    file_kind: FileKind::Changed,
    [23.15117]
    [23.15187]
    file_kind: file::Kind::Changed,
  • edit in inflorescence/src/main.rs at line 613
    [6.3183][14.8143:8146](),[14.8146][23.15369:15474](),[17.5610][14.8227:8257](),[23.15474][14.8227:8257](),[14.8227][14.8227:8257](),[14.8257][23.15475:15500](),[23.15500][14.8284:8337](),[14.8284][14.8284:8337](),[14.8337][15.1697:1756](),[15.1756][17.5611:5644](),[17.5644][23.15501:15517](),[23.15517][14.8405:8423](),[14.8405][14.8405:8423](),[14.8423][15.1757:1779](),[15.1779][23.15518:15545](),[15.1779][14.8423:8474](),[23.15545][14.8423:8474](),[14.8423][14.8423:8474]()
    }
    async fn load_src_file(
    repo_path: PathBuf,
    id: FileId,
    cache_counter: usize,
    ) -> Message {
    let mut path = repo_path;
    path.push(&id.path);
    if let Ok(data) = tokio::fs::read(&path).await {
    let encoding = pijul::change::get_encoding(&data);
    Message::LoadedSrcFile {
    id,
    data,
    encoding,
    cache_counter,
    }
    } else {
    Message::NoOp
    }
  • edit in inflorescence/src/main.rs at line 615
    [2.3224][17.5645:5677](),[17.5677][23.15546:15636](),[23.15636][17.5761:5765](),[17.5761][17.5761:5765](),[17.5765][23.15637:15788](),[23.15788][17.5917:5926](),[17.5917][17.5917:5926](),[17.5926][23.15789:16233](),[23.16233][17.6353:6392](),[17.6353][17.6353:6392](),[17.6392][23.16234:16306](),[23.16306][25.22:73](),[23.16535][29.16921:16924]()
    fn load_src_file_if_not_cached(
    cache: &mut DiffsCache,
    load_tx: &watch::Sender<(FileId, usize)>,
    id: FileId,
    ) {
    if !cache.inner.contains(&id) {
    diffs_cache_put(cache, id.clone(), FileDiff::Loading);
    load_tx.send((id, cache.counter)).unwrap();
    }
    }
    fn diffs_cache_put(cache: &mut DiffsCache, key: FileId, value: FileDiff) {
    if let Err((key, value)) = cache.inner.put_with_weight(key, value) {
    let kv_weight = DiffsCacheWeight.weight(&key, &value);
    info!("Source file cache is too small to hold {}. Resizing cache to to {kv_weight} fit it.", key.path);
    cache.inner.resize(NonZero::new(kv_weight).unwrap());
    let res = cache.inner.put_with_weight(key, value);
    assert!(res.is_ok());
    }
    }
    fn diffs_cache_clear(cache: &mut DiffsCache) {
    cache.inner.clear();
    cache.counter = cache.counter.wrapping_add(1);
    }
  • replacement in inflorescence/src/main.rs at line 709
    [32.1854][23.17095:17129](),[23.17095][23.17095:17129]()
    let id = FileId {
    [32.1854]
    [23.17129]
    let id = file::Id {
  • replacement in inflorescence/src/main.rs at line 711
    [23.17169][23.17169:17221]()
    file_kind: FileKind::Untracked,
    [23.17169]
    [23.17221]
    file_kind: file::Kind::Untracked,
  • replacement in inflorescence/src/main.rs at line 713
    [23.17240][23.17240:17364]()
    let diffs = match state.diffs_cache.inner.peek(&id) {
    Some(FileDiff::Loaded(file)) => {
    [23.17240]
    [32.1855]
    let diffs = match state.files.diffs_cache.inner.peek(&id) {
    Some(file::Diff::Loaded(file)) => {
  • replacement in inflorescence/src/main.rs at line 723
    [23.17682][29.17498:17554]()
    None | Some(FileDiff::Loading) => {
    [23.17682]
    [29.17554]
    None | Some(file::Diff::Loading) => {
  • replacement in inflorescence/src/main.rs at line 736
    [32.2000][23.18071:18105](),[23.18071][23.18071:18105]()
    let id = FileId {
    [32.2000]
    [23.18105]
    let id = file::Id {
  • replacement in inflorescence/src/main.rs at line 738
    [23.18145][23.18145:18195]()
    file_kind: FileKind::Changed,
    [23.18145]
    [23.18195]
    file_kind: file::Kind::Changed,
  • replacement in inflorescence/src/main.rs at line 740
    [23.18214][23.18214:18338]()
    let diffs = match state.diffs_cache.inner.peek(&id) {
    Some(FileDiff::Loaded(file)) => {
    [23.18214]
    [32.2001]
    let diffs = match state.files.diffs_cache.inner.peek(&id) {
    Some(file::Diff::Loaded(file)) => {
  • replacement in inflorescence/src/main.rs at line 750
    [22.4845][29.17813:17869]()
    None | Some(FileDiff::Loading) => {
    [22.4845]
    [29.17869]
    None | Some(file::Diff::Loading) => {
  • file addition: file.rs (----------)
    [34.364]
    //! Provides a way to load files from disk and to cache them.
    use crate::diff;
    use libflorescence::prelude::*;
    use libflorescence::repo;
    use std::mem;
    use std::num::NonZero;
    use std::path::PathBuf;
    use clru::{CLruCache, WeightScale};
    use iced::Task;
    use tokio::sync::watch;
    use tokio_stream::wrappers::WatchStream;
    use tokio_stream::StreamExt;
    // Invariant: Must be non-zero
    const SRC_FILES_CACHE_CAPACITY: usize = 1024 * 1024 * 1024;
    #[derive(Debug)]
    pub struct State {
    pub file_load_tx: watch::Sender<(Id, usize)>,
    pub diffs_cache: DiffsCache,
    }
    #[derive(Debug, Clone)]
    pub enum Msg {
    LoadedSrcFile {
    /// The cache counter value when the file was requested
    cache_counter: usize,
    id: Id,
    data: Vec<u8>,
    encoding: Option<pijul::Encoding>,
    },
    NoOp,
    }
    #[derive(Debug)]
    pub struct DiffsCache {
    /// Used to prevent race-conditions between file loading and clearing cache
    pub counter: usize,
    pub inner: DiffsCacheInner,
    }
    pub type DiffsCacheInner =
    CLruCache<Id, Diff, std::hash::RandomState, DiffsCacheWeight>;
    #[derive(Debug)]
    pub enum Diff {
    Loading,
    Loaded(diff::File),
    }
    #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    pub struct Id {
    pub path: String,
    pub file_kind: Kind,
    }
    #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
    pub enum Kind {
    Untracked,
    Changed,
    }
    #[derive(Debug)]
    pub struct DiffsCacheWeight;
    pub fn init(repo_path: PathBuf) -> (State, Task<Msg>) {
    let (src_file_load_tx, src_file_load_rx) = watch::channel((
    Id {
    path: "".to_string(),
    file_kind: Kind::Untracked,
    },
    0,
    ));
    let src_file_load_rx = WatchStream::from_changes(src_file_load_rx);
    let src_file_load_task = Task::run(
    src_file_load_rx
    .map(move |(id, cache_counter): (Id, usize)| {
    (repo_path.clone(), id, cache_counter)
    })
    .then(|(repo_path, id, cache_counter)| async move {
    load_src_file(repo_path, id, cache_counter).await
    }),
    |msg| msg,
    );
    let src_files_cache_capacity =
    NonZero::new(SRC_FILES_CACHE_CAPACITY).unwrap();
    let diffs_cache = DiffsCache {
    counter: 0,
    inner: DiffsCacheInner::with_scale(
    src_files_cache_capacity,
    DiffsCacheWeight,
    ),
    };
    let state = State {
    file_load_tx: src_file_load_tx,
    diffs_cache,
    };
    (state, src_file_load_task)
    }
    pub fn update(state: &mut State, repo: Option<&repo::State>, msg: Msg) {
    match msg {
    Msg::LoadedSrcFile {
    cache_counter,
    id,
    data,
    encoding,
    } => {
    if state.diffs_cache.counter == cache_counter {
    let file_content = match encoding {
    Some(encoding) => {
    let decoded = encoding.decode(&data);
    diff::FileContent::Decoded(decoded)
    }
    None => diff::FileContent::UnknownEncoding,
    };
    match id.file_kind {
    Kind::Untracked => {
    let file_diff: diff::File =
    diff::init_file(file_content, None);
    diffs_cache_put(
    &mut state.diffs_cache,
    id,
    Diff::Loaded(file_diff),
    );
    }
    Kind::Changed => {
    if let Some(repo) = repo {
    let changed_file = repo.changed_files.get(&id.path);
    let file_diff: diff::File =
    diff::init_file(file_content, changed_file);
    diffs_cache_put(
    &mut state.diffs_cache,
    id,
    Diff::Loaded(file_diff),
    );
    }
    }
    }
    }
    }
    Msg::NoOp => {}
    }
    }
    pub async fn load_src_file(
    repo_path: PathBuf,
    id: Id,
    cache_counter: usize,
    ) -> Msg {
    let mut path = repo_path;
    path.push(&id.path);
    if let Ok(data) = tokio::fs::read(&path).await {
    let encoding = pijul::change::get_encoding(&data);
    Msg::LoadedSrcFile {
    id,
    data,
    encoding,
    cache_counter,
    }
    } else {
    Msg::NoOp
    }
    }
    pub fn load_src_file_if_not_cached(state: &mut State, id: Id) {
    if !state.diffs_cache.inner.contains(&id) {
    diffs_cache_put(&mut state.diffs_cache, id.clone(), Diff::Loading);
    state
    .file_load_tx
    .send((id, state.diffs_cache.counter))
    .unwrap();
    }
    }
    pub fn diffs_cache_clear(cache: &mut DiffsCache) {
    cache.inner.clear();
    cache.counter = cache.counter.wrapping_add(1);
    }
    fn diffs_cache_put(cache: &mut DiffsCache, key: Id, value: Diff) {
    if let Err((key, value)) = cache.inner.put_with_weight(key, value) {
    let kv_weight = DiffsCacheWeight.weight(&key, &value);
    info!("Source file cache is too small to hold {}. Resizing cache to to {kv_weight} fit it.", key.path);
    cache.inner.resize(NonZero::new(kv_weight).unwrap());
    let res = cache.inner.put_with_weight(key, value);
    assert!(res.is_ok());
    }
    }
    impl WeightScale<Id, Diff> for DiffsCacheWeight {
    fn weight(&self, key: &Id, value: &Diff) -> usize {
    let key_weight = key.path.len();
    let val_weight = match value {
    Diff::Loading => 0,
    Diff::Loaded(file) => match file {
    diff::File::Decoded(diff::DecodedFile {
    combined:
    diff::Combined {
    sections,
    max_line_num: _,
    },
    diffs_without_contents,
    }) => {
    mem::size_of_val(sections)
    + mem::size_of::<usize>()
    + mem::size_of_val(diffs_without_contents)
    }
    diff::File::Undecodable(diff::UndecodableFile {
    diffs_with_contents,
    diffs_without_contents,
    }) => {
    mem::size_of_val(diffs_with_contents)
    + mem::size_of_val(diffs_without_contents)
    }
    },
    };
    key_weight + val_weight
    }
    }
  • edit in inflorescence/src/cursor.rs at line 1
    [6.26]
    [31.11927]
    use crate::{diff, file};
    use libflorescence::prelude::*;
    use libflorescence::repo;
  • edit in inflorescence/src/cursor.rs at line 8
    [35.2004][35.2004:2044]()
    use libflorescence::{prelude::*, repo};
  • edit in inflorescence/src/cursor.rs at line 9
    [27.613][26.5870:5871](),[35.2068][26.5870:5871](),[26.5870][26.5870:5871](),[26.5871][35.2069:2147]()
    use crate::{diff, load_src_file_if_not_cached, DiffsCache, FileId, FileKind};
  • replacement in inflorescence/src/cursor.rs at line 75
    [35.2319][35.2319:2353]()
    diffs_cache: &mut DiffsCache,
    [35.2319]
    [35.2353]
    files: &mut file::State,
  • edit in inflorescence/src/cursor.rs at line 77
    [35.2385][35.2385:2440]()
    src_file_load_tx: &watch::Sender<(FileId, usize)>,
  • replacement in inflorescence/src/cursor.rs at line 90
    [35.3023][35.3023:3339]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.3023]
    [35.3339]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 99
    [35.3741][35.3741:3942]()
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    [35.3741]
    [35.3942]
    repo, ix, files,
  • replacement in inflorescence/src/cursor.rs at line 105
    [35.4163][35.4163:4457]()
    let selection = untracked_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.4163]
    [35.4457]
    let selection =
    untracked_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 121
    [35.5213][35.5213:5414]()
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    [35.5213]
    [35.5414]
    repo, ix, files,
  • replacement in inflorescence/src/cursor.rs at line 126
    [35.5604][35.5604:5920]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.5604]
    [35.5920]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 132
    [35.6102][35.6102:6394]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.6102]
    [35.6394]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 188
    [35.8750][35.8750:8983]()
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    [35.8750]
    [35.8983]
    repo, ix, files,
  • replacement in inflorescence/src/cursor.rs at line 194
    [35.9307][35.9307:9524]()
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    [35.9307]
    [35.9524]
    repo, ix, files,
  • replacement in inflorescence/src/cursor.rs at line 211
    [35.10232][35.10232:11599]()
    let (selection, task) =
    if !repo.untracked_files.is_empty() {
    let ix = 0;
    let selection = Some(untracked_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    ));
    (selection, Task::none())
    } else if !repo.changed_files.is_empty() {
    let ix = 0;
    let selection = Some(changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    ));
    (selection, Task::none())
    } else if !repo.log.is_empty() {
    let ix = repo.log.len() - 1;
    let (selection, task) = log_selection(repo, ix);
    (Some(selection), task)
    } else {
    (None, Task::none())
    };
    [35.10232]
    [35.11599]
    let (selection, task) = if !repo
    .untracked_files
    .is_empty()
    {
    let ix = 0;
    let selection =
    Some(untracked_file_selection(repo, ix, files));
    (selection, Task::none())
    } else if !repo.changed_files.is_empty() {
    let ix = 0;
    let selection =
    Some(changed_file_selection(repo, ix, files));
    (selection, Task::none())
    } else if !repo.log.is_empty() {
    let ix = repo.log.len() - 1;
    let (selection, task) = log_selection(repo, ix);
    (Some(selection), task)
    } else {
    (None, Task::none())
    };
  • replacement in inflorescence/src/cursor.rs at line 250
    [35.12414][35.12414:12706]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.12414]
    [35.12706]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 255
    [35.12874][35.12874:13168]()
    let selection = untracked_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.12874]
    [35.13168]
    let selection =
    untracked_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 261
    [35.13334][35.13334:13604]()
    let selection = untracked_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.13334]
    [35.13604]
    let selection =
    untracked_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 271
    [35.14025][35.14025:14319]()
    let selection = untracked_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.14025]
    [35.14319]
    let selection =
    untracked_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 279
    [35.14663][35.14663:14955]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.14663]
    [35.14955]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 285
    [35.15121][35.15121:15389]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.15121]
    [35.15389]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 329
    [35.17312][35.17312:17529]()
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    [35.17312]
    [35.17529]
    repo, ix, files,
  • replacement in inflorescence/src/cursor.rs at line 336
    [35.17926][35.17926:18159]()
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    [35.17926]
    [35.18159]
    repo, ix, files,
  • replacement in inflorescence/src/cursor.rs at line 359
    [35.19282][35.19282:19550]()
    let selection = changed_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.19282]
    [35.19550]
    let selection =
    changed_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 364
    [35.19748][35.19748:20018]()
    let selection = untracked_file_selection(
    repo,
    ix,
    diffs_cache,
    src_file_load_tx,
    );
    [35.19748]
    [35.20018]
    let selection =
    untracked_file_selection(repo, ix, files);
  • replacement in inflorescence/src/cursor.rs at line 446
    [35.23290][35.23290:23451]()
    load_src_file_if_not_cached(
    diffs_cache,
    src_file_load_tx,
    FileId {
    [35.23290]
    [35.23451]
    file::load_src_file_if_not_cached(
    files,
    file::Id {
  • replacement in inflorescence/src/cursor.rs at line 450
    [35.23499][35.23499:23559]()
    file_kind: FileKind::Untracked,
    [35.23499]
    [35.23559]
    file_kind: file::Kind::Untracked,
  • replacement in inflorescence/src/cursor.rs at line 461
    [35.23999][35.23999:24192]()
    load_src_file_if_not_cached(
    diffs_cache,
    src_file_load_tx,
    FileId {
    [35.23999]
    [35.24192]
    file::load_src_file_if_not_cached(
    files,
    file::Id {
  • replacement in inflorescence/src/cursor.rs at line 465
    [35.24248][35.24248:24314]()
    file_kind: FileKind::Changed,
    [35.24248]
    [35.24314]
    file_kind: file::Kind::Changed,
  • replacement in inflorescence/src/cursor.rs at line 521
    [35.26304][35.26304:26393]()
    diffs_cache: &mut DiffsCache,
    src_file_load_tx: &watch::Sender<(FileId, usize)>,
    [35.26304]
    [35.26393]
    files: &mut file::State,
  • replacement in inflorescence/src/cursor.rs at line 525
    [35.26480][35.26480:26502]()
    let id = FileId {
    [35.26480]
    [35.26502]
    let id = file::Id {
  • replacement in inflorescence/src/cursor.rs at line 527
    [35.26530][35.26530:26570]()
    file_kind: FileKind::Untracked,
    [35.26530]
    [35.26570]
    file_kind: file::Kind::Untracked,
  • replacement in inflorescence/src/cursor.rs at line 529
    [35.26577][35.26577:26645]()
    load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);
    [35.26577]
    [35.26645]
    file::load_src_file_if_not_cached(files, id);
  • replacement in inflorescence/src/cursor.rs at line 537
    [35.26761][35.26761:26850]()
    diffs_cache: &mut DiffsCache,
    src_file_load_tx: &watch::Sender<(FileId, usize)>,
    [35.26761]
    [35.26850]
    files: &mut file::State,
  • replacement in inflorescence/src/cursor.rs at line 542
    [35.26980][35.26980:27006]()
    let id = FileId {
    [35.26980]
    [35.27006]
    let id = file::Id {
  • replacement in inflorescence/src/cursor.rs at line 544
    [35.27038][35.27038:27080]()
    file_kind: FileKind::Changed,
    [35.27038]
    [35.27080]
    file_kind: file::Kind::Changed,
  • replacement in inflorescence/src/cursor.rs at line 546
    [35.27091][35.27091:27163]()
    load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);
    [35.27091]
    [35.27163]
    file::load_src_file_if_not_cached(files, id);