diff options
author | Andrew Gallant <jamslam@gmail.com> | 2023-09-20 14:42:03 -0400 |
---|---|---|
committer | Andrew Gallant <jamslam@gmail.com> | 2023-09-25 14:39:54 -0400 |
commit | 19a08bee8a99e8c725b9781568013a9f686605a3 (patch) | |
tree | 24cefa11626735b59072917d0822e90fc0c4417a /crates/cli/src/lib.rs | |
parent | 1a50324013708e3c73bfa986d273af2f8e8e3360 (diff) |
cli: clean-up crate
This does a variety of polishing.
1. Deprecate the tty methods in favor of std's IsTerminal trait.
2. Trim down un-needed dependencies.
3. Use bstr to implement escaping.
4. Various aesthetic polishing.
I'm doing this as prep work before adding more to this crate. And as
part of a general effort toward reducing ripgrep's dependencies.
Diffstat (limited to 'crates/cli/src/lib.rs')
-rw-r--r-- | crates/cli/src/lib.rs | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 53b4d2c3..a16d4c7d 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -11,27 +11,11 @@ and Linux. # Standard I/O -The -[`is_readable_stdin`](fn.is_readable_stdin.html), -[`is_tty_stderr`](fn.is_tty_stderr.html), -[`is_tty_stdin`](fn.is_tty_stdin.html) -and -[`is_tty_stdout`](fn.is_tty_stdout.html) -routines query aspects of standard I/O. `is_readable_stdin` determines whether -stdin can be usefully read from, while the `tty` methods determine whether a -tty is attached to stdin/stdout/stderr. - -`is_readable_stdin` is useful when writing an application that changes behavior -based on whether the application was invoked with data on stdin. For example, -`rg foo` might recursively search the current working directory for -occurrences of `foo`, but `rg foo < file` might only search the contents of -`file`. - -The `tty` methods are useful for similar reasons. Namely, commands like `ls` -will change their output depending on whether they are printing to a terminal -or not. For example, `ls` shows a file on each line when stdout is redirected -to a file or a pipe, but condenses the output to show possibly many files on -each line when stdout is connected to a tty. +[`is_readable_stdin`] determines whether stdin can be usefully read from. It +is useful when writing an application that changes behavior based on whether +the application was invoked with data on stdin. For example, `rg foo` might +recursively search the current working directory for occurrences of `foo`, but +`rg foo < file` might only search the contents of `file`. # Coloring and buffering @@ -165,21 +149,21 @@ mod pattern; mod process; mod wtr; -use std::io::IsTerminal; - -pub use crate::decompress::{ - resolve_binary, DecompressionMatcher, DecompressionMatcherBuilder, - DecompressionReader, DecompressionReaderBuilder, -}; -pub use crate::escape::{escape, escape_os, unescape, unescape_os}; -pub use crate::human::{parse_human_readable_size, ParseSizeError}; -pub use crate::pattern::{ - pattern_from_bytes, pattern_from_os, patterns_from_path, - patterns_from_reader, patterns_from_stdin, InvalidPatternError, -}; -pub use crate::process::{CommandError, CommandReader, CommandReaderBuilder}; -pub use crate::wtr::{ - stdout, stdout_buffered_block, stdout_buffered_line, StandardStream, +pub use crate::{ + decompress::{ + resolve_binary, DecompressionMatcher, DecompressionMatcherBuilder, + DecompressionReader, DecompressionReaderBuilder, + }, + escape::{escape, escape_os, unescape, unescape_os}, + human::{parse_human_readable_size, ParseSizeError}, + pattern::{ + pattern_from_bytes, pattern_from_os, patterns_from_path, + patterns_from_reader, patterns_from_stdin, InvalidPatternError, + }, + process::{CommandError, CommandReader, CommandReaderBuilder}, + wtr::{ + stdout, stdout_buffered_block, stdout_buffered_line, StandardStream, + }, }; /// Returns true if and only if stdin is believed to be readable. @@ -189,34 +173,60 @@ pub use crate::wtr::{ /// might search the current directory for occurrences of `foo` where as /// `command foo < some-file` or `cat some-file | command foo` might instead /// only search stdin for occurrences of `foo`. +/// +/// Note that this isn't perfect and essentially corresponds to a heuristic. +/// When things are unclear (such as if an error occurs during introspection to +/// determine whether stdin is readable), this prefers to return `false`. That +/// means it's possible for an end user to pipe something into your program and +/// have this return `false` and thus potentially lead to ignoring the user's +/// stdin data. While not ideal, this is perhaps better than falsely assuming +/// stdin is readable, which would result in blocking forever on reading stdin. +/// Regardless, commands should always provide explicit fallbacks to override +/// behavior. For example, `rg foo -` will explicitly search stdin and `rg foo +/// ./` will explicitly search the current working directory. pub fn is_readable_stdin() -> bool { + use std::io::IsTerminal; + #[cfg(unix)] fn imp() -> bool { - use same_file::Handle; - use std::os::unix::fs::FileTypeExt; - - let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) { - Err(_) => return false, - Ok(md) => md.file_type(), + use std::{ + fs::File, + os::{fd::AsFd, unix::fs::FileTypeExt}, }; + + let stdin = std::io::stdin(); + let Ok(fd) = stdin.as_fd().try_clone_to_owned() else { return false }; + let file = File::from(fd); + let Ok(md) = file.metadata() else { return false }; + let ft = md.file_type(); ft.is_file() || ft.is_fifo() || ft.is_socket() } #[cfg(windows)] fn imp() -> bool { - use winapi_util as winutil; - - winutil::file::typ(winutil::HandleRef::stdin()) + winapi_util::file::typ(winapi_util::HandleRef::stdin()) .map(|t| t.is_disk() || t.is_pipe()) .unwrap_or(false) } - !is_tty_stdin() && imp() + #[cfg(not(any(unix, windows)))] + fn imp() -> bool { + false + } + + !std::io::stdin().is_terminal() && imp() } /// Returns true if and only if stdin is believed to be connected to a tty /// or a console. +/// +/// Note that this is now just a wrapper around +/// [`std::io::IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html). +/// Callers should prefer using the `IsTerminal` trait directly. This routine +/// is deprecated and will be removed in the next semver incompatible release. +#[deprecated(since = "0.1.10", note = "use std::io::IsTerminal instead")] pub fn is_tty_stdin() -> bool { + use std::io::IsTerminal; std::io::stdin().is_terminal() } @@ -228,12 +238,26 @@ pub fn is_tty_stdin() -> bool { /// terminal or whether it's being redirected somewhere else. For example, /// implementations of `ls` will often show one item per line when stdout is /// redirected, but will condensed output when printing to a tty. +/// +/// Note that this is now just a wrapper around +/// [`std::io::IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html). +/// Callers should prefer using the `IsTerminal` trait directly. This routine +/// is deprecated and will be removed in the next semver incompatible release. +#[deprecated(since = "0.1.10", note = "use std::io::IsTerminal instead")] pub fn is_tty_stdout() -> bool { + use std::io::IsTerminal; std::io::stdout().is_terminal() } /// Returns true if and only if stderr is believed to be connected to a tty /// or a console. +/// +/// Note that this is now just a wrapper around +/// [`std::io::IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html). +/// Callers should prefer using the `IsTerminal` trait directly. This routine +/// is deprecated and will be removed in the next semver incompatible release. +#[deprecated(since = "0.1.10", note = "use std::io::IsTerminal instead")] pub fn is_tty_stderr() -> bool { + use std::io::IsTerminal; std::io::stderr().is_terminal() } |