summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authorRyan Geary <rtgnj42@gmail.com>2019-09-15 18:16:42 -0400
committerRyan Geary <rtgnj42@gmail.com>2019-09-17 23:40:30 -0400
commitfd66e3cfb7f935b00befd7b04609cef7464e6e67 (patch)
tree0ca0e2840222eb61a2b033ba1c13c5c56359dec2 /src/main.rs
parent6c889b3963c797da78918f35709c3a12d0931cb0 (diff)
Move most of the processing out of main
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs156
1 files changed, 2 insertions, 154 deletions
diff --git a/src/main.rs b/src/main.rs
index 4d2e2bb..de1eb0f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,163 +1,11 @@
-use regex::Regex;
-use std::convert::TryInto;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read};
-use std::num::ParseIntError;
-use std::path::PathBuf;
-use std::process;
use structopt::StructOpt;
-type Range = (Option<u32>, Option<u32>);
-
-#[derive(Debug)]
-enum Choice {
- Field(u32),
- FieldRange(Range),
-}
-
-impl Choice {
- fn print_choice(&self, line: &String, opt: &Opt) {
- let re = Regex::new(match &opt.field_separator {
- Some(s) => s,
- None => "[[:space:]]",
- })
- .unwrap_or_else(|e| {
- eprintln!("Failed to compile regular expression: {}", e);
- // Exit code of 1 means failed to compile field_separator regex
- process::exit(1);
- });
-
- let words = re
- .split(line)
- .into_iter()
- .filter(|s| !s.is_empty())
- .enumerate();
-
- match self {
- Choice::Field(i) => {
- print!(
- "{} ",
- words
- .filter(|x| x.0 == *i as usize)
- .map(|x| x.1)
- .collect::<String>()
- );
- }
- Choice::FieldRange(r) => match r {
- (None, None) => print!("{}", words.map(|x| x.1).collect::<String>()),
- (Some(start), None) => print!(
- "{} ",
- words
- .filter(|x| x.0 >= (*start).try_into().unwrap())
- .map(|x| x.1)
- .collect::<Vec<&str>>()
- .join(" ")
- ),
- (None, Some(end)) => {
- let e: usize = if opt.inclusive {
- (end + 1).try_into().unwrap()
- } else {
- (*end).try_into().unwrap()
- };
- print!(
- "{} ",
- words
- .filter(|x| x.0 < e)
- .map(|x| x.1)
- .collect::<Vec<&str>>()
- .join(" ")
- )
- }
- (Some(start), Some(end)) => {
- let e: usize = if opt.inclusive {
- (end + 1).try_into().unwrap()
- } else {
- (*end).try_into().unwrap()
- };
- print!(
- "{} ",
- words
- .filter(|x| x.0 < e && x.0 >= (*start).try_into().unwrap())
- .map(|x| x.1)
- .collect::<Vec<&str>>()
- .join(" ")
- )
- }
- },
- };
- }
-
- fn parse_choice(src: &str) -> Result<Choice, ParseIntError> {
- let re = Regex::new(r"^(\d*):(\d*)$").unwrap();
-
- let cap = match re.captures_iter(src).next() {
- Some(v) => v,
- None => match src.parse() {
- Ok(x) => return Ok(Choice::Field(x)),
- Err(_) => {
- eprintln!("failed to parse choice argument: {}", src);
- // Exit code of 2 means failed to parse choice argument
- process::exit(2);
- }
- },
- };
-
- let start = if cap[1].is_empty() {
- None
- } else {
- match cap[1].parse() {
- Ok(x) => Some(x),
- Err(_) => {
- eprintln!("failed to parse range start: {}", &cap[1]);
- process::exit(2);
- }
- }
- };
-
- let end = if cap[2].is_empty() {
- None
- } else {
- match cap[2].parse() {
- Ok(x) => Some(x),
- Err(_) => {
- eprintln!("failed to parse range end: {}", &cap[2]);
- process::exit(2);
- }
- }
- };
-
- return Ok(Choice::FieldRange((start, end)));
- }
-}
-
-#[derive(Debug, StructOpt)]
-#[structopt(name = "choose", about = "`choose` sections from each line of files")]
-struct Opt {
- /// Specify field separator other than whitespace
- #[structopt(short, long)]
- field_separator: Option<String>,
-
- /// Use inclusive ranges
- #[structopt(short = "n", long)]
- inclusive: bool,
-
- /// Activate debug mode
- #[structopt(short, long)]
- debug: bool,
-
- /// Input file
- #[structopt(short, long, parse(from_os_str))]
- input: Option<PathBuf>,
-
- /// Fields to print. Either x, x:, :y, or x:y, where x and y are integers, colons indicate a
- /// range, and an empty field on either side of the colon continues to the beginning or end of
- /// the line.
- #[structopt(required = true, min_values = 1, parse(try_from_str = Choice::parse_choice))]
- choice: Vec<Choice>,
-}
+mod choice;
fn main() {
- let opt = Opt::from_args();
+ let opt = choice::Opt::from_args();
let read = match &opt.input {
Some(f) => Box::new(File::open(f).expect("Could not open file")) as Box<dyn Read>,