very nice refactor, wip adding channels logs

[?]
Aug 7, 2025, 5:30 PM
WAOGSCOJ5A372BZKHEYD2BCDBCENNVLFYW3INKUOOAZMDADDIFIQC

Dependencies

  • [2] 6YZAVBWU Initial commit
  • [3] IQDCHWCP load a pijul repo
  • [4] SWWE2R6M display basic repo stuff
  • [5] WT3GA27P add cursor with selection
  • [6] UB2ITZJS refresh changed files on FS changes
  • [7] KT5UYXGK fix selection after adding file, add changed file diffs
  • [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] W4LFX7IH group diffs by file name
  • [15] AMPZ2BXK show changed files diffs (only Edit atm)
  • [16] V55EAIWQ add src file LRU cache
  • [17] HOJZI52Y rename flowers_ui to inflorescence
  • [18] B4RMW5AE add syntax highlighter to untracked files contents
  • [19] MJDGPSHG WIP contents diff
  • [20] ZVI4AWER woot contents_diff
  • [21] QMAUTRB6 refactor diff
  • [22] OQ6HSAWH show record log
  • [23] DCSUCH6R add undecoded diff view, improve decoded view style
  • [24] JE44NYHM display log files diffs
  • [25] ONRCENKT rm unnecessary state from repo's internal state
  • [26] 4ELJZGRJ load and store all change diffs at once
  • [27] CALXOZXA flatten crates dir
  • [28] L6KSEFQI move cursor related stuff into its module
  • [29] BFN2VHZS refactor file stuff into sub-mod
  • [30] GWZGYNIB add view crate
  • [31] 3SYSJKYL add app icon
  • [32] 23SFYK4Q big view refactor into a new crate
  • [33] OPXFZKEB view tests setup
  • [34] MYGIBRRH wip custom theme
  • [35] XSZZB47U refactor stuff into lib
  • [36] 3BK22XE5 add a test for hover btn and more refactors
  • [37] WGID4LS4 absolutely slayed testing with iced task
  • [38] VCNKFNUF app init test
  • [39] ACDXXAX2 refactor main's updates into smaller fns
  • [40] FVA36HBV restart repo manager task if it crashes
  • [41] I56UGW7U make record test, fix log update
  • [42] ESMM3FEL test selection reindexing
  • [43] 7SSBM4UQ view: refactor repo view
  • [44] FL2ULDJN test record
  • [45] F542TMBE test log
  • [46] ZD56BUSU add back +/- bg colors
  • [47] S2T7RUKW add nav back placeholder
  • [48] I2AG42PA new cols layout
  • [49] 4PNWU55O replace the circular hor navigation
  • [50] SASAN2XC use nav-scrollable
  • [51] YKHE3XMW refactor diffs handling
  • [52] KEPKF3WO unify diffs handling, simplify view
  • [53] GOLHUD6R nav-scrollable: set skip-able sections
  • [54] KWTBNTO3 diffs selection and scrolling
  • [55] 5MUEECMJ smooth scrolling nav
  • [56] 3TLPJ57B alt scroll via context and couple fixes
  • [57] BNHJU2DU clippy fixes
  • [58] KQABQCCZ update rust to 1.88
  • [59] AI3IMKC3 refactor stairs
  • [60] WXQBBQ2A update nightly
  • [61] DST3HRZZ fix emoji rendering
  • [62] PTWZYQFR use nav-scrollable for repo status
  • [63] RDRBP7AL auto-scroll status selection
  • [64] UR4J677R nav for log changes and refactors
  • [65] K63JN6CR refactor out non-view field from cursor
  • [66] GYZWZ33T fix unwraps on navs for view
  • [67] A6Z4O6RC actions menu
  • [68] 7BLZN73O add a key to refresh repo
  • [69] JZXYSIYD channel selection!
  • [70] 5ZRDYL6K fork channel, fix recording esc key
  • [71] BAUK5BON pimp-up action buttons
  • [72] NZD56PVB fix mouse selection
  • [73] OJPGHVC3 entire log!
  • [74] ZIUHKVJK update tests
  • [75] 3XRG4BB6 rewritten nav-scrollable!
  • [76] S4WH75Y3 allow to select channels if there are any other. Conditional switch
  • [77] NOB64XMR fmt and clippy
  • [78] NWJD6VM6 mv libflowers libflorescence
  • [79] ELG3UDT6 allow to rm added files
  • [80] BJXUYQ2Y show untracked file contents in read-only text editor
  • [81] RPCIGCNS add replacement diff details
  • [82] 4G6DZDO6 rename diff msg for nav-scrollable
  • [83] DXAYDIMQ update to latest pijul
  • [84] C5P3JIFC refactor out the nav-scrollable children len arg
  • [85] 4WO3ZJM2 show untracked files' contents
  • [86] WI2BVQ6J rm client lib crate
  • [87] HC7ROIBC move main diffs state out of cursor
  • [88] VJNWIGSX clippy
  • [89] PKJCFSBM theme improvements
  • [90] AHWWRC73 navigate log entries
  • [91] EC3TVL4X add untracked files
  • [92] NRCUG4R2 load changed files src when selected
  • [93] 3QVNMRNM test non-empty repo app view
  • [94] UF5NJKAS test load repo
  • [95] SWDPAGF6 test channel name

Change contents

  • replacement in libflorescence/src/testing.rs at line 87
    [38.1857][74.5:62]()
    let log = repo::get_log(&internal.repo, None, None);
    [38.1857]
    [44.98]
    let log = repo::get_log(&internal.repo, None, None, None);
  • replacement in libflorescence/src/repo.rs at line 46
    [14.44][22.81:99]()
    pub log: Log,
    [14.44]
    [9.281]
    pub short_log: Log,
    }
    #[derive(Clone, Derivative, strum::Display)]
    #[derivative(Debug)]
    pub enum MsgIn {
    RefreshChangedAndUntrackedFiles,
    AddUntrackedFile {
    path: String,
    },
    RmAddedFile {
    path: String,
    },
    Record {
    msg: String,
    #[derivative(Debug = "ignore")]
    sk: Arc<SKey>,
    },
    GetChangeDiffs {
    hash: ChangeHash,
    },
    SwitchToChannel(String),
    ForkChannel(String),
    LoadEntireLog,
    LoadOtherChannelLog(String),
    }
    #[derive(Debug, Clone, strum::Display)]
    pub enum MsgOut {
    Init(State),
    Refreshed {
    state: State,
    invalidate_logs: bool,
    },
    AddedUntrackedFile {
    path: String,
    },
    RmedAddedFile {
    path: String,
    },
    GotChangeDiffs {
    hash: ChangeHash,
    diffs: ChangedFiles,
    },
    LoadedEntireLog(Log),
    LoadedOtherChannelLog {
    channel: String,
    log: Log,
    },
  • edit in libflorescence/src/repo.rs at line 176
    [15.490][9.312:315](),[7.575][9.312:315](),[9.315][12.283:349](),[12.349][9.355:409](),[9.355][9.355:409](),[9.409][12.350:546](),[12.546][24.7:14](),[24.14][26.7:28](),[26.28][54.165:191](),[26.55][12.546:553](),[24.58][12.546:553](),[54.191][12.546:553](),[12.546][12.546:553](),[12.553][69.116:145](),[69.145][70.6:31](),[70.31][73.6:25](),[73.25][4.466:468](),[70.31][4.466:468](),[69.145][4.466:468](),[9.510][4.466:468](),[12.553][4.466:468](),[7.575][4.466:468](),[4.466][4.466:468](),[4.468][9.511:587](),[9.587][39.6:28](),[39.28][41.6:181](),[39.28][26.56:77](),[41.181][26.56:77](),[25.34][26.56:77](),[26.77][54.192:218](),[54.218][26.104:140](),[26.104][26.104:140](),[26.140][73.26:52]()
    }
    #[derive(Clone, Derivative, strum::Display)]
    #[derivative(Debug)]
    pub enum MsgIn {
    RefreshChangedAndUntrackedFiles,
    AddUntrackedFile {
    path: String,
    },
    RmAddedFile {
    path: String,
    },
    Record {
    msg: String,
    #[derivative(Debug = "ignore")]
    sk: Arc<SKey>,
    },
    GetChangeDiffs {
    hash: ChangeHash,
    },
    SwitchToChannel(String),
    ForkChannel(String),
    LoadEntireLog,
    }
    #[derive(Debug, Clone, strum::Display)]
    pub enum MsgOut {
    Init(State),
    Refreshed(State),
    AddedUntrackedFile {
    path: String,
    },
    RmedAddedFile {
    path: String,
    },
    /// The State is updated after making a record
    Recorded(State),
    GotChangeDiffs {
    hash: ChangeHash,
    diffs: ChangedFiles,
    },
    LoadedEntireLog(Log),
  • replacement in libflorescence/src/repo.rs at line 253
    [9.2072][39.29:92]()
    let _ = msg_out_tx.send(MsgOut::Refreshed(state));
    [9.2072]
    [9.2386]
    let _ = msg_out_tx.send(MsgOut::Refreshed {
    state,
    // To be safe - this msg might be triggered from any change
    // reported by file watch
    invalidate_logs: true,
    });
  • replacement in libflorescence/src/repo.rs at line 290
    [24.321][41.771:833]()
    let _ = msg_out_tx.send(MsgOut::Recorded(state));
    [24.321]
    [24.321]
    let _ = msg_out_tx.send(MsgOut::Refreshed {
    state,
    invalidate_logs: true,
    });
  • replacement in libflorescence/src/repo.rs at line 318
    [69.506][69.506:569]()
    let _ = msg_out_tx.send(MsgOut::Refreshed(state));
    [69.506]
    [9.3030]
    let _ = msg_out_tx.send(MsgOut::Refreshed {
    state,
    invalidate_logs: true,
    });
  • replacement in libflorescence/src/repo.rs at line 332
    [70.373][70.373:436]()
    let _ = msg_out_tx.send(MsgOut::Refreshed(state));
    [70.373]
    [73.53]
    let _ = msg_out_tx.send(MsgOut::Refreshed {
    state,
    invalidate_logs: false,
    });
  • replacement in libflorescence/src/repo.rs at line 340
    [73.184][73.184:253]()
    let log = get_log(&internal_state.repo, None, None);
    [73.184]
    [73.253]
    let log = get_log(&internal_state.repo, None, None, None);
  • edit in libflorescence/src/repo.rs at line 347
    [70.446]
    [9.3040]
    MsgIn::LoadOtherChannelLog(channel) => {
    let channel_returned: String;
    let log: Log;
    (internal_state, channel_returned, log) =
    spawn_blocking(move || {
    let log = get_log(
    &internal_state.repo,
    Some(&channel),
    None,
    None,
    );
    (internal_state, channel, log)
    })
    .await
    .unwrap();
    let _ = msg_out_tx.send(MsgOut::LoadedOtherChannelLog {
    channel: channel_returned,
    log,
    });
    }
  • replacement in libflorescence/src/repo.rs at line 382
    [22.359][73.416:460]()
    let log = get_log(repo, offset, limit);
    [22.359]
    [25.1931]
    let log = get_log(repo, Some(&channel), offset, limit);
  • replacement in libflorescence/src/repo.rs at line 389
    [4.893][22.401:414]()
    log,
    [4.893]
    [4.893]
    short_log: log,
  • edit in libflorescence/src/repo.rs at line 919
    [22.454]
    [22.454]
    channel: Option<&str>,
  • replacement in libflorescence/src/repo.rs at line 928
    [22.671][22.671:767]()
    let cur_channel = txn
    .current_channel()
    .unwrap_or(pijul::DEFAULT_CHANNEL)
    [22.671]
    [22.767]
    let cur_channel = channel
    .unwrap_or_else(|| {
    txn.current_channel().unwrap_or(pijul::DEFAULT_CHANNEL)
    })
  • replacement in libflorescence/src/repo/test.rs at line 99
    [44.582][74.146:203]()
    let log = repo::get_log(&internal.repo, None, None);
    [44.582]
    [44.635]
    let log = repo::get_log(&internal.repo, None, None, None);
  • replacement in libflorescence/src/repo/test.rs at line 110
    [44.863][74.204:261]()
    let log = repo::get_log(&internal.repo, None, None);
    [44.863]
    [44.916]
    let log = repo::get_log(&internal.repo, None, None, None);
  • replacement in libflorescence/src/repo/test.rs at line 196
    [45.215][74.262:323]()
    let mut log = repo::get_log(&internal.repo, None, None);
    [45.215]
    [45.272]
    let mut log = repo::get_log(&internal.repo, None, None, None);
  • replacement in libflorescence/src/repo/test.rs at line 203
    [45.450][74.324:392]()
    let mut log = repo::get_log(&internal.repo, None, Some(limit));
    [45.450]
    [45.514]
    let mut log = repo::get_log(&internal.repo, None, None, Some(limit));
  • replacement in libflorescence/src/repo/test.rs at line 208
    [45.615][74.393:462]()
    let mut log = repo::get_log(&internal.repo, Some(offset), None);
    [45.615]
    [45.680]
    let mut log = repo::get_log(&internal.repo, None, Some(offset), None);
  • replacement in libflorescence/src/diff.rs at line 1
    [35.392][35.393:574]()
    #[derive(Debug, Default)]
    pub struct State {
    pub selected_sections: Vec<usize>,
    pub expanded_unchanged_sections: Vec<usize>,
    pub collapsed_changed_sections: Vec<usize>,
    [35.392]
    [35.574]
    use std::borrow::Cow;
    #[derive(Debug)]
    pub enum FileContent<'a> {
    Decoded(Cow<'a, str>),
    UnknownEncoding,
  • edit in inflorescence_view/src/lib.rs at line 3
    [32.273][69.2919:2938]()
    pub mod selection;
  • edit in inflorescence_view/src/diff.rs at line 1
    [32.417][75.1409:1447]()
    use iced_expl_widget::nav_scrollable;
  • replacement in inflorescence_view/src/diff.rs at line 2
    [36.767][35.5127:5159](),[32.417][35.5127:5159]()
    pub use libflorescence::diff::{
    [36.767]
    [36.768]
    pub use inflorescence_model::diff::{
  • replacement in inflorescence_view/src/diff.rs at line 4
    [36.832][64.26:101](),[64.101][36.907:928](),[50.234][36.907:928](),[36.907][36.907:928]()
    DiffWithoutContents, File, Lines, Section, State, UndecodableContents,
    UndecodableFile,
    [36.832]
    [35.5296]
    DiffWithoutContents, File, FileAndState, Lines, Section, State,
    UndecodableContents, UndecodableFile,
  • replacement in inflorescence_view/src/diff.rs at line 8
    [35.5300][32.418:432](),[32.417][32.418:432]()
    use std::cmp;
    [35.5300]
    [32.432]
    use crate::{el, theme, Theme};
    use iced_expl_widget::nav_scrollable;
  • replacement in inflorescence_view/src/diff.rs at line 14
    [32.549][46.547:578]()
    use crate::{el, theme, Theme};
    [32.549]
    [50.235]
    use std::cmp;
  • replacement in inflorescence_view/src/app.rs at line 6
    [33.4204][69.2942:2990]()
    use crate::{diff, el, selection, theme, Theme};
    [33.4204]
    [75.2426]
    use crate::{diff, el, theme, Theme};
  • edit in inflorescence_view/src/app.rs at line 8
    [75.2464]
    [32.12583]
    use inflorescence_model::{
    get_entire_log_diffs_nav, get_entire_log_files_nav, get_files_diffs_nav,
    get_status_log_diffs_nav, get_status_log_files_nav, selection, Log,
    ReadyState, RecordMsg, SubState,
    };
  • replacement in inflorescence_view/src/app.rs at line 14
    [32.12615][75.2465:2491]()
    use libflorescence::repo;
    [32.12615]
    [32.12641]
    use libflorescence::{file, repo};
  • edit in inflorescence_view/src/app.rs at line 28
    [48.494][48.494:495](),[48.495][32.12753:12793](),[32.12753][32.12753:12793](),[32.12793][48.496:529](),[48.529][32.12793:12822](),[32.12793][32.12793:12822](),[32.12822][62.997:1029](),[32.12896][32.12896:12939](),[32.12939][52.318:415](),[52.415][69.3061:3175](),[69.3175][73.758:820](),[52.481][32.12996:12999](),[51.553][32.12996:12999](),[73.820][32.12996:12999](),[64.1133][32.12996:12999](),[69.3175][32.12996:12999](),[32.12996][32.12996:12999](),[32.12999][62.1030:1166](),[62.1166][73.821:871](),[73.871][75.2492:2573](),[75.2573][73.872:931](),[62.1252][73.872:931](),[73.931][69.3236:3269](),[70.2877][69.3236:3269](),[69.3236][69.3236:3269](),[69.3269][73.932:991](),[73.991][70.2938:2979](),[70.2938][70.2938:2979](),[70.2979][73.992:1088](),[73.1088][64.1134:1154](),[70.2979][64.1134:1154](),[69.3269][64.1134:1154](),[62.1252][64.1134:1154](),[64.1154][69.3270:3301](),[69.3301][64.1179:1372](),[64.1179][64.1179:1372](),[64.1372][67.313:352](),[67.352][64.1372:1516](),[64.1372][64.1372:1516](),[64.1516][75.2574:2622](),[75.2622][64.1556:1563](),[64.1556][64.1556:1563](),[64.1563][62.1252:1255](),[62.1252][62.1252:1255](),[62.1255][64.1564:1826](),[64.1826][75.2623:2663](),[75.2663][64.1858:1861](),[64.1858][64.1858:1861](),[64.1861][73.1089:1200](),[73.1200][75.2664:2705](),[75.2705][73.1233:1281](),[73.1233][73.1233:1281](),[73.1281][75.2706:2747](),[75.2747][73.1321:1511](),[73.1321][73.1321:1511](),[73.1511][75.2748:2796](),[75.2796][73.1551:1554](),[73.1551][73.1551:1554](),[62.1255][32.12999:13038](),[73.1554][32.12999:13038](),[64.1861][32.12999:13038](),[32.12999][32.12999:13038](),[32.13038][69.3302:3358](),[69.3358][32.13063:13088](),[32.13063][32.13063:13088](),[62.1297][32.13088:13128](),[64.1953][32.13088:13128](),[32.13088][32.13088:13128](),[32.13128][67.353:373](),[67.373][32.13145:13161](),[32.13145][32.13145:13161](),[32.13161][67.374:393](),[32.13379][67.394:450](),[67.450][69.3359:3404](),[69.3404][76.28:47](),[76.47][70.2980:3026](),[69.3423][70.2980:3026](),[70.3026][68.28:45](),[69.3423][68.28:45](),[67.450][68.28:45](),[68.45][75.2797:2816](),[68.45][32.15355:15357](),[67.450][32.15355:15357](),[73.1773][32.15355:15357](),[75.2816][32.15355:15357](),[32.15355][32.15355:15357]()
    #[derive(Debug)]
    pub struct State<'a> {
    pub window_size: iced::Size,
    pub repo_path: &'a Path,
    pub repo: Option<&'a Repo>,
    pub record_msg: Option<&'a RecordMsg>,
    /// Diff and state of selected log's file (untracked, changed or from a
    /// log), if any
    pub status_selection: Option<StatusSelection<'a>>,
    pub channel_selection: Option<&'a selection::Channel>,
    pub entire_log_selection: Option<EntireLogSelection<'a>>,
    }
    #[derive(Debug)]
    pub struct Repo {
    pub state: repo::State,
    /// Scrollable status view contains the overview of untracked files,
    /// changed files and most recent log changes
    // pub status_nav: NavScrollable,
    pub status_nav: nav_scrollable::State,
    /// `true` when we're selecting a channel to switch to
    pub switching_channel: bool,
    /// `Some` when we're selecting a channel to switch to
    pub forking_channel: Option<String>,
    /// `Some` when looking at the entire log of changes
    pub entire_log: Option<EntireLog>,
    }
    #[derive(Debug)]
    pub enum StatusSelection<'a> {
    UntrackedFile {
    ix: usize,
    path: &'a str,
    diff: Option<Diff<'a>>,
    },
    ChangedFile {
    ix: usize,
    path: &'a str,
    diff: Option<Diff<'a>>,
    is_added_from_untracked: bool,
    },
    Log {
    ix: usize,
    hash: repo::ChangeHash,
    message: &'a str,
    file: Option<LogChangeFileSelection<'a>>,
    nav: Option<&'a nav_scrollable::State>,
    },
    }
    #[derive(Debug)]
    pub struct LogChangeFileSelection<'a> {
    pub ix: usize,
    pub path: &'a str,
    pub diff: Option<Diff<'a>>,
    }
    #[derive(Debug)]
    pub struct Diff<'a> {
    pub is_selected: bool,
    pub file: &'a diff::File,
    pub state: &'a diff::State,
    pub nav: &'a nav_scrollable::State,
    }
    #[derive(Debug)]
    pub enum EntireLog {
    Loading,
    LoadingButNotViewing,
    Got {
    log: repo::Log,
    nav: Box<nav_scrollable::State>,
    },
    NotViewing {
    log: repo::Log,
    nav: Box<nav_scrollable::State>,
    },
    }
    #[derive(Debug)]
    pub struct EntireLogSelection<'a> {
    pub ix: usize,
    pub hash: repo::ChangeHash,
    pub message: &'a str,
    pub file: Option<LogChangeFileSelection<'a>>,
    pub nav: Option<&'a nav_scrollable::State>,
    }
    #[derive(Debug, Clone)]
    pub enum Msg {
    Confirm,
    Cancel,
    Selection(selection::Msg),
    ToRepo(repo::MsgIn),
    EditRecordMsg(text_editor::Action),
    PostponeRecord,
    SaveRecord,
    DiscardRecord,
    AddUntrackedFile,
    RmAddedFile,
    StartRecord,
    /// Show a list of channels to switch to
    SelectChannel,
    ForkChannel,
    ForkChannelName(String),
    RefreshRepo,
    ShowEntireLog,
    }
  • replacement in inflorescence_view/src/app.rs at line 29
    [32.15358][32.15358:15467](),[32.15467][52.482:499](),[52.499][32.15487:15509](),[32.15487][32.15487:15509]()
    #[derive(Debug)]
    pub enum RecordMsg {
    Typing(text_editor::Content),
    Canceled { old_msg: String },
    }
    pub fn view<'a>(
    state: State<'a>,
    [32.15358]
    [32.15509]
    pub fn view<'a, F>(
    state: &'a inflorescence_model::State,
    get_diff: F,
  • replacement in inflorescence_view/src/app.rs at line 33
    [32.15537][52.500:531](),[52.531][64.2175:2191]()
    ) -> Element<'a, Msg, Theme> {
    let State {
    [32.15537]
    [64.2191]
    ) -> Element<'a, Msg, Theme>
    where
    F: Fn(file::IdHash) -> Option<&'a diff::File>,
    {
    let inflorescence_model::State {
  • replacement in inflorescence_view/src/app.rs at line 40
    [64.2231][64.2231:2245](),[64.2261][64.2261:2281](),[64.2281][69.3424:3477](),[69.3477][73.1774:1804]()
    repo,
    record_msg,
    status_selection,
    channel_selection,
    entire_log_selection,
    [64.2231]
    [64.2300]
    sub,
  • replacement in inflorescence_view/src/app.rs at line 42
    [64.2315][64.2315:2358](),[64.2358][69.3478:3648](),[69.3648][73.1805:1839](),[73.1839][69.3648:3658](),[69.3648][69.3648:3658](),[67.522][43.75:124](),[52.564][43.75:124](),[64.2437][43.75:124](),[69.3658][43.75:124](),[43.75][43.75:124]()
    let inner = if let Some(repo) = repo {
    view_repo(
    window_size,
    repo_path,
    repo,
    record_msg,
    status_selection,
    channel_selection,
    entire_log_selection,
    )
    } else {
    el(text("Loading repo..."))
    [64.2315]
    [43.124]
    let inner = match sub {
    SubState::Loading { .. } => el(text("Loading...")),
    SubState::SelectingId {
    user_ids: _,
    user_selection_ix: _,
    user_selection_nav: _,
    repo: _,
    } => todo!(),
    SubState::Ready(state) => {
    view_ready(*window_size, repo_path, state, get_diff)
    }
  • edit in inflorescence_view/src/app.rs at line 55
    [43.131]
    [43.131]
  • replacement in inflorescence_view/src/app.rs at line 63
    [32.15950][64.2438:2456]()
    fn view_repo<'a>(
    [32.15950]
    [64.2456]
    fn view_ready<'a, F>(
  • edit in inflorescence_view/src/app.rs at line 65
    [64.2485][64.2485:2507]()
    // TODO show path
  • replacement in inflorescence_view/src/app.rs at line 66
    [64.2533][64.2533:2553](),[64.2584][64.2584:2623](),[64.2623][69.3731:3837](),[69.3837][73.1840:1898](),[73.1898][64.2661:2692](),[69.3837][64.2661:2692](),[64.2661][64.2661:2692](),[64.2692][62.1429:1444](),[62.1429][62.1429:1444](),[62.1444][64.2693:2708]()
    repo: &'a Repo,
    record_msg: Option<&'a RecordMsg>,
    status_selection: Option<StatusSelection<'a>>,
    channel_selection: Option<&'a selection::Channel>,
    entire_log_selection: Option<EntireLogSelection<'a>>,
    ) -> Element<'a, Msg, Theme> {
    let Repo {
    state:
    [64.2533]
    [64.2708]
    state: &'a ReadyState,
    get_diff: F,
    ) -> Element<'a, Msg, Theme>
    where
    F: Fn(file::IdHash) -> Option<&'a diff::File>,
    {
    let ReadyState {
    user_id: _,
    repo:
  • replacement in inflorescence_view/src/app.rs at line 81
    [64.2849][64.2849:2870]()
    log,
    [64.2849]
    [64.2870]
    short_log,
  • replacement in inflorescence_view/src/app.rs at line 83
    [64.2885][62.1465:1485](),[62.1465][62.1465:1485](),[62.1485][69.3871:3898](),[69.3898][70.3027:3052](),[70.3052][73.1899:1919](),[73.1919][62.1485:1499](),[70.3052][62.1485:1499](),[69.3898][62.1485:1499](),[62.1485][62.1485:1499]()
    status_nav,
    switching_channel,
    forking_channel,
    entire_log,
    } = repo;
    [64.2885]
    [69.3899]
    selection,
    navigation,
    record_msg,
    forking_channel_name,
    logs,
    } = state;
    let selection = selection::unify(selection);
  • replacement in inflorescence_view/src/app.rs at line 107
    [32.16079][69.4154:4327]()
    let is_selected = matches!(status_selection.as_ref() ,
    Some(StatusSelection::UntrackedFile{ ix: selected_ix, .. }) if &ix == selected_ix
    [32.16079]
    [32.16260]
    let is_selected = matches!(selection,
    selection::Unified::Status(Some(selection::Status::UntrackedFile{ ix: selected_ix, .. })) if &ix == selected_ix
  • replacement in inflorescence_view/src/app.rs at line 126
    [32.16783][69.4488:4658]()
    let is_selected = matches!(status_selection.as_ref(),
    Some(StatusSelection::ChangedFile{ ix: selected_ix, .. }) if &ix == selected_ix
    [32.16783]
    [32.16961]
    let is_selected = matches!(selection,
    selection::Unified::Status(Some(selection::Status::ChangedFile{ ix: selected_ix, .. })) if &ix == selected_ix
  • replacement in inflorescence_view/src/app.rs at line 144
    [73.2268][64.3386:3422](),[64.3386][64.3386:3422]()
    log.iter().enumerate().map(
    [73.2268]
    [73.2269]
    short_log.iter().enumerate().map(
  • replacement in inflorescence_view/src/app.rs at line 149
    [73.2342][69.4822:4985](),[32.17641][69.4822:4985]()
    let is_selected = matches!(status_selection.as_ref(),
    Some(StatusSelection::Log { ix: selected_ix, .. }) if &ix == selected_ix
    [73.2342]
    [32.17818]
    let is_selected = matches!(selection,
    selection::Unified::Status(Some(selection::Status::LogChange(selection::LogChange{ ix: selected_ix, .. }))) if &ix == selected_ix
  • replacement in inflorescence_view/src/app.rs at line 174
    [32.18331][73.2452:2517](),[73.2517][69.5226:5298](),[69.5226][69.5226:5298](),[54.6393][64.4239:4415](),[64.4415][75.2817:2883](),[75.2883][52.771:824](),[64.4549][52.771:824](),[54.6634][52.771:824](),[43.2253][52.771:824](),[52.824][43.2334:2349](),[43.2334][43.2334:2349]()
    let selection_details = || match status_selection.as_ref() {
    Some(StatusSelection::UntrackedFile { ix: _, path, diff }) => {
    let diffs = match diff {
    Some(Diff {
    is_selected,
    file,
    state,
    nav,
    }) => diff::view(state, nav, file, *is_selected),
    None => el(text("Loading diff...")),
    };
    [32.18331]
    [50.1826]
    let selection_details = || {
    if let selection::Unified::Status(selection) = selection {
    match selection {
    Some(selection::Status::UntrackedFile {
    ix: _,
    path,
    diff_selected,
    }) => {
    let id_hash =
    file::id_parts_hash(path, file::Kind::Untracked);
    let diff = get_diff(id_hash);
    let state = navigation.files_diffs.diffs.get(&id_hash);
    let nav = get_files_diffs_nav(navigation, id_hash);
    let diffs = match diff.zip(state).zip(nav) {
    Some(((file, state), nav)) => {
    diff::view(state, nav, file, *diff_selected)
    }
    None => el(text("Loading diff...")),
    };
  • replacement in inflorescence_view/src/app.rs at line 194
    [50.1827][43.2349:2451](),[43.2349][43.2349:2451](),[43.2451][50.1828:1851](),[50.1851][43.2490:2546](),[43.2490][43.2490:2546](),[43.2546][69.5299:5343](),[69.5343][67.1190:1301](),[67.1190][67.1190:1301](),[54.6835][64.4615:4713]()
    el(column([
    view_diff_header(format!("Untracked file {path} contents:")),
    diffs,
    ])
    .spacing(SPACING))
    }
    Some(StatusSelection::ChangedFile {
    path,
    ix: _,
    diff,
    is_added_from_untracked: _,
    }) => {
    let diffs = match diff {
    Some(Diff {
    is_selected,
    [50.1827]
    [64.4713]
    el(column([
    view_diff_header(format!(
    "Untracked file {path} contents:"
    )),
    diffs,
    ])
    .spacing(SPACING))
    }
    Some(selection::Status::ChangedFile {
    path,
    ix: _,
    diff_selected,
    }) => {
    let id_hash =
    file::id_parts_hash(path, file::Kind::Changed);
    let diff = get_diff(id_hash);
    let state = navigation.files_diffs.diffs.get(&id_hash);
    let nav = get_files_diffs_nav(navigation, id_hash);
    let diffs = match diff.zip(state).zip(nav) {
    Some(((file, state), nav)) => {
    diff::view(state, nav, file, *diff_selected)
    }
    None => el(text("Loading diff...")),
    };
    el(column([
    view_diff_header(format!("Changed file {path} diff:")),
    diffs,
    ])
    .spacing(SPACING))
    }
    Some(selection::Status::LogChange(selection::LogChange {
    ix,
    hash,
    message,
  • replacement in inflorescence_view/src/app.rs at line 230
    [64.4739][64.4739:4791](),[64.4791][75.2884:2950](),[75.2950][52.980:1033](),[64.4925][52.980:1033](),[54.7076][52.980:1033](),[43.3194][52.980:1033](),[52.1033][43.3275:3290](),[43.3275][43.3275:3290](),[43.3290][32.18457:18481](),[32.18457][32.18457:18481](),[32.18481][43.3291:3363](),[43.3363][50.1852:1875](),[50.1875][43.3402:3458](),[43.3402][43.3402:3458](),[43.3458][69.5344:5380](),[64.4956][43.3502:3557](),[69.5380][43.3502:3557](),[43.3502][43.3502:3557](),[43.3557][64.4957:4974](),[64.4974][43.3579:3613](),[43.3579][43.3579:3613](),[43.3613][64.4975:5022]()
    state,
    nav,
    }) => diff::view(state, nav, file, *is_selected),
    None => el(text("Loading diff...")),
    };
    el(column([
    view_diff_header(format!("Changed file {path} diff:")),
    diffs,
    ])
    .spacing(SPACING))
    }
    Some(StatusSelection::Log {
    ix,
    hash,
    message,
    nav,
    file,
    }) => {
    let entry = log.get(*ix).unwrap();
    [64.4739]
    [32.18975]
    })) => {
    let entry = short_log.get(*ix).unwrap();
  • replacement in inflorescence_view/src/app.rs at line 233
    [32.18976][43.3690:3745]()
    let short_hash = display_short_hash(hash);
    [32.18976]
    [32.21515]
    let short_hash = display_short_hash(hash);
  • replacement in inflorescence_view/src/app.rs at line 235
    [32.21516][64.5023:5089](),[64.5089][73.2518:2839]()
    let view = match nav {
    Some(nav) => {
    let change_selected = match file.as_ref() {
    Some(LogChangeFileSelection { diff, .. }) => !diff
    .as_ref()
    .map(|diff| diff.is_selected)
    .unwrap_or_default(),
    _ => false,
    [32.21516]
    [73.2839]
    let nav = get_status_log_files_nav(navigation, *hash);
    let view = match nav {
    Some(nav) => {
    let change_selected = match file.as_ref() {
    Some(selection::LogChangeFileSelection {
    ix: _,
    path: _,
    diff_selected,
    }) => *diff_selected,
    _ => false,
    };
    let files = entry.file_paths.iter().enumerate().map(|(ix, path)| {
    let is_selected = matches!(file, Some(selection::LogChangeFileSelection{ path: selected_path, .. }) if selected_path == path);
    el(button(text(path)).on_press_with(move || {
    Msg::Selection(selection::Msg::Select(selection::Select::LogChangeFile { ix, path: path.clone() }))
    }).class(selectable_button_class(is_selected)))
    });
    el(nav_scrollable(nav, files)
    .class(if change_selected {
    theme::Scrollable::Selected
    } else {
    theme::Scrollable::Normal
    })
    .width(Length::Fill)
    .height(Length::Fill))
    }
    None => el(text("Loading...")),
  • replacement in inflorescence_view/src/app.rs at line 265
    [73.2863][64.5149:5236](),[64.5149][64.5149:5236](),[64.5236][73.2864:3298](),[73.3298][75.2951:3315]()
    let files = entry.file_paths.iter().enumerate().map(|(ix, path)| {
    let is_selected = matches!(file, Some(LogChangeFileSelection{ path: selected_path, .. }) if selected_path == path);
    el(button(text(path)).on_press_with(move || {
    Msg::Selection(selection::Msg::Select(selection::Select::LogChangeFile { ix, path: path.clone() }))
    }).class(selectable_button_class(is_selected)))
    });
    el(nav_scrollable(nav, files)
    .class(if change_selected {
    theme::Scrollable::Selected
    } else {
    theme::Scrollable::Normal
    })
    .width(Length::Fill)
    .height(Length::Fill))
    [73.2863]
    [64.5724]
    el(column([
    view_diff_header(format!("{short_hash} message:")),
    el(text(message).shaping(text::Shaping::Advanced)),
    view_diff_header("Changed files:".to_string()),
    view,
    ])
    .width(Length::Fill)
    .height(Length::Fill)
    .spacing(SPACING))
  • replacement in inflorescence_view/src/app.rs at line 275
    [64.5742][64.5742:5806](),[64.5806][43.3826:3918](),[32.22072][43.3826:3918](),[43.3918][64.5807:5876](),[61.278][43.3953:4017](),[64.5876][43.3953:4017](),[43.3953][43.3953:4017](),[43.4017][64.5877:5899](),[48.597][32.23465:23480](),[43.4064][32.23465:23480](),[64.5899][32.23465:23480](),[32.23465][32.23465:23480](),[32.23480][48.598:665](),[48.665][43.4065:4096](),[32.23480][43.4065:4096]()
    None => el(text("Loading...")),
    };
    el(column([
    view_diff_header(format!("{short_hash} message:")),
    el(text(*message).shaping(text::Shaping::Advanced)),
    view_diff_header("Changed files:".to_string()),
    view,
    ])
    .width(Length::Fill)
    .height(Length::Fill)
    .spacing(SPACING))
    [64.5742]
    [43.4096]
    None => el(row([])),
    }
    } else {
    el(row([]))
  • edit in inflorescence_view/src/app.rs at line 280
    [43.4106][43.4106:4135]()
    None => el(row([])),
  • replacement in inflorescence_view/src/app.rs at line 291
    [48.1006][73.3566:3662]()
    } else if let Some(EntireLogSelection { file, .. }) =
    entire_log_selection.as_ref()
    [48.1006]
    [73.3662]
    } else if let selection::Unified::EntireLog(Some(selection::LogChange {
    file,
    ..
    })) = selection
  • replacement in inflorescence_view/src/app.rs at line 301
    [73.3751][69.5506:5570](),[48.1006][69.5506:5570]()
    } else if let Some(selection) = status_selection.as_ref() {
    [73.3751]
    [48.1076]
    } else if let selection::Unified::Status(Some(selection)) = selection {
  • replacement in inflorescence_view/src/app.rs at line 303
    [48.1102][69.5571:5792]()
    StatusSelection::UntrackedFile { .. }
    | StatusSelection::ChangedFile { .. }
    | StatusSelection::Log { file: None, .. } => 1,
    StatusSelection::Log { file: Some(_), .. } => 2,
    [48.1102]
    [48.1343]
    selection::Status::UntrackedFile { .. }
    | selection::Status::ChangedFile { .. }
    | selection::Status::LogChange(selection::LogChange {
    file: None,
    ..
    }) => 1,
    selection::Status::LogChange(selection::LogChange {
    file: Some(_),
    ..
    }) => 2,
  • replacement in inflorescence_view/src/app.rs at line 336
    [62.2065][73.4080:4143](),[73.4143][69.5853:5920](),[69.5853][69.5853:5920](),[69.5920][64.6435:6533](),[64.6435][64.6435:6533](),[64.6533][69.5921:5986](),[69.5986][64.6592:6690](),[64.6592][64.6592:6690](),[64.6690][69.5987:6054](),[69.6054][64.6751:6780](),[64.6751][64.6751:6780]()
    let status_selected = || match status_selection.as_ref() {
    Some(StatusSelection::UntrackedFile { diff, .. }) => !diff
    .as_ref()
    .map(|diff| diff.is_selected)
    .unwrap_or_default(),
    Some(StatusSelection::ChangedFile { diff, .. }) => !diff
    .as_ref()
    .map(|diff| diff.is_selected)
    .unwrap_or_default(),
    Some(StatusSelection::Log { file, .. }) => file.is_none(),
    None => true,
    };
    [62.2065]
    [48.1891]
    let status_selected =
    || match selection {
    selection::Unified::Status(Some(
    selection::Status::UntrackedFile { diff_selected, .. },
    )) => !diff_selected,
    selection::Unified::Status(Some(
    selection::Status::ChangedFile { diff_selected, .. },
    )) => !diff_selected,
    selection::Unified::Status(Some(selection::Status::LogChange(
    selection::LogChange { file, .. },
    ))) => file.is_none(),
    selection::Unified::Status(None) => true,
    selection::Unified::Channel(_)
    | selection::Unified::EntireLog(_) => false,
    };
  • replacement in inflorescence_view/src/app.rs at line 355
    [73.4222][75.3316:3642]()
    el(nav_scrollable(status_nav, status_nav_children())
    .class(if status_selected() {
    theme::Scrollable::Selected
    } else {
    theme::Scrollable::Normal
    })
    .width(Length::Fill)
    .height(Length::Fill)),
    [73.4222]
    [73.4542]
    el(
    nav_scrollable(&navigation.status_nav, status_nav_children())
    .class(if status_selected() {
    theme::Scrollable::Selected
    } else {
    theme::Scrollable::Normal
    })
    .width(Length::Fill)
    .height(Length::Fill),
    ),
  • replacement in inflorescence_view/src/app.rs at line 391
    [73.5273][73.5273:5333](),[73.5333][69.6224:6260](),[69.6224][69.6224:6260](),[69.6260][52.1134:1195](),[64.7034][52.1134:1195](),[52.1134][52.1134:1195](),[52.1195][64.7035:7125](),[64.7125][52.1267:1474](),[54.7257][52.1267:1474](),[52.1267][52.1267:1474](),[52.1474][64.7126:7314](),[64.7314][75.3643:3713](),[75.3713][52.1765:1821](),[52.1765][52.1765:1821]()
    let status_col_2 = || match status_selection.as_ref() {
    Some(StatusSelection::Log {
    ix: _,
    hash,
    message: _,
    file: Some(LogChangeFileSelection { ix: _, path, diff }),
    nav: _,
    }) => Some(el(column([
    el(column([
    view_diff_header(format!(
    "{path} changes in {}:",
    display_short_hash(hash)
    )),
    match diff {
    Some(Diff {
    is_selected,
    file,
    state,
    nav,
    }) => diff::view(state, nav, file, *is_selected),
    None => el(text("Loading diff..")),
    [73.5273]
    [48.3159]
    let status_col_2 = || match selection {
    selection::Unified::Status(Some(selection::Status::LogChange(
    selection::LogChange {
    ix: _,
    hash,
    message: _,
    file:
    Some(selection::LogChangeFileSelection {
    ix: _,
    path,
    diff_selected,
    }),
    },
    ))) => {
    let id_hash = file::log_id_parts_hash(*hash, path);
    let state = navigation.log_diffs.diffs.get(&id_hash);
    let nav = get_status_log_diffs_nav(navigation, id_hash);
    Some(el(column([
    el(column([
    view_diff_header(format!(
    "{path} changes in {}:",
    display_short_hash(hash)
    )),
    match state.zip(nav) {
    Some((diff::FileAndState { file, state }, nav)) => {
    diff::view(state, nav, file, *diff_selected)
    }
    None => el(text("Loading diff..")),
    },
    ])
    .spacing(SPACING)),
    // NOTE: This is currently never true - there are only up to 3
    // cols
    if hidden_cols == 2 {
    el(button(row([el(
    text("← Files").shaping(text::Shaping::Advanced)
    )]))
    .on_press(Msg::Selection(
    selection::Msg::PressDir(selection::Dir::Left),
    )))
    } else {
    el(row([]))
  • replacement in inflorescence_view/src/app.rs at line 435
    [54.7411][52.1822:1983](),[48.3213][52.1822:1983](),[52.1983][73.5334:5461](),[73.5461][69.6261:6371](),[52.2132][69.6261:6371](),[69.6371][55.628:648](),[55.628][55.628:648](),[55.648][52.2191:2354](),[52.2191][52.2191:2354](),[51.2106][32.24109:24110](),[52.2354][32.24109:24110](),[48.3661][32.24109:24110](),[43.5649][32.24109:24110](),[32.24109][32.24109:24110](),[32.24110][69.6372:6520](),[69.6520][52.2515:2539](),[64.7831][52.2515:2539](),[52.2515][52.2515:2539]()
    .spacing(SPACING)),
    // NOTE: This is currently never true - there are only up to 3
    // cols
    if hidden_cols == 2 {
    el(button(row([el(
    text("← Files").shaping(text::Shaping::Advanced)
    )]))
    .on_press(Msg::Selection(
    selection::Msg::PressDir(selection::Dir::Left),
    )))
    } else {
    el(row([]))
    },
    ])
    .width(Length::Fill)
    .height(Length::Fill)
    .spacing(SPACING))),
    Some(StatusSelection::UntrackedFile { .. })
    | Some(StatusSelection::ChangedFile { .. })
    | Some(StatusSelection::Log { .. })
    | None => None,
    [47.314]
    [73.5462]
    .width(Length::Fill)
    .height(Length::Fill)
    .spacing(SPACING)))
    }
    _ => None,
  • replacement in inflorescence_view/src/app.rs at line 442
    [73.5470][73.5470:5629]()
    let entire_log_selected = || match entire_log_selection.as_ref() {
    Some(EntireLogSelection { file, .. }) => file.is_none(),
    None => false,
    [73.5470]
    [73.5629]
    let entire_log_selected = || match selection {
    selection::Unified::EntireLog(log_change) => match log_change {
    Some(selection::LogChange { file, .. }) => file.is_none(),
    None => true,
    },
    _ => false,
  • replacement in inflorescence_view/src/app.rs at line 449
    [73.5636][73.5636:5942]()
    let entire_log_change_selected = || match entire_log_selection.as_ref() {
    Some(EntireLogSelection {
    file: Some(LogChangeFileSelection { diff, .. }),
    ..
    }) => !diff
    .as_ref()
    .map(|diff| diff.is_selected)
    .unwrap_or_default(),
    [73.5636]
    [73.5942]
    let entire_log_change_selected = || match selection {
    selection::Unified::EntireLog(log_change) => match log_change {
    Some(selection::LogChange {
    file:
    Some(selection::LogChangeFileSelection {
    diff_selected, ..
    }),
    ..
    }) => !*diff_selected,
    _ => false,
    },
  • edit in inflorescence_view/src/app.rs at line 462
    [73.5969]
    [73.5969]
    let other_channels_selected = || match selection {
    selection::Unified::Channel(channel) => match channel {
    Some(selection::Channel { log, .. }) => log.is_none(),
    None => true,
    },
    _ => false,
    };
  • replacement in inflorescence_view/src/app.rs at line 471
    [73.6002][73.6002:6077]()
    let Some(EntireLog::Got { log, nav }) = entire_log.as_ref() else {
    [73.6002]
    [73.6077]
    let Some(Log::Loaded { log }) = logs.entire_log.as_ref() else {
  • replacement in inflorescence_view/src/app.rs at line 475
    [73.6180][73.6180:6337]()
    let is_selected = matches!(entire_log_selection.as_ref(),
    Some(EntireLogSelection { ix: selected_ix, .. }) if &ix == selected_ix
    [73.6180]
    [73.6337]
    let is_selected = matches!(selection,
    selection::Unified::EntireLog(Some(selection::LogChange{ ix: selected_ix, .. })) if &ix == selected_ix
  • replacement in inflorescence_view/src/app.rs at line 482
    [73.6446][73.6446:6576]()
    let selected_ix = entire_log_selection
    .as_ref()
    .map(|EntireLogSelection { ix, .. }| len - *ix);
    [73.6446]
    [73.6576]
    let selected_ix = match selection {
    selection::Unified::EntireLog(Some(selection::LogChange {
    ix,
    ..
    })) => Some(len - *ix),
    _ => None,
    };
  • replacement in inflorescence_view/src/app.rs at line 497
    [73.6842][75.3714:3758]()
    el(nav_scrollable(nav, entries)
    [73.6842]
    [73.6916]
    el(nav_scrollable(&navigation.entire_log_nav, entries)
  • replacement in inflorescence_view/src/app.rs at line 511
    [73.7286][73.7286:7387]()
    let files_view = match entire_log_selection.as_ref() {
    Some(EntireLogSelection {
    [73.7286]
    [73.7387]
    let files_view = match selection {
    selection::Unified::EntireLog(Some(selection::LogChange {
  • replacement in inflorescence_view/src/app.rs at line 517
    [73.7476][73.7476:7517]()
    nav,
    }) => {
    [73.7476]
    [73.7517]
    })) => {
  • replacement in inflorescence_view/src/app.rs at line 519
    [73.7576][73.7576:7723]()
    let view = match (nav.as_ref(), entire_log.as_ref()) {
    (Some(nav), Some(EntireLog::Got { log, nav: _ })) => {
    [73.7576]
    [73.7723]
    let nav = get_entire_log_files_nav(navigation, *hash);
    let view = match nav.as_ref().zip(logs.entire_log.as_ref()) {
    Some((nav, Log::Loaded { log })) => {
  • replacement in inflorescence_view/src/app.rs at line 524
    [73.7873][73.7873:8017]()
    let is_selected = matches!(file, Some(LogChangeFileSelection{ path: selected_path, .. }) if selected_path == path);
    [73.7873]
    [73.8017]
    let is_selected = matches!(file, Some(selection::LogChangeFileSelection{ path: selected_path, .. }) if selected_path == path);
  • replacement in inflorescence_view/src/app.rs at line 543
    [73.9060][73.9060:9133]()
    el(text(*message).shaping(text::Shaping::Advanced)),
    [73.9060]
    [73.9133]
    el(text(message).shaping(text::Shaping::Advanced)),
  • replacement in inflorescence_view/src/app.rs at line 551
    [73.9370][73.9370:9403]()
    None => el(row([])),
    [73.9370]
    [73.9403]
    _ => el(row([])),
  • replacement in inflorescence_view/src/app.rs at line 573
    [75.4212][73.9917:10019](),[73.9917][73.9917:10019]()
    let entire_log_col_2 = || match entire_log_selection.as_ref() {
    Some(EntireLogSelection {
    [75.4212]
    [73.10019]
    let entire_log_col_2 = || match selection {
    selection::Unified::EntireLog(Some(selection::LogChange {
  • replacement in inflorescence_view/src/app.rs at line 578
    [73.10080][73.10080:10565](),[73.10565][75.4213:4283](),[75.4283][73.10973:11029](),[73.10973][73.10973:11029]()
    file: Some(LogChangeFileSelection { ix: _, path, diff }),
    nav: _,
    }) => Some(el(column([
    el(column([
    view_diff_header(format!(
    "{path} changes in {}:",
    display_short_hash(hash)
    )),
    match diff {
    Some(Diff {
    is_selected,
    file,
    state,
    nav,
    }) => diff::view(state, nav, file, *is_selected),
    None => el(text("Loading diff..")),
    [73.10080]
    [73.11029]
    file:
    Some(selection::LogChangeFileSelection {
    ix: _,
    path,
    diff_selected,
    }),
    })) => {
    let id_hash = file::log_id_parts_hash(*hash, path);
    let state = navigation.log_diffs.diffs.get(&id_hash);
    let nav = get_entire_log_diffs_nav(navigation, id_hash);
    Some(el(column([
    el(column([
    view_diff_header(format!(
    "{path} changes in {}:",
    display_short_hash(hash)
    )),
    match state.zip(nav) {
    Some((diff::FileAndState { file, state }, nav)) => {
    diff::view(state, nav, file, *diff_selected)
    }
    None => el(text("Loading diff..")),
    },
    ])
    .spacing(SPACING)),
    // NOTE: This is currently never true - there are only up to 3
    // cols
    if hidden_cols == 2 {
    el(button(row([el(
    text("← Files").shaping(text::Shaping::Advanced)
    )]))
    .on_press(Msg::Selection(
    selection::Msg::PressDir(selection::Dir::Left),
    )))
    } else {
    el(row([]))
  • replacement in inflorescence_view/src/app.rs at line 615
    [73.11063][73.11063:11701]()
    .spacing(SPACING)),
    // NOTE: This is currently never true - there are only up to 3
    // cols
    if hidden_cols == 2 {
    el(button(row([el(
    text("← Files").shaping(text::Shaping::Advanced)
    )]))
    .on_press(Msg::Selection(
    selection::Msg::PressDir(selection::Dir::Left),
    )))
    } else {
    el(row([]))
    },
    ])
    .width(Length::Fill)
    .height(Length::Fill)
    .spacing(SPACING))),
    Some(EntireLogSelection { .. }) | None => None,
    [73.11063]
    [73.11701]
    .width(Length::Fill)
    .height(Length::Fill)
    .spacing(SPACING)))
    }
    _ => None,
  • replacement in inflorescence_view/src/app.rs at line 624
    [69.6614][69.6614:6758]()
    let is_selected = matches!(channel_selection,
    Some(selection::Channel{ ix: selected_ix, .. }) if &ix == selected_ix
    [69.6614]
    [69.6758]
    let is_selected = matches!(selection,
    selection::Unified::Channel(Some(selection::Channel{ ix: selected_ix, .. })) if &ix == selected_ix
  • replacement in inflorescence_view/src/app.rs at line 633
    [69.6931][69.6931:7009](),[69.7009][70.3053:3202](),[70.3202][69.7083:7246](),[69.7083][69.7083:7246](),[69.7246][70.3203:3286](),[70.3286][69.7262:7272](),[69.7262][69.7262:7272](),[69.7272][73.11710:12199]()
    let main = if *switching_channel {
    if other_channels.is_empty() {
    el(column([el(text(format!("Current channel: {channel}")))])
    .width(Length::Fill)
    .height(Length::Fill))
    } else {
    el(column([
    el(text(format!("Current channel: {channel}. Switch to:"))),
    el(column(view_channels())),
    ])
    .width(Length::Fill)
    .height(Length::Fill))
    }
    } else if let Some(EntireLog::Loading) = entire_log.as_ref() {
    el(column([
    view_repo_info(),
    el(text("Entire log")),
    el(text("Loading...")),
    ])
    .width(Length::Fill)
    .height(Length::Fill))
    } else if let Some(EntireLog::Got { .. }) = entire_log.as_ref() {
    if let Some(entire_log_col_2) = entire_log_col_2() {
    let cols =
    [entire_log_col_0(), entire_log_col_1(), entire_log_col_2]
    [69.6931]
    [73.12199]
    let main = match selection {
    selection::Unified::Status(_) => {
    if let Some(status_col_2) = status_col_2() {
    let cols = [status_col_0(), status_col_1(), status_col_2]
  • replacement in inflorescence_view/src/app.rs at line 639
    [73.12272][73.12272:12331]()
    el(row(cols)
    .spacing(SPACING)
    [73.12272]
    [73.12331]
    el(row(cols)
    .spacing(SPACING)
    .width(Length::Fill)
    .height(Length::Fill))
    } else {
    let cols = [status_col_0(), status_col_1()];
    el(row(cols)
    .spacing(SPACING)
    .width(Length::Fill)
    .height(Length::Fill))
    }
    }
    selection::Unified::Channel(_) => {
    if other_channels.is_empty() {
    el(column([el(text(format!("Current channel: {channel}")))])
    .width(Length::Fill)
    .height(Length::Fill))
    } else {
    let nav = nav_scrollable(
    &navigation.other_channels_nav,
    view_channels(),
    )
    .class(if other_channels_selected() {
    theme::Scrollable::Selected
    } else {
    theme::Scrollable::Normal
    })
  • replacement in inflorescence_view/src/app.rs at line 667
    [73.12368][73.12368:12548]()
    .height(Length::Fill))
    } else {
    let cols = [entire_log_col_0(), entire_log_col_1()];
    el(row(cols)
    .spacing(SPACING)
    [73.12368]
    [73.12548]
    .height(Length::Fill);
    el(column([
    el(text(format!("Current channel: {channel}"))),
    el(nav),
    ])
  • edit in inflorescence_view/src/app.rs at line 674
    [73.12624]
    [73.12624]
    }
  • replacement in inflorescence_view/src/app.rs at line 676
    [73.12634][73.12634:12813](),[73.12813][67.1720:1771](),[48.3959][67.1720:1771]()
    } else if let Some(status_col_2) = status_col_2() {
    let cols = [status_col_0(), status_col_1(), status_col_2]
    .into_iter()
    .skip(hidden_cols);
    el(row(cols)
    .spacing(SPACING)
    [73.12634]
    [67.1771]
    selection::Unified::EntireLog(_) => match logs.entire_log.as_ref() {
    None | Some(Log::Loading) => el(column([
    view_repo_info(),
    el(text("Entire log")),
    el(text("Loading...")),
    ])
  • replacement in inflorescence_view/src/app.rs at line 683
    [67.1804][67.1804:1839](),[67.1839][48.3998:4011](),[48.3998][48.3998:4011](),[48.4011][73.12814:12867](),[73.12867][67.1840:1959](),[48.4046][67.1840:1959]()
    .height(Length::Fill))
    } else {
    let cols = [status_col_0(), status_col_1()];
    el(row(cols)
    .spacing(SPACING)
    .width(Length::Fill)
    .height(Length::Fill))
    [67.1804]
    [67.1959]
    .height(Length::Fill)),
    Some(Log::Loaded { .. }) => {
    if let Some(entire_log_col_2) = entire_log_col_2() {
    let cols = [
    entire_log_col_0(),
    entire_log_col_1(),
    entire_log_col_2,
    ]
    .into_iter()
    .skip(hidden_cols);
    el(row(cols)
    .spacing(SPACING)
    .width(Length::Fill)
    .height(Length::Fill))
    } else {
    let cols = [entire_log_col_0(), entire_log_col_1()];
    el(row(cols)
    .spacing(SPACING)
    .width(Length::Fill)
    .height(Length::Fill))
    }
    }
    },
  • replacement in inflorescence_view/src/app.rs at line 709
    [70.3334][70.3334:3407]()
    let actions_inner = if let Some(forking_channel) = forking_channel {
    [70.3334]
    [70.3407]
    let actions_inner = if let Some(forking_channel) = forking_channel_name {
  • replacement in inflorescence_view/src/app.rs at line 716
    [70.3621][70.3621:3691](),[70.3691][69.7364:7451](),[69.7364][69.7364:7451](),[69.7451][73.12868:12898](),[73.12898][70.3692:3701](),[69.7451][70.3692:3701]()
    let actions_inner = actions_inner.push(view_actions(action_state(
    repo,
    record_msg,
    status_selection,
    channel_selection,
    entire_log_selection,
    )));
    [70.3621]
    [67.2048]
    let actions_inner = actions_inner.push(view_actions(action_state(state)));
  • edit in inflorescence_view/src/app.rs at line 724
    [67.2274]
    [32.24344]
    }
    #[derive(Debug, Clone)]
    pub enum Msg {
    Confirm,
    Cancel,
    Selection(selection::Msg),
    ToRepo(repo::MsgIn),
    EditRecordMsg(text_editor::Action),
    PostponeRecord,
    SaveRecord,
    DiscardRecord,
    AddUntrackedFile,
    RmAddedFile,
    StartRecord,
    /// Show a list of channels to switch to
    SelectChannel,
    ForkChannel,
    ForkChannelName(String),
    RefreshRepo,
    ShowEntireLog,
  • replacement in inflorescence_view/src/app.rs at line 818
    [76.361][71.1259:1360](),[71.1259][71.1259:1360]()
    let cant_confirm_already_exists =
    || el(action_button_inner("Enter", "already exists"));
    [76.361]
    [71.1360]
    let cant_confirm =
    |label: &'static str| el(action_button_inner("Enter", label));
  • replacement in inflorescence_view/src/app.rs at line 875
    [67.5571][69.8662:8724]()
    ActionState::SwitchingChannel(state) => match state {
    [67.5571]
    [69.8724]
    ActionState::SelectingChannel(state) => match state {
  • edit in inflorescence_view/src/app.rs at line 882
    [76.874]
    [76.874]
    let row = add_if(
    !can_switch,
    || cant_confirm("cannot switch with unrecorded changes"),
    row,
    );
  • replacement in inflorescence_view/src/app.rs at line 894
    [76.1057][71.1426:1499](),[70.4747][71.1426:1499]()
    let row = add_if(!unique, cant_confirm_already_exists, row);
    [76.1057]
    [73.13180]
    let row =
    add_if(!unique, || cant_confirm("channel already exists"), row);
  • replacement in inflorescence_view/src/app.rs at line 957
    [67.6028][69.9097:9142]()
    SwitchingChannel(SwitchingChannelState),
    [67.6028]
    [70.5399]
    SelectingChannel(SwitchingChannelState),
  • replacement in inflorescence_view/src/app.rs at line 987
    [67.6142][67.6142:6222](),[67.6222][69.9241:9347](),[69.9347][73.14120:14178](),[69.9347][67.6260:6279](),[73.14178][67.6260:6279](),[67.6260][67.6260:6279]()
    fn action_state<'a>(
    repo: &'a Repo,
    record_msg: Option<&'a RecordMsg>,
    status_selection: Option<StatusSelection<'a>>,
    channel_selection: Option<&'a selection::Channel>,
    entire_log_selection: Option<EntireLogSelection<'a>>,
    ) -> ActionState {
    [67.6142]
    [67.6279]
    fn action_state<'a>(state: &'a ReadyState) -> ActionState {
    let ReadyState {
    user_id: _,
    repo:
    repo::State {
    dir_name: _,
    channel,
    other_channels,
    untracked_files: _,
    changed_files,
    short_log: _,
    },
    selection,
    navigation,
    record_msg,
    forking_channel_name,
    logs: _,
    } = state;
    let selection::State {
    primary,
    status: status_selection,
    channel: channel_selection,
    entire_log: entire_log_selection,
    held_key: _,
    } = selection;
  • replacement in inflorescence_view/src/app.rs at line 1018
    [69.9355][69.9355:9552](),[69.9552][76.1208:1342](),[76.1342][69.9605:9741](),[69.9605][69.9605:9741](),[69.9741][67.6425:6431](),[67.6425][67.6425:6431](),[67.6431][32.24508:24509](),[32.24508][32.24508:24509](),[32.24509][70.5471:5527]()
    if repo.switching_channel {
    let sub_state = if repo.state.other_channels.is_empty() {
    SwitchingChannelState::NoOtherChannels
    } else if channel_selection.is_some() {
    let can_switch = repo.state.changed_files.is_empty();
    SwitchingChannelState::SomethingSelected { can_switch }
    } else {
    SwitchingChannelState::NothingSelected
    };
    return ActionState::SwitchingChannel(sub_state);
    }
    if let Some(name) = repo.forking_channel.as_ref() {
    [69.9355]
    [70.5527]
    if let Some(name) = forking_channel_name.as_ref() {
  • replacement in inflorescence_view/src/app.rs at line 1021
    [70.5596][70.5596:5671]()
    let unique = !repo.state.other_channels.iter().any(|n| n == name);
    [70.5596]
    [70.5671]
    let unique =
    channel != name && !other_channels.iter().any(|n| n == name);
  • replacement in inflorescence_view/src/app.rs at line 1026
    [70.5740][73.14179:14560]()
    if let Some(EntireLogSelection { file, nav, .. }) = entire_log_selection {
    return match file {
    Some(LogChangeFileSelection {
    ix: _,
    path: _,
    diff,
    }) => {
    if let Some(diff) = diff {
    if diff.is_selected {
    ActionState::EntireLogChangeDiff
    [70.5740]
    [73.14560]
    match primary {
    selection::Primary::Status => {
    let can_record = !changed_files.is_empty();
    let has_other_channels = !other_channels.is_empty();
    match status_selection {
    Some(selection::Status::UntrackedFile {
    ix: _,
    path,
    diff_selected,
    }) => {
    let id_hash =
    file::id_parts_hash(path, file::Kind::Untracked);
    let nav = get_files_diffs_nav(navigation, id_hash);
    if let Some(nav) = nav {
    if *diff_selected {
    ActionState::Diff {
    can_record,
    has_other_channels,
    }
    } else {
    ActionState::Main {
    selection: MainSelection::Untracked,
    can_select_right:
    nav_scrollable::needs_scrolling(nav),
    can_record,
    has_other_channels,
    }
    }
  • replacement in inflorescence_view/src/app.rs at line 1056
    [73.14589][73.14589:14644](),[73.14644][75.4284:4405](),[75.4405][73.14827:14858](),[73.14827][73.14827:14858]()
    ActionState::EntireLogChange {
    can_select_right: nav_scrollable::needs_scrolling(
    diff.nav,
    ),
    [73.14589]
    [73.14858]
    ActionState::Main {
    selection: MainSelection::Untracked,
    can_select_right: false,
    can_record,
    has_other_channels,
  • edit in inflorescence_view/src/app.rs at line 1063
    [73.14906][73.14906:15053]()
    } else {
    ActionState::EntireLogChange {
    can_select_right: false,
    }
  • replacement in inflorescence_view/src/app.rs at line 1064
    [73.15071][73.15071:15130](),[73.15130][75.4406:4544](),[75.4544][73.15205:15238](),[73.15205][73.15205:15238](),[70.5740][67.6432:6491](),[73.15238][67.6432:6491](),[32.24509][67.6432:6491](),[67.6491][76.1343:1411](),[76.1411][67.6491:6492](),[67.6491][67.6491:6492](),[67.6492][69.9742:9817](),[69.9817][67.6554:6705](),[67.6554][67.6554:6705](),[67.6705][76.1412:1532]()
    }
    None => ActionState::EntireLog {
    can_select_right: nav
    .map(nav_scrollable::needs_scrolling)
    .unwrap_or_default(),
    },
    };
    }
    let can_record = !repo.state.changed_files.is_empty();
    let has_other_channels = !repo.state.other_channels.is_empty();
    match status_selection {
    Some(StatusSelection::UntrackedFile {
    ix: _,
    path: _,
    diff,
    }) => {
    if let Some(diff) = diff {
    if diff.is_selected {
    ActionState::Diff {
    can_record,
    has_other_channels,
    [73.15071]
    [76.1532]
    Some(selection::Status::ChangedFile {
    ix: _,
    path,
    diff_selected,
    }) => {
    let is_added_from_untracked = changed_files
    .get(path)
    .map(|diffs| {
    diffs.iter().any(|diff| {
    matches!(diff, repo::ChangedFileDiff::Add)
    })
    })
    .unwrap_or_default();
    let main_selection = || {
    if is_added_from_untracked {
    MainSelection::AddedFromUntracked
    } else {
    MainSelection::Other
    }
    };
    let id_hash =
    file::id_parts_hash(path, file::Kind::Changed);
    let nav = get_files_diffs_nav(navigation, id_hash);
    if let Some(nav) = nav {
    if *diff_selected {
    ActionState::Diff {
    can_record,
    has_other_channels,
    }
    } else {
    ActionState::Main {
    selection: main_selection(),
    can_select_right:
    nav_scrollable::needs_scrolling(nav),
    can_record,
    has_other_channels,
    }
    }
    } else {
    ActionState::Main {
    selection: main_selection(),
    can_select_right: false,
    can_record,
    has_other_channels,
    }
  • replacement in inflorescence_view/src/app.rs at line 1110
    [76.1554][67.6758:6884](),[67.6758][67.6758:6884](),[67.6884][75.4545:4658](),[75.4658][67.7055:7118](),[67.7055][67.7055:7118](),[67.7118][76.1555:1599]()
    } else {
    ActionState::Main {
    selection: MainSelection::Untracked,
    can_select_right: nav_scrollable::needs_scrolling(
    diff.nav,
    ),
    can_record,
    has_other_channels,
    [76.1554]
    [67.7118]
    }
    Some(selection::Status::LogChange(selection::LogChange {
    ix: _,
    hash,
    message: _,
    file,
    })) => {
    let nav = get_status_log_files_nav(navigation, *hash);
    match file {
    Some(selection::LogChangeFileSelection {
    ix: _,
    path: _,
    diff_selected,
    }) => {
    if let Some(nav) = nav {
    if *diff_selected {
    ActionState::Diff {
    can_record,
    has_other_channels,
    }
    } else {
    ActionState::LogChange {
    can_select_right:
    nav_scrollable::needs_scrolling(nav),
    can_record,
    has_other_channels,
    }
    }
    } else {
    ActionState::LogChange {
    can_select_right: false,
    can_record,
    has_other_channels,
    }
    }
    }
    None => ActionState::Main {
    selection: MainSelection::Other,
    can_select_right: nav
    .map(nav_scrollable::needs_scrolling)
    .unwrap_or_default(),
    can_record,
    has_other_channels,
    },
  • replacement in inflorescence_view/src/app.rs at line 1156
    [67.7158][67.7158:7272]()
    } else {
    ActionState::Main {
    selection: MainSelection::Untracked,
    [67.7158]
    [67.7272]
    None => ActionState::Main {
    selection: MainSelection::Other,
  • replacement in inflorescence_view/src/app.rs at line 1161
    [76.1640][67.7349:7367](),[67.7349][67.7349:7367]()
    }
    [76.1640]
    [67.7367]
    },
  • replacement in inflorescence_view/src/app.rs at line 1164
    [67.7391][69.9818:9862](),[69.9862][67.7429:7761](),[67.7429][67.7429:7761]()
    Some(StatusSelection::ChangedFile {
    ix: _,
    path: _,
    diff,
    is_added_from_untracked,
    }) => {
    let main_selection = || {
    if is_added_from_untracked {
    MainSelection::AddedFromUntracked
    } else {
    MainSelection::Other
    }
    [67.7391]
    [67.7761]
    selection::Primary::Channel => {
    let sub_state = if other_channels.is_empty() {
    SwitchingChannelState::NoOtherChannels
    } else if channel_selection.is_some() {
    let can_switch = changed_files.is_empty();
    SwitchingChannelState::SomethingSelected { can_switch }
    } else {
    SwitchingChannelState::NothingSelected
  • replacement in inflorescence_view/src/app.rs at line 1173
    [67.7776][67.7776:7853](),[67.7853][76.1641:1783](),[76.1783][67.7906:8024](),[67.7906][67.7906:8024](),[67.8024][75.4659:4772](),[75.4772][67.8195:8258](),[67.8195][67.8195:8258](),[67.8258][76.1784:1828]()
    if let Some(diff) = diff {
    if diff.is_selected {
    ActionState::Diff {
    can_record,
    has_other_channels,
    }
    } else {
    ActionState::Main {
    selection: main_selection(),
    can_select_right: nav_scrollable::needs_scrolling(
    diff.nav,
    ),
    can_record,
    has_other_channels,
    [67.7776]
    [67.8258]
    return ActionState::SelectingChannel(sub_state);
    }
    selection::Primary::EntireLog => {
    if let Some(selection::LogChange { hash, file, .. }) =
    entire_log_selection
    {
    let nav = get_entire_log_files_nav(navigation, *hash);
    return match file {
    Some(selection::LogChangeFileSelection {
    ix: _,
    path: _,
    diff_selected,
    }) => {
    if let Some(nav) = nav {
    if *diff_selected {
    ActionState::EntireLogChangeDiff
    } else {
    ActionState::EntireLogChange {
    can_select_right:
    nav_scrollable::needs_scrolling(nav),
    }
    }
    } else {
    ActionState::EntireLogChange {
    can_select_right: false,
    }
    }
  • replacement in inflorescence_view/src/app.rs at line 1201
    [67.8280][67.8280:8298]()
    }
    [67.8280]
    [67.8298]
    None => ActionState::EntireLog {
    can_select_right: nav
    .map(nav_scrollable::needs_scrolling)
    .unwrap_or_default(),
    },
    };
  • replacement in inflorescence_view/src/app.rs at line 1208
    [67.8319][67.8319:8404]()
    ActionState::Main {
    selection: main_selection(),
    [67.8319]
    [67.8404]
    ActionState::EntireLog {
  • edit in inflorescence_view/src/app.rs at line 1210
    [67.8449][67.8449:8481](),[67.8481][76.1829:1869]()
    can_record,
    has_other_channels,
  • edit in inflorescence_view/src/app.rs at line 1213
    [67.8523][69.9863:9899](),[69.9899][67.8553:8896](),[67.8553][67.8553:8896](),[67.8896][76.1870:2028](),[76.2028][67.8953:9031](),[67.8953][67.8953:9031](),[67.9031][75.4773:4894](),[75.4894][67.9214:9285](),[67.9214][67.9214:9285](),[67.9285][76.2029:2077](),[76.2077][67.9285:9488](),[67.9285][67.9285:9488](),[67.9488][76.2078:2122](),[76.2122][67.9488:9631](),[67.9488][67.9488:9631](),[67.9631][75.4895:5033](),[75.5033][67.9706:9734](),[67.9706][67.9706:9734](),[67.9734][76.2123:2159](),[76.2159][67.9734:9902](),[67.9734][67.9734:9902](),[67.9902][76.2160:2192](),[76.2192][67.9902:9913](),[67.9902][67.9902:9913]()
    Some(StatusSelection::Log {
    ix: _,
    hash: _,
    message: _,
    file,
    nav,
    }) => match file {
    Some(LogChangeFileSelection {
    ix: _,
    path: _,
    diff,
    }) => {
    if let Some(diff) = diff {
    if diff.is_selected {
    ActionState::Diff {
    can_record,
    has_other_channels,
    }
    } else {
    ActionState::LogChange {
    can_select_right: nav_scrollable::needs_scrolling(
    diff.nav,
    ),
    can_record,
    has_other_channels,
    }
    }
    } else {
    ActionState::LogChange {
    can_select_right: false,
    can_record,
    has_other_channels,
    }
    }
    }
    None => ActionState::Main {
    selection: MainSelection::Other,
    can_select_right: nav
    .map(nav_scrollable::needs_scrolling)
    .unwrap_or_default(),
    can_record,
    has_other_channels,
    },
    },
    None => ActionState::Main {
    selection: MainSelection::Other,
    can_select_right: false,
    can_record,
    has_other_channels,
    },
  • replacement in inflorescence_view/src/app/test.rs at line 62
    [69.10085][74.522:553]()
    forking_channel: None,
    [69.10085]
    [74.553]
    forking_channel_name: None,
  • replacement in inflorescence_view/src/app/test.rs at line 106
    [74.651][74.651:682]()
    forking_channel: None,
    [74.651]
    [74.682]
    forking_channel_name: None,
  • edit in inflorescence_view/Cargo.toml at line 19
    [30.552]
    [30.552]
    [dependencies.inflorescence-model]
    workspace = true
  • file addition: inflorescence_model (d--r------)
    [2.2]
  • file addition: src (d--r------)
    [0.29594]
  • file move: selection.rs (----------)selection.rs (----------)
    [0.29627]
    [35.3124]
  • edit in inflorescence_model/src/selection.rs at line 27
    [35.3348]
    [69.2742]
    /// Primary selection state. This is distinct from `status`, `channel`,
    /// `entire_log` sub-states fields to which each case corresponds, because
    /// they are preserved in different primary selection states.
    pub primary: Primary,
    /// Sub-selection in [`Primary::Status`] state
  • edit in inflorescence_model/src/selection.rs at line 33
    [69.2774]
    [69.2774]
    /// Sub-selection in [`Primary::Channel`] state
  • edit in inflorescence_model/src/selection.rs at line 35
    [69.2808]
    [73.503]
    /// Sub-selection in [`Primary::EntireLog`] state
  • edit in inflorescence_model/src/selection.rs at line 37
    [73.542]
    [55.359]
    /// Last directional key down that's not yet been released
    pub held_key: Option<HeldKey>,
    }
    #[derive(Debug)]
    pub enum Unified<'a> {
    Status(Option<&'a Status>),
    Channel(Option<&'a Channel>),
    EntireLog(Option<&'a LogChange>),
    }
    #[derive(Debug, Default, Clone, Copy)]
    pub enum Primary {
    #[default]
    Status,
    Channel,
    EntireLog,
  • edit in inflorescence_model/src/selection.rs at line 109
    [69.2915]
    [69.2915]
    pub log: Option<LogChange>,
  • edit in inflorescence_model/src/selection.rs at line 118
    [73.751]
    [73.751]
    }
    pub fn unify(state: &State) -> Unified<'_> {
    let State {
    primary,
    status,
    channel,
    entire_log,
    held_key: _,
    } = state;
    match primary {
    Primary::Status => Unified::Status(status.as_ref()),
    Primary::Channel => Unified::Channel(channel.as_ref()),
    Primary::EntireLog => Unified::EntireLog(entire_log.as_ref()),
    }
  • file addition: log.rs (----------)
    [0.29627]
    use crate::diff;
    use iced_expl_widget::nav_scrollable;
    use libflorescence::{file, repo};
    use std::collections::HashSet;
    #[derive(Debug, Default)]
    pub struct FilesAndState {
    /// All the hashes in this set have `diffs` loaded.
    pub changes_with_loaded_diffs: HashSet<repo::ChangeHash>,
    /// All the diffs in this map have the change hash present in
    /// `change_with_loaded_diffs`
    pub diffs: file::LogIdMap<diff::FileAndState>,
    }
    #[derive(Debug, Default)]
    pub struct Navs {
    /// Log change's files scrollable nav. Only the currently selected nav is
    /// kept.
    pub files_nav: Option<(repo::ChangeHash, nav_scrollable::State)>,
    /// Log file's diffs scrollable nav. Only the currently selected nav is
    /// kept.
    pub diffs_nav: Option<(file::LogIdHash, nav_scrollable::State)>,
    }
  • file addition: lib.rs (----------)
    [0.29627]
    pub mod diff;
    pub mod log;
    pub mod selection;
    use iced_expl_widget::nav_scrollable;
    use libflorescence::identity::Id;
    use libflorescence::{file, repo};
    use iced::widget::text_editor;
    use std::collections::HashMap;
    use std::path::PathBuf;
    pub fn ready(state: &State) -> Option<&ReadyState> {
    if let SubState::Ready(state) = &state.sub {
    return Some(state);
    }
    None
    }
    pub fn ready_mut(state: &mut State) -> Option<&mut ReadyState> {
    if let SubState::Ready(state) = &mut state.sub {
    return Some(state);
    }
    None
    }
    #[derive(Debug)]
    pub struct State {
    pub window_size: iced::Size,
    pub repo_path: PathBuf,
    pub sub: SubState,
    }
    #[derive(Debug)]
    pub enum SubState {
    Loading {
    user_ids: Vec<Id>,
    repo: Option<repo::State>,
    },
    SelectingId {
    user_ids: Vec<Id>,
    user_selection_ix: usize,
    user_selection_nav: nav_scrollable::State,
    repo: Option<repo::State>,
    },
    Ready(ReadyState),
    }
    #[derive(Debug)]
    pub struct ReadyState {
    pub user_id: Id,
    pub repo: repo::State,
    pub selection: selection::State,
    pub navigation: Navigation,
    pub record_msg: Option<RecordMsg>,
    /// `Some` when we're writing a name of the new channel forked from current
    pub forking_channel_name: Option<String>,
    pub logs: Logs,
    }
    #[derive(Debug)]
    pub enum RecordMsg {
    Typing(text_editor::Content),
    Canceled { old_msg: String },
    }
    #[derive(Debug, Default)]
    pub struct Navigation {
    /// Scrollable status view contains the overview of untracked files,
    /// changed files and most recent log changes
    pub status_nav: nav_scrollable::State,
    /// Logs shown in the status view.
    pub status_logs_navs: log::Navs,
    /// Other channels selection's nav
    pub other_channels_nav: nav_scrollable::State,
    /// Navs for a log of selected channel other than the current
    pub other_channel_log_navs: Option<(String, log::Navs)>,
    /// Entire log's change selection nav
    pub entire_log_nav: nav_scrollable::State,
    /// Logs for the entire log
    pub entire_logs_navs: log::Navs,
    /// Diffs for untracked and changed files shown in status view
    pub files_diffs: diff::FilesState,
    /// Diffs of status log changes, entire log changes and other channels'
    /// logs
    pub log_diffs: log::FilesAndState,
    }
    #[derive(Debug, Default)]
    pub struct Logs {
    /// Populated when requested to look at the entire log of changes
    pub entire_log: Option<Log>,
    /// Keys are channel names
    pub other_channels_logs: HashMap<String, Log>,
    }
    #[derive(Debug)]
    pub enum Log {
    Loading,
    Loaded { log: repo::Log },
    }
    /// Get untracked or changes files diff's nav if it matches given file ID
    pub fn get_files_diffs_nav(
    navigation: &Navigation,
    id_hash: file::IdHash,
    ) -> Option<&nav_scrollable::State> {
    navigation
    .files_diffs
    .diffs_nav
    .as_ref()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    }
    /// Get untracked or changes files diff's nav if it matches given file ID
    pub fn get_files_diffs_nav_mut(
    navigation: &mut Navigation,
    id_hash: file::IdHash,
    ) -> Option<&mut nav_scrollable::State> {
    navigation
    .files_diffs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    }
    /// Get status log files nav if it matches given change hash
    pub fn get_status_log_files_nav(
    navigation: &Navigation,
    hash: repo::ChangeHash,
    ) -> Option<&nav_scrollable::State> {
    navigation
    .status_logs_navs
    .files_nav
    .as_ref()
    .and_then(|(nav_hash, nav)| (*nav_hash == hash).then_some(nav))
    }
    /// Get status log files nav if it matches given change hash
    pub fn get_status_log_files_nav_mut(
    navigation: &mut Navigation,
    hash: repo::ChangeHash,
    ) -> Option<&mut nav_scrollable::State> {
    navigation
    .status_logs_navs
    .files_nav
    .as_mut()
    .and_then(|(nav_hash, nav)| (*nav_hash == hash).then_some(nav))
    }
    /// Get status log diffs nav if it matches given log file ID
    pub fn get_status_log_diffs_nav(
    navigation: &Navigation,
    id_hash: file::LogIdHash,
    ) -> Option<&nav_scrollable::State> {
    navigation
    .status_logs_navs
    .diffs_nav
    .as_ref()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    }
    /// Get status log diffs nav if it matches given log file ID
    pub fn get_status_log_diffs_nav_mut(
    navigation: &mut Navigation,
    id_hash: file::LogIdHash,
    ) -> Option<&mut nav_scrollable::State> {
    navigation
    .status_logs_navs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    }
    /// Get entire log files nav if it matches given change hash
    pub fn get_entire_log_files_nav(
    navigation: &Navigation,
    hash: repo::ChangeHash,
    ) -> Option<&nav_scrollable::State> {
    navigation
    .entire_logs_navs
    .files_nav
    .as_ref()
    .and_then(|(nav_hash, nav)| (*nav_hash == hash).then_some(nav))
    }
    /// Get entire log files nav if it matches given change hash
    pub fn get_entire_log_files_nav_mut(
    navigation: &mut Navigation,
    hash: repo::ChangeHash,
    ) -> Option<&mut nav_scrollable::State> {
    navigation
    .entire_logs_navs
    .files_nav
    .as_mut()
    .and_then(|(nav_hash, nav)| (*nav_hash == hash).then_some(nav))
    }
    /// Get entire log diffs nav if it matches given log file ID
    pub fn get_entire_log_diffs_nav(
    navigation: &Navigation,
    id_hash: file::LogIdHash,
    ) -> Option<&nav_scrollable::State> {
    navigation
    .entire_logs_navs
    .diffs_nav
    .as_ref()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    }
    /// Get entire log diffs nav if it matches given log file ID
    pub fn get_entire_log_diffs_nav_mut(
    navigation: &mut Navigation,
    id_hash: file::LogIdHash,
    ) -> Option<&mut nav_scrollable::State> {
    navigation
    .entire_logs_navs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    }
  • file addition: diff.rs (----------)
    [0.29627]
    #[doc(inline)]
    pub use libflorescence::diff::{
    contents_to_lines, Combined, DecodedFile, DiffWithContents,
    DiffWithoutContents, File, FileContent, Lines, Section,
    UndecodableContents, UndecodableFile,
    };
    use iced_expl_widget::nav_scrollable;
    use libflorescence::file;
    #[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, Default)]
    pub struct FilesState {
    pub diffs: file::IdMap<State>,
    /// Diffs scrollable nav.
    ///
    /// Only the current nav is kept because the sizes of contents have to be
    /// queried everytime the selection changes due to possible container size
    /// changes.
    pub diffs_nav: Option<(file::IdHash, nav_scrollable::State)>,
    }
    #[derive(Debug)]
    pub struct FileAndState {
    pub file: File,
    pub state: State,
    }
  • file addition: Cargo.toml (----------)
    [0.29594]
    [package]
    name = "inflorescence-model"
    version.workspace = true
    edition.workspace = true
    license.workspace = true
    authors.workspace = true
    [dependencies]
    # Internal dependencies
    [dependencies.libflorescence]
    workspace = true
    [dependencies.iced-expl-widget]
    workspace = true
    # External dependencies
    [dependencies.iced]
    workspace = true
  • edit in inflorescence/src/selection.rs at line 1
    [5.26][75.5302:5340](),[75.5340][63.78:107](),[64.20708][63.78:107](),[5.26][63.78:107]()
    use iced_expl_widget::nav_scrollable;
    use inflorescence_view::app;
  • replacement in inflorescence/src/selection.rs at line 2
    [36.1961][69.13083:13124](),[69.13124][73.15954:16029](),[73.16029][69.13188:13220](),[69.13188][69.13188:13220]()
    pub use inflorescence_view::selection::{
    Channel, Dir, HeldKey, LogChange, LogChangeFileSelection, Msg, Select,
    State as ViewState, Status,
    [36.1961]
    [32.29306]
    pub use inflorescence_model::selection::{
    unify, Channel, Dir, HeldKey, LogChange, LogChangeFileSelection, Msg,
    Primary, Select, State, Status, Unified,
  • replacement in inflorescence/src/selection.rs at line 7
    [37.5795][29.8494:8519](),[32.29310][29.8494:8519](),[5.26][29.8494:8519]()
    use crate::{diff, file};
    [32.29310]
    [55.4188]
    use crate::{diff, file, log};
    use iced_expl_widget::nav_scrollable;
    use inflorescence_model::{
    get_entire_log_diffs_nav_mut, get_entire_log_files_nav_mut,
    get_files_diffs_nav_mut, get_status_log_diffs_nav_mut,
    get_status_log_files_nav_mut, Log, Logs, Navigation,
    };
    use inflorescence_view::app;
  • replacement in inflorescence/src/selection.rs at line 22
    [65.824][65.824:992]()
    #[derive(Debug, Default)]
    pub struct State {
    pub view: ViewState,
    /// Last directional key down that's not yet been released
    pub held_key: Option<HeldKey>,
    [65.824]
    [65.992]
    /// Hot potato
    pub struct Ctx<'a> {
    pub state: &'a mut State,
    pub files: &'a mut file::State,
    pub navigation: &'a mut Navigation,
    pub repo: &'a repo::State,
    pub logs: &'a Logs,
  • replacement in inflorescence/src/selection.rs at line 35
    [29.8608][55.4269:4309](),[55.4309][73.16030:16122](),[73.16122][63.108:142](),[64.20796][63.108:142](),[55.4353][63.108:142]()
    files_diffs: &mut diff::FilesState,
    status_logs: &mut diff::LogFilesAndState,
    entire_logs: &mut diff::LogFilesAndState,
    repo: Option<&mut app::Repo>,
    [29.8608]
    [64.20797]
    navigation: &mut Navigation,
    repo: &repo::State,
    logs: &Logs,
  • edit in inflorescence/src/selection.rs at line 39
    [64.20821]
    [28.2479]
    let mut ctx = Ctx {
    state,
    files,
    navigation,
    repo,
    logs,
    };
    let mctx = &mut ctx;
  • replacement in inflorescence/src/selection.rs at line 51
    [56.2179][56.2179:2229]()
    state.held_key.as_ref().and_then(
    [56.2179]
    [56.2229]
    mctx.state.held_key.as_ref().and_then(
  • replacement in inflorescence/src/selection.rs at line 68
    [56.2885][55.4999:5043](),[55.4999][55.4999:5043]()
    state.held_key = Some(HeldKey {
    [56.2885]
    [55.5043]
    mctx.state.held_key = Some(HeldKey {
  • replacement in inflorescence/src/selection.rs at line 74
    [55.5148][73.16245:16775](),[73.16775][63.143:209](),[55.5508][63.143:209](),[63.209][73.16776:17002]()
    Dir::Down => select_down(
    state,
    files,
    files_diffs,
    status_logs,
    entire_logs,
    repo,
    delta,
    ),
    Dir::Up => select_up(
    state,
    files,
    files_diffs,
    status_logs,
    entire_logs,
    repo,
    delta,
    ),
    Dir::Left => select_left(state, repo.as_deref()),
    Dir::Right => select_right(
    state,
    files_diffs,
    status_logs,
    entire_logs,
    repo.as_deref(),
    ),
    [55.5148]
    [55.5644]
    Dir::Down => select_down(mctx, delta),
    Dir::Up => select_up(mctx, delta),
    Dir::Left => select_left(mctx),
    Dir::Right => select_right(mctx),
  • replacement in inflorescence/src/selection.rs at line 80
    [55.5668][73.17003:17082]()
    Msg::ReleaseDir(dir) => release(dir, state, files_diffs, status_logs),
    [55.5668]
    [56.2886]
    Msg::ReleaseDir(dir) => release(dir, mctx),
  • replacement in inflorescence/src/selection.rs at line 83
    [56.2947][56.2947:2997]()
    state.held_key.as_ref().and_then(
    [56.2947]
    [56.2997]
    mctx.state.held_key.as_ref().and_then(
  • replacement in inflorescence/src/selection.rs at line 100
    [56.3653][56.3653:3697]()
    state.held_key = Some(HeldKey {
    [56.3653]
    [56.3697]
    mctx.state.held_key = Some(HeldKey {
  • replacement in inflorescence/src/selection.rs at line 106
    [56.3802][73.17083:17329]()
    Dir::Down => {
    alt_select_down(state, files_diffs, status_logs, delta)
    }
    Dir::Up => {
    alt_select_up(state, files_diffs, status_logs, delta)
    }
    [56.3802]
    [56.4005]
    Dir::Down => alt_select_down(mctx, delta),
    Dir::Up => alt_select_up(mctx, delta),
  • replacement in inflorescence/src/selection.rs at line 114
    [56.4164][63.341:444](),[63.444][75.5341:5359](),[75.5359][63.473:498](),[63.473][63.473:498](),[63.498][73.17330:17380](),[73.17380][63.521:532](),[64.21350][63.521:532](),[63.521][63.521:532]()
    Msg::Select(select) => select_exact(
    select,
    state,
    files,
    repo,
    files_diffs,
    status_logs,
    entire_logs,
    ),
    [56.4164]
    [54.21708]
    Msg::Select(select) => select_exact(select, mctx),
  • edit in inflorescence/src/selection.rs at line 117
    [54.22121][54.22121:22122](),[54.22122][64.21351:21367](),[64.21367][54.22772:22824](),[54.22772][54.22772:22824](),[63.567][55.5746:5786](),[54.22856][55.5746:5786](),[55.5786][73.17381:17473](),[73.17473][64.21368:21402](),[55.5825][64.21368:21402](),[64.21402][55.5825:5854](),[55.5825][55.5825:5854](),[55.5854][64.21403:21427](),[64.21427][63.568:640](),[54.22942][63.568:640](),[63.640][69.13221:13248](),[69.13248][70.5750:5778](),[70.5778][73.17474:17494](),[70.5778][63.640:665](),[69.13248][63.640:665](),[73.17494][63.640:665](),[63.640][63.640:665](),[63.665][59.82:118](),[59.82][59.82:118](),[59.118][69.13249:13770](),[69.13770][73.17495:17502](),[73.17502][75.5360:5434](),[75.5434][73.17576:18485](),[73.17576][73.17576:18485](),[73.18485][75.5435:5490](),[75.5490][73.18551:18762](),[73.18551][73.18551:18762](),[73.18762][75.5491:5616](),[75.5616][73.18942:18969](),[73.18942][73.18942:18969](),[73.18969][75.5617:5667](),[75.5667][73.19011:19440](),[73.19011][73.19011:19440]()
    fn select_down(
    state: &mut State,
    files: &mut file::State,
    files_diffs: &mut diff::FilesState,
    status_logs: &mut diff::LogFilesAndState,
    entire_logs: &mut diff::LogFilesAndState,
    repo: Option<&mut app::Repo>,
    delta: Option<Duration>,
    ) -> Task<crate::Msg> {
    let Some(app::Repo {
    state: repo_state,
    status_nav,
    switching_channel,
    forking_channel: _,
    entire_log,
    }) = repo
    else {
    return Task::none();
    };
    if *switching_channel {
    let channels = &repo_state.other_channels;
    let selection = match state.view.channel.take() {
    Some(Channel { ix, name: _ }) => {
    let ix = if ix == channels.len() - 1 { 0 } else { ix + 1 };
    channel_selection(ix, channels)
    }
    None => {
    let ix = 0;
    channel_selection(ix, channels)
    }
    };
    state.view.channel = Some(selection);
    return Task::none();
    }
    if let Some(app::EntireLog::Got { log, nav }) = entire_log.as_mut() {
    let (selection, task) = if let Some(LogChange {
    ix: log_ix,
    hash,
    message,
    file,
    }) = state.view.entire_log.take()
    {
    match file {
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected,
    }) => {
    if diff_selected {
    let id_hash = file::log_id_parts_hash(hash, &path);
    let selection = LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected,
    }),
    };
    if let Some(nav) = entire_logs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    })
    {
    nav_scrollable::scroll_down(nav, delta)
    };
    (selection, Task::none())
    } else {
    let log_entry = log.get(log_ix).unwrap();
    let file_ix =
    if log_entry.file_paths.len().saturating_sub(1)
    == file_ix
    {
    0
    } else {
    file_ix + 1
    };
  • replacement in inflorescence/src/selection.rs at line 118
    [73.19441][73.19441:19700](),[73.19700][75.5668:5792](),[75.5792][73.19842:19925](),[73.19842][73.19842:19925](),[73.19925][75.5793:5874](),[75.5874][73.20148:20412](),[73.20148][73.20148:20412](),[73.20412][75.5875:5927](),[75.5927][73.20492:21488](),[73.20492][73.20492:21488]()
    let (file, selection_task) = entire_log_file_selection(
    entire_logs,
    log_entry,
    hash,
    file_ix,
    );
    if let Some((nav_changes_hash, nav)) =
    entire_logs.changes_nav.as_mut()
    && *nav_changes_hash == hash
    {
    nav_scrollable::scroll_down_to_section(nav, file_ix)
    };
    let selection = LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(file),
    };
    (selection, selection_task)
    }
    }
    None => {
    if log.len().saturating_sub(1) == log_ix {
    let ix = 0;
    entire_log_selection(
    nav,
    entire_logs,
    log,
    ix,
    VertDir::Up,
    )
    } else {
    let ix = log_ix + 1;
    entire_log_selection(
    nav,
    entire_logs,
    log,
    ix,
    VertDir::Down,
    )
    }
    }
    }
    } else {
    let ix = 0;
    entire_log_selection(nav, entire_logs, log, ix, VertDir::Down)
    };
    state.view.entire_log = Some(selection);
    return task;
    [73.19441]
    [69.13770]
    fn select_down(ctx: &mut Ctx<'_>, delta: Option<Duration>) -> Task<crate::Msg> {
    match ctx.state.primary {
    Primary::Status => select_down_status(ctx, delta),
    Primary::Channel => select_down_channel(ctx),
    Primary::EntireLog => select_down_entire_log(ctx, delta),
  • edit in inflorescence/src/selection.rs at line 124
    [69.13776]
    [69.13776]
    }
  • replacement in inflorescence/src/selection.rs at line 126
    [69.13777][69.13777:13838]()
    let (selection, task) = match state.view.status.take() {
    [69.13777]
    [69.13838]
    fn select_down_status(
    ctx: &mut Ctx<'_>,
    delta: Option<Duration>,
    ) -> Task<crate::Msg> {
    let (selection, task) = match ctx.state.status.take() {
  • replacement in inflorescence/src/selection.rs at line 138
    [59.430][75.5928:6155]()
    if let Some(nav) = files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [59.430]
    [75.6155]
    if let Some(nav) =
    get_files_diffs_nav_mut(ctx.navigation, id_hash)
    {
  • replacement in inflorescence/src/selection.rs at line 151
    [59.941][63.666:747]()
    } else if repo_state.untracked_files.len().saturating_sub(1) == ix {
    [59.941]
    [63.747]
    } else if ctx.repo.untracked_files.len().saturating_sub(1) == ix {
  • replacement in inflorescence/src/selection.rs at line 153
    [63.795][63.795:853]()
    if !repo_state.changed_files.is_empty() {
    [63.795]
    [59.1068]
    if !ctx.repo.changed_files.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 155
    [59.1100][64.21676:21756](),[64.21756][63.1235:1271](),[63.1235][63.1235:1271](),[63.1271][64.21757:21914](),[64.21914][63.1332:1387](),[63.1332][63.1332:1387]()
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    )
    } else if !repo_state.log.is_empty() {
    [59.1100]
    [59.1272]
    changed_file_selection(ix, VDir::Down, ctx)
    } else if !ctx.repo.short_log.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 158
    [59.1304][73.21489:21531](),[73.21531][63.1658:1694](),[64.21950][63.1658:1694](),[63.1658][63.1658:1694](),[63.1694][73.21532:21569](),[73.21569][64.21981:22106](),[64.21981][64.21981:22106]()
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    )
    [59.1304]
    [54.24638]
    status_log_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 161
    [59.1397][64.22107:22189](),[64.22189][63.2159:2195](),[63.2159][63.2159:2195](),[63.2195][64.22190:22345]()
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [59.1397]
    [59.1398]
    untracked_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 165
    [59.1470][64.22346:22420](),[64.22420][63.2590:2622](),[63.2590][63.2590:2622](),[63.2622][64.22421:22558]()
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    )
    [59.1470]
    [59.1587]
    untracked_file_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 176
    [59.1897][75.6270:6497]()
    if let Some(nav) = files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [59.1897]
    [75.6497]
    if let Some(nav) =
    get_files_diffs_nav_mut(ctx.navigation, id_hash)
    {
  • replacement in inflorescence/src/selection.rs at line 189
    [59.2406][63.2676:2755]()
    } else if repo_state.changed_files.len().saturating_sub(1) == ix {
    [59.2406]
    [63.2755]
    } else if ctx.repo.changed_files.len().saturating_sub(1) == ix {
  • replacement in inflorescence/src/selection.rs at line 191
    [63.2801][63.2801:2849]()
    if !repo_state.log.is_empty() {
    [63.2801]
    [59.2521]
    if !ctx.repo.short_log.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 193
    [59.2553][73.21570:21612](),[73.21612][63.3120:3156](),[64.22842][63.3120:3156](),[63.3120][63.3120:3156](),[63.3156][73.21613:21650](),[73.21650][64.22873:22998](),[64.22873][64.22873:22998](),[64.22998][63.3237:3304](),[63.3237][63.3237:3304]()
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    )
    } else if !repo_state.untracked_files.is_empty() {
    [59.2553]
    [59.2674]
    status_log_selection(ix, VDir::Down, ctx)
    } else if !ctx.repo.untracked_files.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 196
    [59.2706][64.22999:23081](),[64.23081][63.3688:3724](),[63.3688][63.3688:3724](),[63.3724][64.23082:23237]()
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [59.2706]
    [54.26467]
    untracked_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 199
    [59.2864][64.23238:23318](),[64.23318][63.4165:4201](),[63.4165][63.4165:4201](),[63.4201][64.23319:23474]()
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [59.2864]
    [59.2865]
    changed_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 203
    [59.2937][64.23475:23547](),[64.23547][63.4592:4624](),[63.4592][63.4592:4624](),[63.4624][64.23548:23685]()
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    )
    [59.2937]
    [59.3052]
    changed_file_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 231
    [73.21812][75.6612:6667](),[75.6667][64.24172:24383](),[73.21878][64.24172:24383](),[64.24172][64.24172:24383](),[64.24383][75.6668:6725]()
    if let Some(nav) = status_logs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    })
    {
    [73.21812]
    [75.6725]
    if let Some(nav) = get_status_log_diffs_nav_mut(
    ctx.navigation,
    id_hash,
    ) {
  • replacement in inflorescence/src/selection.rs at line 239
    [59.4542][63.4678:4755]()
    let log_entry = repo_state.log.get(log_ix).unwrap();
    [59.4542]
    [28.7109]
    let log_entry = ctx.repo.short_log.get(log_ix).unwrap();
  • replacement in inflorescence/src/selection.rs at line 241
    [28.7110][59.4614:4652]()
    let file_ix =
    [28.7110]
    [59.4652]
    let (file_ix, dir) =
  • replacement in inflorescence/src/selection.rs at line 245
    [59.4801][59.4801:4835]()
    0
    [59.4801]
    [59.4835]
    (0, VDir::Up)
  • replacement in inflorescence/src/selection.rs at line 247
    [59.4872][59.4872:4916]()
    file_ix + 1
    [59.4872]
    [59.4916]
    (file_ix + 1, VDir::Down)
  • replacement in inflorescence/src/selection.rs at line 250
    [64.24634][73.21879:22066]()
    let (file, selection_task) = log_file_selection(
    status_logs,
    log_entry,
    hash,
    [64.24634]
    [73.22066]
    let (file, selection_task) = status_log_file_selection(
  • edit in inflorescence/src/selection.rs at line 252
    [73.22103]
    [73.22103]
    hash,
    dir,
    ctx.navigation,
    log_entry,
  • replacement in inflorescence/src/selection.rs at line 258
    [28.7559][75.6845:6969](),[75.6969][64.24903:24960](),[73.22192][64.24903:24960](),[64.24903][64.24903:24960]()
    if let Some((nav_changes_hash, nav)) =
    status_logs.changes_nav.as_mut()
    && *nav_changes_hash == hash
    [28.7559]
    [64.24960]
    if let Some(nav) =
    get_status_log_files_nav_mut(ctx.navigation, hash)
  • replacement in inflorescence/src/selection.rs at line 274
    [59.5418][63.4756:4830]()
    if repo_state.log.len().saturating_sub(1) == log_ix {
    [59.5418]
    [63.4830]
    if ctx.repo.short_log.len().saturating_sub(1) == log_ix {
  • replacement in inflorescence/src/selection.rs at line 276
    [63.4875][63.4875:4943]()
    if !repo_state.untracked_files.is_empty() {
    [63.4875]
    [63.4943]
    if !ctx.repo.untracked_files.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 278
    [63.4983][64.25565:25872](),[64.25872][63.5589:5692](),[63.5589][63.5589:5692]()
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    } else if !repo_state.changed_files.is_empty() {
    [63.4983]
    [63.5692]
    untracked_file_selection(ix, VDir::Up, ctx)
    } else if !ctx.repo.changed_files.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 281
    [63.5732][64.25873:26178](),[64.26178][63.6334:6364](),[63.6334][63.6334:6364]()
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [63.5732]
    [59.5973]
    changed_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 284
    [63.6405][73.22293:22343](),[73.22343][64.26222:26266](),[64.26222][64.26222:26266](),[64.26266][73.22344:22389](),[73.22389][64.26304:26459](),[64.26304][64.26304:26459]()
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Up,
    )
    [63.6405]
    [63.6922]
    status_log_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 288
    [63.7022][73.22390:22436](),[73.22436][63.7316:7356](),[64.26499][63.7316:7356](),[63.7316][63.7316:7356](),[63.7356][73.22437:22478](),[73.22478][64.26534:26675](),[64.26534][64.26534:26675]()
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    )
    [63.7022]
    [63.7445]
    status_log_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 295
    [59.6232][63.7468:7524]()
    if !repo_state.untracked_files.is_empty() {
    [59.6232]
    [59.6306]
    if !ctx.repo.untracked_files.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 297
    [59.6334][64.26676:26774](),[64.26774][63.7884:7916](),[63.7884][63.7884:7916](),[63.7916][64.26775:26894](),[64.26894][63.7916:7935](),[63.7916][63.7916:7935]()
    let (selection, task) = untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    );
    [59.6334]
    [64.26895]
    let (selection, task) =
    untracked_file_selection(ix, VDir::Down, ctx);
  • replacement in inflorescence/src/selection.rs at line 300
    [64.26935][63.7969:8030](),[63.7969][63.7969:8030]()
    } else if !repo_state.changed_files.is_empty() {
    [64.26935]
    [59.6512]
    } else if !ctx.repo.changed_files.is_empty() {
  • replacement in inflorescence/src/selection.rs at line 302
    [59.6540][64.26936:27032](),[64.27032][63.8386:8418](),[63.8386][63.8386:8418](),[63.8418][64.27033:27152](),[64.27152][63.8418:8437](),[63.8418][63.8418:8437]()
    let (selection, task) = changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    );
    [59.6540]
    [64.27153]
    let (selection, task) =
    changed_file_selection(ix, VDir::Down, ctx);
  • replacement in inflorescence/src/selection.rs at line 305
    [64.27193][63.8471:8573](),[63.8471][63.8471:8573](),[63.8573][73.22479:22541](),[73.22541][63.8787:8819](),[64.27249][63.8787:8819](),[63.8787][63.8787:8819](),[63.8819][73.22542:22575](),[73.22575][64.27276:27367](),[64.27276][64.27276:27367](),[64.27367][63.8819:8838](),[63.8819][63.8819:8838]()
    } else if !repo_state.log.is_empty() {
    let ix = repo_state.log.len() - 1;
    let (selection, task) = status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    );
    [64.27193]
    [63.8838]
    } else if !ctx.repo.short_log.is_empty() {
    let ix = ctx.repo.short_log.len() - 1;
    let (selection, task) =
    status_log_selection(ix, VDir::Down, ctx);
  • replacement in inflorescence/src/selection.rs at line 315
    [59.6976][69.14156:14191]()
    state.view.status = selection;
    [59.6976]
    [59.7009]
    ctx.state.status = selection;
  • replacement in inflorescence/src/selection.rs at line 319
    [54.30877][64.27368:27382](),[64.27382][54.30894:30946](),[54.30894][54.30894:30946](),[63.8928][55.6447:6487](),[54.30978][55.6447:6487](),[55.6487][73.22576:22668](),[73.22668][64.27383:27417](),[55.6526][64.27383:27417]()
    fn select_up(
    state: &mut State,
    files: &mut file::State,
    files_diffs: &mut diff::FilesState,
    status_logs: &mut diff::LogFilesAndState,
    entire_logs: &mut diff::LogFilesAndState,
    repo: Option<&mut app::Repo>,
    [54.30877]
    [55.6526]
    fn select_down_channel(ctx: &mut Ctx<'_>) -> Task<crate::Msg> {
    let ix = match ctx.state.channel.take() {
    Some(Channel {
    ix,
    name: _,
    log: _,
    }) => {
    if ix == ctx.repo.other_channels.len() - 1 {
    0
    } else {
    ix + 1
    }
    }
    None => 0,
    };
    let (selection, task) = channel_selection(ix, VDir::Down, ctx);
    ctx.state.channel = Some(selection);
    return task;
    }
    fn select_down_entire_log(
    ctx: &mut Ctx<'_>,
  • replacement in inflorescence/src/selection.rs at line 343
    [64.27442][63.8929:9001](),[54.31064][63.8929:9001](),[63.9001][69.14192:14219](),[69.14219][70.5779:5807](),[70.5807][73.22669:22689](),[70.5807][63.9001:9026](),[69.14219][63.9001:9026](),[73.22689][63.9001:9026](),[63.9001][63.9001:9026](),[63.9026][59.7061:7097](),[59.7061][59.7061:7097](),[59.7097][69.14220:14764](),[69.14764][73.22690:22691](),[73.22691][75.7105:7179]()
    let Some(app::Repo {
    state: repo_state,
    status_nav,
    switching_channel,
    forking_channel: _,
    entire_log,
    }) = repo
    else {
    return Task::none();
    };
    if *switching_channel {
    let channels = &repo_state.other_channels;
    let selection = match state.view.channel.take() {
    Some(Channel { ix, name: _ }) => {
    let ix = if ix == 0 { channels.len() - 1 } else { ix - 1 };
    channel_selection(ix, channels)
    }
    None => {
    let ix = channels.len() - 1;
    channel_selection(ix, channels)
    }
    };
    state.view.channel = Some(selection);
    return Task::none();
    }
    if let Some(app::EntireLog::Got { log, nav }) = entire_log.as_mut() {
    [64.27442]
    [73.22765]
    if let Some(Log::Loaded { log }) = ctx.logs.entire_log.as_ref() {
  • replacement in inflorescence/src/selection.rs at line 349
    [73.22902][73.22902:22944]()
    }) = state.view.entire_log.take()
    [73.22902]
    [73.22944]
    }) = ctx.state.entire_log.take()
  • replacement in inflorescence/src/selection.rs at line 369
    [73.23674][75.7180:7235]()
    if let Some(nav) = entire_logs
    [73.23674]
    [73.23740]
    if let Some(nav) = ctx
    .navigation
    .entire_logs_navs
  • replacement in inflorescence/src/selection.rs at line 378
    [75.7293][75.7293:7359]()
    nav_scrollable::scroll_up(nav, delta)
    [75.7293]
    [73.24129]
    nav_scrollable::scroll_down(nav, delta)
  • replacement in inflorescence/src/selection.rs at line 384
    [73.24294][73.24294:24523]()
    let file_ix = if 0 == file_ix {
    log_entry.file_paths.len().saturating_sub(1)
    } else {
    file_ix - 1
    };
    [73.24294]
    [73.24523]
    let file_ix =
    if log_entry.file_paths.len().saturating_sub(1)
    == file_ix
    {
    0
    } else {
    file_ix + 1
    };
  • replacement in inflorescence/src/selection.rs at line 394
    [73.24604][73.24604:24645]()
    entire_logs,
    [73.24604]
    [73.24645]
    file_ix,
    hash,
    VDir::Down,
    ctx.navigation,
  • edit in inflorescence/src/selection.rs at line 399
    [73.24684][73.24684:24755]()
    hash,
    file_ix,
  • replacement in inflorescence/src/selection.rs at line 401
    [73.24783][75.7411:7535](),[75.7535][73.24925:24982](),[73.24925][73.24925:24982]()
    if let Some((nav_changes_hash, nav)) =
    entire_logs.changes_nav.as_mut()
    && *nav_changes_hash == hash
    [73.24783]
    [73.24982]
    if let Some(nav) =
    get_entire_log_files_nav_mut(ctx.navigation, hash)
  • replacement in inflorescence/src/selection.rs at line 404
    [73.25008][75.7536:7641]()
    nav_scrollable::scroll_up_to_section(nav, file_ix)
    }
    [73.25008]
    [69.14764]
    nav_scrollable::scroll_down_to_section(nav, file_ix)
    };
  • replacement in inflorescence/src/selection.rs at line 417
    [73.25639][73.25639:25992]()
    if 0 == log_ix {
    let ix = log.len().saturating_sub(1);
    entire_log_selection(
    nav,
    entire_logs,
    log,
    ix,
    VertDir::Down,
    )
    [73.25639]
    [73.25992]
    if log.len().saturating_sub(1) == log_ix {
    let ix = 0;
    entire_log_selection(ix, VDir::Up, ctx, log)
  • replacement in inflorescence/src/selection.rs at line 421
    [73.26021][73.26021:26318]()
    let ix = log_ix - 1;
    entire_log_selection(
    nav,
    entire_logs,
    log,
    ix,
    VertDir::Up,
    )
    [73.26021]
    [73.26318]
    let ix = log_ix + 1;
    entire_log_selection(ix, VDir::Down, ctx, log)
  • replacement in inflorescence/src/selection.rs at line 428
    [73.26413][73.26413:26488]()
    entire_log_selection(nav, entire_logs, log, ix, VertDir::Down)
    [73.26413]
    [73.26488]
    entire_log_selection(ix, VDir::Down, ctx, log)
  • replacement in inflorescence/src/selection.rs at line 430
    [73.26499][73.26499:26548]()
    state.view.entire_log = Some(selection);
    [73.26499]
    [73.26548]
    ctx.state.entire_log = Some(selection);
  • edit in inflorescence/src/selection.rs at line 433
    [73.26575]
    [73.26575]
    Task::none()
    }
  • replacement in inflorescence/src/selection.rs at line 436
    [73.26576][69.14765:14826](),[69.14765][69.14765:14826]()
    let (selection, task) = match state.view.status.take() {
    [73.26576]
    [69.14826]
    fn select_up(ctx: &mut Ctx<'_>, delta: Option<Duration>) -> Task<crate::Msg> {
    match ctx.state.primary {
    Primary::Status => select_up_status(ctx, delta),
    Primary::Channel => select_up_channel(ctx),
    Primary::EntireLog => select_up_entire_log(ctx, delta),
    }
    }
    fn select_up_status(
    ctx: &mut Ctx<'_>,
    delta: Option<Duration>,
    ) -> Task<crate::Msg> {
    let (selection, task) = match ctx.state.status.take() {
  • replacement in inflorescence/src/selection.rs at line 456
    [59.7409][75.7695:7922]()
    if let Some(nav) = files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [59.7409]
    [75.7922]
    if let Some(nav) =
    ctx.navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
    {
  • replacement in inflorescence/src/selection.rs at line 475
    [63.9076][63.9076:9179](),[63.9179][73.26577:26619](),[73.26619][63.9449:9485](),[64.27726][63.9449:9485](),[63.9449][63.9449:9485](),[63.9485][73.26620:26657](),[73.26657][64.27757:27882](),[64.27757][64.27757:27882](),[64.27882][63.9566:9696](),[63.9566][63.9566:9696](),[63.9696][64.27883:27963](),[64.27963][63.10077:10113](),[63.10077][63.10077:10113](),[63.10113][64.27964:28121]()
    if !repo_state.log.is_empty() {
    let ix = repo_state.log.len() - 1;
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    )
    } else if !repo_state.changed_files.is_empty() {
    let ix = repo_state.changed_files.len() - 1;
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    )
    [63.9076]
    [54.32731]
    if !ctx.repo.short_log.is_empty() {
    let ix = ctx.repo.short_log.len() - 1;
    status_log_selection(ix, VDir::Down, ctx)
    } else if !ctx.repo.changed_files.is_empty() {
    let ix = ctx.repo.changed_files.len() - 1;
    changed_file_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 482
    [54.32756][63.10175:10242](),[63.10242][64.28122:28204](),[64.28204][63.10627:10663](),[63.10627][63.10627:10663](),[63.10663][64.28205:28362]()
    let ix = repo_state.untracked_files.len() - 1;
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    )
    [54.32756]
    [59.8405]
    let ix = ctx.repo.untracked_files.len() - 1;
    untracked_file_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 487
    [59.8477][64.28363:28437](),[64.28437][63.11056:11088](),[63.11056][63.11056:11088](),[63.11088][64.28438:28573]()
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [59.8477]
    [59.8594]
    untracked_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 498
    [59.8904][75.8034:8261]()
    if let Some(nav) = files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [59.8904]
    [75.8261]
    if let Some(nav) =
    ctx.navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
    {
  • replacement in inflorescence/src/selection.rs at line 517
    [63.11189][63.11189:11316](),[63.11316][64.28822:28904](),[64.28904][63.11699:11735](),[63.11699][63.11699:11735](),[63.11735][64.28905:29060](),[64.29060][63.11796:11906](),[63.11796][63.11796:11906](),[63.11906][73.26658:26700](),[73.26700][63.12243:12279](),[64.29096][63.12243:12279](),[63.12243][63.12243:12279](),[63.12279][73.26701:26738](),[73.26738][64.29127:29252](),[64.29127][64.29127:29252]()
    if !repo_state.untracked_files.is_empty() {
    let ix = repo_state.untracked_files.len() - 1;
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    } else if !repo_state.log.is_empty() {
    let ix = repo_state.log.len() - 1;
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    )
    [63.11189]
    [54.34478]
    if !ctx.repo.untracked_files.is_empty() {
    let ix = ctx.repo.untracked_files.len() - 1;
    untracked_file_selection(ix, VDir::Up, ctx)
    } else if !ctx.repo.short_log.is_empty() {
    let ix = ctx.repo.short_log.len() - 1;
    status_log_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 524
    [54.34503][63.12341:12406](),[63.12406][64.29253:29333](),[64.29333][63.12787:12823](),[63.12787][63.12787:12823](),[63.12823][64.29334:29491]()
    let ix = repo_state.changed_files.len() - 1;
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    )
    [54.34503]
    [63.12884]
    let ix = ctx.repo.changed_files.len() - 1;
    changed_file_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 529
    [59.9995][64.29492:29564](),[64.29564][63.13230:13262](),[63.13230][63.13230:13262](),[63.13262][64.29565:29700]()
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [59.9995]
    [59.10110]
    changed_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 557
    [73.26900][75.8373:8428]()
    if let Some(nav) = status_logs
    [73.26900]
    [64.30187]
    if let Some(nav) = ctx
    .navigation
    .status_logs_navs
  • replacement in inflorescence/src/selection.rs at line 570
    [59.11562][63.13316:13393]()
    let log_entry = repo_state.log.get(log_ix).unwrap();
    [59.11562]
    [54.36562]
    let log_entry = ctx.repo.short_log.get(log_ix).unwrap();
  • replacement in inflorescence/src/selection.rs at line 572
    [54.36563][59.11634:11749]()
    let file_ix = if 0 == file_ix {
    log_entry.file_paths.len() - 1
    [54.36563]
    [28.15043]
    let (file_ix, dir) = if 0 == file_ix {
    (log_entry.file_paths.len() - 1, VDir::Down)
  • replacement in inflorescence/src/selection.rs at line 575
    [28.15076][59.11750:11790]()
    file_ix - 1
    [28.15076]
    [28.15443]
    (file_ix - 1, VDir::Up)
  • replacement in inflorescence/src/selection.rs at line 578
    [59.11792][73.26967:27154]()
    let (file, selection_task) = log_file_selection(
    status_logs,
    log_entry,
    hash,
    [59.11792]
    [73.27154]
    let (file, selection_task) = status_log_file_selection(
  • edit in inflorescence/src/selection.rs at line 580
    [73.27191]
    [73.27191]
    hash,
    dir,
    ctx.navigation,
    log_entry,
  • replacement in inflorescence/src/selection.rs at line 586
    [64.30780][75.8604:8728](),[75.8728][64.30915:30972](),[73.27280][64.30915:30972](),[64.30915][64.30915:30972]()
    if let Some((nav_changes_hash, nav)) =
    status_logs.changes_nav.as_mut()
    && *nav_changes_hash == hash
    [64.30780]
    [64.30972]
    if let Some(nav) =
    get_entire_log_files_nav_mut(ctx.navigation, hash)
  • replacement in inflorescence/src/selection.rs at line 604
    [63.13477][63.13477:13616](),[63.13616][64.31575:31910](),[64.31910][63.14240:14390](),[63.14240][63.14240:14390](),[63.14390][64.31911:32248]()
    if !repo_state.changed_files.is_empty() {
    let ix = repo_state.changed_files.len() - 1;
    changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    } else if !repo_state.untracked_files.is_empty() {
    let ix = repo_state.untracked_files.len() - 1;
    untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    )
    [63.13477]
    [59.12717]
    if !ctx.repo.changed_files.is_empty() {
    let ix = ctx.repo.changed_files.len() - 1;
    changed_file_selection(ix, VDir::Up, ctx)
    } else if !ctx.repo.untracked_files.is_empty() {
    let ix = ctx.repo.untracked_files.len() - 1;
    untracked_file_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 611
    [59.12750][63.15019:15082](),[63.15082][73.27381:27431](),[73.27431][64.32292:32336](),[64.32292][64.32292:32336](),[64.32336][73.27432:27477](),[73.27477][64.32374:32531](),[64.32374][64.32374:32531]()
    let ix = repo_state.log.len() - 1;
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    )
    [59.12750]
    [59.12859]
    let ix = ctx.repo.short_log.len() - 1;
    status_log_selection(ix, VDir::Down, ctx)
  • replacement in inflorescence/src/selection.rs at line 616
    [59.12959][73.27478:27524](),[73.27524][63.16020:16060](),[64.32571][63.16020:16060](),[63.16020][63.16020:16060](),[63.16060][73.27525:27566](),[73.27566][64.32606:32745](),[64.32606][64.32606:32745]()
    status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Up,
    )
    [59.12959]
    [63.16129]
    status_log_selection(ix, VDir::Up, ctx)
  • replacement in inflorescence/src/selection.rs at line 623
    [59.13173][63.16152:16247](),[63.16247][73.27567:27629](),[73.27629][63.16459:16491](),[64.32801][63.16459:16491](),[63.16459][63.16459:16491](),[63.16491][73.27630:27663](),[73.27663][64.32828:32917](),[64.32828][64.32828:32917](),[64.32917][63.16491:16510](),[63.16491][63.16491:16510]()
    if !repo_state.log.is_empty() {
    let ix = repo_state.log.len() - 1;
    let (selection, task) = status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Up,
    );
    [59.13173]
    [63.16510]
    if !ctx.repo.short_log.is_empty() {
    let ix = ctx.repo.short_log.len() - 1;
    let (selection, task) = status_log_selection(ix, VDir::Up, ctx);
  • replacement in inflorescence/src/selection.rs at line 627
    [63.16550][63.16550:16672](),[63.16672][64.32918:33014](),[64.33014][63.17001:17033](),[63.17001][63.17001:17033](),[63.17033][64.33015:33132](),[64.33132][63.17033:17052](),[63.17033][63.17033:17052]()
    } else if !repo_state.changed_files.is_empty() {
    let ix = repo_state.changed_files.len() - 1;
    let (selection, task) = changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    );
    [63.16550]
    [63.17052]
    } else if !ctx.repo.changed_files.is_empty() {
    let ix = ctx.repo.changed_files.len() - 1;
    let (selection, task) =
    changed_file_selection(ix, VDir::Up, ctx);
  • replacement in inflorescence/src/selection.rs at line 632
    [63.17092][63.17092:17218](),[63.17218][64.33133:33231](),[64.33231][63.17549:17581](),[63.17549][63.17549:17581](),[63.17581][64.33232:33349](),[64.33349][63.17581:17600](),[63.17581][63.17581:17600]()
    } else if !repo_state.untracked_files.is_empty() {
    let ix = repo_state.untracked_files.len() - 1;
    let (selection, task) = untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Up,
    );
    [63.17092]
    [63.17600]
    } else if !ctx.repo.untracked_files.is_empty() {
    let ix = ctx.repo.untracked_files.len() - 1;
    let (selection, task) =
    untracked_file_selection(ix, VDir::Up, ctx);
  • replacement in inflorescence/src/selection.rs at line 643
    [54.38655][69.15144:15179]()
    state.view.status = selection;
    [54.38655]
    [59.14007]
    ctx.state.status = selection;
  • replacement in inflorescence/src/selection.rs at line 647
    [56.4174][56.4174:4299]()
    fn alt_select_down<M>(
    state: &mut State,
    files_diffs: &mut diff::FilesState,
    logs: &mut diff::LogFilesAndState,
    [56.4174]
    [56.4299]
    fn select_up_channel(ctx: &mut Ctx<'_>) -> Task<crate::Msg> {
    let ix = match ctx.state.channel.take() {
    Some(Channel {
    ix,
    name: _,
    log: _,
    }) => {
    if ix == 0 {
    ctx.repo.other_channels.len() - 1
    } else {
    ix - 1
    }
    }
    None => ctx.repo.other_channels.len() - 1,
    };
    let (selection, task) = channel_selection(ix, VDir::Up, ctx);
    ctx.state.channel = Some(selection);
    return task;
    }
    fn select_up_entire_log(
    ctx: &mut Ctx<'_>,
  • replacement in inflorescence/src/selection.rs at line 670
    [56.4328][56.4328:4343](),[56.4343][69.15180:15219]()
    ) -> Task<M> {
    match state.view.status.as_mut() {
    [56.4328]
    [69.15219]
    ) -> Task<crate::Msg> {
    if let Some(Log::Loaded { log }) = ctx.logs.entire_log.as_ref() {
    let (selection, task) = if let Some(LogChange {
    ix: log_ix,
    hash,
    message,
    file,
    }) = ctx.state.entire_log.take()
    {
    match file {
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected,
    }) => {
    if diff_selected {
    let id_hash = file::log_id_parts_hash(hash, &path);
    let selection = LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected,
    }),
    };
    if let Some(nav) = get_entire_log_diffs_nav_mut(
    ctx.navigation,
    id_hash,
    ) {
    nav_scrollable::scroll_up(nav, delta)
    };
    (selection, Task::none())
    } else {
    let log_entry = log.get(log_ix).unwrap();
    let file_ix = if 0 == file_ix {
    log_entry.file_paths.len().saturating_sub(1)
    } else {
    file_ix - 1
    };
    let (file, selection_task) = entire_log_file_selection(
    file_ix,
    hash,
    VDir::Up,
    ctx.navigation,
    log_entry,
    );
    if let Some(nav) =
    get_entire_log_files_nav_mut(ctx.navigation, hash)
    {
    nav_scrollable::scroll_up_to_section(nav, file_ix)
    }
    let selection = LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(file),
    };
    (selection, selection_task)
    }
    }
    None => {
    if 0 == log_ix {
    let ix = log.len().saturating_sub(1);
    entire_log_selection(ix, VDir::Down, ctx, log)
    } else {
    let ix = log_ix - 1;
    entire_log_selection(ix, VDir::Up, ctx, log)
    }
    }
    }
    } else {
    let ix = 0;
    entire_log_selection(ix, VDir::Down, ctx, log)
    };
    ctx.state.entire_log = Some(selection);
    return task;
    }
    Task::none()
    }
    fn alt_select_down<M>(ctx: &mut Ctx<'_>, delta: Option<Duration>) -> Task<M> {
    match ctx.state.status.as_mut() {
  • replacement in inflorescence/src/selection.rs at line 765
    [64.33381][64.33381:33440](),[64.33440][75.8862:8892](),[75.8892][64.33470:33523](),[64.33470][64.33470:33523]()
    files_diffs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| {
    [64.33381]
    [64.33523]
    ctx.navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
  • replacement in inflorescence/src/selection.rs at line 768
    [64.33588][64.33588:33611]()
    })
    [64.33588]
    [56.4715]
    },
    )
  • replacement in inflorescence/src/selection.rs at line 782
    [64.33643][64.33643:33702](),[64.33702][75.8980:9010](),[75.9010][64.33732:33785](),[64.33732][64.33732:33785]()
    files_diffs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| {
    [64.33643]
    [64.33785]
    ctx.navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
  • replacement in inflorescence/src/selection.rs at line 785
    [64.33850][64.33850:33873]()
    })
    [64.33850]
    [56.5199]
    },
    )
  • replacement in inflorescence/src/selection.rs at line 805
    [64.33905][75.9098:9170](),[75.9170][64.33977:34057](),[64.33977][64.33977:34057]()
    logs.diffs_nav.as_mut().and_then(|(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    })
    [64.33905]
    [56.5860]
    ctx.navigation.status_logs_navs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
  • replacement in inflorescence/src/selection.rs at line 822
    [56.6190][56.6190:6357](),[56.6357][69.15455:15494]()
    fn alt_select_up<M>(
    state: &mut State,
    files_diffs: &mut diff::FilesState,
    logs: &mut diff::LogFilesAndState,
    delta: Option<Duration>,
    ) -> Task<M> {
    match state.view.status.as_mut() {
    [56.6190]
    [69.15494]
    fn alt_select_up<M>(ctx: &mut Ctx<'_>, delta: Option<Duration>) -> Task<M> {
    match ctx.state.status.as_mut() {
  • replacement in inflorescence/src/selection.rs at line 831
    [64.34089][64.34089:34148](),[64.34148][75.9258:9288](),[75.9288][64.34178:34231](),[64.34178][64.34178:34231]()
    files_diffs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| {
    [64.34089]
    [64.34231]
    ctx.navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
  • replacement in inflorescence/src/selection.rs at line 834
    [64.34296][64.34296:34319]()
    })
    [64.34296]
    [56.6729]
    },
    )
  • replacement in inflorescence/src/selection.rs at line 848
    [64.34351][64.34351:34410](),[64.34410][75.9374:9404](),[75.9404][64.34440:34493](),[64.34440][64.34440:34493]()
    files_diffs
    .diffs_nav
    .as_mut()
    .and_then(|(nav_id_hash, nav)| {
    [64.34351]
    [64.34493]
    ctx.navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
  • replacement in inflorescence/src/selection.rs at line 851
    [64.34558][64.34558:34581]()
    })
    [64.34558]
    [56.7211]
    },
    )
  • replacement in inflorescence/src/selection.rs at line 871
    [64.34613][75.9490:9562](),[75.9562][64.34685:34765](),[64.34685][64.34685:34765]()
    logs.diffs_nav.as_mut().and_then(|(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    })
    [64.34613]
    [56.7870]
    ctx.navigation.status_logs_navs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
  • replacement in inflorescence/src/selection.rs at line 888
    [54.38748][64.34766:34912](),[64.34912][75.9648:9671](),[75.9671][69.15730:15760](),[64.34932][69.15730:15760](),[69.15760][70.5808:5836](),[70.5836][73.27894:27914](),[70.5836][64.34932:34966](),[69.15760][64.34932:34966](),[73.27914][64.34932:34966](),[64.34932][64.34932:34966](),[64.34966][59.14060:14096](),[59.14060][59.14060:14096](),[59.14096][73.27915:27916](),[73.27916][75.9672:9752](),[75.9752][73.27993:28091](),[73.27993][73.27993:28091](),[69.15903][64.35113:35252](),[73.28091][64.35113:35252](),[64.35113][64.35113:35252](),[59.14661][54.39120:39187](),[64.35252][54.39120:39187](),[54.39120][54.39120:39187](),[54.39187][64.35253:35292](),[59.14708][54.39226:39250](),[64.35292][54.39226:39250](),[54.39226][54.39226:39250](),[54.39250][64.35293:35370](),[64.35370][73.28092:28133](),[69.15953][64.35422:35589](),[73.28133][64.35422:35589](),[64.35422][64.35422:35589]()
    fn select_left(
    state: &mut State,
    repo: Option<&app::Repo>,
    ) -> Task<crate::Msg> {
    let Some(app::Repo {
    state: _repo_state,
    status_nav: _,
    switching_channel: _,
    forking_channel: _,
    entire_log,
    }) = repo.as_ref()
    else {
    return Task::none();
    };
    if let Some(app::EntireLog::Got { log: _, nav: _ }) = entire_log.as_ref() {
    let (selection, task) = match state.view.entire_log.take() {
    Some(LogChange {
    ix,
    hash,
    message,
    file:
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected,
    }),
    }) => {
    if diff_selected {
    (
    Some(LogChange {
    ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    [54.38748]
    [64.35589]
    fn select_left(ctx: &mut Ctx<'_>) -> Task<crate::Msg> {
    match ctx.state.primary {
    Primary::Status => {
    let (selection, task): (Option<Status>, Task<crate::Msg>) =
    match ctx.state.status.take() {
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file:
    Some(LogChangeFileSelection {
  • replacement in inflorescence/src/selection.rs at line 901
    [64.35672][64.35672:35726]()
    diff_selected: false,
    [64.35672]
    [64.35726]
    diff_selected,
  • edit in inflorescence/src/selection.rs at line 903
    [64.35758]
    [64.35758]
    })) => {
    if diff_selected {
    (
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    })),
    Task::none(),
    )
    } else {
    let selection = Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file: None,
    });
    (Some(selection), Task::none())
    }
    }
    Some(Status::UntrackedFile {
    ix,
    path,
    diff_selected: true,
    }) => (
    Some(Status::UntrackedFile {
    ix,
    path,
    diff_selected: false,
  • replacement in inflorescence/src/selection.rs at line 939
    [64.35824][64.35824:35871](),[64.35871][73.28134:28182]()
    )
    } else {
    let selection = LogChange {
    [64.35824]
    [64.35930]
    ),
    Some(Status::ChangedFile {
  • edit in inflorescence/src/selection.rs at line 942
    [64.35958][64.35958:36080](),[64.36080][75.9753:9805](),[75.9805][73.28333:28904](),[73.28333][73.28333:28904]()
    hash,
    message,
    file: None,
    };
    (Some(selection), Task::none())
    }
    }
    selection @ (Some(LogChange { file: None, .. }) | None) => {
    (selection, Task::none())
    }
    };
    state.view.entire_log = selection;
    return task;
    }
    let (selection, task): (Option<Status>, Task<crate::Msg>) =
    match state.view.status.take() {
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file:
    Some(LogChangeFileSelection {
    ix: file_ix,
  • replacement in inflorescence/src/selection.rs at line 943
    [73.28934][73.28934:29134]()
    diff_selected,
    }),
    })) => {
    if diff_selected {
    (
    Some(Status::LogChange(LogChange {
    [73.28934]
    [73.29134]
    diff_selected: true,
    }) => (
    Some(Status::ChangedFile {
  • replacement in inflorescence/src/selection.rs at line 947
    [73.29166][73.29166:29499]()
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    })),
    [73.29166]
    [73.29499]
    path,
    diff_selected: false,
    }),
  • replacement in inflorescence/src/selection.rs at line 951
    [73.29537][73.29537:29741]()
    )
    } else {
    let selection = Status::LogChange(LogChange {
    ix,
    hash,
    message,
    [73.29537]
    [73.29741]
    ),
    selection @ (Some(Status::UntrackedFile { .. })
    | Some(Status::ChangedFile { .. })
    | Some(Status::LogChange(LogChange {
  • replacement in inflorescence/src/selection.rs at line 956
    [73.29777][73.29777:29801](),[73.29801][75.9806:9858](),[75.9858][64.36260:36292](),[64.36260][64.36260:36292](),[64.36292][69.16011:16052](),[69.16052][64.36336:36435](),[64.36336][64.36336:36435](),[64.36435][69.16053:16098](),[69.16098][59.14793:14817](),[64.36483][59.14793:14817](),[59.14793][59.14793:14817](),[59.14817][64.36484:36617](),[64.36617][69.16099:16138](),[69.16138][64.36659:36758](),[64.36659][64.36659:36758](),[64.36758][69.16139:16182]()
    });
    (Some(selection), Task::none())
    }
    }
    Some(Status::UntrackedFile {
    ix,
    path,
    diff_selected: true,
    }) => (
    Some(Status::UntrackedFile {
    ix,
    path,
    diff_selected: false,
    }),
    Task::none(),
    ),
    Some(Status::ChangedFile {
    ix,
    path,
    diff_selected: true,
    }) => (
    Some(Status::ChangedFile {
    [73.29777]
    [64.36804]
    ..
    }))
    | None) => (selection, Task::none()),
    };
    ctx.state.status = selection;
    return task;
    }
    Primary::Channel => {
    // todo!()
    }
    Primary::EntireLog => {
    let (selection, task) = match ctx.state.entire_log.take() {
    Some(LogChange {
  • replacement in inflorescence/src/selection.rs at line 970
    [64.36828][64.36828:36961](),[64.36961][69.16183:16290](),[69.16290][73.29802:29914](),[69.16347][64.37134:37195](),[73.29914][64.37134:37195](),[64.37134][64.37134:37195](),[64.37195][69.16348:16383](),[65.1372][64.37196:37205](),[69.16383][64.37196:37205](),[59.15627][64.37196:37205](),[64.37205][54.40638:40640](),[54.40638][54.40638:40640](),[54.40640][28.16096:16097](),[28.16096][28.16096:16097](),[28.16097][64.37206:37223](),[64.37223][54.40661:40684](),[54.40661][54.40661:40684](),[63.17763][54.40716:40752](),[54.40716][54.40716:40752](),[54.40752][73.29915:30007](),[73.30007][64.37263:37317](),[64.37263][64.37263:37317](),[64.37317][63.17764:17839](),[54.40802][63.17764:17839](),[63.17839][69.16384:16414](),[69.16414][70.5837:5865](),[70.5865][73.30008:30028](),[70.5865][63.17839:17873](),[69.16414][63.17839:17873](),[73.30028][63.17839:17873](),[63.17839][63.17839:17873](),[63.17873][59.15670:15706](),[59.15670][59.15670:15706](),[59.15706][73.30029:30620](),[73.30620][75.9859:10085](),[75.10085][73.30748:30794](),[73.30748][73.30748:30794](),[73.30872][73.30872:30986](),[73.30986][75.10086:10222](),[75.10222][73.31175:31245](),[73.31175][73.31175:31245](),[73.31782][73.31782:31828]()
    path,
    diff_selected: false,
    }),
    Task::none(),
    ),
    selection @ (Some(Status::UntrackedFile { .. })
    | Some(Status::ChangedFile { .. })
    | Some(Status::LogChange(LogChange {
    file: None,
    ..
    }))
    | None) => (selection, Task::none()),
    };
    state.view.status = selection;
    task
    }
    fn select_right(
    state: &mut State,
    files_diffs: &diff::FilesState,
    status_logs: &mut diff::LogFilesAndState,
    entire_logs: &mut diff::LogFilesAndState,
    repo: Option<&app::Repo>,
    ) -> Task<crate::Msg> {
    let Some(app::Repo {
    state: repo_state,
    status_nav: _,
    switching_channel: _,
    forking_channel: _,
    entire_log,
    }) = repo.as_ref()
    else {
    return Task::none();
    };
    if let Some(app::EntireLog::Got { log, nav: _ }) = entire_log.as_ref()
    && let Some(entire_log) = state.view.entire_log.take()
    {
    let (selection, task) = match entire_log {
    LogChange {
    ix,
    hash,
    message,
    file: None,
    } => {
    let log_entry = log.get(ix).unwrap();
    let (file, task) = if let Some(path) =
    log_entry.file_paths.first()
    {
    let id_hash = file::log_id_parts_hash(log_entry.hash, path);
    // If the log is not loaded yet, the nav will be initialized
    // once it's loaded (`repo::MsgOut::GotChangeDifs`)
    if let Some(log) = entire_logs.diffs.get(&id_hash) {
    // Init log diffs nav
    let unchanged_sections =
    diff::unchanged_sections(&log.file);
    let nav = nav_scrollable::State::default()
    .with_skip_sections(unchanged_sections);
    entire_logs.diffs_nav = Some((id_hash, nav));
    };
    (
    [64.36828]
    [73.31828]
    hash,
    message,
    file:
  • edit in inflorescence/src/selection.rs at line 974
    [73.31882][73.31882:32043](),[73.32043][75.10223:10261](),[75.10261][73.32073:32940](),[73.32073][73.32073:32940](),[73.33526][73.33526:33732]()
    ix: 0,
    path: path.clone(),
    diff_selected: false,
    }),
    Task::none(),
    )
    } else {
    (None, Task::none())
    };
    (
    Some(LogChange {
    ix,
    hash,
    message,
    file,
    }),
    task,
    )
    }
    LogChange {
    ix,
    hash,
    message,
    file:
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    } => {
    let id_hash = file::log_id_parts_hash(hash, &path);
    let is_diff_scrollable =
    diff::log_diff_needs_scrolling(entire_logs, id_hash);
    (
    Some(LogChange {
    ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
  • replacement in inflorescence/src/selection.rs at line 976
    [73.33807][73.33807:33870]()
    diff_selected: is_diff_scrollable,
    [73.33807]
    [73.33870]
    diff_selected,
  • replacement in inflorescence/src/selection.rs at line 978
    [73.33898][73.33898:33922](),[73.33922][75.10262:10296](),[75.10296][73.33948:34132](),[73.33948][73.33948:34132]()
    }),
    Task::none(),
    )
    }
    selection @ LogChange { .. } => (Some(selection), Task::none()),
    };
    state.view.entire_log = selection;
    return task;
    [73.33898]
    [73.34132]
    }) => {
    if diff_selected {
    (
    Some(LogChange {
    ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    }),
    Task::none(),
    )
    } else {
    let selection = LogChange {
    ix,
    hash,
    message,
    file: None,
    };
    (Some(selection), Task::none())
    }
    }
    selection @ (Some(LogChange { file: None, .. }) | None) => {
    (selection, Task::none())
    }
    };
    ctx.state.entire_log = selection;
    return task;
    }
  • edit in inflorescence/src/selection.rs at line 1011
    [73.34138]
    [73.34138]
    Task::none()
    }
  • replacement in inflorescence/src/selection.rs at line 1014
    [73.34139][75.10297:10753]()
    let (selection, task): (Option<Status>, Task<crate::Msg>) =
    match state.view.status.take() {
    Some(Status::UntrackedFile {
    ix,
    path,
    diff_selected: false,
    }) => {
    let id_hash = file::id_parts_hash(&path, file::Kind::Untracked);
    let diff_selected =
    diff::file_diff_needs_scrolling(files_diffs, id_hash);
    (
    [73.34139]
    [75.10753]
    fn select_right(ctx: &mut Ctx<'_>) -> Task<crate::Msg> {
    match ctx.state.primary {
    Primary::Status => {
    let (selection, task): (Option<Status>, Task<crate::Msg>) =
    match ctx.state.status.take() {
  • replacement in inflorescence/src/selection.rs at line 1022
    [75.10860][75.10860:11336]()
    diff_selected,
    }),
    Task::none(),
    )
    }
    Some(Status::ChangedFile {
    ix,
    path,
    diff_selected: false,
    }) => {
    let id_hash = file::id_parts_hash(&path, file::Kind::Changed);
    let diff_selected =
    diff::file_diff_needs_scrolling(files_diffs, id_hash);
    (
    [75.10860]
    [75.11336]
    diff_selected: false,
    }) => {
    let id_hash =
    file::id_parts_hash(&path, file::Kind::Untracked);
    let diff_selected = diff::file_diff_needs_scrolling(
    &ctx.navigation.files_diffs,
    id_hash,
    );
    (
    Some(Status::UntrackedFile {
    ix,
    path,
    diff_selected,
    }),
    Task::none(),
    )
    }
  • replacement in inflorescence/src/selection.rs at line 1042
    [75.11441][75.11441:12001](),[75.12001][64.40599:40752](),[54.41902][64.40599:40752](),[64.40752][75.12002:12464]()
    diff_selected,
    }),
    Task::none(),
    )
    }
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file: None,
    })) => {
    let log_entry = repo_state.log.get(ix).unwrap();
    let (file, task) = if let Some(path) =
    log_entry.file_paths.first()
    {
    let id_hash = file::log_id_parts_hash(log_entry.hash, path);
    // If the log is not loaded yet, the nav will be initialized
    // once it's loaded (`repo::MsgOut::GotChangeDifs`)
    if let Some(log) = status_logs.diffs.get(&id_hash) {
    // Init log diffs nav
    let unchanged_sections =
    diff::unchanged_sections(&log.file);
    let nav = nav_scrollable::State::default()
    .with_skip_sections(unchanged_sections);
    status_logs.diffs_nav = Some((id_hash, nav));
    };
    [75.11441]
    [75.12464]
    diff_selected: false,
    }) => {
    let id_hash =
    file::id_parts_hash(&path, file::Kind::Changed);
    let diff_selected = diff::file_diff_needs_scrolling(
    &ctx.navigation.files_diffs,
    id_hash,
    );
    (
    Some(Status::ChangedFile {
    ix,
    path,
    diff_selected,
    }),
    Task::none(),
    )
    }
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file: None,
    })) => {
    let log_entry = ctx.repo.short_log.get(ix).unwrap();
    let (file, task) = if let Some(path) =
    log_entry.file_paths.first()
    {
    let id_hash =
    file::log_id_parts_hash(log_entry.hash, path);
    // If the log is not loaded yet, the nav will be
    // initialized once it's
    // loaded (`repo::MsgOut::GotChangeDifs`)
    if let Some(log) =
    ctx.navigation.log_diffs.diffs.get(&id_hash)
    {
    // Init log diffs nav
    let unchanged_sections =
    diff::unchanged_sections(&log.file);
    let nav = nav_scrollable::State::default()
    .with_skip_sections(unchanged_sections);
    ctx.navigation.status_logs_navs.diffs_nav =
    Some((id_hash, nav));
    };
  • replacement in inflorescence/src/selection.rs at line 1086
    [75.12465][75.12465:12828]()
    (
    Some(LogChangeFileSelection {
    ix: 0,
    path: path.clone(),
    diff_selected: false,
    }),
    Task::none(),
    )
    } else {
    (None, Task::none())
    [75.12465]
    [54.41935]
    (
    Some(LogChangeFileSelection {
    ix: 0,
    path: path.clone(),
    diff_selected: false,
    }),
    Task::none(),
    )
    } else {
    (None, Task::none())
    };
    (
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file,
    })),
    task,
    )
    }
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file:
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    })) => {
    let id_hash = file::log_id_parts_hash(hash, &path);
    let is_diff_scrollable = log::log_diff_needs_scrolling(
    &ctx.navigation.status_logs_navs,
    id_hash,
    );
    (
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: is_diff_scrollable,
    }),
    })),
    Task::none(),
    )
    }
    selection => (selection, Task::none()),
  • replacement in inflorescence/src/selection.rs at line 1139
    [64.40754][54.41954:41972](),[54.41954][54.41954:41972](),[54.41972][75.12829:12884]()
    (
    Some(Status::LogChange(LogChange {
    [54.41954]
    [75.12884]
    ctx.state.status = selection;
    return task;
    }
    Primary::Channel => {
    // TODO
    }
    Primary::EntireLog => {
    if let Some(Log::Loaded { log }) = ctx.logs.entire_log.as_ref()
    && let Some(entire_log) = ctx.state.entire_log.take()
    {
    let (selection, task) = match entire_log {
    LogChange {
  • replacement in inflorescence/src/selection.rs at line 1154
    [75.12975][75.12975:13030](),[75.13030][54.42145:42189](),[54.42145][54.42145:42189](),[54.42189][75.13031:13231](),[75.13231][64.42364:42401](),[64.42364][64.42364:42401](),[64.42401][54.43259:43289](),[54.43259][54.43259:43289](),[54.43289][75.13232:13278](),[75.13278][54.43328:43352](),[73.35150][54.43328:43352](),[54.43328][54.43328:43352](),[54.43352][75.13279:13556]()
    file,
    })),
    task,
    )
    }
    Some(Status::LogChange(LogChange {
    ix,
    hash,
    message,
    file:
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    })) => {
    let id_hash = file::log_id_parts_hash(hash, &path);
    let is_diff_scrollable =
    diff::log_diff_needs_scrolling(status_logs, id_hash);
    (
    Some(Status::LogChange(LogChange {
    [75.12975]
    [75.13556]
    file: None,
    } => {
    let log_entry = log.get(ix).unwrap();
    let (file, task) = if let Some(path) =
    log_entry.file_paths.first()
    {
    let id_hash =
    file::log_id_parts_hash(log_entry.hash, path);
    // If the log is not loaded yet, the nav will be
    // initialized once it's
    // loaded (`repo::MsgOut::GotChangeDifs`)
    if let Some(log) =
    ctx.navigation.log_diffs.diffs.get(&id_hash)
    {
    // Init log diffs nav
    let unchanged_sections =
    diff::unchanged_sections(&log.file);
    let nav = nav_scrollable::State::default()
    .with_skip_sections(unchanged_sections);
    ctx.navigation.entire_logs_navs.diffs_nav =
    Some((id_hash, nav));
    };
    (
    Some(LogChangeFileSelection {
    ix: 0,
    path: path.clone(),
    diff_selected: false,
    }),
    Task::none(),
    )
    } else {
    (None, Task::none())
    };
    (
    Some(LogChange {
    ix,
    hash,
    message,
    file,
    }),
    task,
    )
    }
    LogChange {
  • replacement in inflorescence/src/selection.rs at line 1202
    [75.13647][75.13647:13950]()
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: is_diff_scrollable,
    }),
    })),
    Task::none(),
    )
    [75.13647]
    [75.13950]
    file:
    Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: false,
    }),
    } => {
    let id_hash = file::log_id_parts_hash(hash, &path);
    let is_diff_scrollable = log::log_diff_needs_scrolling(
    &ctx.navigation.entire_logs_navs,
    id_hash,
    );
    (
    Some(LogChange {
    ix,
    hash,
    message,
    file: Some(LogChangeFileSelection {
    ix: file_ix,
    path,
    diff_selected: is_diff_scrollable,
    }),
    }),
    Task::none(),
    )
    }
    selection @ LogChange { .. } => {
    (Some(selection), Task::none())
    }
    };
    ctx.state.entire_log = selection;
    return task;
  • replacement in inflorescence/src/selection.rs at line 1235
    [75.13964][75.13964:14027](),[75.14027][69.16825:16860](),[64.42523][69.16825:16860](),[65.1426][59.15837:15846](),[69.16860][59.15837:15846](),[59.15837][59.15837:15846]()
    selection => (selection, Task::none()),
    };
    state.view.status = selection;
    task
    [75.13964]
    [55.7148]
    }
    }
    Task::none()
  • replacement in inflorescence/src/selection.rs at line 1241
    [58.609][55.7150:7242](),[55.7150][55.7150:7242](),[55.7242][64.42524:42563](),[64.42563][55.7286:7301](),[55.7286][55.7286:7301]()
    fn release<M>(
    dir: Dir,
    state: &mut State,
    files_diffs: &mut diff::FilesState,
    logs: &mut diff::LogFilesAndState,
    ) -> Task<M> {
    [58.609]
    [55.7301]
    fn release<M>(dir: Dir, ctx: &mut Ctx<'_>) -> Task<M> {
    let Ctx {
    state,
    files: _,
    navigation,
    repo: _,
    logs: _,
    } = ctx;
  • replacement in inflorescence/src/selection.rs at line 1253
    [55.7441][69.16861:16908]()
    match state.view.status.as_mut() {
    [55.7441]
    [69.16908]
    match state.status.as_mut() {
  • replacement in inflorescence/src/selection.rs at line 1261
    [57.804][64.42564:42811]()
    if let Some(nav) = files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [57.804]
    [75.14028]
    if let Some(nav) =
    navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
    {
  • replacement in inflorescence/src/selection.rs at line 1278
    [57.877][64.42812:43059]()
    if let Some(nav) = files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [57.877]
    [75.14092]
    if let Some(nav) =
    navigation.files_diffs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
    {
  • replacement in inflorescence/src/selection.rs at line 1300
    [55.9013][64.43060:43300]()
    if let Some(nav) = logs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    ) {
    [55.9013]
    [75.14156]
    if let Some(nav) =
    navigation.status_logs_navs.diffs_nav.as_mut().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    )
    {
  • edit in inflorescence/src/selection.rs at line 1319
    [54.46062][54.46062:46063](),[54.46063][72.37:54](),[72.54][54.46083:46155](),[54.46083][54.46083:46155](),[54.46155][75.14220:14254](),[75.14254][72.55:95](),[63.17970][72.55:95](),[72.95][73.35312:35404](),[73.35404][72.134:158](),[72.134][72.134:158](),[72.158][63.17971:18023](),[54.46273][63.17971:18023](),[63.18023][72.159:179](),[72.179][69.17192:17222](),[63.18046][69.17192:17222](),[69.17222][70.5866:5894](),[70.5894][73.35405:35425](),[70.5894][63.18046:18107](),[69.17222][63.18046:18107](),[73.35425][63.18046:18107](),[63.18046][63.18046:18107]()
    fn select_exact(
    select: Select,
    state: &mut State,
    files: &mut file::State,
    repo: Option<&mut app::Repo>,
    files_diffs: &mut diff::FilesState,
    status_logs: &mut diff::LogFilesAndState,
    entire_logs: &mut diff::LogFilesAndState,
    ) -> Task<crate::Msg> {
    let Some(app::Repo {
    state: repo_state,
    status_nav,
    switching_channel: _,
    forking_channel: _,
    entire_log,
    }) = repo
    else {
    return Task::none();
    };
  • replacement in inflorescence/src/selection.rs at line 1320
    [73.35427][75.14255:14329](),[75.14329][73.35501:35817](),[73.35501][73.35501:35817]()
    if let Some(app::EntireLog::Got { log, nav }) = entire_log.as_mut() {
    let (selection, task) = match select {
    Select::LogChange {
    ix,
    hash: _,
    message: _,
    } => {
    let (selection, task) = entire_log_selection(
    nav,
    entire_logs,
    log,
    [73.35427]
    [73.35817]
    fn select_exact(select: Select, ctx: &mut Ctx<'_>) -> Task<crate::Msg> {
    match ctx.state.primary {
    Primary::Status => {
    let (selection, task) = match select {
    Select::UntrackedFile { ix, path } => {
    let id = file::Id {
    path: path.clone(),
    file_kind: file::Kind::Changed,
    };
    file::load_src_file_if_not_cached(ctx.files, id);
    let (selection, selection_task) =
    untracked_file_selection(ix, VDir::Down, ctx);
    (Some(selection), selection_task)
    }
    Select::ChangedFile { ix, path } => {
    let id = file::Id {
    path: path.clone(),
    file_kind: file::Kind::Changed,
    };
    if let Some(diffs) = ctx.repo.changed_files.get(&path)
    && diff::any_diff_has_contents(diffs)
    {
    file::load_src_file_if_not_cached(ctx.files, id);
    }
    let (selection, selection_task) =
    changed_file_selection(ix, VDir::Down, ctx);
    (Some(selection), selection_task)
    }
    Select::LogChange {
  • replacement in inflorescence/src/selection.rs at line 1350
    [73.35841][73.35841:35949](),[73.35949][75.14330:14991]()
    VertDir::Down,
    );
    (Some(selection), task)
    }
    Select::LogChangeFile {
    ix: file_ix,
    path: _,
    } => match state.view.entire_log.take() {
    Some(LogChange {
    ix: log_ix,
    hash,
    message,
    file: _,
    }) => {
    let log_entry = log.get(log_ix).unwrap();
    let (file, selection_task) = log_file_selection(
    entire_logs,
    log_entry,
    hash,
    file_ix,
    );
    let selection = Some(LogChange {
    [73.35841]
    [73.36100]
    hash: _,
    message: _,
    } => {
    let (selection, task) =
    status_log_selection(ix, VDir::Down, ctx);
    (Some(selection), task)
    }
    Select::LogChangeFile {
    ix: file_ix,
    path: _,
    } => match ctx.state.status.take() {
    Some(Status::LogChange(LogChange {
  • replacement in inflorescence/src/selection.rs at line 1365
    [73.36199][75.14992:15106](),[75.15106][73.37988:38006](),[73.37988][73.37988:38006](),[73.38006][75.15107:15178](),[75.15178][73.38020:38165](),[73.38020][73.38020:38165]()
    file: Some(file),
    });
    (selection, selection_task)
    }
    selection => (selection, Task::none()),
    },
    _ => {
    unreachable!()
    }
    };
    state.view.entire_log = selection;
    return task;
    }
    [73.36199]
    [73.38165]
    file: _,
    })) => {
    let log_entry = ctx.repo.short_log.get(log_ix).unwrap();
  • replacement in inflorescence/src/selection.rs at line 1369
    [63.18107][54.46273:46480](),[73.38166][54.46273:46480](),[54.46273][54.46273:46480]()
    let (selection, task) = match select {
    Select::UntrackedFile { ix, path } => {
    let id = file::Id {
    path: path.clone(),
    file_kind: file::Kind::Changed,
    [73.38166]
    [54.46480]
    let (file, selection_task) = status_log_file_selection(
    file_ix,
    hash,
    VDir::Down,
    ctx.navigation,
    log_entry,
    );
    let selection = Some(Status::LogChange(LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(file),
    }));
    (selection, selection_task)
    }
    selection => (selection, Task::none()),
    },
  • replacement in inflorescence/src/selection.rs at line 1388
    [54.46541][54.46541:46599](),[54.47252][72.233:479](),[72.479][75.15179:15225]()
    file::load_src_file_if_not_cached(files, id);
    let (selection, selection_task) = untracked_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    );
    (Some(selection), selection_task)
    [54.46495]
    [54.47462]
    ctx.state.status = selection;
    return task;
  • replacement in inflorescence/src/selection.rs at line 1391
    [54.47472][54.47472:47649](),[54.47695][63.18108:18177](),[63.18177][58.784:838](),[54.47805][58.784:838](),[58.838][54.47805:47819](),[54.47805][54.47805:47819](),[54.47819][58.839:901](),[58.901][49.1460:1474](),[54.47959][49.1460:1474](),[49.1460][49.1460:1474](),[72.608][72.608:852](),[72.852][75.15226:15272]()
    Select::ChangedFile { ix, path } => {
    let id = file::Id {
    path: path.clone(),
    file_kind: file::Kind::Changed,
    };
    if let Some(diffs) = repo_state.changed_files.get(&path)
    && diff::any_diff_has_contents(diffs)
    {
    file::load_src_file_if_not_cached(files, id);
    }
    let (selection, selection_task) = changed_file_selection(
    repo_state,
    status_nav,
    ix,
    files,
    files_diffs,
    VertDir::Down,
    );
    (Some(selection), selection_task)
    [54.47472]
    [72.926]
    Primary::Channel => {
    // TODO
  • replacement in inflorescence/src/selection.rs at line 1394
    [72.936][72.936:1040](),[72.1040][73.38167:38376](),[73.38376][72.1156:1192](),[72.1156][72.1156:1192](),[72.1192][28.23134:23144](),[54.48821][28.23134:23144](),[28.23134][28.23134:23144](),[28.23144][75.15273:15634]()
    Select::LogChange {
    ix,
    hash: _,
    message: _,
    } => {
    let (selection, task) = status_log_selection(
    status_nav,
    status_logs,
    repo_state,
    ix,
    VertDir::Down,
    );
    (Some(selection), task)
    }
    Select::LogChangeFile {
    ix: file_ix,
    path: _,
    } => match state.view.status.take() {
    Some(Status::LogChange(LogChange {
    ix: log_ix,
    hash,
    message,
    file: _,
    })) => {
    let log_entry = repo_state.log.get(log_ix).unwrap();
    [72.936]
    [75.15634]
    Primary::EntireLog => {
    if let Some(Log::Loaded { log }) = ctx.logs.entire_log.as_ref() {
    let (selection, task) = match select {
    Select::LogChange {
    ix,
    hash: _,
    message: _,
    } => {
    let (selection, task) =
    entire_log_selection(ix, VDir::Down, ctx, log);
    (Some(selection), task)
    }
    Select::LogChangeFile {
    ix: file_ix,
    path: _,
    } => match ctx.state.entire_log.take() {
    Some(LogChange {
    ix: log_ix,
    hash,
    message,
    file: _,
    }) => {
    let log_entry = log.get(log_ix).unwrap();
  • replacement in inflorescence/src/selection.rs at line 1418
    [75.15635][75.15635:15759]()
    let (file, selection_task) =
    log_file_selection(status_logs, log_entry, hash, file_ix);
    [75.15635]
    [75.15759]
    let (file, selection_task) =
    status_log_file_selection(
    file_ix,
    hash,
    VDir::Down,
    ctx.navigation,
    log_entry,
    );
  • replacement in inflorescence/src/selection.rs at line 1427
    [75.15760][75.15760:15827](),[75.15827][72.1193:1225](),[73.38428][72.1193:1225](),[69.17437][72.1193:1225](),[72.1225][54.49242:49297](),[54.49242][54.49242:49297](),[54.49297][75.15828:15931]()
    let selection = Some(Status::LogChange(LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(file),
    }));
    (selection, selection_task)
    [75.15760]
    [54.50589]
    let selection = Some(LogChange {
    ix: log_ix,
    hash,
    message,
    file: Some(file),
    });
    (selection, selection_task)
    }
    selection => (selection, Task::none()),
    },
    _ => {
    unreachable!()
    }
    };
    ctx.state.entire_log = selection;
    return task;
  • replacement in inflorescence/src/selection.rs at line 1444
    [54.50603][75.15932:15995](),[29.12008][28.26570:26577](),[75.15995][28.26570:26577](),[28.26570][28.26570:26577](),[28.26577][69.17488:17523](),[65.1565][54.50637:50646](),[69.17523][54.50637:50646](),[54.50637][54.50637:50646]()
    selection => (selection, Task::none()),
    },
    };
    state.view.status = selection;
    task
    [54.50603]
    [63.18178]
    }
    }
    Task::none()
  • replacement in inflorescence/src/selection.rs at line 1472
    [64.44051][64.44051:44070]()
    pub enum VertDir {
    [64.44051]
    [64.44070]
    pub enum VDir {
  • edit in inflorescence/src/selection.rs at line 1478
    [64.44124][64.44124:44148](),[64.44148][75.15996:16040]()
    repo: &repo::State,
    status_nav: &mut nav_scrollable::State,
  • replacement in inflorescence/src/selection.rs at line 1479
    [64.44195][64.44195:44282]()
    files: &mut file::State,
    files_diffs: &mut diff::FilesState,
    dir: VertDir,
    [64.44195]
    [69.17524]
    dir: VDir,
    ctx: &mut Ctx<'_>,
  • edit in inflorescence/src/selection.rs at line 1482
    [69.17558]
    [64.44319]
    let Ctx {
    state: _,
    files,
    navigation,
    repo,
    logs: _,
    } = ctx;
  • replacement in inflorescence/src/selection.rs at line 1498
    [75.16205][64.44858:44916](),[64.44858][64.44858:44916]()
    files_diffs.diffs_nav = Some((id_hash, nav));
    [75.16205]
    [64.45121]
    navigation.files_diffs.diffs_nav = Some((id_hash, nav));
  • replacement in inflorescence/src/selection.rs at line 1512
    [75.16229][75.16229:16314]()
    VertDir::Up => nav_scrollable::scroll_up_to_section(
    status_nav,
    [75.16229]
    [64.45581]
    VDir::Up => nav_scrollable::scroll_up_to_section(
    &mut navigation.status_nav,
  • replacement in inflorescence/src/selection.rs at line 1516
    [64.45687][75.16315:16380](),[75.16380][64.45828:45852](),[64.45828][64.45828:45852]()
    VertDir::Down => nav_scrollable::scroll_down_to_section(
    status_nav,
    [64.45687]
    [75.16381]
    VDir::Down => nav_scrollable::scroll_down_to_section(
    &mut navigation.status_nav,
  • edit in inflorescence/src/selection.rs at line 1532
    [64.46084][64.46084:46108](),[64.46108][75.16491:16535]()
    repo: &repo::State,
    status_nav: &mut nav_scrollable::State,
  • replacement in inflorescence/src/selection.rs at line 1533
    [64.46155][64.46155:46242]()
    files: &mut file::State,
    files_diffs: &mut diff::FilesState,
    dir: VertDir,
    [64.46155]
    [69.17604]
    dir: VDir,
    ctx: &mut Ctx<'_>,
  • edit in inflorescence/src/selection.rs at line 1536
    [69.17638]
    [64.46279]
    let Ctx {
    state: _,
    files,
    navigation,
    repo,
    logs: _,
    } = ctx;
  • replacement in inflorescence/src/selection.rs at line 1552
    [75.16700][64.46823:46881](),[64.46823][64.46823:46881]()
    files_diffs.diffs_nav = Some((id_hash, nav));
    [75.16700]
    [64.47086]
    navigation.files_diffs.diffs_nav = Some((id_hash, nav));
  • edit in inflorescence/src/selection.rs at line 1561
    [64.47343]
    [64.47343]
    dbg!(diff::any_diff_has_contents(diffs));
  • replacement in inflorescence/src/selection.rs at line 1569
    [75.16724][75.16724:16785](),[75.16785][64.47683:47707](),[64.47683][64.47683:47707]()
    VertDir::Up => nav_scrollable::scroll_up_to_section(
    status_nav,
    [75.16724]
    [75.16786]
    VDir::Up => nav_scrollable::scroll_up_to_section(
    &mut navigation.status_nav,
  • replacement in inflorescence/src/selection.rs at line 1573
    [64.47718][75.16856:16945]()
    VertDir::Down => nav_scrollable::scroll_down_to_section(
    status_nav,
    [64.47718]
    [64.47788]
    VDir::Down => nav_scrollable::scroll_down_to_section(
    &mut navigation.status_nav,
  • edit in inflorescence/src/selection.rs at line 1586
    [75.16976]
    [63.18659]
    }
    fn channel_selection(
    ix: usize,
    dir: VDir,
    ctx: &mut Ctx<'_>,
    ) -> (Channel, Task<crate::Msg>) {
    let Ctx {
    state: _,
    files: _,
    navigation,
    repo,
    logs,
    } = ctx;
    let name = repo.other_channels.get(ix).unwrap().clone();
    let task = if logs.other_channels_logs.contains_key(&name) {
    Task::none()
    } else {
    Task::done(crate::Msg::View(app::Msg::ToRepo(
    repo::MsgIn::LoadOtherChannelLog(name.clone()),
    )))
    };
    match dir {
    VDir::Up => nav_scrollable::scroll_up_to_section(
    &mut navigation.other_channels_nav,
    ix,
    ),
    VDir::Down => nav_scrollable::scroll_down_to_section(
    &mut navigation.other_channels_nav,
    ix,
    ),
    }
    let selection = Channel {
    ix,
    name,
    log: None,
    };
    (selection, task)
  • edit in inflorescence/src/selection.rs at line 1629
    [73.39113][75.16977:17021](),[75.17021][64.48129:48192](),[64.48129][64.48129:48192]()
    status_nav: &mut nav_scrollable::State,
    logs: &mut diff::LogFilesAndState,
    repo: &repo::State,
  • replacement in inflorescence/src/selection.rs at line 1630
    [64.48207][64.48207:48225]()
    dir: VertDir,
    [64.48207]
    [69.17682]
    dir: VDir,
    ctx: &mut Ctx<'_>,
  • replacement in inflorescence/src/selection.rs at line 1633
    [69.17716][64.48262:48305](),[64.48262][64.48262:48305]()
    let entry = repo.log.get(ix).unwrap();
    [69.17716]
    [64.48305]
    let Ctx {
    state: _,
    files: _,
    navigation,
    repo,
    logs: _,
    } = ctx;
    let entry = repo.short_log.get(ix).unwrap();
  • replacement in inflorescence/src/selection.rs at line 1643
    [64.48333][75.17022:17089]()
    let task = if logs.changes_with_loaded_diffs.contains(&hash) {
    [64.48333]
    [75.17089]
    let task = if navigation
    .log_diffs
    .changes_with_loaded_diffs
    .contains(&hash)
    {
  • replacement in inflorescence/src/selection.rs at line 1650
    [75.17173][75.17173:17219]()
    logs.changes_nav = Some((hash, nav));
    [75.17173]
    [75.17219]
    navigation.status_logs_navs.files_nav = Some((hash, nav));
  • replacement in inflorescence/src/selection.rs at line 1661
    [75.17515][75.17515:17600]()
    VertDir::Up => nav_scrollable::scroll_up_to_section(
    status_nav,
    [75.17515]
    [64.49148]
    VDir::Up => nav_scrollable::scroll_up_to_section(
    &mut navigation.status_nav,
  • replacement in inflorescence/src/selection.rs at line 1665
    [75.17612][75.17612:17677](),[75.17677][64.49213:49237](),[64.49213][64.49213:49237]()
    VertDir::Down => nav_scrollable::scroll_down_to_section(
    status_nav,
    [75.17612]
    [64.49318]
    VDir::Down => nav_scrollable::scroll_down_to_section(
    &mut navigation.status_nav,
  • edit in inflorescence/src/selection.rs at line 1682
    [73.39422][75.17708:17745](),[75.17745][73.39447:39507](),[73.39447][73.39447:39507]()
    nav: &mut nav_scrollable::State,
    logs: &mut diff::LogFilesAndState,
    log: &repo::Log,
  • replacement in inflorescence/src/selection.rs at line 1683
    [73.39522][73.39522:39540]()
    dir: VertDir,
    [73.39522]
    [73.39540]
    dir: VDir,
    ctx: &mut Ctx<'_>,
    log: &repo::Log,
  • edit in inflorescence/src/selection.rs at line 1687
    [73.39577]
    [73.39577]
    let Ctx {
    state: _,
    files: _,
    navigation,
    repo: _,
    logs: _,
    } = ctx;
  • replacement in inflorescence/src/selection.rs at line 1697
    [64.49426][75.17746:17813]()
    let task = if logs.changes_with_loaded_diffs.contains(&hash) {
    [64.49426]
    [75.17813]
    let task = if navigation
    .log_diffs
    .changes_with_loaded_diffs
    .contains(&hash)
    {
  • replacement in inflorescence/src/selection.rs at line 1704
    [75.17897][75.17897:17943]()
    logs.changes_nav = Some((hash, nav));
    [75.17897]
    [75.17943]
    navigation.entire_logs_navs.files_nav = Some((hash, nav));
  • replacement in inflorescence/src/selection.rs at line 1715
    [75.18239][75.18239:18383]()
    VertDir::Up => nav_scrollable::scroll_up_to_section(nav, ix),
    VertDir::Down => nav_scrollable::scroll_down_to_section(nav, ix),
    [75.18239]
    [75.18383]
    VDir::Up => nav_scrollable::scroll_up_to_section(
    &mut navigation.entire_log_nav,
    ix,
    ),
    VDir::Down => nav_scrollable::scroll_down_to_section(
    &mut navigation.entire_log_nav,
    ix,
    ),
  • replacement in inflorescence/src/selection.rs at line 1735
    [64.49620][64.49620:49714]()
    fn log_file_selection(
    logs: &mut diff::LogFilesAndState,
    log_entry: &repo::LogEntry,
    [64.49620]
    [64.49714]
    fn status_log_file_selection(
    ix: usize,
  • replacement in inflorescence/src/selection.rs at line 1738
    [64.49742][64.49742:49762]()
    file_ix: usize,
    [64.49742]
    [64.49762]
    dir: VDir,
    navigation: &mut Navigation,
    log_entry: &repo::LogEntry,
  • replacement in inflorescence/src/selection.rs at line 1742
    [64.49812][64.49812:49879]()
    let path = log_entry.file_paths.get(file_ix).unwrap().clone();
    [64.49812]
    [64.49879]
    let path = log_entry.file_paths.get(ix).unwrap().clone();
  • replacement in inflorescence/src/selection.rs at line 1747
    [75.18534][75.18534:18650]()
    if logs.diffs.contains_key(&id_hash) {
    let needs_new_nav = logs.diffs_nav.is_none()
    || logs
    [75.18534]
    [75.18650]
    if navigation
    .log_diffs
    .changes_with_loaded_diffs
    .contains(&hash)
    {
    let needs_new_nav = navigation.status_logs_navs.diffs_nav.is_none()
    || navigation
    .status_logs_navs
  • replacement in inflorescence/src/selection.rs at line 1762
    [75.18932][75.18932:18983]()
    logs.diffs_nav = Some((id_hash, nav));
    [75.18932]
    [64.50570]
    navigation.status_logs_navs.diffs_nav = Some((id_hash, nav));
  • edit in inflorescence/src/selection.rs at line 1765
    [64.50774]
    [64.50774]
    if let Some((selected_hash, nav)) =
    &mut navigation.status_logs_navs.files_nav
    && *selected_hash == hash
    {
    match dir {
    VDir::Up => nav_scrollable::scroll_up_to_section(nav, ix),
    VDir::Down => nav_scrollable::scroll_down_to_section(nav, ix),
    }
    }
  • replacement in inflorescence/src/selection.rs at line 1778
    [64.50814][64.50814:50839]()
    ix: file_ix,
    [64.50814]
    [64.50839]
    ix,
  • replacement in inflorescence/src/selection.rs at line 1787
    [73.40694][73.40694:40765]()
    logs: &mut diff::LogFilesAndState,
    log_entry: &repo::LogEntry,
    [73.40694]
    [73.40765]
    ix: usize,
  • replacement in inflorescence/src/selection.rs at line 1789
    [73.40793][73.40793:40813]()
    file_ix: usize,
    [73.40793]
    [73.40813]
    dir: VDir,
    navigation: &mut Navigation,
    log_entry: &repo::LogEntry,
  • replacement in inflorescence/src/selection.rs at line 1793
    [73.40863][73.40863:40930]()
    let path = log_entry.file_paths.get(file_ix).unwrap().clone();
    [73.40863]
    [73.40930]
    let path = log_entry.file_paths.get(ix).unwrap().clone();
  • replacement in inflorescence/src/selection.rs at line 1798
    [75.19128][75.19128:19244]()
    if logs.diffs.contains_key(&id_hash) {
    let needs_new_nav = logs.diffs_nav.is_none()
    || logs
    [75.19128]
    [75.19244]
    if navigation
    .log_diffs
    .changes_with_loaded_diffs
    .contains(&hash)
    {
    let needs_new_nav = navigation.entire_logs_navs.diffs_nav.is_none()
    || navigation
    .entire_logs_navs
  • replacement in inflorescence/src/selection.rs at line 1813
    [75.19526][75.19526:19577]()
    logs.diffs_nav = Some((id_hash, nav));
    [75.19526]
    [73.41933]
    navigation.entire_logs_navs.diffs_nav = Some((id_hash, nav));
  • edit in inflorescence/src/selection.rs at line 1817
    [73.42141]
    [73.42141]
    if let Some((selected_hash, nav)) =
    &mut navigation.entire_logs_navs.files_nav
    && *selected_hash == hash
    {
    match dir {
    VDir::Up => nav_scrollable::scroll_up_to_section(nav, ix),
    VDir::Down => nav_scrollable::scroll_down_to_section(nav, ix),
    }
    }
  • replacement in inflorescence/src/selection.rs at line 1829
    [73.42180][73.42180:42205]()
    ix: file_ix,
    [73.42180]
    [73.42205]
    ix,
  • edit in inflorescence/src/selection.rs at line 1835
    [73.42292][73.42292:42295](),[73.42295][69.17761:17902](),[69.17761][69.17761:17902]()
    }
    fn channel_selection(ix: usize, channels: &[String]) -> Channel {
    let name = channels.get(ix).unwrap().clone();
    Channel { ix, name }
  • edit in inflorescence/src/main.rs at line 3
    [29.27]
    [69.17904]
    mod log;
  • replacement in inflorescence/src/main.rs at line 10
    [50.2366][32.25349:25389](),[18.162][32.25349:25389]()
    use inflorescence_view::app::RecordMsg;
    [50.2366]
    [37.5240]
    use inflorescence_model::{
    self as model, Log, Logs, ReadyState, RecordMsg, State as MState,
    SubState as MSubState,
    };
  • edit in inflorescence/src/main.rs at line 30
    [37.5324][37.5324:5338](),[37.5338][75.19641:19673]()
    use std::cmp;
    use std::collections::BTreeSet;
  • edit in inflorescence/src/main.rs at line 32
    [37.5413]
    [16.174]
    use std::{cmp, mem};
  • edit in inflorescence/src/main.rs at line 75
    [37.5689][31.653:654](),[31.653][31.653:654](),[31.654][69.17984:18033]()
    let selection = selection::State::default();
  • edit in inflorescence/src/main.rs at line 95
    [31.755][11.754:776](),[6.1460][11.754:776](),[11.776][48.4755:4780]()
    id: None,
    window_size,
  • edit in inflorescence/src/main.rs at line 96
    [10.234][10.234:257]()
    repo_path,
  • edit in inflorescence/src/main.rs at line 97
    [9.6018][9.6018:6075](),[9.6075][69.18034:18057](),[69.18057][8.100:130](),[6.1520][8.100:130]()
    repo: None, // This is loaded by `repo_task`
    selection,
    record_msg: None,
  • replacement in inflorescence/src/main.rs at line 98
    [29.164][54.8817:8871](),[54.8871][73.42297:42417]()
    files_diffs: diff::FilesState::default(),
    status_logs: diff::LogFilesAndState::default(),
    entire_logs: diff::LogFilesAndState::default(),
    [29.164]
    [6.1520]
    sub: MState {
    window_size,
    repo_path,
    sub: MSubState::Loading {
    user_ids: Vec::new(),
    repo: None,
    },
    },
  • edit in inflorescence/src/main.rs at line 113
    [31.783][11.777:797](),[3.1363][11.777:797](),[11.797][48.4781:4810]()
    id: Option<Id>,
    window_size: iced::Size,
  • edit in inflorescence/src/main.rs at line 114
    [10.334][10.334:358]()
    repo_path: PathBuf,
  • edit in inflorescence/src/main.rs at line 115
    [9.6144][62.4371:4400](),[62.4400][69.18058:18091](),[69.18091][13.23:58](),[5.652][13.23:58]()
    repo: Option<app::Repo>,
    selection: selection::State,
    record_msg: Option<RecordMsg>,
  • replacement in inflorescence/src/main.rs at line 117
    [29.189][73.42418:42485](),[73.42485][54.8925:8960](),[51.3085][54.8925:8960](),[54.8960][73.42486:42705]()
    /// Diffs for untracked and changed files shown in status view
    files_diffs: diff::FilesState,
    /// Logs shown in the status view. The diffs are loaded async and not
    /// present while loading.
    status_logs: diff::LogFilesAndState,
    /// Logs for the entire log
    entire_logs: diff::LogFilesAndState,
    [29.189]
    [16.1025]
    sub: inflorescence_model::State,
  • replacement in inflorescence/src/main.rs at line 137
    [32.25998][13.252:286](),[13.252][13.252:286]()
    state.id = Some(*id);
    [32.25998]
    [13.286]
    match &mut state.sub.sub {
    MSubState::Loading { user_ids, repo } => {
    // TODO switch to `SelectingId` if more than one id found
    if let Some(repo) = repo.take() {
    state.sub.sub = MSubState::Ready(ReadyState {
    user_id: *id,
    repo,
    selection: default(),
    navigation: default(),
    record_msg: default(),
    forking_channel_name: default(),
    logs: default(),
    })
    } else {
    user_ids.push(*id);
    }
    }
    MSubState::SelectingId { .. } => unreachable!(),
    MSubState::Ready(..) => {
    unreachable!()
    }
    }
  • replacement in inflorescence/src/main.rs at line 166
    [40.321][40.321:389]()
    start_task_to_manage_repo(state.repo_path.clone());
    [40.321]
    [40.389]
    start_task_to_manage_repo(state.sub.repo_path.clone());
  • replacement in inflorescence/src/main.rs at line 177
    [32.26187][62.4401:4571](),[62.4571][53.37:76](),[50.2762][53.37:76](),[53.76][64.8104:8129](),[53.128][53.128:188]()
    let loaded = file::update(
    &mut state.files,
    state.repo.as_ref().map(|repo| &repo.state),
    msg,
    );
    if let Some(file::Loaded {
    id_hash,
    unchanged_sections,
    }) = loaded
    [32.26187]
    [53.188]
    if let Some(ReadyState {
    repo,
    navigation,
    selection,
    ..
    }) = model::ready_mut(&mut state.sub)
  • replacement in inflorescence/src/main.rs at line 184
    [53.202][75.19674:19794](),[75.19794][64.8130:8198](),[53.360][64.8130:8198](),[64.8198][75.19795:19864]()
    let nav = nav_scrollable::State::default()
    .with_skip_sections(unchanged_sections);
    state.files_diffs.diffs_nav = Some((id_hash, nav));
    state.files_diffs.diffs.entry(id_hash).or_default();
    [53.202]
    [50.3698]
    let loaded = file::update(&mut state.files, repo, msg);
    if let Some(file::Loaded {
    id_hash,
    unchanged_sections,
    }) = loaded
    {
    let is_selected = match selection.status.as_ref() {
    Some(selection::Status::UntrackedFile {
    ix: _,
    path,
    diff_selected: _,
    }) => {
    let selected_id_hash = file::id_parts_hash(
    path,
    file::Kind::Untracked,
    );
    selected_id_hash == id_hash
    }
    Some(selection::Status::ChangedFile {
    ix: _,
    path,
    diff_selected: _,
    }) => {
    let selected_id_hash =
    file::id_parts_hash(path, file::Kind::Changed);
    selected_id_hash == id_hash
    }
    _ => false,
    };
    if is_selected {
    let nav = nav_scrollable::State::default()
    .with_skip_sections(unchanged_sections);
    navigation.files_diffs.diffs_nav = Some((id_hash, nav));
    }
    navigation.files_diffs.diffs.entry(id_hash).or_default();
    }
  • replacement in inflorescence/src/main.rs at line 234
    [48.5165][48.5165:5203]()
    state.window_size = size;
    [48.5165]
    [48.5203]
    state.sub.window_size = size;
  • replacement in inflorescence/src/main.rs at line 267
    [69.18123][70.5896:5950]()
    if let Some(repo) = state.repo.as_mut() {
    [69.18123]
    [70.5950]
    if let Some(ReadyState {
    repo,
    navigation: _,
    selection,
    forking_channel_name,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
  • replacement in inflorescence/src/main.rs at line 276
    [70.5999][70.5999:6173]()
    if repo.switching_channel {
    if let Some(selection::Channel { ix: _, name }) =
    state.selection.view.channel.take()
    [70.5999]
    [70.6173]
    if matches!(selection.primary, selection::Primary::Channel) {
    if let Some(selection::Channel {
    ix: _,
    name,
    log: _,
    }) = selection.channel.take()
  • replacement in inflorescence/src/main.rs at line 288
    [69.18501][70.6375:6431]()
    repo.switching_channel = false;
    [69.18501]
    [70.6431]
    selection.primary = selection::Primary::default();
  • replacement in inflorescence/src/main.rs at line 291
    [76.2246][76.2246:2304]()
    repo.forking_channel.take_if(|name| {
    [76.2246]
    [76.2304]
    forking_channel_name.take_if(|name| {
  • replacement in inflorescence/src/main.rs at line 295
    [76.2447][76.2447:2528]()
    !repo.state.other_channels.iter().any(|n| n == name)
    [76.2447]
    [76.2528]
    repo.channel != name
    && !repo
    .other_channels
    .iter()
    .any(|n| n == name)
  • replacement in inflorescence/src/main.rs at line 313
    [69.18628][70.6810:6890]()
    if let Some(RecordMsg::Typing(content)) = state.record_msg.as_ref()
    [69.18628]
    [69.18722]
    if let Some(ReadyState {
    selection,
    record_msg,
    forking_channel_name,
    ..
    }) = model::ready_mut(&mut state.sub)
  • replacement in inflorescence/src/main.rs at line 320
    [69.18736][70.6891:7347](),[70.7347][76.2799:3159]()
    state.record_msg = Some(RecordMsg::Canceled {
    old_msg: content.text(),
    });
    }
    if let Some(repo) = state.repo.as_mut() {
    if repo.switching_channel {
    repo.switching_channel = false;
    state.selection.view.channel = None;
    } else if repo.forking_channel.is_some() {
    repo.forking_channel = None;
    } else if let Some(app::EntireLog::Got { log, nav }) = repo
    .entire_log
    .take_if(|log| matches!(log, app::EntireLog::Got { .. }))
    {
    // Cache for later viewing
    repo.entire_log =
    Some(app::EntireLog::NotViewing { log, nav });
    [69.18736]
    [70.7347]
    if let Some(RecordMsg::Typing(content)) = record_msg.as_ref() {
    *record_msg = Some(RecordMsg::Canceled {
    old_msg: content.text(),
    });
    }
    match selection.primary {
    selection::Primary::Status => {
    if forking_channel_name.is_some() {
    *forking_channel_name = None;
    }
    }
    selection::Primary::Channel
    | selection::Primary::EntireLog => {
    selection.primary = selection::Primary::default();
    }
  • replacement in inflorescence/src/main.rs at line 339
    [69.18886][69.18886:18941](),[69.18941][64.9017:9034](),[64.9017][64.9017:9034](),[64.9034][69.18942:18976](),[69.18976][64.9065:9131](),[64.9065][64.9065:9131](),[64.9131][73.43488:43560](),[73.43560][64.9160:9204](),[64.9160][64.9160:9204]()
    app::Msg::Selection(msg) => selection::update(
    msg,
    &mut state.selection,
    &mut state.files,
    &mut state.files_diffs,
    &mut state.status_logs,
    &mut state.entire_logs,
    state.repo.as_mut(),
    ),
    [69.18886]
    [32.26614]
    app::Msg::Selection(msg) => {
    if let Some(ReadyState {
    repo,
    selection,
    navigation,
    logs,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
    return selection::update(
    msg,
    selection,
    &mut state.files,
    navigation,
    repo,
    logs,
    );
    }
    Task::none()
    }
  • replacement in inflorescence/src/main.rs at line 371
    [76.3197][69.19014:19115](),[69.19014][69.19014:19115]()
    if let Some(repo) = state.repo.as_mut() {
    repo.switching_channel = true;
    [76.3197]
    [70.7366]
    if let Some(ReadyState { selection, .. }) =
    model::ready_mut(&mut state.sub)
    {
    selection.primary = selection::Primary::Channel;
  • replacement in inflorescence/src/main.rs at line 379
    [70.7450][70.7450:7564]()
    if let Some(repo) = state.repo.as_mut() {
    repo.forking_channel = Some(String::new());
    [70.7450]
    [70.7564]
    if let Some(ReadyState {
    forking_channel_name,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
    *forking_channel_name = Some(String::new());
  • replacement in inflorescence/src/main.rs at line 390
    [70.7660][70.7660:7765]()
    if let Some(repo) = state.repo.as_mut() {
    repo.forking_channel = Some(name);
    [70.7660]
    [70.7765]
    if let Some(ReadyState {
    forking_channel_name,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
    *forking_channel_name = Some(name);
  • replacement in inflorescence/src/main.rs at line 407
    [75.20020][73.43923:44026](),[73.43923][73.43923:44026]()
    if let Some(repo) = state.repo.as_mut() {
    match repo.entire_log.as_ref() {
    [75.20020]
    [73.44026]
    if let Some(ReadyState {
    selection, logs, ..
    }) = model::ready_mut(&mut state.sub)
    {
    selection.primary = selection::Primary::EntireLog;
    match logs.entire_log.as_ref() {
  • replacement in inflorescence/src/main.rs at line 418
    [73.44227][73.44227:44621](),[73.44621][76.3198:3274](),[76.3274][75.20100:20151](),[75.20100][75.20100:20151](),[75.20151][76.3275:3486]()
    repo.entire_log = Some(app::EntireLog::Loading);
    }
    Some(app::EntireLog::LoadingButNotViewing) => {
    repo.entire_log = Some(app::EntireLog::Loading);
    }
    Some(app::EntireLog::NotViewing { .. }) => {
    // Repeated match to take ownership of the log
    let Some(app::EntireLog::NotViewing { log, nav }) =
    repo.entire_log.take()
    else {
    unreachable!()
    };
    repo.entire_log =
    Some(app::EntireLog::Got { log, nav });
    [73.44227]
    [73.46042]
    logs.entire_log = Some(Log::Loading);
  • replacement in inflorescence/src/main.rs at line 420
    [73.46064][73.46064:46196]()
    Some(
    app::EntireLog::Loading | app::EntireLog::Got { .. },
    ) => {}
    [73.46064]
    [73.46196]
    Some(Log::Loading | Log::Loaded { .. }) => {}
  • replacement in inflorescence/src/main.rs at line 431
    [39.1008][39.1008:1078]()
    repo::MsgOut::Refreshed(repo) => repo_refreshed(state, repo),
    [39.1008]
    [41.7884]
    repo::MsgOut::Refreshed {
    state: repo_state,
    invalidate_logs,
    } => repo_refreshed(state, repo_state, invalidate_logs),
  • edit in inflorescence/src/main.rs at line 437
    [41.8019][41.8019:8088]()
    repo::MsgOut::Recorded(repo) => repo_refreshed(state, repo),
  • edit in inflorescence/src/main.rs at line 441
    [73.47201]
    [39.1200]
    repo::MsgOut::LoadedOtherChannelLog { channel, log } => {
    loaded_other_channel_log(state, channel, log)
    }
  • replacement in inflorescence/src/main.rs at line 448
    [39.1265][62.4983:5058](),[62.5058][69.19165:19195](),[69.19195][70.7815:7843](),[70.7843][73.47202:47225](),[70.7843][62.5058:5087](),[69.19195][62.5058:5087](),[73.47225][62.5058:5087](),[62.5058][62.5058:5087]()
    if let Some(app::Repo {
    state: repo_state,
    status_nav,
    switching_channel: _,
    forking_channel: _,
    entire_log: _,
    }) = state.repo.as_mut()
    [39.1265]
    [69.19196]
    if let Some(ReadyState {
    repo,
    selection,
    navigation,
    logs,
    ..
    }) = model::ready_mut(&mut state.sub)
  • replacement in inflorescence/src/main.rs at line 459
    [54.12165][69.19252:19302]()
    }) = state.selection.view.status.as_ref()
    [54.12165]
    [60.201]
    }) = selection.status.as_ref()
  • replacement in inflorescence/src/main.rs at line 466
    [12.5330][62.5088:5325]()
    let removed = repo_state.untracked_files.remove(path);
    debug_assert!(
    removed,
    "{:?}, path: {path}",
    repo_state.untracked_files
    );
    repo_state
    .changed_files
    [12.5330]
    [60.501]
    let removed = repo.untracked_files.remove(path);
    debug_assert!(removed, "{:?}, path: {path}", repo.untracked_files);
    repo.changed_files
  • edit in inflorescence/src/main.rs at line 473
    [62.5327][69.19303:19339](),[69.19339][75.20271:20334](),[75.20334][62.5546:5584](),[62.5546][62.5546:5584](),[62.5584][64.9884:9885]()
    // Re-initialize status nav
    let new_status_nav = nav_scrollable::State::default();
    *status_nav = new_status_nav;
  • replacement in inflorescence/src/main.rs at line 474
    [60.659][64.9992:10043](),[64.10043][75.20335:20383]()
    if repo_state.untracked_files.is_empty() {
    state.selection.view.status = None;
    [60.659]
    [60.746]
    if repo.untracked_files.is_empty() {
    selection.status = None;
  • replacement in inflorescence/src/main.rs at line 477
    [60.763][62.5663:5737](),[62.5737][69.19388:19434]()
    let ix = cmp::min(*ix, repo_state.untracked_files.len() - 1);
    let (selection, selection_task) =
    [60.763]
    [69.19434]
    let ix = cmp::min(*ix, repo.untracked_files.len() - 1);
    let (new_selection, selection_task) =
  • edit in inflorescence/src/main.rs at line 480
    [69.19487][69.19487:19551]()
    repo_state,
    status_nav,
  • replacement in inflorescence/src/main.rs at line 481
    [69.19575][69.19575:19703]()
    &mut state.files,
    &mut state.files_diffs,
    selection::VertDir::Down,
    [69.19575]
    [69.19703]
    selection::VDir::Down,
    &mut selection::Ctx {
    state: selection,
    files: &mut state.files,
    navigation,
    repo,
    logs,
    },
  • replacement in inflorescence/src/main.rs at line 491
    [64.10291][69.19723:19782]()
    state.selection.view.status = Some(selection);
    [64.10291]
    [75.20384]
    selection.status = Some(new_selection);
  • replacement in inflorescence/src/main.rs at line 501
    [39.2373][62.5967:6042](),[62.6042][69.19783:19813](),[69.19813][70.7844:7872](),[70.7872][73.47226:47249](),[70.7872][62.6042:6071](),[69.19813][62.6042:6071](),[73.47249][62.6042:6071](),[62.6042][62.6042:6071]()
    if let Some(app::Repo {
    state: repo_state,
    status_nav,
    switching_channel: _,
    forking_channel: _,
    entire_log: _,
    }) = state.repo.as_mut()
    [39.2373]
    [69.19814]
    if let Some(ReadyState {
    repo,
    selection,
    navigation,
    logs,
    ..
    }) = model::ready_mut(&mut state.sub)
  • replacement in inflorescence/src/main.rs at line 512
    [54.12328][69.19868:19918]()
    }) = state.selection.view.status.as_ref()
    [54.12328]
    [60.1020]
    }) = selection.status.as_ref()
  • replacement in inflorescence/src/main.rs at line 514
    [60.1026][62.6072:6137]()
    let diffs = repo_state.changed_files.get(path).unwrap();
    [60.1026]
    [60.1085]
    let diffs = repo.changed_files.get(path).unwrap();
  • replacement in inflorescence/src/main.rs at line 525
    [60.1377][62.6138:6203]()
    let removed = repo_state.changed_files.remove(path);
    [60.1377]
    [60.1436]
    let removed = repo.changed_files.remove(path);
  • replacement in inflorescence/src/main.rs at line 530
    [60.1562][62.6204:6245]()
    repo_state.changed_files
    [60.1562]
    [60.1597]
    repo.changed_files
  • replacement in inflorescence/src/main.rs at line 533
    [60.1650][62.6246:6307]()
    repo_state.untracked_files.insert(path.clone());
    [60.1650]
    [62.6307]
    repo.untracked_files.insert(path.clone());
  • edit in inflorescence/src/main.rs at line 535
    [62.6308][62.6308:6341](),[62.6341][75.20450:20517](),[75.20517][62.6543:6585](),[62.6543][62.6543:6585](),[62.6585][64.10446:10447]()
    // Re-initialize nav
    let new_status_nav = nav_scrollable::State::default();
    *status_nav = new_status_nav;
  • replacement in inflorescence/src/main.rs at line 536
    [60.1757][64.10562:10615](),[64.10615][69.19919:19970]()
    if repo_state.changed_files.is_empty() {
    state.selection.view.status = None
    [60.1757]
    [60.1850]
    if repo.changed_files.is_empty() {
    selection.status = None
  • replacement in inflorescence/src/main.rs at line 539
    [60.1871][62.6666:6742](),[62.6742][64.10662:10712]()
    let ix = cmp::min(*ix, repo_state.changed_files.len() - 1);
    let (selection, selection_task) =
    [60.1871]
    [69.19971]
    let ix = cmp::min(*ix, repo.changed_files.len() - 1);
    let (new_selection, selection_task) =
  • edit in inflorescence/src/main.rs at line 542
    [69.20026][64.10764:10836](),[64.10764][64.10764:10836]()
    repo_state,
    status_nav,
  • replacement in inflorescence/src/main.rs at line 543
    [64.10864][64.10864:10954](),[64.10954][69.20027:20077]()
    &mut state.files,
    &mut state.files_diffs,
    selection::VertDir::Down,
    [64.10864]
    [64.11001]
    selection::VDir::Down,
    &mut selection::Ctx {
    state: selection,
    files: &mut state.files,
    navigation,
    repo,
    logs,
    },
  • replacement in inflorescence/src/main.rs at line 553
    [64.11025][69.20078:20141]()
    state.selection.view.status = Some(selection);
    [64.11025]
    [75.20518]
    selection.status = Some(new_selection);
  • replacement in inflorescence/src/main.rs at line 564
    [39.3780][39.3780:3926](),[39.3926][15.2052:2062](),[15.2052][15.2052:2062](),[15.2062][62.7011:7060]()
    if let Some(repo) = state.repo.as_ref() {
    if state.id.is_none() {
    info!("Requested to record, but ID is not yet loaded");
    }
    if repo.state.changed_files.is_empty() {
    [39.3780]
    [39.3970]
    if let Some(ReadyState {
    repo, record_msg, ..
    }) = model::ready_mut(&mut state.sub)
    {
    if repo.changed_files.is_empty() {
  • replacement in inflorescence/src/main.rs at line 570
    [39.4031][39.4031:4110]()
    } else if let Some(RecordMsg::Typing(_)) = state.record_msg.as_ref() {
    [39.4031]
    [39.4110]
    } else if let Some(RecordMsg::Typing(_)) = record_msg.as_ref() {
  • replacement in inflorescence/src/main.rs at line 574
    [39.4225][39.4225:4283]()
    let content = match state.record_msg.take() {
    [39.4225]
    [39.4283]
    let content = match record_msg.take() {
  • replacement in inflorescence/src/main.rs at line 582
    [39.4541][39.4541:4606]()
    state.record_msg = Some(RecordMsg::Typing(content));
    [39.4541]
    [39.4606]
    *record_msg = Some(RecordMsg::Typing(content));
  • replacement in inflorescence/src/main.rs at line 594
    [39.4876][39.4876:4953]()
    if let Some(RecordMsg::Typing(record_msg)) = state.record_msg.as_mut() {
    [39.4876]
    [39.4953]
    if let Some(ReadyState {
    record_msg: Some(RecordMsg::Typing(record_msg)),
    ..
    }) = model::ready_mut(&mut state.sub)
    {
  • replacement in inflorescence/src/main.rs at line 605
    [39.5064][39.5064:5494](),[39.5637][39.5637:5800](),[39.5800][69.20142:20320](),[69.20320][73.47250:47348]()
    if let Some(RecordMsg::Typing(record_msg)) = state.record_msg.as_ref() {
    let msg = record_msg.text();
    if msg.trim().is_empty() {
    info!("Cannot record with an empty message");
    } else {
    let id =
    state.id.as_ref().expect("ID must be loaded at this point");
    // TODO: this call has CLI prompt - replace it
    let (sk, _) = id.decrypt().unwrap();
    let sk = Arc::new(sk);
    state
    .repo_tx_in
    .send(repo::MsgIn::Record { msg, sk })
    .unwrap();
    // Reset most things
    state.selection = selection::State::default();
    state.record_msg = None;
    state.files_diffs.diffs_nav = None;
    state.status_logs.changes_nav = None;
    state.status_logs.diffs_nav = None;
    [39.5064]
    [69.20404]
    if let Some(ReadyState {
    record_msg,
    repo,
    user_id,
    selection,
    navigation,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
    if let Some(RecordMsg::Typing(msg)) = record_msg.as_ref() {
    let msg = msg.text();
    if msg.trim().is_empty() {
    info!("Cannot record with an empty message");
    } else {
    // TODO: this call has CLI prompt - replace it
    let (sk, _) = user_id.decrypt().unwrap();
    let sk = Arc::new(sk);
    state
    .repo_tx_in
    .send(repo::MsgIn::Record { msg, sk })
    .unwrap();
  • replacement in inflorescence/src/main.rs at line 627
    [69.20405][69.20405:20534](),[69.20534][70.7873:7909](),[70.7909][73.47349:47380](),[70.7909][69.20534:20698](),[73.47380][69.20534:20698](),[69.20534][69.20534:20698]()
    let app::Repo {
    state: repo_state,
    status_nav,
    switching_channel: _,
    forking_channel: _,
    entire_log: _,
    } = state.repo.as_mut().unwrap();
    repo_state.changed_files = repo::ChangedFiles::default();
    state.files_diffs.diffs_nav = None;
    [69.20405]
    [69.20698]
    // Reset most things
    *selection = selection::State::default();
    *record_msg = None;
    // Status view fields
    navigation.files_diffs.diffs_nav = None;
    navigation.status_logs_navs.files_nav = None;
    navigation.status_logs_navs.diffs_nav = None;
  • replacement in inflorescence/src/main.rs at line 635
    [69.20699][69.20699:20739](),[69.20739][75.20592:20659](),[75.20659][69.20941:20983](),[69.20941][69.20941:20983]()
    // Re-initialize status nav
    let new_status_nav = nav_scrollable::State::default();
    *status_nav = new_status_nav;
    [69.20699]
    [39.5800]
    repo.changed_files = repo::ChangedFiles::default();
    }
  • replacement in inflorescence/src/main.rs at line 643
    [39.5886][39.5886:6158]()
    if let Some(RecordMsg::Typing(record_msg)) = state.record_msg.as_ref() {
    let old_msg = record_msg.text();
    state.record_msg = if !old_msg.trim().is_empty() {
    Some(RecordMsg::Canceled { old_msg })
    } else {
    None
    };
    [39.5886]
    [39.6158]
    if let Some(ReadyState { record_msg, .. }) =
    model::ready_mut(&mut state.sub)
    {
    if let Some(RecordMsg::Typing(msg)) = record_msg.as_ref() {
    let old_msg = msg.text();
    *record_msg = if !old_msg.trim().is_empty() {
    Some(RecordMsg::Canceled { old_msg })
    } else {
    None
    };
    }
  • replacement in inflorescence/src/main.rs at line 659
    [39.6236][39.6236:6337]()
    if let Some(RecordMsg::Typing(_)) = state.record_msg.as_ref() {
    state.record_msg = None;
    [39.6236]
    [39.6337]
    if let Some(ReadyState { record_msg, .. }) =
    model::ready_mut(&mut state.sub)
    {
    if let Some(RecordMsg::Typing(_msg)) = record_msg.as_ref() {
    *record_msg = None;
    }
  • replacement in inflorescence/src/main.rs at line 669
    [9.14764][39.7864:7930](),[39.7930][75.20660:20715](),[75.20715][62.7294:7370](),[62.7294][62.7294:7370](),[62.7370][69.21234:21268](),[69.21268][70.7910:7941](),[70.7941][73.48874:48900](),[70.7941][62.7370:7378](),[69.21268][62.7370:7378](),[73.48900][62.7370:7378](),[62.7370][62.7370:7378]()
    fn repo_init(state: &mut State, repo: repo::State) -> Task<Msg> {
    let status_nav = nav_scrollable::State::default();
    state.repo = Some(app::Repo {
    state: repo,
    status_nav,
    switching_channel: false,
    forking_channel: None,
    entire_log: None,
    });
    [39.6363]
    [62.7378]
    fn repo_init(state: &mut State, repo_state: repo::State) -> Task<Msg> {
    match &mut state.sub.sub {
    MSubState::Loading { user_ids, repo: _ } => {
    state.sub.sub = if user_ids.len() == 1 {
    let user_id = user_ids.pop().unwrap();
    MSubState::Ready(ReadyState {
    user_id,
    repo: repo_state,
    selection: default(),
    navigation: default(),
    record_msg: default(),
    forking_channel_name: default(),
    logs: default(),
    })
    } else {
    MSubState::SelectingId {
    user_ids: mem::take(user_ids),
    user_selection_ix: default(),
    user_selection_nav: default(),
    repo: Some(repo_state),
    }
    }
    }
    MSubState::SelectingId { repo, .. } => *repo = Some(repo_state),
    MSubState::Ready(_) => {}
    };
  • replacement in inflorescence/src/main.rs at line 721
    [39.8807][39.8807:8866]()
    .watch(&state.repo_path, RecursiveMode::Recursive)
    [39.8807]
    [39.8866]
    .watch(&state.sub.repo_path, RecursiveMode::Recursive)
  • replacement in inflorescence/src/main.rs at line 735
    [10.360][39.9172:9306](),[39.9306][69.21269:21296](),[69.21296][39.9306:9441](),[39.9306][39.9306:9441]()
    fn repo_refreshed(state: &mut State, repo: repo::State) -> Task<Msg> {
    let repo::State {
    dir_name: _,
    channel: _,
    other_channels: _,
    untracked_files,
    changed_files,
    log,
    } = &repo;
    file::diffs_cache_clear(&mut state.files.diffs_cache);
    [10.360]
    [10.1649]
    fn repo_refreshed(
    state: &mut State,
    repo_state: repo::State,
    invalidate_logs: bool,
    ) -> Task<Msg> {
    match &mut state.sub.sub {
    MSubState::Loading { user_ids: _, repo } => *repo = Some(repo_state),
    MSubState::SelectingId { repo, .. } => *repo = Some(repo_state),
    MSubState::Ready(ReadyState {
    repo,
    user_id: _,
    selection,
    navigation: _,
    record_msg: _,
    forking_channel_name: _,
    logs,
    }) => {
    *repo = repo_state;
    // Throw away the logs
    if invalidate_logs {
    *logs = default();
    };
  • replacement in inflorescence/src/main.rs at line 758
    [10.1650][69.21297:21397](),[69.21397][42.8696:8790](),[42.8696][42.8696:8790](),[62.7710][42.8820:8821](),[42.8820][42.8820:8821](),[42.8821][69.21398:21699](),[69.21699][70.7942:8061](),[70.8061][75.20732:20926](),[70.8061][62.7711:7786](),[75.20926][62.7711:7786](),[69.21699][62.7711:7786](),[42.8821][62.7711:7786](),[62.7786][69.21700:21727](),[69.21727][70.8062:8087](),[70.8087][73.48901:48927](),[70.8087][62.7786:7795](),[69.21727][62.7786:7795](),[73.48927][62.7786:7795](),[62.7786][62.7786:7795](),[62.7795][75.20927:20946]()
    // Re-index selection
    let selection_task = reindex_selection(
    &mut state.selection,
    &mut state.files,
    untracked_files,
    changed_files,
    log,
    );
    let switching_channel = if changed_files.is_empty() {
    state
    .repo
    .as_mut()
    .map(|repo| repo.switching_channel)
    .unwrap_or_default()
    } else {
    // If any changed files gets added, exit out of channel selection
    false
    };
    let forking_channel = state
    .repo
    .as_mut()
    .and_then(|repo| repo.forking_channel.take());
    let status_nav = state
    .repo
    .take()
    .map(|repo| repo.status_nav)
    .unwrap_or_default();
    // TODO: reload entire_log if it's being viewed or it's loading
    state.repo = Some(app::Repo {
    state: repo,
    status_nav,
    switching_channel,
    forking_channel,
    entire_log: None,
    });
    selection_task
    [10.1650]
    [42.8830]
    // Re-index selection
    let selection_task =
    reindex_selection(repo, selection, &mut state.files, logs);
    return selection_task;
    }
    }
    Task::none()
  • edit in inflorescence/src/main.rs at line 769
    [42.8931]
    [69.21753]
    repo: &repo::State,
  • replacement in inflorescence/src/main.rs at line 772
    [42.8992][42.8992:9093]()
    untracked_files: &BTreeSet<String>,
    changed_files: &repo::ChangedFiles,
    log: &repo::Log,
    [42.8992]
    [42.9093]
    logs: &Logs,
  • replacement in inflorescence/src/main.rs at line 774
    [42.9110][69.21792:21860]()
    if let Some(current_selection) = selection.view.status.take() {
    [42.9110]
    [69.21860]
    let status_task = if let Some(current_selection) = selection.status.take() {
  • replacement in inflorescence/src/main.rs at line 781
    [54.13965][39.10022:10070](),[9.15250][39.10022:10070]()
    let selection = untracked_files
    [54.13965]
    [39.10070]
    let selection = repo
    .untracked_files
  • replacement in inflorescence/src/main.rs at line 809
    [54.14146][39.10682:10728](),[39.10682][39.10682:10728]()
    let selection = changed_files
    [54.14146]
    [39.10728]
    let selection = repo
    .changed_files
  • replacement in inflorescence/src/main.rs at line 823
    [60.2439][60.2439:2505]()
    && let Some(diffs) = changed_files.get(&path)
    [60.2439]
    [60.2505]
    && let Some(diffs) = repo.changed_files.get(&path)
  • replacement in inflorescence/src/main.rs at line 843
    [73.49013][39.11538:11574](),[39.11538][39.11538:11574]()
    let selection = log
    [73.49013]
    [39.11574]
    let selection = repo
    .short_log
  • replacement in inflorescence/src/main.rs at line 890
    [42.10442][69.22392:22439]()
    selection.view.status = new_selection;
    [42.10442]
    [26.9662]
    selection.status = new_selection;
  • replacement in inflorescence/src/main.rs at line 895
    [39.12720][42.10481:10487](),[42.10487][39.12767:12769](),[39.12767][39.12767:12769]()
    }
    }
    [39.12720]
    [25.2586]
    };
  • replacement in inflorescence/src/main.rs at line 897
    [25.2587][39.12770:12819](),[39.12819][64.12245:12273](),[64.12273][39.12842:12890](),[39.12842][39.12842:12890](),[64.12318][73.49119:49254]()
    fn repo_got_change_diffs(
    state: &mut State,
    hash: repo::ChangeHash,
    diffs: repo::ChangedFiles,
    ) -> Task<Msg> {
    if let Some(app::EntireLog::Got { .. }) = state
    .repo
    .as_ref()
    .and_then(|repo| repo.entire_log.as_ref())
    [25.2587]
    [39.13098]
    let channel_task = if let Some(selection::Channel { ix: _, name, log }) =
    selection.channel.take()
  • replacement in inflorescence/src/main.rs at line 900
    [39.13104][73.49255:49502]()
    let Some(selection::LogChange {
    ix: _,
    hash: selected_hash,
    message: _,
    file,
    }) = state.selection.view.entire_log.as_mut()
    else {
    return Task::none();
    };
    [39.13104]
    [73.49502]
    let (new_selection, task) = {
    let selection = repo
    .other_channels
    .iter()
    .enumerate()
    .find(|(_ix, channel_name)| *channel_name == &name)
    // TODO: re-index log selection once loaded for channels
    .map(|(ix, _name)| selection::Channel { ix, name, log });
  • replacement in inflorescence/src/main.rs at line 909
    [73.49503][73.49503:49582]()
    if *selected_hash != hash {
    return Task::none();
    }
    [73.49503]
    [73.49582]
    let task = if let Some(selection::Channel { name, .. }) =
    selection.as_ref()
    {
    // Request to get the log
    Task::done(Msg::View(app::Msg::ToRepo(
    repo::MsgIn::LoadOtherChannelLog(name.clone()),
    )))
    } else {
    Task::none()
    };
  • replacement in inflorescence/src/main.rs at line 920
    [73.49583][75.20947:20991](),[75.20991][64.12436:12500](),[73.49638][64.12436:12500](),[64.12436][64.12436:12500](),[64.12500][75.20992:21054](),[75.21054][64.12725:12794](),[64.12725][64.12725:12794]()
    if let Some(file) = file.as_ref() {
    // If a file is selected, init the nav for its diff
    let diffs_nav = nav_scrollable::State::default();
    let id_hash = file::log_id_parts_hash(hash, &file.path);
    [73.49583]
    [64.12794]
    (selection, task)
    };
    selection.channel = new_selection;
    task
    } else {
    Task::none()
    };
  • replacement in inflorescence/src/main.rs at line 928
    [64.12795][73.49639:49709]()
    state.entire_logs.diffs_nav = Some((id_hash, diffs_nav));
    [64.12795]
    [64.13066]
    let entire_log_task = if let Some(selection::LogChange {
    ix: _,
    hash,
    message,
    file,
    }) = selection.entire_log.take()
    {
    let new_selection =
    if let Some(Log::Loaded { log }) = logs.entire_log.as_ref() {
    log.iter()
    .enumerate()
    .find(|(_ix, entry)| entry.hash == hash)
    .map(|(ix, entry)| {
    let file = file.and_then(
    |selection::LogChangeFileSelection {
    ix: _,
    path: selected_path,
    diff_selected,
    }| {
    entry
    .file_paths
    .iter()
    .enumerate()
    .find(|(_ix, path)| *path == &selected_path)
    .map(|(ix, path)| {
    selection::LogChangeFileSelection {
    ix,
    path: path.clone(),
    diff_selected,
    }
    })
    },
    );
    selection::LogChange {
    ix,
    hash: entry.hash,
    message,
    file,
    }
    })
    } else {
    None
    };
    let task = if new_selection.is_some() {
    // Request to get the entire log
    Task::done(Msg::View(app::Msg::ToRepo(repo::MsgIn::LoadEntireLog)))
  • replacement in inflorescence/src/main.rs at line 976
    [64.13083][64.13083:13134](),[64.13134][75.21055:21119](),[75.21119][73.49710:49781](),[64.13257][73.49710:49781]()
    // Init scrollable nav for log changes
    let changes_nav = nav_scrollable::State::default();
    state.entire_logs.changes_nav = Some((hash, changes_nav));
    [64.13083]
    [73.49913]
    Task::none()
  • edit in inflorescence/src/main.rs at line 978
    [73.49924]
    [73.49924]
    selection.entire_log = new_selection;
    task
    } else {
    Task::none()
    };
  • edit in inflorescence/src/main.rs at line 986
    [73.49925]
    [73.49925]
    Task::batch([status_task, channel_task, entire_log_task])
    }
    fn repo_got_change_diffs(
    state: &mut State,
    hash: repo::ChangeHash,
    diffs: repo::ChangedFiles,
    ) -> Task<Msg> {
    if let Some(ReadyState {
    selection,
    navigation,
    logs,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
  • replacement in inflorescence/src/main.rs at line 1002
    [73.49954][75.21120:21186]()
    state.entire_logs.changes_with_loaded_diffs.insert(hash);
    [73.49954]
    [73.50073]
    navigation.log_diffs.changes_with_loaded_diffs.insert(hash);
  • replacement in inflorescence/src/main.rs at line 1018
    [73.50714][73.50714:50782]()
    state.entire_logs.diffs.insert(id_hash, log_file_diff);
    [73.50714]
    [73.50782]
    navigation.log_diffs.diffs.insert(id_hash, log_file_diff);
  • replacement in inflorescence/src/main.rs at line 1020
    [73.50794][75.21187:21208](),[75.21208][73.50807:51013](),[73.50807][73.50807:51013](),[73.51013][75.21209:21245](),[75.21245][73.51060:51176](),[73.51060][73.51060:51176](),[73.51176][75.21246:21312](),[75.21312][73.51456:51529](),[73.51456][73.51456:51529]()
    Task::none()
    } else if let Some(selection::Status::LogChange(selection::LogChange {
    ix: _,
    hash: selected_hash,
    message: _,
    file,
    })) = state.selection.view.status.as_mut()
    {
    if *selected_hash == hash {
    if let Some(file) = file.as_ref() {
    // If a file is selected, init the nav for its diff
    let diffs_nav = nav_scrollable::State::default();
    let id_hash = file::log_id_parts_hash(hash, &file.path);
    [73.50794]
    [64.13321]
    match selection::unify(selection) {
    selection::Unified::Status(Some(selection::Status::LogChange(
    selection::LogChange {
    ix: _,
    hash: selected_hash,
    message: _,
    file,
    },
    ))) => {
    if *selected_hash != hash {
    return Task::none();
    }
    if let Some(file) = file.as_ref() {
    // If a file is selected, init the nav for its diff
    let diffs_nav = nav_scrollable::State::default();
    let id_hash = file::log_id_parts_hash(hash, &file.path);
  • replacement in inflorescence/src/main.rs at line 1039
    [64.13322][73.51530:51604](),[73.51836][73.51836:51912](),[73.51912][75.21313:21381]()
    state.status_logs.diffs_nav = Some((id_hash, diffs_nav));
    } else {
    // Init scrollable nav for log changes
    let changes_nav = nav_scrollable::State::default();
    [64.13322]
    [73.52081]
    navigation.status_logs_navs.diffs_nav =
    Some((id_hash, diffs_nav));
    } else {
    // Init scrollable nav for log files
    let changes_nav = nav_scrollable::State::default();
  • replacement in inflorescence/src/main.rs at line 1045
    [73.52082][73.52082:52157]()
    state.status_logs.changes_nav = Some((hash, changes_nav));
    [73.52082]
    [73.52295]
    navigation.status_logs_navs.files_nav =
    Some((hash, changes_nav));
    }
  • replacement in inflorescence/src/main.rs at line 1049
    [73.52351][64.14124:14135](),[64.14124][64.14124:14135](),[64.14135][73.52352:52381](),[73.52381][75.21382:21448](),[75.21448][73.52500:52913](),[73.52500][73.52500:52913]()
    };
    // Store the changes
    state.status_logs.changes_with_loaded_diffs.insert(hash);
    diffs.into_iter().for_each(|(path, diffs)| {
    // NOTE: using unknown encoding as we don't yet have the file
    // for past changes
    let file = diff::init_file(
    diff::FileContent::UnknownEncoding,
    Some(&diffs),
    );
    let id_hash = file::log_id_parts_hash(hash, &path);
    let log_file_diff = diff::FileAndState {
    [73.52309]
    [73.52913]
    selection::Unified::EntireLog(Some(selection::LogChange {
    ix: _,
    hash: selected_hash,
    message: _,
  • replacement in inflorescence/src/main.rs at line 1054
    [73.52935][73.52935:53140]()
    // The nav is initialized only once a file is selected,
    // because its tasks need it to be visible to complete
    state: diff::State::default(),
    };
    [73.52935]
    [64.14135]
    })) => {
    if *selected_hash != hash {
    return Task::none();
    }
  • replacement in inflorescence/src/main.rs at line 1059
    [64.14136][73.53141:53221](),[73.53221][75.21449:21470](),[75.21470][73.53234:53268](),[73.53234][73.53234:53268]()
    state.status_logs.diffs.insert(id_hash, log_file_diff);
    });
    Task::none()
    } else {
    Task::none()
    [64.14136]
    [73.53268]
    let Some(Log::Loaded { .. }) = logs.entire_log.as_ref() else {
    return Task::none();
    };
    if let Some(file) = file.as_ref() {
    // If a file is selected, init the nav for its diff
    let diffs_nav = nav_scrollable::State::default();
    let id_hash = file::log_id_parts_hash(hash, &file.path);
    navigation.entire_logs_navs.diffs_nav =
    Some((id_hash, diffs_nav));
    } else {
    // Init scrollable nav for log files
    let changes_nav = nav_scrollable::State::default();
    navigation.entire_logs_navs.files_nav =
    Some((hash, changes_nav));
    };
    }
    selection::Unified::Channel(Some(selection::Channel {
    ix: _,
    name,
    log:
    Some(selection::LogChange {
    ix: _,
    hash: selected_hash,
    message: _,
    file,
    }),
    })) => {
    if *selected_hash != hash {
    return Task::none();
    }
    let Some(Log::Loaded { .. }) =
    logs.other_channels_logs.get(name)
    else {
    return Task::none();
    };
    if let Some((selected_name, navs)) =
    navigation.other_channel_log_navs.as_mut()
    && name == selected_name
    {
    if let Some(file) = file.as_ref() {
    // If a file is selected, init the nav for its diff
    let diffs_nav = nav_scrollable::State::default();
    let id_hash = file::log_id_parts_hash(hash, &file.path);
    navs.diffs_nav = Some((id_hash, diffs_nav));
    } else {
    // Init scrollable nav for log files
    let changes_nav = nav_scrollable::State::default();
    navs.files_nav = Some((hash, changes_nav));
    };
    }
    }
    _ => {}
    }
  • edit in inflorescence/src/main.rs at line 1118
    [73.53274]
    [73.53274]
    Task::none()
  • replacement in inflorescence/src/main.rs at line 1122
    [73.53345][73.53345:53527](),[73.53527][75.21471:21531](),[75.21531][73.53635:53781](),[73.53635][73.53635:53781](),[73.53860][73.53860:53874](),[73.53874][75.21532:21652](),[75.21652][73.54017:54110](),[73.54017][73.54017:54110](),[73.54110][75.21653:21693](),[75.21693][73.54155:54189](),[73.54155][73.54155:54189](),[73.54189][75.21694:21752]()
    if let Some(repo) = state.repo.as_mut() {
    match repo.entire_log.as_ref() {
    None
    | Some(app::EntireLog::Loading | app::EntireLog::Got { .. }) => {
    let nav = nav_scrollable::State::default();
    repo.entire_log = Some(app::EntireLog::Got {
    log,
    nav: Box::new(nav),
    });
    }
    Some(app::EntireLog::LoadingButNotViewing) => {
    let nav = nav_scrollable::State::default();
    repo.entire_log = Some(app::EntireLog::NotViewing {
    log,
    nav: Box::new(nav),
    });
    }
    Some(app::EntireLog::NotViewing { .. }) => {}
    [73.53345]
    [73.54189]
    if let Some(ReadyState { logs, .. }) = model::ready_mut(&mut state.sub) {
    logs.entire_log = Some(Log::Loaded { log });
    }
    Task::none()
    }
    fn loaded_other_channel_log(
    state: &mut State,
    channel: String,
    log: Vec<repo::LogEntry>,
    ) -> Task<Msg> {
    if let Some(ReadyState {
    navigation,
    selection,
    logs,
    ..
    }) = model::ready_mut(&mut state.sub)
    {
    if let Some(selection::Channel {
    name: selection_name,
    ..
    }) = selection.channel.as_ref()
    && selection_name == &channel
    {
    navigation.other_channel_log_navs =
    Some((channel.clone(), log::Navs::default()));
  • edit in inflorescence/src/main.rs at line 1149
    [73.54199]
    [73.54199]
    logs.other_channels_logs
    .insert(channel, Log::Loaded { log });
  • replacement in inflorescence/src/main.rs at line 1334
    [60.3737][32.28532:28563](),[34.9026][32.28532:28563](),[32.28532][32.28532:28563](),[32.28563][48.5770:5791](),[48.5791][32.28563:28645](),[32.28563][32.28563:28645](),[32.28645][69.27156:27175](),[69.27175][32.28661:28696](),[32.28661][32.28661:28696](),[32.28696][54.17577:17598](),[54.17598][73.58741:58783](),[51.6242][32.28717:28732](),[64.14983][32.28717:28732](),[54.17623][32.28717:28732](),[73.58783][32.28717:28732](),[32.28717][32.28717:28732](),[32.28732][51.6243:6244](),[51.6244][69.27176:27290](),[69.27290][64.15045:15061](),[54.17672][64.15045:15061](),[64.15061][54.17691:17709](),[54.17691][54.17691:17709](),[54.17709][64.15062:15089](),[64.15089][54.17739:17831](),[54.17739][54.17739:17831](),[54.17831][64.15090:15153](),[64.15153][66.37:302](),[66.302][64.15489:15731](),[64.15489][64.15489:15731](),[64.15731][52.3368:3386](),[54.17968][52.3368:3386](),[52.3368][52.3368:3386](),[52.3386][66.303:449](),[66.449][64.15732:15747](),[52.3444][64.15732:15747](),[64.15747][69.27291:27346](),[69.27346][64.15796:15880](),[64.15796][64.15796:15880](),[52.3458][51.6542:6552](),[64.15880][51.6542:6552](),[51.6542][51.6542:6552](),[51.6552][69.27347:27393](),[69.27393][54.18015:18033](),[54.18015][54.18015:18033](),[54.18033][64.15881:15924](),[64.15924][54.18082:18172](),[54.18082][54.18082:18172](),[54.18172][64.15925:15988](),[64.15988][66.450:715](),[66.715][64.16324:16566](),[64.16324][64.16324:16566](),[64.16566][52.3662:3680](),[54.18309][52.3662:3680](),[52.3662][52.3662:3680](),[52.3680][66.716:862](),[66.862][64.16567:16582](),[52.3738][64.16567:16582](),[64.16582][67.13489:13859](),[67.13859][69.27394:27447](),[69.27447][64.16629:16698](),[64.16629][64.16629:16698](),[64.16698][67.13860:13901](),[67.13901][64.16698:16713](),[64.16698][64.16698:16713](),[52.3752][51.6782:6792](),[64.16713][51.6782:6792](),[51.6782][51.6782:6792](),[51.6792][73.58784:60549](),[69.27492][64.16714:16738](),[73.60549][64.16714:16738](),[51.6978][64.16714:16738](),[64.16738][51.6997:7015](),[51.6997][51.6997:7015](),[51.7015][64.16739:16778](),[64.16778][51.7111:7127](),[54.18493][51.7111:7127](),[51.7111][51.7111:7127](),[51.7127][64.16779:16821](),[64.16821][69.27493:27546](),[69.27546][64.16871:17064](),[64.16871][64.16871:17064](),[64.17064][73.60550:60621](),[73.60621][66.927:1093](),[66.927][66.927:1093](),[66.1093][73.60622:60699](),[73.60699][66.1163:1402](),[66.1163][66.1163:1402](),[66.1402][64.17781:18037](),[64.17781][64.17781:18037](),[64.18037][73.60700:60734](),[73.60734][64.18064:18199](),[64.18064][64.18064:18199](),[64.18199][73.60735:60778](),[69.27592][64.18238:18379](),[73.60778][64.18238:18379](),[64.18238][64.18238:18379](),[52.3865][51.7354:7364](),[64.18379][51.7354:7364](),[54.18686][51.7354:7364](),[51.7354][51.7354:7364](),[51.7364][64.18380:18402](),[52.3944][51.7383:7391](),[64.18402][51.7383:7391](),[51.7383][51.7383:7391](),[51.7391][64.18403:18515](),[65.728][64.18531:18572](),[64.18531][64.18531:18572](),[64.18572][69.27593:27679](),[69.27679][73.60779:60809](),[69.27679][64.18591:18645](),[73.60809][64.18591:18645](),[64.18591][64.18591:18645]()
    let State {
    id: _,
    window_size,
    repo_fs_watch: _,
    repo_path,
    repo_tx_in: _,
    repo,
    selection,
    record_msg,
    files,
    files_diffs,
    status_logs,
    entire_logs,
    } = state;
    let status_selection = match selection.view.status.as_ref() {
    Some(selection::Status::UntrackedFile {
    ix,
    path,
    diff_selected,
    }) => {
    let id_hash = file::id_parts_hash(path, file::Kind::Untracked);
    let diff = files.diffs_cache.inner.peek(&id_hash);
    let nav = files_diffs.diffs_nav.as_ref().and_then(
    |(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav),
    );
    let diff = match (diff, nav) {
    (Some(file::Diff::Loaded(file)), Some(nav)) => {
    files_diffs.diffs.get(&id_hash).map(|state| app::Diff {
    is_selected: *diff_selected,
    file,
    state,
    nav,
    })
    }
    (
    Some(file::Diff::Loaded(_) | file::Diff::Loading) | None,
    _,
    ) => None,
    };
    Some(app::StatusSelection::UntrackedFile {
    ix: *ix,
    path,
    diff,
    })
    }
    Some(selection::Status::ChangedFile {
    path,
    ix,
    diff_selected,
    }) => {
    let id_hash = file::id_parts_hash(path, file::Kind::Changed);
    let diff = files.diffs_cache.inner.peek(&id_hash);
    let nav = files_diffs.diffs_nav.as_ref().and_then(
    |(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav),
    );
    let diff = match (diff, nav) {
    (Some(file::Diff::Loaded(file)), Some(nav)) => {
    files_diffs.diffs.get(&id_hash).map(|state| app::Diff {
    is_selected: *diff_selected,
    file,
    state,
    nav,
    })
    }
    (
    Some(file::Diff::Loaded(_) | file::Diff::Loading) | None,
    _,
    ) => None,
    };
    let is_added_from_untracked = repo
    .as_ref()
    .and_then(|repo| repo.state.changed_files.get(path))
    .map(|diffs| {
    diffs
    .iter()
    .any(|diff| matches!(diff, repo::ChangedFileDiff::Add))
    })
    .unwrap_or_default();
    Some(app::StatusSelection::ChangedFile {
    ix: *ix,
    path,
    diff,
    is_added_from_untracked,
    })
    }
    Some(selection::Status::LogChange(selection::LogChange {
    ix: log_ix,
    hash,
    message,
    file,
    })) => {
    let file = file.as_ref().map(
    |selection::LogChangeFileSelection {
    ix: change_ix,
    path,
    diff_selected,
    }| {
    let id_hash = file::log_id_parts_hash(*hash, path);
    let nav = status_logs.diffs_nav.as_ref().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    );
    let diff = status_logs.diffs.get(&id_hash).zip(nav).map(
    |(diff::FileAndState { file, state }, nav)| app::Diff {
    is_selected: *diff_selected,
    file,
    state,
    nav,
    },
    );
    app::LogChangeFileSelection {
    ix: *change_ix,
    path,
    diff,
    }
    },
    );
    let nav = status_logs
    .changes_nav
    .as_ref()
    .and_then(|(nav_hash, nav)| (nav_hash == hash).then_some(nav));
    Some(app::StatusSelection::Log {
    ix: *log_ix,
    hash: *hash,
    message,
    file,
    nav,
    })
    }
    None => None,
    };
    let entire_log_selection = match selection.view.entire_log.as_ref() {
    Some(selection::LogChange {
    ix: log_ix,
    hash,
    message,
    file,
    }) => {
    let file = file.as_ref().map(
    |selection::LogChangeFileSelection {
    ix: change_ix,
    path,
    diff_selected,
    }| {
    let id_hash = file::log_id_parts_hash(*hash, path);
    let nav = entire_logs.diffs_nav.as_ref().and_then(
    |(nav_id_hash, nav)| {
    (*nav_id_hash == id_hash).then_some(nav)
    },
    );
    let diff = entire_logs.diffs.get(&id_hash).zip(nav).map(
    |(diff::FileAndState { file, state }, nav)| app::Diff {
    is_selected: *diff_selected,
    file,
    state,
    nav,
    },
    );
    app::LogChangeFileSelection {
    ix: *change_ix,
    path,
    diff,
    }
    },
    );
    let nav = entire_logs
    .changes_nav
    .as_ref()
    .and_then(|(nav_hash, nav)| (nav_hash == hash).then_some(nav));
    Some(app::EntireLogSelection {
    ix: *log_ix,
    hash: *hash,
    message,
    file,
    nav,
    })
    }
    None => None,
    };
    let state = app::State {
    window_size: *window_size,
    repo_path,
    repo: repo.as_ref(),
    record_msg: record_msg.as_ref(),
    status_selection,
    channel_selection: selection.view.channel.as_ref(),
    entire_log_selection,
    };
    app::view(state, window_id).map(Msg::View)
    [60.3737]
    [24.20154]
    app::view(
    &state.sub,
    |id_hash| file::try_get_src_file(&state.files, id_hash),
    window_id,
    )
    .map(Msg::View)
  • file addition: log.rs (----------)
    [27.364]
    //! Dealing with record logs.
    #[doc(inline)]
    pub use inflorescence_model::log::Navs;
    use crate::file;
    use iced_expl_widget::nav_scrollable;
    pub fn log_diff_needs_scrolling(logs: &Navs, id_hash: file::LogIdHash) -> bool {
    logs.diffs_nav
    .as_ref()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    .map(nav_scrollable::needs_scrolling)
    .unwrap_or_default()
    }
  • replacement in inflorescence/src/file.rs at line 5
    [54.18720][54.18720:18823]()
    id_hash, id_parts_hash, log_id_parts_hash, Diff, Id, IdHash, IdMap, Kind,
    LogIdHash, LogIdMap,
    [54.18720]
    [54.18823]
    id_hash, id_parts_hash, log_id_parts_hash, Diff, Id, IdHash, Kind,
    LogIdHash,
  • replacement in inflorescence/src/file.rs at line 103
    [50.7844][50.7844:7876]()
    repo: Option<&repo::State>,
    [50.7844]
    [50.7876]
    repo: &repo::State,
  • replacement in inflorescence/src/file.rs at line 141
    [29.5365][29.5365:5497]()
    if let Some(repo) = repo {
    let changed_file = repo.changed_files.get(&id.path);
    [29.5365]
    [29.5497]
    let changed_file = repo.changed_files.get(&id.path);
  • replacement in inflorescence/src/file.rs at line 143
    [29.5498][29.5498:5631](),[50.8220][53.989:1107]()
    let file_diff: diff::File =
    diff::init_file(file_content, changed_file);
    let skip_sections =
    diff::unchanged_sections(&file_diff);
    [29.5498]
    [50.8220]
    let file_diff: diff::File =
    diff::init_file(file_content, changed_file);
    let skip_sections =
    diff::unchanged_sections(&file_diff);
  • replacement in inflorescence/src/file.rs at line 148
    [50.8221][29.5631:5732](),[29.5631][29.5631:5732](),[29.5732][54.19046:19087](),[50.8266][29.5768:5856](),[54.19087][29.5768:5856](),[29.5768][29.5768:5856]()
    diffs_cache_put(
    &mut state.diffs_cache,
    id_hash,
    Diff::Loaded(file_diff),
    );
    [50.8221]
    [50.8267]
    diffs_cache_put(
    &mut state.diffs_cache,
    id_hash,
    Diff::Loaded(file_diff),
    );
  • replacement in inflorescence/src/file.rs at line 154
    [50.8268][53.1108:1157](),[53.1157][54.19088:19129](),[53.1241][53.1241:1340](),[53.1340][29.5856:5882](),[50.8340][29.5856:5882](),[29.5856][29.5856:5882]()
    return Some(Loaded {
    id_hash,
    unchanged_sections: skip_sections,
    });
    }
    [50.8268]
    [29.5882]
    return Some(Loaded {
    id_hash,
    unchanged_sections: skip_sections,
    });
  • edit in inflorescence/src/diff.rs at line 3
    [19.5056][36.1680:1695](),[36.1695][75.21947:21988]()
    #[doc(inline)]
    pub use inflorescence_view::diff::State;
  • replacement in inflorescence/src/diff.rs at line 4
    [36.1749][36.1749:1781]()
    pub use libflorescence::diff::{
    [36.1749]
    [36.1781]
    pub use inflorescence_model::diff::{
  • replacement in inflorescence/src/diff.rs at line 6
    [36.1845][50.8401:8469](),[50.8469][36.1920:1941](),[36.1920][36.1920:1941]()
    DiffWithoutContents, File, Lines, Section, UndecodableContents,
    UndecodableFile,
    [36.1845]
    [36.1941]
    DiffWithoutContents, File, FileAndState, FileContent, FilesState, Lines,
    Section, State, UndecodableContents, UndecodableFile,
  • edit in inflorescence/src/diff.rs at line 14
    [19.5154][32.29117:29139]()
    use std::borrow::Cow;
  • edit in inflorescence/src/diff.rs at line 16
    [64.19016][54.19693:19694](),[75.22059][54.19693:19694](),[53.1373][54.19693:19694](),[54.19694][64.19017:19314](),[64.19314][75.22060:22126](),[75.22126][64.19372:19374](),[64.19372][64.19372:19374](),[64.19374][54.19736:19793](),[54.19736][54.19736:19793](),[54.19793][75.22127:22245](),[64.19610][54.19898:19964](),[75.22245][54.19898:19964](),[54.19898][54.19898:19964](),[54.19964][73.60812:60848](),[73.60848][54.19988:20033](),[54.19988][54.19988:20033](),[54.20033][75.22246:22539](),[64.20170][54.20033:20035](),[75.22539][54.20033:20035](),[54.20033][54.20033:20035](),[53.1373][23.287:288](),[54.20035][23.287:288](),[32.29153][23.287:288](),[23.287][23.287:288](),[23.288][54.20036:20121](),[50.8814][50.8814:8816](),[50.8816][21.1927:1928](),[32.29202][21.1927:1928](),[21.1927][21.1927:1928](),[20.19291][20.19291:19308](),[19.5887][20.19633:19687](),[20.19687][21.2490:2511](),[21.2842][21.2842:2844]()
    #[derive(Debug, Default)]
    pub struct FilesState {
    pub diffs: file::IdMap<State>,
    /// Diffs scrollable nav.
    ///
    /// Only the current nav is kept because the sizes of contents have to be
    /// queried everytime the selection changes due to possible container size
    /// changes.
    pub diffs_nav: Option<(file::IdHash, nav_scrollable::State)>,
    }
    #[derive(Debug, Default)]
    pub struct LogFilesAndState {
    /// All the hashes in this set have `diffs` loaded.
    pub changes_with_loaded_diffs: HashSet<repo::ChangeHash>,
    /// All the diffs in this map have the change hash present in
    /// `change_file_counts`'s keys
    pub diffs: file::LogIdMap<FileAndState>,
    /// Log changes scrollable nav. Only the currently selected nav is kept.
    pub changes_nav: Option<(repo::ChangeHash, nav_scrollable::State)>,
    /// Log diffs scrollable nav. Only the currently selected nav is kept.
    pub diffs_nav: Option<(file::LogIdHash, nav_scrollable::State)>,
    }
    #[derive(Debug)]
    pub struct FileAndState {
    pub file: File,
    pub state: State,
    }
    #[derive(Debug)]
    pub enum FileContent<'a> {
    Decoded(Cow<'a, str>),
    UnknownEncoding,
    }
  • edit in inflorescence/src/diff.rs at line 164
    [75.22575][75.22575:22749](),[75.22749][54.20431:20538](),[54.20431][54.20431:20538](),[54.20538][75.22750:22769]()
    .as_ref()
    .and_then(|(nav_id_hash, nav)| (*nav_id_hash == id_hash).then_some(nav))
    .map(nav_scrollable::needs_scrolling)
    .unwrap_or_default()
    }
    pub fn log_diff_needs_scrolling(
    logs: &LogFilesAndState,
    id_hash: file::LogIdHash,
    ) -> bool {
    logs.diffs_nav
  • edit in inflorescence/Cargo.toml at line 15
    [2.3603]
    [30.812]
    [dependencies.inflorescence-model]
    workspace = true
  • edit in Cargo.toml at line 4
    [27.539]
    [30.865]
    "inflorescence_model",
  • edit in Cargo.toml at line 20
    [2.4043]
    [30.892]
    inflorescence-model = { path = "inflorescence_model" }
  • edit in Cargo.lock at line 2497
    [50.14971]
    [30.947]
    "inflorescence-model",
  • edit in Cargo.lock at line 2509
    [17.549]
    [30.971]
    name = "inflorescence-model"
    version = "0.1.0"
    dependencies = [
    "iced",
    "iced-expl-widget",
    "libflorescence",
    ]
    [[package]]
  • edit in Cargo.lock at line 2524
    [32.29741]
    [30.1043]
    "inflorescence-model",