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.h>
|
||||||
#include <sprinter_mem.h>
|
#include <sprinter_mem.h>
|
||||||
#include <palette.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 uint8_t viewport_x = 0; /* горизонтальный сдвиг для nowrap-строк */
|
||||||
static char filename[64] = {0};
|
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
|
#define HPAN_STEP 8u
|
||||||
|
|
||||||
/* Спиннер в статус-баре (col=8,row=0).
|
/* Спиннер в статус-баре (col=8,row=0).
|
||||||
@@ -1291,10 +1301,11 @@ static void index_lines(void)
|
|||||||
if (file_size == 0) return;
|
if (file_size == 0) return;
|
||||||
|
|
||||||
uint32_t p = 0;
|
uint32_t p = 0;
|
||||||
while (p < file_size && n_lines < max_lines) {
|
while (p < file_size && n_lines < max_lines && !g_abort) {
|
||||||
|
|
||||||
|
if (g_loading)
|
||||||
if ((n_lines & 15) == 0)
|
progress_tick(); /* первый экран + статус + скролл по готовым данным */
|
||||||
|
else if ((n_lines & 15) == 0)
|
||||||
spinner_tick();
|
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) относительно доступного диапазона. */
|
/* Возвращает процент прокрутки (0..100) относительно доступного диапазона. */
|
||||||
static uint8_t calc_pct(void)
|
static uint8_t calc_pct(void)
|
||||||
{
|
{
|
||||||
|
uint16_t total = drawable_lines();
|
||||||
uint8_t pct;
|
uint8_t pct;
|
||||||
if (n_lines <= VIEW_H)
|
if (total <= VIEW_H)
|
||||||
pct = 100;
|
pct = 100;
|
||||||
else
|
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;
|
return pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1577,8 +1597,9 @@ static uint8_t calc_pct(void)
|
|||||||
* Полностью перезаписывает колонки 45..79, чтобы не оставлять «хвосты». */
|
* Полностью перезаписывает колонки 45..79, чтобы не оставлять «хвосты». */
|
||||||
static void render_status_numbers(void)
|
static void render_status_numbers(void)
|
||||||
{
|
{
|
||||||
|
uint16_t total = drawable_lines();
|
||||||
uint16_t last = top_line + VIEW_H;
|
uint16_t last = top_line + VIEW_H;
|
||||||
if (last > n_lines) last = n_lines;
|
if (last > total) last = total;
|
||||||
uint8_t pct = calc_pct();
|
uint8_t pct = calc_pct();
|
||||||
|
|
||||||
textattr(ATTR_BAR);
|
textattr(ATTR_BAR);
|
||||||
@@ -1592,13 +1613,25 @@ static void render_status_numbers(void)
|
|||||||
cputs("-");
|
cputs("-");
|
||||||
dec16(last);
|
dec16(last);
|
||||||
cputs(" / ");
|
cputs(" / ");
|
||||||
dec16(n_lines);
|
dec16(total);
|
||||||
|
if (g_loading) cputs("..."); /* ещё грузится */
|
||||||
|
|
||||||
wrchar(70, 0, 0xB3, ATTR_BAR); /* вертикальный разделитель */
|
wrchar(70, 0, 0xB3, ATTR_BAR); /* вертикальный разделитель */
|
||||||
gotoxy( 73, 0);
|
gotoxy( 73, 0);
|
||||||
dec8(pct);
|
dec8(pct);
|
||||||
cputs("%");
|
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();
|
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");
|
cputs("\n\r\n\r");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* Прогрессивная загрузка: index_lines() сама рисует первый экран и пускает
|
||||||
|
* скролл по готовым данным через progress_tick(). */
|
||||||
|
g_loading = 1;
|
||||||
|
g_first_drawn = 0;
|
||||||
|
g_last_prog = 0;
|
||||||
|
getdatetime(&g_load_t0); /* DEBUG: старт обработки */
|
||||||
index_lines();
|
index_lines();
|
||||||
|
g_loading = 0;
|
||||||
spinner_show(0);
|
spinner_show(0);
|
||||||
|
if (g_abort) goto exit_loop; /* F10/Esc во время загрузки — корректный выход */
|
||||||
if (n_lines == 0) {
|
if (n_lines == 0) {
|
||||||
die("mdview: empty file");
|
die("mdview: empty file");
|
||||||
unload_file();
|
unload_file();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Финальная отрисовка: все строки готовы, top_line мог уехать при скролле. */
|
||||||
|
clamp_top();
|
||||||
render_full_status();
|
render_full_status();
|
||||||
draw_viewport_from_cache(); /* Фаза 4: рендер уже сделан во время index_lines(), рисуем только из кэша */
|
draw_viewport_from_cache();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint16_t k = getkey();
|
uint16_t k = getkey();
|
||||||
|
|||||||
Reference in New Issue
Block a user