#[cfg(feature = "ansi")]
use crate::nu_ansi_term::Style;
use std::{fmt, io};
use time::{format_description::FormatItem, formatting::Formattable, OffsetDateTime};
use tracing_subscriber::fmt::{format::Writer, time::FormatTime};
pub(crate) struct WriteAdaptor<'a> {
fmt_write: &'a mut dyn fmt::Write,
}
#[cfg(feature = "time")]
fn format_datetime(
into: &mut Writer<'_>,
now: OffsetDateTime,
fmt: &impl Formattable,
) -> fmt::Result {
let mut into = WriteAdaptor::new(into);
now.format_into(&mut into, fmt)
.map_err(|_| fmt::Error)
.map(|_| ())
}
impl<'a> WriteAdaptor<'a> {
pub(crate) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self {
Self { fmt_write }
}
}
impl<'a> std::io::Write for WriteAdaptor<'a> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let s = std::str::from_utf8(buf)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
self.fmt_write
.write_str(s)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
Ok(s.as_bytes().len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<'a> fmt::Debug for WriteAdaptor<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("WriteAdaptor { .. }")
}
}
#[derive(Clone, Debug)]
pub struct UtcTime<F = Vec<FormatItem<'static>>> {
format: F,
}
impl<F> FormatTime for UtcTime<F>
where
F: Formattable,
{
fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result {
let now = OffsetDateTime::now_utc();
#[cfg(feature = "ansi")]
if writer.has_ansi_escapes() {
let style = Style::new().dimmed();
write!(writer, "{}", style.prefix())?;
format_datetime(writer, now, &self.format)?;
write!(writer, "{}", style.suffix())?;
return Ok(());
}
format_datetime(writer, now, &self.format)
}
}
impl Default for UtcTime {
fn default() -> Self {
let format: Vec<FormatItem> = time::format_description::parse(
"[month][day] [hour]:[minute]:[second].[subsecond digits:6]",
)
.expect("Unable to make time formatter");
Self { format }
}
}
#[derive(Clone, Debug)]
#[cfg(feature = "local-time")]
pub struct LocalTime<F = Vec<FormatItem<'static>>> {
format: F,
}
#[cfg(feature = "local-time")]
impl Default for LocalTime {
fn default() -> Self {
let format: Vec<FormatItem> = time::format_description::parse(
"[month][day] [hour]:[minute]:[second].[subsecond digits:6]",
)
.expect("Unable to make time formatter");
Self { format }
}
}
#[cfg(feature = "local-time")]
impl<F> FormatTime for LocalTime<F>
where
F: Formattable,
{
fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result {
let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?;
#[cfg(feature = "ansi")]
if writer.has_ansi_escapes() {
let style = Style::new().dimmed();
write!(writer, "{}", style.prefix())?;
format_datetime(writer, now, &self.format)?;
write!(writer, "{}", style.suffix())?;
return Ok(());
}
format_datetime(writer, now, &self.format)
}
}