bluegum 0.1.0

A tree printer with rich formatting, alternate values, debug info, and flexible structure - perfect for ASTs and complex data visualization
Documentation
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use {
  super::prefix::Glyph,
  crate::styles::Styles,
  owo_colors::OwoColorize,
  std::{
    fmt::Write,
    sync::Arc,
  },
  unicode_width::UnicodeWidthStr,
};

pub(crate) struct Line {
  pub(crate) prefix: String,
  pub(crate) line:   String,
  pub(crate) alt:    String,
  pub(crate) debug:  String,
}

pub(crate) struct Writer {
  pub(super) lines: Vec<Line>,
}

impl Writer {
  pub(crate) fn new() -> Self {
    Self { lines: vec![] }
  }
}

impl Writer {
  pub(crate) fn trim_line_endings(&mut self) {
    self.lines.iter_mut().for_each(|l| {
      l.prefix = l.prefix.trim().to_string();
      l.line = l.line.trim().to_string();
      l.alt = l.alt.trim().to_string();
      l.debug = l.debug.trim().to_string();
    });

    // if the last line is blank, remove it
    let pop_last = if let Some(l) = self.lines.last_mut() {
      anstream::adapter::strip_str(&l.prefix)
        .to_string()
        .trim()
        .is_empty()
        && anstream::adapter::strip_str(&l.line)
          .to_string()
          .trim()
          .is_empty()
        && anstream::adapter::strip_str(&l.alt)
          .to_string()
          .trim()
          .is_empty()
        && anstream::adapter::strip_str(&l.debug)
          .to_string()
          .trim()
          .is_empty()
    } else {
      false
    };

    if pop_last {
      self.lines.pop();
    }
  }

  pub(crate) fn write_prefix(&mut self, prefix: String) -> std::fmt::Result {
    self.lines.push(Line {
      prefix: prefix.trim().to_string(),
      line:   String::new(),
      alt:    String::new(),
      debug:  String::new(),
    });

    Ok(())
  }

  pub(crate) fn write_line(&mut self, s: String) -> std::fmt::Result {
    if let Some(Line {
      prefix,
      line,
      alt,
      debug,
    }) = self.lines.last_mut()
    {
      write!(line, "{}", s.trim())?;
    } else {
      self.lines.push(Line {
        prefix: String::new(),
        line:   s.trim().to_string(),
        alt:    String::new(),
        debug:  String::new(),
      });
    }

    Ok(())
  }

  pub(crate) fn write_alt(&mut self, s: String) -> std::fmt::Result {
    if let Some(Line {
      prefix,
      line,
      alt,
      debug,
    }) = self.lines.last_mut()
    {
      write!(alt, "{}", s.trim())?;
    } else {
      self.lines.push(Line {
        prefix: String::new(),
        line:   String::new(),
        alt:    s.trim().to_string(),
        debug:  String::new(),
      });
    }

    Ok(())
  }

  pub(crate) fn write_debug(&mut self, s: String) -> std::fmt::Result {
    if let Some(Line {
      prefix,
      line,
      alt,
      debug,
    }) = self.lines.last_mut()
    {
      write!(debug, "{}", s.trim())?;
    } else {
      self.lines.push(Line {
        prefix: String::new(),
        line:   String::new(),
        alt:    String::new(),
        debug:  s.trim().to_string(),
      });
    }

    Ok(())
  }
}