L6KSEFQIWICZJ6HJUFKLZQDEH6X2QMFM4Z7ZZUGMLDMFF7EHRXWAC WT3GA27PQ2AOAIGK65O3Q4DMX4AZDVNULBLRL6GF4QW6QCASUEAAC DVKSPF7R5QBWRHNADU7LK37OVZHOHNDSRETUVY6GNXWE74SHXSUAC UB2ITZJSDADVINSQEZ3HA6PVGA7OA6JYFG5GMSO7Y7LOXJC4FI7AC EC3TVL4X6VZZVLOKUN63LC73ADPHBHMZO7QMDXGX2ZPURVI4B4XQC KT5UYXGKEEXUHURNOYFVIG7WQ3Y3SJZMM2TP4OSW6NXSXQ5XXRHAC W7IUT3ZVMFH77IGKLAL7WX7IVVTGTY3FKEJ3WHMP3KI37B6NENLQC YBJRDOTCX3ZRDB5EVXJBR55FX3CADCSIGMYWNYVC2PD5W3GXR3DQC D7A7MSIHJS3IAOLEPK52M4CZLDPLO7JB3Y62XACT2AM6UUCPQ6BAC UCBNZULEO6OIEV3RZCAPP6ICALAR7JIS2LLG7IRSX6PVYMFQT5AAC 4WO3ZJM2RNYZCBPS7FGYAEBELYD57OSS7LEUYCWGZBCAY272SNQQC W4LFX7IHQ7SDX67ATSGWDB5IN6472ZJDBKY2XZ54SBJEYD5GAT5QC FDDPOH5RRFK323PLIFJM2K2NWTSE2LW525YMHWJA6KIFPY2QVQNQC NOB64XMRXRLXGYS4JMGTFQMH5KMD7DHSTQ4YYBZ73E4PICW7QBQAC V55EAIWQXWER2HWKZHPJBV7DDJMSPSPWSO3FSSAYODJHVDBHUN6QC NRCUG4R2NIM2ANIETSUZ7WZDXFOOCMJ73ROP5MDYJA4RUT4PYA4QC Y5ATDI2HRWTTYJAVUR7SVWQVB4ZKKDZF3UVE4JJQFZ7RX7H7VPJQC ZVI4AWERNOTDJ3765HJXRBZT57XPNKVONQ6TGOGNPOL2VN42KMJQC QMAUTRB6R5R7ABWT2JIDEA7LMILZOS3PGPZIF3YUFKRVLW6HGKTQC TTKR4Q76RBWCVB74UAYLVIOJIZQDSCSAXKPN7GM7WKFOA3TL47CQC OQ6HSAWHIRTAIIWMDGCTIOK47JDY7QVVAHLRDA2R5TTJKNSBFCWQC NWJD6VM6POMYKQTTPP3X6LVCWU3FHLDRIHMCSC2PPUT7JWNY42LAC AHWWRC73FXLSUDAJBU5UU76MZETHD3DSGJ7OLZPFEHXBDJ733QNAC UJPRF6DASB6TLFQSUZETOMCUVXIE5TXMCKWXMZR5SNE3IYCX4PMQC TEI5NQ3SCTU6JQIPU62B2AUXWRFSEU6DZYJG5T526G666VV5XXPAC JE44NYHM4QORCRKOF33QM42EDT7SBCPTULWGT6IVDL3D5LUHQXLAC ONRCENKTUB4JJMPXNAQQYEWDYD54TAGOLWH742GF4EH3KTHV7YLQC 4ELJZGRJNL6FXB33QTYDNPY57JA3WZPUXKLQRTGSLDM7W65PD3YQC HC7ROIBC66IBYFED4ZZM7RXGSNC2CCBWBI36RKM2G5FD5DKVEYMQC 6YZAVBWU6E5FYOI5JGEIPXGZLIKAW6LS2AOFIQWEE5DMOPPCD5PQC MJDGPSHGF62FTVWZBE7MFNJTUQD42OBVJEOSVPBT553UFJLTEMXQC let untracked_file_selection =|repo: &repo::State,ix: usize,diffs_cache: &mut DiffsCache,src_file_load_tx: &watch::Sender<(FileId, usize)>|-> cursor::Selection {let path = repo.untracked_files.iter().nth(ix).unwrap().clone();let id = FileId {path: path.clone(),file_kind: FileKind::Untracked,};load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);cursor::Selection::UntrackedFile { ix, path }};let changed_file_selection =|repo: &repo::State,ix: usize,diffs_cache: &mut DiffsCache,src_file_load_tx: &watch::Sender<(FileId, usize)>|-> cursor::Selection {let (path, diffs) = repo.changed_files.iter().nth(ix).unwrap();if any_diff_has_contents(diffs) {let id = FileId {path: path.clone(),file_kind: FileKind::Changed,};load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);}cursor::Selection::ChangedFile {ix,path: path.clone(),}};let log_selection = |repo: &repo::State,ix: usize|-> (cursor::Selection, Task<Message>) {let entry = repo.log.get(ix).unwrap();// Request to get the diffslet task = Task::done(Message::ToRepo(repo::MsgIn::GetChangeDiffs {hash: entry.hash,}));(cursor::Selection::LogChange {ix,hash: entry.hash,message: entry.message.clone(),diffs: None,file: None,},task,)};let log_file_selection = |log_entry: &repo::LogEntry,file_ix: usize|-> cursor::LogChangeFileSelection {let path = log_entry.file_paths.get(file_ix).unwrap().clone();cursor::LogChangeFileSelection { ix: file_ix, path }};
Message::CursorDown => {if let Some(repo) = state.repo.as_ref() {let (selection, task) = match state.cursor.selection.take() {Some(cursor::Selection::UntrackedFile { ix, path: _ }) => {let (selection, task) =if repo.untracked_files.len().saturating_sub(1)== ix{if !repo.changed_files.is_empty() {let ix = 0;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else if !repo.log.is_empty() {let ix = 0;log_selection(repo, ix)} else {let ix = 0;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())}} else {let ix = ix + 1;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(cursor::Selection::ChangedFile { ix, path: _ }) => {let (selection, task) =if repo.changed_files.len().saturating_sub(1) == ix{if !repo.log.is_empty() {let ix = 0;log_selection(repo, ix)} else if !repo.untracked_files.is_empty() {let ix = 0;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else {let ix = 0;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())}} else {let ix = ix + 1;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(cursor::Selection::LogChange {ix: log_ix,hash,message,diffs,file,}) => {let (selection, task) = match file {Some(cursor::LogChangeFileSelection {ix: file_ix,path: _,}) => {let log_entry = repo.log.get(log_ix).unwrap();let file_ix = if log_entry.file_paths.len().saturating_sub(1)== file_ix{0} else {file_ix + 1};let file =log_file_selection(log_entry, file_ix);(cursor::Selection::LogChange {ix: log_ix,hash,message,diffs,file: Some(file),},Task::none(),)}None => {let (selection, task) = if repo.log.len().saturating_sub(1)== log_ix{if !repo.untracked_files.is_empty() {let ix = 0;let selection =untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else if !repo.changed_files.is_empty() {let ix = 0;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else {let ix = 0;log_selection(repo, ix)}} else {let ix = log_ix + 1;log_selection(repo, ix)};(selection, task)}};(Some(selection), task)}None => {let (selection, task) =if !repo.untracked_files.is_empty() {let ix = 0;let selection = Some(untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,));(selection, Task::none())} else if !repo.changed_files.is_empty() {let ix = 0;let selection = Some(changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,));(selection, Task::none())} else if !repo.log.is_empty() {let ix = repo.log.len() - 1;let (selection, task) = log_selection(repo, ix);(Some(selection), task)} else {(None, Task::none())};(selection, task)}};state.cursor.selection = selection;task} else {Task::none()}}Message::CursorUp => {if let Some(repo) = state.repo.as_ref() {let (selection, task) = match state.cursor.selection.take() {Some(cursor::Selection::UntrackedFile { ix, path: _ }) => {let (selection, task) = if 0 == ix {if !repo.log.is_empty() {let ix = repo.log.len() - 1;log_selection(repo, ix)} else if !repo.changed_files.is_empty() {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else {let ix = repo.untracked_files.len() - 1;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())}} else {let ix = ix - 1;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(cursor::Selection::ChangedFile { ix, path: _ }) => {let (selection, task) = if 0 == ix {if !repo.untracked_files.is_empty() {let ix = repo.untracked_files.len() - 1;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else if !repo.log.is_empty() {let ix = repo.log.len() - 1;log_selection(repo, ix)} else {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())}} else {let ix = ix - 1;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(cursor::Selection::LogChange {ix: log_ix,hash,message,diffs,file,}) => {let (selection, task) = match file {Some(cursor::LogChangeFileSelection {ix: file_ix,path: _,}) => {let log_entry = repo.log.get(log_ix).unwrap();let file_ix = if 0 == file_ix {log_entry.file_paths.len() - 1} else {file_ix - 1};let file =log_file_selection(log_entry, file_ix);(cursor::Selection::LogChange {ix: log_ix,hash,message,diffs,file: Some(file),},Task::none(),)}None => {let (selection, task) = if 0 == log_ix {if !repo.changed_files.is_empty() {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else if !repo.untracked_files.is_empty() {let ix = repo.untracked_files.len() - 1;let selection =untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(selection, Task::none())} else {let ix = repo.log.len() - 1;log_selection(repo, ix)}} else {let ix = log_ix - 1;log_selection(repo, ix)};(selection, task)}};(Some(selection), task)}None => {let (selection, task) = if !repo.log.is_empty() {let ix = repo.log.len() - 1;let (selection, task) = log_selection(repo, ix);(Some(selection), task)} else if !repo.changed_files.is_empty() {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(Some(selection), Task::none())} else if !repo.untracked_files.is_empty() {let ix = repo.untracked_files.len() - 1;let selection = untracked_file_selection(repo,ix,&mut state.diffs_cache,&state.src_file_load_tx,);(Some(selection), Task::none())} else {(None, Task::none())};(selection, task)}};state.cursor.selection = selection;task} else {Task::none()}}Message::CursorLeft | Message::CursorRight => {if let Some(repo) = state.repo.as_ref() {let (selection, task): (Option<cursor::Selection>,Task<Message>,) = match state.cursor.selection.take() {Some(cursor::Selection::LogChange {ix,hash,message,diffs,file,}) => {if file.is_none() {let log_entry = repo.log.get(ix).unwrap();let (file, task) = if let Some(path) =log_entry.file_paths.first(){(Some(cursor::LogChangeFileSelection {ix: 0,path: path.clone(),}),Task::none(),)} else {(None, Task::none())};(Some(cursor::Selection::LogChange {ix,hash,message,diffs,file,}),task,)} else {(Some(cursor::Selection::LogChange {ix,hash,message,diffs,file: None,}),Task::none(),)}}selection @ (Some(cursor::Selection::UntrackedFile {..})| Some(cursor::Selection::ChangedFile {..})| None) => (selection, Task::none()),};state.cursor.selection = selection;task} else {Task::none()}}Message::CursorSelect(select) => {let (selection, task) = match select {cursor::Select::UntrackedFile { ix, path } => {load_src_file_if_not_cached(&mut state.diffs_cache,&state.src_file_load_tx,FileId {path: path.clone(),file_kind: FileKind::Untracked,},);(Some(cursor::Selection::UntrackedFile { ix, path }),Task::none(),)}cursor::Select::ChangedFile { ix, path } => {if let Some(diffs) = state.repo.as_ref().and_then(|repo| repo.changed_files.get(&path)){if any_diff_has_contents(diffs) {load_src_file_if_not_cached(&mut state.diffs_cache,&state.src_file_load_tx,FileId {path: path.clone(),file_kind: FileKind::Changed,},);}}(Some(cursor::Selection::ChangedFile { ix, path }),Task::none(),)}cursor::Select::LogChange { ix, hash, message } => {// Request to get the diffslet task = Task::done(Message::ToRepo(repo::MsgIn::GetChangeDiffs { hash },));(Some(cursor::Selection::LogChange {ix,hash,message,diffs: None,file: None,}),task,)}cursor::Select::LogChangeFile { ix: file_ix, path } => {match state.cursor.selection.take() {Some(cursor::Selection::LogChange {ix: change_ix,hash,message,diffs,file: _,}) => {let file = cursor::LogChangeFileSelection {ix: file_ix,path,};(Some(cursor::Selection::LogChange {ix: change_ix,hash,message,diffs,file: Some(file),}),Task::none(),)}selection => (selection, Task::none()),}}};state.cursor.selection = selection;task}
Message::Cursor(msg) => cursor::update(&mut state.cursor,&mut state.diffs_cache,state.repo.as_ref(),&state.src_file_load_tx,msg,).map(Message::ToRepo),
"j" => Some(Message::CursorDown),"k" => Some(Message::CursorUp),"h" => Some(Message::CursorLeft),"l" => Some(Message::CursorRight),
"j" => Some(Message::Cursor(cursor::Msg::CursorDown)),"k" => Some(Message::Cursor(cursor::Msg::CursorUp)),"h" => Some(Message::Cursor(cursor::Msg::CursorLeft)),"l" => Some(Message::Cursor(cursor::Msg::CursorRight)),
Key::Named(key::Named::ArrowDown) => Some(Message::CursorDown),Key::Named(key::Named::ArrowUp) => Some(Message::CursorUp),Key::Named(key::Named::ArrowLeft) => Some(Message::CursorLeft),
Key::Named(key::Named::ArrowDown) => {Some(Message::Cursor(cursor::Msg::CursorDown))}Key::Named(key::Named::ArrowUp) => {Some(Message::Cursor(cursor::Msg::CursorUp))}Key::Named(key::Named::ArrowLeft) => {Some(Message::Cursor(cursor::Msg::CursorLeft))}
}/// Returns true if any of the changed file's diffs has contentsfn any_diff_has_contents(changed_file: &repo::ChangedFile) -> bool {let (with_contents, _without_contents) =diff::from_repo_changed_file(changed_file);!with_contents.is_empty()
pub fn update(state: &mut State,diffs_cache: &mut DiffsCache,repo: Option<&repo::State>,src_file_load_tx: &watch::Sender<(FileId, usize)>,msg: Msg,) -> Task<repo::MsgIn> {match msg {Msg::CursorDown => {if let Some(repo) = repo.as_ref() {let (selection, task) = match state.selection.take() {Some(Selection::UntrackedFile { ix, path: _ }) => {let (selection, task) =if repo.untracked_files.len().saturating_sub(1)== ix{if !repo.changed_files.is_empty() {let ix = 0;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else if !repo.log.is_empty() {let ix = 0;log_selection(repo, ix)} else {let ix = 0;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())}} else {let ix = ix + 1;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(Selection::ChangedFile { ix, path: _ }) => {let (selection, task) =if repo.changed_files.len().saturating_sub(1) == ix{if !repo.log.is_empty() {let ix = 0;log_selection(repo, ix)} else if !repo.untracked_files.is_empty() {let ix = 0;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else {let ix = 0;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())}} else {let ix = ix + 1;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(Selection::LogChange {ix: log_ix,hash,message,diffs,file,}) => {let (selection, task) = match file {Some(LogChangeFileSelection {ix: file_ix,path: _,}) => {let log_entry = repo.log.get(log_ix).unwrap();let file_ix = if log_entry.file_paths.len().saturating_sub(1)== file_ix{0} else {file_ix + 1};let file =log_file_selection(log_entry, file_ix);(Selection::LogChange {ix: log_ix,hash,message,diffs,file: Some(file),},Task::none(),)}None => {let (selection, task) = if repo.log.len().saturating_sub(1)== log_ix{if !repo.untracked_files.is_empty() {let ix = 0;let selection =untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else if !repo.changed_files.is_empty() {let ix = 0;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else {let ix = 0;log_selection(repo, ix)}} else {let ix = log_ix + 1;log_selection(repo, ix)};(selection, task)}};(Some(selection), task)}None => {let (selection, task) =if !repo.untracked_files.is_empty() {let ix = 0;let selection = Some(untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,));(selection, Task::none())} else if !repo.changed_files.is_empty() {let ix = 0;let selection = Some(changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,));(selection, Task::none())} else if !repo.log.is_empty() {let ix = repo.log.len() - 1;let (selection, task) = log_selection(repo, ix);(Some(selection), task)} else {(None, Task::none())};(selection, task)}};state.selection = selection;task} else {Task::none()}}Msg::CursorUp => {if let Some(repo) = repo.as_ref() {let (selection, task) = match state.selection.take() {Some(Selection::UntrackedFile { ix, path: _ }) => {let (selection, task) = if 0 == ix {if !repo.log.is_empty() {let ix = repo.log.len() - 1;log_selection(repo, ix)} else if !repo.changed_files.is_empty() {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else {let ix = repo.untracked_files.len() - 1;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())}} else {let ix = ix - 1;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(Selection::ChangedFile { ix, path: _ }) => {let (selection, task) = if 0 == ix {if !repo.untracked_files.is_empty() {let ix = repo.untracked_files.len() - 1;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else if !repo.log.is_empty() {let ix = repo.log.len() - 1;log_selection(repo, ix)} else {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())}} else {let ix = ix - 1;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())};(Some(selection), task)}Some(Selection::LogChange {ix: log_ix,hash,message,diffs,file,}) => {let (selection, task) = match file {Some(LogChangeFileSelection {ix: file_ix,path: _,}) => {let log_entry = repo.log.get(log_ix).unwrap();let file_ix = if 0 == file_ix {log_entry.file_paths.len() - 1} else {file_ix - 1};let file =log_file_selection(log_entry, file_ix);(Selection::LogChange {ix: log_ix,hash,message,diffs,file: Some(file),},Task::none(),)}None => {let (selection, task) = if 0 == log_ix {if !repo.changed_files.is_empty() {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else if !repo.untracked_files.is_empty() {let ix = repo.untracked_files.len() - 1;let selection =untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(selection, Task::none())} else {let ix = repo.log.len() - 1;log_selection(repo, ix)}} else {let ix = log_ix - 1;log_selection(repo, ix)};(selection, task)}};(Some(selection), task)}None => {let (selection, task) = if !repo.log.is_empty() {let ix = repo.log.len() - 1;let (selection, task) = log_selection(repo, ix);(Some(selection), task)} else if !repo.changed_files.is_empty() {let ix = repo.changed_files.len() - 1;let selection = changed_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(Some(selection), Task::none())} else if !repo.untracked_files.is_empty() {let ix = repo.untracked_files.len() - 1;let selection = untracked_file_selection(repo,ix,diffs_cache,src_file_load_tx,);(Some(selection), Task::none())} else {(None, Task::none())};(selection, task)}};state.selection = selection;task} else {Task::none()}}Msg::CursorLeft | Msg::CursorRight => {if let Some(repo) = repo.as_ref() {let (selection, task): (Option<Selection>, Task<repo::MsgIn>) =match state.selection.take() {Some(Selection::LogChange {ix,hash,message,diffs,file,}) => {if file.is_none() {let log_entry = repo.log.get(ix).unwrap();let (file, task) = if let Some(path) =log_entry.file_paths.first(){(Some(LogChangeFileSelection {ix: 0,path: path.clone(),}),Task::none(),)} else {(None, Task::none())};(Some(Selection::LogChange {ix,hash,message,diffs,file,}),task,)} else {(Some(Selection::LogChange {ix,hash,message,diffs,file: None,}),Task::none(),)}}selection @ (Some(Selection::UntrackedFile {..})| Some(Selection::ChangedFile {..})| None) => (selection, Task::none()),};state.selection = selection;task} else {Task::none()}}Msg::CursorSelect(select) => {let (selection, task) = match select {Select::UntrackedFile { ix, path } => {load_src_file_if_not_cached(diffs_cache,src_file_load_tx,FileId {path: path.clone(),file_kind: FileKind::Untracked,},);(Some(Selection::UntrackedFile { ix, path }), Task::none())}Select::ChangedFile { ix, path } => {if let Some(diffs) = repo.as_ref().and_then(|repo| repo.changed_files.get(&path)){if diff::any_diff_has_contents(diffs) {load_src_file_if_not_cached(diffs_cache,src_file_load_tx,FileId {path: path.clone(),file_kind: FileKind::Changed,},);}}(Some(Selection::ChangedFile { ix, path }), Task::none())}Select::LogChange { ix, hash, message } => {// Request to get the diffslet task = Task::done(repo::MsgIn::GetChangeDiffs { hash });(Some(Selection::LogChange {ix,hash,message,diffs: None,file: None,}),task,)}Select::LogChangeFile { ix: file_ix, path } => {match state.selection.take() {Some(Selection::LogChange {ix: change_ix,hash,message,diffs,file: _,}) => {let file =LogChangeFileSelection { ix: file_ix, path };(Some(Selection::LogChange {ix: change_ix,hash,message,diffs,file: Some(file),}),Task::none(),)}selection => (selection, Task::none()),}}};state.selection = selection;task}}}pub fn untracked_file_selection(repo: &repo::State,ix: usize,diffs_cache: &mut DiffsCache,src_file_load_tx: &watch::Sender<(FileId, usize)>,) -> Selection {let path = repo.untracked_files.iter().nth(ix).unwrap().clone();let id = FileId {path: path.clone(),file_kind: FileKind::Untracked,};load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);Selection::UntrackedFile { ix, path }}pub fn changed_file_selection(repo: &repo::State,ix: usize,diffs_cache: &mut DiffsCache,src_file_load_tx: &watch::Sender<(FileId, usize)>,) -> Selection {let (path, diffs) = repo.changed_files.iter().nth(ix).unwrap();if diff::any_diff_has_contents(diffs) {let id = FileId {path: path.clone(),file_kind: FileKind::Changed,};load_src_file_if_not_cached(diffs_cache, src_file_load_tx, id);}Selection::ChangedFile {ix,path: path.clone(),}}pub fn log_selection(repo: &repo::State,ix: usize,) -> (Selection, Task<repo::MsgIn>) {let entry = repo.log.get(ix).unwrap();// Request to get the diffslet task = Task::done(repo::MsgIn::GetChangeDiffs { hash: entry.hash });(Selection::LogChange {ix,hash: entry.hash,message: entry.message.clone(),diffs: None,file: None,},task,)}pub fn log_file_selection(log_entry: &repo::LogEntry,file_ix: usize,) -> LogChangeFileSelection {let path = log_entry.file_paths.get(file_ix).unwrap().clone();LogChangeFileSelection { ix: file_ix, path }}