Skip to content

Commit

Permalink
chore: add --stdin-paths and -stdin-paths0
Browse files Browse the repository at this point in the history
  • Loading branch information
dpc committed Aug 27, 2023
1 parent ca8ac80 commit 04059e0
Show file tree
Hide file tree
Showing 17 changed files with 157 additions and 6 deletions.
8 changes: 6 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/typos-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ colorchoice-clap = "1.0.0"
serde_regex = "1.1.0"
regex = "1.8.3"
encoding_rs = "0.8.32"
os_str_bytes = "6.5.1"

[dev-dependencies]
assert_fs = "1.0"
Expand Down
16 changes: 15 additions & 1 deletion crates/typos-cli/src/bin/typos-cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,17 @@ impl Default for Format {
#[command(group = clap::ArgGroup::new("mode").multiple(false))]
pub(crate) struct Args {
/// Paths to check with `-` for stdin
#[arg(default_value = ".")]
#[arg(default_value = ".", group = "source")]
pub(crate) path: Vec<std::path::PathBuf>,

/// Read the list of newline separated paths from stdin
#[arg(long, group = "source")]
pub(crate) stdin_paths: bool,

/// Read the list of '\0' separated paths from stdin
#[arg(long, group = "source")]
pub(crate) stdin_paths0: bool,

/// Custom config file
#[arg(short = 'c', long = "config")]
pub(crate) custom_config: Option<std::path::PathBuf>,
Expand Down Expand Up @@ -104,6 +112,12 @@ pub(crate) struct Args {
pub(crate) verbose: clap_verbosity_flag::Verbosity,
}

impl Args {
pub fn is_using_stdin_paths(&self) -> bool {
self.stdin_paths || self.stdin_paths0
}
}

#[derive(Debug, Clone, clap::Args)]
#[command(rename_all = "kebab-case")]
pub(crate) struct FileArgs {
Expand Down
69 changes: 67 additions & 2 deletions crates/typos-cli/src/bin/typos-cli/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::io::Write;
use std::ffi::OsString;
use std::io::{Read as _, Write as _};
use std::path::PathBuf;

use clap::Parser;

Expand Down Expand Up @@ -161,8 +163,29 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {

let mut typos_found = false;
let mut errors_found = false;
for path in args.path.iter() {

let stdin_paths = if args.stdin_paths {
Some(
std::io::stdin()
.lines()
.map(|res| res.map(PathBuf::from))
.collect::<Result<_, _>>()
.with_code(proc_exit::sysexits::IO_ERR)?,
)
} else if args.stdin_paths0 {
Some(unix_read_paths_from_stdin()?)
} else {
None
};

// Note: stdin_paths and args.path are mutually exclusive, enforced by clap
for path in stdin_paths.as_ref().unwrap_or(&args.path) {
// Note paths are passed through stdin, `-` is treated like a normal path
let cwd = if path == std::path::Path::new("-") {
if args.is_using_stdin_paths() {
return Err(proc_exit::sysexits::USAGE_ERR
.with_message("Can't use `-` (stdin) while using stdin provided paths"));
};
global_cwd.clone()
} else if path.is_file() {
let mut cwd = path
Expand Down Expand Up @@ -282,6 +305,48 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
}
}

#[cfg(target_family = "unix")]
fn os_str_from_bytes(bytes: Vec<u8>) -> Result<OsString, proc_exit::Exit> {
use std::os::unix::ffi::OsStringExt;

Ok(OsString::from_vec(bytes))
}

#[cfg(not(target_family = "unix"))]
fn os_str_from_bytes(bytes: Vec<u8>) -> Result<OsString, proc_exit::Exit> {
use os_str_bytes::RawOsString;

Ok(RawOsString::from_raw_vec(bytes).map_err(|_e| {
proc_exit::sysexits::USAGE_ERR
.with_message("Invalid encoding")?
.into_os_string()
}))
}

fn unix_read_paths_from_stdin() -> Result<Vec<PathBuf>, proc_exit::Exit> {
let mut buf = Vec::new();
std::io::stdin()
.read_to_end(&mut buf)
.with_code(proc_exit::sysexits::IO_ERR)?;

let (mut paths, rest) = buf.into_iter().try_fold(
(vec![], vec![]),
|(mut paths, mut cur_path): (Vec<PathBuf>, Vec<u8>), byte| {
if byte == 0 {
paths.push(PathBuf::from(os_str_from_bytes(cur_path)?));
Ok((paths, vec![]))
} else {
cur_path.push(byte);
Ok((paths, cur_path))
}
},
)?;
if !rest.is_empty() {
paths.push(PathBuf::from(os_str_from_bytes(rest)?));
}
Ok(paths)
}

fn init_logging(level: Option<log::Level>) {
if let Some(level) = level {
let mut builder = env_logger::Builder::new();
Expand Down
4 changes: 3 additions & 1 deletion crates/typos-cli/tests/cli_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#[test]
#[cfg(feature = "dict")]
fn cli_tests() {
trycmd::TestCases::new().case("tests/cmd/*.toml");
trycmd::TestCases::new()
.case("tests/cmd/*.toml")
.case("tests/cmd/*.trycmd");
}
8 changes: 8 additions & 0 deletions crates/typos-cli/tests/cmd/stdin-paths.in/_typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[files]
extend-exclude = ["_typos.toml"]

[default.extend-identifiers]
hello = "goodbye"

[type.fail]
extend-glob = ["*.fail"]
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths.in/a.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths.in/b.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths.in/c.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths.in/d.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
22 changes: 22 additions & 0 deletions crates/typos-cli/tests/cmd/stdin-paths.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
bin.name = "typos"
args = "--stdin-paths"
stdin = """
b.fail
d.fail
"""
stdout = """
error: `hello` should be `goodbye`
--> b.fail:1:1
|
1 | hello
| ^^^^^
|
error: `hello` should be `goodbye`
--> d.fail:1:1
|
1 | hello
| ^^^^^
|
"""
stderr = ""
status.code = 2
8 changes: 8 additions & 0 deletions crates/typos-cli/tests/cmd/stdin-paths0.in/_typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[files]
extend-exclude = ["_typos.toml"]

[default.extend-identifiers]
hello = "goodbye"

[type.fail]
extend-glob = ["*.fail"]
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths0.in/a.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths0.in/b.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths0.in/c.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
1 change: 1 addition & 0 deletions crates/typos-cli/tests/cmd/stdin-paths0.in/d.fail
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
19 changes: 19 additions & 0 deletions crates/typos-cli/tests/cmd/stdin-paths0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
bin.name = "typos"
args = "--stdin-paths0"
stdin = "b.fail\u0000c.fail"
stdout = """
error: `hello` should be `goodbye`
--> b.fail:1:1
|
1 | hello
| ^^^^^
|
error: `hello` should be `goodbye`
--> c.fail:1:1
|
1 | hello
| ^^^^^
|
"""
stderr = ""
status.code = 2

0 comments on commit 04059e0

Please sign in to comment.