mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-01 20:52:03 -07:00
Compare commits
21 Commits
0.4.0
...
termcolor-
Author | SHA1 | Date | |
---|---|---|---|
|
a5a16ebb27 | ||
|
8ac5bc0147 | ||
|
cf750a190f | ||
|
d825648b86 | ||
|
22cb644eb6 | ||
|
e424f87487 | ||
|
f5b2c96b77 | ||
|
6e209b6fdb | ||
|
72e3c54e0a | ||
|
b67886264f | ||
|
e67ab459d3 | ||
|
7a926d090d | ||
|
596f94aa7f | ||
|
de55d37bea | ||
|
fecef10c1c | ||
|
79e5e6671f | ||
|
b04a68a782 | ||
|
e573ab5c60 | ||
|
f5a2d022ec | ||
|
b1d1cd2366 | ||
|
f26e0f088f |
@@ -39,6 +39,9 @@ Bug fixes:
|
||||
Fix bug that caused ripgrep's parallel iterator to spin and burn CPU.
|
||||
* [BUG #262](https://github.com/BurntSushi/ripgrep/issues/262):
|
||||
Document how to install shell completion files.
|
||||
* [BUG #266](https://github.com/BurntSushi/ripgrep/issues/266),
|
||||
[BUG #293](https://github.com/BurntSushi/ripgrep/issues/293):
|
||||
Fix handling of bold styling and change the default colors.
|
||||
* [BUG #268](https://github.com/BurntSushi/ripgrep/issues/268):
|
||||
Make lack of backreference support more explicit.
|
||||
* [BUG #271](https://github.com/BurntSushi/ripgrep/issues/271):
|
||||
|
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -2,6 +2,7 @@
|
||||
name = "ripgrep"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -9,7 +10,7 @@ dependencies = [
|
||||
"ignore 0.1.7",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -33,6 +34,16 @@ name = "ansi_term"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
@@ -53,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -85,7 +96,7 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -95,7 +106,6 @@ version = "0.1.3"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -141,7 +151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.19"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -154,7 +164,7 @@ name = "memchr"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -164,7 +174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fs2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -173,7 +183,7 @@ name = "num_cpus"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -200,7 +210,7 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -220,7 +230,7 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -228,7 +238,7 @@ dependencies = [
|
||||
name = "termcolor"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"wincolor 0.1.1",
|
||||
"wincolor 0.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -237,7 +247,7 @@ version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -304,7 +314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wincolor"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -313,6 +323,7 @@ dependencies = [
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f660b942762979b56c9f07b4b36bb559776fbad102f05d6771e1b629e8fd5bf"
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a"
|
||||
"checksum clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95b78f3fe0fc94c13c731714363260e04b557a637166f33a4570d3189d642374"
|
||||
@@ -322,7 +333,7 @@ dependencies = [
|
||||
"checksum fs2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "640001e1bd865c7c32806292822445af576a6866175b5225aa2087ca5e3de551"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
|
||||
"checksum libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e030dc72013ed68994d1b2cbf36a94dd0e58418ba949c4b0db7eeb70a7a6352"
|
||||
"checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
|
||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "065ce59af31c18ea2c419100bda6247dd4ec3099423202b12f0bd32e529fabd2"
|
||||
|
@@ -11,6 +11,7 @@ homepage = "https://github.com/BurntSushi/ripgrep"
|
||||
repository = "https://github.com/BurntSushi/ripgrep"
|
||||
readme = "README.md"
|
||||
keywords = ["regex", "grep", "egrep", "search", "pattern"]
|
||||
categories = ["command-line-utilities", "text-processing"]
|
||||
license = "Unlicense/MIT"
|
||||
exclude = ["HomebrewFormula"]
|
||||
build = "build.rs"
|
||||
@@ -25,6 +26,7 @@ name = "integration"
|
||||
path = "tests/tests.rs"
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.2"
|
||||
bytecount = "0.1.4"
|
||||
clap = "2.19.0"
|
||||
env_logger = { version = "0.3", default-features = false }
|
||||
@@ -40,10 +42,6 @@ regex = "0.2.1"
|
||||
same-file = "0.1.1"
|
||||
termcolor = { version = "0.2.0", path = "termcolor" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
kernel32-sys = "0.2.2"
|
||||
winapi = "0.2.8"
|
||||
|
||||
[build-dependencies]
|
||||
clap = "2.18"
|
||||
lazy_static = "0.2"
|
||||
|
@@ -201,7 +201,8 @@ $ nix-env --install ripgrep
|
||||
$ # (Or using the attribute name, which is also `ripgrep`.)
|
||||
```
|
||||
|
||||
If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`:
|
||||
If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`. Note
|
||||
that this requires you to have **Rust 1.12 or newer** installed.
|
||||
|
||||
```
|
||||
$ cargo install ripgrep
|
||||
|
@@ -21,7 +21,6 @@ bench = false
|
||||
[dependencies]
|
||||
aho-corasick = "0.6.0"
|
||||
fnv = "1.0"
|
||||
lazy_static = "0.2"
|
||||
log = "0.3"
|
||||
memchr = "1"
|
||||
regex = "0.2.1"
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fmt;
|
||||
use std::hash;
|
||||
use std::iter;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::{Path, is_separator};
|
||||
@@ -76,7 +77,7 @@ impl MatchStrategy {
|
||||
///
|
||||
/// It cannot be used directly to match file paths, but it can be converted
|
||||
/// to a regular expression string or a matcher.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq)]
|
||||
pub struct Glob {
|
||||
glob: String,
|
||||
re: String,
|
||||
@@ -84,6 +85,19 @@ pub struct Glob {
|
||||
tokens: Tokens,
|
||||
}
|
||||
|
||||
impl PartialEq for Glob {
|
||||
fn eq(&self, other: &Glob) -> bool {
|
||||
self.glob == other.glob && self.opts == other.opts
|
||||
}
|
||||
}
|
||||
|
||||
impl hash::Hash for Glob {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.glob.hash(state);
|
||||
self.opts.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Glob {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.glob.fmt(f)
|
||||
@@ -173,7 +187,7 @@ pub struct GlobBuilder<'a> {
|
||||
opts: GlobOptions,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
struct GlobOptions {
|
||||
/// Whether to match case insensitively.
|
||||
case_insensitive: bool,
|
||||
|
@@ -101,8 +101,6 @@ or to enable case insensitive matching.
|
||||
extern crate aho_corasick;
|
||||
extern crate fnv;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate memchr;
|
||||
extern crate regex;
|
||||
|
@@ -454,7 +454,7 @@ fn gitconfig_contents() -> Option<Vec<u8>> {
|
||||
fn excludes_file_default() -> Option<PathBuf> {
|
||||
env::var_os("XDG_CONFIG_HOME")
|
||||
.and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) })
|
||||
.or_else(|| env::home_dir())
|
||||
.or_else(|| env::home_dir().map(|p| p.join(".config")))
|
||||
.map(|x| x.join("git/ignore"))
|
||||
}
|
||||
|
||||
|
@@ -103,6 +103,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("awk", &["*.awk"]),
|
||||
("c", &["*.c", "*.h", "*.H"]),
|
||||
("cbor", &["*.cbor"]),
|
||||
("ceylon", &["*.ceylon"]),
|
||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
||||
("cmake", &["*.cmake", "CMakeLists.txt"]),
|
||||
("coffeescript", &["*.coffee"]),
|
||||
@@ -120,7 +121,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("dart", &["*.dart"]),
|
||||
("d", &["*.d"]),
|
||||
("elisp", &["*.el"]),
|
||||
("elixir", &["*.ex", "*.exs"]),
|
||||
("elixir", &["*.ex", "*.eex", "*.exs"]),
|
||||
("erlang", &["*.erl", "*.hrl"]),
|
||||
("fish", &["*.fish"]),
|
||||
("fortran", &[
|
||||
@@ -169,7 +170,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("rst", &["*.rst"]),
|
||||
("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
|
||||
("rust", &["*.rs"]),
|
||||
("sass", &["*.scss"]),
|
||||
("sass", &["*.sass", "*.scss"]),
|
||||
("scala", &["*.scala"]),
|
||||
("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
|
||||
("spark", &["*.spark"]),
|
||||
@@ -185,6 +186,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("ts", &["*.ts", "*.tsx"]),
|
||||
("txt", &["*.txt"]),
|
||||
("toml", &["*.toml", "Cargo.lock"]),
|
||||
("twig", &["*.twig"]),
|
||||
("vala", &["*.vala"]),
|
||||
("vb", &["*.vb"]),
|
||||
("vimscript", &["*.vim"]),
|
||||
|
@@ -1,14 +1,18 @@
|
||||
class RipgrepBin < Formula
|
||||
version '0.3.2'
|
||||
version '0.4.0'
|
||||
desc "Search tool like grep and The Silver Searcher."
|
||||
homepage "https://github.com/BurntSushi/ripgrep"
|
||||
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
|
||||
sha256 "05869abe67104822d29081f12e31e3e90c29cac60ee50546387b17e9be45739c"
|
||||
sha256 "6ac71251909227f8ef7eda27d3080c954843f3665b81e455362c90b2a9c4734a"
|
||||
|
||||
conflicts_with "ripgrep"
|
||||
|
||||
def install
|
||||
bin.install "rg"
|
||||
man1.install "rg.1"
|
||||
|
||||
bash_completion.install "complete/rg.bash-completion"
|
||||
fish_completion.install "complete/rg.fish"
|
||||
zsh_completion.install "complete/_rg"
|
||||
end
|
||||
end
|
||||
|
37
src/args.rs
37
src/args.rs
@@ -182,8 +182,8 @@ impl Args {
|
||||
}
|
||||
|
||||
/// Create a new writer for single-threaded searching with color support.
|
||||
pub fn stdout(&self) -> termcolor::Stdout {
|
||||
termcolor::Stdout::new(self.color_choice)
|
||||
pub fn stdout(&self) -> termcolor::StandardStream {
|
||||
termcolor::StandardStream::stdout(self.color_choice)
|
||||
}
|
||||
|
||||
/// Returns a handle to stdout for filtering search.
|
||||
@@ -394,8 +394,8 @@ impl<'a> ArgMatches<'a> {
|
||||
self.values_of_os("file").map_or(false, |mut files| {
|
||||
files.any(|f| f == "-")
|
||||
});
|
||||
let search_cwd = atty::on_stdin()
|
||||
|| !atty::stdin_is_readable()
|
||||
let search_cwd = atty::is(atty::Stream::Stdin)
|
||||
|| !stdin_is_readable()
|
||||
|| (self.is_present("file") && file_is_stdin)
|
||||
|| self.is_present("files")
|
||||
|| self.is_present("type-list");
|
||||
@@ -584,7 +584,7 @@ impl<'a> ArgMatches<'a> {
|
||||
} else {
|
||||
self.is_present("line-number")
|
||||
|| self.is_present("column")
|
||||
|| atty::on_stdout()
|
||||
|| atty::is(atty::Stream::Stdout)
|
||||
|| self.is_present("pretty")
|
||||
|| self.is_present("vimgrep")
|
||||
}
|
||||
@@ -602,7 +602,7 @@ impl<'a> ArgMatches<'a> {
|
||||
false
|
||||
} else {
|
||||
self.is_present("heading")
|
||||
|| atty::on_stdout()
|
||||
|| atty::is(atty::Stream::Stdout)
|
||||
|| self.is_present("pretty")
|
||||
}
|
||||
}
|
||||
@@ -667,7 +667,7 @@ impl<'a> ArgMatches<'a> {
|
||||
} else if self.is_present("vimgrep") {
|
||||
false
|
||||
} else if preference == "auto" {
|
||||
atty::on_stdout() || self.is_present("pretty")
|
||||
atty::is(atty::Stream::Stdout) || self.is_present("pretty")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -687,7 +687,7 @@ impl<'a> ArgMatches<'a> {
|
||||
} else if self.is_present("vimgrep") {
|
||||
termcolor::ColorChoice::Never
|
||||
} else if preference == "auto" {
|
||||
if atty::on_stdout() || self.is_present("pretty") {
|
||||
if atty::is(atty::Stream::Stdout) || self.is_present("pretty") {
|
||||
termcolor::ColorChoice::Auto
|
||||
} else {
|
||||
termcolor::ColorChoice::Never
|
||||
@@ -869,3 +869,24 @@ impl QuietMatched {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if and only if stdin is deemed searchable.
|
||||
#[cfg(unix)]
|
||||
fn stdin_is_readable() -> bool {
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use same_file::Handle;
|
||||
|
||||
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
||||
Err(_) => return false,
|
||||
Ok(md) => md.file_type(),
|
||||
};
|
||||
ft.is_file() || ft.is_fifo()
|
||||
}
|
||||
|
||||
/// Returns true if and only if stdin is deemed searchable.
|
||||
#[cfg(windows)]
|
||||
fn stdin_is_readable() -> bool {
|
||||
// On Windows, it's not clear what the possibilities are to me, so just
|
||||
// always return true.
|
||||
true
|
||||
}
|
||||
|
145
src/atty.rs
145
src/atty.rs
@@ -1,145 +0,0 @@
|
||||
/*!
|
||||
This atty module contains functions for detecting whether ripgrep is being fed
|
||||
from (or to) a terminal. Windows and Unix do this differently, so implement
|
||||
both here.
|
||||
*/
|
||||
|
||||
#[cfg(windows)]
|
||||
use winapi::minwindef::DWORD;
|
||||
#[cfg(windows)]
|
||||
use winapi::winnt::HANDLE;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn stdin_is_readable() -> bool {
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use same_file::Handle;
|
||||
|
||||
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
||||
Err(_) => return false,
|
||||
Ok(md) => md.file_type(),
|
||||
};
|
||||
ft.is_file() || ft.is_fifo()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn stdin_is_readable() -> bool {
|
||||
// ???
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns true if there is a tty on stdin.
|
||||
#[cfg(unix)]
|
||||
pub fn on_stdin() -> bool {
|
||||
use libc;
|
||||
0 < unsafe { libc::isatty(libc::STDIN_FILENO) }
|
||||
}
|
||||
|
||||
/// Returns true if there is a tty on stdout.
|
||||
#[cfg(unix)]
|
||||
pub fn on_stdout() -> bool {
|
||||
use libc;
|
||||
0 < unsafe { libc::isatty(libc::STDOUT_FILENO) }
|
||||
}
|
||||
|
||||
/// Returns true if there is a tty on stdin.
|
||||
#[cfg(windows)]
|
||||
pub fn on_stdin() -> bool {
|
||||
use kernel32::GetStdHandle;
|
||||
use winapi::winbase::{
|
||||
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if console_on_handle(stdin) {
|
||||
// False positives aren't possible. If we got a console then
|
||||
// we definitely have a tty on stdin.
|
||||
return true;
|
||||
}
|
||||
// Otherwise, it's possible to get a false negative. If we know that
|
||||
// there's a console on stdout or stderr however, then this is a true
|
||||
// negative.
|
||||
if console_on_fd(STD_OUTPUT_HANDLE)
|
||||
|| console_on_fd(STD_ERROR_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
// Otherwise, we can't really tell, so we do a weird hack.
|
||||
msys_tty_on_handle(stdin)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if there is a tty on stdout.
|
||||
#[cfg(windows)]
|
||||
pub fn on_stdout() -> bool {
|
||||
use kernel32::GetStdHandle;
|
||||
use winapi::winbase::{
|
||||
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if console_on_handle(stdout) {
|
||||
// False positives aren't possible. If we got a console then
|
||||
// we definitely have a tty on stdout.
|
||||
return true;
|
||||
}
|
||||
// Otherwise, it's possible to get a false negative. If we know that
|
||||
// there's a console on stdin or stderr however, then this is a true
|
||||
// negative.
|
||||
if console_on_fd(STD_INPUT_HANDLE) || console_on_fd(STD_ERROR_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
// Otherwise, we can't really tell, so we do a weird hack.
|
||||
msys_tty_on_handle(stdout)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if there is an MSYS tty on the given handle.
|
||||
#[cfg(windows)]
|
||||
unsafe fn msys_tty_on_handle(handle: HANDLE) -> bool {
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::slice;
|
||||
|
||||
use kernel32::{GetFileInformationByHandleEx};
|
||||
use winapi::fileapi::FILE_NAME_INFO;
|
||||
use winapi::minwinbase::FileNameInfo;
|
||||
use winapi::minwindef::MAX_PATH;
|
||||
|
||||
let size = mem::size_of::<FILE_NAME_INFO>();
|
||||
let mut name_info_bytes = vec![0u8; size + MAX_PATH];
|
||||
let res = GetFileInformationByHandleEx(
|
||||
handle,
|
||||
FileNameInfo,
|
||||
&mut *name_info_bytes as *mut _ as *mut c_void,
|
||||
name_info_bytes.len() as u32);
|
||||
if res == 0 {
|
||||
return true;
|
||||
}
|
||||
let name_info: FILE_NAME_INFO =
|
||||
*(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
|
||||
let name_bytes =
|
||||
&name_info_bytes[size..size + name_info.FileNameLength as usize];
|
||||
let name_u16 = slice::from_raw_parts(
|
||||
name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
|
||||
let name = OsString::from_wide(name_u16)
|
||||
.as_os_str().to_string_lossy().into_owned();
|
||||
name.contains("msys-") || name.contains("-pty")
|
||||
}
|
||||
|
||||
/// Returns true if there is a console on the given file descriptor.
|
||||
#[cfg(windows)]
|
||||
unsafe fn console_on_fd(fd: DWORD) -> bool {
|
||||
use kernel32::GetStdHandle;
|
||||
console_on_handle(GetStdHandle(fd))
|
||||
}
|
||||
|
||||
/// Returns true if there is a console on the given handle.
|
||||
#[cfg(windows)]
|
||||
unsafe fn console_on_handle(handle: HANDLE) -> bool {
|
||||
use kernel32::GetConsoleMode;
|
||||
let mut out = 0;
|
||||
GetConsoleMode(handle, &mut out) != 0
|
||||
}
|
@@ -1,11 +1,10 @@
|
||||
extern crate atty;
|
||||
extern crate bytecount;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate env_logger;
|
||||
extern crate grep;
|
||||
extern crate ignore;
|
||||
#[cfg(windows)]
|
||||
extern crate kernel32;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate libc;
|
||||
@@ -17,8 +16,6 @@ extern crate num_cpus;
|
||||
extern crate regex;
|
||||
extern crate same_file;
|
||||
extern crate termcolor;
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
|
||||
use std::error::Error;
|
||||
use std::process;
|
||||
@@ -46,7 +43,6 @@ macro_rules! eprintln {
|
||||
|
||||
mod app;
|
||||
mod args;
|
||||
mod atty;
|
||||
mod pathutil;
|
||||
mod printer;
|
||||
mod search_buffer;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "termcolor"
|
||||
version = "0.2.0" #:version
|
||||
version = "0.3.0" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
A simple cross platform library for writing colored text to a terminal.
|
||||
|
@@ -39,12 +39,13 @@ extern crate termcolor;
|
||||
The `WriteColor` trait extends the `io::Write` trait with methods for setting
|
||||
colors or resetting them.
|
||||
|
||||
`Stdout` and `StdoutLock` both satisfy `WriteColor` and are analogous to
|
||||
`std::io::Stdout` and `std::io::StdoutLock`.
|
||||
`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
|
||||
analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr`
|
||||
and `std::io::StderrLock`.
|
||||
|
||||
`Buffer` is an in memory buffer that supports colored text. In a parallel
|
||||
program, each thread might write to its own buffer. A buffer can be printed
|
||||
to stdout using a `BufferWriter`. The advantage of this design is that
|
||||
program, each thread might write to its own buffer. A buffer can be printed to
|
||||
stdout or stderr using a `BufferWriter`. The advantage of this design is that
|
||||
each thread can work in parallel on a buffer without having to synchronize
|
||||
access to global resources such as the Windows console. Moreover, this design
|
||||
also prevents interleaving of buffer output.
|
||||
@@ -53,34 +54,34 @@ also prevents interleaving of buffer output.
|
||||
`io::Write`. These types are useful when you know exactly what you need. An
|
||||
analogous type for the Windows console is not provided since it cannot exist.
|
||||
|
||||
### Example: using `Stdout`
|
||||
### Example: using `StandardStream`
|
||||
|
||||
The `Stdout` type in this crate works similarly to `std::io::Stdout`, except
|
||||
it is augmented with methods for coloring by the `WriteColor` trait. For
|
||||
example, to write some green text:
|
||||
The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
|
||||
except it is augmented with methods for coloring by the `WriteColor` trait.
|
||||
For example, to write some green text:
|
||||
|
||||
```rust
|
||||
use std::io::Write;
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, Stdout, WriteColor};
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||
|
||||
let mut stdout = Stdout::new(ColorChoice::Always);
|
||||
let mut stdout = StandardStream::stdout(ColorChoice::Always);
|
||||
try!(stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
|
||||
try!(writeln!(&mut stdout, "green text!"));
|
||||
```
|
||||
|
||||
### Example: using `BufferWriter`
|
||||
|
||||
A `BufferWriter` can create buffers and write buffers to stdout. It does *not*
|
||||
implement `io::Write` or `WriteColor` itself. Instead, `Buffer` implements
|
||||
`io::Write` and `io::WriteColor`.
|
||||
A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
|
||||
does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
|
||||
implements `io::Write` and `io::WriteColor`.
|
||||
|
||||
This example shows how to print some green text to stdout.
|
||||
This example shows how to print some green text to stderr.
|
||||
|
||||
```rust
|
||||
use std::io::Write;
|
||||
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
|
||||
|
||||
let mut bufwtr = BufferWriter::stdout(ColorChoice::Always);
|
||||
let mut bufwtr = BufferWriter::stderr(ColorChoice::Always);
|
||||
let mut buffer = bufwtr.buffer();
|
||||
try!(buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
|
||||
try!(writeln!(&mut buffer, "green text!"));
|
||||
|
@@ -15,32 +15,33 @@ Windows console API, which requires synchronous communication.
|
||||
The `WriteColor` trait extends the `io::Write` trait with methods for setting
|
||||
colors or resetting them.
|
||||
|
||||
`Stdout` and `StdoutLock` both satisfy `WriteColor` and are analogous to
|
||||
`std::io::Stdout` and `std::io::StdoutLock`.
|
||||
`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
|
||||
analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr`
|
||||
and `std::io::StderrLock`.
|
||||
|
||||
`Buffer` is an in memory buffer that supports colored text. In a parallel
|
||||
program, each thread might write to its own buffer. A buffer can be printed
|
||||
to stdout using a `BufferWriter`. The advantage of this design is that
|
||||
each thread can work in parallel on a buffer without having to synchronize
|
||||
access to global resources such as the Windows console. Moreover, this design
|
||||
also prevents interleaving of buffer output.
|
||||
program, each thread might write to its own buffer. A buffer can be printed to
|
||||
using a `BufferWriter`. The advantage of this design is that each thread can
|
||||
work in parallel on a buffer without having to synchronize access to global
|
||||
resources such as the Windows console. Moreover, this design also prevents
|
||||
interleaving of buffer output.
|
||||
|
||||
`Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of
|
||||
`io::Write`. These types are useful when you know exactly what you need. An
|
||||
analogous type for the Windows console is not provided since it cannot exist.
|
||||
|
||||
# Example: using `Stdout`
|
||||
# Example: using `StandardStream`
|
||||
|
||||
The `Stdout` type in this crate works similarly to `std::io::Stdout`, except
|
||||
it is augmented with methods for coloring by the `WriteColor` trait. For
|
||||
example, to write some green text:
|
||||
The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
|
||||
except it is augmented with methods for coloring by the `WriteColor` trait.
|
||||
For example, to write some green text:
|
||||
|
||||
```rust,no_run
|
||||
# fn test() -> Result<(), Box<::std::error::Error>> {
|
||||
use std::io::Write;
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, Stdout, WriteColor};
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||
|
||||
let mut stdout = Stdout::new(ColorChoice::Always);
|
||||
let mut stdout = StandardStream::stdout(ColorChoice::Always);
|
||||
try!(stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
|
||||
try!(writeln!(&mut stdout, "green text!"));
|
||||
# Ok(()) }
|
||||
@@ -48,18 +49,18 @@ try!(writeln!(&mut stdout, "green text!"));
|
||||
|
||||
# Example: using `BufferWriter`
|
||||
|
||||
A `BufferWriter` can create buffers and write buffers to stdout. It does *not*
|
||||
implement `io::Write` or `WriteColor` itself. Instead, `Buffer` implements
|
||||
`io::Write` and `io::WriteColor`.
|
||||
A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
|
||||
does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
|
||||
implements `io::Write` and `io::WriteColor`.
|
||||
|
||||
This example shows how to print some green text to stdout.
|
||||
This example shows how to print some green text to stderr.
|
||||
|
||||
```rust,no_run
|
||||
# fn test() -> Result<(), Box<::std::error::Error>> {
|
||||
use std::io::Write;
|
||||
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
|
||||
|
||||
let mut bufwtr = BufferWriter::stdout(ColorChoice::Always);
|
||||
let mut bufwtr = BufferWriter::stderr(ColorChoice::Always);
|
||||
let mut buffer = bufwtr.buffer();
|
||||
try!(buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
|
||||
try!(writeln!(&mut buffer, "green text!"));
|
||||
@@ -184,20 +185,89 @@ impl ColorChoice {
|
||||
}
|
||||
}
|
||||
|
||||
/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
|
||||
/// to stdout.
|
||||
pub struct Stdout {
|
||||
wtr: LossyStdout<WriterInner<'static, io::Stdout>>,
|
||||
/// `std::io` implements `Stdout` and `Stderr` (and their `Lock` variants) as
|
||||
/// separate types, which makes it difficult to abstract over them. We use
|
||||
/// some simple internal enum types to work around this.
|
||||
|
||||
enum StandardStreamType {
|
||||
Stdout,
|
||||
Stderr,
|
||||
}
|
||||
|
||||
/// `StdoutLock` is a locked reference to a `Stdout`.
|
||||
enum IoStandardStream {
|
||||
Stdout(io::Stdout),
|
||||
Stderr(io::Stderr),
|
||||
}
|
||||
|
||||
impl IoStandardStream {
|
||||
fn new(sty: StandardStreamType) -> IoStandardStream {
|
||||
match sty {
|
||||
StandardStreamType::Stdout => IoStandardStream::Stdout(io::stdout()),
|
||||
StandardStreamType::Stderr => IoStandardStream::Stderr(io::stderr()),
|
||||
}
|
||||
}
|
||||
|
||||
fn lock(&self) -> IoStandardStreamLock {
|
||||
match *self {
|
||||
IoStandardStream::Stdout(ref s) => IoStandardStreamLock::StdoutLock(s.lock()),
|
||||
IoStandardStream::Stderr(ref s) => IoStandardStreamLock::StderrLock(s.lock()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for IoStandardStream {
|
||||
fn write(&mut self, b: &[u8]) -> io::Result<usize> {
|
||||
match *self {
|
||||
IoStandardStream::Stdout(ref mut s) => s.write(b),
|
||||
IoStandardStream::Stderr(ref mut s) => s.write(b),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
IoStandardStream::Stdout(ref mut s) => s.flush(),
|
||||
IoStandardStream::Stderr(ref mut s) => s.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Same rigamorale for the locked variants of the standard streams.
|
||||
|
||||
enum IoStandardStreamLock<'a> {
|
||||
StdoutLock(io::StdoutLock<'a>),
|
||||
StderrLock(io::StderrLock<'a>),
|
||||
}
|
||||
|
||||
impl<'a> io::Write for IoStandardStreamLock<'a> {
|
||||
fn write(&mut self, b: &[u8]) -> io::Result<usize> {
|
||||
match *self {
|
||||
IoStandardStreamLock::StdoutLock(ref mut s) => s.write(b),
|
||||
IoStandardStreamLock::StderrLock(ref mut s) => s.write(b),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
IoStandardStreamLock::StdoutLock(ref mut s) => s.flush(),
|
||||
IoStandardStreamLock::StderrLock(ref mut s) => s.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
|
||||
/// to either of the standard output streams, stdout and stderr.
|
||||
pub struct StandardStream {
|
||||
wtr: LossyStandardStream<WriterInner<'static, IoStandardStream>>,
|
||||
}
|
||||
|
||||
/// `StandardStreamLock` is a locked reference to a `StandardStream`.
|
||||
///
|
||||
/// This implements the `io::Write` and `WriteColor` traits, and is constructed
|
||||
/// via the `Write::lock` method.
|
||||
///
|
||||
/// The lifetime `'a` refers to the lifetime of the corresponding `Stdout`.
|
||||
pub struct StdoutLock<'a> {
|
||||
wtr: LossyStdout<WriterInner<'a, io::StdoutLock<'a>>>,
|
||||
/// The lifetime `'a` refers to the lifetime of the corresponding `StandardStream`.
|
||||
pub struct StandardStreamLock<'a> {
|
||||
wtr: LossyStandardStream<WriterInner<'a, IoStandardStreamLock<'a>>>,
|
||||
}
|
||||
|
||||
/// WriterInner is a (limited) generic representation of a writer. It is
|
||||
@@ -217,23 +287,23 @@ enum WriterInner<'a, W> {
|
||||
WindowsLocked { wtr: W, console: MutexGuard<'a, wincolor::Console> },
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
/// Create a new `Stdout` with the given color preferences.
|
||||
impl StandardStream {
|
||||
/// Create a new `StandardStream` with the given color preferences.
|
||||
///
|
||||
/// The specific color/style settings can be configured when writing via
|
||||
/// the `WriteColor` trait.
|
||||
#[cfg(not(windows))]
|
||||
pub fn new(choice: ColorChoice) -> Stdout {
|
||||
fn create(sty: StandardStreamType, choice: ColorChoice) -> StandardStream {
|
||||
let wtr =
|
||||
if choice.should_attempt_color() {
|
||||
WriterInner::Ansi(Ansi(io::stdout()))
|
||||
WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
|
||||
} else {
|
||||
WriterInner::NoColor(NoColor(io::stdout()))
|
||||
WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
|
||||
};
|
||||
Stdout { wtr: LossyStdout::new(wtr) }
|
||||
StandardStream { wtr: LossyStandardStream::new(wtr) }
|
||||
}
|
||||
|
||||
/// Create a new `Stdout` with the given color preferences.
|
||||
/// Create a new `StandardStream` with the given color preferences.
|
||||
///
|
||||
/// If coloring is desired and a Windows console could not be found, then
|
||||
/// ANSI escape sequences are used instead.
|
||||
@@ -241,25 +311,52 @@ impl Stdout {
|
||||
/// The specific color/style settings can be configured when writing via
|
||||
/// the `WriteColor` trait.
|
||||
#[cfg(windows)]
|
||||
pub fn new(choice: ColorChoice) -> Stdout {
|
||||
let con = wincolor::Console::stdout();
|
||||
fn create(sty: StandardStreamType, choice: ColorChoice) -> StandardStream {
|
||||
let con = match sty {
|
||||
StandardStreamType::Stdout => wincolor::Console::stdout(),
|
||||
StandardStreamType::Stderr => wincolor::Console::stderr(),
|
||||
};
|
||||
let is_win_console = con.is_ok();
|
||||
let wtr =
|
||||
if choice.should_attempt_color() {
|
||||
if choice.should_ansi() {
|
||||
WriterInner::Ansi(Ansi(io::stdout()))
|
||||
WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
|
||||
} else if let Ok(console) = con {
|
||||
WriterInner::Windows {
|
||||
wtr: io::stdout(),
|
||||
wtr: IoStandardStream::new(sty),
|
||||
console: Mutex::new(console),
|
||||
}
|
||||
} else {
|
||||
WriterInner::Ansi(Ansi(io::stdout()))
|
||||
WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
|
||||
}
|
||||
} else {
|
||||
WriterInner::NoColor(NoColor(io::stdout()))
|
||||
WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
|
||||
};
|
||||
Stdout { wtr: LossyStdout::new(wtr).is_console(is_win_console) }
|
||||
StandardStream { wtr: LossyStandardStream::new(wtr).is_console(is_win_console) }
|
||||
}
|
||||
|
||||
/// Create a new `StandardStream` with the given color preferences that
|
||||
/// writes to standard output.
|
||||
///
|
||||
/// On Windows, if coloring is desired and a Windows console could not be
|
||||
/// found, then ANSI escape sequences are used instead.
|
||||
///
|
||||
/// The specific color/style settings can be configured when writing via
|
||||
/// the `WriteColor` trait.
|
||||
pub fn stdout(choice: ColorChoice) -> StandardStream {
|
||||
StandardStream::create(StandardStreamType::Stdout, choice)
|
||||
}
|
||||
|
||||
/// Create a new `StandardStream` with the given color preferences that
|
||||
/// writes to standard error.
|
||||
///
|
||||
/// On Windows, if coloring is desired and a Windows console could not be
|
||||
/// found, then ANSI escape sequences are used instead.
|
||||
///
|
||||
/// The specific color/style settings can be configured when writing via
|
||||
/// the `WriteColor` trait.
|
||||
pub fn stderr(choice: ColorChoice) -> StandardStream {
|
||||
StandardStream::create(StandardStreamType::Stderr, choice)
|
||||
}
|
||||
|
||||
/// Lock the underlying writer.
|
||||
@@ -268,16 +365,16 @@ impl Stdout {
|
||||
/// `WriteColor`.
|
||||
///
|
||||
/// This method is **not reentrant**. It may panic if `lock` is called
|
||||
/// while a `StdoutLock` is still alive.
|
||||
pub fn lock(&self) -> StdoutLock {
|
||||
StdoutLock::from_stdout(self)
|
||||
/// while a `StandardStreamLock` is still alive.
|
||||
pub fn lock(&self) -> StandardStreamLock {
|
||||
StandardStreamLock::from_stream(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> StdoutLock<'a> {
|
||||
impl<'a> StandardStreamLock<'a> {
|
||||
#[cfg(not(windows))]
|
||||
fn from_stdout(stdout: &Stdout) -> StdoutLock {
|
||||
let locked = match *stdout.wtr.get_ref() {
|
||||
fn from_stream(stream: &StandardStream) -> StandardStreamLock {
|
||||
let locked = match *stream.wtr.get_ref() {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref w) => {
|
||||
WriterInner::NoColor(NoColor(w.0.lock()))
|
||||
@@ -286,12 +383,12 @@ impl<'a> StdoutLock<'a> {
|
||||
WriterInner::Ansi(Ansi(w.0.lock()))
|
||||
}
|
||||
};
|
||||
StdoutLock { wtr: stdout.wtr.wrap(locked) }
|
||||
StandardStreamLock { wtr: stream.wtr.wrap(locked) }
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn from_stdout(stdout: &Stdout) -> StdoutLock {
|
||||
let locked = match *stdout.wtr.get_ref() {
|
||||
fn from_stream(stream: &StandardStream) -> StandardStreamLock {
|
||||
let locked = match *stream.wtr.get_ref() {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref w) => {
|
||||
WriterInner::NoColor(NoColor(w.0.lock()))
|
||||
@@ -308,19 +405,19 @@ impl<'a> StdoutLock<'a> {
|
||||
}
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked{..} => {
|
||||
panic!("cannot call Stdout.lock while a StdoutLock is alive");
|
||||
panic!("cannot call StandardStream.lock while a StandardStreamLock is alive");
|
||||
}
|
||||
};
|
||||
StdoutLock { wtr: stdout.wtr.wrap(locked) }
|
||||
StandardStreamLock { wtr: stream.wtr.wrap(locked) }
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for Stdout {
|
||||
impl io::Write for StandardStream {
|
||||
fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
|
||||
fn flush(&mut self) -> io::Result<()> { self.wtr.flush() }
|
||||
}
|
||||
|
||||
impl WriteColor for Stdout {
|
||||
impl WriteColor for StandardStream {
|
||||
fn supports_color(&self) -> bool { self.wtr.supports_color() }
|
||||
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
self.wtr.set_color(spec)
|
||||
@@ -328,12 +425,12 @@ impl WriteColor for Stdout {
|
||||
fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
|
||||
}
|
||||
|
||||
impl<'a> io::Write for StdoutLock<'a> {
|
||||
impl<'a> io::Write for StandardStreamLock<'a> {
|
||||
fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
|
||||
fn flush(&mut self) -> io::Result<()> { self.wtr.flush() }
|
||||
}
|
||||
|
||||
impl<'a> WriteColor for StdoutLock<'a> {
|
||||
impl<'a> WriteColor for StandardStreamLock<'a> {
|
||||
fn supports_color(&self) -> bool { self.wtr.supports_color() }
|
||||
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
self.wtr.set_color(spec)
|
||||
@@ -420,7 +517,7 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes colored buffers to stdout.
|
||||
/// Writes colored buffers to stdout or stderr.
|
||||
///
|
||||
/// Writable buffers can be obtained by calling `buffer` on a `BufferWriter`.
|
||||
///
|
||||
@@ -430,7 +527,7 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
|
||||
/// It is intended for a `BufferWriter` to be put in an `Arc` and written to
|
||||
/// from multiple threads simultaneously.
|
||||
pub struct BufferWriter {
|
||||
stdout: LossyStdout<io::Stdout>,
|
||||
stream: LossyStandardStream<IoStandardStream>,
|
||||
printed: AtomicBool,
|
||||
separator: Option<Vec<u8>>,
|
||||
color_choice: ColorChoice,
|
||||
@@ -439,23 +536,23 @@ pub struct BufferWriter {
|
||||
}
|
||||
|
||||
impl BufferWriter {
|
||||
/// Create a new `BufferWriter` that writes to stdout with the given
|
||||
/// color preferences.
|
||||
/// Create a new `BufferWriter` that writes to a standard stream with the
|
||||
/// given color preferences.
|
||||
///
|
||||
/// The specific color/style settings can be configured when writing to
|
||||
/// the buffers themselves.
|
||||
#[cfg(not(windows))]
|
||||
pub fn stdout(choice: ColorChoice) -> BufferWriter {
|
||||
fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
|
||||
BufferWriter {
|
||||
stdout: LossyStdout::new(io::stdout()),
|
||||
stream: LossyStandardStream::new(IoStandardStream::new(sty)),
|
||||
printed: AtomicBool::new(false),
|
||||
separator: None,
|
||||
color_choice: choice,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `BufferWriter` that writes to stdout with the given
|
||||
/// color preferences.
|
||||
/// Create a new `BufferWriter` that writes to a standard stream with the
|
||||
/// given color preferences.
|
||||
///
|
||||
/// If coloring is desired and a Windows console could not be found, then
|
||||
/// ANSI escape sequences are used instead.
|
||||
@@ -463,11 +560,14 @@ impl BufferWriter {
|
||||
/// The specific color/style settings can be configured when writing to
|
||||
/// the buffers themselves.
|
||||
#[cfg(windows)]
|
||||
pub fn stdout(choice: ColorChoice) -> BufferWriter {
|
||||
let con = wincolor::Console::stdout().ok().map(Mutex::new);
|
||||
let stdout = LossyStdout::new(io::stdout()).is_console(con.is_some());
|
||||
fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
|
||||
let con = match sty {
|
||||
StandardStreamType::Stdout => wincolor::Console::stdout(),
|
||||
StandardStreamType::Stderr => wincolor::Console::stderr(),
|
||||
}.ok().map(Mutex::new);
|
||||
let stream = LossyStandardStream::new(IoStandardStream::new(sty)).is_console(con.is_some());
|
||||
BufferWriter {
|
||||
stdout: stdout,
|
||||
stream: stream,
|
||||
printed: AtomicBool::new(false),
|
||||
separator: None,
|
||||
color_choice: choice,
|
||||
@@ -475,6 +575,30 @@ impl BufferWriter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `BufferWriter` that writes to stdout with the given
|
||||
/// color preferences.
|
||||
///
|
||||
/// On Windows, if coloring is desired and a Windows console could not be
|
||||
/// found, then ANSI escape sequences are used instead.
|
||||
///
|
||||
/// The specific color/style settings can be configured when writing to
|
||||
/// the buffers themselves.
|
||||
pub fn stdout(choice: ColorChoice) -> BufferWriter {
|
||||
BufferWriter::create(StandardStreamType::Stdout, choice)
|
||||
}
|
||||
|
||||
/// Create a new `BufferWriter` that writes to stderr with the given
|
||||
/// color preferences.
|
||||
///
|
||||
/// On Windows, if coloring is desired and a Windows console could not be
|
||||
/// found, then ANSI escape sequences are used instead.
|
||||
///
|
||||
/// The specific color/style settings can be configured when writing to
|
||||
/// the buffers themselves.
|
||||
pub fn stderr(choice: ColorChoice) -> BufferWriter {
|
||||
BufferWriter::create(StandardStreamType::Stderr, choice)
|
||||
}
|
||||
|
||||
/// If set, the separator given is printed between buffers. By default, no
|
||||
/// separator is printed.
|
||||
///
|
||||
@@ -510,16 +634,16 @@ impl BufferWriter {
|
||||
if buf.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut stdout = self.stdout.wrap(self.stdout.get_ref().lock());
|
||||
let mut stream = self.stream.wrap(self.stream.get_ref().lock());
|
||||
if let Some(ref sep) = self.separator {
|
||||
if self.printed.load(Ordering::SeqCst) {
|
||||
try!(stdout.write_all(sep));
|
||||
try!(stdout.write_all(b"\n"));
|
||||
try!(stream.write_all(sep));
|
||||
try!(stream.write_all(b"\n"));
|
||||
}
|
||||
}
|
||||
match buf.0 {
|
||||
BufferInner::NoColor(ref b) => try!(stdout.write_all(&b.0)),
|
||||
BufferInner::Ansi(ref b) => try!(stdout.write_all(&b.0)),
|
||||
BufferInner::NoColor(ref b) => try!(stream.write_all(&b.0)),
|
||||
BufferInner::Ansi(ref b) => try!(stream.write_all(&b.0)),
|
||||
#[cfg(windows)]
|
||||
BufferInner::Windows(ref b) => {
|
||||
// We guarantee by construction that we have a console here.
|
||||
@@ -527,7 +651,7 @@ impl BufferWriter {
|
||||
let console_mutex = self.console.as_ref()
|
||||
.expect("got Windows buffer but have no Console");
|
||||
let mut console = console_mutex.lock().unwrap();
|
||||
try!(b.print(&mut *console, &mut stdout));
|
||||
try!(b.print(&mut *console, &mut stream));
|
||||
}
|
||||
}
|
||||
self.printed.store(true, Ordering::SeqCst);
|
||||
@@ -905,25 +1029,25 @@ impl WindowsBuffer {
|
||||
self.colors.push((pos, spec));
|
||||
}
|
||||
|
||||
/// Print the contents to the given stdout handle, and use the console
|
||||
/// Print the contents to the given stream handle, and use the console
|
||||
/// for coloring.
|
||||
fn print(
|
||||
&self,
|
||||
console: &mut wincolor::Console,
|
||||
stdout: &mut LossyStdout<io::StdoutLock>,
|
||||
stream: &mut LossyStandardStream<IoStandardStreamLock>,
|
||||
) -> io::Result<()> {
|
||||
let mut last = 0;
|
||||
for &(pos, ref spec) in &self.colors {
|
||||
try!(stdout.write_all(&self.buf[last..pos]));
|
||||
try!(stdout.flush());
|
||||
try!(stream.write_all(&self.buf[last..pos]));
|
||||
try!(stream.flush());
|
||||
last = pos;
|
||||
match *spec {
|
||||
None => try!(console.reset()),
|
||||
Some(ref spec) => try!(spec.write_console(console)),
|
||||
}
|
||||
}
|
||||
try!(stdout.write_all(&self.buf[last..]));
|
||||
stdout.flush()
|
||||
try!(stream.write_all(&self.buf[last..]));
|
||||
stream.flush()
|
||||
}
|
||||
|
||||
/// Clear the buffer.
|
||||
@@ -1121,33 +1245,33 @@ impl FromStr for Color {
|
||||
}
|
||||
}
|
||||
|
||||
struct LossyStdout<W> {
|
||||
struct LossyStandardStream<W> {
|
||||
wtr: W,
|
||||
#[cfg(windows)]
|
||||
is_console: bool,
|
||||
}
|
||||
|
||||
impl<W: io::Write> LossyStdout<W> {
|
||||
impl<W: io::Write> LossyStandardStream<W> {
|
||||
#[cfg(not(windows))]
|
||||
fn new(wtr: W) -> LossyStdout<W> { LossyStdout { wtr: wtr } }
|
||||
fn new(wtr: W) -> LossyStandardStream<W> { LossyStandardStream { wtr: wtr } }
|
||||
|
||||
#[cfg(windows)]
|
||||
fn new(wtr: W) -> LossyStdout<W> {
|
||||
LossyStdout { wtr: wtr, is_console: false }
|
||||
fn new(wtr: W) -> LossyStandardStream<W> {
|
||||
LossyStandardStream { wtr: wtr, is_console: false }
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStdout<Q> {
|
||||
LossyStdout::new(wtr)
|
||||
fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
|
||||
LossyStandardStream::new(wtr)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStdout<Q> {
|
||||
LossyStdout::new(wtr).is_console(self.is_console)
|
||||
fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
|
||||
LossyStandardStream::new(wtr).is_console(self.is_console)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_console(mut self, yes: bool) -> LossyStdout<W> {
|
||||
fn is_console(mut self, yes: bool) -> LossyStandardStream<W> {
|
||||
self.is_console = yes;
|
||||
self
|
||||
}
|
||||
@@ -1157,7 +1281,7 @@ impl<W: io::Write> LossyStdout<W> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: WriteColor> WriteColor for LossyStdout<W> {
|
||||
impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
|
||||
fn supports_color(&self) -> bool { self.wtr.supports_color() }
|
||||
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
self.wtr.set_color(spec)
|
||||
@@ -1165,7 +1289,7 @@ impl<W: WriteColor> WriteColor for LossyStdout<W> {
|
||||
fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
|
||||
}
|
||||
|
||||
impl<W: io::Write> io::Write for LossyStdout<W> {
|
||||
impl<W: io::Write> io::Write for LossyStandardStream<W> {
|
||||
#[cfg(not(windows))]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.wtr.write(buf)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wincolor"
|
||||
version = "0.1.1" #:version
|
||||
version = "0.1.2" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
A simple Windows specific API for controlling text color in a Windows console.
|
||||
|
@@ -3,7 +3,7 @@ use std::mem;
|
||||
|
||||
use kernel32;
|
||||
use winapi::{DWORD, HANDLE, WORD};
|
||||
use winapi::winbase::STD_OUTPUT_HANDLE;
|
||||
use winapi::winbase::{STD_ERROR_HANDLE, STD_OUTPUT_HANDLE};
|
||||
use winapi::wincon::{
|
||||
FOREGROUND_BLUE as FG_BLUE,
|
||||
FOREGROUND_GREEN as FG_GREEN,
|
||||
@@ -44,13 +44,11 @@ impl Drop for Console {
|
||||
}
|
||||
|
||||
impl Console {
|
||||
/// Create a new Console to stdout.
|
||||
///
|
||||
/// If there was a problem creating the console, then an error is returned.
|
||||
pub fn stdout() -> io::Result<Console> {
|
||||
/// Get a console for a standard I/O stream.
|
||||
fn create_for_stream(handle_id: DWORD) -> io::Result<Console> {
|
||||
let mut info = unsafe { mem::zeroed() };
|
||||
let (handle, res) = unsafe {
|
||||
let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
let handle = kernel32::GetStdHandle(handle_id);
|
||||
(handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
|
||||
};
|
||||
if res == 0 {
|
||||
@@ -64,6 +62,20 @@ impl Console {
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new Console to stdout.
|
||||
///
|
||||
/// If there was a problem creating the console, then an error is returned.
|
||||
pub fn stdout() -> io::Result<Console> {
|
||||
Self::create_for_stream(STD_OUTPUT_HANDLE)
|
||||
}
|
||||
|
||||
/// Create a new Console to stderr.
|
||||
///
|
||||
/// If there was a problem creating the console, then an error is returned.
|
||||
pub fn stderr() -> io::Result<Console> {
|
||||
Self::create_for_stream(STD_ERROR_HANDLE)
|
||||
}
|
||||
|
||||
/// Applies the current text attributes.
|
||||
fn set(&mut self) -> io::Result<()> {
|
||||
let attr = self.cur_attr.to_word();
|
||||
|
Reference in New Issue
Block a user