mirror of
https://github.com/crate-ci/typos.git
synced 2024-11-22 00:51:11 -05:00
fix: Handle broken pipe
This commit is contained in:
parent
d84117da1f
commit
869b916ca6
13 changed files with 241 additions and 340 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -668,6 +668,12 @@ dependencies = [
|
||||||
"treeline",
|
"treeline",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-exit"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ac573c94c4d539e8c339d612c8fc9835d286989411f1381a84a304c0ac19b41"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -973,15 +979,6 @@ dependencies = [
|
||||||
"unicode-xid 0.2.1",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sysexit"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a26991bb0e6ef939ac9a8d6b57979efa59921928a3aa0334d818fe6e458aa6a9"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tap"
|
name = "tap"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -1099,9 +1096,9 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"phf",
|
"phf",
|
||||||
"predicates",
|
"predicates",
|
||||||
|
"proc-exit",
|
||||||
"serde",
|
"serde",
|
||||||
"structopt",
|
"structopt",
|
||||||
"sysexit",
|
|
||||||
"toml",
|
"toml",
|
||||||
"typos",
|
"typos",
|
||||||
"typos-dict",
|
"typos-dict",
|
||||||
|
|
|
@ -48,7 +48,7 @@ env_logger = "0.8"
|
||||||
bstr = "0.2"
|
bstr = "0.2"
|
||||||
ahash = "0.5.8"
|
ahash = "0.5.8"
|
||||||
difflib = "0.4"
|
difflib = "0.4"
|
||||||
sysexit = "0.2"
|
proc-exit = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_fs = "1.0"
|
assert_fs = "1.0"
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub trait Check: Send + Sync {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
dictionary: &dyn Dictionary,
|
dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error>;
|
) -> Result<(), std::io::Error>;
|
||||||
|
|
||||||
fn check_bytes(
|
fn check_bytes(
|
||||||
&self,
|
&self,
|
||||||
|
@ -20,7 +20,7 @@ pub trait Check: Send + Sync {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
dictionary: &dyn Dictionary,
|
dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error>;
|
) -> Result<(), std::io::Error>;
|
||||||
|
|
||||||
fn check_filenames(&self) -> bool;
|
fn check_filenames(&self) -> bool;
|
||||||
|
|
||||||
|
@ -34,11 +34,9 @@ pub trait Check: Send + Sync {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
dictionary: &dyn Dictionary,
|
dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let mut typos_found = false;
|
|
||||||
|
|
||||||
if !self.check_filenames() {
|
if !self.check_filenames() {
|
||||||
return Ok(typos_found);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
|
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
|
||||||
|
@ -46,10 +44,10 @@ pub trait Check: Send + Sync {
|
||||||
reporter,
|
reporter,
|
||||||
context: report::PathContext { path }.into(),
|
context: report::PathContext { path }.into(),
|
||||||
};
|
};
|
||||||
typos_found |= self.check_str(file_name, parser, dictionary, &context_reporter)?;
|
self.check_str(file_name, parser, dictionary, &context_reporter)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_file(
|
fn check_file(
|
||||||
|
@ -59,19 +57,17 @@ pub trait Check: Send + Sync {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
dictionary: &dyn Dictionary,
|
dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let mut typos_found = false;
|
|
||||||
|
|
||||||
if !self.check_files() {
|
if !self.check_files() {
|
||||||
return Ok(typos_found);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = read_file(path)?;
|
let buffer = read_file(path, reporter)?;
|
||||||
let (buffer, content_type) = massage_data(buffer)?;
|
let (buffer, content_type) = massage_data(buffer)?;
|
||||||
if !explicit && !self.binary() && content_type.is_binary() {
|
if !explicit && !self.binary() && content_type.is_binary() {
|
||||||
let msg = report::BinaryFile { path };
|
let msg = report::BinaryFile { path };
|
||||||
reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
return Ok(typos_found);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (line_idx, line) in buffer.lines().enumerate() {
|
for (line_idx, line) in buffer.lines().enumerate() {
|
||||||
|
@ -80,10 +76,10 @@ pub trait Check: Send + Sync {
|
||||||
reporter,
|
reporter,
|
||||||
context: report::FileContext { path, line_num }.into(),
|
context: report::FileContext { path, line_num }.into(),
|
||||||
};
|
};
|
||||||
typos_found |= self.check_bytes(line, parser, dictionary, &context_reporter)?;
|
self.check_bytes(line, parser, dictionary, &context_reporter)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +89,7 @@ struct ReportContext<'m, 'r> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m, 'r> report::Report for ReportContext<'m, 'r> {
|
impl<'m, 'r> report::Report for ReportContext<'m, 'r> {
|
||||||
fn report(&self, msg: report::Message) -> bool {
|
fn report(&self, msg: report::Message) -> Result<(), std::io::Error> {
|
||||||
let msg = msg.context(Some(self.context.clone()));
|
let msg = msg.context(Some(self.context.clone()));
|
||||||
self.reporter.report(msg)
|
self.reporter.report(msg)
|
||||||
}
|
}
|
||||||
|
@ -179,9 +175,7 @@ impl Check for Typos {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
dictionary: &dyn Dictionary,
|
dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let mut typos_found = false;
|
|
||||||
|
|
||||||
for ident in parser.parse_str(buffer) {
|
for ident in parser.parse_str(buffer) {
|
||||||
match dictionary.correct_ident(ident) {
|
match dictionary.correct_ident(ident) {
|
||||||
Some(Status::Valid) => {}
|
Some(Status::Valid) => {}
|
||||||
|
@ -194,7 +188,7 @@ impl Check for Typos {
|
||||||
typo: ident.token(),
|
typo: ident.token(),
|
||||||
corrections,
|
corrections,
|
||||||
};
|
};
|
||||||
typos_found |= reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
for word in ident.split() {
|
for word in ident.split() {
|
||||||
|
@ -209,7 +203,7 @@ impl Check for Typos {
|
||||||
typo: word.token(),
|
typo: word.token(),
|
||||||
corrections,
|
corrections,
|
||||||
};
|
};
|
||||||
typos_found |= reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
@ -217,8 +211,7 @@ impl Check for Typos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
Ok(typos_found)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_bytes(
|
fn check_bytes(
|
||||||
|
@ -227,9 +220,7 @@ impl Check for Typos {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
dictionary: &dyn Dictionary,
|
dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let mut typos_found = false;
|
|
||||||
|
|
||||||
for ident in parser.parse_bytes(buffer) {
|
for ident in parser.parse_bytes(buffer) {
|
||||||
match dictionary.correct_ident(ident) {
|
match dictionary.correct_ident(ident) {
|
||||||
Some(Status::Valid) => {}
|
Some(Status::Valid) => {}
|
||||||
|
@ -242,7 +233,7 @@ impl Check for Typos {
|
||||||
typo: ident.token(),
|
typo: ident.token(),
|
||||||
corrections,
|
corrections,
|
||||||
};
|
};
|
||||||
typos_found |= reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
for word in ident.split() {
|
for word in ident.split() {
|
||||||
|
@ -257,7 +248,7 @@ impl Check for Typos {
|
||||||
typo: word.token(),
|
typo: word.token(),
|
||||||
corrections,
|
corrections,
|
||||||
};
|
};
|
||||||
typos_found |= reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +257,7 @@ impl Check for Typos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_filenames(&self) -> bool {
|
fn check_filenames(&self) -> bool {
|
||||||
|
@ -296,19 +287,17 @@ impl Check for ParseIdentifiers {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
|
||||||
|
|
||||||
let msg = report::Parse {
|
let msg = report::Parse {
|
||||||
context: None,
|
context: None,
|
||||||
kind: report::ParseKind::Identifier,
|
kind: report::ParseKind::Identifier,
|
||||||
data: parser.parse_str(buffer).map(|i| i.token()).collect(),
|
data: parser.parse_str(buffer).map(|i| i.token()).collect(),
|
||||||
};
|
};
|
||||||
if !msg.data.is_empty() {
|
if !msg.data.is_empty() {
|
||||||
reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_bytes(
|
fn check_bytes(
|
||||||
|
@ -317,19 +306,17 @@ impl Check for ParseIdentifiers {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
|
||||||
|
|
||||||
let msg = report::Parse {
|
let msg = report::Parse {
|
||||||
context: None,
|
context: None,
|
||||||
kind: report::ParseKind::Identifier,
|
kind: report::ParseKind::Identifier,
|
||||||
data: parser.parse_bytes(buffer).map(|i| i.token()).collect(),
|
data: parser.parse_bytes(buffer).map(|i| i.token()).collect(),
|
||||||
};
|
};
|
||||||
if !msg.data.is_empty() {
|
if !msg.data.is_empty() {
|
||||||
reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_filenames(&self) -> bool {
|
fn check_filenames(&self) -> bool {
|
||||||
|
@ -359,9 +346,7 @@ impl Check for ParseWords {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
|
||||||
|
|
||||||
let msg = report::Parse {
|
let msg = report::Parse {
|
||||||
context: None,
|
context: None,
|
||||||
kind: report::ParseKind::Word,
|
kind: report::ParseKind::Word,
|
||||||
|
@ -371,10 +356,10 @@ impl Check for ParseWords {
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
if !msg.data.is_empty() {
|
if !msg.data.is_empty() {
|
||||||
reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_bytes(
|
fn check_bytes(
|
||||||
|
@ -383,9 +368,7 @@ impl Check for ParseWords {
|
||||||
parser: &tokens::Parser,
|
parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
|
||||||
|
|
||||||
let msg = report::Parse {
|
let msg = report::Parse {
|
||||||
context: None,
|
context: None,
|
||||||
kind: report::ParseKind::Word,
|
kind: report::ParseKind::Word,
|
||||||
|
@ -395,10 +378,10 @@ impl Check for ParseWords {
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
if !msg.data.is_empty() {
|
if !msg.data.is_empty() {
|
||||||
reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_filenames(&self) -> bool {
|
fn check_filenames(&self) -> bool {
|
||||||
|
@ -424,9 +407,8 @@ impl Check for Files {
|
||||||
_parser: &tokens::Parser,
|
_parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
_reporter: &dyn report::Report,
|
_reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
Ok(())
|
||||||
Ok(typos_found)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_bytes(
|
fn check_bytes(
|
||||||
|
@ -435,9 +417,8 @@ impl Check for Files {
|
||||||
_parser: &tokens::Parser,
|
_parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
_reporter: &dyn report::Report,
|
_reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
Ok(())
|
||||||
Ok(typos_found)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_filenames(&self) -> bool {
|
fn check_filenames(&self) -> bool {
|
||||||
|
@ -458,9 +439,8 @@ impl Check for Files {
|
||||||
_parser: &tokens::Parser,
|
_parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
_reporter: &dyn report::Report,
|
_reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
Ok(())
|
||||||
Ok(typos_found)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_file(
|
fn check_file(
|
||||||
|
@ -470,23 +450,32 @@ impl Check for Files {
|
||||||
_parser: &tokens::Parser,
|
_parser: &tokens::Parser,
|
||||||
_dictionary: &dyn Dictionary,
|
_dictionary: &dyn Dictionary,
|
||||||
reporter: &dyn report::Report,
|
reporter: &dyn report::Report,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let typos_found = false;
|
|
||||||
|
|
||||||
let msg = report::File::new(path);
|
let msg = report::File::new(path);
|
||||||
reporter.report(msg.into());
|
reporter.report(msg.into())?;
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file(path: &std::path::Path) -> Result<Vec<u8>, crate::Error> {
|
fn read_file(
|
||||||
std::fs::read(path).map_err(|e| crate::ErrorKind::IoError.into_error().with_source(e))
|
path: &std::path::Path,
|
||||||
|
reporter: &dyn report::Report,
|
||||||
|
) -> Result<Vec<u8>, std::io::Error> {
|
||||||
|
let buffer = match std::fs::read(path) {
|
||||||
|
Ok(buffer) => buffer,
|
||||||
|
Err(err) => {
|
||||||
|
let msg = report::Error::new(err.to_string());
|
||||||
|
reporter.report(msg.into())?;
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn massage_data(
|
fn massage_data(
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
) -> Result<(Vec<u8>, content_inspector::ContentType), crate::Error> {
|
) -> Result<(Vec<u8>, content_inspector::ContentType), std::io::Error> {
|
||||||
let mut content_type = content_inspector::inspect(&buffer);
|
let mut content_type = content_inspector::inspect(&buffer);
|
||||||
|
|
||||||
// HACK: We only support UTF-8 at the moment
|
// HACK: We only support UTF-8 at the moment
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
#[derive(Debug, Clone, Copy, derive_more::Display)]
|
|
||||||
pub enum ErrorKind {
|
|
||||||
#[display(fmt = "Invalid word")]
|
|
||||||
InvalidWord,
|
|
||||||
#[display(fmt = "IO Error")]
|
|
||||||
IoError,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErrorKind {
|
|
||||||
pub fn into_error(self) -> Error {
|
|
||||||
Error {
|
|
||||||
kind: self,
|
|
||||||
msg: None,
|
|
||||||
source: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub struct Error {
|
|
||||||
kind: ErrorKind,
|
|
||||||
msg: Option<String>,
|
|
||||||
source: Option<anyhow::Error>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error {
|
|
||||||
pub fn with_message(mut self, msg: String) -> Self {
|
|
||||||
self.msg = Some(msg);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_source<E: std::error::Error + std::fmt::Debug + Send + Sync + 'static>(
|
|
||||||
mut self,
|
|
||||||
source: E,
|
|
||||||
) -> Self {
|
|
||||||
self.source = Some(source.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
|
||||||
if let Some(msg) = self.msg.as_ref() {
|
|
||||||
write!(f, "{}: {}", self.kind, msg)?;
|
|
||||||
} else if let Some(source) = self.source.as_ref() {
|
|
||||||
write!(f, "{}: {}", self.kind, source)?;
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", self.kind)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,7 @@
|
||||||
mod dict;
|
mod dict;
|
||||||
mod error;
|
|
||||||
|
|
||||||
pub mod checks;
|
pub mod checks;
|
||||||
pub mod report;
|
pub mod report;
|
||||||
pub mod tokens;
|
pub mod tokens;
|
||||||
|
|
||||||
pub use crate::dict::*;
|
pub use crate::dict::*;
|
||||||
pub use crate::error::*;
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use std::sync::atomic;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
|
#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
@ -214,15 +215,49 @@ impl Default for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Report: Send + Sync {
|
pub trait Report: Send + Sync {
|
||||||
fn report(&self, msg: Message) -> bool;
|
fn report(&self, msg: Message) -> Result<(), std::io::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
pub struct MessageStatus<'r> {
|
||||||
|
typos_found: atomic::AtomicBool,
|
||||||
|
errors_found: atomic::AtomicBool,
|
||||||
|
reporter: &'r dyn Report,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> MessageStatus<'r> {
|
||||||
|
pub fn new(reporter: &'r dyn Report) -> Self {
|
||||||
|
Self {
|
||||||
|
typos_found: atomic::AtomicBool::new(false),
|
||||||
|
errors_found: atomic::AtomicBool::new(false),
|
||||||
|
reporter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn typos_found(&self) -> bool {
|
||||||
|
self.typos_found.load(atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn errors_found(&self) -> bool {
|
||||||
|
self.errors_found.load(atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> Report for MessageStatus<'r> {
|
||||||
|
fn report(&self, msg: Message) -> Result<(), std::io::Error> {
|
||||||
|
self.typos_found
|
||||||
|
.compare_and_swap(false, msg.is_correction(), atomic::Ordering::Relaxed);
|
||||||
|
self.errors_found
|
||||||
|
.compare_and_swap(false, msg.is_error(), atomic::Ordering::Relaxed);
|
||||||
|
self.reporter.report(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
pub struct PrintSilent;
|
pub struct PrintSilent;
|
||||||
|
|
||||||
impl Report for PrintSilent {
|
impl Report for PrintSilent {
|
||||||
fn report(&self, msg: Message) -> bool {
|
fn report(&self, _msg: Message) -> Result<(), std::io::Error> {
|
||||||
msg.is_correction()
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,17 +265,17 @@ impl Report for PrintSilent {
|
||||||
pub struct PrintBrief;
|
pub struct PrintBrief;
|
||||||
|
|
||||||
impl Report for PrintBrief {
|
impl Report for PrintBrief {
|
||||||
fn report(&self, msg: Message) -> bool {
|
fn report(&self, msg: Message) -> Result<(), std::io::Error> {
|
||||||
match &msg {
|
match &msg {
|
||||||
Message::BinaryFile(msg) => {
|
Message::BinaryFile(msg) => {
|
||||||
log::info!("{}", msg);
|
log::info!("{}", msg);
|
||||||
}
|
}
|
||||||
Message::Typo(msg) => print_brief_correction(msg),
|
Message::Typo(msg) => print_brief_correction(msg)?,
|
||||||
Message::File(msg) => {
|
Message::File(msg) => {
|
||||||
println!("{}", msg.path.display());
|
writeln!(io::stdout(), "{}", msg.path.display())?;
|
||||||
}
|
}
|
||||||
Message::Parse(msg) => {
|
Message::Parse(msg) => {
|
||||||
println!("{}", itertools::join(msg.data.iter(), " "));
|
writeln!(io::stdout(), "{}", itertools::join(msg.data.iter(), " "))?;
|
||||||
}
|
}
|
||||||
Message::PathError(msg) => {
|
Message::PathError(msg) => {
|
||||||
log::error!("{}: {}", msg.path.display(), msg.msg);
|
log::error!("{}: {}", msg.path.display(), msg.msg);
|
||||||
|
@ -249,7 +284,7 @@ impl Report for PrintBrief {
|
||||||
log::error!("{}", msg.msg);
|
log::error!("{}", msg.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg.is_correction()
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,17 +292,17 @@ impl Report for PrintBrief {
|
||||||
pub struct PrintLong;
|
pub struct PrintLong;
|
||||||
|
|
||||||
impl Report for PrintLong {
|
impl Report for PrintLong {
|
||||||
fn report(&self, msg: Message) -> bool {
|
fn report(&self, msg: Message) -> Result<(), std::io::Error> {
|
||||||
match &msg {
|
match &msg {
|
||||||
Message::BinaryFile(msg) => {
|
Message::BinaryFile(msg) => {
|
||||||
log::info!("{}", msg);
|
log::info!("{}", msg);
|
||||||
}
|
}
|
||||||
Message::Typo(msg) => print_long_correction(msg),
|
Message::Typo(msg) => print_long_correction(msg)?,
|
||||||
Message::File(msg) => {
|
Message::File(msg) => {
|
||||||
println!("{}", msg.path.display());
|
writeln!(io::stdout(), "{}", msg.path.display())?;
|
||||||
}
|
}
|
||||||
Message::Parse(msg) => {
|
Message::Parse(msg) => {
|
||||||
println!("{}", itertools::join(msg.data.iter(), " "));
|
writeln!(io::stdout(), "{}", itertools::join(msg.data.iter(), " "))?;
|
||||||
}
|
}
|
||||||
Message::PathError(msg) => {
|
Message::PathError(msg) => {
|
||||||
log::error!("{}: {}", msg.path.display(), msg.msg);
|
log::error!("{}: {}", msg.path.display(), msg.msg);
|
||||||
|
@ -276,34 +311,38 @@ impl Report for PrintLong {
|
||||||
log::error!("{}", msg.msg);
|
log::error!("{}", msg.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg.is_correction()
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_brief_correction(msg: &Typo) {
|
fn print_brief_correction(msg: &Typo) -> Result<(), std::io::Error> {
|
||||||
match &msg.corrections {
|
match &msg.corrections {
|
||||||
crate::Status::Valid => {}
|
crate::Status::Valid => {}
|
||||||
crate::Status::Invalid => {
|
crate::Status::Invalid => {
|
||||||
println!(
|
writeln!(
|
||||||
|
io::stdout(),
|
||||||
"{}:{}: {} is disallowed",
|
"{}:{}: {} is disallowed",
|
||||||
context_display(&msg.context),
|
context_display(&msg.context),
|
||||||
msg.byte_offset,
|
msg.byte_offset,
|
||||||
msg.typo,
|
msg.typo,
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
crate::Status::Corrections(corrections) => {
|
crate::Status::Corrections(corrections) => {
|
||||||
println!(
|
writeln!(
|
||||||
|
io::stdout(),
|
||||||
"{}:{}: {} -> {}",
|
"{}:{}: {} -> {}",
|
||||||
context_display(&msg.context),
|
context_display(&msg.context),
|
||||||
msg.byte_offset,
|
msg.byte_offset,
|
||||||
msg.typo,
|
msg.typo,
|
||||||
itertools::join(corrections.iter(), ", ")
|
itertools::join(corrections.iter(), ", ")
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_long_correction(msg: &Typo) {
|
fn print_long_correction(msg: &Typo) -> Result<(), std::io::Error> {
|
||||||
let stdout = io::stdout();
|
let stdout = io::stdout();
|
||||||
let mut handle = stdout.lock();
|
let mut handle = stdout.lock();
|
||||||
match &msg.corrections {
|
match &msg.corrections {
|
||||||
|
@ -315,8 +354,7 @@ fn print_long_correction(msg: &Typo) {
|
||||||
context_display(&msg.context),
|
context_display(&msg.context),
|
||||||
msg.byte_offset,
|
msg.byte_offset,
|
||||||
msg.typo,
|
msg.typo,
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
crate::Status::Corrections(corrections) => {
|
crate::Status::Corrections(corrections) => {
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -324,8 +362,7 @@ fn print_long_correction(msg: &Typo) {
|
||||||
"error: `{}` should be {}",
|
"error: `{}` should be {}",
|
||||||
msg.typo,
|
msg.typo,
|
||||||
itertools::join(corrections.iter(), ", ")
|
itertools::join(corrections.iter(), ", ")
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -333,8 +370,7 @@ fn print_long_correction(msg: &Typo) {
|
||||||
" --> {}:{}",
|
" --> {}:{}",
|
||||||
context_display(&msg.context),
|
context_display(&msg.context),
|
||||||
msg.byte_offset
|
msg.byte_offset
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(Context::File(context)) = &msg.context {
|
if let Some(Context::File(context)) = &msg.context {
|
||||||
let line_num = context.line_num.to_string();
|
let line_num = context.line_num.to_string();
|
||||||
|
@ -345,11 +381,13 @@ fn print_long_correction(msg: &Typo) {
|
||||||
|
|
||||||
let line = String::from_utf8_lossy(msg.buffer.as_ref());
|
let line = String::from_utf8_lossy(msg.buffer.as_ref());
|
||||||
let line = line.replace("\t", " ");
|
let line = line.replace("\t", " ");
|
||||||
writeln!(handle, "{} |", line_indent).unwrap();
|
writeln!(handle, "{} |", line_indent)?;
|
||||||
writeln!(handle, "{} | {}", line_num, line.trim_end()).unwrap();
|
writeln!(handle, "{} | {}", line_num, line.trim_end())?;
|
||||||
writeln!(handle, "{} | {}{}", line_indent, hl_indent, hl).unwrap();
|
writeln!(handle, "{} | {}{}", line_indent, hl_indent, hl)?;
|
||||||
writeln!(handle, "{} |", line_indent).unwrap();
|
writeln!(handle, "{} |", line_indent)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn context_display<'c>(context: &'c Option<Context<'c>>) -> &'c dyn std::fmt::Display {
|
fn context_display<'c>(context: &'c Option<Context<'c>>) -> &'c dyn std::fmt::Display {
|
||||||
|
@ -363,8 +401,8 @@ fn context_display<'c>(context: &'c Option<Context<'c>>) -> &'c dyn std::fmt::Di
|
||||||
pub struct PrintJson;
|
pub struct PrintJson;
|
||||||
|
|
||||||
impl Report for PrintJson {
|
impl Report for PrintJson {
|
||||||
fn report(&self, msg: Message) -> bool {
|
fn report(&self, msg: Message) -> Result<(), std::io::Error> {
|
||||||
println!("{}", serde_json::to_string(&msg).unwrap());
|
writeln!(io::stdout(), "{}", serde_json::to_string(&msg).unwrap())?;
|
||||||
msg.is_correction()
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,23 +192,26 @@ pub struct Word<'t> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Word<'t> {
|
impl<'t> Word<'t> {
|
||||||
pub fn new(token: &'t str, offset: usize) -> Result<Self, crate::Error> {
|
pub fn new(token: &'t str, offset: usize) -> Result<Self, std::io::Error> {
|
||||||
let mut itr = split_ident(token, 0);
|
let mut itr = split_ident(token, 0);
|
||||||
let mut item = itr.next().ok_or_else(|| {
|
let mut item = itr.next().ok_or_else(|| {
|
||||||
crate::ErrorKind::InvalidWord
|
std::io::Error::new(
|
||||||
.into_error()
|
std::io::ErrorKind::InvalidInput,
|
||||||
.with_message(format!("{:?} is nothing", token))
|
format!("{:?} is nothing", token),
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
if item.offset != 0 {
|
if item.offset != 0 {
|
||||||
return Err(crate::ErrorKind::InvalidWord
|
return Err(std::io::Error::new(
|
||||||
.into_error()
|
std::io::ErrorKind::InvalidInput,
|
||||||
.with_message(format!("{:?} has padding", token)));
|
format!("{:?} has padding", token),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
item.offset += offset;
|
item.offset += offset;
|
||||||
if itr.next().is_some() {
|
if itr.next().is_some() {
|
||||||
return Err(crate::ErrorKind::InvalidWord
|
return Err(std::io::Error::new(
|
||||||
.into_error()
|
std::io::ErrorKind::InvalidInput,
|
||||||
.with_message(format!("{:?} is multiple words", token)));
|
format!("{:?} is multiple words", token),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(item)
|
Ok(item)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ arg_enum! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRINT_SILENT: typos::report::PrintSilent = typos::report::PrintSilent;
|
pub const PRINT_SILENT: typos::report::PrintSilent = typos::report::PrintSilent;
|
||||||
const PRINT_BRIEF: typos::report::PrintBrief = typos::report::PrintBrief;
|
pub const PRINT_BRIEF: typos::report::PrintBrief = typos::report::PrintBrief;
|
||||||
const PRINT_LONG: typos::report::PrintLong = typos::report::PrintLong;
|
pub const PRINT_LONG: typos::report::PrintLong = typos::report::PrintLong;
|
||||||
const PRINT_JSON: typos::report::PrintJson = typos::report::PrintJson;
|
pub const PRINT_JSON: typos::report::PrintJson = typos::report::PrintJson;
|
||||||
|
|
||||||
impl Format {
|
impl Format {
|
||||||
pub(crate) fn reporter(self) -> &'static dyn typos::report::Report {
|
pub(crate) fn reporter(self) -> &'static dyn typos::report::Report {
|
||||||
|
|
|
@ -1,28 +1,14 @@
|
||||||
use std::sync::atomic;
|
|
||||||
|
|
||||||
pub(crate) fn check_path(
|
pub(crate) fn check_path(
|
||||||
walk: ignore::Walk,
|
walk: ignore::Walk,
|
||||||
checks: &dyn typos::checks::Check,
|
checks: &dyn typos::checks::Check,
|
||||||
parser: &typos::tokens::Parser,
|
parser: &typos::tokens::Parser,
|
||||||
dictionary: &dyn typos::Dictionary,
|
dictionary: &dyn typos::Dictionary,
|
||||||
reporter: &dyn typos::report::Report,
|
reporter: &dyn typos::report::Report,
|
||||||
) -> (bool, bool) {
|
) -> Result<(), anyhow::Error> {
|
||||||
let mut typos_found = false;
|
|
||||||
let mut errors_found = false;
|
|
||||||
|
|
||||||
for entry in walk {
|
for entry in walk {
|
||||||
match check_entry(entry, checks, parser, dictionary, reporter) {
|
check_entry(entry, checks, parser, dictionary, reporter)?;
|
||||||
Ok(true) => typos_found = true,
|
|
||||||
Err(err) => {
|
|
||||||
let msg = typos::report::Error::new(err.to_string());
|
|
||||||
reporter.report(msg.into());
|
|
||||||
errors_found = true
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
(typos_found, errors_found)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn check_path_parallel(
|
pub(crate) fn check_path_parallel(
|
||||||
|
@ -31,26 +17,21 @@ pub(crate) fn check_path_parallel(
|
||||||
parser: &typos::tokens::Parser,
|
parser: &typos::tokens::Parser,
|
||||||
dictionary: &dyn typos::Dictionary,
|
dictionary: &dyn typos::Dictionary,
|
||||||
reporter: &dyn typos::report::Report,
|
reporter: &dyn typos::report::Report,
|
||||||
) -> (bool, bool) {
|
) -> Result<(), anyhow::Error> {
|
||||||
let typos_found = atomic::AtomicBool::new(false);
|
let error: std::sync::Mutex<Result<(), anyhow::Error>> = std::sync::Mutex::new(Ok(()));
|
||||||
let errors_found = atomic::AtomicBool::new(false);
|
|
||||||
|
|
||||||
walk.run(|| {
|
walk.run(|| {
|
||||||
Box::new(|entry: Result<ignore::DirEntry, ignore::Error>| {
|
Box::new(|entry: Result<ignore::DirEntry, ignore::Error>| {
|
||||||
match check_entry(entry, checks, parser, dictionary, reporter) {
|
match check_entry(entry, checks, parser, dictionary, reporter) {
|
||||||
Ok(true) => typos_found.store(true, atomic::Ordering::Relaxed),
|
Ok(()) => ignore::WalkState::Continue,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = typos::report::Error::new(err.to_string());
|
*error.lock().unwrap() = Err(err);
|
||||||
reporter.report(msg.into());
|
ignore::WalkState::Quit
|
||||||
errors_found.store(true, atomic::Ordering::Relaxed);
|
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
ignore::WalkState::Continue
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
(typos_found.into_inner(), errors_found.into_inner())
|
error.into_inner().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_entry(
|
fn check_entry(
|
||||||
|
@ -59,19 +40,13 @@ fn check_entry(
|
||||||
parser: &typos::tokens::Parser,
|
parser: &typos::tokens::Parser,
|
||||||
dictionary: &dyn typos::Dictionary,
|
dictionary: &dyn typos::Dictionary,
|
||||||
reporter: &dyn typos::report::Report,
|
reporter: &dyn typos::report::Report,
|
||||||
) -> Result<bool, anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let mut typos_found = false;
|
|
||||||
|
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
if entry.file_type().map(|t| t.is_file()).unwrap_or(true) {
|
if entry.file_type().map(|t| t.is_file()).unwrap_or(true) {
|
||||||
let explicit = entry.depth() == 0;
|
let explicit = entry.depth() == 0;
|
||||||
if checks.check_filename(entry.path(), parser, dictionary, reporter)? {
|
checks.check_filename(entry.path(), parser, dictionary, reporter)?;
|
||||||
typos_found = true;
|
checks.check_file(entry.path(), explicit, parser, dictionary, reporter)?;
|
||||||
}
|
|
||||||
if checks.check_file(entry.path(), explicit, parser, dictionary, reporter)? {
|
|
||||||
typos_found = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(typos_found)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl<'r> Diff<'r> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> typos::report::Report for Diff<'r> {
|
impl<'r> typos::report::Report for Diff<'r> {
|
||||||
fn report(&self, msg: typos::report::Message<'_>) -> bool {
|
fn report(&self, msg: typos::report::Message<'_>) -> Result<(), std::io::Error> {
|
||||||
let typo = match &msg {
|
let typo = match &msg {
|
||||||
typos::report::Message::Typo(typo) => typo,
|
typos::report::Message::Typo(typo) => typo,
|
||||||
_ => return self.reporter.report(msg),
|
_ => return self.reporter.report(msg),
|
||||||
|
@ -85,9 +85,9 @@ impl<'r> typos::report::Report for Diff<'r> {
|
||||||
.entry(line_num)
|
.entry(line_num)
|
||||||
.or_insert_with(Vec::new);
|
.or_insert_with(Vec::new);
|
||||||
content.push(correction);
|
content.push(correction);
|
||||||
false
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => msg.is_correction(),
|
_ => self.reporter.report(msg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
55
src/exit.rs
55
src/exit.rs
|
@ -1,55 +0,0 @@
|
||||||
pub struct ExitCode {
|
|
||||||
pub code: sysexit::Code,
|
|
||||||
pub error: Option<anyhow::Error>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExitCode {
|
|
||||||
pub fn code(code: sysexit::Code) -> Self {
|
|
||||||
Self { code, error: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(mut self, error: anyhow::Error) -> Self {
|
|
||||||
self.error = Some(error);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<sysexit::Code> for ExitCode {
|
|
||||||
fn from(code: sysexit::Code) -> Self {
|
|
||||||
Self::code(code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ChainCodeExt {
|
|
||||||
fn error(self) -> ExitCode;
|
|
||||||
fn chain(self, error: anyhow::Error) -> ExitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChainCodeExt for sysexit::Code {
|
|
||||||
fn error(self) -> ExitCode {
|
|
||||||
ExitCode::code(self)
|
|
||||||
}
|
|
||||||
fn chain(self, error: anyhow::Error) -> ExitCode {
|
|
||||||
ExitCode::code(self).error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ExitCodeResultErrorExt<T> {
|
|
||||||
fn code(self, code: sysexit::Code) -> Result<T, ExitCode>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: std::error::Error + Send + Sync + 'static> ExitCodeResultErrorExt<T> for Result<T, E> {
|
|
||||||
fn code(self, code: sysexit::Code) -> Result<T, ExitCode> {
|
|
||||||
self.map_err(|e| ExitCode::code(code).error(e.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ExitCodeResultAnyhowExt<T> {
|
|
||||||
fn code(self, code: sysexit::Code) -> Result<T, ExitCode>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ExitCodeResultAnyhowExt<T> for Result<T, anyhow::Error> {
|
|
||||||
fn code(self, code: sysexit::Code) -> Result<T, ExitCode> {
|
|
||||||
self.map_err(|e| ExitCode::code(code).error(e))
|
|
||||||
}
|
|
||||||
}
|
|
64
src/main.rs
64
src/main.rs
|
@ -11,35 +11,24 @@ mod checks;
|
||||||
mod config;
|
mod config;
|
||||||
mod dict;
|
mod dict;
|
||||||
mod diff;
|
mod diff;
|
||||||
mod exit;
|
|
||||||
mod replace;
|
mod replace;
|
||||||
|
|
||||||
use exit::ChainCodeExt;
|
use proc_exit::ProcessExitResultExt;
|
||||||
use exit::ExitCodeResultAnyhowExt;
|
use proc_exit::WithCodeResultExt;
|
||||||
use exit::ExitCodeResultErrorExt;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let code = match run() {
|
run().process_exit();
|
||||||
Ok(()) => sysexit::Code::Success,
|
|
||||||
Err(err) => {
|
|
||||||
if let Some(error) = err.error {
|
|
||||||
eprintln!("{}", error);
|
|
||||||
}
|
|
||||||
err.code
|
|
||||||
}
|
|
||||||
};
|
|
||||||
std::process::exit(code as i32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> Result<(), exit::ExitCode> {
|
fn run() -> Result<(), proc_exit::Exit> {
|
||||||
// clap's `get_matches` uses Failure rather than Usage, so bypass it for `get_matches_safe`.
|
// clap's `get_matches` uses Failure rather than Usage, so bypass it for `get_matches_safe`.
|
||||||
let args = match args::Args::from_args_safe() {
|
let args = match args::Args::from_args_safe() {
|
||||||
Ok(args) => args,
|
Ok(args) => args,
|
||||||
Err(e) if e.use_stderr() => {
|
Err(e) if e.use_stderr() => {
|
||||||
return Err(sysexit::Code::Usage.chain(e.into()));
|
return Err(proc_exit::Code::USAGE_ERR.with_message(e));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("{}", e);
|
writeln!(std::io::stdout(), "{}", e)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -47,7 +36,7 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
init_logging(args.verbose.log_level());
|
init_logging(args.verbose.log_level());
|
||||||
|
|
||||||
let config = if let Some(path) = args.custom_config.as_ref() {
|
let config = if let Some(path) = args.custom_config.as_ref() {
|
||||||
config::Config::from_file(path).code(sysexit::Code::Config)?
|
config::Config::from_file(path).with_code(proc_exit::Code::CONFIG_ERR)?
|
||||||
} else {
|
} else {
|
||||||
config::Config::default()
|
config::Config::default()
|
||||||
};
|
};
|
||||||
|
@ -55,7 +44,7 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
let mut typos_found = false;
|
let mut typos_found = false;
|
||||||
let mut errors_found = false;
|
let mut errors_found = false;
|
||||||
for path in args.path.iter() {
|
for path in args.path.iter() {
|
||||||
let path = path.canonicalize().code(sysexit::Code::Usage)?;
|
let path = path.canonicalize().with_code(proc_exit::Code::USAGE_ERR)?;
|
||||||
let cwd = if path.is_file() {
|
let cwd = if path.is_file() {
|
||||||
path.parent().unwrap()
|
path.parent().unwrap()
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,7 +53,7 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
|
|
||||||
let mut config = config.clone();
|
let mut config = config.clone();
|
||||||
if !args.isolated {
|
if !args.isolated {
|
||||||
let derived = config::Config::derive(cwd).code(sysexit::Code::Config)?;
|
let derived = config::Config::derive(cwd).with_code(proc_exit::Code::CONFIG_ERR)?;
|
||||||
config.update(&derived);
|
config.update(&derived);
|
||||||
}
|
}
|
||||||
config.update(&args.config);
|
config.update(&args.config);
|
||||||
|
@ -102,7 +91,14 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
.git_exclude(config.files.ignore_vcs())
|
.git_exclude(config.files.ignore_vcs())
|
||||||
.parents(config.files.ignore_parent());
|
.parents(config.files.ignore_parent());
|
||||||
|
|
||||||
let mut reporter = args.format.reporter();
|
// HACK: Diff doesn't handle mixing content
|
||||||
|
let output_reporter = if args.diff {
|
||||||
|
&args::PRINT_SILENT
|
||||||
|
} else {
|
||||||
|
args.format.reporter()
|
||||||
|
};
|
||||||
|
let status_reporter = typos::report::MessageStatus::new(output_reporter);
|
||||||
|
let mut reporter: &dyn typos::report::Report = &status_reporter;
|
||||||
let replace_reporter = replace::Replace::new(reporter);
|
let replace_reporter = replace::Replace::new(reporter);
|
||||||
let diff_reporter = diff::Diff::new(reporter);
|
let diff_reporter = diff::Diff::new(reporter);
|
||||||
if args.diff {
|
if args.diff {
|
||||||
|
@ -126,7 +122,7 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
&checks
|
&checks
|
||||||
};
|
};
|
||||||
|
|
||||||
let (cur_typos, cur_errors) = if single_threaded {
|
if single_threaded {
|
||||||
checks::check_path(
|
checks::check_path(
|
||||||
walk.build(),
|
walk.build(),
|
||||||
selected_checks,
|
selected_checks,
|
||||||
|
@ -134,6 +130,7 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
&dictionary,
|
&dictionary,
|
||||||
reporter,
|
reporter,
|
||||||
)
|
)
|
||||||
|
.with_code(proc_exit::Code::FAILURE)?;
|
||||||
} else {
|
} else {
|
||||||
checks::check_path_parallel(
|
checks::check_path_parallel(
|
||||||
walk.build_parallel(),
|
walk.build_parallel(),
|
||||||
|
@ -142,27 +139,34 @@ fn run() -> Result<(), exit::ExitCode> {
|
||||||
&dictionary,
|
&dictionary,
|
||||||
reporter,
|
reporter,
|
||||||
)
|
)
|
||||||
};
|
.with_code(proc_exit::Code::FAILURE)?;
|
||||||
if cur_typos {
|
}
|
||||||
|
if status_reporter.typos_found() {
|
||||||
typos_found = true;
|
typos_found = true;
|
||||||
}
|
}
|
||||||
if cur_errors {
|
if status_reporter.errors_found() {
|
||||||
errors_found = true;
|
errors_found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.diff {
|
if args.diff {
|
||||||
diff_reporter.show().code(sysexit::Code::Unknown)?;
|
diff_reporter.show().with_code(proc_exit::Code::FAILURE)?;
|
||||||
} else if args.write_changes {
|
} else if args.write_changes {
|
||||||
replace_reporter.write().code(sysexit::Code::Unknown)?;
|
replace_reporter
|
||||||
|
.write()
|
||||||
|
.with_code(proc_exit::Code::FAILURE)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors_found {
|
if errors_found {
|
||||||
Err(sysexit::Code::Failure.error())
|
proc_exit::Code::FAILURE.ok()
|
||||||
} else if typos_found {
|
} else if typos_found {
|
||||||
Err(sysexit::Code::DataErr.error())
|
// Can;'t use `Failure` since its so prevalent, it could be easy to get a
|
||||||
|
// `Failure` from something else and get it mixed up with typos.
|
||||||
|
//
|
||||||
|
// Can't use DataErr or anything else an std::io::ErrorKind might map to.
|
||||||
|
proc_exit::Code::UNKNOWN.ok()
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
proc_exit::Code::SUCCESS.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ impl<'r> Replace<'r> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> typos::report::Report for Replace<'r> {
|
impl<'r> typos::report::Report for Replace<'r> {
|
||||||
fn report(&self, msg: typos::report::Message<'_>) -> bool {
|
fn report(&self, msg: typos::report::Message<'_>) -> Result<(), std::io::Error> {
|
||||||
let typo = match &msg {
|
let typo = match &msg {
|
||||||
typos::report::Message::Typo(typo) => typo,
|
typos::report::Message::Typo(typo) => typo,
|
||||||
_ => return self.reporter.report(msg),
|
_ => return self.reporter.report(msg),
|
||||||
|
@ -80,7 +80,7 @@ impl<'r> typos::report::Report for Replace<'r> {
|
||||||
.entry(line_num)
|
.entry(line_num)
|
||||||
.or_insert_with(Vec::new);
|
.or_insert_with(Vec::new);
|
||||||
content.push(correction);
|
content.push(correction);
|
||||||
false
|
Ok(())
|
||||||
}
|
}
|
||||||
Some(typos::report::Context::Path(path)) => {
|
Some(typos::report::Context::Path(path)) => {
|
||||||
let path = path.path.to_owned();
|
let path = path.path.to_owned();
|
||||||
|
@ -89,7 +89,7 @@ impl<'r> typos::report::Report for Replace<'r> {
|
||||||
let mut deferred = self.deferred.lock().unwrap();
|
let mut deferred = self.deferred.lock().unwrap();
|
||||||
let content = deferred.paths.entry(path).or_insert_with(Vec::new);
|
let content = deferred.paths.entry(path).or_insert_with(Vec::new);
|
||||||
content.push(correction);
|
content.push(correction);
|
||||||
false
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => self.reporter.report(msg),
|
_ => self.reporter.report(msg),
|
||||||
}
|
}
|
||||||
|
@ -207,22 +207,24 @@ mod test {
|
||||||
|
|
||||||
let primary = typos::report::PrintSilent;
|
let primary = typos::report::PrintSilent;
|
||||||
let replace = Replace::new(&primary);
|
let replace = Replace::new(&primary);
|
||||||
replace.report(
|
replace
|
||||||
typos::report::Typo::default()
|
.report(
|
||||||
.context(Some(
|
typos::report::Typo::default()
|
||||||
typos::report::FileContext::default()
|
.context(Some(
|
||||||
.path(input_file.path())
|
typos::report::FileContext::default()
|
||||||
.line_num(1)
|
.path(input_file.path())
|
||||||
.into(),
|
.line_num(1)
|
||||||
))
|
.into(),
|
||||||
.buffer(std::borrow::Cow::Borrowed(b"1 foo 2\n3 4 5"))
|
))
|
||||||
.byte_offset(2)
|
.buffer(std::borrow::Cow::Borrowed(b"1 foo 2\n3 4 5"))
|
||||||
.typo("foo")
|
.byte_offset(2)
|
||||||
.corrections(typos::Status::Corrections(vec![
|
.typo("foo")
|
||||||
std::borrow::Cow::Borrowed("bar"),
|
.corrections(typos::Status::Corrections(vec![
|
||||||
]))
|
std::borrow::Cow::Borrowed("bar"),
|
||||||
.into(),
|
]))
|
||||||
);
|
.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
replace.write().unwrap();
|
replace.write().unwrap();
|
||||||
|
|
||||||
input_file.assert("1 bar 2\n3 4 5");
|
input_file.assert("1 bar 2\n3 4 5");
|
||||||
|
@ -236,21 +238,23 @@ mod test {
|
||||||
|
|
||||||
let primary = typos::report::PrintSilent;
|
let primary = typos::report::PrintSilent;
|
||||||
let replace = Replace::new(&primary);
|
let replace = Replace::new(&primary);
|
||||||
replace.report(
|
replace
|
||||||
typos::report::Typo::default()
|
.report(
|
||||||
.context(Some(
|
typos::report::Typo::default()
|
||||||
typos::report::PathContext::default()
|
.context(Some(
|
||||||
.path(input_file.path())
|
typos::report::PathContext::default()
|
||||||
.into(),
|
.path(input_file.path())
|
||||||
))
|
.into(),
|
||||||
.buffer(std::borrow::Cow::Borrowed(b"foo.txt"))
|
))
|
||||||
.byte_offset(0)
|
.buffer(std::borrow::Cow::Borrowed(b"foo.txt"))
|
||||||
.typo("foo")
|
.byte_offset(0)
|
||||||
.corrections(typos::Status::Corrections(vec![
|
.typo("foo")
|
||||||
std::borrow::Cow::Borrowed("bar"),
|
.corrections(typos::Status::Corrections(vec![
|
||||||
]))
|
std::borrow::Cow::Borrowed("bar"),
|
||||||
.into(),
|
]))
|
||||||
);
|
.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
replace.write().unwrap();
|
replace.write().unwrap();
|
||||||
|
|
||||||
input_file.assert(predicates::path::missing());
|
input_file.assert(predicates::path::missing());
|
||||||
|
|
Loading…
Reference in a new issue