use anstyle::Style;
use std::borrow::Borrow;
use syntect::highlighting::HighlightState;
use syntect::parsing::ParseState;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(super) enum MarginControl {
Margin,
NoMargin,
}
#[derive(Debug, PartialEq, Clone)]
pub struct InlineAttrs {
pub(super) style: Style,
pub(super) indent: u16,
pub(super) quote_bar_cols: Vec<u16>,
}
impl Default for InlineAttrs {
fn default() -> Self {
InlineAttrs {
style: Style::new(),
indent: 0,
quote_bar_cols: Vec::new(),
}
}
}
impl<T> From<T> for InlineAttrs
where
T: Borrow<StyledBlockAttrs>,
{
fn from(attrs: T) -> Self {
InlineAttrs {
style: attrs.borrow().style,
indent: attrs.borrow().indent,
quote_bar_cols: attrs.borrow().quote_bar_cols.clone(),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ListItemKind {
Unordered,
Ordered(u64),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ListItemState {
StartItem,
ItemText,
ItemBlock,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum InlineState {
InlineText,
InlineBlock,
InlineLink,
ListItem(ListItemKind, ListItemState),
}
#[derive(Debug, PartialEq, Clone)]
pub struct StyledBlockAttrs {
pub(super) margin_before: MarginControl,
pub(super) indent: u16,
pub(super) style: Style,
pub(super) quote_bar_cols: Vec<u16>,
}
impl StyledBlockAttrs {
pub(super) fn without_margin_before(self) -> Self {
StyledBlockAttrs {
margin_before: MarginControl::NoMargin,
..self
}
}
pub(super) fn with_margin_before(self) -> Self {
StyledBlockAttrs {
margin_before: MarginControl::Margin,
..self
}
}
pub(super) fn indented(mut self, extra: u16) -> Self {
self.indent += extra;
self
}
pub(super) fn block_quote(mut self) -> Self {
self.quote_bar_cols.push(self.indent);
StyledBlockAttrs {
indent: self.indent + 2,
style: self.style.italic(),
..self
}
}
}
impl Default for StyledBlockAttrs {
fn default() -> Self {
StyledBlockAttrs {
margin_before: MarginControl::NoMargin,
indent: 0,
style: Style::new(),
quote_bar_cols: Vec::new(),
}
}
}
impl<T> From<T> for StyledBlockAttrs
where
T: Borrow<InlineAttrs>,
{
fn from(attrs: T) -> Self {
StyledBlockAttrs {
indent: attrs.borrow().indent,
style: attrs.borrow().style,
quote_bar_cols: attrs.borrow().quote_bar_cols.clone(),
..StyledBlockAttrs::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HighlightBlockAttrs {
pub(super) parse_state: ParseState,
pub(super) highlight_state: HighlightState,
pub(super) indent: u16,
}
#[derive(Debug, PartialEq)]
pub struct LiteralBlockAttrs {
pub(super) indent: u16,
pub(super) style: Style,
}
#[derive(Debug, PartialEq)]
pub struct HtmlBlockAttrs {
pub(super) initial_indent: u16,
pub(super) indent: u16,
pub(super) style: Style,
}
#[derive(Debug, PartialEq)]
pub enum StackedState {
StyledBlock(StyledBlockAttrs),
HighlightBlock(HighlightBlockAttrs),
LiteralBlock(LiteralBlockAttrs),
HtmlBlock(HtmlBlockAttrs),
RenderedImage,
TableBlock,
Inline(InlineState, InlineAttrs),
}
impl From<StyledBlockAttrs> for StackedState {
fn from(attrs: StyledBlockAttrs) -> Self {
StackedState::StyledBlock(attrs)
}
}
impl From<HighlightBlockAttrs> for StackedState {
fn from(attrs: HighlightBlockAttrs) -> Self {
StackedState::HighlightBlock(attrs)
}
}
impl From<LiteralBlockAttrs> for StackedState {
fn from(attrs: LiteralBlockAttrs) -> Self {
StackedState::LiteralBlock(attrs)
}
}
impl From<HtmlBlockAttrs> for StackedState {
fn from(attrs: HtmlBlockAttrs) -> Self {
StackedState::HtmlBlock(attrs)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TopLevelAttrs {
pub(super) margin_before: MarginControl,
}
impl TopLevelAttrs {
pub(super) fn margin_before() -> Self {
TopLevelAttrs {
margin_before: MarginControl::Margin,
}
}
}
impl Default for TopLevelAttrs {
fn default() -> Self {
TopLevelAttrs {
margin_before: MarginControl::NoMargin,
}
}
}
const MAX_STATES: usize = 100;
#[derive(Debug, PartialEq)]
pub struct StateStack {
top_level: TopLevelAttrs,
states: Vec<StackedState>,
}
impl StateStack {
fn new(top_level: TopLevelAttrs) -> Self {
StateStack {
top_level,
states: Vec::with_capacity(20),
}
}
pub(crate) fn push(mut self, state: StackedState) -> StateStack {
assert!(
MAX_STATES > self.states.len(),
"More than {MAX_STATES} levels of nesting reached.
Report an issue to https://github.com/swsnr/mdcat/issues
including the document causing this panic.",
);
self.states.push(state);
self
}
pub(crate) fn current(self, state: StackedState) -> State {
State::Stacked(self, state)
}
pub(crate) fn pop(self) -> State {
let StateStack {
mut states,
top_level,
} = self;
match states.pop() {
None => State::TopLevel(top_level),
Some(state) => StateStack { top_level, states }.current(state),
}
}
}
#[derive(Debug, PartialEq)]
pub enum State {
TopLevel(TopLevelAttrs),
Stacked(StateStack, StackedState),
}
impl State {
pub(super) fn stack_onto(top_level: TopLevelAttrs) -> StateStack {
StateStack::new(top_level)
}
pub(super) fn and_data<T>(self, data: T) -> StateAndData<T> {
StateAndData(self, data)
}
}
impl Default for State {
fn default() -> Self {
State::TopLevel(TopLevelAttrs::default())
}
}
impl From<TopLevelAttrs> for State {
fn from(attrs: TopLevelAttrs) -> Self {
State::TopLevel(attrs)
}
}
#[derive(Debug, PartialEq)]
pub struct StateAndData<T>(pub State, pub T);
impl<T> StateAndData<T> {
#[allow(clippy::unnecessary_wraps)]
pub fn ok<E>(self) -> Result<Self, E> {
Ok(self)
}
}