Графика вынесена из libc/ в новую библиотеку libbgi/:
- common/ — mode-agnostic математика и состояние (один исходник,
.rel попадает в оба driver-архива);
- bgi256/ + bgi16/ — mode-specific leaf'ы (raw-плот/чтение/спаны);
- include/ — graphics.h + gfx.h; _bgi.h — внутренний заголовок.
Собираются lib/bgi256.lib (и bgi16.lib в Фазе 2); выбор режима
линковкой через sprinter-cc --gfx 256|16. libc/ теперь без графики.
tests/bgi_img — тест спрайтов getimage/putimage/imagesize (5 операций
COPY/XOR/OR/AND/NOT + XOR-round-trip + self-check imagesize).
Проверен автотестом в MAME.
Примечание: make size-check пока красный (gfx_dbuf/gfx_demo выросли
после реорга) — закрыть по завершении миграции libbgi.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docs/mame-autotest.md — исчерпывающий документ: запуск, ввод команд,
скриншоты, завершение сессий, анализ, раскладка клавиатуры, все квирки.
Одного этого документа достаточно, чтобы работать с MAME в режиме
автотестирования.
- mame_interactive.py теперь единственный инструмент: авто-запускает exe
вводом пути (a:\<exe>+Enter), --step опционален (доп. ввод в программу),
умные дефолты снимков/таймаута.
- удалён mame_auto_test.py (старый метод через AUTORUN.BAT chainload) и
все упоминания AUTORUN.BAT в доках; интерактивный ввод его заменил.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
settextstyle/gettextsettings/textwidth/textheight: DEFAULT_FONT 8×8,
целочисленный масштаб 1..10, HORIZ/VERT (поворот 90° CCW), прозрачный
фон. Свой scaled-рендер (_bgi_draw_scaled) читает глиф через leaf
_bgi_font_rows (interleaved системный шрифт) и рисует блоки size×size
raw в одной W3-скобке. outtext/outtextxy переведены на него. Проверено
в MAME (tests/bgitest): размеры 1..4 + вертикальный текст.
Доки обновлены (Ф2d-1/2/3 готовы; осталось viewport/клиппинг).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
setlinestyle/getlinesettings: SOLID/DOTTED/CENTER/DASHED/USERBIT +
NORM/THICK. _bgi_styled_line — Брезенхэм с 16-битной маской (пропуск
пикселя по биту) и дублированием ±1 перпендикулярно оси для THICK;
SOLID+NORM идёт быстрым путём (accel _bgi_lineseg). line/lineto/linerel/
rectangle/drawpoly переведены на него. Проверено в MAME (tests/bgitest).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Растровые образы: imagesize (4 байта заголовка w,h + w*h пикселей),
getimage (захват прямоугольника), putimage с COPY/XOR/OR/AND/NOT_PUT.
Блит идёт raw в одной W3-скобке — добавлен _gfx_getpixel256_raw в gfx +
leaf _bgi_read_raw в drv256. Проверено в MAME (tests/bgitest): захват
спрайта, 3 COPY-копии, XOR/OR/COPY поверх фона.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
floodfill — скан-строчная заливка области до границы (self-bracket
чтение: корректно, но медленно; raw-оптимизация в TODO).
pieslice/sector — залитые сектора круга/эллипса: границу (центр→дуга→
центр) прогоняем через _bgi_poly_edge и заливаем min/max по строкам,
как fillpoly (для >180° возможен перелив — упрощение). Проверено в
MAME (tests/bgitest): floodfill круга, круговая диаграмма, штрих-сектор.
Доки/справочник/память обновлены (Ф2a-c готовы; Ф2d = images/viewport/
text-style/line-style — осталось).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
setfillstyle/getfillsettings + 10 стандартных 8×8 паттернов Borland.
bar теперь честно учитывает стиль заливки; bar3d (3D-брусок), fillpoly
(scanline min/max по строкам через брезенхэмовский проход рёбер),
fillellipse (полуширина строки через целочисленный _bgi_isqrt — без
32-бит). Общий _bgi_fill_span (SOLID/EMPTY/паттерн) с клипом, поверх
raw-hline в одной W3-скобке. Проверено в MAME (tests/bgitest): solid/
hatch бары, bar3d со slash, синий fillellipse, xhatch-треугольник.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Дуги/эллипсы через целочисленную тригонометрию Q7 (_bgi_trig.c, ×128) +
общий рисователь полилинией (_bgi_arc_draw.c). arc(x,y,st,end,r),
ellipse(x,y,st,end,xr,yr), drawpoly(n,pts). Проверено в MAME (tests/
bgitest): окружность/эллипс/дуга/полигон рисуются корректно.
ВАЖНО: тригонометрию считаем в int (Q7), НЕ через (long)…>>8 — первая
версия на 32-бит арифметике рисовала эллипс прямоугольником (SDCC/z80
криво собирает 32-бит; см. memory/avoid_32bit_arith_z80). Q7 даёт
радиус×значение ≤ 255×128 < 32767 — всё влезает в 16 бит.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Функционально-совместимый с Turbo-C <graphics.h> поверх gfx.h.
Архитектура: mode-agnostic математика (libc/bgi/*.c → sprinter.lib) +
driver-leaf'ы per-режим (libc/bgi/drv256/*.c → sprinter_gfx256.lib).
Режим выбирается линковкой: sprinter-cc --gfx 256 (16 — позже, тем же
leaf-split'ом). Один код работает в любом режиме без правок.
API: initgraph/closegraph/graphresult/cleardevice, set/get color+bkcolor,
getmaxx/y/color, put/getpixel, moveto/moverel/getx/gety, line/lineto/
linerel, rectangle, bar, circle, outtext/outtextxy. initgraph грузит
EGA-палитру 0..15. Пакетные примитивы (circle) — одна W3-скобка на
примитив (иначе на порядок медленнее). Проверено в MAME (tests/bgitest).
Попутно: gfx_getpixel256 в libc/gfx. size-check без регресса, baseline
обновлён. Детали: memory/bgi_two_lib_design, docs/TODO.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mame_interactive.py печатает произвольный текст в командную строку DSS,
дёргая поля AT/PS-2-клавиатуры :kbd:ms_naturl через Lua set_value
(at_keyboard сам генерит scancode'ы → SIO Z84C015 → DSS). Раньше
инъекция шла в ZX-матрицу :IO_LINE*, которую DSS не читает — отсюда
«нет эффекта». Полная раскладка char→(port,mask,shift) с авто-Shift.
Квирки: attotime.seconds целое (субсекунды через attoseconds/1e18),
клавишу держать коротко (~0.06с, иначе автоповтор), дискета без
AUTORUN.BAT → приглашение C:\>. Проверено end-to-end: dir<Enter> и
запуск теста набором a:\rt_test.exe<Enter> (Shift для ':' и '\').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AUTORUN.BAT chainload из system.bat (правится пользователем один раз)
+ mame_auto_test.py: кладёт .exe и сгенерированный AUTORUN.BAT на
дискету, гоняет MAME с Lua-таймингом (register_periodic +
manager.machine.time) для скриншотов и выхода по таймауту.
Natural keyboard (Lua natkeyboard:post/post_coded, -autoboot_command)
и прямая инъекция через ioport.fields[...]:set_value() не работают на
этом драйвере — перепробовано разными способами; AUTORUN.BAT chainload
оказался единственным надёжным путём запуска без участия человека.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
gfx_wait_vsync() и sleep() раньше предполагали, что КАЖДОЕ прерывание
на векторе 0xFF — кадровый тик; с CBL/клавиатурой на том же векторе
это уже не так.
gfx_wait_vsync(): вместо halt — polling бита 5 порта 0xFE (реальная
позиция луча, см. MAME kbd_fe_r), доступного пока включён CBL bit7
порта 0x004E. Разделяемое владение портом с CBL через
_cbl_port_ref/unref (тот же ref-counting паттерн, что у IM2-таблицы) —
cbl_close() возвращает "немой" режим вместо полного выключения, если
gfx ещё держит ссылку. Fallback на halt при таймауте.
sleep()/delayms(): калиброванный busy-wait по духу delayms.asm вместо
подсчёта halt-пробуждений. Калибровка одна на кадр (не на секунду —
не переполняет uint16_t и не требует умножения/32-бит арифметики),
общий движок libc/time/_sleep_calib.c для обеих функций. Fallback на
старое поведение при EBUSY (фрейм-хук занят другим irq_install()).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CBL уже имеет аппаратный буфер 256 Б (2×128, двойная буферизация на
стороне железа) — держать поверх него ещё одно кольцо в libc было бы
лишней копией. cbl_open(freq, fmt, pump_mode, underrun_mode, fill)
регистрирует callback, вызываемый из ISR за очередным блоком; он сам
пропихивает данные приложения (откуда угодно) через cbl_push_otir()/
cbl_push_accel() — без промежуточного буфера.
- два насоса: OTIR (порт 0x4F) и ACCEL (акселератор, спец-страница
EMM 0xFD@0xC000); OTIR+16-бит запрещён (EINVAL) — по исходнику MAME
порт данных физически не может собрать 16-бит сэмпл из пары байт;
- форматы CBL_FMT_MONO8/16/STEREO8/16, частоты 7.8..109к;
- CBL_UNDERRUN_APP (по умолчанию, недолив не наша забота) /
CBL_UNDERRUN_SILENCE (буфер тишины malloc'ится только в этом режиме);
- tests/cbltest: матрица 64 комбинации (2 насоса × 8 форматов × 4
частоты); tests/cblwav: banked-стрим речи с дискеты (физстраницы
кэшированы заранее — mem_get_page нельзя звать из fill()/ISR);
tests/cblstream: единственный случай с собственным кольцом уровня
приложения (диск нельзя читать из fill()).
Verified в MAME 2026-07-07 — все три теста работают.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- irq_ctc_install(handler, div2, div3) / irq_ctc_remove: канал 2 CTC
делит видеотакт 875 кГц (1 тик = 1 знакоместо), канал 3 считает от
него и прерывает; f = 875000/(div2*div3), div 0 = 256. Пресет
IRQ_CTC_VSYNC_DIV2/3 = 112*160 — точное начало кадра ~48.8 Гц БЕЗ
примеси клавиатуры (вектор 0x06 отделён от общего 0xFF)
- CTC-трамплин: полный сейв -> handler -> EI/RETI; RETI обязателен
(daisy chain Z84C015 снимает IUS только по опкоду RETI); к DSS не
чейнится — личное прерывание
- общая IM2-таблица под счётчиком ссылок (_irq_table.c): кадровый и
CTC-хендлеры независимы, последний unref возвращает I/IM 1;
atexit-уборка глушит CTC обязательно (иначе кГц-прерывания душат
шелл после выхода)
- порты/слова по docs/samples: CH0=0x10/CH2=0x12/CH3=0x13,
0x57/0xD7/вектор в CH0, стоп 0x03
- irqtest: CTC-vsync параллельно с кадровым + произвольная частота;
MAME: frame 48 Гц, ctc(vsync) 49 Гц (parallel frame жив),
ctc(50x50) 350 Гц точно по формуле, remove/выход чистые
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Первая версия висла на первом прерывании. Две причины (verified по
docs/samples/sprinterIntLib.asm, SIO_CTC_KEY.asm и исходникам MAME):
- DSS работает в IM 1 (обработчик 0x0038); I=0x3F — наследие Spectrum
ROM, НЕ таблица: чтение [I<<8|0xFF] давало мусор (0x00BF) и прыжок в
никуда. Чейн из трамплина теперь ВСЕГДА jp 0x0038 (interrupted-PC на
стеке = имитация RST 38); irq_remove безусловно восстанавливает IM 1
- CBL-фильтр по биту 7 порта 0xFE убран: при выключенном CBL бит
подтянут к 1 (MAME kbd_fe_r: data |= 0xE0) — каждый кадр ложно
уходил в чейн, user-handler не вызывался бы. Вернуть в Phase 2
вместе с поддержкой CBL
Попутно подтверждено: порт 0x19 = SIO-A RR0 (Z84C015), бит 0 = Rx
Available; вектора встроенной периферии SIO 0x10..0x1E / CTC 0x06
(заливка 257×H ловит любые); внешний вектор 0xFF.
irqtest: диагностика I до установки + фаза без ESTEX; прогон в MAME:
~49 Гц, клавиатура жива, remove останавливает тики, чистый выход.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Проще исходного плана (docs/im2_isr_design.md обновлён): отдельный
--memory im2 не понадобился.
- <irq.h>: irq_install(handler) — вызов ~50 Гц только на КАДРОВЫХ
прерываниях (клавиатура bit0:0x19 и CBL bit7:0xFE отфильтровываются);
штатный обработчик DSS чейнится ВСЕГДА (SMC-jp, адрес из старой
IM2-таблицы по регистру I) — клавиатура/SYSTIME/мышь живут
- вектор-таблица: 513 Б BSS + runtime-выравнивание; Sprinter шлёт
только вектор 0xFF, поэтому jp-заглушка лежит внутри самой таблицы
по смещению H — без linker-областей и правок crt0
- трамплин: полный сейв обоих наборов+IX/IY вокруг user-handler'а
(ex af,af' как .db 0x08 — апостроф ломает препроцессор SDCC)
- tiny/big: работает (код в W2); small/huge: EINVAL по проверке
адресов; irq_remove идемпотентен и висит на atexit (выход без
снятия = I в памяти умершего процесса = крах шелла); old_I==0 → IM1
- tests/irqtest: тики за 3 с против time() (~50 Гц), живая клавиатура
под handler'ом, остановка после remove, чистый выход
- docs: im2_isr_design (статус+дельты), libc-reference (<irq.h>), TODO
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Регрессия от 961cfb7 (gsinit зануляет _DATA, 2026-07-04): crt0_banked
заполняет таблицу физических страниц _bank_pages ДО gsinit, а тот её
стирал — трамплины banked-вызовов читали нули и прыгали в незамапленную
страницу. Висли ВСЕ banked-программы (banked/bankedbg/banklocl/
banktest); найдено MAME-смоуком. Тот коммит перенёс crt0-приватные
_estex_* в _CODE, но _bank_pages в runtime/bank.s пропустил.
- runtime/bank.s: _bank_pages → .area _CODE (RAM, всегда замаплен —
это же условие нужно и трамплину); +16 Б _CODE у программ с bank.s
- app.mk: exe теперь зависит от runtime/*.s — правка crt0/bank.s
перелинковывает тесты без make clean (фикс иначе не подхватывался)
- эталон размеров обновлён (+16 Б у banked/bankedbg/banklocl/
banktest/openenv — size-check поймал ровно их)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- docs/libc-reference.md — сводный справочник по всем заголовкам:
сигнатуры + описание + особенности ABI и квирки
- CLAUDE.md — сборка/проверка (make, size-check, MAME-workflow),
правила libc (1 функция = 1 модуль, internal _-модули, русские
комментарии, без = 0, asm-связки), ABI-шпаргалка, структура репо
- docs/TODO.md переписан: открытые задачи наверху (MAME/железо,
auto-banking, v2: BGI/IM2/audio, gfx-расширения, Port_Y),
закрытые этапы 5-10 сжаты в «Историю»; снят протухший пункт
«FILE API rewrite для v2» (сделан в v1), fprintf/fscanf и др.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- lib/Makefile: stale .rel удаляются сверкой списка модулей перед
упаковкой; штамп build/.modules триггерит перелинковку при любом
изменении состава исходников (при смене списка архив сносится —
на exFAT гранулярность mtime грубая, сравнение времён ненадёжно)
- top-level TESTS: все каталоги tests/ теперь собираются make all
(43 программы; banktest переименован из banked.exe — конфликт имён
с tests/banked); mdview2 добавлен в APPS
- размерный регресс: toolchain/size_check.py сверяет _CODE всех
программ с docs/size_baseline.tsv; make size-check / size-baseline
- заголовки: контракт затенения SDCC задокументирован в
docs/libc-headers.md; новый string.h (include_next + strlwr/strupr);
из sprinter_compat.h убраны макросы min/max — конфликтовали с
функциями из stdlib.h, и в Solid-C min/max тоже функции
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- единый ленивый буфер BUFSIZ=512 на чтение и запись с
автопереключением направления (_F_DIROUT, _file_sync: запись
сбрасывается write()-ом, readahead откатывается lseek-ом)
- статическая таблица OPEN_MAX=8 слотов вместо malloc для FILE;
_fclosall через atexit — exit() сбрасывает несброшенную запись
- fread/fwrite: мелкое через буфер (memcpy), блоки >= BUFSIZ — мимо
буфера одним syscall; горячие пути fgetc/fputc и сканер строк
fgets (LDI до '\n') — на asm, SDCC на эти цепочки генерит ~90
инструкций с IX-фреймом
- новое: ungetc (1 байт через hold, работает и на stdin),
fprintf/vfprintf (vsprintf+fwrite), fflush(NULL) = все потоки
- фиксы stdio-review: fwrite ставит _F_ERROR при короткой записи
(issue 3), fgets(n=1) возвращает пустую строку (issue 4)
- замер (MAME, HDD, 100 КБ): небуферизованная оценка ~144 с →
fgetc 5 с (×29), fgets ~1 с; дизайн и отвергнутые варианты —
docs/file-buffering-design.md
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- индексатор порезан на резюмируемые шаги index_begin/index_step/index_finish;
межшаговое состояние в статиках модуля, в docset_t не входит
- bg_build_start/bg_step: второй набор (UTF-8 при 8-битном первичном и
наоборот) строится в idle главного цикла; холдаун после клавиш, спиннер
погашен (g_bg_building) — фон незаметен
- F8 до готовности докручивает начатое фоном (ветка resume в build_doc),
а не строит заново; общий setup вынесен в doc_setup
- кодировка в статус-баре показывается сразу (детект/F8), не дожидаясь
конца индексации
- побочный фикс: UTF-конвертация впереди проверки останова — >4КБ абзац
больше не обрывает конвертацию остатка
- README.md (новый, v1.0 b3), CHANGELOG.md; дискета: README/DEMO/CHANGES
в трёх кодировках (пути автодетекта)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Новый модуль mdview2_hex.c (WITH_HEX в conf): формат
' 0x012340 │ 16×hex │ 16 print', 30 строк, один атрибут.
- Дамп всегда ОРИГИНАЛЬНОГО файла (orig_file_phys), не активного буфера;
ряд выровнен на 16 → один bank_read на ряд (не пересекает EMM-страницу),
fb()/W3 не используются.
- Printable по текущей кодировке: CP866 как есть, CP1251/KOI8 через
g_remap, UTF-8 — глиф на позиции лид-байта (continuation → '.') через
новый utf_cp_glyph(), выделенный из конвертера enc-модуля.
- Навигация: ±16 / ±480 / Home / End; одна строка — аппаратный scroll()
+ подрисовка одного ряда (как MD/RAW); процент в статусе.
- F4 — тумблер HEX ↔ прежний вид; F2 из HEX уводит в MD; позиция при
всех переходах через view_pos/view_reanchor (map_off orig ↔ active).
- F8 в HEX: hex-колонка неизменна, printable перерисовывается в новой
кодировке; позиция не двигается.
- Help: версия v1.0 (b1), строка F4.
exe 25725 → 27893 (+2168). Проверено в MAME.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Валюта позиции — байт-offset активного буфера:
- line_at_off(off): обратный перевод offset → MD-строка (бинарный поиск
по seg_off, оффсеты сегментов монотонны);
- map_off(off, from, to): пропорциональный перенос позиции между
буферами разного размера — один цикл restoring-деления, без
__mullong/__divulong, точность from/65536;
- raw_pos()/raw_reanchor(off) в RAW-модуле; raw_seed_from через
reanchor, raw_home стал приватным (только клавиша Home).
F2 RAW→MD: top_line = line_at_off(raw_pos()) — точное позиционирование.
F8 между готовыми наборами: view_pos → map_off → view_reanchor вместо
восстановления сохранённой позиции набора. Ленивая сборка — по-прежнему
с начала (в RAW с raw_reanchor(0) и откатом при неудаче).
Попутно: F8 в RAW-режиме больше не рисует MD-вид поверх RAW —
перерисовка по g_view.
exe 25100 → 25725 (+625). Проверено в MAME.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
B2 stage2: общий цикл inline-форматирования/переносов/склейки в одном
scan_stream (mode: NONE / LIST / QUOTE / PLAIN); дублировавшиеся блоки
эмиссии пробела/символа, переноса с усечением и отката стиля — в одном
экземпляре. Старые имена — тонкие обёртки, API inline_scan для
table-модуля не изменился. styles_map умерла: emph_to_attr(ls, ATTR_TEXT)
тождественна ей.
Индексатор 9839 → 9315 Б. Проверено в MAME: переносы заголовков/списков/
цитат, таблицы, inline-маркеры на границе переноса, жёсткие переносы.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Все четыре crt0 (default/small/minimal/banked): gsinit теперь зануляет
_DATA и _BSS через общий zero_area, затем копирует _INITIALIZER.
Явные `= 0` у глобалов/статиков больше не нужны (они жгли байты
_INITIALIZER в образе). crt0-приватные переменные, записываемые ДО
gsinit (_estex_startup_ix и др.), перенесены из _DATA в _CODE (RAM).
sprinter-cc: новая опция --max-allocs N → SDCC --max-allocs-per-node
(агрессивнее аллокация регистров, меньше/быстрее код ценой времени
компиляции).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
render_full_status форсирует перерисовку чисел через local_loading=UCHAR_MAX
(сентинел), а не отдельным force_redraw в условии. Отдельный 4-й терм + запись
флага опрокидывали render_md_status_numbers в IX-стек-фрейм (все локали в
память, +68 Б). Вынос local_* в file-scope разгрузил регистровый аллокатор
SDCC — функция осталась на регистрах. Итог даже меньше базы (28215 Б).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
calc_md_pct/calc_raw_pct тянули 32-битное деление __divulong (+__muluint2ulong)
ради показа процента в статусе. Оба дают операнды ≤16 бит (≤18432 / ≤1024),
переполняет только *100. Новый pct16() масштабирует оба вниз и считает долю
циклом-вычитанием — 66 Б, НОЛЬ подтянутых арифм-хелперов. Точность ±1%
(на границах точно), для индикатора прокрутки незаметно.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Тест-файлы лимита 256 КБ (TABLES/LINES/HUGE) проверены в MAME и сняты с
диска. Сами файлы и генератор остаются в testfiles/ как архив для повтора.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Лимит строк не показывал предупреждение: g_trunc_cause=TRUNC_LINES
ставился в emit_seg, но главный цикл выходит по n_lines<max_lines ДО
вызова emit_seg в переполненном состоянии (для code-block — один
emit_seg на строку). Теперь ловим после цикла по признаку p<file_size
(остановились, файл не кончился).
2. Файл >256 КБ больше не отвергаем экраном ошибки, а КЛАМПим: читаем
первые 256 КБ, индексатор дописывает строку TRUNC_FILE (File too large
- truncated at 256 KB). Приоритет ниже content/lines. Текст ошибки -2
поправлен (был 'size > 128K').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Вьювер склеивает подряд идущие непустые строки в один абзац (markdown
soft-wrap), из-за чего простые строки сворачивались в ~2752 экранных и
лимит 18432 не достигался. Завернул содержимое в code fence (verbatim,
1:1 строка-источник = экранная строка) -> 22000 строк > 18432.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
make run пересобирает образ через floppy, затирая прежний диск. Теперь
floppy генерирует BIG.MD (README+READMEBG ×2 ~216 КБ → CP866) и кладёт
его рядом с README/UTF8TEST — образ всегда содержит файл >128 КБ для
проверки лимита 256 КБ. Состав переопределяется: make floppy BIG_SRCS=...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- status-bar: dirty-tracking (числа/процент/кодировка перерисовываются
только при изменении), поле кодировки сдвинуто к DIV1_X-10 (8 симв.)
- md_key: HOME/END не перерисовывают экран, если позиция не меняется
- help: версия v1.0(a3), добавлены F2/F3 (RAW/Wrap), компактные секции
- enc: детекция по 5 частотным буквам и сэмплу 1КБ; ENC_UNSUPPORTED (UTF16/32)
- libc: добавлены min()/max() (naked, <stdlib.h>) + сборка в lib/Makefile
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MD-навигация после загрузки (стрелки/PgUp/PgDn/Home/End/←/→) вынесена из
switch в main() в md_key(scan) — peer к raw_key(): возвращает 1/0, сама
перерисовывает область+статус. main() теперь симметричен для обоих видов:
F-клавиши (F1/F8/F10, для RAW ещё F2/F3) разбираются в цикле, навигация
делегируется md_key()/raw_key().
HPAN_STEP вынесен в mdview2.h (был продублирован в ядре и raw). load_key()
(навигация во время прогрессивной загрузки, bounded по drawable_lines)
остаётся в ядре — у неё нет RAW-аналога.
Поведение сохранено (F1 теперь без лишнего render_updated_status — show_help
и так перерисовывает всё). Размер: exe 28115→28173 (+58 Б — стоимость
границы функции, как у raw_key). Сборка чистая.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- mdview2_view.c → mdview2_md.c: модуль уже содержит отрисовку MD-документа
из рендер-кэша + скролл + статус-бар, т.е. это парный к mdview2_raw.c вид
(MD ↔ RAW). Переименование делает пару явной.
- mdview2.c: обновлён устаревший заголовок-комментарий («Фаза 0 — копия
mdview.c») на описание ядра + карту модулей; убраны осиротевшие после
выноса комментарии; нормализованы баннеры секций (рендер-кэш / примитивы
экрана+EMM / загрузка файла / doc-slots / loading-loop / точка входа).
- mdview2.h: освежён заголовок-комментарий под текущую раскладку модулей.
Только переименование и комментарии/баннеры — поведение и размер не
меняются (exe 28115, как до). Сборка чистая.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
В RAW-режиме offset ряда под экраном (raw_bot) велся инкрементально в
предположении, что экран всегда полон контентом. После Wrap → конец файла
→ Unwrap контент кончается в середине экрана, raw_bot рассинхронизировался
(raw_scroll_up1 делал raw_bot = raw_prev(raw_bot)), и guard raw_bot >=
file_size в scroll-down ложно проходил → дубликат последней строки внизу.
Фикс: убран хрупкий raw_bot. raw_scroll_down1 проходит VIEW_H рядов от
raw_top и скроллит вниз только если контент реально уходит за нижний край
(иначе внизу была бы пустая строка). Кнопка «вниз» теперь работает лишь
когда под экраном есть контент; иначе доступна только «вверх».
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Новый модуль mdview2_raw.c (+ mdview2.h с общими константами/атрибутами и
extern'ами) — первый шаг разбиения монолита. Опционален через mdview2_conf.h
(#define WITH_RAW): при 0 — пустой объектник, нулевой расход (проверено:
размер как до RAW).
RAW-просмотр (без markdown-форматирования):
- работает по активному буферу (8-бит как есть / UTF-8 декодированный), 1 байт
= 1 ячейка, \t→пробел, ремап CP1251/KOI8 на отрисовке;
- два под-режима: wrap (перенос кратно 80) и hscroll (одна строка + ←/→);
- прокрутка на 1 строку через аппаратный scroll + отрисовка одной строки;
вывод char-буфером (bios_write_until по фону ATTR_TEXT), без win_rest/scratch;
- индекс/кэш markdown не используются, 0 доп. EMM.
Клавиши/меню:
- F2 — тумблер RAW↔MD (запоминает под-режим RAW);
- F3 — Wrap/Unwrap (только в RAW), метка показывает целевой режим;
- меню перестроено: блоки по 8 кол (col i*8), номера всех 10 клавиш без 'F'
(' 1'..' 9','10'), текст-функция 6 симв. сразу за номером и только когда
функция доступна; F8 сокращён до CodePg.
Инкрементальная UTF-8→CP866 конвертация: вместо полного прохода перед
индексацией — чанками впереди позиции чтения (CONV_MARGIN), первый экран
появляется быстро. Конвертер читает оригинал через cv_read (своя W3-страница),
index_lines докручивает конвертацию; progress_tick рисует по текущему виду
(MD/RAW), без мелькания чужого вида.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A.1: таблицы ремапа cp1251/koi8r 256→128 (старшие байты; младшие в
ремапе не используются — win_rest_remap трогает только ch>=0x80).
A.2: conv_emit_cp switch → таблица структур utf_sym_t {utf8, cp866}
(читаемо, добавление символа = одна строка; … и BOM — спецветки).
A.3: common_* цепочки сравнений → таблицы детекции + in_set10.
B1: удалён мёртвый код в scan_join_stream — условия
`if(!soft_break)...else q++` во всех непробельных ветках
(там soft_break всегда 0, т.к. ch!=' ').
_CODE (mdview2.c): 23284 → 22246 байт. Поведение не менялось.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Детекция при открытии (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>