use crate::{AnsiStyle, LinkCapability};
use ansi_term::Style;
use std::borrow::Borrow;
use syntect::highlighting::HighlightState;
use syntect::parsing::ParseState;
#[derive(Debug, PartialEq, Copy, Clone)]
pub(super) enum MarginControl {
Margin,
NoMargin,
NoMarginForHTMLOnly,
}
#[derive(Debug, PartialEq, Clone)]
pub struct InlineAttrs {
pub(super) style: Style,
pub(super) indent: u16,
}
impl Default for InlineAttrs {
fn default() -> Self {
InlineAttrs {
style: Style::new(),
indent: 0,
}
}
}
impl<T> From<T> for InlineAttrs
where
T: Borrow<StyledBlockAttrs>,
{
fn from(attrs: T) -> Self {
InlineAttrs {
style: attrs.borrow().style,
indent: attrs.borrow().indent,
}
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ListItemKind {
Unordered,
Ordered(u64),
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ListItemState {
StartItem,
ItemText,
ItemBlock,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum InlineState {
InlineText,
InlineLink(LinkCapability),
ListItem(ListItemKind, ListItemState),
}
#[derive(Debug, PartialEq, Clone)]
pub struct StyledBlockAttrs {
pub(super) margin_before: MarginControl,
pub(super) indent: u16,
pub(super) style: Style,
}
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 without_margin_for_html_only(self) -> Self {
StyledBlockAttrs {
margin_before: MarginControl::NoMarginForHTMLOnly,
..self
}
}
pub(super) fn block_quote(self) -> Self {
StyledBlockAttrs {
indent: self.indent + 4,
style: self.style.italic(),
..self
}
}
}
impl Default for StyledBlockAttrs {
fn default() -> Self {
StyledBlockAttrs {
margin_before: MarginControl::NoMargin,
indent: 0,
style: Style::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,
..StyledBlockAttrs::default()
}
}
}
#[derive(Debug, PartialEq)]
pub struct HighlightBlockAttrs {
pub(super) ansi: AnsiStyle,
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 enum StackedState {
StyledBlock(StyledBlockAttrs),
HighlightBlock(HighlightBlockAttrs),
LiteralBlock(LiteralBlockAttrs),
RenderedImage,
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)
}
}
#[derive(Debug, PartialEq)]
pub struct TopLevelAttrs {
pub(super) margin_before: MarginControl,
}
impl TopLevelAttrs {
pub(super) fn margin_before() -> Self {
TopLevelAttrs {
margin_before: MarginControl::Margin,
}
}
pub(super) fn no_margin_for_html_only() -> Self {
TopLevelAttrs {
margin_before: MarginControl::NoMarginForHTMLOnly,
}
}
}
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 {
if MAX_STATES <= self.states.len() {
panic!(
"More than {} levels of nesting reached.
Report an issue to https://github.com/lunaryorn/mdcat/issues
including the document causing this panic.",
MAX_STATES
)
}
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 { states, top_level }.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) -> (Self, T) {
(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)
}
}