use std::{io, path::Path};
use termcolor::WriteColor;
use crate::{
color::ColorSpecs,
hyperlink::{self, HyperlinkConfig},
util::PrinterPath,
};
#[derive(Clone, Debug)]
struct Config {
colors: ColorSpecs,
hyperlink: HyperlinkConfig,
separator: Option<u8>,
terminator: u8,
}
impl Default for Config {
fn default() -> Config {
Config {
colors: ColorSpecs::default(),
hyperlink: HyperlinkConfig::default(),
separator: None,
terminator: b'\n',
}
}
}
#[derive(Clone, Debug)]
pub struct PathPrinterBuilder {
config: Config,
}
impl PathPrinterBuilder {
pub fn new() -> PathPrinterBuilder {
PathPrinterBuilder { config: Config::default() }
}
pub fn build<W: WriteColor>(&self, wtr: W) -> PathPrinter<W> {
let interpolator =
hyperlink::Interpolator::new(&self.config.hyperlink);
PathPrinter { config: self.config.clone(), wtr, interpolator }
}
pub fn color_specs(
&mut self,
specs: ColorSpecs,
) -> &mut PathPrinterBuilder {
self.config.colors = specs;
self
}
pub fn hyperlink(
&mut self,
config: HyperlinkConfig,
) -> &mut PathPrinterBuilder {
self.config.hyperlink = config;
self
}
pub fn separator(&mut self, sep: Option<u8>) -> &mut PathPrinterBuilder {
self.config.separator = sep;
self
}
pub fn terminator(&mut self, terminator: u8) -> &mut PathPrinterBuilder {
self.config.terminator = terminator;
self
}
}
#[derive(Debug)]
pub struct PathPrinter<W> {
config: Config,
wtr: W,
interpolator: hyperlink::Interpolator,
}
impl<W: WriteColor> PathPrinter<W> {
pub fn write(&mut self, path: &Path) -> io::Result<()> {
let ppath = PrinterPath::new(path.as_ref())
.with_separator(self.config.separator);
if !self.wtr.supports_color() {
self.wtr.write_all(ppath.as_bytes())?;
} else {
let status = self.start_hyperlink(&ppath)?;
self.wtr.set_color(self.config.colors.path())?;
self.wtr.write_all(ppath.as_bytes())?;
self.wtr.reset()?;
self.interpolator.finish(status, &mut self.wtr)?;
}
self.wtr.write_all(&[self.config.terminator])
}
fn start_hyperlink(
&mut self,
path: &PrinterPath,
) -> io::Result<hyperlink::InterpolatorStatus> {
let Some(hyperpath) = path.as_hyperlink() else {
return Ok(hyperlink::InterpolatorStatus::inactive());
};
let values = hyperlink::Values::new(hyperpath);
self.interpolator.begin(&values, &mut self.wtr)
}
}