use crate::write_str::WriteStr;
use std::{
fmt::{self, Write as _},
io,
};
#[expect(missing_debug_implementations)]
pub struct Indented<'a, D: ?Sized> {
inner: &'a mut D,
needs_indent: bool,
indentation: &'static str,
}
impl<'a, D: ?Sized> Indented<'a, D> {
pub fn with_str(mut self, indentation: &'static str) -> Self {
self.indentation = indentation;
self
}
pub fn skip_initial(mut self) -> Self {
self.needs_indent = false;
self
}
pub fn into_inner(self) -> &'a mut D {
self.inner
}
}
impl<T> WriteStr for Indented<'_, T>
where
T: WriteStr + ?Sized,
{
fn write_str(&mut self, s: &str) -> io::Result<()> {
for (ind, line) in s.split('\n').enumerate() {
if ind > 0 {
self.inner.write_char('\n')?;
self.needs_indent = true;
}
if self.needs_indent {
if line.is_empty() {
continue;
}
self.inner.write_str(self.indentation)?;
self.needs_indent = false;
}
self.inner.write_str(line)?;
}
Ok(())
}
fn write_str_flush(&mut self) -> io::Result<()> {
self.inner.write_str_flush()
}
}
impl<T> fmt::Write for Indented<'_, T>
where
T: fmt::Write + ?Sized,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
for (ind, line) in s.split('\n').enumerate() {
if ind > 0 {
self.inner.write_char('\n')?;
self.needs_indent = true;
}
if self.needs_indent {
if line.is_empty() {
continue;
}
self.inner.write_str(self.indentation)?;
self.needs_indent = false;
}
self.inner.write_str(line)?;
}
Ok(())
}
}
pub fn indented<D: ?Sized>(f: &mut D) -> Indented<'_, D> {
Indented {
inner: f,
needs_indent: true,
indentation: " ",
}
}
#[derive(Clone, Debug)]
pub struct DisplayIndented<T> {
pub item: T,
pub indent: &'static str,
}
impl<T: fmt::Display> fmt::Display for DisplayIndented<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut indented = Indented {
inner: f,
needs_indent: true,
indentation: self.indent,
};
write!(indented, "{}", self.item)
}
}