/* * mdview2_table.c — выровненная отрисовка markdown-таблиц. * * Разбор |-разделённых ячеек и эмиссия рамок/строк в общий буфер ячеек * рендера (gc_put/gc_fill, см. mdview2.h). Вызывается из index_lines() * ядра при обнаружении таблицы. Геометрия рамок (TBL_n), словарь стилей * (CK_n, INIT_STYLE_n) и cell-buffer API объявлены в mdview2.h. */ #include #include /* COLOR() / COLOR_* для атрибутов TBL_ATTR/ATTR_TEXT */ #include "mdview2.h" uint32_t row_end(uint32_t p) { while (p < file_size && fb(p) != '\n') p++; return p; } /* Начало контента первой ячейки строки (после ведущих пробелов и '|'). */ uint32_t table_first_cell(uint32_t row_start) { uint32_t p = row_start; while (p < file_size && fb(p) == ' ') p++; if (p < file_size && fb(p) == '|') p++; return p; } /* Следующая ячейка: [*cs,*ce) — обрезанный диапазон; *pp продвигается за '|'. * 0 — ячеек больше нет (включая хвостовую пустоту после последнего '|'). */ uint8_t table_next_cell(uint32_t *pp, uint32_t lineend, uint32_t *cs, uint32_t *ce) { uint32_t p = *pp; if (p >= lineend) return 0; uint32_t a = p; while (p < lineend && fb(p) != '|') p++; uint32_t b = p; uint8_t had_pipe = (uint8_t)(p < lineend && fb(p) == '|'); if (had_pipe) p++; *pp = p; while (a < b && fb(a) == ' ') a++; while (b > a && fb(b - 1) == ' ') b--; if (!had_pipe && a == b) return 0; *cs = a; *ce = b; return 1; } /* Строка-разделитель (|---|:-:|): каждая ячейка непустая и только '-'/':'. */ uint8_t table_is_sep_row(uint32_t row_start, uint32_t lineend) { uint32_t p = table_first_cell(row_start); uint32_t cs, ce; uint8_t n = 0; while (table_next_cell(&p, lineend, &cs, &ce)) { if (cs >= ce) return 0; for (uint32_t q = cs; q < ce; q++) { char c = fb(q); if (c != '-' && c != ':') return 0; } n++; } return (uint8_t)(n > 0); } /* Горизонтальная рамка в g_cells: left + (H×(w+2) + mid|right) по колонкам. */ void table_border(const uint8_t *widths, uint8_t ncols, char left, char mid, char right) { gc_put(left, TBL_ATTR); for (uint8_t c = 0; c < ncols; c++) { gc_fill(TBL_H, TBL_ATTR, (uint8_t)(widths[c] + 2)); gc_put((c == (uint8_t)(ncols - 1)) ? right : mid, TBL_ATTR); } } /* Строка данных в g_cells: │ <ячейка, добитая до widths[c]> │ … */ void table_data_row(uint32_t row_start, uint32_t lineend, const uint8_t *widths, uint8_t ncols) { uint32_t p = table_first_cell(row_start); uint32_t cs, ce; gc_put(TBL_V, TBL_ATTR); for (uint8_t c = 0; c < ncols; c++) { uint8_t got = table_next_cell(&p, lineend, &cs, &ce); gc_put(' ', TBL_ATTR); uint8_t rendered = 0; if (got && ce > cs) { uint8_t before = g_ncells; (void)inline_scan(cs, ce, 0, CK_OTHER, INIT_STYLE_PLAIN, ATTR_TEXT, 1); rendered = (uint8_t)(g_ncells - before); } if (rendered < widths[c]) gc_fill(' ', ATTR_TEXT, (uint8_t)(widths[c] - rendered)); gc_put(' ', TBL_ATTR); gc_put(TBL_V, TBL_ATTR); } }