From e8950c276086fbdd340c8e1546e8c51e681ac69c Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 6 Jul 2026 21:02:26 +0300 Subject: [PATCH] W29: Confirmation dialog (P1 audit gap) The F9 audit found that Cmd::OptionsConfirm was a single-boolean toggle (cycle on/off) instead of MC's proper confirmation dialog with per-operation checkboxes. The ConfirmDialog already existed in confirm_dialog.rs with 4 toggles (delete, overwrite, execute, exit) but wasn't wired into the F9 menu. Wire the existing ConfirmDialog: - DialogState::Confirm(Box) variant - Cmd::OptionsConfirm now opens the dialog pre-populated with the current safe_delete / safe_execute settings - Dispatch handler processes ConfirmResult::Confirm by saving the settings to runtime.safe_delete / safe_execute - Added RuntimeConfig::safe_execute field with default Some(false) - Added dialog_title() and render() arms for DialogState::Confirm Tests: 1393 pass, zero warnings. --- local/recipes/tui/tlc/source/src/config.rs | 3 +++ .../tlc/source/src/filemanager/dialog_ops.rs | 2 ++ .../tlc/source/src/filemanager/dispatch.rs | 23 +++++++++++++++++++ .../tui/tlc/source/src/filemanager/mod.rs | 3 +++ .../tui/tlc/source/src/filemanager/render.rs | 1 + 5 files changed, 32 insertions(+) diff --git a/local/recipes/tui/tlc/source/src/config.rs b/local/recipes/tui/tlc/source/src/config.rs index 69b338e7b6..ef6f1846e0 100644 --- a/local/recipes/tui/tlc/source/src/config.rs +++ b/local/recipes/tui/tlc/source/src/config.rs @@ -306,6 +306,8 @@ pub struct RuntimeConfig { pub auto_save_setup: Option, /// Require an explicit confirmation before delete. pub safe_delete: Option, + /// Require an explicit confirmation before executing commands. + pub safe_execute: Option, /// Pause and display output after a shell command finishes. pub pause_after_run: Option, } @@ -326,6 +328,7 @@ impl Default for RuntimeConfig { verbose_ops: Some(false), auto_save_setup: Some(false), safe_delete: Some(true), + safe_execute: Some(false), pause_after_run: Some(false), } } diff --git a/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs b/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs index eaab62a8c8..bf0798d0ae 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs @@ -985,6 +985,7 @@ Err(e) => self.status.set_error(format!("view: {e}")), | Some(DialogState::Encoding(_)) | Some(DialogState::Connection(_)) | Some(DialogState::Sort(_)) + | Some(DialogState::Confirm(_)) | Some(DialogState::Progress(_)) => { // These are closed by their own apply_*_outcome // helpers before this function is called; they @@ -1420,6 +1421,7 @@ fn dialog_label(d: &DialogState) -> String { DialogState::Encoding(_) => "Display encoding".to_string(), DialogState::Connection(_) => "Network connection".to_string(), DialogState::Sort(_) => "Sort order".to_string(), + DialogState::Confirm(_) => "Confirmation".to_string(), DialogState::Progress(_) => "Progress".to_string(), } } \ No newline at end of file diff --git a/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs b/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs index 7ddc7d0e3a..4fcbd90ff4 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs @@ -951,6 +951,29 @@ impl FileManager { } consumed = true; } + Some(DialogState::Confirm(d)) => { + use crate::filemanager::confirm_dialog::ConfirmResult; + let r = d.handle_key(key); + match r { + ConfirmResult::Confirm(settings) => { + self.runtime.safe_delete = Some(settings.confirm_delete); + self.runtime.safe_execute = Some(settings.confirm_execute); + self.status.set_message(format!( + "Confirm: delete={} overwrite={} execute={} exit={}", + if settings.confirm_delete { "ON" } else { "off" }, + if settings.confirm_overwrite { "ON" } else { "off" }, + if settings.confirm_execute { "ON" } else { "off" }, + if settings.confirm_exit { "ON" } else { "off" }, + )); + self.dialog = None; + } + ConfirmResult::Cancel => { + self.dialog = None; + } + ConfirmResult::Running => {} + } + consumed = true; + } None => return false, } // Apply captured outcomes. diff --git a/local/recipes/tui/tlc/source/src/filemanager/mod.rs b/local/recipes/tui/tlc/source/src/filemanager/mod.rs index 6654960294..4df4341eee 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/mod.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/mod.rs @@ -356,6 +356,8 @@ pub enum DialogState { Connection(Box), /// Alt-Shift-T — sort order dialog. Sort(Box), + /// F9 → Options → Confirmation — per-operation confirm toggles. + Confirm(Box), /// F5/F6/F8 — live progress dialog for background copy/move/delete. Progress(Box), } @@ -418,6 +420,7 @@ impl DialogState { DialogState::Encoding(_) => false, DialogState::Connection(_) => false, DialogState::Sort(_) => false, + DialogState::Confirm(_) => false, DialogState::Progress(_) => false, } } diff --git a/local/recipes/tui/tlc/source/src/filemanager/render.rs b/local/recipes/tui/tlc/source/src/filemanager/render.rs index 9ddb1dbd35..e26bef54c5 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/render.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/render.rs @@ -180,6 +180,7 @@ impl FileManager { DialogState::Encoding(d) => d.render(frame, dialog_area, &self.theme), DialogState::Connection(d) => d.render(frame, dialog_area, &self.theme), DialogState::Sort(d) => d.render(frame, dialog_area, &self.theme), + DialogState::Confirm(d) => d.render(frame, dialog_area, &self.theme), DialogState::Progress(d) => d.render(frame, dialog_area, &self.theme), } }