refactor diffs handling
[?]
Jul 4, 2025, 12:12 PM
YKHE3XMWOWPGOWYSISF73MIAKN7WB3AHCV2OA4ECAFPF47YHUXEACDependencies
- [2]
WT3GA27Padd cursor with selection - [3]
UB2ITZJSrefresh changed files on FS changes - [4]
D7A7MSIHallow to defer or abandon record, add buttons - [5]
AMPZ2BXKshow changed files diffs (only Edit atm) - [6]
V55EAIWQadd src file LRU cache - [7]
ZVI4AWERwoot contents_diff - [8]
HC7ROIBCmove main diffs state out of cursor - [9]
FR52XEMWadd action for log change file diff - [10]
L6KSEFQImove cursor related stuff into its module - [11]
BFN2VHZSrefactor file stuff into sub-mod - [12]
23SFYK4Qbig view refactor into a new crate - [13]
OPXFZKEBview tests setup - [14]
3QVNMRNMtest non-empty repo app view - [15]
MYGIBRRHwip custom theme - [16]
XSZZB47Urefactor stuff into lib - [17]
3BK22XE5add a test for hover btn and more refactors - [18]
ACDXXAX2refactor main's updates into smaller fns - [19]
ESMM3FELtest selection reindexing - [20]
TSFQFCB2test got repo change - [21]
7SSBM4UQview: refactor repo view - [22]
S2T7RUKWadd nav back placeholder - [23]
I2AG42PAnew cols layout - [24]
4PNWU55Oreplace the circular hor navigation - [25]
SASAN2XCuse nav-scrollable - [26]
XZ6D3UUEavoid alloc - [27]
ZD56BUSUadd back +/- bg colors - [28]
ONRCENKTrm unnecessary state from repo's internal state - [29]
Y5ATDI2Hconvert changed file diffs and load src only if any needs it - [30]
FVA36HBVrestart repo manager task if it crashes - [31]
SK3WVX7Aadd wee spacing for nav back - [32]
BJXUYQ2Yshow untracked file contents in read-only text editor - [33]
4WO3ZJM2show untracked files' contents - [34]
S2NVIFXRallow to enter record msg - [35]
JE44NYHMdisplay log files diffs - [36]
VJNWIGSXclippy - [37]
PKJCFSBMtheme improvements - [38]
I56UGW7Umake record test, fix log update - [*]
VCNKFNUFapp init test - [*]
6YZAVBWUInitial commit
Change contents
- edit in inflorescence_view/src/diff.rs at line 18
/// Initialized once the file is loadedpub contents_count: Option<usize>, - replacement in inflorescence_view/src/diff.rs at line 96[26.74]→[25.691:834](∅→∅),[25.691]→[25.691:834](∅→∅),[25.834]→[26.75:105](∅→∅),[26.105]→[25.834:898](∅→∅),[25.834]→[25.834:898](∅→∅)
el(column([el(text("NAV")),el(iced_nav_scrollable::view(nav,sections_view,children_len,Msg::NavScrollable,)),]))el(iced_nav_scrollable::view(nav,sections_view,children_len,Msg::NavScrollable,)) - replacement in inflorescence_view/src/diff.rs at line 138[25.1403]→[25.1403:1515](∅→∅),[25.1515]→[26.233:283](∅→∅),[26.283]→[25.1550:1614](∅→∅),[25.1550]→[25.1550:1614](∅→∅)
el(column([el(text("NAV")),el(iced_nav_scrollable::view(nav,diffs,diffs_len,Msg::NavScrollable,)),]))el(iced_nav_scrollable::view(nav,diffs,diffs_len,Msg::NavScrollable,)) - edit in inflorescence_view/src/cursor.rs at line 1
use crate::diff; - edit in inflorescence_view/src/cursor.rs at line 2
use std::collections::HashMap; - edit in inflorescence_view/src/cursor.rs at line 31
/// All the diffs in this change keyed by file path. Loaded async/// and set to None only while loading. The/// `diff::State` is also in here so that is it/// preserved while navigating between files.diffs: Option<HashMap<String, (diff::File, diff::State)>>, - edit in inflorescence_view/src/app.rs at line 16
use std::collections::HashMap; - replacement in inflorescence_view/src/app.rs at line 30
pub diffs_state: &'a HashMap<file::Id, diff::State>,/// State of selected untracked of changed file, if anypub selected_diff: Option<&'a diff::State>,/// Diff and state of selected log's file, if anypub selected_log_diff: Option<(&'a diff::File, &'a diff::State)>, - replacement in inflorescence_view/src/app.rs at line 185
let selection_state = state.diffs_state.get(&id);diff::view(selection_state, file).map(move |msg| {diff::view(state.selected_diff, file).map(move |msg| { - replacement in inflorescence_view/src/app.rs at line 208
let selection_state = state.diffs_state.get(&id);diff::view(selection_state, file).map(move |msg| {diff::view(state.selected_diff, file).map(move |msg| { - edit in inflorescence_view/src/app.rs at line 227
diffs: _, - replacement in inflorescence_view/src/app.rs at line 307[23.2381]→[23.2381:2437](∅→∅),[23.2437]→[21.4203:4399](∅→∅),[21.4203]→[21.4203:4399](∅→∅),[21.4399]→[23.2438:2469](∅→∅),[23.2469]→[22.28:52](∅→∅),[21.5333]→[22.28:52](∅→∅),[22.52]→[23.2470:2887](∅→∅)
let col_2 = match state.cursor.selection.as_ref() {Some(cursor::Selection::LogChange {ix: _,hash,message: _,diffs,file: Some(cursor::LogChangeFileSelection { ix: _, path }),}) => Some(el(column([el(column([view_diff_header(format!("{path} changes in {}:",display_short_hash(hash))),match diffs {Some(diffs) => {let (file, state) = diffs.get(path).unwrap();diff::view(Some(state), file).map(|action| {Msg::LogChangeFileDiffAction {let col_2 =match state.cursor.selection.as_ref() {Some(cursor::Selection::LogChange {ix: _,hash,message: _,file: Some(cursor::LogChangeFileSelection { ix: _, path }),}) => Some(el(column([el(column([view_diff_header(format!("{path} changes in {}:",display_short_hash(hash))),match state.selected_log_diff {Some((file, state)) => diff::view(Some(state), file).map(|action| Msg::LogChangeFileDiffAction { - replacement in inflorescence_view/src/app.rs at line 326
}})}None => el(text("Loading diff..")),}),None => el(text("Loading diff..")),},]).width(Length::Fill).height(Length::Fill).spacing(SPACING)),// NOTE: This is currently never true - there are only up to 3// colsif hidden_cols == 2 {el(button(row([el(text("← ").font(Font::MONOSPACE)),el(text("Log")),])).on_press(Msg::Cursor(cursor::Msg::Left)))} else {el(row([])) - replacement in inflorescence_view/src/app.rs at line 347[23.3213]→[23.3213:3631](∅→∅),[22.574]→[21.5564:5575](∅→∅),[23.3631]→[21.5564:5575](∅→∅),[21.5564]→[21.5564:5575](∅→∅),[21.5575]→[22.575:634](∅→∅),[22.634]→[23.3632:3661](∅→∅)
.spacing(SPACING)),// NOTE: This is currently never true - there are only up to 3 colsif hidden_cols == 2 {el(button(row([el(text("← ").font(Font::MONOSPACE)),el(text("Log")),])).on_press(Msg::Cursor(cursor::Msg::Left)))} else {el(row([]))},]).width(Length::Fill).height(Length::Fill).spacing(SPACING))),.spacing(SPACING))), - replacement in inflorescence_view/src/app.rs at line 349
Some(cursor::Selection::UntrackedFile { .. })| Some(cursor::Selection::ChangedFile { .. })| Some(cursor::Selection::LogChange { .. })| None => None,};Some(cursor::Selection::UntrackedFile { .. })| Some(cursor::Selection::ChangedFile { .. })| Some(cursor::Selection::LogChange { .. })| None => None,}; - replacement in inflorescence_view/src/app/test.rs at line 6
use libflorescence::prelude::pijul::{self, HashMap};use libflorescence::prelude::pijul; - edit in inflorescence_view/src/app/test.rs at line 34
let diffs_state = HashMap::new(); - replacement in inflorescence_view/src/app/test.rs at line 42
diffs_state: &diffs_state,selected_diff: None,selected_log_diff: None, - replacement in inflorescence_view/src/app/test.rs at line 69
diffs_state: &diffs_state,selected_diff: None,selected_log_diff: None, - replacement in inflorescence_view/src/app/test.rs at line 109
diffs_state: &diffs_state,selected_diff: None,selected_log_diff: None, - replacement in inflorescence_view/src/app/test.rs at line 129
diffs_state: &diffs_state,selected_diff: None,selected_log_diff: None, - replacement in inflorescence_view/src/app/test.rs at line 159
diffs_state: &diffs_state,selected_diff: None,selected_log_diff: None, - edit in inflorescence/src/test.rs at line 628
diffs: None, - replacement in inflorescence/src/test.rs at line 694
// Case: selection is changed// Case: selection is changed and doesn't match the loaded diff - edit in inflorescence/src/test.rs at line 700
diffs: None, - edit in inflorescence/src/test.rs at line 706
assert_matches!(state.cursor.selection.as_ref().unwrap(),cursor::Selection::LogChange { diffs: None, .. }); - replacement in inflorescence/src/test.rs at line 708
// Case: selection is still the same// Case: selection is still the same and matches the loaded diff - edit in inflorescence/src/test.rs at line 714
diffs: None, - replacement in inflorescence/src/test.rs at line 718
assert!(task.is_none());// Initializes nav-scrollables for diffsassert!(task.is_some()); - edit in inflorescence/src/test.rs at line 721
assert_matches!(state.cursor.selection.as_ref().unwrap(),cursor::Selection::LogChange { diffs: Some(_), .. }); - replacement in inflorescence/src/main.rs at line 102
diffs_state: HashMap::new(),files_diffs: HashMap::new(),log_diffs: HashMap::new(), - edit in inflorescence/src/main.rs at line 119
/// Cache for untracked and changed files loaded from disk - replacement in inflorescence/src/main.rs at line 121
// Diffs for untracked and changed filesdiffs_state: HashMap<file::Id, diff::State>,/// Diffs for untracked and changed filesfiles_diffs: HashMap<file::Id, diff::State>,/// The diffs are loaded async and not present while loading.log_diffs: HashMap<LogFileId, LogFileDiff>, - edit in inflorescence/src/main.rs at line 148
}#[derive(Debug, Clone, PartialEq, Eq, Hash)]struct LogFileId {pub hash: pijul::Hash,pub path: String,}#[derive(Debug)]struct LogFileDiff {pub diff: diff::File,pub state: diff::State, - replacement in inflorescence/src/main.rs at line 194
state.diffs_state.entry(id.clone()).or_default();state.files_diffs.entry(id.clone()).or_default(); - replacement in inflorescence/src/main.rs at line 206
if let Some(diff_state) = state.diffs_state.get_mut(&id) {if let Some(diff_state) = state.files_diffs.get_mut(&id) { - replacement in inflorescence/src/main.rs at line 221
diffs: Some(diffs),file: _,file: Some(cursor::LogChangeFileSelection { ix: _, path }), - replacement in inflorescence/src/main.rs at line 225
if let Some((_file, diff_state)) = diffs.get_mut(&file) {let task = diff::update(diff_state, msg);let id = LogFileId {hash,path: path.clone(),};if let Some(LogFileDiff { diff: _, state }) =state.log_diffs.get_mut(&id){let task = diff::update(state, msg); - replacement in inflorescence/src/main.rs at line 285
app::Msg::Cursor(msg) => {let log_file_selection_before =if let Some(cursor::Selection::LogChange {file: Some(file),..}) = state.cursor.selection.as_ref(){Some(file.ix)} else {None};let cursor_task = cursor::update(&mut state.cursor,&mut state.files,state.repo.as_ref(),msg,).map(|msg| Msg::View(app::Msg::ToRepo(msg)));// If the log file selection has changed, initialize a nav for itif let Some(cursor::Selection::LogChange {hash,diffs: Some(diffs),file: Some(cursor::LogChangeFileSelection { ix, path }),..}) = state.cursor.selection.as_mut(){if Some(*ix) != log_file_selection_before {let (_file,diff::State {contents_count,nav,..},) = diffs.get_mut(path).unwrap();let (new_nav, nav_tasks) =iced_nav_scrollable::init(contents_count.unwrap());*nav = Some(new_nav);let hash = *hash;let path_clone = path.clone();return Task::batch([cursor_task,nav_tasks.map(move |msg| Msg::LogChangeDiff {hash,file: path_clone.clone(),msg: diff::Msg::NavScrollable(msg),}),]);}}cursor_task}app::Msg::Cursor(msg) => cursor::update(&mut state.cursor,&mut state.files,state.repo.as_ref(),msg,).map(|msg| Msg::View(app::Msg::ToRepo(msg))), - replacement in inflorescence/src/main.rs at line 488
let diffs = state.diffs_state.entry(id.clone()).or_default();let diffs = state.files_diffs.entry(id.clone()).or_default(); - replacement in inflorescence/src/main.rs at line 500
let diffs = state.diffs_state.entry(id.clone()).or_default();let diffs = state.files_diffs.entry(id.clone()).or_default(); - edit in inflorescence/src/main.rs at line 525
diffs: Some(diffs), - replacement in inflorescence/src/main.rs at line 533
let (_file, state) = diffs.get_mut(&file).unwrap();return diff::update(state, action).map(move |msg| {Msg::LogChangeDiff {hash,file: file.clone(),msg,}});let id = LogFileId {hash,path: file.clone(),};if let Some(LogFileDiff { diff: _, state }) =state.log_diffs.get_mut(&id){return diff::update(state, action).map(move |msg| {Msg::LogChangeDiff {hash,file: file.clone(),msg,}});} - edit in inflorescence/src/main.rs at line 681
diffs: _, - edit in inflorescence/src/main.rs at line 705
diffs: None, - edit in inflorescence/src/main.rs at line 739
diffs: selection_diffs @ None, - replacement in inflorescence/src/main.rs at line 743[18.13140]→[25.7332:7406](∅→∅),[25.7406]→[18.13170:13311](∅→∅),[18.13170]→[18.13170:13311](∅→∅),[18.13311]→[20.2371:2420](∅→∅),[20.2420]→[18.13383:13552](∅→∅),[18.13383]→[18.13383:13552](∅→∅),[18.13552]→[25.7407:7694](∅→∅),[25.7694]→[18.13611:13702](∅→∅),[18.13611]→[18.13611:13702](∅→∅)
let diffs: HashMap<String, (diff::File, diff::State)> = diffs.into_iter().map(|(path, diffs)| {// NOTE: using unknown encoding as we don't yet have// the file for past changeslet file = diff::init_file(diff::FileContent::UnknownEncoding,Some(&diffs),);let contents_count = diff::contents_count(&file);let state = diff::State {contents_count: Some(contents_count),..default()};(path.clone(), (file, state))}).collect();*selection_diffs = Some(diffs);let mut tasks = Vec::with_capacity(diffs.len());diffs.into_iter().for_each(|(path, diffs)| {// NOTE: using unknown encoding as we don't yet have the file// for past changeslet diff = diff::init_file(diff::FileContent::UnknownEncoding,Some(&diffs),);let contents_count = diff::contents_count(&diff);let (nav, nav_tasks) =iced_nav_scrollable::init(contents_count);let diff_state = diff::State {nav: Some(nav),state: libflorescence::diff::State::default(),};let path_clone = path.clone();let id = LogFileId { hash, path };let log_file_diff = LogFileDiff {diff,state: diff_state,};state.log_diffs.insert(id, log_file_diff);tasks.push(nav_tasks.map(move |msg| Msg::LogChangeDiff {hash,file: path_clone.clone(),msg: diff::Msg::NavScrollable(msg),}))});return Task::batch(tasks); - replacement in inflorescence/src/main.rs at line 846
diffs_state,files_diffs: diffs_state,log_diffs, - edit in inflorescence/src/main.rs at line 849
let selected_diff = match state.cursor.selection.as_ref() {Some(cursor::Selection::UntrackedFile { ix: _, path }) => {let id = file::Id {path: path.clone(),file_kind: file::Kind::Untracked,};diffs_state.get(&id)}Some(cursor::Selection::ChangedFile { path, ix: _ }) => {let id = file::Id {path: path.clone(),file_kind: file::Kind::Changed,};diffs_state.get(&id)}Some(cursor::Selection::LogChange { .. }) | None => None,};let selected_log_diff = match state.cursor.selection.as_ref() {Some(cursor::Selection::LogChange {ix: _,hash,message: _,file: Some(cursor::LogChangeFileSelection { ix: _, path }),}) => {let id = LogFileId {hash: *hash,path: path.clone(),};log_diffs.get(&id).map(|LogFileDiff { diff, state }| (diff, state))}_ => None,}; - replacement in inflorescence/src/main.rs at line 893
diffs_state,selected_diff,selected_log_diff, - edit in inflorescence/src/cursor.rs at line 79
diffs, - edit in inflorescence/src/cursor.rs at line 107
diffs, - edit in inflorescence/src/cursor.rs at line 230
diffs, - edit in inflorescence/src/cursor.rs at line 252
diffs, - edit in inflorescence/src/cursor.rs at line 321
diffs, - edit in inflorescence/src/cursor.rs at line 327
diffs, - edit in inflorescence/src/cursor.rs at line 357
diffs, - edit in inflorescence/src/cursor.rs at line 439
diffs: None, - edit in inflorescence/src/cursor.rs at line 450
diffs, - edit in inflorescence/src/cursor.rs at line 459
diffs, - edit in inflorescence/src/cursor.rs at line 525
diffs: None,