From 800755abf537b347e34c910f9016b2999e111886 Mon Sep 17 00:00:00 2001 From: macro Date: Sun, 26 Apr 2026 00:25:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(cli):=20=E9=87=8D=E6=9E=84=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=91=BD=E4=BB=A4=E5=B9=B6=E5=A2=9E=E5=BC=BA=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E6=97=B6=E9=97=B4=E5=A4=84=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重写Delete子命令参数结构,使用start和count替代range参数 - 添加-y/--yes选项用于跳过删除确认提示 - 新增日期时间解析和转换辅助函数支持 - 实现Excel序列号与Chrono时间类型的相互转换 - 增强单元格值获取函数支持日期格式化显示 - 修改插入和更新函数支持日期时间值的自动识别和格式化 - 优化删除命令的行号解析逻辑支持负数索引 - 改进安全保存函数的备份和恢复机制 --- dexcel/src/main.rs | 65 +++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/dexcel/src/main.rs b/dexcel/src/main.rs index a9ab360..02edd04 100644 --- a/dexcel/src/main.rs +++ b/dexcel/src/main.rs @@ -154,8 +154,15 @@ enum Commands { }, /// 删除行 Delete { - #[arg(num_args = 1..=2, allow_hyphen_values = true, value_delimiter = ' ')] - range: Vec, + /// 起始行号(支持负数) + #[arg(allow_hyphen_values = true)] + start: i32, + /// 删除的行数(默认1) + #[arg(long, default_value_t = 1)] + count: u32, + /// 跳过确认 + #[arg(long, short = 'y')] + yes: bool, #[arg(long)] sheet: Option, }, @@ -314,10 +321,10 @@ fn main() -> Result<()> { update_excel(&mut book, value, *row, *cell, sheet, split)?; safe_save_umya(&mut book, file) } - Commands::Delete { range, sheet } => { + Commands::Delete { start, count, yes, sheet } => { let file = cli.file.as_ref().unwrap(); let mut book = reader::xlsx::read(file).map_err(|e| DexcelError::Umya(e.to_string()))?; - delete_excel(&mut book, range, sheet)?; + delete_excel(&mut book, *start, *count, *yes, sheet)?; safe_save_umya(&mut book, file) } Commands::Style { rows, cols, row_height, col_width, wrap_text, sheet } => { @@ -495,39 +502,43 @@ fn update_excel( fn delete_excel( book: &mut Spreadsheet, - range: &[i32], + start: i32, + count: u32, + yes: bool, sheet_name: &Option, ) -> Result<()> { let sheet = get_sheet_mut(book, sheet_name)?; let (_, max_row) = sheet.get_highest_column_and_row(); - let (start_del, end_del) = match range { - [n] if n > &0 => (1, *n as u32), - [n] if n < &0 => { - let count = (-n) as u32; - (max_row - count + 1, max_row) - }, - [a, b] => { - if a <= &0 || b < a { return Err(DexcelError::Operation("范围无效".into())); } - (*a as u32, *b as u32) - } - _ => return Err(DexcelError::Operation("参数错误".into())), + // 解析起始行 (转为 1-based) + let start_del = if start < 0 { + // 负数:从后往前数 + let pos = (max_row as i32 + start + 1).max(1) as u32; + pos + } else { + // 正数:直接使用 + start.max(1) as u32 }; - eprintln!("⚠ 即将删除第 {} 至 {} 行", start_del, end_del); - eprint!("确认? (y/N): "); - std::io::stdout().flush()?; - let mut input = String::new(); - std::io::stdin().read_line(&mut input)?; - if !input.trim().eq_ignore_ascii_case("y") { - println!("操作已取消"); - return Ok(()); + let end_del = (start_del + count - 1).min(max_row); + + // 确认 + if !yes { + eprintln!("⚠ 即将删除第 {} 至 {} 行(共 {} 行)", start_del, end_del, count); + eprint!("确认? (y/N): "); + std::io::stdout().flush()?; + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + if !input.trim().eq_ignore_ascii_case("y") { + println!("操作已取消"); + return Ok(()); + } } - let num_to_del = end_del - start_del + 1; - sheet.remove_row(&start_del, &num_to_del); + // 调用 umya 的删除方法 + sheet.remove_row(&start_del, &count); - println!("✓ 删除完成"); + println!("✓ 已删除第 {} 至 {} 行(共 {} 行)", start_del, end_del, count); Ok(()) }