|
@@ -1,17 +1,19 @@
|
|
use std::{
|
|
use std::{
|
|
fs::File,
|
|
fs::File,
|
|
io::{Cursor, Read, Write},
|
|
io::{Cursor, Read, Write},
|
|
|
|
+ ops::RangeInclusive,
|
|
path::PathBuf,
|
|
path::PathBuf,
|
|
time::Instant,
|
|
time::Instant,
|
|
};
|
|
};
|
|
|
|
|
|
use binrw::{BinRead, BinWrite, BinWriterExt};
|
|
use binrw::{BinRead, BinWrite, BinWriterExt};
|
|
-use clap::{Args, Parser, Subcommand};
|
|
|
|
|
|
+use clap::{error::ErrorKind, Args, Error, Parser, Subcommand};
|
|
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
|
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
|
use diff::Diff;
|
|
use diff::Diff;
|
|
use env_logger::Target;
|
|
use env_logger::Target;
|
|
use ezcad::{file::EzCadHeader, layer::Layer, objects::Object};
|
|
use ezcad::{file::EzCadHeader, layer::Layer, objects::Object};
|
|
use log::{info, trace, warn};
|
|
use log::{info, trace, warn};
|
|
|
|
+use regex::Regex;
|
|
|
|
|
|
use crate::config::{Config, Operations};
|
|
use crate::config::{Config, Operations};
|
|
|
|
|
|
@@ -48,11 +50,12 @@ struct DiffCmd {
|
|
/// Queries input .mlp file for pen or object info
|
|
/// Queries input .mlp file for pen or object info
|
|
#[derive(Debug, Args)]
|
|
#[derive(Debug, Args)]
|
|
struct QueryCmd {
|
|
struct QueryCmd {
|
|
- /// Print pen info
|
|
|
|
|
|
+ /// Print info for pens
|
|
#[arg(short, long)]
|
|
#[arg(short, long)]
|
|
- pen: Option<Vec<usize>>,
|
|
|
|
|
|
+ #[arg(value_parser = parse_range)]
|
|
|
|
+ pen: Option<RangeInclusive<usize>>,
|
|
|
|
|
|
- /// Print object info
|
|
|
|
|
|
+ /// Print info for objects
|
|
#[arg(short, long)]
|
|
#[arg(short, long)]
|
|
object: Option<usize>,
|
|
object: Option<usize>,
|
|
|
|
|
|
@@ -73,6 +76,44 @@ struct ApplyConfig {
|
|
output: Option<PathBuf>,
|
|
output: Option<PathBuf>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/// Helper function to parse a string as an RangeInclusive<usize>
|
|
|
|
+fn parse_range(arg: &str) -> Result<RangeInclusive<usize>, Error> {
|
|
|
|
+ let re: Regex = Regex::new(r"(\d+)?(\.{2})?(=)?(\d+)?").unwrap();
|
|
|
|
+ const PEN_MAX: usize = 255;
|
|
|
|
+
|
|
|
|
+ match re.captures(arg) {
|
|
|
|
+ Some(found) => {
|
|
|
|
+ let range: bool = found.get(2).is_some();
|
|
|
|
+ let inclusive: bool = found.get(3).is_some();
|
|
|
|
+ let d1: Option<usize> = found
|
|
|
|
+ .get(1)
|
|
|
|
+ .map(|x| usize::from_str_radix(x.as_str(), 10).unwrap());
|
|
|
|
+ let d2: Option<usize> = found
|
|
|
|
+ .get(4)
|
|
|
|
+ .map(|x| usize::from_str_radix(x.as_str(), 10).unwrap());
|
|
|
|
+
|
|
|
|
+ let ret = |d1: usize, d2: usize, inclusive: bool| -> RangeInclusive<usize> {
|
|
|
|
+ match inclusive {
|
|
|
|
+ true => d1..=d2,
|
|
|
|
+ false => d1..=(d2 - 1),
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ match (d1, d2) {
|
|
|
|
+ (None, None) if range => Ok(0..=PEN_MAX),
|
|
|
|
+ (None, None) => Err(Error::new(ErrorKind::InvalidValue)),
|
|
|
|
+ (Some(d1), None) if !range => Ok(d1..=d1),
|
|
|
|
+ (Some(d1), None) => Ok(ret(d1, PEN_MAX, true)),
|
|
|
|
+ (None, Some(d2)) if !range => Ok(d2..=d2),
|
|
|
|
+ (None, Some(d2)) => Ok(ret(0, d2, inclusive)),
|
|
|
|
+ (Some(d1), Some(d2)) if d1 > d2 => Err(Error::new(ErrorKind::InvalidValue)),
|
|
|
|
+ (Some(d1), Some(d2)) => Ok(ret(d1, d2, inclusive)),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ _ => Err(Error::new(ErrorKind::InvalidValue)),
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
fn main() {
|
|
fn main() {
|
|
let cli: Cli = Cli::parse();
|
|
let cli: Cli = Cli::parse();
|
|
|
|
|
|
@@ -164,8 +205,8 @@ fn main() {
|
|
}
|
|
}
|
|
|
|
|
|
// Process pen query
|
|
// Process pen query
|
|
- args.pen.map(|pens| {
|
|
|
|
- for pen in pens {
|
|
|
|
|
|
+ args.pen.map(|pen_range| {
|
|
|
|
+ for pen in pen_range {
|
|
info!(
|
|
info!(
|
|
"Pen #{}: {}",
|
|
"Pen #{}: {}",
|
|
pen,
|
|
pen,
|