This commit is contained in:
Greg 2018-12-23 00:01:35 -05:00
commit db3fc2fcff
8 changed files with 413 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
**/*.rs.bk

212
Cargo.lock generated Normal file
View file

@ -0,0 +1,212 @@
[[package]]
name = "aho-corasick"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "re"
version = "0.1.0"
dependencies = [
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9"
"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

20
Cargo.toml Normal file
View file

@ -0,0 +1,20 @@
[package]
name = "re"
version = "0.1.0"
edition = "2018"
authors = ["Gregory <gregory.mkv@gmail.com>"]
description = "A find & replace CLI focused on user-friendliness"
keywords = ["sed", "find", "replace", "regex"]
license = "MIT"
homepage = "https://github.com/chmln/re"
repository = "https://github.com/chmln/re.git"
categories = ["command-line-utilities", "text-processing", "development-tools"]
[dependencies]
clap = "2.32.0"
regex = "1.1.0"
[profile.release]
opt-level = 3
lto = true
debug = false

56
src/app.rs Normal file
View file

@ -0,0 +1,56 @@
use {crate::{Error,Stream,Source}};
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub(crate) struct App;
impl App {
pub(crate) fn run() -> Result<(), Error> {
use clap;
let app = clap::App::new("re")
.version(VERSION)
.setting(clap::AppSettings::ColoredHelp)
.setting(clap::AppSettings::NextLineHelp)
.arg(
clap::Arg::with_name("enable_regex")
.short("r")
.long("regex")
.required(false)
.takes_value(false)
.help("Enable regex"),
)
.arg(
clap::Arg::with_name("input")
.short("i")
.required(false)
.takes_value(true)
.help("The path to file")
)
.arg(
clap::Arg::with_name("find")
.help("The string or regexp (if --regex) to search for.")
.required(true)
.index(1),
)
.arg(
clap::Arg::with_name("replace_with")
.help("What to replace each match with. If regex is enabled, you may use captured values like $1, $2, etc.")
.required(true)
.index(2),
);
let matches = app.get_matches();
let file_path = matches.value_of("input").map(|p| p.to_string());
let find = matches.value_of("find").unwrap();
let replace_with = matches.value_of("replace_with").unwrap();
let is_regex = matches.occurrences_of("enable_regex") == 1;
let source = Source::from(file_path);
let mut stream: Stream = (&source).into_stream()?;
stream.replace(is_regex, find, replace_with)?;
// replace file in-place, or pipe to stdout
stream.output(&source)
}
}

32
src/error.rs Normal file
View file

@ -0,0 +1,32 @@
pub(crate) struct Error {
// low-level cause, used only for debugging
cause: String,
// user-facing error output
description: String,
}
impl<T> From<T> for Error
where
T: std::error::Error,
{
fn from(err: T) -> Error {
Error {
cause: err
.source()
.map_or_else(|| "N/A".to_string(), |e| e.to_string()),
description: format!("{}", err),
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.description)
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Error: {}\nDetails: {}", self.description, self.cause)
}
}

78
src/input.rs Normal file
View file

@ -0,0 +1,78 @@
use {crate::Error, std::{fs::File, io::prelude::*}};
pub(crate) enum Source {
Stdin,
File(String),
}
impl Source {
pub(crate) fn from(maybe_path: Option<String>) -> Self {
maybe_path
.map(Source::File)
.unwrap_or_else(|| Source::Stdin)
}
pub(crate) fn into_stream(&self) -> Result<Stream, Error> {
match self {
Source::Stdin => {
let mut buffer = String::new();
let stdin = std::io::stdin();
let mut handle = stdin.lock();
handle.read_to_string(&mut buffer)?;
Ok(Stream::new(buffer))
}
Source::File(path) => {
let file = File::open(path)?;
let mut buf_reader = std::io::BufReader::new(file);
let mut buffer = String::new();
buf_reader.read_to_string(&mut buffer)?;
Ok(Stream::new(buffer))
}
}
}
}
pub(crate) struct Stream {
data: String,
}
impl Stream {
pub(crate) fn new(data: String) -> Self {
Self { data }
}
pub(crate) fn replace(
&mut self,
is_regex: bool,
look_for: &str,
replace_with: &str,
) -> Result<(), crate::Error> {
if is_regex {
self.data = regex::Regex::new(look_for)?
.replace_all(&self.data, replace_with)
.to_string()
} else {
self.data = self.data.replace(look_for, replace_with)
}
Ok(())
}
// Output based on input.
// When dealing with a file, transform it in-place.
// Otherwise, pipe to stdout.
pub(crate) fn output(self, source: &Source) -> Result<(), crate::Error> {
match source {
Source::File(path) => {
Ok(std::fs::write(path, self.data)?)
},
Source::Stdin => {
let stdout = std::io::stdout();
let mut handle = stdout.lock();
handle.write(self.data.as_bytes())?;
Ok(())
}
}
}
}

12
src/main.rs Normal file
View file

@ -0,0 +1,12 @@
mod app;
mod error;
mod input;
pub(crate) use {
crate::error::Error,
crate::input::{Source, Stream},
};
fn main() -> Result<(), ()> {
app::App::run().map_err(|e| eprintln!("{}", e))
}

1
src/utils.rs Normal file
View file

@ -0,0 +1 @@