mdview2: прогрессивная загрузка (первый экран сразу, скролл во время индексации)
Препроцессинг 52КБ занимает ~10с; теперь UI не ждёт его завершения.
index_lines() кооперативно вызывает progress_tick() (без прерываний —
IM2 отложен):
- первый экран рисуется, как только готово ≥ VIEW_H строк (~0.3с);
- статус-бар показывает растущее число обработанных строк с многоточием
("L 1-30 / 247...");
- ↑↓ PgUp PgDn Home End (=последняя готовая страница) и F1 работают по
УЖЕ готовым строкам (drawable_lines = [0..n_lines-2], т.к. последний
сегмент ещё в g_cells до flush);
- Esc/F10 во время загрузки — корректный выход (прерывание индексации
флагом g_abort + штатный unload_file/pal_reset/clrscr).
После каждого тика форсируем ре-маппинг W3 (cur_page=0xFF), т.к.
отрисовка/WINREST/BIOS могли сбить страницу, на которую опирается fb().
Временно: debug-индикатор времени обработки "t=Ns" в зоне имени файла
(по просьбе — следить за временем при дальнейших оптимизациях).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+112
-9
@@ -30,6 +30,7 @@
|
||||
#include <sprinter.h>
|
||||
#include <sprinter_mem.h>
|
||||
#include <palette.h>
|
||||
#include <time.h> /* DEBUG: время обработки в статус-баре прогресса */
|
||||
|
||||
/* ---- Геометрия экрана -------------------------------------------- */
|
||||
|
||||
@@ -282,6 +283,15 @@ static uint8_t cur_page = 0xFF; /* 0xFF = в W3 ещё не отображ
|
||||
static uint8_t viewport_x = 0; /* горизонтальный сдвиг для nowrap-строк */
|
||||
static char filename[64] = {0};
|
||||
|
||||
/* Прогрессивная загрузка: рисуем первый экран и пускаем скролл, пока
|
||||
* index_lines() ещё досканирует файл (кооперативно, без прерываний). */
|
||||
static uint8_t g_loading = 0; /* 1 во время index_lines() */
|
||||
static uint8_t g_first_drawn = 0; /* первый экран уже нарисован */
|
||||
static uint8_t g_abort = 0; /* F10/Esc во время загрузки → прервать индексацию */
|
||||
static uint16_t g_last_prog = 0; /* n_lines на последнем обновлении статуса */
|
||||
static datetime_t g_load_t0; /* DEBUG: старт обработки (для времени в статусе) */
|
||||
static void progress_tick(void); /* определена ниже (нужна в index_lines) */
|
||||
|
||||
#define HPAN_STEP 8u
|
||||
|
||||
/* Спиннер в статус-баре (col=8,row=0).
|
||||
@@ -1291,10 +1301,11 @@ static void index_lines(void)
|
||||
if (file_size == 0) return;
|
||||
|
||||
uint32_t p = 0;
|
||||
while (p < file_size && n_lines < max_lines) {
|
||||
while (p < file_size && n_lines < max_lines && !g_abort) {
|
||||
|
||||
|
||||
if ((n_lines & 15) == 0)
|
||||
if (g_loading)
|
||||
progress_tick(); /* первый экран + статус + скролл по готовым данным */
|
||||
else if ((n_lines & 15) == 0)
|
||||
spinner_tick();
|
||||
|
||||
/* Пустая строка — разделитель параграфов.
|
||||
@@ -1562,14 +1573,23 @@ static void draw_viewport_from_cache(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Число строк, готовых к показу. Во время загрузки последняя эмитированная
|
||||
* строка ещё в g_cells (не зафлашена), поэтому доступны [0..n_lines-2]. */
|
||||
static uint16_t drawable_lines(void)
|
||||
{
|
||||
if (g_loading) return (n_lines >= 1) ? (uint16_t)(n_lines - 1) : 0;
|
||||
return n_lines;
|
||||
}
|
||||
|
||||
/* Возвращает процент прокрутки (0..100) относительно доступного диапазона. */
|
||||
static uint8_t calc_pct(void)
|
||||
{
|
||||
uint16_t total = drawable_lines();
|
||||
uint8_t pct;
|
||||
if (n_lines <= VIEW_H)
|
||||
if (total <= VIEW_H)
|
||||
pct = 100;
|
||||
else
|
||||
pct = (uint8_t)((uint32_t)top_line * 100UL / (uint32_t)(n_lines - VIEW_H));
|
||||
pct = (uint8_t)((uint32_t)top_line * 100UL / (uint32_t)(total - VIEW_H));
|
||||
return pct;
|
||||
}
|
||||
|
||||
@@ -1577,8 +1597,9 @@ static uint8_t calc_pct(void)
|
||||
* Полностью перезаписывает колонки 45..79, чтобы не оставлять «хвосты». */
|
||||
static void render_status_numbers(void)
|
||||
{
|
||||
uint16_t total = drawable_lines();
|
||||
uint16_t last = top_line + VIEW_H;
|
||||
if (last > n_lines) last = n_lines;
|
||||
if (last > total) last = total;
|
||||
uint8_t pct = calc_pct();
|
||||
|
||||
textattr(ATTR_BAR);
|
||||
@@ -1592,13 +1613,25 @@ static void render_status_numbers(void)
|
||||
cputs("-");
|
||||
dec16(last);
|
||||
cputs(" / ");
|
||||
dec16(n_lines);
|
||||
|
||||
dec16(total);
|
||||
if (g_loading) cputs("..."); /* ещё грузится */
|
||||
|
||||
wrchar(70, 0, 0xB3, ATTR_BAR); /* вертикальный разделитель */
|
||||
gotoxy( 73, 0);
|
||||
dec8(pct);
|
||||
cputs("%");
|
||||
|
||||
if (g_loading) { /* DEBUG: время обработки (зона имени файла) */
|
||||
datetime_t now;
|
||||
getdatetime(&now);
|
||||
int16_t el = (int16_t)now.minute*60 + now.second
|
||||
- ((int16_t)g_load_t0.minute*60 + g_load_t0.second);
|
||||
if (el < 0) el += 3600;
|
||||
gotoxy(31, 0);
|
||||
cputs("t=");
|
||||
dec16((uint16_t)el);
|
||||
cputs("s "); /* трейлинг-пробелы затирают прошлую ширину */
|
||||
}
|
||||
}
|
||||
|
||||
/* Полностью перерисовывает статус-бар (заголовок + числа). */
|
||||
@@ -1813,6 +1846,66 @@ static void show_help(void)
|
||||
render_menu();
|
||||
}
|
||||
|
||||
/* Обработка клавиши во время прогрессивной загрузки: скролл строго в
|
||||
* пределах готовых строк (drawable_lines); End = последняя готовая страница;
|
||||
* F1 = справка (show_help сам блокирует и перерисовывает). */
|
||||
static void load_key(uint16_t k)
|
||||
{
|
||||
uint8_t ascii = (uint8_t)(k & 0xFF);
|
||||
uint8_t scan = (uint8_t)((k >> 8) & 0x7F);
|
||||
uint16_t dr = drawable_lines();
|
||||
uint16_t maxtop = (dr > VIEW_H) ? (uint16_t)(dr - VIEW_H) : 0;
|
||||
uint16_t nt = top_line;
|
||||
|
||||
if (ascii == 0x1B || scan == KEY_F10) { g_abort = 1; return; } /* Esc/F10 → выход */
|
||||
if (ascii) return; /* прочие ascii игнорируем */
|
||||
|
||||
switch (scan) {
|
||||
case KEY_UP: nt = (top_line >= 1) ? (uint16_t)(top_line - 1) : 0; break;
|
||||
case KEY_DOWN: nt = top_line + 1; break;
|
||||
case KEY_PGUP: nt = (top_line >= VIEW_H) ? (uint16_t)(top_line - VIEW_H) : 0; break;
|
||||
case KEY_PGDN: nt = top_line + VIEW_H; break;
|
||||
case KEY_HOME: top_line = 0; viewport_x = 0; draw_viewport_from_cache(); render_status_numbers(); return;
|
||||
case KEY_END: top_line = maxtop; viewport_x = 0; draw_viewport_from_cache(); render_status_numbers(); return;
|
||||
case KEY_LEFT: scroll_h(-(int8_t)HPAN_STEP); render_status_numbers(); return;
|
||||
case KEY_RIGHT: scroll_h(+(int8_t)HPAN_STEP); render_status_numbers(); return;
|
||||
case KEY_F1: show_help(); return;
|
||||
default: return;
|
||||
}
|
||||
if (nt > maxtop) nt = maxtop;
|
||||
if (nt != top_line) {
|
||||
top_line = nt;
|
||||
draw_viewport_from_cache();
|
||||
render_status_numbers();
|
||||
}
|
||||
}
|
||||
|
||||
/* Кооперативный «тик» прогрессивной загрузки — вызывается из index_lines(). */
|
||||
static void progress_tick(void)
|
||||
{
|
||||
uint8_t touched = 0;
|
||||
|
||||
if (!g_first_drawn && drawable_lines() >= VIEW_H) {
|
||||
draw_viewport_from_cache();
|
||||
render_status_numbers();
|
||||
g_first_drawn = 1;
|
||||
touched = 1;
|
||||
}
|
||||
if (n_lines >= (uint16_t)(g_last_prog + 20)) {
|
||||
g_last_prog = n_lines;
|
||||
spinner_tick();
|
||||
if (g_first_drawn) render_status_numbers();
|
||||
touched = 1;
|
||||
}
|
||||
if (g_first_drawn && kbhit()) {
|
||||
load_key(getkey());
|
||||
touched = 1;
|
||||
}
|
||||
/* Отрисовка/WINREST/BIOS могли сбить маппинг W3, на который опирается fb()
|
||||
* при индексации → форсируем ре-маппинг страницы файла на следующем fb(). */
|
||||
if (touched) cur_page = 0xFF;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
* Точка входа
|
||||
* ================================================================== */
|
||||
@@ -1876,16 +1969,26 @@ int main(int argc, char **argv)
|
||||
cputs("\n\r\n\r");
|
||||
return 1;
|
||||
}
|
||||
/* Прогрессивная загрузка: index_lines() сама рисует первый экран и пускает
|
||||
* скролл по готовым данным через progress_tick(). */
|
||||
g_loading = 1;
|
||||
g_first_drawn = 0;
|
||||
g_last_prog = 0;
|
||||
getdatetime(&g_load_t0); /* DEBUG: старт обработки */
|
||||
index_lines();
|
||||
g_loading = 0;
|
||||
spinner_show(0);
|
||||
if (g_abort) goto exit_loop; /* F10/Esc во время загрузки — корректный выход */
|
||||
if (n_lines == 0) {
|
||||
die("mdview: empty file");
|
||||
unload_file();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Финальная отрисовка: все строки готовы, top_line мог уехать при скролле. */
|
||||
clamp_top();
|
||||
render_full_status();
|
||||
draw_viewport_from_cache(); /* Фаза 4: рендер уже сделан во время index_lines(), рисуем только из кэша */
|
||||
draw_viewport_from_cache();
|
||||
|
||||
for (;;) {
|
||||
uint16_t k = getkey();
|
||||
|
||||
Reference in New Issue
Block a user