mdview2: полировка статус-бара/справки/детекции + libc min/max

- 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>
This commit is contained in:
2026-06-30 20:43:04 +03:00
parent 1b78dda125
commit 733746572c
9 changed files with 260 additions and 104 deletions
+34 -20
View File
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <stdio.h> /* dec8/dec16, cputs */
#include <conio.h> /* textattr/gotoxy/wrchar/COLOR */
#include <limits.h>
#include <bios/text.h> /* bios_fillcharattr/bios_write_until */
#include "mdview2.h"
@@ -32,7 +33,8 @@ static uint8_t spinner_active = 0;
/* Продвигает спиннер на один кадр (если включён). */
void spinner_tick(void)
{
if (!spinner_active) return;
if (!spinner_active)
return;
wrchar(SPINNER_COL, 0, spinner_chars[spinner_phase & 3], ATTR_BAR_SPINNER);
spinner_phase++;
}
@@ -73,8 +75,8 @@ void prerender_status(void)
void status_encoding(void)
{
textattr(ATTR_BAR);
gotoxy(37, 0);
bios_write_until(enc_name(g_encoding), 7, 0);
gotoxy(DIV1_X - 10, 0);
bios_write_until(enc_name(g_encoding), 8, 0);
}
/* Числовая часть (MD): "L a-b / total" между разделителями + "pct%" справа.
@@ -82,22 +84,29 @@ void status_encoding(void)
* хром не трогает. */
void render_md_status_numbers(void)
{
static uint16_t local_total = UINT_MAX;
static uint16_t local_last = UINT_MAX;
static uint8_t local_loading = UCHAR_MAX;
uint16_t total = drawable_lines();
uint16_t last = top_line + VIEW_H;
if (last > total)
last = total;
textattr(ATTR_BAR);
gotoxy(DIV1_X + 1, 0);
bios_fillcharattr(' ', ATTR_BAR, DIV2_X - DIV1_X - 1); /* очистить [DIV1_X+1 .. DIV2_X-1] */
gotoxy(DIV1_X + 2, 0);
cputs("L ");
dec16(top_line + 1);
cputs("-");
dec16(last);
cputs(" / ");
dec16(total);
if (g_loading) cputs("..."); /* ещё грузится */
if(local_total != total || local_last != last || local_loading != g_loading) {
local_total = total; local_last = last; local_loading = g_loading;
textattr(ATTR_BAR);
gotoxy(DIV1_X + 2, 0);
bios_fillcharattr(' ', ATTR_BAR, DIV2_X - DIV1_X - 2); /* очистить [DIV1_X+1 .. DIV2_X-1] */
gotoxy(DIV1_X + 2, 0);
cputs("L ");
dec16(top_line + 1);
cputs("-");
dec16(last);
cputs(" / ");
dec16(total);
if (g_loading) cputs("..."); /* ещё грузится */
}
}
@@ -109,11 +118,15 @@ void render_full_status(void)
}
void render_percent_progress(uint8_t pct) {
gotoxy(DIV2_X + 1, 0);
bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 1); /* очистить [DIV2_X+1 .. конец] */
gotoxy(DIV2_X + 2, 0);
dec8(pct);
cputs("%");
static uint8_t local_pct = UCHAR_MAX;
if (local_pct != pct) {
local_pct = pct;
gotoxy(DIV2_X + 2, 0);
bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 2); /* очистить [DIV2_X+1 .. конец] */
gotoxy(DIV2_X + 2, 0);
dec8(pct);
cputs("%");
}
}
#if WITH_RAW
@@ -141,7 +154,8 @@ void render_menu(void)
* только у задействованных и доступных сейчас. */
fill_row(MENU_ROW, ATTR_MENU_T);
char num[3]; num[2] = 0;
char num[3];
num[2] = 0;
for (uint8_t i = 0; i < 9; i++) { /* F1..F9: ' 1'..' 9' */
num[0] = ' '; num[1] = (char)('1' + i);
put_str_attr((uint8_t)(i * 8), MENU_ROW, num, ATTR_MENU_K);