mdview2: лимит файла 256 КБ, обрыв с сообщением вместо потери строк

- MAX_PAGES 8->16 (256 КБ), MAX_INDEX_PAGES/MAX_CACHE_DIR_PAGES 8->9
  (18432 строк), кап контент-кэша 64->40 стр./набор (80 на оба).
  Бюджет worst-case (UTF-8 Latin+BOM): ~150 из 215 EMM-страниц.
- При исчерпании контент-кэша (cache_reserve==0) или лимита строк
  индексация обрывается и последняя строка заменяется предупреждением
  (IF_TRUNC_MSG, рисуется вживую с ATTR_WARN — жёлтый по красному),
  без хвоста пустых строк. Раньше переполнение молча давало len=0
  (пустые строки) без какого-либо индикатора.
- help: лимиты обновлены (256 КБ / 18432 строк).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 20:48:35 +03:00
parent 733746572c
commit bc3483c2dd
5 changed files with 55 additions and 7 deletions
+30 -2
View File
@@ -241,6 +241,12 @@ uint8_t g_ncells = 0; /* ячеек в текущем сег
static uint8_t g_ncells_at_space = 0; /* снимок g_ncells на последнем пробеле (для усечения при переносе) */
static uint8_t g_skip_flush = 0; /* следующий emit_seg пропустит lag-флаш (pending уже зафлашен вручную, напр. перед таблицей) */
/* Обрыв индексации: причина (0 / TRUNC_CONTENT / TRUNC_LINES) и строка, на
* которой упёрлись. Выставляются ОДИН раз (первая причина побеждает); по ним
* index_lines() в конце пишет строку-сообщение (IF_TRUNC_MSG, рисуется вживую). */
static uint8_t g_trunc_cause = 0;
static uint16_t g_trunc_line = 0;
/* Пишет одну (char,attr)-ячейку в g_cells, молча игнорируя переполнение
* MAX_CACHE_LINE_LEN. Оставлена ФУНКЦИЕЙ намеренно: инлайн в сильно
* регистро-нагруженный скан-цикл на Z80/SDCC увеличивает спиллы и замедляет
@@ -274,6 +280,9 @@ static void seg_commit_cells(uint16_t line_idx)
if (cache_reserve((uint16_t)(g_ncells * 2u), &out_rec.page, &out_rec.off)) {
cache_commit(out_rec.page, out_rec.off, g_cells, (uint16_t)(g_ncells * 2u));
} else {
/* Контент-кэш исчерпан: фиксируем причину и строку обрыва (один раз).
* index_lines() оборвёт цикл и перезапишет эту строку сообщением. */
if (!g_trunc_cause) { g_trunc_cause = TRUNC_CONTENT; g_trunc_line = line_idx; }
out_rec.page = 0; out_rec.off = 0; out_rec.len = 0;
}
cache_dir_put(line_idx, &out_rec);
@@ -283,7 +292,11 @@ static void seg_commit_cells(uint16_t line_idx)
static void emit_seg(uint32_t off, uint8_t style, uint8_t ckind, uint8_t cont)
{
(void)ckind; /* тип сегмента восстанавливается флагами idx-записи */
if (n_lines >= max_lines) { index_truncated = 1; return; }
if (n_lines >= max_lines) {
index_truncated = 1;
if (!g_trunc_cause) { g_trunc_cause = TRUNC_LINES; g_trunc_line = (uint16_t)(max_lines - 1); }
return;
}
cur_rec.off = off;
cur_rec.flags = (uint8_t)(cont ? IF_CONT : 0);
cur_rec.style = (uint8_t)(style & 7u);
@@ -687,11 +700,13 @@ void index_lines(void)
uint8_t in_block = 0;
n_lines = 0;
index_truncated = 0;
g_trunc_cause = 0;
g_trunc_line = 0;
cur_seg_off = 0xFFFFFFFFu; /* пока не эмитили ни одного сегмента */
if (file_size == 0) return;
uint32_t p = 0;
while (p < file_size && n_lines < max_lines && !g_abort) {
while (p < file_size && n_lines < max_lines && !g_abort && !g_trunc_cause) {
/* UTF-8: держим конвертацию впереди позиции чтения (включая look-ahead
* склейки/классификации ~ один абзац). file_size при этом = доступная
@@ -957,6 +972,19 @@ void index_lines(void)
* комментарий) — последняя эмитированная строка файла так и остаётся
* незафлашенной, её ячейки ещё в g_cells; коммитим здесь. */
if (n_lines > 0) seg_commit_cells((uint16_t)(n_lines - 1));
/* Обрыв по контенту/лимиту строк (не путать с пользовательским g_abort):
* документ заканчиваем строкой-сообщением на g_trunc_line. Сообщение
* рисуется вживую (IF_TRUNC_MSG) — место в контент-кэше ему не нужно, что
* и снимает тупик «кэш полон, а сообщение тоже надо закэшировать». */
if (g_trunc_cause && !g_abort) {
cache_rec_t r;
r.page = 0; r.off = 0; r.len = 0;
r.flags = IF_TRUNC_MSG; r.reserved = g_trunc_cause;
r.pad[0] = 0; r.pad[1] = 0;
cache_dir_put(g_trunc_line, &r);
n_lines = (uint16_t)(g_trunc_line + 1); /* документ кончается на строке-обрыве */
}
}
#define EM_NONE 0
#define EM_BOLD 1