use std::fmt::Display;
#[derive(Debug, Clone, PartialEq)]
pub enum Event<'a> {
Content(Content<'a>),
Begin(Grouping),
End,
Visual(Visual),
Script {
ty: ScriptType,
position: ScriptPosition,
},
Space {
width: Option<Dimension>,
height: Option<Dimension>,
},
StateChange(StateChange),
EnvironmentFlow(EnvironmentFlow),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Content<'a> {
Text(&'a str),
Number(&'a str),
Function(&'a str),
Ordinary {
content: char,
stretchy: bool,
},
LargeOp {
content: char,
small: bool,
},
BinaryOp {
content: char,
small: bool,
},
Relation {
content: RelationContent,
small: bool,
},
Delimiter {
content: char,
size: Option<DelimiterSize>,
ty: DelimiterType,
},
Punctuation(char),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Visual {
SquareRoot,
Root,
Fraction(Option<Dimension>),
Negation,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ScriptType {
Subscript,
Superscript,
SubSuperscript,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ScriptPosition {
Right,
AboveBelow,
Movable,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum StateChange {
Font(Option<Font>),
Color(ColorChange),
Style(Style),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Font {
BoldScript,
BoldItalic,
Bold,
Fraktur,
Script,
Monospace,
SansSerif,
DoubleStruck,
Italic,
BoldFraktur,
SansSerifBoldItalic,
SansSerifItalic,
BoldSansSerif,
UpRight,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Style {
Display,
Text,
Script,
ScriptScript,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ColorChange {
pub color: (u8, u8, u8),
pub target: ColorTarget,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ColorTarget {
Text,
Background,
Border,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Grouping {
Normal,
LeftRight(Option<char>, Option<char>),
Array(Box<[ArrayColumn]>),
Matrix {
alignment: ColumnAlignment,
},
Cases {
left: bool,
},
Equation {
eq_numbers: bool,
},
Align {
eq_numbers: bool,
},
Aligned,
SubArray {
alignment: ColumnAlignment,
},
Alignat {
pairs: u16,
eq_numbers: bool,
},
Alignedat {
pairs: u16,
},
Gather {
eq_numbers: bool,
},
Gathered,
Multline,
Split,
}
impl Grouping {
pub(crate) fn is_math_env(&self) -> bool {
!matches!(self, Self::Normal | Self::LeftRight(_, _))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EnvironmentFlow {
Alignment,
NewLine {
spacing: Option<Dimension>,
horizontal_lines: Box<[Line]>,
},
StartLines { lines: Box<[Line]> },
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum GroupingKind {
Normal,
OptionalArgument,
BeginEnd,
LeftRight,
Array { display: bool },
Matrix { ty: MatrixType, column_spec: bool },
Cases { left: bool, display: bool },
Equation { eq_numbers: bool },
Align { eq_numbers: bool },
Aligned,
SubArray,
Alignat { eq_numbers: bool },
Alignedat,
Gather { eq_numbers: bool },
Gathered,
Multline,
Split,
}
impl GroupingKind {
pub fn opening_str(&self) -> &'static str {
match self {
Self::Normal => "{",
Self::OptionalArgument => "[",
Self::BeginEnd => "\\begin",
Self::LeftRight => "\\left",
Self::Array { display: false } => "\\begin{array}",
Self::Array { display: true } => "\\begin{darray}",
Self::Matrix { ty, column_spec } => match (ty, column_spec) {
(MatrixType::Normal, true) => "\\begin{matrix*}",
(MatrixType::Normal, false) => "\\begin{matrix}",
(MatrixType::Small, true) => "\\begin{smallmatrix*}",
(MatrixType::Small, false) => "\\begin{smallmatrix}",
(MatrixType::Parens, true) => "\\begin{pmatrix*}",
(MatrixType::Parens, false) => "\\begin{pmatrix}",
(MatrixType::Brackets, true) => "\\begin{bmatrix*}",
(MatrixType::Brackets, false) => "\\begin{bmatrix}",
(MatrixType::Braces, true) => "\\begin{Bmatrix*}",
(MatrixType::Braces, false) => "\\begin{Bmatrix}",
(MatrixType::Vertical, true) => "\\begin{vmatrix*}",
(MatrixType::Vertical, false) => "\\begin{vmatrix}",
(MatrixType::DoubleVertical, true) => "\\begin{Vmatrix*}",
(MatrixType::DoubleVertical, false) => "\\begin{Vmatrix}",
},
Self::Cases { left, display } => match (left, display) {
(true, false) => "\\begin{cases}",
(true, true) => "\\begin{dcases}",
(false, false) => "\\begin{rcases}",
(false, true) => "\\begin{drcases}",
},
Self::Equation { eq_numbers: true } => "\\begin{equation}",
Self::Equation { eq_numbers: false } => "\\begin{equation*}",
Self::Align { eq_numbers: true } => "\\begin{align}",
Self::Align { eq_numbers: false } => "\\begin{align*}",
Self::Aligned => "\\begin{aligned}",
Self::SubArray => "\\begin{subarray}",
Self::Alignat { eq_numbers: true } => "\\begin{alignat}",
Self::Alignat { eq_numbers: false } => "\\begin{alignat*}",
Self::Alignedat => "\\begin{alignedat}",
Self::Gather { eq_numbers: true } => "\\begin{gather}",
Self::Gather { eq_numbers: false } => "\\begin{gather*}",
Self::Gathered => "\\begin{gathered}",
Self::Multline => "\\begin{multline}",
Self::Split => "\\begin{split}",
}
}
pub fn closing_str(&self) -> &'static str {
match self {
Self::Normal => "}",
Self::OptionalArgument => "]",
Self::BeginEnd => "\\end",
Self::LeftRight => "\\right",
Self::Array { display: false } => "\\end{array}",
Self::Array { display: true } => "\\end{darray}",
Self::Matrix { ty, column_spec } => match (ty, column_spec) {
(MatrixType::Normal, true) => "\\end{matrix*}",
(MatrixType::Normal, false) => "\\end{matrix}",
(MatrixType::Small, true) => "\\end{smallmatrix*}",
(MatrixType::Small, false) => "\\end{smallmatrix}",
(MatrixType::Parens, true) => "\\end{pmatrix*}",
(MatrixType::Parens, false) => "\\end{pmatrix}",
(MatrixType::Brackets, true) => "\\end{bmatrix*}",
(MatrixType::Brackets, false) => "\\end{bmatrix}",
(MatrixType::Braces, true) => "\\end{Bmatrix*}",
(MatrixType::Braces, false) => "\\end{Bmatrix}",
(MatrixType::Vertical, true) => "\\end{vmatrix*}",
(MatrixType::Vertical, false) => "\\end{vmatrix}",
(MatrixType::DoubleVertical, true) => "\\end{Vmatrix*}",
(MatrixType::DoubleVertical, false) => "\\end{Vmatrix}",
},
Self::Cases { left, display } => match (left, display) {
(true, false) => "\\end{cases}",
(true, true) => "\\end{dcases}",
(false, false) => "\\end{rcases}",
(false, true) => "\\end{drcases}",
},
Self::Equation { eq_numbers: true } => "\\end{equation}",
Self::Equation { eq_numbers: false } => "\\end{equation*}",
Self::Align { eq_numbers: true } => "\\end{align}",
Self::Align { eq_numbers: false } => "\\end{align*}",
Self::Aligned => "\\end{aligned}",
Self::SubArray => "\\end{subarray}",
Self::Alignat { eq_numbers: true } => "\\end{alignat}",
Self::Alignat { eq_numbers: false } => "\\end{alignat*}",
Self::Alignedat => "\\end{alignedat}",
Self::Gather { eq_numbers: true } => "\\end{gather}",
Self::Gather { eq_numbers: false } => "\\end{gather*}",
Self::Gathered => "\\end{gathered}",
Self::Multline => "\\end{multline}",
Self::Split => "\\end{split}",
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum MatrixType {
Normal,
Small,
Parens,
Brackets,
Braces,
Vertical,
DoubleVertical,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ColumnAlignment {
Left,
Center,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ArrayColumn {
Column(ColumnAlignment),
Separator(Line),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DelimiterSize {
Big,
BIG,
Bigg,
BIGG,
}
impl DelimiterSize {
pub(crate) fn to_em(self) -> f32 {
match self {
DelimiterSize::Big => 1.2,
DelimiterSize::BIG => 1.8,
DelimiterSize::Bigg => 2.4,
DelimiterSize::BIGG => 3.,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DelimiterType {
Open,
Fence,
Close,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Line {
Solid,
Dashed,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RelationContent {
content: (char, Option<char>),
}
impl RelationContent {
pub(crate) fn single_char(content: char) -> Self {
Self {
content: (content, None),
}
}
pub(crate) fn double_char(first: char, second: char) -> Self {
Self {
content: (first, Some(second)),
}
}
pub fn encode_utf8_to_buf<'a>(&self, buf: &'a mut [u8]) -> &'a [u8] {
let mut len = self.content.0.encode_utf8(buf).len();
if let Some(second) = self.content.1 {
len += second.encode_utf8(&mut buf[len..]).len();
}
&buf[..len]
}
}
pub type Glue = (Dimension, Option<Dimension>, Option<Dimension>);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Dimension {
pub value: f32,
pub unit: DimensionUnit,
}
impl Dimension {
pub fn new(value: f32, unit: DimensionUnit) -> Self {
Self { value, unit }
}
}
impl Display for Dimension {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
const BP_PER_PT: f32 = 72. / 72.27;
const BP_PER_SP: f32 = 1. / 65536. * BP_PER_PT;
const BP_PER_DD: f32 = 1238. / 1157. * BP_PER_PT;
const BP_PER_CC: f32 = 12. * BP_PER_DD;
const EM_PER_MU: f32 = 1. / 18.;
let mut value = self.value;
let unit = match self.unit {
DimensionUnit::Em => "em",
DimensionUnit::Mu => {
value *= EM_PER_MU;
"mu"
}
DimensionUnit::Ex => "ex",
DimensionUnit::Mm => "mm",
DimensionUnit::Cm => "cm",
DimensionUnit::In => "in",
DimensionUnit::Bp => "pt",
DimensionUnit::Pt => {
value *= BP_PER_PT;
"pt"
}
DimensionUnit::Pc => {
value *= BP_PER_PT;
"pc"
}
DimensionUnit::Sp => {
value *= BP_PER_SP;
"pt"
}
DimensionUnit::Dd => {
value *= BP_PER_DD;
"pt"
}
DimensionUnit::Cc => {
value *= BP_PER_CC;
"pt"
}
};
write!(f, "{}{}", value, unit)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DimensionUnit {
Em,
Mu,
Ex,
Pt,
Pc,
In,
Bp,
Cm,
Mm,
Dd,
Cc,
Sp,
}