1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2024-12-12 19:18:24 +02:00
ripgrep/crates/core/path_printer.rs
Lucas Trzesniewski 1a50324013 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.
2023-09-25 14:39:54 -04:00

135 lines
3.8 KiB
Rust

use std::io;
use std::path::Path;
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,
}
impl Default for Config {
fn default() -> Config {
Config {
colors: ColorSpecs::default(),
hyperlink_pattern: HyperlinkPattern::default(),
separator: None,
terminator: b'\n',
}
}
}
/// A builder for constructing things to search over.
#[derive(Clone, Debug)]
pub struct PathPrinterBuilder {
config: Config,
}
impl PathPrinterBuilder {
/// Return a new subject builder with a default configuration.
pub fn new() -> PathPrinterBuilder {
PathPrinterBuilder { config: Config::default() }
}
/// 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, buf: vec![] }
}
/// Set the color specification for this printer.
///
/// Currently, only the `path` component of the given specification is
/// used.
pub fn color_specs(
&mut self,
specs: ColorSpecs,
) -> &mut PathPrinterBuilder {
self.config.colors = specs;
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
/// the given separator.
///
/// This is not set by default, and the system's default path separator
/// will be used.
pub fn separator(&mut self, sep: Option<u8>) -> &mut PathPrinterBuilder {
self.config.separator = sep;
self
}
/// A path terminator.
///
/// When printing a path, it will be by terminated by the given byte.
///
/// This is set to `\n` by default.
pub fn terminator(&mut self, terminator: u8) -> &mut PathPrinterBuilder {
self.config.terminator = terminator;
self
}
}
/// A printer for emitting paths to a writer, with optional color support.
#[derive(Debug)]
pub struct PathPrinter<W> {
config: Config,
wtr: W,
buf: Vec<u8>,
}
impl<W: WriteColor> PathPrinter<W> {
/// Write the given path to the underlying writer.
pub fn write_path(&mut self, path: &Path) -> io::Result<()> {
let ppath = PrinterPath::with_separator(path, self.config.separator);
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())
}
}