summaryrefslogtreecommitdiffstats
path: root/crates/cli/src/lib.rs
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2023-09-20 14:42:03 -0400
committerAndrew Gallant <jamslam@gmail.com>2023-09-25 14:39:54 -0400
commit19a08bee8a99e8c725b9781568013a9f686605a3 (patch)
tree24cefa11626735b59072917d0822e90fc0c4417a /crates/cli/src/lib.rs
parent1a50324013708e3c73bfa986d273af2f8e8e3360 (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.rs116
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()
}