printer: add hyperlinks

This commit represents the initial work to get hyperlinks working and
was submitted as part of PR #2483. Subsequent commits largely retain the
functionality and structure of the hyperlink support added here, but
rejigger some things around.
This commit is contained in:
Lucas Trzesniewski
2023-07-08 00:56:50 +02:00
committed by Andrew Gallant
parent 86ef683308
commit 1a50324013
16 changed files with 1178 additions and 83 deletions

View File

@@ -1,13 +1,16 @@
use std::io;
use std::path::Path;
use grep::printer::{ColorSpecs, PrinterPath};
use grep::printer::{
ColorSpecs, HyperlinkPattern, HyperlinkSpan, PrinterPath,
};
use termcolor::WriteColor;
/// A configuration for describing how paths should be written.
#[derive(Clone, Debug)]
struct Config {
colors: ColorSpecs,
hyperlink_pattern: HyperlinkPattern,
separator: Option<u8>,
terminator: u8,
}
@@ -16,6 +19,7 @@ impl Default for Config {
fn default() -> Config {
Config {
colors: ColorSpecs::default(),
hyperlink_pattern: HyperlinkPattern::default(),
separator: None,
terminator: b'\n',
}
@@ -37,7 +41,7 @@ impl PathPrinterBuilder {
/// Create a new path printer with the current configuration that writes
/// paths to the given writer.
pub fn build<W: WriteColor>(&self, wtr: W) -> PathPrinter<W> {
PathPrinter { config: self.config.clone(), wtr }
PathPrinter { config: self.config.clone(), wtr, buf: vec![] }
}
/// Set the color specification for this printer.
@@ -52,6 +56,17 @@ impl PathPrinterBuilder {
self
}
/// Set the hyperlink pattern to use for hyperlinks output by this printer.
///
/// Colors need to be enabled for hyperlinks to be output.
pub fn hyperlink_pattern(
&mut self,
pattern: HyperlinkPattern,
) -> &mut PathPrinterBuilder {
self.config.hyperlink_pattern = pattern;
self
}
/// A path separator.
///
/// When provided, the path's default separator will be replaced with
@@ -80,6 +95,7 @@ impl PathPrinterBuilder {
pub struct PathPrinter<W> {
config: Config,
wtr: W,
buf: Vec<u8>,
}
impl<W: WriteColor> PathPrinter<W> {
@@ -89,10 +105,30 @@ impl<W: WriteColor> PathPrinter<W> {
if !self.wtr.supports_color() {
self.wtr.write_all(ppath.as_bytes())?;
} else {
let mut hyperlink = self.start_hyperlink_span(&ppath)?;
self.wtr.set_color(self.config.colors.path())?;
self.wtr.write_all(ppath.as_bytes())?;
self.wtr.reset()?;
hyperlink.end(&mut self.wtr)?;
}
self.wtr.write_all(&[self.config.terminator])
}
/// Starts a hyperlink span when applicable.
fn start_hyperlink_span(
&mut self,
path: &PrinterPath,
) -> io::Result<HyperlinkSpan> {
if self.wtr.supports_hyperlinks() {
if let Some(spec) = path.create_hyperlink_spec(
&self.config.hyperlink_pattern,
None,
None,
&mut self.buf,
) {
return Ok(HyperlinkSpan::start(&mut self.wtr, &spec)?);
}
}
Ok(HyperlinkSpan::default())
}
}