mirror of
https://github.com/theryangeary/choose
synced 2024-11-10 05:24:13 +00:00
Move backslash escaping to separate crate
This commit is contained in:
parent
767b9303f2
commit
2ee77aa848
5 changed files with 14 additions and 138 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -29,6 +29,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backslash"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35a89ea09f2c7f3c81711c0db7d389d86a9d66fa15a7067e6fd6dbef863ef786"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
|
@ -39,6 +45,7 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
|||
name = "choose"
|
||||
version = "1.2.0"
|
||||
dependencies = [
|
||||
"backslash",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"structopt",
|
||||
|
|
|
@ -19,3 +19,4 @@ exclude = [
|
|||
structopt = "0.3"
|
||||
regex = "1"
|
||||
lazy_static = "1"
|
||||
backslash = "0"
|
||||
|
|
136
src/escape.rs
136
src/escape.rs
|
@ -1,137 +1 @@
|
|||
pub fn process_escapes(input: &str) -> String {
|
||||
if input.len() < 1 {
|
||||
return String::from(input);
|
||||
}
|
||||
|
||||
let mut v = Vec::from(input);
|
||||
for i in 0..(v.len() - 1) {
|
||||
if v[i] == '\\' as u8 && is_escapable(v[i + 1] as char) {
|
||||
v.remove(i);
|
||||
v[i] = char_to_escape_sequence(v[i] as char) as u8;
|
||||
}
|
||||
}
|
||||
String::from_utf8(v).unwrap()
|
||||
}
|
||||
|
||||
fn char_to_escape_sequence(chr: char) -> char {
|
||||
match chr {
|
||||
'n' => '\n',
|
||||
't' => '\t',
|
||||
'r' => '\r',
|
||||
'\\' => '\\',
|
||||
'0' => '\0',
|
||||
_ => chr,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_escapable(chr: char) -> bool {
|
||||
match chr {
|
||||
'n' | 't' | 'r' | '\\' | '0' => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
mod test_process_escapes {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_newline() {
|
||||
assert_eq!(
|
||||
String::from("hello\nworld"),
|
||||
process_escapes(r#"hello\nworld"#)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_carriage_return() {
|
||||
assert_eq!(
|
||||
String::from("hello\rworld"),
|
||||
process_escapes(r#"hello\rworld"#)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tab() {
|
||||
assert_eq!(
|
||||
String::from("hello\tworld"),
|
||||
process_escapes(r#"hello\tworld"#)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backslash() {
|
||||
assert_eq!(
|
||||
String::from("hello\\world"),
|
||||
process_escapes(r#"hello\\world"#)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_null() {
|
||||
assert_eq!(
|
||||
String::from("hello\0world"),
|
||||
process_escapes(r#"hello\0world"#)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_char_to_escape_sequence {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_escape_n() {
|
||||
assert_eq!('\n', char_to_escape_sequence('n'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_t() {
|
||||
assert_eq!('\t', char_to_escape_sequence('t'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_r() {
|
||||
assert_eq!('\r', char_to_escape_sequence('r'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_backslash() {
|
||||
assert_eq!('\\', char_to_escape_sequence('\\'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_0() {
|
||||
assert_eq!('\0', char_to_escape_sequence('0'));
|
||||
}
|
||||
}
|
||||
|
||||
mod is_escapable_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_escape_n() {
|
||||
assert!(is_escapable('n'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_t() {
|
||||
assert!(is_escapable('t'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_r() {
|
||||
assert!(is_escapable('r'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_backslash() {
|
||||
assert!(is_escapable('\\'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_0() {
|
||||
assert!(is_escapable('0'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::path::PathBuf;
|
|||
use structopt::StructOpt;
|
||||
|
||||
use crate::choice::Choice;
|
||||
use crate::escape;
|
||||
use crate::parse;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
|
@ -38,7 +37,7 @@ pub struct Opt {
|
|||
pub one_indexed: bool,
|
||||
|
||||
/// Specify output field separator
|
||||
#[structopt(short, long, parse(from_str = escape::process_escapes))]
|
||||
#[structopt(short, long, parse(from_str = parse::output_field_separator))]
|
||||
pub output_field_separator: Option<String>,
|
||||
|
||||
/// Fields to print. Either a, a:b, a..b, or a..=b, where a and b are integers. The beginning
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use backslash::escape_ascii;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::choice::{Choice, ChoiceKind};
|
||||
|
@ -60,6 +61,10 @@ pub fn choice(src: &str) -> Result<Choice, ParseError> {
|
|||
return Ok(Choice::new(start, end, kind));
|
||||
}
|
||||
|
||||
pub fn output_field_separator(src: &str) -> String {
|
||||
escape_ascii(src).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::parse;
|
||||
|
|
Loading…
Reference in a new issue