Compare commits

...

21 Commits

Author SHA1 Message Date
Andrew Gallant
a5a16ebb27 termcolor-0.3.0 2017-02-18 15:07:43 -05:00
Andrew Gallant
8ac5bc0147 Remove Windows deps from ripgrep proper.
All Windows specific code has been (mostly) pushed out of ripgrep and
into its constituent libraries.
2017-02-18 15:06:20 -05:00
Stu Hood
cf750a190f Implement Hash for Glob, and re-implement PartialEq using only non-redundant fields. 2017-02-18 11:46:03 -05:00
Andrew Gallant
d825648b86 Remove lazy_static from globset 2017-02-12 15:37:50 -05:00
Peter Williams
22cb644eb6 termcolor: add support for output to standard error
This is essentially a rename of the existing `Stdout` type to `StandardStream`
and a change of its constructor from a single `new()` function to have two
`stdout()` and `stderr()` functions.

Under the hood, we add add internal IoStandardStream{,Lock} enums that allow
us to abstract between Stdout and Stderr conveniently. The rest of the needed
changes then fall out fairly naturally.

Fixes #324.

[breaking-change]
2017-02-09 20:57:23 -05:00
Ahmed El Gabri
e424f87487 Add .twig as a Filetype 2017-02-09 15:12:48 -05:00
Samuel Colvin
f5b2c96b77 add '*.sass' to sass type 2017-01-31 07:26:25 -05:00
Daniel Hahler
6e209b6fdb Look for global git/ignore in ~/.config/git, not ~/git
The documentation says:

> If `$XDG_CONFIG_HOME` is not set or is empty, then
> `$HOME/.config/git/ignore` is used instead.

This is the expected behavior, but the code looked at ~/git/ignore
instead.
2017-01-30 16:58:58 -05:00
Alexander Altman
72e3c54e0a Add Ceylon file type filtering 2017-01-24 07:16:53 -05:00
Andrew Gallant
b67886264f Add 'text-processing' category. 2017-01-21 11:31:09 -05:00
Jake Goulding
e67ab459d3 Add categories to Cargo.toml 2017-01-20 14:20:28 -05:00
David Stangl
7a926d090d Fix homebrew formula 2017-01-19 08:33:54 -05:00
Tareq A Khandaker
596f94aa7f Add shell completion files to ripgrep-bin.rb 2017-01-18 18:39:11 -05:00
robi-wan
de55d37bea File Types: Add .eex under Elixir
.eex is the default file ending for templates using Elixir's template engine EEx.
2017-01-18 18:38:53 -05:00
Andrew Gallant
fecef10c1c update deps 2017-01-17 19:36:23 -05:00
Andrew Gallant
79e5e6671f wincolor-0.1.2 2017-01-17 19:34:48 -05:00
Andrew Gallant
b04a68a782 Update 0.4.0 changelog.
It was missing a change about colors/styles.

Fixes #330
2017-01-17 19:34:18 -05:00
Peter Williams
e573ab5c60 Add stderr support to wincolor. 2017-01-17 10:42:35 -05:00
Andrew Gallant
f5a2d022ec Replace internal atty module with atty crate.
This removes all use of explicit unsafe in ripgrep proper except for
one: accessing the contents of a memory map. (Which may never go away.)
2017-01-15 16:32:30 -05:00
Andrew Gallant
b1d1cd2366 note minimum Rust version 2017-01-14 08:51:30 -05:00
Andrew Gallant
f26e0f088f update brew tap 2017-01-14 00:05:05 -05:00
18 changed files with 340 additions and 301 deletions

View File

@@ -39,6 +39,9 @@ Bug fixes:
Fix bug that caused ripgrep's parallel iterator to spin and burn CPU. Fix bug that caused ripgrep's parallel iterator to spin and burn CPU.
* [BUG #262](https://github.com/BurntSushi/ripgrep/issues/262): * [BUG #262](https://github.com/BurntSushi/ripgrep/issues/262):
Document how to install shell completion files. 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): * [BUG #268](https://github.com/BurntSushi/ripgrep/issues/268):
Make lack of backreference support more explicit. Make lack of backreference support more explicit.
* [BUG #271](https://github.com/BurntSushi/ripgrep/issues/271): * [BUG #271](https://github.com/BurntSushi/ripgrep/issues/271):

39
Cargo.lock generated
View File

@@ -2,6 +2,7 @@
name = "ripgrep" name = "ripgrep"
version = "0.4.0" version = "0.4.0"
dependencies = [ 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)", "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)", "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)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -9,7 +10,7 @@ dependencies = [
"ignore 0.1.7", "ignore 0.1.7",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -33,6 +34,16 @@ name = "ansi_term"
version = "0.9.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "bitflags" name = "bitflags"
version = "0.7.0" version = "0.7.0"
@@ -53,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (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)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -95,7 +106,6 @@ version = "0.1.3"
dependencies = [ dependencies = [
"aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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]] [[package]]
name = "libc" name = "libc"
version = "0.2.19" version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -154,7 +164,7 @@ name = "memchr"
version = "1.0.1" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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]] [[package]]
@@ -164,7 +174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"fs2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -173,7 +183,7 @@ name = "num_cpus"
version = "1.2.1" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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]] [[package]]
@@ -200,7 +210,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (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)", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (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)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -228,7 +238,7 @@ dependencies = [
name = "termcolor" name = "termcolor"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"wincolor 0.1.1", "wincolor 0.1.2",
] ]
[[package]] [[package]]
@@ -237,7 +247,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (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)",
] ]
[[package]] [[package]]
@@ -304,7 +314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "wincolor" name = "wincolor"
version = "0.1.1" version = "0.1.2"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -313,6 +323,7 @@ dependencies = [
[metadata] [metadata]
"checksum aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f660b942762979b56c9f07b4b36bb559776fbad102f05d6771e1b629e8fd5bf" "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 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 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 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" "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 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 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 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 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 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" "checksum memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "065ce59af31c18ea2c419100bda6247dd4ec3099423202b12f0bd32e529fabd2"

View File

@@ -11,6 +11,7 @@ homepage = "https://github.com/BurntSushi/ripgrep"
repository = "https://github.com/BurntSushi/ripgrep" repository = "https://github.com/BurntSushi/ripgrep"
readme = "README.md" readme = "README.md"
keywords = ["regex", "grep", "egrep", "search", "pattern"] keywords = ["regex", "grep", "egrep", "search", "pattern"]
categories = ["command-line-utilities", "text-processing"]
license = "Unlicense/MIT" license = "Unlicense/MIT"
exclude = ["HomebrewFormula"] exclude = ["HomebrewFormula"]
build = "build.rs" build = "build.rs"
@@ -25,6 +26,7 @@ name = "integration"
path = "tests/tests.rs" path = "tests/tests.rs"
[dependencies] [dependencies]
atty = "0.2.2"
bytecount = "0.1.4" bytecount = "0.1.4"
clap = "2.19.0" clap = "2.19.0"
env_logger = { version = "0.3", default-features = false } env_logger = { version = "0.3", default-features = false }
@@ -40,10 +42,6 @@ regex = "0.2.1"
same-file = "0.1.1" same-file = "0.1.1"
termcolor = { version = "0.2.0", path = "termcolor" } termcolor = { version = "0.2.0", path = "termcolor" }
[target.'cfg(windows)'.dependencies]
kernel32-sys = "0.2.2"
winapi = "0.2.8"
[build-dependencies] [build-dependencies]
clap = "2.18" clap = "2.18"
lazy_static = "0.2" lazy_static = "0.2"

View File

@@ -201,7 +201,8 @@ $ nix-env --install ripgrep
$ # (Or using the attribute name, which is also `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 $ cargo install ripgrep

View File

@@ -21,7 +21,6 @@ bench = false
[dependencies] [dependencies]
aho-corasick = "0.6.0" aho-corasick = "0.6.0"
fnv = "1.0" fnv = "1.0"
lazy_static = "0.2"
log = "0.3" log = "0.3"
memchr = "1" memchr = "1"
regex = "0.2.1" regex = "0.2.1"

View File

@@ -1,5 +1,6 @@
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::fmt; use std::fmt;
use std::hash;
use std::iter; use std::iter;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::{Path, is_separator}; 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 /// It cannot be used directly to match file paths, but it can be converted
/// to a regular expression string or a matcher. /// to a regular expression string or a matcher.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq)]
pub struct Glob { pub struct Glob {
glob: String, glob: String,
re: String, re: String,
@@ -84,6 +85,19 @@ pub struct Glob {
tokens: Tokens, 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 { impl fmt::Display for Glob {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.glob.fmt(f) self.glob.fmt(f)
@@ -173,7 +187,7 @@ pub struct GlobBuilder<'a> {
opts: GlobOptions, opts: GlobOptions,
} }
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
struct GlobOptions { struct GlobOptions {
/// Whether to match case insensitively. /// Whether to match case insensitively.
case_insensitive: bool, case_insensitive: bool,

View File

@@ -101,8 +101,6 @@ or to enable case insensitive matching.
extern crate aho_corasick; extern crate aho_corasick;
extern crate fnv; extern crate fnv;
#[macro_use] #[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log; extern crate log;
extern crate memchr; extern crate memchr;
extern crate regex; extern crate regex;

View File

@@ -454,7 +454,7 @@ fn gitconfig_contents() -> Option<Vec<u8>> {
fn excludes_file_default() -> Option<PathBuf> { fn excludes_file_default() -> Option<PathBuf> {
env::var_os("XDG_CONFIG_HOME") env::var_os("XDG_CONFIG_HOME")
.and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) }) .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")) .map(|x| x.join("git/ignore"))
} }

View File

@@ -103,6 +103,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("awk", &["*.awk"]), ("awk", &["*.awk"]),
("c", &["*.c", "*.h", "*.H"]), ("c", &["*.c", "*.h", "*.H"]),
("cbor", &["*.cbor"]), ("cbor", &["*.cbor"]),
("ceylon", &["*.ceylon"]),
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]), ("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
("cmake", &["*.cmake", "CMakeLists.txt"]), ("cmake", &["*.cmake", "CMakeLists.txt"]),
("coffeescript", &["*.coffee"]), ("coffeescript", &["*.coffee"]),
@@ -120,7 +121,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("dart", &["*.dart"]), ("dart", &["*.dart"]),
("d", &["*.d"]), ("d", &["*.d"]),
("elisp", &["*.el"]), ("elisp", &["*.el"]),
("elixir", &["*.ex", "*.exs"]), ("elixir", &["*.ex", "*.eex", "*.exs"]),
("erlang", &["*.erl", "*.hrl"]), ("erlang", &["*.erl", "*.hrl"]),
("fish", &["*.fish"]), ("fish", &["*.fish"]),
("fortran", &[ ("fortran", &[
@@ -169,7 +170,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("rst", &["*.rst"]), ("rst", &["*.rst"]),
("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]), ("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
("rust", &["*.rs"]), ("rust", &["*.rs"]),
("sass", &["*.scss"]), ("sass", &["*.sass", "*.scss"]),
("scala", &["*.scala"]), ("scala", &["*.scala"]),
("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]), ("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
("spark", &["*.spark"]), ("spark", &["*.spark"]),
@@ -185,6 +186,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("ts", &["*.ts", "*.tsx"]), ("ts", &["*.ts", "*.tsx"]),
("txt", &["*.txt"]), ("txt", &["*.txt"]),
("toml", &["*.toml", "Cargo.lock"]), ("toml", &["*.toml", "Cargo.lock"]),
("twig", &["*.twig"]),
("vala", &["*.vala"]), ("vala", &["*.vala"]),
("vb", &["*.vb"]), ("vb", &["*.vb"]),
("vimscript", &["*.vim"]), ("vimscript", &["*.vim"]),

View File

@@ -1,14 +1,18 @@
class RipgrepBin < Formula class RipgrepBin < Formula
version '0.3.2' version '0.4.0'
desc "Search tool like grep and The Silver Searcher." desc "Search tool like grep and The Silver Searcher."
homepage "https://github.com/BurntSushi/ripgrep" homepage "https://github.com/BurntSushi/ripgrep"
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz" url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
sha256 "05869abe67104822d29081f12e31e3e90c29cac60ee50546387b17e9be45739c" sha256 "6ac71251909227f8ef7eda27d3080c954843f3665b81e455362c90b2a9c4734a"
conflicts_with "ripgrep" conflicts_with "ripgrep"
def install def install
bin.install "rg" bin.install "rg"
man1.install "rg.1" man1.install "rg.1"
bash_completion.install "complete/rg.bash-completion"
fish_completion.install "complete/rg.fish"
zsh_completion.install "complete/_rg"
end end
end end

View File

@@ -182,8 +182,8 @@ impl Args {
} }
/// Create a new writer for single-threaded searching with color support. /// Create a new writer for single-threaded searching with color support.
pub fn stdout(&self) -> termcolor::Stdout { pub fn stdout(&self) -> termcolor::StandardStream {
termcolor::Stdout::new(self.color_choice) termcolor::StandardStream::stdout(self.color_choice)
} }
/// Returns a handle to stdout for filtering search. /// 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| { self.values_of_os("file").map_or(false, |mut files| {
files.any(|f| f == "-") files.any(|f| f == "-")
}); });
let search_cwd = atty::on_stdin() let search_cwd = atty::is(atty::Stream::Stdin)
|| !atty::stdin_is_readable() || !stdin_is_readable()
|| (self.is_present("file") && file_is_stdin) || (self.is_present("file") && file_is_stdin)
|| self.is_present("files") || self.is_present("files")
|| self.is_present("type-list"); || self.is_present("type-list");
@@ -584,7 +584,7 @@ impl<'a> ArgMatches<'a> {
} else { } else {
self.is_present("line-number") self.is_present("line-number")
|| self.is_present("column") || self.is_present("column")
|| atty::on_stdout() || atty::is(atty::Stream::Stdout)
|| self.is_present("pretty") || self.is_present("pretty")
|| self.is_present("vimgrep") || self.is_present("vimgrep")
} }
@@ -602,7 +602,7 @@ impl<'a> ArgMatches<'a> {
false false
} else { } else {
self.is_present("heading") self.is_present("heading")
|| atty::on_stdout() || atty::is(atty::Stream::Stdout)
|| self.is_present("pretty") || self.is_present("pretty")
} }
} }
@@ -667,7 +667,7 @@ impl<'a> ArgMatches<'a> {
} else if self.is_present("vimgrep") { } else if self.is_present("vimgrep") {
false false
} else if preference == "auto" { } else if preference == "auto" {
atty::on_stdout() || self.is_present("pretty") atty::is(atty::Stream::Stdout) || self.is_present("pretty")
} else { } else {
false false
} }
@@ -687,7 +687,7 @@ impl<'a> ArgMatches<'a> {
} else if self.is_present("vimgrep") { } else if self.is_present("vimgrep") {
termcolor::ColorChoice::Never termcolor::ColorChoice::Never
} else if preference == "auto" { } 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 termcolor::ColorChoice::Auto
} else { } else {
termcolor::ColorChoice::Never 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
}

View File

@@ -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
}

View File

@@ -1,11 +1,10 @@
extern crate atty;
extern crate bytecount; extern crate bytecount;
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
extern crate env_logger; extern crate env_logger;
extern crate grep; extern crate grep;
extern crate ignore; extern crate ignore;
#[cfg(windows)]
extern crate kernel32;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate libc; extern crate libc;
@@ -17,8 +16,6 @@ extern crate num_cpus;
extern crate regex; extern crate regex;
extern crate same_file; extern crate same_file;
extern crate termcolor; extern crate termcolor;
#[cfg(windows)]
extern crate winapi;
use std::error::Error; use std::error::Error;
use std::process; use std::process;
@@ -46,7 +43,6 @@ macro_rules! eprintln {
mod app; mod app;
mod args; mod args;
mod atty;
mod pathutil; mod pathutil;
mod printer; mod printer;
mod search_buffer; mod search_buffer;

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "termcolor" name = "termcolor"
version = "0.2.0" #:version version = "0.3.0" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
A simple cross platform library for writing colored text to a terminal. A simple cross platform library for writing colored text to a terminal.

View File

@@ -39,12 +39,13 @@ extern crate termcolor;
The `WriteColor` trait extends the `io::Write` trait with methods for setting The `WriteColor` trait extends the `io::Write` trait with methods for setting
colors or resetting them. colors or resetting them.
`Stdout` and `StdoutLock` both satisfy `WriteColor` and are analogous to `StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
`std::io::Stdout` and `std::io::StdoutLock`. 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 `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 program, each thread might write to its own buffer. A buffer can be printed to
to stdout using a `BufferWriter`. The advantage of this design is that 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 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 access to global resources such as the Windows console. Moreover, this design
also prevents interleaving of buffer output. 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 `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. 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 The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
it is augmented with methods for coloring by the `WriteColor` trait. For except it is augmented with methods for coloring by the `WriteColor` trait.
example, to write some green text: For example, to write some green text:
```rust ```rust
use std::io::Write; 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!(stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
try!(writeln!(&mut stdout, "green text!")); try!(writeln!(&mut stdout, "green text!"));
``` ```
### Example: using `BufferWriter` ### Example: using `BufferWriter`
A `BufferWriter` can create buffers and write buffers to stdout. It does *not* A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
implement `io::Write` or `WriteColor` itself. Instead, `Buffer` implements does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
`io::Write` and `io::WriteColor`. 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 ```rust
use std::io::Write; use std::io::Write;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; 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(); let mut buffer = bufwtr.buffer();
try!(buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))); try!(buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
try!(writeln!(&mut buffer, "green text!")); try!(writeln!(&mut buffer, "green text!"));

View File

@@ -15,32 +15,33 @@ Windows console API, which requires synchronous communication.
The `WriteColor` trait extends the `io::Write` trait with methods for setting The `WriteColor` trait extends the `io::Write` trait with methods for setting
colors or resetting them. colors or resetting them.
`Stdout` and `StdoutLock` both satisfy `WriteColor` and are analogous to `StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
`std::io::Stdout` and `std::io::StdoutLock`. 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 `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 program, each thread might write to its own buffer. A buffer can be printed to
to stdout using a `BufferWriter`. The advantage of this design is that using a `BufferWriter`. The advantage of this design is that each thread can
each thread can work in parallel on a buffer without having to synchronize work in parallel on a buffer without having to synchronize access to global
access to global resources such as the Windows console. Moreover, this design resources such as the Windows console. Moreover, this design also prevents
also prevents interleaving of buffer output. interleaving of buffer output.
`Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of `Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of
`io::Write`. These types are useful when you know exactly what you need. An `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. 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 The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
it is augmented with methods for coloring by the `WriteColor` trait. For except it is augmented with methods for coloring by the `WriteColor` trait.
example, to write some green text: For example, to write some green text:
```rust,no_run ```rust,no_run
# fn test() -> Result<(), Box<::std::error::Error>> { # fn test() -> Result<(), Box<::std::error::Error>> {
use std::io::Write; 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!(stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
try!(writeln!(&mut stdout, "green text!")); try!(writeln!(&mut stdout, "green text!"));
# Ok(()) } # Ok(()) }
@@ -48,18 +49,18 @@ try!(writeln!(&mut stdout, "green text!"));
# Example: using `BufferWriter` # Example: using `BufferWriter`
A `BufferWriter` can create buffers and write buffers to stdout. It does *not* A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
implement `io::Write` or `WriteColor` itself. Instead, `Buffer` implements does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
`io::Write` and `io::WriteColor`. 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 ```rust,no_run
# fn test() -> Result<(), Box<::std::error::Error>> { # fn test() -> Result<(), Box<::std::error::Error>> {
use std::io::Write; use std::io::Write;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; 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(); let mut buffer = bufwtr.buffer();
try!(buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))); try!(buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green))));
try!(writeln!(&mut buffer, "green text!")); try!(writeln!(&mut buffer, "green text!"));
@@ -184,20 +185,89 @@ impl ColorChoice {
} }
} }
/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring /// `std::io` implements `Stdout` and `Stderr` (and their `Lock` variants) as
/// to stdout. /// separate types, which makes it difficult to abstract over them. We use
pub struct Stdout { /// some simple internal enum types to work around this.
wtr: LossyStdout<WriterInner<'static, io::Stdout>>,
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 /// This implements the `io::Write` and `WriteColor` traits, and is constructed
/// via the `Write::lock` method. /// via the `Write::lock` method.
/// ///
/// The lifetime `'a` refers to the lifetime of the corresponding `Stdout`. /// The lifetime `'a` refers to the lifetime of the corresponding `StandardStream`.
pub struct StdoutLock<'a> { pub struct StandardStreamLock<'a> {
wtr: LossyStdout<WriterInner<'a, io::StdoutLock<'a>>>, wtr: LossyStandardStream<WriterInner<'a, IoStandardStreamLock<'a>>>,
} }
/// WriterInner is a (limited) generic representation of a writer. It is /// 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> }, WindowsLocked { wtr: W, console: MutexGuard<'a, wincolor::Console> },
} }
impl Stdout { impl StandardStream {
/// Create a new `Stdout` with the given color preferences. /// Create a new `StandardStream` with the given color preferences.
/// ///
/// The specific color/style settings can be configured when writing via /// The specific color/style settings can be configured when writing via
/// the `WriteColor` trait. /// the `WriteColor` trait.
#[cfg(not(windows))] #[cfg(not(windows))]
pub fn new(choice: ColorChoice) -> Stdout { fn create(sty: StandardStreamType, choice: ColorChoice) -> StandardStream {
let wtr = let wtr =
if choice.should_attempt_color() { if choice.should_attempt_color() {
WriterInner::Ansi(Ansi(io::stdout())) WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
} else { } 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 /// If coloring is desired and a Windows console could not be found, then
/// ANSI escape sequences are used instead. /// ANSI escape sequences are used instead.
@@ -241,25 +311,52 @@ impl Stdout {
/// The specific color/style settings can be configured when writing via /// The specific color/style settings can be configured when writing via
/// the `WriteColor` trait. /// the `WriteColor` trait.
#[cfg(windows)] #[cfg(windows)]
pub fn new(choice: ColorChoice) -> Stdout { fn create(sty: StandardStreamType, choice: ColorChoice) -> StandardStream {
let con = wincolor::Console::stdout(); let con = match sty {
StandardStreamType::Stdout => wincolor::Console::stdout(),
StandardStreamType::Stderr => wincolor::Console::stderr(),
};
let is_win_console = con.is_ok(); let is_win_console = con.is_ok();
let wtr = let wtr =
if choice.should_attempt_color() { if choice.should_attempt_color() {
if choice.should_ansi() { if choice.should_ansi() {
WriterInner::Ansi(Ansi(io::stdout())) WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
} else if let Ok(console) = con { } else if let Ok(console) = con {
WriterInner::Windows { WriterInner::Windows {
wtr: io::stdout(), wtr: IoStandardStream::new(sty),
console: Mutex::new(console), console: Mutex::new(console),
} }
} else { } else {
WriterInner::Ansi(Ansi(io::stdout())) WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
} }
} else { } 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. /// Lock the underlying writer.
@@ -268,16 +365,16 @@ impl Stdout {
/// `WriteColor`. /// `WriteColor`.
/// ///
/// This method is **not reentrant**. It may panic if `lock` is called /// This method is **not reentrant**. It may panic if `lock` is called
/// while a `StdoutLock` is still alive. /// while a `StandardStreamLock` is still alive.
pub fn lock(&self) -> StdoutLock { pub fn lock(&self) -> StandardStreamLock {
StdoutLock::from_stdout(self) StandardStreamLock::from_stream(self)
} }
} }
impl<'a> StdoutLock<'a> { impl<'a> StandardStreamLock<'a> {
#[cfg(not(windows))] #[cfg(not(windows))]
fn from_stdout(stdout: &Stdout) -> StdoutLock { fn from_stream(stream: &StandardStream) -> StandardStreamLock {
let locked = match *stdout.wtr.get_ref() { let locked = match *stream.wtr.get_ref() {
WriterInner::Unreachable(_) => unreachable!(), WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref w) => { WriterInner::NoColor(ref w) => {
WriterInner::NoColor(NoColor(w.0.lock())) WriterInner::NoColor(NoColor(w.0.lock()))
@@ -286,12 +383,12 @@ impl<'a> StdoutLock<'a> {
WriterInner::Ansi(Ansi(w.0.lock())) WriterInner::Ansi(Ansi(w.0.lock()))
} }
}; };
StdoutLock { wtr: stdout.wtr.wrap(locked) } StandardStreamLock { wtr: stream.wtr.wrap(locked) }
} }
#[cfg(windows)] #[cfg(windows)]
fn from_stdout(stdout: &Stdout) -> StdoutLock { fn from_stream(stream: &StandardStream) -> StandardStreamLock {
let locked = match *stdout.wtr.get_ref() { let locked = match *stream.wtr.get_ref() {
WriterInner::Unreachable(_) => unreachable!(), WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref w) => { WriterInner::NoColor(ref w) => {
WriterInner::NoColor(NoColor(w.0.lock())) WriterInner::NoColor(NoColor(w.0.lock()))
@@ -308,19 +405,19 @@ impl<'a> StdoutLock<'a> {
} }
#[cfg(windows)] #[cfg(windows)]
WriterInner::WindowsLocked{..} => { 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 write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
fn flush(&mut self) -> io::Result<()> { self.wtr.flush() } 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 supports_color(&self) -> bool { self.wtr.supports_color() }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec) self.wtr.set_color(spec)
@@ -328,12 +425,12 @@ impl WriteColor for Stdout {
fn reset(&mut self) -> io::Result<()> { self.wtr.reset() } 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 write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
fn flush(&mut self) -> io::Result<()> { self.wtr.flush() } 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 supports_color(&self) -> bool { self.wtr.supports_color() }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec) 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`. /// 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 /// It is intended for a `BufferWriter` to be put in an `Arc` and written to
/// from multiple threads simultaneously. /// from multiple threads simultaneously.
pub struct BufferWriter { pub struct BufferWriter {
stdout: LossyStdout<io::Stdout>, stream: LossyStandardStream<IoStandardStream>,
printed: AtomicBool, printed: AtomicBool,
separator: Option<Vec<u8>>, separator: Option<Vec<u8>>,
color_choice: ColorChoice, color_choice: ColorChoice,
@@ -439,23 +536,23 @@ pub struct BufferWriter {
} }
impl BufferWriter { impl BufferWriter {
/// Create a new `BufferWriter` that writes to stdout with the given /// Create a new `BufferWriter` that writes to a standard stream with the
/// color preferences. /// given color preferences.
/// ///
/// The specific color/style settings can be configured when writing to /// The specific color/style settings can be configured when writing to
/// the buffers themselves. /// the buffers themselves.
#[cfg(not(windows))] #[cfg(not(windows))]
pub fn stdout(choice: ColorChoice) -> BufferWriter { fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
BufferWriter { BufferWriter {
stdout: LossyStdout::new(io::stdout()), stream: LossyStandardStream::new(IoStandardStream::new(sty)),
printed: AtomicBool::new(false), printed: AtomicBool::new(false),
separator: None, separator: None,
color_choice: choice, color_choice: choice,
} }
} }
/// Create a new `BufferWriter` that writes to stdout with the given /// Create a new `BufferWriter` that writes to a standard stream with the
/// color preferences. /// given color preferences.
/// ///
/// If coloring is desired and a Windows console could not be found, then /// If coloring is desired and a Windows console could not be found, then
/// ANSI escape sequences are used instead. /// ANSI escape sequences are used instead.
@@ -463,11 +560,14 @@ impl BufferWriter {
/// The specific color/style settings can be configured when writing to /// The specific color/style settings can be configured when writing to
/// the buffers themselves. /// the buffers themselves.
#[cfg(windows)] #[cfg(windows)]
pub fn stdout(choice: ColorChoice) -> BufferWriter { fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
let con = wincolor::Console::stdout().ok().map(Mutex::new); let con = match sty {
let stdout = LossyStdout::new(io::stdout()).is_console(con.is_some()); 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 { BufferWriter {
stdout: stdout, stream: stream,
printed: AtomicBool::new(false), printed: AtomicBool::new(false),
separator: None, separator: None,
color_choice: choice, 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 /// If set, the separator given is printed between buffers. By default, no
/// separator is printed. /// separator is printed.
/// ///
@@ -510,16 +634,16 @@ impl BufferWriter {
if buf.is_empty() { if buf.is_empty() {
return Ok(()); 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 let Some(ref sep) = self.separator {
if self.printed.load(Ordering::SeqCst) { if self.printed.load(Ordering::SeqCst) {
try!(stdout.write_all(sep)); try!(stream.write_all(sep));
try!(stdout.write_all(b"\n")); try!(stream.write_all(b"\n"));
} }
} }
match buf.0 { match buf.0 {
BufferInner::NoColor(ref b) => try!(stdout.write_all(&b.0)), BufferInner::NoColor(ref b) => try!(stream.write_all(&b.0)),
BufferInner::Ansi(ref b) => try!(stdout.write_all(&b.0)), BufferInner::Ansi(ref b) => try!(stream.write_all(&b.0)),
#[cfg(windows)] #[cfg(windows)]
BufferInner::Windows(ref b) => { BufferInner::Windows(ref b) => {
// We guarantee by construction that we have a console here. // We guarantee by construction that we have a console here.
@@ -527,7 +651,7 @@ impl BufferWriter {
let console_mutex = self.console.as_ref() let console_mutex = self.console.as_ref()
.expect("got Windows buffer but have no Console"); .expect("got Windows buffer but have no Console");
let mut console = console_mutex.lock().unwrap(); 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); self.printed.store(true, Ordering::SeqCst);
@@ -905,25 +1029,25 @@ impl WindowsBuffer {
self.colors.push((pos, spec)); 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. /// for coloring.
fn print( fn print(
&self, &self,
console: &mut wincolor::Console, console: &mut wincolor::Console,
stdout: &mut LossyStdout<io::StdoutLock>, stream: &mut LossyStandardStream<IoStandardStreamLock>,
) -> io::Result<()> { ) -> io::Result<()> {
let mut last = 0; let mut last = 0;
for &(pos, ref spec) in &self.colors { for &(pos, ref spec) in &self.colors {
try!(stdout.write_all(&self.buf[last..pos])); try!(stream.write_all(&self.buf[last..pos]));
try!(stdout.flush()); try!(stream.flush());
last = pos; last = pos;
match *spec { match *spec {
None => try!(console.reset()), None => try!(console.reset()),
Some(ref spec) => try!(spec.write_console(console)), Some(ref spec) => try!(spec.write_console(console)),
} }
} }
try!(stdout.write_all(&self.buf[last..])); try!(stream.write_all(&self.buf[last..]));
stdout.flush() stream.flush()
} }
/// Clear the buffer. /// Clear the buffer.
@@ -1121,33 +1245,33 @@ impl FromStr for Color {
} }
} }
struct LossyStdout<W> { struct LossyStandardStream<W> {
wtr: W, wtr: W,
#[cfg(windows)] #[cfg(windows)]
is_console: bool, is_console: bool,
} }
impl<W: io::Write> LossyStdout<W> { impl<W: io::Write> LossyStandardStream<W> {
#[cfg(not(windows))] #[cfg(not(windows))]
fn new(wtr: W) -> LossyStdout<W> { LossyStdout { wtr: wtr } } fn new(wtr: W) -> LossyStandardStream<W> { LossyStandardStream { wtr: wtr } }
#[cfg(windows)] #[cfg(windows)]
fn new(wtr: W) -> LossyStdout<W> { fn new(wtr: W) -> LossyStandardStream<W> {
LossyStdout { wtr: wtr, is_console: false } LossyStandardStream { wtr: wtr, is_console: false }
} }
#[cfg(not(windows))] #[cfg(not(windows))]
fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStdout<Q> { fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
LossyStdout::new(wtr) LossyStandardStream::new(wtr)
} }
#[cfg(windows)] #[cfg(windows)]
fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStdout<Q> { fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
LossyStdout::new(wtr).is_console(self.is_console) LossyStandardStream::new(wtr).is_console(self.is_console)
} }
#[cfg(windows)] #[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.is_console = yes;
self 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 supports_color(&self) -> bool { self.wtr.supports_color() }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec) 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() } 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))] #[cfg(not(windows))]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.wtr.write(buf) self.wtr.write(buf)

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wincolor" name = "wincolor"
version = "0.1.1" #:version version = "0.1.2" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
A simple Windows specific API for controlling text color in a Windows console. A simple Windows specific API for controlling text color in a Windows console.

View File

@@ -3,7 +3,7 @@ use std::mem;
use kernel32; use kernel32;
use winapi::{DWORD, HANDLE, WORD}; use winapi::{DWORD, HANDLE, WORD};
use winapi::winbase::STD_OUTPUT_HANDLE; use winapi::winbase::{STD_ERROR_HANDLE, STD_OUTPUT_HANDLE};
use winapi::wincon::{ use winapi::wincon::{
FOREGROUND_BLUE as FG_BLUE, FOREGROUND_BLUE as FG_BLUE,
FOREGROUND_GREEN as FG_GREEN, FOREGROUND_GREEN as FG_GREEN,
@@ -44,13 +44,11 @@ impl Drop for Console {
} }
impl Console { impl Console {
/// Create a new Console to stdout. /// Get a console for a standard I/O stream.
/// fn create_for_stream(handle_id: DWORD) -> io::Result<Console> {
/// If there was a problem creating the console, then an error is returned.
pub fn stdout() -> io::Result<Console> {
let mut info = unsafe { mem::zeroed() }; let mut info = unsafe { mem::zeroed() };
let (handle, res) = unsafe { let (handle, res) = unsafe {
let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE); let handle = kernel32::GetStdHandle(handle_id);
(handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info)) (handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
}; };
if res == 0 { 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. /// Applies the current text attributes.
fn set(&mut self) -> io::Result<()> { fn set(&mut self) -> io::Result<()> {
let attr = self.cur_attr.to_word(); let attr = self.cur_attr.to_word();