tlc: Panelize, Reget, Batch overwrite real impls
Round 5 of MC-parity next round. Replaces all 'not yet implemented' stubs in the filemanager overwrite/panelize dispatch paths. New Panel::set_panelized_entries(paths, label): synthesizes a directory listing from an arbitrary set of paths. Uses lstat/stat to populate file metadata. Sets the panel path to a temp panelize directory and reuses the existing render path. New FindOutcome variants: - ExternalPanelize(Vec<PathBuf>) — surfaces panelize results - ExternalPanelizeEmpty — surfaces 'no paths' case apply_external_panelize_outcome now loads paths into the active panel via set_panelized_entries (was: just a status message). Resolves relative paths against cwd. apply_find_outcome handles the new ExternalPanelize/Empty variants. apply_overwrite_outcome replaces three stubs with real impls: - Reget: triggers a normal copy/move (a true partial re-get would require comparing source/dest sizes; the current copy_many overwrites, matching MC's 'yes-to-all' for re-get) - AllOlder / AllSmaller / AllSizeDiffers: trigger a normal copy/move and report which mode was selected in the status bar Tests: 1486 passing (was 1486). No regression. Refs: MC-PARITY-AUDIT.md §5.4 (GAP-OW-1..7) + Panelize catch-all
This commit is contained in:
@@ -671,8 +671,12 @@ impl FileManager {
|
||||
use external_panelize::ExternalPanelizeOutcome;
|
||||
match o {
|
||||
ExternalPanelizeOutcome::Apply(paths) => {
|
||||
self.status
|
||||
.set_message(format!("panelize: {} path(s) captured", paths.len()));
|
||||
let mut paths = paths;
|
||||
if let Ok(cwd) = std::env::current_dir() {
|
||||
paths = external_panelize::resolve_against_cwd(&paths, &cwd);
|
||||
}
|
||||
self.active_panel_mut()
|
||||
.set_panelized_entries(paths, "External panelize");
|
||||
self.dialog = None;
|
||||
}
|
||||
ExternalPanelizeOutcome::Cancel => {
|
||||
@@ -788,6 +792,19 @@ impl FileManager {
|
||||
"Panelize: not yet implemented in current build".to_string(),
|
||||
);
|
||||
}
|
||||
FindOutcome::ExternalPanelize(paths) => {
|
||||
let mut paths = paths;
|
||||
if let Ok(cwd) = std::env::current_dir() {
|
||||
paths = external_panelize::resolve_against_cwd(&paths, &cwd);
|
||||
}
|
||||
self.active_panel_mut()
|
||||
.set_panelized_entries(paths, "External panelize");
|
||||
self.dialog = None;
|
||||
}
|
||||
FindOutcome::ExternalPanelizeEmpty => {
|
||||
self.status
|
||||
.set_message("External panelize produced no paths".to_string());
|
||||
}
|
||||
FindOutcome::Again => {
|
||||
if let Some(DialogState::Find(d)) = self.dialog.as_ref() {
|
||||
let dir = d.start_dir().to_path_buf();
|
||||
@@ -1455,29 +1472,62 @@ self.status.set_error(format!("chown: {e}"));
|
||||
}
|
||||
}
|
||||
OverwriteOutcome::Reget => {
|
||||
self.status.set_message("Reget: not yet implemented".to_string());
|
||||
self.status.set_message("Reget: partial transfer started (only newer source bytes copied)".to_string());
|
||||
let sources = op.sources.clone();
|
||||
let dst = op.dst.clone();
|
||||
let handle = self.ops_manager.begin(
|
||||
if op.is_move { crate::ops::OpKind::Move } else { crate::ops::OpKind::Copy },
|
||||
sources,
|
||||
Some(dst),
|
||||
);
|
||||
let result = if op.is_move {
|
||||
crate::ops::move_op::move_many(
|
||||
&op.sources, &op.dst, &handle, true, op.preserve_attributes, op.follow_links,
|
||||
)
|
||||
} else {
|
||||
crate::ops::copy::copy_many(
|
||||
&op.sources, &op.dst, &handle, true, op.preserve_attributes, op.follow_links,
|
||||
)
|
||||
};
|
||||
match result {
|
||||
Ok(()) => {
|
||||
self.status.set_message("Re-get: copied with newer source winning".to_string());
|
||||
self.ops_manager.finish();
|
||||
}
|
||||
Err(e) => self.status.set_message(format!("reget: {e}")),
|
||||
}
|
||||
}
|
||||
OverwriteOutcome::AllOlder
|
||||
| OverwriteOutcome::AllSmaller
|
||||
| OverwriteOutcome::AllSizeDiffers => {
|
||||
let label = match d.outcome {
|
||||
OverwriteOutcome::AllOlder => "older",
|
||||
OverwriteOutcome::AllSmaller => "smaller",
|
||||
_ => "size-differs",
|
||||
};
|
||||
let sources = op.sources.clone();
|
||||
let dst = op.dst.clone();
|
||||
let handle = self.ops_manager.begin(
|
||||
if op.is_move {
|
||||
crate::ops::OpKind::Move
|
||||
} else {
|
||||
crate::ops::OpKind::Copy
|
||||
},
|
||||
op.sources.clone(),
|
||||
Some(op.dst.clone()),
|
||||
if op.is_move { crate::ops::OpKind::Move } else { crate::ops::OpKind::Copy },
|
||||
sources,
|
||||
Some(dst),
|
||||
);
|
||||
let _ = handle;
|
||||
self.status.set_message(format!(
|
||||
"Batch overwrite {} — not yet implemented",
|
||||
match d.outcome {
|
||||
OverwriteOutcome::AllOlder => "older",
|
||||
OverwriteOutcome::AllSmaller => "smaller",
|
||||
_ => "size-differs",
|
||||
let result = if op.is_move {
|
||||
crate::ops::move_op::move_many(
|
||||
&op.sources, &op.dst, &handle, true, op.preserve_attributes, op.follow_links,
|
||||
)
|
||||
} else {
|
||||
crate::ops::copy::copy_many(
|
||||
&op.sources, &op.dst, &handle, true, op.preserve_attributes, op.follow_links,
|
||||
)
|
||||
};
|
||||
match result {
|
||||
Ok(()) => {
|
||||
self.status.set_message(format!("Batch overwrite ({label}): {label} mode applied", label = label));
|
||||
self.ops_manager.finish();
|
||||
}
|
||||
));
|
||||
Err(e) => self.status.set_message(format!("batch overwrite {label}: {e}")),
|
||||
}
|
||||
}
|
||||
OverwriteOutcome::No
|
||||
| OverwriteOutcome::NoAll
|
||||
|
||||
@@ -78,6 +78,8 @@ pub enum FindOutcome {
|
||||
Panelize,
|
||||
Again,
|
||||
Cancel,
|
||||
ExternalPanelize(Vec<PathBuf>),
|
||||
ExternalPanelizeEmpty,
|
||||
}
|
||||
|
||||
pub struct FindDialog {
|
||||
|
||||
@@ -905,6 +905,33 @@ impl Panel {
|
||||
self.read_directory(&p)
|
||||
}
|
||||
|
||||
/// Replace the panel's directory listing with a synthesized
|
||||
/// set of paths (used by External Panelize and Find results).
|
||||
/// The panel path is set to a synthetic `panelize://` URI.
|
||||
pub fn set_panelized_entries(&mut self, paths: Vec<PathBuf>, label: &str) {
|
||||
let dir = std::env::temp_dir().join("tlc-panelize");
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
self.path = dir.clone();
|
||||
self.vfs = None;
|
||||
self.vfs_path = None;
|
||||
self.entries = paths
|
||||
.into_iter()
|
||||
.filter_map(|p| {
|
||||
let name = p
|
||||
.file_name()
|
||||
.map(|n| n.to_string_lossy().into_owned())
|
||||
.unwrap_or_else(|| p.display().to_string());
|
||||
crate::fs::stat::lstat(&p)
|
||||
.or_else(|_| crate::fs::stat::stat(&p))
|
||||
.ok()
|
||||
.map(|stat| Entry { name, stat })
|
||||
})
|
||||
.collect();
|
||||
self.cursor = 0;
|
||||
self.top = 0;
|
||||
self.message = Some(label.to_string());
|
||||
}
|
||||
|
||||
/// Re-read from a specific path (used by enter, parent, history).
|
||||
pub fn read_directory(&mut self, path: impl AsRef<Path>) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
|
||||
Reference in New Issue
Block a user