|
| 1 | +use std::fs; |
| 2 | + |
1 | 3 | use anyhow::{Context, Result}; |
2 | 4 | use cpal::traits::{DeviceTrait, HostTrait}; |
3 | | -use std::fs; |
4 | 5 | use terminal_menu::{ |
5 | 6 | TerminalMenuItem, back_button, button, label, list, menu, mut_menu, run, submenu, |
6 | 7 | }; |
7 | 8 |
|
8 | | -// 导入您在 main.rs 中定义的 pub clap 结构体 |
9 | | -use crate::cli::*; |
10 | | - |
11 | | -/// 设备类型,用于区分输入和输出 |
12 | | -#[derive(Clone, Copy)] |
13 | | -pub enum DeviceType { |
14 | | - Input, |
15 | | - Output, |
16 | | -} |
| 9 | +use crate::{cli::*, device::DeviceType}; |
17 | 10 |
|
18 | | -impl std::fmt::Display for DeviceType { |
19 | | - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
20 | | - match self { |
21 | | - DeviceType::Input => write!(f, "输入"), |
22 | | - DeviceType::Output => write!(f, "输出"), |
23 | | - } |
24 | | - } |
25 | | -} |
| 11 | +const NONE_EXEC_ITEM: &str = "None"; |
26 | 12 |
|
27 | 13 | /// 非交互式地获取可用设备名称列表 |
28 | 14 | fn get_device_names(device_type: DeviceType) -> Result<Vec<String>> { |
@@ -56,16 +42,16 @@ pub fn run_tui() -> Result<Cli> { |
56 | 42 | // 2. 构建菜单 |
57 | 43 | let main_menu = menu(vec![ |
58 | 44 | label("请选择一个要执行的操作,按 q 退出:"), |
59 | | - button("ListDevices (列出设备)"), |
60 | | - submenu("UnpackDll (解压DLL)", unpack_dll_menu()), |
61 | | - submenu( |
62 | | - "Start (启动程序)", |
63 | | - start_menu(&input_devices, &output_devices, &executable_options), |
64 | | - ), |
65 | 45 | submenu( |
66 | 46 | "UnpackAndStart (解压并启动)", |
67 | 47 | unpack_and_start_menu(&input_devices, &output_devices, &executable_options), |
68 | 48 | ), |
| 49 | + submenu( |
| 50 | + "Start (启动程序)", |
| 51 | + start_menu(&input_devices, &output_devices, &executable_options), |
| 52 | + ), |
| 53 | + submenu("UnpackDll (解压DLL)", unpack_dll_menu()), |
| 54 | + button("ListDevices (列出设备)"), |
69 | 55 | button("Exit (退出)"), |
70 | 56 | ]); |
71 | 57 |
|
@@ -109,7 +95,7 @@ pub fn run_tui() -> Result<Cli> { |
109 | 95 | .context("选择的输出设备无效")?; |
110 | 96 |
|
111 | 97 | let exec_selection = sub_menu.selection_value("执行程序 (可选)"); |
112 | | - let exec = if exec_selection == "None" { |
| 98 | + let exec = if exec_selection == NONE_EXEC_ITEM { |
113 | 99 | None |
114 | 100 | } else { |
115 | 101 | Some(exec_selection.to_string()) |
@@ -141,7 +127,7 @@ pub fn run_tui() -> Result<Cli> { |
141 | 127 | .context("选择的输出设备无效")?; |
142 | 128 |
|
143 | 129 | let exec_selection = sub_menu.selection_value("执行程序 (可选)"); |
144 | | - let exec = if exec_selection == "None" { |
| 130 | + let exec = if exec_selection == NONE_EXEC_ITEM { |
145 | 131 | None |
146 | 132 | } else { |
147 | 133 | Some(exec_selection.to_string()) |
@@ -217,9 +203,25 @@ fn speed_options() -> Vec<&'static str> { |
217 | 203 |
|
218 | 204 | /// 获取当前目录下的文件和文件夹作为 `exec` 的选项 |
219 | 205 | fn exec_options() -> Vec<String> { |
220 | | - let mut options = vec!["None".to_string()]; // 提供不选择的选项 |
| 206 | + let mut options = vec![NONE_EXEC_ITEM.to_string()]; // 提供不选择的选项 |
221 | 207 | if let Ok(entries) = fs::read_dir(".") { |
222 | | - for entry in entries.flatten() { |
| 208 | + for entry in entries |
| 209 | + .flatten() |
| 210 | + .filter(|e| e.file_type().map(|t| t.is_file()).unwrap_or(false)) |
| 211 | + .filter(|e| { |
| 212 | + // 过滤掉自身 |
| 213 | + if let Some(name) = e.file_name().to_str() |
| 214 | + && name.contains(env!("CARGO_PKG_NAME")) |
| 215 | + { |
| 216 | + return false; |
| 217 | + } |
| 218 | + if let Some(ext) = e.path().extension().and_then(|e| e.to_str()) { |
| 219 | + return ["exe", "bat", "cmd", "ps1", "sh"] |
| 220 | + .contains(&ext.to_lowercase().as_str()); |
| 221 | + } |
| 222 | + false |
| 223 | + }) |
| 224 | + { |
223 | 225 | if let Some(name) = entry.file_name().to_str() { |
224 | 226 | options.push(name.to_string()); |
225 | 227 | } |
|
0 commit comments