use crate::log_debug;
use crate::script::ScriptMetadata;
use std::io;
use std::path::PathBuf;
use std::process::Command;
use windows::Win32::Foundation::{HINSTANCE, HWND};
use windows::Win32::UI::Controls::{
TASKDIALOG_BUTTON, TASKDIALOGCONFIG, TDF_ALLOW_DIALOG_CANCELLATION,
TaskDialogIndirect,
};
use windows::core::PCWSTR;
pub(crate) enum UserChoice {
Run,
Edit,
Exit,
}
pub(crate) fn interactive_prompt(
script: &ScriptMetadata,
editor: &str,
) -> io::Result<UserChoice> {
const ID_RUN: i32 = 1001;
const ID_EDIT: i32 = 1002;
const ID_CANCEL: i32 = 1003;
let script_name = &script
.file_path
.file_name()
.and_then(|s| s.to_str())
.unwrap_or_default();
let run_text: Vec<u16> = "Run\0".encode_utf16().collect();
let edit_text: Vec<u16> = "Display\0".encode_utf16().collect();
let cancel_text: Vec<u16> = "Cancel\0".encode_utf16().collect();
let title: Vec<u16> = format!(
"Do you want to run \"{}\", or display its contents?\0",
script_name
)
.encode_utf16()
.collect();
let content: Vec<u16> =
format!("\"{}\" is an executable text file.\0", script_name)
.encode_utf16()
.collect();
let buttons = [
TASKDIALOG_BUTTON {
nButtonID: ID_RUN,
pszButtonText: PCWSTR(run_text.as_ptr()),
},
TASKDIALOG_BUTTON {
nButtonID: ID_EDIT,
pszButtonText: PCWSTR(edit_text.as_ptr()),
},
TASKDIALOG_BUTTON {
nButtonID: ID_CANCEL,
pszButtonText: PCWSTR(cancel_text.as_ptr()),
},
];
let mut selected_button: i32 = 0;
let config = TASKDIALOGCONFIG {
cbSize: size_of::<TASKDIALOGCONFIG>() as u32,
hwndParent: HWND(std::ptr::null_mut()),
hInstance: HINSTANCE(std::ptr::null_mut()),
pszWindowTitle: PCWSTR(title.as_ptr()),
pszContent: PCWSTR(content.as_ptr()),
cButtons: buttons.len() as u32,
pButtons: buttons.as_ptr(),
nDefaultButton: ID_CANCEL,
dwFlags: TDF_ALLOW_DIALOG_CANCELLATION,
..Default::default()
};
unsafe {
TaskDialogIndirect(&config, Some(&mut selected_button), None, None)
.map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("{e}"))
})?;
}
match selected_button {
ID_RUN => Ok(UserChoice::Run),
ID_EDIT => {
let editor_path = which::which(editor)
.unwrap_or_else(|_| PathBuf::from("notepad"));
log_debug!(&format!(
"User chose to edit the script: {:?} with editor: {:?}",
script, editor_path
));
match Command::new(editor_path)
.arg::<&PathBuf>(&script.file_path)
.spawn()
{
Ok(mut child) => {
if let Err(_e) = child.wait() {
log_debug!(&format!("Editor wait() failed: {}", _e));
}
}
Err(_e) => {
log_debug!(&format!("Editor spawn() failed: {}", _e));
}
}
Ok(UserChoice::Edit)
}
_ => Ok(UserChoice::Exit),
}
}