DNTMUCMOH4BRNMQAVCHDM2XESAJIKWTZW344CVHOQIJBWXJWCOMAC YBJRDOTCX3ZRDB5EVXJBR55FX3CADCSIGMYWNYVC2PD5W3GXR3DQC 23SFYK4Q5NKBPJG53PQNPWQH6UOUU2YKJEL7RLXYBRLJOJYV7AWQC 3QVNMRNMI63L2VOFVTMPCVPXH3J4JXLXVTIIPNOMACQCPCAPWILQC XSZZB47UXR6KGYFZZQFQR63X2LDKOH6TPNNBRRGHUCI5JJ4JIWVAC I2AG42PAVOII4V4TWDJV5ZVNDIHKBRDT254BFQLFUIY723TW6CCQC KWTBNTO3QUUE2YADF6SYW6G6ZOKYEWRJQKIWDGZXR33S3YNDVIZQC 5MUEECMJHU44FL5RDUR3VFBIWK3H4X2L5MVJ73J37PYHZWLUKU2AC PTWZYQFRWWUOE2WMQT26CKZKFSHAIJVJS3QWHJFYUFDRRTVPHSUAC UR4J677RWA3OFG6HQTD46BUUE5YFPSBEFCJAEM5OMT4V5A7SBNNQC K63JN6CRRCP4S5NY2FPH46Q7QLWH4B6QXQHKFPVQBHHIHNDVXFDQC A6Z4O6RC33HYWP7JIVQ6FDWE4EOCQWQTIGENK2WAHUGSHDDLSA7QC JZXYSIYDPBWQZCAMGDZ5BFMN6SU73EVVDIYEGTDJN6DVOSBNHN4QC OJPGHVC3RFBQ7TTSCZH6URSSATII3TESD74EISDNOTNXXSX7PQMAC WAOGSCOJ5A372BZKHEYD2BCDBCENNVLFYW3INKUOOAZMDADDIFIQC WH57EHNML4OTGQQZBT2SG6SOFTBOD6OJPJYHJVGPH22CSSOE25AAC EJPSD5XO43DWUBBZGNQMY4TMCAXL5EWCGX3OEHUERQ5GRASGWQLQC YK3MOJJLRYEKZ4FUCNJ3YKMTKOINWIYOJKR3ER7IRSGTC7O6FJZQC TQEZQJV4G4OXAYDLTMJW3NCRQV6W7I3MUBOKNCSOSXCSVLABW4QQC EGJG2KPDC7CLY3H66NW6MROGTF43G3EKHS7W7JRJ5WO3RU5Q7UXQC 7WCB5YQJJZIPUAFHTCQBWNI6ZM5XMIQJAKTLYTR7NOR5NKESRMDQC PKLUHYE4BGIMJKU6VKGBGSHEB2ZT53OYMTFBYCZYCO4J3RVTRXSAC CULHFNIVQ3ATML2W3Z45RARZ2LHGXONYTGGN2ETWAAMV7R3Y67AQC IFQPVMBD552DZ3B5HCM6W6MI2SB6576ZYJNU5KVA3O4YPZAUEFHAC LFEMJYYDO45ASMQSOJ3TNID7B5UZXDHB3NWFZJXWOAWNBS6GMDEAC 5O4FWCFP4ZPAS7WKSYPHN76ML3O2S4JUOYWOV2ETD4TF2H6KZ6AQC N256FH74YJDO7OYYVIHMV54IP7XA23UKVNMBDZ66LT3DRNEXUGYAC 2SLTGWP6FTM7C7BMSYEI2EBD4YTVO2XCIVRPHBJH5XHVLLVR76TAC YGZ3VCW4OAJYPI2CYK3MTABNFY7Y2ENSSTFE5ZZ4K6HK57FCU3XQC ODCT4QJNJLQTDNFPIF7HX4XCFTEXZBESG3PTD276O7TWB7MSGWMQC UTDTZCTXAAP6AHENYQP7MOQ5QNIKKXN34NV2ONWEGM4HA4FU637AC TEDT26JQBWGATVTY6HZTIOGFR6BXW2BHSUKUTXTA7HOXARRQ5D6AC C4V7DNBNNW5DYPWCMYM32KKVB72QBGY2YLCVXISZQSDPBF3LGUMQC TWULZ43VFT5HYWMCXPPPRRJFOKZV3RGKRMNPNPZ3TRI3BTSKAPZAC 3CM5KELT4W7HHZXEY4GYVDPMMUPG6U2R7MJ4V2RYJG424DTGNGVQC BJ3CYLUTYL3ODCU7XIQ2YIBQ6GMHP4IQ7HYMD4YCOPFRYEIYNWKQC YRGDFHABL6BRX55ZWIBGXX3ZX2R4WUV4BELP7JMW5AZX54P5BBIQC LPSUBGUBMG2QHJJSAWQ35SZIMUR62R6ODPWBS7TSNNXJ5UJCNABQC IMJQ4PML6OQ2MG5OK3SVUJH4RGXO4DD3O6IFD2A4UBZIMF6QI6YQC TMDH7GPVR3J7OEIELEE7RM7KXBA5IMFBCCVJTEGGMLYJZZCOLJ6QC IOXNOVX2FJWPCEFVUHA5FEKIZJQT45R7VBAA43EPAKKVF5IWF4GAC XQDYES5MDSTFO7OPUPCRQLLQ6NAVELJOCCLSS6YE7TI6QDDFANDQC MWQ7NABXLUOIM635NSN5YNEQNZKURZLKSGIGUXPAWQMFISGJGQFQC 6E6MSENZAZE7RGL4QBQD3MIAURXE5R3HINFWTNLOASJYVNHVOUMAC E7HE2UFTIOINUJQBRVCIG5GMANK6XWOYFX2ZHA73QJ6RW627G55QC SWWE2R6MVBX5CNM6X3WLXZTSRTU53PBJL7WJSFVF77XBPXDX4COAC UF5NJKASGMZSZMBUKSUI67B2GIMQFX5SNNQEHHGUBNDBQ2QZZWSAC OPXFZKEBDHZZLXEJ2JRDYBOJH6YIN7UZNZYHVHMWMQVDTE2ZD53QC WT3GA27PQ2AOAIGK65O3Q4DMX4AZDVNULBLRL6GF4QW6QCASUEAAC 6YZAVBWU6E5FYOI5JGEIPXGZLIKAW6LS2AOFIQWEE5DMOPPCD5PQC #[derive(Clone, Debug, Default)]pub struct Remotes {pub default: Option<String>,pub other: Vec<String>,}/// Records that are only present locally xor remotely#[derive(Clone, Debug, Default)]pub struct RecordDichotomy {/// Added records only. Removed local records that are present on remote/// show as unpulled added records.pub local_records: Log,/// Remote records that haven't been pulledpub remote_records: Log,/// Remote unrecordspub remote_unrecords: Log,}impl RecordDichotomy {pub fn is_empty(&self) -> bool {let Self {local_records,remote_records,remote_unrecords,} = self;remote_records.is_empty()&& remote_unrecords.is_empty()&& local_records.is_empty()}
pub fn len(&self) -> usize {let Self {local_records,remote_records,remote_unrecords,} = self;remote_records.len() + remote_unrecords.len() + local_records.len()}pub fn get(&self, ix: usize) -> Option<&LogEntry> {let Self {local_records,remote_records,remote_unrecords,} = self;if ix < local_records.len() {return local_records.get(ix);}let ix = ix - local_records.len();if ix < remote_records.len() {return remote_records.get(ix);}let ix = ix - remote_records.len();remote_unrecords.get(ix)}}
let config = PijulConfig::load(Some(&repo.path), vec![]).context("getting Pijul config")?;let remotes = Remotes {default: config.default_remote,other: config.remotes.into_iter().map(|conf| match conf {pijul_config::remote::RemoteConfig::Ssh { name, .. } => name,pijul_config::remote::RemoteConfig::Http { name, .. } => name,}).collect(),};
}#[allow(clippy::await_holding_lock,reason = "imposed by sanakirja API for txn")]async fn compare_remote(internal_state: &mut InternalState,remote_name: &str,channel_name: &str,) -> anyhow::Result<ComparedRemote> {let txn = internal_state.repo.pristine.arc_txn_begin().context("Begin txn")?;let mut channel = txn.write().open_or_create_channel(channel_name).context("Loading current channel")?;let config = PijulConfig::load(Some(&internal_state.repo.path), vec![])?;let from_channel = libpijul::DEFAULT_CHANNEL;let no_cert_check = false;let mut remote = pijul_remote::repository(&config,Some(&internal_state.repo.path),None,remote_name,from_channel,no_cert_check,true,).await?;let PushDelta {to_upload,remote_unrecs: _,unknown_changes: _,..} = to_upload(&mut txn.write(),&mut channel,&internal_state.repo,&mut remote,).await?;let RemoteDelta {inodes: _,remote_ref: _,to_download,remote_unrecs,..} = to_download(&mut txn.write(),&mut channel,&mut internal_state.repo,&mut remote,).await?;let remote_records = to_download.into_iter().filter_map(|cs| match cs {pijul_remote::CS::Change(hash) => Some(hash),pijul_remote::CS::State(_) => None,}).map(|hash| mk_log_entry(&internal_state.repo, hash)).collect::<anyhow::Result<Log>>()?;let remote_unrecords = remote_unrecs.into_iter().filter_map(|(_, cs)| match cs {pijul_remote::CS::Change(hash) => Some(hash),pijul_remote::CS::State(_) => None,}).map(|hash| mk_log_entry(&internal_state.repo, hash)).collect::<anyhow::Result<Log>>()?;let local_records = to_upload.into_iter().filter_map(|cs| match cs {pijul_remote::CS::Change(hash) => Some(hash),pijul_remote::CS::State(_) => None,}).map(|hash| mk_log_entry(&internal_state.repo, hash)).collect::<anyhow::Result<Log>>()?;let record_dichotomy = RecordDichotomy {remote_records,remote_unrecords,local_records,};Ok(ComparedRemote {record_dichotomy,remote: remote_name.to_string(),channel: channel_name.to_string(),})
diff::view(state,nav,file,None,*diff_selected,false,to_record,)}None => el(text("Loading diff..")),},]).spacing(SPACING)),// NOTE: This is currently never true - there are only up to 3// colsif hidden_cols == 2 {el(button(row([el(text("← Files").shaping(text::Shaping::Advanced))])).on_press(Msg::Action(action::FilteredMsg::Selection(selection::Msg::PressDir(selection::Dir::Left),),)))} else {el(row([]))},]).width(Length::Fill).height(Length::Fill).spacing(SPACING))}_ => el(column([])),};let compare_remote_nav_children = || {if let Some(record_dichotomy) =remotes.default.as_ref().and_then(|default_remote| {model::get_record_dichotomy(record_dichotomy,default_remote,channel,)}){let repo::RecordDichotomy {local_records,remote_records,remote_unrecords,} = record_dichotomy;let count = |records: &[_]| {records.len() + if records.is_empty() { 0 } else { 1 } // account for a header if non-empty};let row_count = count(local_records)+ count(remote_records)+ count(remote_unrecords);if row_count == 0 {vec![el(text("Local and remote are the same!"))]} else {let mut rows = Vec::with_capacity(row_count);let view = |rows: &mut Vec<_>, ix, entry: &repo::LogEntry| {let selection = match selection {selection::Unified::CompareRemote(Some(selection::CompareRemote {ix: Some(selected_ix),hash: _,file,remote: _,channel: _,},)) if &ix == selected_ix => {if file.is_some() {HierarchicalSelection::ChildSelected} else {HierarchicalSelection::Selected}}_ => HierarchicalSelection::NotSelected,};rows.push(el(button(el(text(display_short_hash(&entry.hash,)))).on_press(Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::CompareRemote { ix },),)).class(hierarchical_button_class(selection))));};if !local_records.is_empty() {rows.push(el(container(el(text("Local records:"))).padding(Padding::ZERO.top(SPACING))));}let ix_offset = 0;record_dichotomy.local_records.iter().enumerate().for_each(|(ix, entry)| view(&mut rows, ix + ix_offset, entry),);if !remote_records.is_empty() {rows.push(el(container(el(text("Remote records:"))).padding(Padding::ZERO.top(SPACING))));}let ix_offset = local_records.len();record_dichotomy.remote_records.iter().enumerate().for_each(|(ix, entry)| view(&mut rows, ix + ix_offset, entry),);if !remote_unrecords.is_empty() {rows.push(el(container(el(text("Remote unrecords:"))).padding(Padding::ZERO.top(SPACING))));}let ix_offset = ix_offset + remote_records.len();record_dichotomy.remote_unrecords.iter().enumerate().for_each(|(ix, entry)| {view(&mut rows, ix + ix_offset, entry)});rows}} else {vec![]}};// Compare remote records dichotomylet compare_remote_col_0 = || {el(column([el(nav_scrollable(&navigation.status_nav,compare_remote_nav_children(),).class(if status_selected() {theme::Scrollable::Selected} else {theme::Scrollable::Normal}).width(Length::Fill).height(Length::Fill))]).width(Length::Fill).height(Length::Fill))};// Compare remote file selection in selected changelet compare_remote_col_1 = || match selection {selection::Unified::CompareRemote(Some(selection::CompareRemote {ix: Some(ix),hash: _,file,remote: _,channel: _,})) => {let files_view = if let Some(record_dichotomy) =remotes.default.as_ref().and_then(|default_remote| {model::get_record_dichotomy(record_dichotomy,default_remote,channel,)}) {let nav = &navigation.compare_remote_navs.files_nav;let entry = record_dichotomy.get(*ix).unwrap();let files =entry.file_paths.iter().enumerate().map(|(ix, path)| {let selection = match file {Some(selection::LogChangeFileSelection {path: selected_path,diff_selected,..}) if selected_path == path => {if *diff_selected {HierarchicalSelection::ChildSelected} else {HierarchicalSelection::Selected}}_ => HierarchicalSelection::NotSelected,};el(button(text(path)).on_press_with(move || {Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::CompareRemoteFile {ix,path: path.clone(),},),)}).class(hierarchical_button_class(selection)))});el(column([view_log_change_header(entry),el(nav_scrollable(nav, files).class(if entire_log_change_selected() {theme::Scrollable::Selected} else {theme::Scrollable::Normal}).width(Length::Fill).height(Length::Fill)),]))} else {el(text("Loading..."))};el(column([files_view,if hidden_cols == 1 {el(button(row([el(text("← Records").shaping(text::Shaping::Advanced))])).on_press(Msg::Action(action::FilteredMsg::Selection(selection::Msg::PressDir(selection::Dir::Left),),)))} else {el(row([]))},]).width(Length::Fill).height(Length::Fill).spacing(SPACING))}_ => el(row([])),};// TODO more re-use with status_col_2// Compare remote log diff selection in selected change's filelet compare_remote_col_2 = || match selection {selection::Unified::CompareRemote(Some(selection::CompareRemote {ix: _,hash: Some(hash),file:Some(selection::LogChangeFileSelection {ix: _,path,diff_selected,}),remote: _,channel: _,})) => {let file_id = file::log_id_parts_hash(*hash, path);let state = navigation.log_diffs.diffs.get(&file_id);el(column([el(column([view_header(format!("{path} changes in {}:",display_short_hash(hash))),match state {Some(diff::FileAndState { file, state }) => {let nav = &navigation.compare_remote_navs.diffs_nav;
InitRepo { path: PathBuf },ImportFromGit { path: PathBuf },Add { recursive: bool },
InitRepo {path: PathBuf,},ImportFromGit {path: PathBuf,},Add {recursive: bool,},CompareRemote {remote: Option<String>,channel: Option<String>,},
// Outer key is remote name, inner key is channel namepub record_dichotomy:HashMap<String, HashMap<String, repo::RecordDichotomy>>,}pub fn get_record_dichotomy<'a>(record_dichotomy: &'a HashMap<String,HashMap<String, repo::RecordDichotomy>,>,remote: &str,channel: &str,) -> Option<&'a repo::RecordDichotomy> {record_dichotomy.get(remote).and_then(|map| map.get(channel))
model::SubMenu::CompareRemote {remote: _,channel: _,} => {// TODO select remote name// TODO select local and remote channelvec![Binding {keys_str: "Enter | S-c",keys: ModKeys::Two(ModKey {key: Key::Named(Named::Enter),mods: Mods::NONE,},ModKey {key: Key::Character("c".into()),mods: Mods::SHIFT,},),label: "compare default remote",msg: Some(FilteredMsg::Confirm),},cancel(),]}
}};let compare_remote = || -> Binding {Binding {keys_str: "S-c",keys: ModKeys::One(ModKey {key: Key::Character("c".into()),mods: Mods::SHIFT,}),label: "compare remote",msg: Some(FilteredMsg::EnterSubMenu(model::SubMenu::CompareRemote {remote: None,channel: None,},)),
SubState::CompareRemote {can_select_right,has_any_diff,} => {push_if(has_any_diff, down, ma);push_if(has_any_diff, up, ma);push_if(has_any_diff && can_select_right, right, ma);push_if(has_any_diff, clipboard_copy_change_hash, ma);push(cancel, ma);}SubState::CompareRemoteChange { can_select_right } => {push(left, ma);push(down, ma);push(up, ma);push_if(can_select_right, right, ma);push(clipboard_copy_change_hash, ma);push(cancel, ma);}SubState::CompareRemoteChangeDiff => {push(left, ma);push(down, ma);push(up, ma);push(clipboard_copy_change_hash, ma);push(cancel, ma);}
/// Comparing records in local vs. remoteCompareRemote {can_select_right: bool,has_any_diff: bool,},/// Viewing a change in comparing records in local vs. remoteCompareRemoteChange {can_select_right: bool,},/// Viewing a file diff of a change in comparing records in local vs./// remoteCompareRemoteChangeDiff,
selection::Primary::CompareRemote => {let has_any_diff = remotes.default.as_ref().and_then(|default_remote| {model::get_record_dichotomy(record_dichotomy,default_remote,channel,)}).map(|d| !d.is_empty()).unwrap_or(false);if let Some(selection::CompareRemote { file, .. }) =compare_remote_selection{match file {Some(selection::LogChangeFileSelection {diff_selected,..}) => {if *diff_selected {SubState::CompareRemoteChangeDiff} else {let diffs_nav =&navigation.compare_remote_navs.diffs_nav;let can_select_right =nav_scrollable::needs_scrolling(diffs_nav);SubState::CompareRemoteChange { can_select_right }}}None => {let files_nav =&navigation.compare_remote_navs.files_nav;let can_select_right =nav_scrollable::has_sections(files_nav);SubState::CompareRemote {can_select_right,has_any_diff,}}}} else {SubState::CompareRemote {has_any_diff,can_select_right: false,}}}
unify, Channel, Dir, HeldKey, LogChange, LogChangeFileSelection, Msg,Primary, Select, State, Status, UnfilteredMsg, Unified,
unify, Channel, CompareRemote, Dir, HeldKey, LogChange,LogChangeFileSelection, Msg, Primary, Select, State, Status, UnfilteredMsg,Unified,
fn select_down_compare_remote(ctx: &mut Ctx<'_>,delta: Option<Duration>,) -> Task<crate::ManagingRepoMsg> {if let Some(record_dichotomy) = ctx.record_dichotomy {let len = record_dichotomy.len();if len > 0&& let Some(CompareRemote {ix,hash,file,remote,channel,}) = ctx.state.compare_remote.take(){let (selection, task) = if let (Some(change_ix), Some(hash)) =(ix, hash){if let Some(LogChangeFileSelection {ix: file_ix,path,diff_selected,}) = file{if diff_selected {let selection = CompareRemote {ix: Some(change_ix),hash: Some(hash),file: Some(LogChangeFileSelection {ix: file_ix,path,diff_selected,}),remote,channel,};
nav_scrollable::scroll_down(&mut ctx.navigation.compare_remote_navs.diffs_nav,delta,);(selection, Task::none())} else {let log_entry =record_dichotomy.get(change_ix).unwrap();let file_ix =if log_entry.file_paths.len().saturating_sub(1)== file_ix{0} else {file_ix + 1};let (file, selection_task) =compare_remote_file_selection(file_ix,hash,VDir::Down,ctx.navigation,log_entry,);let selection = CompareRemote {ix: Some(change_ix),hash: Some(hash),file: Some(file),remote,channel,};(selection, selection_task)}} else {if change_ix + 1 == len {let ix = 0;compare_remote_selection(ix,VDir::Up,ctx,record_dichotomy,remote,channel,)} else {let ix = change_ix + 1;compare_remote_selection(ix,VDir::Down,ctx,record_dichotomy,remote,channel,)}}} else {let ix = 0;compare_remote_selection(ix,VDir::Down,ctx,record_dichotomy,remote,channel,)};ctx.state.compare_remote = Some(selection);return task;}}Task::none()}
fn select_up_compare_remote(ctx: &mut Ctx<'_>,delta: Option<Duration>,) -> Task<crate::ManagingRepoMsg> {if let Some(record_dichotomy) = ctx.record_dichotomy {let len = record_dichotomy.len();if len > 0&& let Some(CompareRemote {ix,hash,file,remote,channel,}) = ctx.state.compare_remote.take(){let (selection, task) = if let (Some(change_ix), Some(hash)) =(ix, hash){if let Some(LogChangeFileSelection {ix: file_ix,path,diff_selected,}) = file{if diff_selected {let selection = CompareRemote {ix: Some(change_ix),hash: Some(hash),file: Some(LogChangeFileSelection {ix: file_ix,path,diff_selected,}),remote,channel,};nav_scrollable::scroll_up(&mut ctx.navigation.compare_remote_navs.diffs_nav,delta,);(selection, Task::none())} else {let log_entry =record_dichotomy.get(change_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) =compare_remote_file_selection(file_ix,hash,VDir::Up,ctx.navigation,log_entry,);let selection = CompareRemote {ix: Some(change_ix),hash: Some(hash),file: Some(file),remote,channel,};(selection, selection_task)}} else {if change_ix == 0 {let ix = len.saturating_sub(1);compare_remote_selection(ix,VDir::Up,ctx,record_dichotomy,remote,channel,)} else {let ix = change_ix - 1;compare_remote_selection(ix,VDir::Up,ctx,record_dichotomy,remote,channel,)}}} else {let ix = len.saturating_sub(1);compare_remote_selection(ix,VDir::Down,ctx,record_dichotomy,remote,channel,)};ctx.state.compare_remote = Some(selection);return task;}}Task::none()}
Primary::CompareRemote => {let (selection, task) = match ctx.state.compare_remote.take() {Some(CompareRemote {ix,hash,file:Some(LogChangeFileSelection {ix: file_ix,path,diff_selected,}),remote,channel,}) => {if diff_selected {(Some(CompareRemote {ix,hash,file: Some(LogChangeFileSelection {ix: file_ix,path,diff_selected: false,}),remote,channel,}),Task::none(),)} else {let selection = CompareRemote {ix,hash,file: None,remote,channel,};(Some(selection), Task::none())}}selection @ (Some(CompareRemote { file: None, .. }) | None) => {(selection, Task::none())}};ctx.state.compare_remote = selection;task}
}Task::none()}fn select_right_compare_remote(ctx: &mut Ctx<'_>,) -> Task<crate::ManagingRepoMsg> {if let Some(record_dichotomy) = ctx.record_dichotomy {let len = record_dichotomy.len();if len > 0&& let Some(CompareRemote {ix: Some(change_ix),hash: Some(hash),file,remote,channel,}) = ctx.state.compare_remote.take(){let (selection, task) = match file {None => {let log_entry = record_dichotomy.get(change_ix).unwrap();let (file, task) =if let Some(path) = log_entry.file_paths.first() {let file_id =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::GotChangeDiffs`)if let Some(log) =ctx.navigation.log_diffs.diffs.get(&file_id){let unchanged_sections =diff::unchanged_sections(&log.file);log::init_diffs_nav(&mut ctx.navigation.compare_remote_navs,file_id,).set_skip_sections(unchanged_sections);};(Some(LogChangeFileSelection {ix: 0,path: path.clone(),diff_selected: false,}),Task::none(),)} else {(None, Task::none())};(Some(CompareRemote {ix: Some(change_ix),hash: Some(hash),file,remote,channel,}),task,)}Some(LogChangeFileSelection {ix: file_ix,path,diff_selected: false,}) => {let is_diff_scrollable = log::diff_needs_scrolling(&ctx.navigation.compare_remote_navs,);(Some(CompareRemote {ix: Some(change_ix),hash: Some(hash),file: Some(LogChangeFileSelection {ix: file_ix,path,diff_selected: is_diff_scrollable,}),remote,channel,}),Task::none(),)}file => (Some(CompareRemote {ix: Some(change_ix),hash: Some(hash),file,remote,channel,}),Task::none(),),};ctx.state.compare_remote = selection;return task;}
return task;}}Primary::CompareRemote => {if let Some((record_dichotomy,CompareRemote {ix: record_ix,hash,file: _,remote,channel,},)) = ctx.record_dichotomy.zip(ctx.state.compare_remote.take()){let (selection, task) = match select {Select::CompareRemote { ix } => {let (selection, task) = compare_remote_selection(ix,VDir::Down,ctx,record_dichotomy,remote,channel,);(Some(selection), task)}Select::CompareRemoteFile {ix: file_ix,path: _,} => {let record_ix = record_ix.unwrap();let entry = record_dichotomy.get(record_ix).unwrap();let (file, task) = compare_remote_file_selection(file_ix,hash.unwrap(),VDir::Down,ctx.navigation,entry,);let selection = Some(CompareRemote {ix: Some(record_ix),hash,file: Some(file),remote,channel,});(selection, task)}Select::UntrackedFile { .. }| Select::ChangedFile { .. }| Select::LogChange { .. }| Select::LogChangeFile { .. }| Select::Channel { .. } => unreachable!(),};ctx.state.compare_remote = selection;
match dir {VDir::Up => nav_scrollable::scroll_up_to_section(nav, ix),VDir::Down => nav_scrollable::scroll_down_to_section(nav, ix),}(LogChangeFileSelection {ix,path,diff_selected: false,},Task::none(),)}fn compare_remote_selection(ix: usize,dir: VDir,ctx: &mut Ctx<'_>,record_dichotomy: &repo::RecordDichotomy,remote: String,channel: String,) -> (CompareRemote, Task<crate::ManagingRepoMsg>) {let Ctx {state: _,files: _,navigation,repo: _,logs: _,record_dichotomy: _,} = ctx;let entry = record_dichotomy.get(ix).unwrap();let hash = entry.hash;let task = if !navigation.log_diffs.changes_with_loaded_diffs.contains(&hash){Task::done(crate::ManagingRepoMsg::ToRepo(repo::MsgIn::GetChangeDiffs { hash },))} else {Task::none()};log::init_files_nav(&mut navigation.compare_remote_navs, hash);
VDir::Up => nav_scrollable::scroll_up_to_section(&mut navigation.compare_remote_nav,ix,),VDir::Down => nav_scrollable::scroll_down_to_section(&mut navigation.compare_remote_nav,ix,),}let selection = CompareRemote {ix: Some(ix),hash: Some(hash),file: None,remote,channel,};(selection, task)}fn compare_remote_file_selection(ix: usize,hash: repo::ChangeHash,dir: VDir,navigation: &mut Navigation,log_entry: &repo::LogEntry,) -> (LogChangeFileSelection, Task<crate::ManagingRepoMsg>) {let path = log_entry.file_paths.get(ix).unwrap().clone();log::init_diffs_nav(&mut navigation.compare_remote_navs,file::log_id_parts_hash(hash, &path),);let nav = &mut navigation.compare_remote_navs.files_nav;match dir {
}Some(model::SubMenu::CompareRemote { remote, channel }) => {if let Some(ReadyState {repo,selection,jobs,..}) = model::is_ready_mut(model){let remote = remote.as_ref().or(repo.remotes.default.as_ref()).cloned();if let Some(remote) = remote {let channel = channel.clone().unwrap_or_else(|| repo.channel.clone());jobs.insert(model::Job::CompareRemote {remote: remote.clone(),channel: channel.clone(),});selection.primary = selection::Primary::CompareRemote;selection.compare_remote =Some(selection::CompareRemote {ix: None,hash: None,file: None,remote: remote.clone(),channel: channel.clone(),});state.repo_tx_in.send(repo::MsgIn::CompareRemote {remote,channel,}).unwrap();} else {report::show_err(report,"No default remote configured".to_string(),);}*sub_menu = None;}Task::none()
Some(*hash));}}if let Some(selection::CompareRemote {ix: _,hash: Some(hash),file,remote: _,channel: _,}) = compare_remote{assert_eq!(navigation.compare_remote_navs.change_hash,Some(*hash));if let Some(selection::LogChangeFileSelection {path, ..}) = file{assert_eq!(navigation.compare_remote_navs.change_hash,Some(*hash));let file_id = file::log_id_parts_hash(*hash, path);if navigation.log_diffs.diffs.contains_key(&file_id) {assert_eq!(navigation.compare_remote_navs.file_id,Some(file_id));}} else {assert_eq!(navigation.compare_remote_navs.change_hash,
if let Some(ReadyState {repo,record_dichotomy,..}) = model::is_ready_mut(model)&& let Some(record_dichotomy) =repo.remotes.default.as_ref().and_then(|default_remote| {model::get_record_dichotomy_mut(record_dichotomy,default_remote,&channel,)},){let repo::RecordDichotomy {local_records,remote_records,remote_unrecords,} = record_dichotomy;// Remove remote unrecords that were re-pushedremote_unrecords.retain(|entry| {local_records.iter().all(|local| local.hash != entry.hash)});// Move local records into remote recordsremote_records.extend(mem::take(local_records));}
if let Some(ReadyState {repo,record_dichotomy,..}) = model::is_ready_mut(model)&& let Some(record_dichotomy) =repo.remotes.default.as_ref().and_then(|default_remote| {model::get_record_dichotomy_mut(record_dichotomy,default_remote,&channel,)},){let repo::RecordDichotomy {local_records: _,remote_records,remote_unrecords: _,} = record_dichotomy;// Remove remote records as they were pulled*remote_records = default();}
repo::MsgOut::ComparedRemote {result,channel,remote,} => {match result {Ok(repo::ComparedRemote {record_dichotomy: d,remote,channel,}) => {if let Some(ReadyState {record_dichotomy, ..}) = model::is_ready_mut(model){record_dichotomy.entry(remote).or_default().insert(channel, d);}}Err(err) => {let msg =format!("Failed to compare with remote with {err:?}. Remote {remote:?}, channel: {channel:?}");report::show_err(report, msg);}}if let Some(ReadyState { jobs, .. }) = model::is_ready_mut(model) {jobs.swap_remove(&Job::CompareRemote { remote, channel });}Task::none()}