Compare commits

..

6 Commits

Author SHA1 Message Date
Andrew Gallant
12a78a992c termcolor-0.3.3 2017-08-27 11:05:55 -04:00
Andrew Gallant
d97c80be63 termcolor: make StandardStream be Send
This commit fixes a bug where the `StandardStream` type isn't `Send` on
Windows. This can cause some surprising compile breakage, and the only
motivation for it being non-Send was dubious. Namely, it was a result of
trying to eliminate code duplication.

This refactoring also eliminates at least one "unreachable" panic case
that was a result of trying to eliminate code reuse, so that's a nice
benefit as well.

Fixes #503
2017-08-27 11:05:02 -04:00
Andrew Gallant
5213bd30ea termcolor: 80 cols 2017-08-27 11:05:02 -04:00
Alex Burka
82d101907a ignore: document git_global enabled by default 2017-08-26 14:49:40 -04:00
Andrew Gallant
30608f2444 readme: update minimum version 2017-08-23 23:08:21 -04:00
Andrew Gallant
3d323928a0 update brew tap 2017-08-23 22:04:16 -04:00
5 changed files with 120 additions and 51 deletions

View File

@@ -210,7 +210,8 @@ $ # (Or using the attribute name, which is also `ripgrep`.)
``` ```
If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`. Note 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. that the minimum supported version of Rust for ripgrep is **1.17**, although
ripgrep may work with older versions.
``` ```
$ cargo install ripgrep $ cargo install ripgrep
@@ -346,7 +347,7 @@ For **fish**, move `complete/rg.fish` to `$HOME/.config/fish/completions/`.
For **PowerShell**, add `. _rg.ps1` to your PowerShell For **PowerShell**, add `. _rg.ps1` to your PowerShell
[profile](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx) [profile](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx)
(note the leading period). If the `_rg.ps1` file is not on your `PATH`, do (note the leading period). If the `_rg.ps1` file is not on your `PATH`, do
`. /path/to/_rg.ps1` instead. `. /path/to/_rg.ps1` instead.
For **zsh**, move `complete/_rg` to one of your `$fpath` directories. For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
@@ -354,7 +355,7 @@ For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
`ripgrep` is written in Rust, so you'll need to grab a `ripgrep` is written in Rust, so you'll need to grab a
[Rust installation](https://www.rust-lang.org/) in order to compile it. [Rust installation](https://www.rust-lang.org/) in order to compile it.
`ripgrep` compiles with Rust 1.12 (stable) or newer. Building is easy: `ripgrep` compiles with Rust 1.17 (stable) or newer. Building is easy:
``` ```
$ git clone https://github.com/BurntSushi/ripgrep $ git clone https://github.com/BurntSushi/ripgrep
@@ -449,7 +450,7 @@ Example `$OutputEncoding` settings:
`$OutputEncoding = [System.Console]::OutputEncoding` `$OutputEncoding = [System.Console]::OutputEncoding`
If you continue to have encoding problems, you can also force the encoding If you continue to have encoding problems, you can also force the encoding
that the console will use for printing to UTF-8 with that the console will use for printing to UTF-8 with
`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This `[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This
will also reset when PowerShell is restarted, so you can add that line will also reset when PowerShell is restarted, so you can add that line
to your profile as well if you want to make the setting permanent. to your profile as well if you want to make the setting permanent.

View File

@@ -610,6 +610,8 @@ impl WalkBuilder {
/// does not exist or does not specify `core.excludesFile`, then /// does not exist or does not specify `core.excludesFile`, then
/// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not /// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not
/// set or is empty, then `$HOME/.config/git/ignore` is used instead. /// set or is empty, then `$HOME/.config/git/ignore` is used instead.
///
/// This is enabled by default.
pub fn git_global(&mut self, yes: bool) -> &mut WalkBuilder { pub fn git_global(&mut self, yes: bool) -> &mut WalkBuilder {
self.ig_builder.git_global(yes); self.ig_builder.git_global(yes);
self self

View File

@@ -1,9 +1,9 @@
class RipgrepBin < Formula class RipgrepBin < Formula
version '0.5.2' version '0.6.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 "a0326a84af8517ad707d8c7cccba6e112de27822c391cc0937e4727fbb6c48f4" sha256 "2aeffe25322f886bcd846ac15b6574dc769865fb44b28a9b0c356f3004019685"
conflicts_with "ripgrep" conflicts_with "ripgrep"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "termcolor" name = "termcolor"
version = "0.3.2" #:version version = "0.3.3" #: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

@@ -202,15 +202,23 @@ enum IoStandardStream {
impl IoStandardStream { impl IoStandardStream {
fn new(sty: StandardStreamType) -> IoStandardStream { fn new(sty: StandardStreamType) -> IoStandardStream {
match sty { match sty {
StandardStreamType::Stdout => IoStandardStream::Stdout(io::stdout()), StandardStreamType::Stdout => {
StandardStreamType::Stderr => IoStandardStream::Stderr(io::stderr()), IoStandardStream::Stdout(io::stdout())
}
StandardStreamType::Stderr => {
IoStandardStream::Stderr(io::stderr())
}
} }
} }
fn lock(&self) -> IoStandardStreamLock { fn lock(&self) -> IoStandardStreamLock {
match *self { match *self {
IoStandardStream::Stdout(ref s) => IoStandardStreamLock::StdoutLock(s.lock()), IoStandardStream::Stdout(ref s) => {
IoStandardStream::Stderr(ref s) => IoStandardStreamLock::StderrLock(s.lock()), IoStandardStreamLock::StdoutLock(s.lock())
}
IoStandardStream::Stderr(ref s) => {
IoStandardStreamLock::StderrLock(s.lock())
}
} }
} }
} }
@@ -257,7 +265,7 @@ impl<'a> io::Write for IoStandardStreamLock<'a> {
/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring /// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
/// to either of the standard output streams, stdout and stderr. /// to either of the standard output streams, stdout and stderr.
pub struct StandardStream { pub struct StandardStream {
wtr: LossyStandardStream<WriterInner<'static, IoStandardStream>>, wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
} }
/// `StandardStreamLock` is a locked reference to a `StandardStream`. /// `StandardStreamLock` is a locked reference to a `StandardStream`.
@@ -265,14 +273,24 @@ pub struct 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 `StandardStream`. /// The lifetime `'a` refers to the lifetime of the corresponding
/// `StandardStream`.
pub struct StandardStreamLock<'a> { pub struct StandardStreamLock<'a> {
wtr: LossyStandardStream<WriterInner<'a, IoStandardStreamLock<'a>>>, wtr: LossyStandardStream<WriterInnerLock<'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
/// limited because W should only ever be stdout/stderr on Windows. /// limited because W should only ever be stdout/stderr on Windows.
enum WriterInner<'a, W> { enum WriterInner<W> {
NoColor(NoColor<W>),
Ansi(Ansi<W>),
#[cfg(windows)]
Windows { wtr: W, console: Mutex<wincolor::Console> },
}
/// WriterInnerLock is a (limited) generic representation of a writer. It is
/// limited because W should only ever be stdout/stderr on Windows.
enum WriterInnerLock<'a, W> {
NoColor(NoColor<W>), NoColor(NoColor<W>),
Ansi(Ansi<W>), Ansi(Ansi<W>),
/// What a gross hack. On Windows, we need to specify a lifetime for the /// What a gross hack. On Windows, we need to specify a lifetime for the
@@ -282,9 +300,7 @@ enum WriterInner<'a, W> {
#[allow(dead_code)] #[allow(dead_code)]
Unreachable(::std::marker::PhantomData<&'a ()>), Unreachable(::std::marker::PhantomData<&'a ()>),
#[cfg(windows)] #[cfg(windows)]
Windows { wtr: W, console: Mutex<wincolor::Console> }, Windows { wtr: W, console: MutexGuard<'a, wincolor::Console> },
#[cfg(windows)]
WindowsLocked { wtr: W, console: MutexGuard<'a, wincolor::Console> },
} }
impl StandardStream { impl StandardStream {
@@ -332,7 +348,9 @@ impl StandardStream {
} else { } else {
WriterInner::NoColor(NoColor(IoStandardStream::new(sty))) WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
}; };
StandardStream { wtr: LossyStandardStream::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 /// Create a new `StandardStream` with the given color preferences that
@@ -375,12 +393,11 @@ impl<'a> StandardStreamLock<'a> {
#[cfg(not(windows))] #[cfg(not(windows))]
fn from_stream(stream: &StandardStream) -> StandardStreamLock { fn from_stream(stream: &StandardStream) -> StandardStreamLock {
let locked = match *stream.wtr.get_ref() { let locked = match *stream.wtr.get_ref() {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref w) => { WriterInner::NoColor(ref w) => {
WriterInner::NoColor(NoColor(w.0.lock())) WriterInnerLock::NoColor(NoColor(w.0.lock()))
} }
WriterInner::Ansi(ref w) => { WriterInner::Ansi(ref w) => {
WriterInner::Ansi(Ansi(w.0.lock())) WriterInnerLock::Ansi(Ansi(w.0.lock()))
} }
}; };
StandardStreamLock { wtr: stream.wtr.wrap(locked) } StandardStreamLock { wtr: stream.wtr.wrap(locked) }
@@ -389,24 +406,19 @@ impl<'a> StandardStreamLock<'a> {
#[cfg(windows)] #[cfg(windows)]
fn from_stream(stream: &StandardStream) -> StandardStreamLock { fn from_stream(stream: &StandardStream) -> StandardStreamLock {
let locked = match *stream.wtr.get_ref() { let locked = match *stream.wtr.get_ref() {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref w) => { WriterInner::NoColor(ref w) => {
WriterInner::NoColor(NoColor(w.0.lock())) WriterInnerLock::NoColor(NoColor(w.0.lock()))
} }
WriterInner::Ansi(ref w) => { WriterInner::Ansi(ref w) => {
WriterInner::Ansi(Ansi(w.0.lock())) WriterInnerLock::Ansi(Ansi(w.0.lock()))
} }
#[cfg(windows)] #[cfg(windows)]
WriterInner::Windows { ref wtr, ref console } => { WriterInner::Windows { ref wtr, ref console } => {
WriterInner::WindowsLocked { WriterInnerLock::Windows {
wtr: wtr.lock(), wtr: wtr.lock(),
console: console.lock().unwrap(), console: console.lock().unwrap(),
} }
} }
#[cfg(windows)]
WriterInner::WindowsLocked{..} => {
panic!("cannot call StandardStream.lock while a StandardStreamLock is alive");
}
}; };
StandardStreamLock { wtr: stream.wtr.wrap(locked) } StandardStreamLock { wtr: stream.wtr.wrap(locked) }
} }
@@ -438,48 +450,38 @@ impl<'a> WriteColor for StandardStreamLock<'a> {
fn reset(&mut self) -> io::Result<()> { self.wtr.reset() } fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
} }
impl<'a, W: io::Write> io::Write for WriterInner<'a, W> { impl<W: io::Write> io::Write for WriterInner<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match *self { match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.write(buf), WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
WriterInner::Ansi(ref mut wtr) => wtr.write(buf), WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
#[cfg(windows)] #[cfg(windows)]
WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf), WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, .. } => wtr.write(buf),
} }
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
match *self { match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.flush(), WriterInner::NoColor(ref mut wtr) => wtr.flush(),
WriterInner::Ansi(ref mut wtr) => wtr.flush(), WriterInner::Ansi(ref mut wtr) => wtr.flush(),
#[cfg(windows)] #[cfg(windows)]
WriterInner::Windows { ref mut wtr, .. } => wtr.flush(), WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, .. } => wtr.flush(),
} }
} }
} }
impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> { impl<W: io::Write> WriteColor for WriterInner<W> {
fn supports_color(&self) -> bool { fn supports_color(&self) -> bool {
match *self { match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(_) => false, WriterInner::NoColor(_) => false,
WriterInner::Ansi(_) => true, WriterInner::Ansi(_) => true,
#[cfg(windows)] #[cfg(windows)]
WriterInner::Windows { .. } => true, WriterInner::Windows { .. } => true,
#[cfg(windows)]
WriterInner::WindowsLocked { .. } => true,
} }
} }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self { match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec), WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec), WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
#[cfg(windows)] #[cfg(windows)]
@@ -488,17 +490,11 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
let mut console = console.lock().unwrap(); let mut console = console.lock().unwrap();
spec.write_console(&mut *console) spec.write_console(&mut *console)
} }
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, ref mut console } => {
try!(wtr.flush());
spec.write_console(console)
}
} }
} }
fn reset(&mut self) -> io::Result<()> { fn reset(&mut self) -> io::Result<()> {
match *self { match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.reset(), WriterInner::NoColor(ref mut wtr) => wtr.reset(),
WriterInner::Ansi(ref mut wtr) => wtr.reset(), WriterInner::Ansi(ref mut wtr) => wtr.reset(),
#[cfg(windows)] #[cfg(windows)]
@@ -507,8 +503,63 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
try!(console.lock().unwrap().reset()); try!(console.lock().unwrap().reset());
Ok(()) Ok(())
} }
}
}
}
impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
#[cfg(windows)] #[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, ref mut console } => { WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
#[cfg(windows)]
WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
}
}
}
impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
fn supports_color(&self) -> bool {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(_) => false,
WriterInnerLock::Ansi(_) => true,
#[cfg(windows)]
WriterInnerLock::Windows { .. } => true,
}
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
#[cfg(windows)]
WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
try!(wtr.flush());
spec.write_console(console)
}
}
}
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
#[cfg(windows)]
WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
try!(wtr.flush()); try!(wtr.flush());
try!(console.reset()); try!(console.reset());
Ok(()) Ok(())
@@ -565,7 +616,8 @@ impl BufferWriter {
StandardStreamType::Stdout => wincolor::Console::stdout(), StandardStreamType::Stdout => wincolor::Console::stdout(),
StandardStreamType::Stderr => wincolor::Console::stderr(), StandardStreamType::Stderr => wincolor::Console::stderr(),
}.ok().map(Mutex::new); }.ok().map(Mutex::new);
let stream = LossyStandardStream::new(IoStandardStream::new(sty)).is_console(con.is_some()); let stream = LossyStandardStream::new(IoStandardStream::new(sty))
.is_console(con.is_some());
BufferWriter { BufferWriter {
stream: stream, stream: stream,
printed: AtomicBool::new(false), printed: AtomicBool::new(false),
@@ -1253,7 +1305,9 @@ struct LossyStandardStream<W> {
impl<W: io::Write> LossyStandardStream<W> { impl<W: io::Write> LossyStandardStream<W> {
#[cfg(not(windows))] #[cfg(not(windows))]
fn new(wtr: W) -> LossyStandardStream<W> { LossyStandardStream { wtr: wtr } } fn new(wtr: W) -> LossyStandardStream<W> {
LossyStandardStream { wtr: wtr }
}
#[cfg(windows)] #[cfg(windows)]
fn new(wtr: W) -> LossyStandardStream<W> { fn new(wtr: W) -> LossyStandardStream<W> {
@@ -1320,3 +1374,15 @@ fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
Err(e) => w.write(&buf[..e.valid_up_to()]), Err(e) => w.write(&buf[..e.valid_up_to()]),
} }
} }
#[cfg(test)]
mod tests {
use super::StandardStream;
fn assert_is_send<T: Send>() {}
#[test]
fn standard_stream_is_send() {
assert_is_send::<StandardStream>();
}
}