woot contents_diff

[?]
May 1, 2025, 7:27 AM
ZVI4AWERNOTDJ3765HJXRBZT57XPNKVONQ6TGOGNPOL2VN42KMJQC

Dependencies

  • [2] WT3GA27P add cursor with selection
  • [3] UB2ITZJS refresh changed files on FS changes
  • [4] EC3TVL4X add untracked files
  • [5] KT5UYXGK fix selection after adding file, add changed file diffs
  • [6] ELG3UDT6 allow to rm added files
  • [7] S2NVIFXR allow to enter record msg
  • [8] W7IUT3ZV start recording impl
  • [9] YBJRDOTC make all repo actions async
  • [10] KM5PSZ4A watch repo once loaded
  • [11] 2VUX5BTD load identity
  • [12] D7A7MSIH allow to defer or abandon record, add buttons
  • [13] 4WO3ZJM2 show untracked files' contents
  • [14] BJXUYQ2Y show untracked file contents in read-only text editor
  • [15] W4LFX7IH group diffs by file name
  • [16] PTFDJ567 add untracked files encoding
  • [17] AMPZ2BXK show changed files diffs (only Edit atm)
  • [18] NOB64XMR fmt and clippy
  • [19] AXSXZQDG fix updating changed file contents, styling
  • [20] V55EAIWQ add src file LRU cache
  • [21] NRCUG4R2 load changed files src when selected
  • [22] Y5ATDI2H convert changed file diffs and load src only if any needs it
  • [23] YBLPPHZN show contents for move, del and undel
  • [24] UMO6U2ZT partition the change files diffs on whether they have content
  • [25] B4RMW5AE add syntax highlighter to untracked files contents
  • [26] MJDGPSHG WIP contents diff
  • [27] A5YBC77V record!
  • [28] FDDPOH5R add arrow controls
  • [29] SWWE2R6M display basic repo stuff
  • [30] ZONPDYO7 wrap untracked files' contents on word or glyph
  • [31] IQDCHWCP load a pijul repo
  • [32] UCBNZULE make changed files paths optional (no path for root)
  • [33] 6YZAVBWU Initial commit
  • [34] DVKSPF7R track selected file path together with an index
  • [35] CFYW3HGZ wip: display changed files

Change contents

  • replacement in crates/libflowers_client/src/repo.rs at line 79
    [26.186][26.186:296]()
    diff_line(self)
    .zip(diff_line(other))
    .map(|(left, right)| left.cmp(&right))
    [26.186]
    [26.296]
    Some(self.cmp(other))
  • edit in crates/inflorescence/src/main.rs at line 5
    [25.41][25.41:73]()
    use std::collections::BTreeMap;
  • replacement in crates/inflorescence/src/main.rs at line 8
    [25.140][25.140:161]()
    use std::{cmp, ffi};
    [25.140]
    [25.161]
    use std::{cmp, mem};
  • edit in crates/inflorescence/src/main.rs at line 12
    [11.447][17.1221:1274]()
    use libflowers_client::repo::MAX_LEN_BASE64_DISPLAY;
  • replacement in crates/inflorescence/src/main.rs at line 17
    [19.34][25.200:292]()
    font, highlighter, Border, Color, Element, Font, Length, Subscription,
    Task, Theme,
    [19.34]
    [19.109]
    font, Border, Color, Element, Font, Length, Subscription, Task, Theme,
  • replacement in crates/inflorescence/src/main.rs at line 75
    [11.678][20.176:333]()
    let (src_file_load_tx, src_file_load_rx) = watch::channel("".to_string());
    let untracked_file_load_rx = WatchStream::from_changes(src_file_load_rx);
    [11.678]
    [13.1795]
    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);
  • replacement in crates/inflorescence/src/main.rs at line 84
    [13.1840][13.1840:1917](),[13.1917][20.334:515]()
    let untracked_file_load_task = Task::run(
    untracked_file_load_rx
    .map(move |file_path| (repo_path_clone.clone(), file_path))
    .then(|(repo_path, file_path)| async {
    load_src_file(repo_path, file_path).await
    [13.1840]
    [13.2084]
    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
  • edit in crates/inflorescence/src/main.rs at line 97
    [13.2127]
    [13.2127]
    let diffs_cache = DiffsCache {
    counter: 0,
    inner: DiffsCacheInner::with_scale(
    src_files_cache_capacity,
    DiffsCacheWeight,
    ),
    };
  • replacement in crates/inflorescence/src/main.rs at line 109
    [13.2225][13.2225:2259]()
    untracked_file_load_task,
    [13.2225]
    [13.2259]
    src_file_load_task,
  • edit in crates/inflorescence/src/main.rs at line 111
    [13.2267]
    [3.1438]
  • edit in crates/inflorescence/src/main.rs at line 121
    [7.130][20.609:754]()
    src_files_cache: CLruCache::with_scale(
    src_files_cache_capacity,
    SrcFileCacheWeight,
    ),
  • replacement in crates/inflorescence/src/main.rs at line 122
    [20.784][17.1455:1512](),[13.2347][17.1455:1512]()
    changed_files_contents: BTreeMap::default(),
    [20.784]
    [3.1520]
    diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 137
    [12.58][20.785:866](),[20.866][17.1513:1620](),[13.2459][17.1513:1620]()
    src_files_cache: SrcFilesCache,
    src_file_load_tx: watch::Sender<String>,
    /// Keyed by file name matching `repo::ChangedFiles`
    changed_files_contents: ChangedFilesContents,
    [12.58]
    [12.58]
    src_file_load_tx: watch::Sender<(FileId, usize)>,
    diffs_cache: DiffsCache,
  • edit in crates/inflorescence/src/main.rs at line 140
    [12.60][20.867:965]()
    type SrcFilesCache =
    CLruCache<String, SrcFile, std::hash::RandomState, SrcFileCacheWeight>;
  • replacement in crates/inflorescence/src/main.rs at line 142
    [12.78][20.966:1025]()
    enum SrcFile {
    Loading,
    Loaded(FileEditorContent),
    [12.78]
    [20.1025]
    struct DiffsCache {
    /// Used to prevent race-conditions between file loading and clearing cache
    counter: usize,
    inner: DiffsCacheInner,
  • replacement in crates/inflorescence/src/main.rs at line 148
    [20.1028][20.1028:1072]()
    #[derive(Debug)]
    struct SrcFileCacheWeight;
    [20.1028]
    [20.1072]
    type DiffsCacheInner =
    CLruCache<FileId, FileDiff, std::hash::RandomState, DiffsCacheWeight>;
  • replacement in crates/inflorescence/src/main.rs at line 151
    [20.1073][20.1073:1195](),[20.1195][22.22:58](),[22.58][20.1242:1398](),[20.1242][20.1242:1398](),[20.1398][22.59:208](),[22.208][20.1647:1770](),[20.1647][20.1647:1770]()
    impl WeightScale<String, SrcFile> for SrcFileCacheWeight {
    fn weight(&self, key: &String, value: &SrcFile) -> usize {
    let key_weight = key.len();
    let value_weight = match value {
    SrcFile::Loading => 0,
    SrcFile::Loaded(file_editor_content) => match file_editor_content {
    FileEditorContent::Decoded(content) => content.text().len(),
    FileEditorContent::ShortBase64(string) => string.len(),
    FileEditorContent::UnknownEncoding => 0,
    },
    };
    key_weight + value_weight
    }
    [20.1073]
    [20.1770]
    #[derive(Debug)]
    enum FileDiff {
    Loading,
    Loaded(contents_diff::File),
  • replacement in crates/inflorescence/src/main.rs at line 157
    [20.1773][20.1773:1790](),[13.2723][16.262:322](),[16.322][18.160:297](),[18.297][16.459:505](),[16.459][16.459:505]()
    #[derive(Debug)]
    enum FileEditorContent {
    Decoded(text_editor::Content),
    /// Short byte sequence of unknown encoding encoded with base64 for
    /// display. Must be shorter than [`MAX_LEN_BASE64_DISPLAY`]
    ShortBase64(String),
    UnknownEncoding,
    [20.1773]
    [16.505]
    #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    struct FileId {
    path: String,
    file_kind: FileKind,
  • edit in crates/inflorescence/src/main.rs at line 162
    [16.507][17.1621:1689]()
    type ChangedFilesContents = BTreeMap<String, ChangedFileContents>;
  • replacement in crates/inflorescence/src/main.rs at line 164
    [22.276][24.141:282](),[24.282][22.399:401](),[22.399][22.399:401]()
    struct ChangedFileContents {
    with_contents: Vec<ChangedFileDiffWithContents>,
    without_contents: Vec<ChangedFileDiffWithoutContents>,
    }
    [22.276]
    [21.134]
    struct DiffsCacheWeight;
  • replacement in crates/inflorescence/src/main.rs at line 166
    [21.135][20.1792:1908](),[20.1792][20.1792:1908](),[20.1908][22.402:439](),[22.439][20.1944:2139](),[20.1944][20.1944:2139](),[20.2139][23.22:42]()
    #[derive(Debug)]
    enum ChangedFileDiffWithContents {
    Add,
    Edit {
    line: usize,
    deleted: bool,
    contents: FileEditorContent,
    },
    Replacement {
    line: usize,
    /// Deleted line
    change_contents: FileEditorContent,
    /// Added lines
    replacement_contents: FileEditorContent,
    },
    Del,
    Undel,
    [21.135]
    [20.2139]
    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 {
    contents_diff::File::Decoded(contents_diff::DecodedFile {
    combined:
    contents_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)
    }
    contents_diff::File::Undecodable(
    contents_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
    }
  • replacement in crates/inflorescence/src/main.rs at line 199
    [20.2142][20.2142:2159](),[20.2159][21.136:174](),[21.174][26.1341:1351](),[26.1351][20.2231:2378](),[20.2231][20.2231:2378]()
    #[derive(Debug)]
    enum ChangedFileDiffWithoutContents {
    Move,
    SolveNameConflict,
    UnsolveNameConflict,
    SolveOrderConflict,
    UnsolveOrderConflict,
    ResurrectZombines,
    AddRoot,
    DelRoot,
    [20.2142]
    [20.2378]
    #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
    enum FileKind {
    Untracked,
    Changed,
  • replacement in crates/inflorescence/src/main.rs at line 224
    [2.698][2.698:735]()
    CursorSelect(cursor::Selection),
    [2.698]
    [5.4615]
    CursorSelect(cursor::Select),
  • replacement in crates/inflorescence/src/main.rs at line 233
    [20.2401][16.552:574](),[16.552][16.552:574]()
    path: String,
    [20.2401]
    [16.574]
    /// The cache counter value when the file was requested
    cache_counter: usize,
    id: FileId,
  • edit in crates/inflorescence/src/main.rs at line 238
    [16.640][16.640:647](),[16.647][20.2402:2495]()
    },
    UntrackedFileContentsAction {
    path: String,
    action: text_editor::Action,
  • replacement in crates/inflorescence/src/main.rs at line 239
    [20.2502][17.1804:1914](),[14.122][17.1804:1914]()
    ChangedFileContentsAction {
    file: String,
    ix: usize,
    action: text_editor::Action,
    [20.2502]
    [17.1914]
    FileDiffsContentsAction {
    id: FileId,
    action: contents_diff::Msg,
  • replacement in crates/inflorescence/src/main.rs at line 246
    [9.6312][20.2503:2873]()
    let untracked_file_selection = |repo: &repo::State,
    ix: usize,
    src_files_cache: &mut SrcFilesCache,
    src_file_load_tx: &watch::Sender<
    String,
    >|
    -> cursor::Selection {
    let path = repo.untracked_files.iter().nth(ix).unwrap().clone();
    [9.6312]
    [13.3002]
    let untracked_file_selection =
    |repo: &repo::State,
    ix: usize,
    diffs_cache: &mut DiffsCache,
    src_file_load_tx: &watch::Sender<(FileId, usize)>|
    -> cursor::Selection {
    let path = repo.untracked_files.iter().nth(ix).unwrap().clone();
  • replacement in crates/inflorescence/src/main.rs at line 254
    [20.2899][20.2899:2978]()
    load_src_file_if_not_cached(src_files_cache, src_file_load_tx, &path);
    [13.3003]
    [13.3212]
    let id = FileId {
    path: path.clone(),
    file_kind: FileKind::Untracked,
    };
    load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);
  • replacement in crates/inflorescence/src/main.rs at line 260
    [13.3213][20.2979:3040]()
    cursor::Selection::UntrackedFile { ix, path }
    };
    [13.3213]
    [9.6556]
    cursor::Selection::UntrackedFile {
    ix,
    path,
    diffs: contents_diff::State::default(),
    }
    };
  • replacement in crates/inflorescence/src/main.rs at line 268
    [22.473][22.473:529]()
    |changed_files_contents: &ChangedFilesContents,
    [22.473]
    [22.529]
    |repo: &repo::State,
  • replacement in crates/inflorescence/src/main.rs at line 270
    [22.549][22.549:646]()
    src_files_cache: &mut SrcFilesCache,
    src_file_load_tx: &watch::Sender<String>|
    [22.549]
    [22.646]
    diffs_cache: &mut DiffsCache,
    src_file_load_tx: &watch::Sender<(FileId, usize)>|
  • replacement in crates/inflorescence/src/main.rs at line 273
    [22.678][22.678:758]()
    let (path, diffs) = changed_files_contents.iter().nth(ix).unwrap();
    [22.678]
    [21.615]
    let (path, diffs) = repo.changed_files.iter().nth(ix).unwrap();
  • replacement in crates/inflorescence/src/main.rs at line 276
    [22.805][22.805:970]()
    load_src_file_if_not_cached(
    src_files_cache,
    src_file_load_tx,
    path,
    );
    [22.805]
    [22.970]
    let id = FileId {
    path: path.clone(),
    file_kind: FileKind::Changed,
    };
    load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);
  • edit in crates/inflorescence/src/main.rs at line 286
    [22.1086]
    [22.1086]
    diffs: contents_diff::State::default(),
  • replacement in crates/inflorescence/src/main.rs at line 310
    [9.7096][9.7096:7561]()
    state.cursor.selection = match state.cursor.selection.as_ref() {
    Some(cursor::Selection::UntrackedFile { ix, path: _ }) => {
    let new_selection =
    if repo.untracked_files.len().saturating_sub(1)
    == *ix
    {
    if repo.changed_files.is_empty() {
    let ix = 0;
    [9.7096]
    [13.3254]
    state.cursor.selection =
    match state.cursor.selection.as_ref() {
    Some(cursor::Selection::UntrackedFile {
    ix,
    path: _,
    diffs: _,
    }) => {
    let new_selection =
    if repo.untracked_files.len().saturating_sub(1)
    == *ix
    {
    if repo.changed_files.is_empty() {
    let ix = 0;
    untracked_file_selection(
    repo,
    ix,
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    )
    } else {
    let ix = 0;
    changed_file_selection(
    repo,
    ix,
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    )
    }
    } else {
    let ix = ix + 1;
  • replacement in crates/inflorescence/src/main.rs at line 343
    [13.3406][20.3041:3109]()
    &mut state.src_files_cache,
    [13.3406]
    [20.3109]
    &mut state.diffs_cache,
  • edit in crates/inflorescence/src/main.rs at line 346
    [13.3591]
    [9.7632]
    };
    Some(new_selection)
    }
    Some(cursor::Selection::ChangedFile {
    ix,
    path: _,
    diffs: _,
    }) => {
    let new_selection =
    if repo.changed_files.len().saturating_sub(1)
    == *ix
    {
    if repo.untracked_files.is_empty() {
    let ix = 0;
    changed_file_selection(
    repo,
    ix,
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    )
    } else {
    let ix = 0;
    untracked_file_selection(
    repo,
    ix,
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    )
    }
  • replacement in crates/inflorescence/src/main.rs at line 376
    [9.7673][9.7673:7721]()
    let ix = 0;
    [9.7673]
    [21.757]
    let ix = ix + 1;
  • replacement in crates/inflorescence/src/main.rs at line 378
    [21.817][22.1112:1183]()
    &state.changed_files_contents,
    [21.817]
    [21.863]
    repo,
  • replacement in crates/inflorescence/src/main.rs at line 380
    [21.907][21.907:975]()
    &mut state.src_files_cache,
    [21.907]
    [21.975]
    &mut state.diffs_cache,
  • edit in crates/inflorescence/src/main.rs at line 383
    [21.1078]
    [9.7790]
    };
    Some(new_selection)
    }
    None => {
    if repo.untracked_files.is_empty() {
    if repo.changed_files.is_empty() {
    None
    } else {
    let ix = 0;
    Some(changed_file_selection(
    repo,
    ix,
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    ))
  • edit in crates/inflorescence/src/main.rs at line 400
    [9.7861][9.7861:7910](),[9.7910][13.3592:3732](),[13.3732][20.3175:3300](),[20.3300][13.3871:3905](),[13.3871][13.3871:3905](),[13.3905][9.7977:8329](),[9.7977][9.7977:8329](),[9.8329][4.4037:4098](),[4.4037][4.4037:4098](),[4.4098][9.8330:8395]()
    let ix = ix + 1;
    untracked_file_selection(
    repo,
    ix,
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    )
    };
    Some(new_selection)
    }
    Some(cursor::Selection::ChangedFile { ix, path: _ }) => {
    let new_selection = if repo
    .changed_files
    .len()
    .saturating_sub(1)
    == *ix
    {
    if repo.untracked_files.is_empty() {
  • replacement in crates/inflorescence/src/main.rs at line 401
    [4.4211][21.1079:1135](),[21.1135][22.1184:1251](),[22.1251][21.1177:1376](),[21.1177][21.1177:1376](),[21.1376][4.4272:4353](),[5.5426][4.4272:4353](),[9.8461][4.4272:4353](),[4.4272][4.4272:4353](),[4.4353][13.3906:3964]()
    changed_file_selection(
    &state.changed_files_contents,
    ix,
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    )
    } else {
    let ix = 0;
    untracked_file_selection(
    [4.4211]
    [13.3964]
    Some(untracked_file_selection(
  • edit in crates/inflorescence/src/main.rs at line 403
    [13.4006][13.4006:4046](),[13.4046][20.3301:3426](),[20.3426][13.4185:4219](),[13.4185][13.4185:4219](),[13.4219][4.4412:4442](),[5.5493][4.4412:4442](),[9.8529][4.4412:4442](),[4.4412][4.4412:4442](),[4.4442][2.1067:1100](),[2.1067][2.1067:1100](),[2.1100][4.4443:4488](),[4.4488][21.1377:1429](),[21.1429][22.1252:1315](),[22.1315][21.1467:1650](),[21.1467][21.1467:1650](),[21.1650][4.4545:4572](),[5.5558][4.4545:4572](),[9.8591][4.4545:4572](),[4.4545][4.4545:4572](),[4.4572][9.8592:8849](),[5.5625][4.4919:5000](),[9.8849][4.4919:5000](),[4.4919][4.4919:5000](),[4.5000][21.1651:1712](),[21.1712][22.1316:1383]()
    ix,
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    )
    }
    } else {
    let ix = ix + 1;
    changed_file_selection(
    &state.changed_files_contents,
    ix,
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    )
    };
    Some(new_selection)
    }
    None => {
    if repo.untracked_files.is_empty() {
    if repo.changed_files.is_empty() {
    None
    } else {
    let ix = 0;
    Some(changed_file_selection(
    &state.changed_files_contents,
  • replacement in crates/inflorescence/src/main.rs at line 404
    [21.1794][21.1794:1858]()
    &mut state.src_files_cache,
    [21.1794]
    [21.1858]
    &mut state.diffs_cache,
  • edit in crates/inflorescence/src/main.rs at line 408
    [4.5419][4.5419:5492](),[4.5492][13.4220:4353](),[13.4353][20.3427:3544](),[20.3544][13.4484:4515](),[13.4484][13.4484:4515]()
    } else {
    let ix = 0;
    Some(untracked_file_selection(
    repo,
    ix,
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    ))
  • replacement in crates/inflorescence/src/main.rs at line 409
    [4.5678][2.1573:1595](),[5.5893][2.1573:1595](),[2.1573][2.1573:1595](),[2.1595][9.8992:9011]()
    }
    };
    [2.1573]
    [9.9011]
    };
  • replacement in crates/inflorescence/src/main.rs at line 416
    [9.9161][9.9161:9241]()
    Some(cursor::Selection::UntrackedFile { ix, path: _ }) => {
    [9.9161]
    [9.9241]
    Some(cursor::Selection::UntrackedFile {
    ix,
    path: _,
    diffs: _,
    }) => {
  • replacement in crates/inflorescence/src/main.rs at line 427
    [13.4656][20.3545:3609]()
    &mut state.src_files_cache,
    [13.4656]
    [20.3609]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 433
    [21.2011][22.1384:1451]()
    &state.changed_files_contents,
    [21.2011]
    [21.2053]
    repo,
  • replacement in crates/inflorescence/src/main.rs at line 435
    [21.2093][21.2093:2157]()
    &mut state.src_files_cache,
    [21.2093]
    [21.2157]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 444
    [13.4958][20.3671:3731]()
    &mut state.src_files_cache,
    [13.4958]
    [20.3731]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 450
    [9.9907][9.9907:9985]()
    Some(cursor::Selection::ChangedFile { ix, path: _ }) => {
    [9.9907]
    [9.9985]
    Some(cursor::Selection::ChangedFile {
    ix,
    path: _,
    diffs: _,
    }) => {
  • replacement in crates/inflorescence/src/main.rs at line 459
    [21.2309][22.1452:1519]()
    &state.changed_files_contents,
    [21.2309]
    [21.2351]
    repo,
  • replacement in crates/inflorescence/src/main.rs at line 461
    [21.2391][21.2391:2455]()
    &mut state.src_files_cache,
    [21.2391]
    [21.2455]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 469
    [13.5260][20.3789:3853]()
    &mut state.src_files_cache,
    [13.5260]
    [20.3853]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 476
    [21.2603][22.1520:1583]()
    &state.changed_files_contents,
    [21.2603]
    [21.2641]
    repo,
  • replacement in crates/inflorescence/src/main.rs at line 478
    [21.2677][21.2677:2737]()
    &mut state.src_files_cache,
    [21.2677]
    [21.2737]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 493
    [13.5579][20.3915:3979]()
    &mut state.src_files_cache,
    [13.5579]
    [20.3979]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 500
    [21.2882][22.1584:1647]()
    &state.changed_files_contents,
    [21.2882]
    [21.2920]
    repo,
  • replacement in crates/inflorescence/src/main.rs at line 502
    [21.2956][21.2956:3016]()
    &mut state.src_files_cache,
    [21.2956]
    [21.3016]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 511
    [2.2548][2.2548:2594](),[2.2594][13.5754:5852]()
    Message::CursorSelect(selection) => {
    match &selection {
    cursor::Selection::UntrackedFile { path, .. } => {
    [2.2548]
    [21.3105]
    Message::CursorSelect(select) => {
    let selection = match select {
    cursor::Select::UntrackedFile { ix, path } => {
  • replacement in crates/inflorescence/src/main.rs at line 515
    [21.3154][21.3154:3206]()
    &mut state.src_files_cache,
    [21.3154]
    [21.3206]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 517
    [21.3255][21.3255:3285]()
    path,
    [21.3255]
    [21.3285]
    FileId {
    path: path.clone(),
    file_kind: FileKind::Untracked,
    },
  • edit in crates/inflorescence/src/main.rs at line 522
    [21.3308]
    [21.3308]
    cursor::Selection::UntrackedFile {
    ix,
    path,
    diffs: contents_diff::State::default(),
    }
  • replacement in crates/inflorescence/src/main.rs at line 528
    [21.3326][21.3326:3391](),[21.3391][22.1648:2006]()
    cursor::Selection::ChangedFile { path, .. } => {
    let diffs = state.changed_files_contents.get(path).unwrap();
    if any_diff_has_contents(diffs) {
    load_src_file_if_not_cached(
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    path,
    );
    [21.3326]
    [22.2006]
    cursor::Select::ChangedFile { ix, path } => {
    if let Some(diffs) = state
    .repo
    .as_ref()
    .and_then(|repo| repo.changed_files.get(&path))
    {
    if any_diff_has_contents(diffs) {
    load_src_file_if_not_cached(
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    FileId {
    path: path.clone(),
    file_kind: FileKind::Changed,
    },
    );
    }
    }
    cursor::Selection::ChangedFile {
    ix,
    path,
    diffs: contents_diff::State::default(),
  • replacement in crates/inflorescence/src/main.rs at line 551
    [13.6235][13.6235:6249]()
    }
    [13.6175]
    [8.1381]
    };
  • replacement in crates/inflorescence/src/main.rs at line 557
    [9.11279][9.11279:11408]()
    if let Some(cursor::Selection::UntrackedFile { ix, path }) =
    state.cursor.selection.as_ref()
    [9.11279]
    [9.11408]
    if let Some(cursor::Selection::UntrackedFile {
    ix,
    path,
    diffs: _,
    }) = state.cursor.selection.as_ref()
  • edit in crates/inflorescence/src/main.rs at line 580
    [15.3583][19.113:233]()
    state.changed_files_contents =
    changed_files_contents(&repo.changed_files);
  • replacement in crates/inflorescence/src/main.rs at line 589
    [13.6371][20.4245:4301]()
    &mut state.src_files_cache,
    [13.6371]
    [20.4301]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 599
    [9.12473][9.12473:12600]()
    if let Some(cursor::Selection::ChangedFile { ix, path }) =
    state.cursor.selection.as_ref()
    [9.12473]
    [9.12600]
    if let Some(cursor::Selection::ChangedFile {
    ix,
    path,
    diffs: _,
    }) = state.cursor.selection.as_ref()
  • edit in crates/inflorescence/src/main.rs at line 619
    [15.3943][19.234:301]()
    state.changed_files_contents.remove(path);
  • replacement in crates/inflorescence/src/main.rs at line 635
    [21.3453][22.2029:2096]()
    &state.changed_files_contents,
    [21.3453]
    [21.3495]
    repo,
  • replacement in crates/inflorescence/src/main.rs at line 637
    [21.3535][21.3535:3599]()
    &mut state.src_files_cache,
    [21.3535]
    [21.3599]
    &mut state.diffs_cache,
  • edit in crates/inflorescence/src/main.rs at line 700
    [15.4197][17.1922:1994]()
    state.changed_files_contents = BTreeMap::default();
  • replacement in crates/inflorescence/src/main.rs at line 730
    [20.4388][16.687:705](),[16.687][16.687:705]()
    path,
    [20.4388]
    [16.705]
    cache_counter,
    id,
  • replacement in crates/inflorescence/src/main.rs at line 735
    [16.760][16.760:1411]()
    let content = match encoding {
    Some(encoding) => {
    let decoded = encoding.decode(&data);
    FileEditorContent::Decoded(text_editor::Content::with_text(
    &decoded,
    ))
    }
    None => {
    if data.len() <= MAX_LEN_BASE64_DISPLAY {
    let encoded =
    format!("b{}", data_encoding::BASE64.encode(&data));
    FileEditorContent::ShortBase64(encoded)
    } else {
    FileEditorContent::UnknownEncoding
    [16.760]
    [16.1411]
    if state.diffs_cache.counter == cache_counter {
    let file_content = match encoding {
    Some(encoding) => {
    let decoded = encoding.decode(&data);
    contents_diff::FileContent::Decoded(decoded)
  • replacement in crates/inflorescence/src/main.rs at line 741
    [16.1433][16.1433:1466](),[16.1466][20.4389:4703](),[20.4703][13.7310:7355](),[13.7310][13.7310:7355](),[13.7355][14.663:712](),[14.712][20.4704:4771](),[20.4771][14.770:830](),[14.770][14.770:830](),[14.830][20.4772:4956](),[20.4956][14.1003:1021](),[14.1003][14.1003:1021](),[14.1021][16.1651:1696](),[16.1696][20.4957:5181]()
    }
    };
    match state.src_files_cache.get(&path) {
    Some(SrcFile::Loading | SrcFile::Loaded(_)) => {
    src_files_cache_put(
    &mut state.src_files_cache,
    path,
    SrcFile::Loaded(content),
    );
    }
    None => {}
    }
    Task::none()
    }
    Message::UntrackedFileContentsAction { path, action } => {
    // Read-only
    if !action.is_edit() {
    if let Some(SrcFile::Loaded(
    FileEditorContent::Decoded(mut content),
    ..,
    )) = state.src_files_cache.pop(&path)
    {
    content.perform(action);
    src_files_cache_put(
    &mut state.src_files_cache,
    path,
    SrcFile::Loaded(FileEditorContent::Decoded(content)),
    );
    [16.1433]
    [17.1995]
    None => contents_diff::FileContent::UnknownEncoding,
    };
    match id.file_kind {
    FileKind::Untracked => {
    let file_diff: contents_diff::File =
    contents_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: contents_diff::File =
    contents_diff::init_file(
    file_content,
    changed_file,
    );
    diffs_cache_put(
    &mut state.diffs_cache,
    id,
    FileDiff::Loaded(file_diff),
    );
    }
    }
  • edit in crates/inflorescence/src/main.rs at line 771
    [17.2027]
    [17.2027]
  • replacement in crates/inflorescence/src/main.rs at line 774
    [17.2062][17.2062:2313](),[17.2313][22.2097:2541]()
    Message::ChangedFileContentsAction { file, ix, action } => {
    // Read-only
    if !action.is_edit() {
    if let Some(contents) =
    state.changed_files_contents.get_mut(&file)
    {
    todo!()
    // if let Some(content) = contents.get_mut(ix) {
    // match content {
    // Some(FileEditorContent::Decoded(content)) => {
    // content.perform(action);
    // }
    // _ => panic!("Unexpected content: {content:?}"),
    // }
    // }
    [17.2062]
    [14.1071]
    Message::FileDiffsContentsAction { id, action } => {
    if let Some(selection) = state.cursor.selection.as_mut() {
    match (selection, id.file_kind) {
    (
    cursor::Selection::UntrackedFile { ix: _, path, diffs },
    FileKind::Untracked,
    ) if path == &id.path => {
    contents_diff::update(diffs, action);
    }
    (
    cursor::Selection::ChangedFile { ix: _, path, diffs },
    FileKind::Changed,
    ) if path == &id.path => {
    contents_diff::update(diffs, action);
    }
    _ => {
    // Selection has changed
    }
  • edit in crates/inflorescence/src/main.rs at line 802
    [9.14895][17.2706:2810]()
    state.changed_files_contents =
    changed_files_contents(&repo.changed_files);
  • replacement in crates/inflorescence/src/main.rs at line 803
    [9.14932][20.5182:5245]()
    src_files_cache_clear(&mut state.src_files_cache);
    [9.14932]
    [10.359]
    diffs_cache_clear(&mut state.diffs_cache);
  • edit in crates/inflorescence/src/main.rs at line 842
    [9.15096][17.2811:2910]()
    state.changed_files_contents =
    changed_files_contents(&changed_files);
  • replacement in crates/inflorescence/src/main.rs at line 845
    [9.15249][20.5246:5309]()
    src_files_cache_clear(&mut state.src_files_cache);
    [9.15249]
    [9.15249]
    diffs_cache_clear(&mut state.diffs_cache);
  • replacement in crates/inflorescence/src/main.rs at line 852
    [9.15531][13.7405:7479]()
    cursor::Selection::UntrackedFile { ix: _, path } => {
    [9.15531]
    [20.5310]
    cursor::Selection::UntrackedFile {
    ix: _,
    path,
    diffs: _,
    } => {
  • replacement in crates/inflorescence/src/main.rs at line 858
    [20.5363][20.5363:5419]()
    &mut state.src_files_cache,
    [20.5363]
    [20.5419]
    &mut state.diffs_cache,
  • replacement in crates/inflorescence/src/main.rs at line 860
    [20.5472][22.2542:2576]()
    path,
    [20.5472]
    [20.5507]
    FileId {
    path: path.clone(),
    file_kind: FileKind::Untracked,
    },
  • edit in crates/inflorescence/src/main.rs at line 874
    [13.8055]
    [13.8055]
    diffs: contents_diff::State::default(),
  • replacement in crates/inflorescence/src/main.rs at line 878
    [13.8142][21.3696:3768](),[21.3768][22.2577:2991]()
    cursor::Selection::ChangedFile { ix: _, path } => {
    let diffs =
    state.changed_files_contents.get(path).unwrap();
    if any_diff_has_contents(diffs) {
    load_src_file_if_not_cached(
    &mut state.src_files_cache,
    &state.src_file_load_tx,
    path,
    );
    [13.8142]
    [22.2991]
    cursor::Selection::ChangedFile {
    ix: _,
    path,
    diffs: _,
    } => {
    if let Some(diffs) = repo.changed_files.get(path) {
    if any_diff_has_contents(diffs) {
    load_src_file_if_not_cached(
    &mut state.diffs_cache,
    &state.src_file_load_tx,
    FileId {
    path: path.clone(),
    file_kind: FileKind::Changed,
    },
    );
    }
  • edit in crates/inflorescence/src/main.rs at line 906
    [21.4489]
    [21.4489]
    diffs: contents_diff::State::default(),
  • edit in crates/inflorescence/src/main.rs at line 916
    [17.2927][17.2927:3059](),[17.3059][24.283:408](),[24.408][17.4266:4296](),[17.4266][17.4266:4296]()
    }
    fn changed_files_contents(
    changed_files: &repo::ChangedFiles,
    ) -> ChangedFilesContents {
    changed_files
    .iter()
    .map(|(path, diffs)| {
    let contents = changed_file_contents(diffs);
    (path.clone(), contents)
    })
    .collect()
  • edit in crates/inflorescence/src/main.rs at line 918
    [17.4299][24.409:699](),[24.699][26.1352:1427](),[26.1427][24.768:1942](),[24.768][24.768:1942](),[24.1942][22.4772:4809](),[22.4772][22.4772:4809](),[22.4899][22.4899:4941](),[22.4941][24.1943:3250](),[24.3250][22.5847:5856](),[22.5847][22.5847:5856](),[22.5856][17.4299:4539](),[17.4299][17.4299:4539](),[17.4539][9.16466:16476](),[9.16466][9.16466:16476](),[9.16476][17.4540:4764](),[7.1290][2.2657:2666](),[6.2051][2.2657:2666](),[8.2149][2.2657:2666](),[17.4764][2.2657:2666](),[5.7537][2.2657:2666](),[9.16476][2.2657:2666](),[2.2657][2.2657:2666]()
    fn changed_file_contents(diffs: &repo::ChangedFile) -> ChangedFileContents {
    let (with_contents, without_contents) = diffs.iter().fold(
    (vec![], vec![]),
    |(mut acc_with, mut acc_without), diff| {
    match diff {
    repo::ChangedFileDiff::Move => {
    acc_without.push(ChangedFileDiffWithoutContents::Move)
    }
    repo::ChangedFileDiff::Del => {
    acc_with.push(ChangedFileDiffWithContents::Del)
    }
    repo::ChangedFileDiff::Undel => {
    acc_with.push(ChangedFileDiffWithContents::Undel)
    }
    repo::ChangedFileDiff::Add => {
    acc_with.push(ChangedFileDiffWithContents::Add)
    }
    repo::ChangedFileDiff::SolveNameConflict => acc_without
    .push(ChangedFileDiffWithoutContents::SolveNameConflict),
    repo::ChangedFileDiff::UnsolveNameConflict => acc_without
    .push(ChangedFileDiffWithoutContents::UnsolveNameConflict),
    repo::ChangedFileDiff::Edit {
    line,
    deleted,
    contents,
    } => acc_with.push(ChangedFileDiffWithContents::Edit {
    line: *line,
    deleted: *deleted,
    contents: contents_to_file_editor_content(contents),
    }),
    repo::ChangedFileDiff::Replacement {
    line,
    change_contents,
    replacement_contents,
    } => acc_with.push(ChangedFileDiffWithContents::Replacement {
    line: *line,
    change_contents: contents_to_file_editor_content(
    change_contents,
    ),
    replacement_contents: contents_to_file_editor_content(
    replacement_contents,
    ),
    }),
    repo::ChangedFileDiff::SolveOrderConflict => acc_without
    .push(ChangedFileDiffWithoutContents::SolveOrderConflict),
    repo::ChangedFileDiff::UnsolveOrderConflict => acc_without
    .push(ChangedFileDiffWithoutContents::UnsolveOrderConflict),
    repo::ChangedFileDiff::ResurrectZombines => acc_without
    .push(ChangedFileDiffWithoutContents::ResurrectZombines),
    repo::ChangedFileDiff::AddRoot => {
    acc_without.push(ChangedFileDiffWithoutContents::AddRoot)
    }
    repo::ChangedFileDiff::DelRoot => {
    acc_without.push(ChangedFileDiffWithoutContents::DelRoot)
    }
    };
    (acc_with, acc_without)
    },
    );
    ChangedFileContents {
    with_contents,
    without_contents,
    }
    }
    fn contents_to_file_editor_content(
    contents: &repo::Contents,
    ) -> FileEditorContent {
    match contents {
    repo::Contents::Decoded(content) => {
    FileEditorContent::Decoded(text_editor::Content::with_text(content))
    }
    repo::Contents::ShortBase64(short) => {
    FileEditorContent::ShortBase64(short.clone())
    }
    repo::Contents::UnknownEncoding(_vec) => {
    FileEditorContent::UnknownEncoding
    }
    }
    }
  • replacement in crates/inflorescence/src/main.rs at line 954
    [13.8146][20.5535:5610]()
    async fn load_src_file(repo_path: PathBuf, file_path: String) -> Message {
    [13.8146]
    [13.8227]
    async fn load_src_file(
    repo_path: PathBuf,
    id: FileId,
    cache_counter: usize,
    ) -> Message {
  • replacement in crates/inflorescence/src/main.rs at line 960
    [13.8257][13.8257:8284]()
    path.push(&file_path);
    [13.8257]
    [13.8284]
    path.push(&id.path);
  • replacement in crates/inflorescence/src/main.rs at line 964
    [20.5644][13.8376:8405](),[13.8376][13.8376:8405]()
    path: file_path,
    [20.5644]
    [13.8405]
    id,
  • edit in crates/inflorescence/src/main.rs at line 967
    [16.1779]
    [13.8423]
    cache_counter,
  • replacement in crates/inflorescence/src/main.rs at line 975
    [20.5677][20.5677:5761]()
    cache: &mut SrcFilesCache,
    load_tx: &watch::Sender<String>,
    path: &str,
    [20.5677]
    [20.5761]
    cache: &mut DiffsCache,
    load_tx: &watch::Sender<(FileId, usize)>,
    id: FileId,
  • replacement in crates/inflorescence/src/main.rs at line 979
    [20.5765][20.5765:5917]()
    if !cache.contains(path) {
    src_files_cache_put(cache, path.to_string(), SrcFile::Loading);
    load_tx.send(path.to_string()).unwrap();
    [20.5765]
    [20.5917]
    if !cache.inner.contains(&id) {
    diffs_cache_put(cache, id.clone(), FileDiff::Loading);
    load_tx.send((id, cache.counter)).unwrap();
  • replacement in crates/inflorescence/src/main.rs at line 985
    [20.5926][20.5926:6353]()
    fn src_files_cache_put(cache: &mut SrcFilesCache, key: String, value: SrcFile) {
    if let Err((key, value)) = cache.put_with_weight(key, value) {
    let kv_weight = SrcFileCacheWeight.weight(&key, &value);
    info!("Source file cache is too small to hold {key}. Resizing cache to to {kv_weight} fit it.");
    cache.resize(NonZero::new(kv_weight).unwrap());
    let res = cache.put_with_weight(key, value);
    [20.5926]
    [20.6353]
    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);
  • replacement in crates/inflorescence/src/main.rs at line 995
    [20.6392][20.6392:6465]()
    fn src_files_cache_clear(cache: &mut SrcFilesCache) {
    cache.clear();
    [20.6392]
    [20.6465]
    fn diffs_cache_clear(cache: &mut DiffsCache) {
    cache.inner.clear();
    cache.counter += 1;
  • replacement in crates/inflorescence/src/main.rs at line 1001
    [22.5922][22.5922:5993](),[22.5993][24.3251:3294]()
    fn any_diff_has_contents(changed_file: &ChangedFileContents) -> bool {
    !changed_file.with_contents.is_empty()
    [22.5922]
    [22.6096]
    fn any_diff_has_contents(changed_file: &repo::ChangedFile) -> bool {
    let (with_contents, _without_contents) =
    contents_diff::diffs_from_repo_diffs(changed_file);
    !with_contents.is_empty()
  • replacement in crates/inflorescence/src/main.rs at line 1022
    [4.7859][4.7859:7965]()
    Some(cursor::Selection::UntrackedFile{ix: selected_ix, path:_}) if &ix == selected_ix
    [4.7859]
    [4.7965]
    Some(cursor::Selection::UntrackedFile{ix: selected_ix, path:_, diffs: _}) if &ix == selected_ix
  • replacement in crates/inflorescence/src/main.rs at line 1027
    [4.8111][4.8111:8197]()
    cursor::Selection::UntrackedFile{ix, path: path.clone()},
    [4.8111]
    [4.8197]
    cursor::Select::UntrackedFile{ix, path: path.clone()},
  • replacement in crates/inflorescence/src/main.rs at line 1038
    [2.3737][4.8342:8446]()
    Some(cursor::Selection::ChangedFile{ix: selected_ix, path:_}) if &ix == selected_ix
    [2.3737]
    [2.3822]
    Some(cursor::Selection::ChangedFile{ix: selected_ix, path:_, diffs:_}) if &ix == selected_ix
  • replacement in crates/inflorescence/src/main.rs at line 1044
    [2.3968][15.4613:4702]()
    cursor::Selection::ChangedFile{ix, path: file_path.clone()},
    [2.3968]
    [2.4025]
    cursor::Select::ChangedFile{ix, path: file_path.clone()},
  • replacement in crates/inflorescence/src/main.rs at line 1073
    [13.8559][13.8559:8696](),[13.8696][25.323:324](),[25.324][20.6469:6608](),[13.8696][20.6469:6608](),[20.6608][25.325:1204](),[25.1204][16.2021:2326](),[20.6720][16.2021:2326](),[14.1281][16.2021:2326](),[16.2326][20.6721:6889]()
    Some(cursor::Selection::UntrackedFile { path, .. }) => {
    debug_assert!(repo.untracked_files.contains(path));
    let diff = match &state.src_files_cache.peek(path) {
    Some(SrcFile::Loaded(content)) => match content {
    FileEditorContent::Decoded(content) => {
    let path_buf = PathBuf::from(path);
    let file_ext = path_buf.extension().and_then(ffi::OsStr::to_str);
    let editor = text_editor(content)
    .wrapping(text::Wrapping::WordOrGlyph)
    .on_action(|action|
    Message::UntrackedFileContentsAction{path: path.clone(), action}
    );
    if let Some(file_ext) = file_ext {
    el(editor
    .highlight(file_ext, highlighter::Theme::SolarizedDark))
    } else {
    el(editor)
    }
    },
    FileEditorContent::ShortBase64(content) => {
    el(text(content))
    }
    FileEditorContent::UnknownEncoding => {
    el("Unknown encoding")
    }
    },
    Some(SrcFile::Loading) => el(text("Loading...")),
    None => panic!("Unexpectedly, the src file {path} is not even being loaded"),
    [13.8559]
    [13.9266]
    Some(cursor::Selection::UntrackedFile {
    ix: _,
    path,
    diffs: selection_state,
    }) => {
    let id = FileId {
    path: path.clone(),
    file_kind: FileKind::Untracked,
    };
    let diffs = match state.diffs_cache.inner.peek(&id) {
    Some(FileDiff::Loaded(file)) => {
    contents_diff::view(selection_state, file).map(
    move |msg| Message::FileDiffsContentsAction {
    id: id.clone(),
    action: msg,
    },
    )
    }
    None | Some(FileDiff::Loading) => el(text("loading...")),
  • replacement in crates/inflorescence/src/main.rs at line 1093
    [13.9285][19.302:380]()
    el(column([view_diff_header(format!("{path} diff:")), diff]))
    [13.9285]
    [13.9339]
    el(column([
    view_diff_header(format!("{path} diff:")),
    el(scrollable(diffs)),
    ]))
  • replacement in crates/inflorescence/src/main.rs at line 1098
    [13.9353][22.6100:6545](),[22.6545][26.1428:2931]()
    Some(cursor::Selection::ChangedFile { path, ix: _ }) => {
    let diffs = state.changed_files_contents.get(path).unwrap();
    let _src_file_contents: Option<text_editor::Content> =
    if any_diff_has_contents(diffs) {
    // TODO: load file contents from cache
    None
    } else {
    None
    };
    match state.src_files_cache.peek(path) {
    Some(SrcFile::Loaded(content)) => {
    let file_content = match content {
    FileEditorContent::Decoded(content) => {
    content.text()
    }
    FileEditorContent::ShortBase64(_) => todo!(),
    FileEditorContent::UnknownEncoding => todo!(),
    };
    let with_contents = diffs
    .with_contents
    .iter()
    .map(|change| match dbg!(change) {
    ChangedFileDiffWithContents::Add => {
    contents_diff::ChangedFileDiffWithContents::Add
    }
    ChangedFileDiffWithContents::Edit {
    line,
    deleted,
    contents,
    } => contents_diff::ChangedFileDiffWithContents::Edit {
    line: *line,
    deleted: *deleted,
    contents: match contents {
    FileEditorContent::Decoded(content) => contents_diff::ChangeContents::Decoded(content.text()) ,
    FileEditorContent::ShortBase64(_) => todo!(),
    FileEditorContent::UnknownEncoding => todo!(),
    [13.9353]
    [26.2931]
    Some(cursor::Selection::ChangedFile {
    path,
    ix: _,
    diffs: selection_state,
    }) => {
    let id = FileId {
    path: path.clone(),
    file_kind: FileKind::Changed,
    };
    let diffs = match state.diffs_cache.inner.peek(&id) {
    Some(FileDiff::Loaded(file)) => {
    contents_diff::view(selection_state, file).map(
    move |msg| Message::FileDiffsContentsAction {
    id: id.clone(),
    action: msg,
  • replacement in crates/inflorescence/src/main.rs at line 1114
    [26.2962][26.2962:4823]()
    },
    ChangedFileDiffWithContents::Replacement {
    line,
    change_contents,
    replacement_contents,
    } => contents_diff::ChangedFileDiffWithContents::Replacement {
    line:*line ,
    change_contents: match change_contents {
    FileEditorContent::Decoded(content) => contents_diff::ChangeContents::Decoded(content.text()) ,
    FileEditorContent::ShortBase64(_) => todo!(),
    FileEditorContent::UnknownEncoding => todo!(),
    },
    replacement_contents: match replacement_contents {
    FileEditorContent::Decoded(content) => contents_diff::ChangeContents::Decoded(content.text()) ,
    FileEditorContent::ShortBase64(_) => todo!(),
    FileEditorContent::UnknownEncoding => todo!(),
    }
    },
    ChangedFileDiffWithContents::Del => contents_diff::ChangedFileDiffWithContents::Del,
    ChangedFileDiffWithContents::Undel => contents_diff::ChangedFileDiffWithContents::Undel,
    })
    .collect::<Vec<_>>();
    let state =
    contents_diff::init(&file_content, &with_contents);
    let diffs =
    contents_diff::view(state).map(|msg| todo!());
    el(column([
    view_diff_header(format!("{path} diff:")),
    el(scrollable(diffs)),
    ]))
    [26.2962]
    [26.4823]
    )
  • replacement in crates/inflorescence/src/main.rs at line 1116
    [26.4845][26.4845:4970]()
    Some(SrcFile::Loading) => el(text("loading...")),
    None => todo!(),
    }
    [26.4845]
    [13.9691]
    None | Some(FileDiff::Loading) => el(text("loading...")),
    };
    el(column([
    view_diff_header(format!("{path} diff:")),
    el(scrollable(diffs)),
    ]))
  • edit in crates/inflorescence/src/cursor.rs at line 1
    [2.26]
    [2.27]
    use crate::contents_diff;
  • replacement in crates/inflorescence/src/cursor.rs at line 8
    [2.113][2.113:137]()
    #[derive(Debug, Clone)]
    [2.113]
    [2.137]
    #[derive(Debug)]
  • edit in crates/inflorescence/src/cursor.rs at line 10
    [2.158]
    [4.1599]
    UntrackedFile {
    ix: usize,
    path: String,
    diffs: contents_diff::State,
    },
    ChangedFile {
    ix: usize,
    path: String,
    diffs: contents_diff::State,
    },
    }
    #[derive(Debug, Clone)]
    pub enum Select {
  • edit in crates/inflorescence/src/contents_diff.rs at line 3
    [26.5056]
    [26.5056]
    use std::borrow::Cow;
  • edit in crates/inflorescence/src/contents_diff.rs at line 8
    [26.5137]
    [26.5137]
    use libflowers_client::repo;
  • replacement in crates/inflorescence/src/contents_diff.rs at line 13
    [26.5171][26.5171:5517]()
    pub enum ChangedFileDiffWithContents {
    Add,
    Edit {
    line: usize,
    deleted: bool,
    contents: ChangeContents,
    },
    Replacement {
    line: usize,
    /// Deleted line
    change_contents: ChangeContents,
    /// Added lines
    replacement_contents: ChangeContents,
    },
    Del,
    Undel,
    [26.5171]
    [26.5517]
    pub enum File {
    Decoded(DecodedFile),
    Undecodable(UndecodableFile),
    }
    #[derive(Debug)]
    pub struct DecodedFile {
    pub combined: Combined,
    pub diffs_without_contents: Vec<DiffWithoutContents>,
  • replacement in crates/inflorescence/src/contents_diff.rs at line 25
    [26.5537][26.5537:5767]()
    pub enum ChangeContents {
    Decoded(String),
    /// Short byte sequence of unknown encoding encoded with base64 for
    /// display. Must be shorter than [`MAX_LEN_BASE64_DISPLAY`]
    ShortBase64(String),
    UnknownEncoding,
    [26.5537]
    [26.5767]
    pub struct UndecodableFile {
    pub diffs_with_contents: Vec<DiffWithContents>,
    pub diffs_without_contents: Vec<DiffWithoutContents>,
  • edit in crates/inflorescence/src/contents_diff.rs at line 30
    [26.5770]
    [26.5770]
    /// A file combined with its diffs into sections
  • replacement in crates/inflorescence/src/contents_diff.rs at line 32
    [26.5787][26.5787:5806]()
    pub struct State {
    [26.5787]
    [26.5806]
    pub struct Combined {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 38
    [26.5887][26.5887:6144]()
    pub enum Section {
    Unchanged(Lines),
    /// `deleted` and `added` are together because for
    /// `ChangedFileDiffWithContents::Replacement` they begin on the same line
    /// number
    Changed {
    deleted: Lines,
    added: Lines,
    },
    [26.5887]
    [26.6144]
    pub enum FileContent<'a> {
    Decoded(Cow<'a, str>),
    UnknownEncoding,
    }
    pub fn init_file(
    file_content: FileContent<'_>,
    changed_file: Option<&repo::ChangedFile>,
    ) -> File {
    let (diffs_with_contents, diffs_without_contents) = changed_file
    .map(diffs_from_repo_diffs)
    .unwrap_or((vec![], vec![]));
    match file_content {
    FileContent::Decoded(file_content) => {
    let combined =
    combine_decoded_contents(&file_content, diffs_with_contents);
    File::Decoded(DecodedFile {
    combined,
    diffs_without_contents,
    })
    }
    FileContent::UnknownEncoding => File::Undecodable(UndecodableFile {
    diffs_with_contents,
    diffs_without_contents,
    }),
    }
  • replacement in crates/inflorescence/src/contents_diff.rs at line 67
    [26.6147][26.6147:6390]()
    pub fn init(
    file_contents: &str,
    changes: &[ChangedFileDiffWithContents],
    ) -> State {
    let changes_len = changes.len();
    let mut file_lines = file_contents.split('\n');
    let mut sections = Vec::with_capacity(changes.len());
    [26.6147]
    [26.6390]
    pub fn combine_decoded_contents(
    file_content: &str,
    diffs_with_contents: Vec<DiffWithContents>,
    ) -> Combined {
    let changes_len = diffs_with_contents.len();
    let mut file_lines = file_content.split('\n');
    let mut sections = Vec::with_capacity(diffs_with_contents.len());
  • replacement in crates/inflorescence/src/contents_diff.rs at line 77
    [26.6465][26.6465:6493]()
    for change in changes {
    [26.6465]
    [26.6493]
    for change in diffs_with_contents {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 79
    [26.6516][26.6516:6615]()
    ChangedFileDiffWithContents::Add
    | ChangedFileDiffWithContents::Undel => {
    [26.6516]
    [26.6615]
    DiffWithContents::Add | DiffWithContents::Undel => {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 87
    [26.6924][26.6924:6955]()
    return State {
    [26.6924]
    [26.6955]
    return Combined {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 92
    [26.7052][26.7052:7102]()
    ChangedFileDiffWithContents::Del => {
    [26.7052]
    [26.7102]
    DiffWithContents::Del => {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 100
    [26.7415][26.7415:7446]()
    return State {
    [26.7415]
    [26.7446]
    return Combined {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 105
    [26.7543][26.7543:7591]()
    ChangedFileDiffWithContents::Edit {
    [26.7543]
    [26.7591]
    DiffWithContents::Edit {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 112
    [26.7778][26.7778:7820]()
    current_line = *line;
    [26.7778]
    [26.7820]
    current_line = line;
  • replacement in crates/inflorescence/src/contents_diff.rs at line 119
    [26.8010][26.8010:8103]()
    if *deleted {
    let deleted = contents_to_lines(contents);
    [26.8010]
    [26.8103]
    if deleted {
    let deleted = contents_to_lines(&contents);
  • replacement in crates/inflorescence/src/contents_diff.rs at line 128
    [26.8343][26.8343:8404]()
    let added = contents_to_lines(contents);
    [26.8343]
    [26.8404]
    let added = contents_to_lines(&contents);
  • replacement in crates/inflorescence/src/contents_diff.rs at line 139
    [26.8748][26.8748:8803]()
    ChangedFileDiffWithContents::Replacement {
    [26.8748]
    [26.8803]
    DiffWithContents::Replacement {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 146
    [26.9010][26.9010:9052]()
    current_line = *line;
    [26.9010]
    [26.9052]
    current_line = line;
  • replacement in crates/inflorescence/src/contents_diff.rs at line 153
    [26.9242][26.9242:9377]()
    let added = contents_to_lines(replacement_contents);
    let deleted = contents_to_lines(change_contents);
    [26.9242]
    [26.9377]
    let added = contents_to_lines(&replacement_contents);
    let deleted = contents_to_lines(&change_contents);
  • replacement in crates/inflorescence/src/contents_diff.rs at line 170
    [26.9881][26.9881:9893]()
    State {
    [26.9881]
    [26.9893]
    Combined {
  • replacement in crates/inflorescence/src/contents_diff.rs at line 176
    [26.9942][26.9942:10247]()
    fn contents_to_lines(contents: &ChangeContents) -> Lines {
    match contents {
    ChangeContents::Decoded(string) => {
    string.split('\n').map(str::to_string).collect()
    }
    ChangeContents::ShortBase64(_) => todo!(),
    ChangeContents::UnknownEncoding => todo!(),
    }
    [26.9942]
    [26.10247]
    pub fn diffs_from_repo_diffs(
    changed_file: &repo::ChangedFile,
    ) -> (Vec<DiffWithContents>, Vec<DiffWithoutContents>) {
    changed_file.iter().fold((vec![], vec![]), |(mut with, mut without), diff| {
    match diff {
    repo::ChangedFileDiff::Move => {
    without.push(DiffWithoutContents::Move);
    },
    repo::ChangedFileDiff::Del => {
    with.push(DiffWithContents::Del);
    },
    repo::ChangedFileDiff::Undel => {
    with.push(DiffWithContents::Undel);
    },
    repo::ChangedFileDiff::Add => {
    with.push(DiffWithContents::Add);
    },
    repo::ChangedFileDiff::SolveNameConflict => {
    without.push(DiffWithoutContents::Move);
    },
    repo::ChangedFileDiff::UnsolveNameConflict => {
    without.push(DiffWithoutContents::Move);
    },
    repo::ChangedFileDiff::Edit { line, deleted, contents } => match contents{
    repo::Contents::Decoded(lines) => {
    with.push(DiffWithContents::Edit {
    line: *line,
    deleted: *deleted,
    contents: lines.clone(),
    });
    },
    repo::Contents::ShortBase64(short) => {
    without.push(DiffWithoutContents::Edit {
    line: *line,
    deleted: *deleted,
    contents: UndecodableContents::ShortBase64(short.clone()),
    });
    },
    repo::Contents::UnknownEncoding(_bytes) => {
    without.push(DiffWithoutContents::Edit {
    line: *line,
    deleted: *deleted,
    contents: UndecodableContents::UnknownEncoding,
    });
    },
    },
    repo::ChangedFileDiff::Replacement { line, change_contents, replacement_contents } => match (change_contents, replacement_contents) {
    (repo::Contents::Decoded(change), repo::Contents::Decoded(replacement)) => {
    with.push(DiffWithContents::Replacement {
    line: *line,
    change_contents: change.clone(),
    replacement_contents: replacement.clone(),
    });
    },
    (repo::Contents::ShortBase64(change), repo::Contents::ShortBase64(replacement)) => {
    without.push(DiffWithoutContents::Replacement {
    line: *line,
    change_contents: UndecodableContents::ShortBase64(change.clone()),
    replacement_contents: UndecodableContents::ShortBase64(replacement.clone()),
    });
    },
    (repo::Contents::UnknownEncoding(_change), repo::Contents::UnknownEncoding(_replacement)) => {
    without.push(DiffWithoutContents::Replacement {
    line: *line,
    change_contents: UndecodableContents::UnknownEncoding,
    replacement_contents: UndecodableContents::UnknownEncoding,
    });
    },
    _ => {
    unimplemented!("The change and replacement have different encoding!");
    }
    },
    repo::ChangedFileDiff::SolveOrderConflict => {
    without.push(DiffWithoutContents::SolveOrderConflict);
    },
    repo::ChangedFileDiff::UnsolveOrderConflict => {
    without.push(DiffWithoutContents::UnsolveOrderConflict);
    },
    repo::ChangedFileDiff::ResurrectZombines => {
    without.push(DiffWithoutContents::ResurrectZombines);
    },
    repo::ChangedFileDiff::AddRoot => {
    without.push(DiffWithoutContents::AddRoot);
    },
    repo::ChangedFileDiff::DelRoot => {
    without.push(DiffWithoutContents::DelRoot);
    },
    };
    (with, without)
    })
    }
    #[derive(Debug)]
    pub enum DiffWithContents {
    Add,
    Edit {
    line: usize,
    deleted: bool,
    contents: String,
    },
    Replacement {
    line: usize,
    /// Deleted line
    change_contents: String,
    /// Added lines
    replacement_contents: String,
    },
    Del,
    Undel,
    }
    #[allow(dead_code)] // TODO rm once `view_undecodable` is implemented
    #[derive(Debug)]
    pub enum DiffWithoutContents {
    // _________________________________________________________________________
    // Cases that never have contents:
    Move,
    SolveNameConflict,
    UnsolveNameConflict,
    SolveOrderConflict,
    UnsolveOrderConflict,
    ResurrectZombines,
    AddRoot,
    DelRoot,
    // _________________________________________________________________________
    // Cases that normally have contents, but in these cases the contents are
    // not decodable:
    Edit {
    line: usize,
    deleted: bool,
    contents: UndecodableContents,
    },
    Replacement {
    line: usize,
    /// Deleted line
    change_contents: UndecodableContents,
    /// Added lines
    replacement_contents: UndecodableContents,
    },
    }
    #[allow(dead_code)] // TODO rm once `view_undecodable` is implemented
    #[derive(Debug)]
    pub enum UndecodableContents {
    /// Short byte sequence of unknown encoding encoded with base64 for
    /// display. Must be shorter than [`crate::repo::MAX_LEN_BASE64_DISPLAY`]
    ShortBase64(String),
    UnknownEncoding,
  • edit in crates/inflorescence/src/contents_diff.rs at line 326
    [26.10250]
    [26.10250]
    #[allow(dead_code)] // TODO rm once `view_decoded` is fully implemented
    #[derive(Debug, Default)]
    pub struct State {
    pub selected_sections: Vec<usize>,
    pub expanded_unchanged_sections: Vec<usize>,
    pub collapsed_changed_sections: Vec<usize>,
    }
    #[derive(Debug)]
    pub enum Section {
    Unchanged(Lines),
    /// `deleted` and `added` are together because for
    /// `ChangedFileDiffWithContents::Replacement` they begin on the same line
    /// number
    Changed {
    deleted: Lines,
    added: Lines,
    },
    }
    fn contents_to_lines(contents: &str) -> Lines {
    contents.split('\n').map(str::to_string).collect()
    }
  • replacement in crates/inflorescence/src/contents_diff.rs at line 368
    [26.10752][26.10752:10769]()
    #[derive(Debug)]
    [26.10752]
    [26.10769]
    #[derive(Debug, Clone)]
  • replacement in crates/inflorescence/src/contents_diff.rs at line 371
    [26.10786][26.10786:10832]()
    pub fn update(state: &mut State, msg: Msg) {}
    [26.10786]
    [26.10832]
    pub fn update(_state: &mut State, _msg: Msg) {}
    pub fn view<'a>(state: &'a State, file: &'a File) -> Element<'a, Msg> {
    match file {
    File::Decoded(decoded_file) => view_decoded(state, decoded_file),
    File::Undecodable(undecodable_file) => {
    view_undecodable(state, undecodable_file)
    }
    }
    }
  • replacement in crates/inflorescence/src/contents_diff.rs at line 382
    [26.10833][26.10833:10886]()
    pub fn view(state: State) -> Element<'static, Msg> {
    [26.10833]
    [26.10886]
    pub fn view_decoded<'a>(
    _state: &'a State,
    file: &'a DecodedFile,
    ) -> Element<'a, Msg> {
    // TODO use state to display selection, and control section expansion
  • replacement in crates/inflorescence/src/contents_diff.rs at line 388
    [26.10916][26.10916:11010]()
    let line_num_digits = state.max_line_num.to_string().len();
    let sections_view = state
    [26.10916]
    [26.11010]
    let line_num_digits = file.combined.max_line_num.to_string().len();
    let sections_view = file
    .combined
  • edit in crates/inflorescence/src/contents_diff.rs at line 448
    [26.13072]
    [26.13072]
    }
    pub fn view_undecodable<'a>(
    _state: &'a State,
    file: &'a UndecodableFile,
    ) -> Element<'a, Msg> {
    // TODO implement proper view
    el(code(format!("{file:#?}")))