Skip to main content

varar_core/
table_cells.rs

1//! Parses a Markdown/Gherkin table row (`| a | b |`) into trimmed cells + each
2//! cell's source span — port of `table-cells.ts` / `TableCells.java`.
3
4use crate::offsets::{java_strip, java_strip_leading, utf16_index, utf16_len};
5use crate::span::Span;
6
7/// Parallel, same-length trimmed cells and their source spans.
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct RowCells {
10    pub cells: Vec<String>,
11    pub cell_spans: Vec<Span>,
12}
13
14/// Splits `line_text` (a `| a | b |` row) into trimmed cells and each cell's
15/// source span. `line_start_offset` is the row's UTF-16 start offset in `source`.
16pub fn parse_row_cells(line_text: &str, line_start_offset: usize, source: &str) -> RowCells {
17    let (Some(first), Some(last)) = (line_text.find('|'), line_text.rfind('|')) else {
18        return RowCells {
19            cells: Vec::new(),
20            cell_spans: Vec::new(),
21        };
22    };
23    if last <= first {
24        return RowCells {
25            cells: Vec::new(),
26            cell_spans: Vec::new(),
27        };
28    }
29    // `|` is ASCII, so `first`/`last` byte indices order identically to UTF-16.
30    let inner = &line_text[first + 1..last];
31    let inner_start = utf16_index(line_text, first + 1);
32
33    let mut cells = Vec::new();
34    let mut cell_spans = Vec::new();
35    let mut cursor = 0usize;
36    for seg in inner.split('|') {
37        let trimmed = java_strip(seg);
38        let leading = utf16_len(seg) - utf16_len(java_strip_leading(seg));
39        let abs_start = line_start_offset + inner_start + cursor + leading;
40        cell_spans.push(Span::from_offsets(source, abs_start, abs_start + utf16_len(trimmed)));
41        cells.push(trimmed.to_string());
42        cursor += utf16_len(seg) + 1; // +1 for the '|' delimiter
43    }
44    RowCells { cells, cell_spans }
45}