mdview2: поддержка кодировок CP866/CP1251/KOI8-R/UTF-8 (F8)

- Детекция при открытии (BOM + эвристика по первым 4 КБ).
- 8-битные (CP866/CP1251/KOI8-R) — общий индекс/кэш, переключение
  мгновенным ремапом глифов [128-255] на отрисовке по attr (структурные
  глифы — рамка/HR/маркеры — не ремапятся).
- UTF-8 — отдельный набор: декодирование в CP866 (кириллица + ходовые
  символы: стрелки/галка/буллет/тире/кавычки/box), свой индекс/кэш.
- Два набора (docset_t g_doc[2]) со свапом «живых» глобалов; второй
  строится ЛЕНИВО при первом F8-переходе в него (build-on-demand).
- F8: цикл CP866→CP1251→KOI8R→UTF8; метка в меню видна только когда
  переключение возможно; во время сборки 8-бит первичного F8 крутит 8-бит.
- F1-справка: секция Encoding; меню разбито на блоки (F1/F8/F10).
- Фикс: g_doc обязан быть инициализирован (SDCC z80 не обнуляет статики
  надёжно) — иначе мусорный built вёл к показу неинициализированного набора.
- Убрана отладка времени обработки из статус-бара.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 11:00:49 +03:00
parent a6e0aacc80
commit a14f19b657
5 changed files with 640 additions and 68 deletions
+28 -9
View File
@@ -1,6 +1,8 @@
# mdview2 — поддержка кодировок (CP866 / CP1251 / KOI8-R / UTF-8)
Статус: ПЛАН (2026-06-24, ревизия 2). Реализация — отдельными фазами.
Статус: РЕАЛИЗОВАНО (2026-06-25). Все фазы сделаны; Фаза 4 — eager-кооперативным
вариантом (см. ниже), а не idle-build. Осталась только проверка на железе и
возможная оптимизация «не строить заведомо бесполезный вторичный набор».
## Цель
@@ -96,15 +98,32 @@ redraw, draw ремапит). Переиндексация только при
(если построен; иначе достроить — но при ленивом build обычно уже готов).
- Статус-бар: имя кодировки; меню (строка 31): «F8 Codepage».
## Фазы реализации
## Фазы реализации (ИТОГ)
1. **Ядро 8-бит**: ATTR_BOX; кэш хранит исходный байт; таблицы CP1251/KOI8R;
ремап в draw для CP1251/KOI8; кодировка задаётся константой для теста.
2. **UTF-8 набор**: utf_phys + конвертация + отдельный индекс/кэш; ручной
выбор UTF-8.
3. **Детекция** (BOM + эвристика) при загрузке.
4. **Нон-блокирующий main loop + ленивый idle-build** второго набора.
5. **F8** + статус/меню.
1. **Ядро 8-бит**: ATTR_BOX; кэш хранит исходный байт; таблицы CP1251/KOI8R;
ремап в draw (`win_rest_remap`).
2. **UTF-8 набор**: `alloc_and_convert_utf8` + `utf8_convert` (декодер 1/2/3-
байт, 4-байтные/битые → `?`); `utf_cyr_to_866[96]` + символьные подстановки
в `conv_emit_cp` (стрелки 0x18-0x1B, галка 0xFB, буллет 0xF9, тире/кавычки/
box/° и т.п.; «» → `<`/`>`, т.к. в CP866 гильеметов нет).
3. **Детекция** (BOM + эвристика), сэмпл — первые **4 КБ** (быстро); хвост-
обрезка multibyte на границе сэмпла не штрафуется.
4.**Сосуществование 2 наборов** (`docset_t g_doc[2]` + `doc_save/load/switch`,
свап «живых» глобалов). Сборка — **ленивая (build-on-demand)**: при старте
строится только первичный (показываемый) набор; UTF-8 конвертация тоже
ленивая (в `build_doc`, не до первого экрана → старт быстрый). Второй набор
достраивается `switch_encoding()` при первом F8-переходе в него (спиннер,
потом кэш). Eager-вариант отвергнут: удваивал старт и блокировал F8 на время
фоновой сборки.
5.**F8** полный цикл CP866→CP1251→KOI8R→UTF8→CP866 (внутри 8-бит — ремап,
на границе — `doc_switch`/ленивая сборка). Статус: `enc_name` кол.37. Меню
«F8 Codepage» показывается только когда переключение возможно (`g_f8_enabled`):
во время сборки 8-битного первичного F8 разрешён в `load_key` (только цикл
8-бит); во время сборки UTF-8 первичного метка F8 скрыта. F1-справка: секция
Encoding.
NB: меню-строка разбита на 10 блоков по 8 колонок, метки Fn кладутся в блок
(n-1)*8 (F1→0, F8→7, F10→9).
## Память
- 8-бит: src + scratch-страница для ремапа (1 стр.). Доп. индекса нет.