use crate::converter::tier1::tags::TagSpec;
const OUTPUT_CAPACITY_MIN: usize = 1024;
const OUTPUT_CAPACITY_MAX: usize = 256 * 1024;
const OUTPUT_CAPACITY_DIVISOR: usize = 3;
#[derive(Debug, Clone, Default)]
pub struct TableState {
pub rows: Vec<Vec<String>>,
pub current_row: Vec<String>,
pub current_cell: String,
pub in_thead: bool,
pub in_cell: bool,
pub seen_tbody_close: bool,
pub seen_tfoot: bool,
pub has_th: bool,
pub link_count: usize,
pub first_row_col_count: Option<usize>,
}
bitflags::bitflags! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct EscapeCtx: u8 {
const CODE = 1 << 1;
const PRE = 1 << 2;
const LINK = 1 << 3;
const BLOCKQUOTE = 1 << 4;
const HEADING = 1 << 5;
}
}
#[derive(Debug, Clone)]
pub struct OpenTag {
pub spec: &'static TagSpec,
pub content_start: usize,
pub prev_escape_ctx: EscapeCtx,
pub list_index: u16,
pub link_href: Option<String>,
pub link_title: Option<String>,
pub ol_start: u16,
pub name_range: std::ops::Range<usize>,
}
pub struct Tier1State {
pub stack: Vec<OpenTag>,
pub escape_ctx: EscapeCtx,
pub output: String,
pub list_depth: u16,
pub last_block_sep_pos: usize,
pub table_stack: Vec<TableState>,
}
impl Tier1State {
pub fn new(input_len: usize) -> Self {
Self {
stack: Vec::with_capacity(16),
escape_ctx: EscapeCtx::empty(),
output: String::with_capacity(
(input_len / OUTPUT_CAPACITY_DIVISOR)
.clamp(OUTPUT_CAPACITY_MIN, OUTPUT_CAPACITY_MAX),
),
list_depth: 0,
last_block_sep_pos: 0,
table_stack: Vec::new(),
}
}
pub fn cell_or_output_mut(&mut self) -> &mut String {
if let Some(ts) = self.table_stack.last_mut()
&& ts.in_cell
{
return &mut ts.current_cell;
}
&mut self.output
}
pub fn in_table_cell(&self) -> bool {
self.table_stack.last().is_some_and(|ts| ts.in_cell)
}
pub fn ensure_blank_line(&mut self) {
let out = &mut self.output;
if out.is_empty() {
return;
}
if out.ends_with("\n\n") {
return;
}
if out.ends_with('\n') {
out.push('\n');
} else {
out.push_str("\n\n");
}
}
pub fn ensure_newline(&mut self) {
if !self.output.is_empty() && !self.output.ends_with('\n') {
self.output.push('\n');
}
}
}