aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-08 01:22:56 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-08 01:22:56 +0000
commit1e4d8be4d300b3dea857f24ee2ed0b5db5839c75 (patch)
tree49bc4fab49bba8875ab1201bb30694bdf546b5bb
parentc5083b1d97af67404a26acecd827cf80711a0ae2 (diff)
parentabdf78a2cbd6ac24a6667e46dde12ffbadccda4f (diff)
downloadtermcolor-simpleperf-release.tar.gz
Snap for 11421525 from abdf78a2cbd6ac24a6667e46dde12ffbadccda4f to simpleperf-releasesimpleperf-release
Change-Id: Ifccfe70602a8daecb3bbcd337523337a83f8f84b
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml48
-rw-r--r--.gitignore1
-rw-r--r--Android.bp4
-rw-r--r--Cargo.toml2
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA23
-rw-r--r--README.md23
-rw-r--r--src/lib.rs252
9 files changed, 279 insertions, 78 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index f84bcf3..6252881 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "a4c5d5102122cf3442775fc464d6d5f976c95256"
+ "sha1": "71f0921f1eeceda85487098588a1602979d52493"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9fdfc46..3412b2c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,67 +12,53 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- build:
- - pinned
- - pinned-win
- - stable
- - beta
- - nightly
- - macos
- - win-msvc
- - win-gnu
include:
- build: pinned
- os: ubuntu-18.04
- rust: 1.34.0
+ os: ubuntu-latest
+ rust: 1.60.0
- build: pinned-win
- os: windows-2019
- rust: 1.34.0
+ os: windows-latest
+ rust: 1.60.0
- build: stable
- os: ubuntu-18.04
+ os: ubuntu-latest
rust: stable
- build: beta
- os: ubuntu-18.04
+ os: ubuntu-latest
rust: beta
- build: nightly
- os: ubuntu-18.04
+ os: ubuntu-latest
rust: nightly
- build: macos
os: macos-latest
rust: stable
- build: win-msvc
- os: windows-2019
+ os: windows-latest
rust: stable
- build: win-gnu
- os: windows-2019
+ os: windows-latest
rust: stable-x86_64-gnu
steps:
- name: Checkout repository
- uses: actions/checkout@v1
- with:
- fetch-depth: 1
+ uses: actions/checkout@v3
- name: Install Rust
- uses: hecrj/setup-rust-action@v1
+ uses: dtolnay/rust-toolchain@master
with:
- rust-version: ${{ matrix.rust }}
+ toolchain: ${{ matrix.rust }}
- run: cargo build --verbose
- run: cargo doc --verbose
- run: cargo test --verbose
rustfmt:
name: rustfmt
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v1
- with:
- fetch-depth: 1
+ uses: actions/checkout@v3
- name: Install Rust
- uses: hecrj/setup-rust-action@v1
+ uses: dtolnay/rust-toolchain@master
with:
- rust-version: stable
- - name: Install rustfmt
- run: rustup component add rustfmt
+ toolchain: stable
+ components: rustfmt
- name: Check formatting
run: |
cargo fmt --all -- --check
diff --git a/.gitignore b/.gitignore
index 2f2825f..27c3378 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ tags
target
/Cargo.lock
/wincolor/Cargo.lock
+/.idea
diff --git a/Android.bp b/Android.bp
index 5abe428..deb4063 100644
--- a/Android.bp
+++ b/Android.bp
@@ -43,7 +43,7 @@ rust_library {
host_supported: true,
crate_name: "termcolor",
cargo_env_compat: true,
- cargo_pkg_version: "1.2.0",
+ cargo_pkg_version: "1.4.1",
srcs: ["src/lib.rs"],
edition: "2018",
apex_available: [
@@ -59,7 +59,7 @@ rust_test {
host_supported: true,
crate_name: "termcolor",
cargo_env_compat: true,
- cargo_pkg_version: "1.2.0",
+ cargo_pkg_version: "1.4.1",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
diff --git a/Cargo.toml b/Cargo.toml
index dbdb6e8..f90eaca 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "termcolor"
-version = "1.2.0"
+version = "1.4.1"
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A simple cross platform library for writing colored text to a terminal.
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index ef7f1c1..1afe819 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "termcolor"
-version = "1.2.0" #:version
+version = "1.4.1" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A simple cross platform library for writing colored text to a terminal.
diff --git a/METADATA b/METADATA
index 4531041..46e39c0 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
# This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update rust/crates/termcolor
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# Usage: tools/external_updater/updater.sh update external/rust/crates/termcolor
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
name: "termcolor"
description: "A simple cross platform library for writing colored text to a terminal."
third_party {
- url {
- type: HOMEPAGE
- value: "https://crates.io/crates/termcolor"
- }
- url {
- type: ARCHIVE
- value: "https://static.crates.io/crates/termcolor/termcolor-1.2.0.crate"
- }
- version: "1.2.0"
license_type: NOTICE
last_upgrade_date {
- year: 2023
+ year: 2024
month: 2
- day: 6
+ day: 7
+ }
+ homepage: "https://crates.io/crates/termcolor"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/termcolor/termcolor-1.4.1.crate"
+ version: "1.4.1"
}
}
diff --git a/README.md b/README.md
index 646e3b5..ef7e3e8 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
termcolor
=========
A simple cross platform library for writing colored text to a terminal. This
-library writes colored text either using standard ANSI escape sequences or
-by interacting with the Windows console. Several convenient abstractions
-are provided for use in single-threaded or multi-threaded command line
+library writes colored text either using standard ANSI escape sequences or by
+interacting with the Windows console. Several convenient abstractions are
+provided for use in single-threaded or multi-threaded command line
applications.
[![Build status](https://github.com/BurntSushi/termcolor/workflows/ci/badge.svg)](https://github.com/BurntSushi/termcolor/actions)
-[![](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor)
+[![crates.io](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor)
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
@@ -17,12 +17,7 @@ Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
### Usage
-Add this to your `Cargo.toml`:
-
-```toml
-[dependencies]
-termcolor = "1.1"
-```
+Run `cargo add termcolor` to add this dependency to your `Cargo.toml` file.
### Organization
@@ -47,8 +42,8 @@ analogous type for the Windows console is not provided since it cannot exist.
### Example: using `StandardStream`
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:
+except it is augmented with methods for coloring by the `WriteColor` trait. For
+example, to write some green text:
```rust
use std::io::{self, Write};
@@ -98,8 +93,8 @@ termcolor will inspect the `TERM` and `NO_COLOR` environment variables:
This decision procedure may change over time.
Currently, `termcolor` does not attempt to detect whether a tty is present or
-not. To achieve that, please use the [`atty`](https://crates.io/crates/atty)
-crate.
+not. To achieve that, please use
+[`std::io::IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html).
### Minimum Rust version policy
diff --git a/src/lib.rs b/src/lib.rs
index 062df18..9e6371f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,8 @@ to an in memory buffer. While this is easy to do with ANSI escape sequences
(because they are in the buffer themselves), it is trickier to do with the
Windows console API, which requires synchronous communication.
+In ANSI mode, this crate also provides support for writing hyperlinks.
+
# Organization
The `WriteColor` trait extends the `io::Write` trait with methods for setting
@@ -85,21 +87,21 @@ is via libc's
[`isatty`](https://man7.org/linux/man-pages/man3/isatty.3.html)
function.
Unfortunately, this notoriously does not work well in Windows environments. To
-work around that, the currently recommended solution is to use the
-[`atty`](https://crates.io/crates/atty)
-crate, which goes out of its way to get this as right as possible in Windows
-environments.
+work around that, the recommended solution is to use the standard library's
+[`IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html) trait.
+It goes out of its way to get it as right as possible in Windows environments.
For example, in a command line application that exposes a `--color` flag,
your logic for how to enable colors might look like this:
-```rust,ignore
-use atty;
+```ignore
+use std::io::IsTerminal;
+
use termcolor::{ColorChoice, StandardStream};
let preference = argv.get_flag("color").unwrap_or("auto");
let mut choice = preference.parse::<ColorChoice>()?;
-if choice == ColorChoice::Auto && !atty::is(atty::Stream::Stdout) {
+if choice == ColorChoice::Auto && !std::io::stdin().is_terminal() {
choice = ColorChoice::Never;
}
let stdout = StandardStream::stdout(choice);
@@ -146,6 +148,10 @@ pub trait WriteColor: io::Write {
///
/// If there was a problem resetting the color settings, then an error is
/// returned.
+ ///
+ /// Note that this does not reset hyperlinks. Those need to be
+ /// reset on their own, e.g., by calling `set_hyperlink` with
+ /// [`HyperlinkSpec::none`].
fn reset(&mut self) -> io::Result<()>;
/// Returns true if and only if the underlying writer must synchronously
@@ -162,15 +168,49 @@ pub trait WriteColor: io::Write {
fn is_synchronous(&self) -> bool {
false
}
+
+ /// Set the current hyperlink of the writer.
+ ///
+ /// The typical way to use this is to first call it with a
+ /// [`HyperlinkSpec::open`] to write the actual URI to a tty that supports
+ /// [OSC-8]. At this point, the caller can now write the label for the
+ /// hyperlink. This may include coloring or other styles. Once the caller
+ /// has finished writing the label, one should call this method again with
+ /// [`HyperlinkSpec::close`].
+ ///
+ /// If there was a problem setting the hyperlink, then an error is
+ /// returned.
+ ///
+ /// This defaults to doing nothing.
+ ///
+ /// [OSC8]: https://github.com/Alhadis/OSC8-Adoption/
+ fn set_hyperlink(&mut self, _link: &HyperlinkSpec) -> io::Result<()> {
+ Ok(())
+ }
+
+ /// Returns true if and only if the underlying writer supports hyperlinks.
+ ///
+ /// This can be used to avoid generating hyperlink URIs unnecessarily.
+ ///
+ /// This defaults to `false`.
+ fn supports_hyperlinks(&self) -> bool {
+ false
+ }
}
impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
fn supports_color(&self) -> bool {
(&**self).supports_color()
}
+ fn supports_hyperlinks(&self) -> bool {
+ (&**self).supports_hyperlinks()
+ }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
(&mut **self).set_color(spec)
}
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ (&mut **self).set_hyperlink(link)
+ }
fn reset(&mut self) -> io::Result<()> {
(&mut **self).reset()
}
@@ -183,9 +223,15 @@ impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
fn supports_color(&self) -> bool {
(&**self).supports_color()
}
+ fn supports_hyperlinks(&self) -> bool {
+ (&**self).supports_hyperlinks()
+ }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
(&mut **self).set_color(spec)
}
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ (&mut **self).set_hyperlink(link)
+ }
fn reset(&mut self) -> io::Result<()> {
(&mut **self).reset()
}
@@ -669,11 +715,21 @@ impl WriteColor for StandardStream {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ self.wtr.supports_hyperlinks()
+ }
+
+ #[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec)
}
#[inline]
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ self.wtr.set_hyperlink(link)
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
}
@@ -703,11 +759,21 @@ impl<'a> WriteColor for StandardStreamLock<'a> {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ self.wtr.supports_hyperlinks()
+ }
+
+ #[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec)
}
#[inline]
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ self.wtr.set_hyperlink(link)
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
}
@@ -737,6 +803,11 @@ impl WriteColor for BufferedStandardStream {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ self.wtr.supports_hyperlinks()
+ }
+
+ #[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
if self.is_synchronous() {
self.wtr.flush()?;
@@ -745,6 +816,14 @@ impl WriteColor for BufferedStandardStream {
}
#[inline]
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ if self.is_synchronous() {
+ self.wtr.flush()?;
+ }
+ self.wtr.set_hyperlink(link)
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
}
@@ -787,6 +866,15 @@ impl<W: io::Write> WriteColor for WriterInner<W> {
}
}
+ fn supports_hyperlinks(&self) -> bool {
+ match *self {
+ WriterInner::NoColor(_) => false,
+ WriterInner::Ansi(_) => true,
+ #[cfg(windows)]
+ WriterInner::Windows { .. } => false,
+ }
+ }
+
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
@@ -800,6 +888,15 @@ impl<W: io::Write> WriteColor for WriterInner<W> {
}
}
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ match *self {
+ WriterInner::NoColor(ref mut wtr) => wtr.set_hyperlink(link),
+ WriterInner::Ansi(ref mut wtr) => wtr.set_hyperlink(link),
+ #[cfg(windows)]
+ WriterInner::Windows { .. } => Ok(()),
+ }
+ }
+
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInner::NoColor(ref mut wtr) => wtr.reset(),
@@ -856,6 +953,16 @@ impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
}
}
+ fn supports_hyperlinks(&self) -> bool {
+ match *self {
+ WriterInnerLock::Unreachable(_) => unreachable!(),
+ WriterInnerLock::NoColor(_) => false,
+ WriterInnerLock::Ansi(_) => true,
+ #[cfg(windows)]
+ WriterInnerLock::Windows { .. } => false,
+ }
+ }
+
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
@@ -869,6 +976,16 @@ impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
}
}
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ match *self {
+ WriterInnerLock::Unreachable(_) => unreachable!(),
+ WriterInnerLock::NoColor(ref mut wtr) => wtr.set_hyperlink(link),
+ WriterInnerLock::Ansi(ref mut wtr) => wtr.set_hyperlink(link),
+ #[cfg(windows)]
+ WriterInnerLock::Windows { .. } => Ok(()),
+ }
+ }
+
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
@@ -1026,7 +1143,7 @@ impl BufferWriter {
}
let mut stream = self.stream.wrap(self.stream.get_ref().lock());
if let Some(ref sep) = self.separator {
- if self.printed.load(Ordering::SeqCst) {
+ if self.printed.load(Ordering::Relaxed) {
stream.write_all(sep)?;
stream.write_all(b"\n")?;
}
@@ -1046,7 +1163,7 @@ impl BufferWriter {
b.print(&mut *console, &mut stream)?;
}
}
- self.printed.store(true, Ordering::SeqCst);
+ self.printed.store(true, Ordering::Relaxed);
Ok(())
}
}
@@ -1062,11 +1179,11 @@ impl BufferWriter {
/// method, which will take color preferences and the environment into
/// account. However, buffers can also be manually created using `no_color`,
/// `ansi` or `console` (on Windows).
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub struct Buffer(BufferInner);
/// BufferInner is an enumeration of different buffer types.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
enum BufferInner {
/// No coloring information should be applied. This ignores all coloring
/// directives.
@@ -1220,6 +1337,16 @@ impl WriteColor for Buffer {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ match self.0 {
+ BufferInner::NoColor(_) => false,
+ BufferInner::Ansi(_) => true,
+ #[cfg(windows)]
+ BufferInner::Windows(_) => false,
+ }
+ }
+
+ #[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match self.0 {
BufferInner::NoColor(ref mut w) => w.set_color(spec),
@@ -1230,6 +1357,16 @@ impl WriteColor for Buffer {
}
#[inline]
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ match self.0 {
+ BufferInner::NoColor(ref mut w) => w.set_hyperlink(link),
+ BufferInner::Ansi(ref mut w) => w.set_hyperlink(link),
+ #[cfg(windows)]
+ BufferInner::Windows(ref mut w) => w.set_hyperlink(link),
+ }
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
match self.0 {
BufferInner::NoColor(ref mut w) => w.reset(),
@@ -1246,7 +1383,7 @@ impl WriteColor for Buffer {
}
/// Satisfies `WriteColor` but ignores all color options.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub struct NoColor<W>(W);
impl<W: Write> NoColor<W> {
@@ -1291,11 +1428,21 @@ impl<W: io::Write> WriteColor for NoColor<W> {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ false
+ }
+
+ #[inline]
fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
Ok(())
}
#[inline]
+ fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
+ Ok(())
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
Ok(())
}
@@ -1307,7 +1454,7 @@ impl<W: io::Write> WriteColor for NoColor<W> {
}
/// Satisfies `WriteColor` using standard ANSI escape sequences.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub struct Ansi<W>(W);
impl<W: Write> Ansi<W> {
@@ -1363,6 +1510,11 @@ impl<W: io::Write> WriteColor for Ansi<W> {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ true
+ }
+
+ #[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
if spec.reset {
self.reset()?;
@@ -1392,6 +1544,15 @@ impl<W: io::Write> WriteColor for Ansi<W> {
}
#[inline]
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ self.write_str("\x1B]8;;")?;
+ if let Some(uri) = link.uri() {
+ self.write_all(uri)?;
+ }
+ self.write_str("\x1B\\")
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
self.write_str("\x1B[0m")
}
@@ -1522,10 +1683,18 @@ impl WriteColor for io::Sink {
false
}
+ fn supports_hyperlinks(&self) -> bool {
+ false
+ }
+
fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
Ok(())
}
+ fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
+ Ok(())
+ }
+
fn reset(&mut self) -> io::Result<()> {
Ok(())
}
@@ -1625,12 +1794,22 @@ impl WriteColor for WindowsBuffer {
}
#[inline]
+ fn supports_hyperlinks(&self) -> bool {
+ false
+ }
+
+ #[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.push(Some(spec.clone()));
Ok(())
}
#[inline]
+ fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
+ Ok(())
+ }
+
+ #[inline]
fn reset(&mut self) -> io::Result<()> {
self.push(None);
Ok(())
@@ -2085,6 +2264,29 @@ impl FromStr for Color {
}
}
+/// A hyperlink specification.
+#[derive(Clone, Debug)]
+pub struct HyperlinkSpec<'a> {
+ uri: Option<&'a [u8]>,
+}
+
+impl<'a> HyperlinkSpec<'a> {
+ /// Creates a new hyperlink specification.
+ pub fn open(uri: &'a [u8]) -> HyperlinkSpec<'a> {
+ HyperlinkSpec { uri: Some(uri) }
+ }
+
+ /// Creates a hyperlink specification representing no hyperlink.
+ pub fn close() -> HyperlinkSpec<'a> {
+ HyperlinkSpec { uri: None }
+ }
+
+ /// Returns the URI of the hyperlink if one is attached to this spec.
+ pub fn uri(&self) -> Option<&'a [u8]> {
+ self.uri
+ }
+}
+
#[derive(Debug)]
struct LossyStandardStream<W> {
wtr: W,
@@ -2124,9 +2326,15 @@ impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
fn supports_color(&self) -> bool {
self.wtr.supports_color()
}
+ fn supports_hyperlinks(&self) -> bool {
+ self.wtr.supports_hyperlinks()
+ }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec)
}
+ fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
+ self.wtr.set_hyperlink(link)
+ }
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
}
@@ -2170,8 +2378,8 @@ fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
#[cfg(test)]
mod tests {
use super::{
- Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
- StandardStream, WriteColor,
+ Ansi, Color, ColorSpec, HyperlinkSpec, ParseColorError,
+ ParseColorErrorKind, StandardStream, WriteColor,
};
fn assert_is_send<T: Send>() {}
@@ -2347,4 +2555,18 @@ mod tests {
assert!(color1.is_none(), "{:?} => {:?}", color, color1);
}
}
+
+ #[test]
+ fn test_ansi_hyperlink() {
+ let mut buf = Ansi::new(vec![]);
+ buf.set_hyperlink(&HyperlinkSpec::open(b"https://example.com"))
+ .unwrap();
+ buf.write_str("label").unwrap();
+ buf.set_hyperlink(&HyperlinkSpec::close()).unwrap();
+
+ assert_eq!(
+ buf.0,
+ b"\x1B]8;;https://example.com\x1B\\label\x1B]8;;\x1B\\".to_vec()
+ );
+ }
}