mdview2: B2 stage 1 — вынос inline_marker (-870 байт)
Разбор inline-маркеров (\X, [x], `, **, ~~, *, _, \t) был продублирован в inline_scan() и scan_join_stream(). Вынесен в общий inline_marker(): возвращает 1 если токен обработан, 0 если обычный символ/пробел (его кладёт вызывающий). attr = emph_to_attr(ls, base); для join base=ATTR_TEXT, что тождественно прежнему styles_map[ls]. В scan_join маркеры пропускаются при soft_break (синтетический пробел склейки кладёт ветка пробела). scan_join_stream 3794→2329, inline_scan 1842→700, inline_marker +1436. _CODE 22246→21376. Рендер идентичный (проверено в MAME). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+71
-171
@@ -1011,6 +1011,70 @@ static uint8_t is_table_raw(uint32_t p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Разбор одного inline-МАРКЕРА в позиции *pq (< bound): \X, [x], `, **, ~~,
|
||||||
|
* *, _, \t. Общий код для inline_scan() и scan_join_stream(). Возврат: 1 —
|
||||||
|
* маркер обработан (вызывающий делает continue), 0 — символ обычный (пробел/
|
||||||
|
* текст), его кладёт сам вызывающий (и проверяет перенос). Меняет
|
||||||
|
* *pq/*pls/*pseg/*pprev. attr берётся как emph_to_attr(line_style, base) —
|
||||||
|
* для join base=ATTR_TEXT, что тождественно styles_map[line_style]. */
|
||||||
|
static uint8_t inline_marker(uint32_t *pq, uint32_t bound, uint8_t *pls,
|
||||||
|
uint8_t *pseg, char *pprev, uint8_t base)
|
||||||
|
{
|
||||||
|
uint32_t q = *pq;
|
||||||
|
uint8_t ls = *pls;
|
||||||
|
char ch = fb(q);
|
||||||
|
|
||||||
|
if (ls != INIT_STYLE_CODE && ch == '\\' && (q + 1) < bound && is_escapable(fb(q + 1))) {
|
||||||
|
char nb = fb(q + 1);
|
||||||
|
gc_put(nb, emph_to_attr(ls, base));
|
||||||
|
*pseg += 1; *pq = q + 2; *pprev = nb; return 1;
|
||||||
|
}
|
||||||
|
if (ls != INIT_STYLE_CODE && ch == '[' && (q + 2) < bound && fb(q + 2) == ']') {
|
||||||
|
gc_put('[', ATTR_TEXT_BOLD); gc_put(fb(q + 1), ATTR_TEXT_BOLD); gc_put(']', ATTR_TEXT_BOLD);
|
||||||
|
*pseg += 3; *pq = q + 3; *pprev = ']'; return 1;
|
||||||
|
}
|
||||||
|
if (ch == '`') {
|
||||||
|
if (ls == INIT_STYLE_PLAIN) { *pls = INIT_STYLE_CODE; *pq = q + 1; return 1; }
|
||||||
|
if (ls == INIT_STYLE_CODE) { *pls = INIT_STYLE_PLAIN; *pq = q + 1; return 1; }
|
||||||
|
gc_put('`', emph_to_attr(ls, base)); *pseg += 1; *pq = q + 1; *pprev = '`'; return 1;
|
||||||
|
}
|
||||||
|
if (ch == '*' && (q + 1) < bound && fb(q + 1) == '*') {
|
||||||
|
char nx = ((q + 2) < bound) ? fb(q + 2) : '\n';
|
||||||
|
if (is_emph_flanked(*pprev, nx)) {
|
||||||
|
if (ls == INIT_STYLE_PLAIN && ws_or_eol(*pprev)) { *pls = INIT_STYLE_BOLD; *pq = q + 2; return 1; }
|
||||||
|
if (ls == INIT_STYLE_BOLD && ws_or_eol_or_delim(nx)) { *pls = INIT_STYLE_PLAIN; *pq = q + 2; return 1; }
|
||||||
|
}
|
||||||
|
gc_put('*', emph_to_attr(ls, base)); gc_put('*', emph_to_attr(ls, base));
|
||||||
|
*pseg += 2; *pq = q + 2; *pprev = '*'; return 1;
|
||||||
|
}
|
||||||
|
if (ch == '~' && (q + 1) < bound && fb(q + 1) == '~') {
|
||||||
|
char nx = ((q + 2) < bound) ? fb(q + 2) : '\n';
|
||||||
|
if (is_emph_flanked(*pprev, nx)) {
|
||||||
|
if (ls == INIT_STYLE_PLAIN && ws_or_eol(*pprev)) { *pls = INIT_STYLE_STRIKE; *pq = q + 2; return 1; }
|
||||||
|
if (ls == INIT_STYLE_STRIKE && ws_or_eol_or_delim(nx)) { *pls = INIT_STYLE_PLAIN; *pq = q + 2; return 1; }
|
||||||
|
}
|
||||||
|
gc_put('~', emph_to_attr(ls, base)); gc_put('~', emph_to_attr(ls, base));
|
||||||
|
*pseg += 2; *pq = q + 2; *pprev = '~'; return 1;
|
||||||
|
}
|
||||||
|
if (ch == '*' || ch == '_') {
|
||||||
|
char nx = ((q + 1) < bound) ? fb(q + 1) : '\n';
|
||||||
|
if (is_emph_flanked(*pprev, nx)) {
|
||||||
|
uint8_t ns = (ch == '*') ? INIT_STYLE_ITALIC : INIT_STYLE_UNDER;
|
||||||
|
if (ls == INIT_STYLE_PLAIN && ws_or_eol(*pprev)) { *pls = ns; *pq = q + 1; return 1; }
|
||||||
|
if (ls != INIT_STYLE_PLAIN && ws_or_eol_or_delim(nx)) { *pls = INIT_STYLE_PLAIN; *pq = q + 1; return 1; }
|
||||||
|
}
|
||||||
|
gc_put(ch, emph_to_attr(ls, base)); *pseg += 1; *pq = q + 1; *pprev = ch; return 1;
|
||||||
|
}
|
||||||
|
if (ch == '\t') {
|
||||||
|
uint8_t old_sc = *pseg;
|
||||||
|
uint8_t tgt_full = (uint8_t)((old_sc & (uint8_t)~(TAB_STOP - 1)) + TAB_STOP);
|
||||||
|
uint8_t tgt = tgt_full; if (tgt > SCREEN_W) tgt = SCREEN_W;
|
||||||
|
gc_fill(' ', emph_to_attr(ls, base), (uint8_t)(tgt_full - old_sc));
|
||||||
|
*pseg = tgt; *pq = q + 1; *pprev = ' '; return 1;
|
||||||
|
}
|
||||||
|
return 0; /* пробел или обычный символ — обрабатывает вызывающий */
|
||||||
|
}
|
||||||
|
|
||||||
/* Общий сканер inline-форматирования и переносов.
|
/* Общий сканер inline-форматирования и переносов.
|
||||||
* Идёт от q до q_end, учитывает стартовую колонку col и при необходимости
|
* Идёт от q до q_end, учитывает стартовую колонку col и при необходимости
|
||||||
* эмитит continuation-сегменты. Возвращает итоговый line_style. */
|
* эмитит continuation-сегменты. Возвращает итоговый line_style. */
|
||||||
@@ -1039,73 +1103,9 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Экранированная пунктуация: \* \_ \` … → литерал (не внутри кода). */
|
/* Inline-маркеры (\X [x] ` ** ~~ * _ \t) — общий разбор. */
|
||||||
if (line_style != INIT_STYLE_CODE && ch == '\\' && (q + 1) < q_end && is_escapable(fb(q + 1))) {
|
if (inline_marker(&q, q_end, &line_style, &seg_col, &prev_ch, base)) continue;
|
||||||
char nb = fb(q + 1);
|
|
||||||
gc_put(nb, emph_to_attr(line_style, base));
|
|
||||||
seg_col++; q += 2; prev_ch = nb; continue;
|
|
||||||
}
|
|
||||||
/* [x] — ровно один символ в скобках → болд (task-list checkbox; не внутри кода). */
|
|
||||||
if (line_style != INIT_STYLE_CODE && ch == '[' && (q + 2) < q_end && fb(q + 2) == ']') {
|
|
||||||
char mid = fb(q + 1);
|
|
||||||
gc_put('[', ATTR_TEXT_BOLD);
|
|
||||||
gc_put(mid, ATTR_TEXT_BOLD);
|
|
||||||
gc_put(']', ATTR_TEXT_BOLD);
|
|
||||||
seg_col += 3; q += 3; prev_ch = ']'; continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '`') {
|
|
||||||
if (line_style == INIT_STYLE_PLAIN) { line_style = INIT_STYLE_CODE; q++; continue; }
|
|
||||||
if (line_style == INIT_STYLE_CODE) { line_style = INIT_STYLE_PLAIN; q++; continue; }
|
|
||||||
gc_put('`', emph_to_attr(line_style, base));
|
|
||||||
seg_col++; q++; prev_ch = '`'; continue;
|
|
||||||
}
|
|
||||||
if (ch == '*' && (q + 1) < q_end && fb(q + 1) == '*') {
|
|
||||||
char next_ch = ((q + 2) < q_end) ? fb(q + 2) : '\n';
|
|
||||||
if (is_emph_flanked(prev_ch, next_ch)) {
|
|
||||||
if (line_style == INIT_STYLE_PLAIN && ws_or_eol(prev_ch)) {
|
|
||||||
line_style = INIT_STYLE_BOLD; q += 2; continue;
|
|
||||||
} else if (line_style == INIT_STYLE_BOLD && ws_or_eol_or_delim(next_ch)) {
|
|
||||||
line_style = INIT_STYLE_PLAIN; q += 2; continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ gc_put('*', emph_to_attr(line_style, base)); gc_put('*', emph_to_attr(line_style, base)); }
|
|
||||||
seg_col += 2; q += 2; prev_ch = '*'; continue;
|
|
||||||
}
|
|
||||||
if (ch == '~' && (q + 1) < q_end && fb(q + 1) == '~') {
|
|
||||||
char next_ch = ((q + 2) < q_end) ? fb(q + 2) : '\n';
|
|
||||||
if (is_emph_flanked(prev_ch, next_ch)) {
|
|
||||||
if (line_style == INIT_STYLE_PLAIN && ws_or_eol(prev_ch)) {
|
|
||||||
line_style = INIT_STYLE_STRIKE; q += 2; continue;
|
|
||||||
} else if (line_style == INIT_STYLE_STRIKE && ws_or_eol_or_delim(next_ch)) {
|
|
||||||
line_style = INIT_STYLE_PLAIN; q += 2; continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ gc_put('~', emph_to_attr(line_style, base)); gc_put('~', emph_to_attr(line_style, base)); }
|
|
||||||
seg_col += 2; q += 2; prev_ch = '~'; continue;
|
|
||||||
}
|
|
||||||
if (ch == '*' || ch == '_') {
|
|
||||||
char next_ch = ((q + 1) < q_end) ? fb(q + 1) : '\n';
|
|
||||||
if (is_emph_flanked(prev_ch, next_ch)) {
|
|
||||||
uint8_t new_style = (ch == '*') ? INIT_STYLE_ITALIC : INIT_STYLE_UNDER;
|
|
||||||
if (line_style == INIT_STYLE_PLAIN && ws_or_eol(prev_ch)) {
|
|
||||||
line_style = new_style; q++; continue;
|
|
||||||
} else if (line_style != INIT_STYLE_PLAIN && ws_or_eol_or_delim(next_ch)) {
|
|
||||||
/* как render: закрывает любой активный эмфазис */
|
|
||||||
line_style = INIT_STYLE_PLAIN; q++; continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gc_put(ch, emph_to_attr(line_style, base));
|
|
||||||
seg_col++; q++; prev_ch = ch; continue;
|
|
||||||
}
|
|
||||||
if (ch == '\t') {
|
|
||||||
uint8_t old_sc = seg_col;
|
|
||||||
uint8_t tgt_full = (uint8_t)((seg_col & (uint8_t)~(TAB_STOP - 1)) + TAB_STOP);
|
|
||||||
uint8_t tgt = tgt_full;
|
|
||||||
if (tgt > SCREEN_W) tgt = SCREEN_W;
|
|
||||||
gc_fill(' ', emph_to_attr(line_style, base), (uint8_t)(tgt_full - old_sc));
|
|
||||||
seg_col = tgt; q++; prev_ch = ' '; continue;
|
|
||||||
}
|
|
||||||
if (ch == ' ') {
|
if (ch == ' ') {
|
||||||
gc_put(' ', emph_to_attr(line_style, base));
|
gc_put(' ', emph_to_attr(line_style, base));
|
||||||
last_space = q + 1;
|
last_space = q + 1;
|
||||||
@@ -1261,112 +1261,12 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Экранированная пунктуация: \* \_ \` … → литерал (не внутри кода). */
|
/* Inline-маркеры (\X [x] ` ** ~~ * _ \t) — общий разбор; при
|
||||||
if (line_style != INIT_STYLE_CODE && ch == '\\' && (q + 1) < file_size && is_escapable(fb(q + 1))) {
|
* soft_break ch==' ' (синтетический пробел склейки) — маркеры
|
||||||
char nb = fb(q + 1);
|
* пропускаем, его кладёт ветка пробела ниже. */
|
||||||
gc_put(nb, styles_map[line_style]);
|
if (!soft_break && inline_marker(&q, file_size, &line_style, &seg_col, &prev_ch, ATTR_TEXT))
|
||||||
seg_col++; q += 2; prev_ch = nb; continue;
|
continue;
|
||||||
}
|
|
||||||
/* [x] — ровно один символ в скобках → болд (task-list checkbox; не внутри кода). */
|
|
||||||
if (line_style != INIT_STYLE_CODE && ch == '[' && (q + 2) < file_size && fb(q + 2) == ']') {
|
|
||||||
char mid = fb(q + 1);
|
|
||||||
gc_put('[', ATTR_TEXT_BOLD);
|
|
||||||
gc_put(mid, ATTR_TEXT_BOLD);
|
|
||||||
gc_put(']', ATTR_TEXT_BOLD);
|
|
||||||
seg_col += 3; q += 3; prev_ch = ']'; continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '`') {
|
|
||||||
/* Как handle_inline_marker в render: backtick переключает code-режим
|
|
||||||
* ТОЛЬКО из PLAIN или CODE; если активен эмфазис (bold/italic/...),
|
|
||||||
* backtick — обычный литеральный символ (нет вложенного кода). */
|
|
||||||
if (line_style == INIT_STYLE_PLAIN) {
|
|
||||||
line_style = INIT_STYLE_CODE;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line_style == INIT_STYLE_CODE) {
|
|
||||||
line_style = INIT_STYLE_PLAIN;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
gc_put('`', styles_map[line_style]);
|
|
||||||
seg_col++;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
prev_ch = '`';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == '*' && (q + 1) < file_size && fb(q + 1) == '*') {
|
|
||||||
char next_ch = ((q + 2) < file_size) ? fb(q + 2) : '\n';
|
|
||||||
if (is_emph_flanked(prev_ch, next_ch)) {
|
|
||||||
if (line_style == INIT_STYLE_PLAIN && ws_or_eol(prev_ch)) {
|
|
||||||
line_style = INIT_STYLE_BOLD;
|
|
||||||
q += 2; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
} else if (line_style == INIT_STYLE_BOLD && ws_or_eol_or_delim(next_ch)) {
|
|
||||||
line_style = INIT_STYLE_PLAIN;
|
|
||||||
q += 2; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ gc_put('*', styles_map[line_style]); gc_put('*', styles_map[line_style]); }
|
|
||||||
seg_col += 2;
|
|
||||||
q += 2; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
prev_ch = '*';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == '~' && (q + 1) < file_size && fb(q + 1) == '~') {
|
|
||||||
char next_ch = ((q + 2) < file_size) ? fb(q + 2) : '\n';
|
|
||||||
if (is_emph_flanked(prev_ch, next_ch)) {
|
|
||||||
if (line_style == INIT_STYLE_PLAIN && ws_or_eol(prev_ch)) {
|
|
||||||
line_style = INIT_STYLE_STRIKE;
|
|
||||||
q += 2; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
} else if (line_style == INIT_STYLE_STRIKE && ws_or_eol_or_delim(next_ch)) {
|
|
||||||
line_style = INIT_STYLE_PLAIN;
|
|
||||||
q += 2; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ gc_put('~', styles_map[line_style]); gc_put('~', styles_map[line_style]); }
|
|
||||||
seg_col += 2;
|
|
||||||
q += 2; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
prev_ch = '~';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == '*' || ch == '_') {
|
|
||||||
char next_ch = ((q + 1) < file_size) ? fb(q + 1) : '\n';
|
|
||||||
if (is_emph_flanked(prev_ch, next_ch)) {
|
|
||||||
uint8_t new_style = (ch == '*') ? INIT_STYLE_ITALIC : INIT_STYLE_UNDER;
|
|
||||||
if (line_style == INIT_STYLE_PLAIN && ws_or_eol(prev_ch)) {
|
|
||||||
line_style = new_style;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
} else if (line_style != INIT_STYLE_PLAIN && ws_or_eol_or_delim(next_ch)) {
|
|
||||||
/* как render: одиночный маркер закрывает ЛЮБОЙ активный эмфазис */
|
|
||||||
line_style = INIT_STYLE_PLAIN;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gc_put(ch, styles_map[line_style]);
|
|
||||||
seg_col++;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
prev_ch = ch;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == '\t') {
|
|
||||||
uint8_t old_sc = seg_col;
|
|
||||||
uint8_t tgt_full = (uint8_t)((seg_col & (uint8_t)~(TAB_STOP - 1)) + TAB_STOP);
|
|
||||||
uint8_t tgt = tgt_full;
|
|
||||||
if (tgt > SCREEN_W) tgt = SCREEN_W;
|
|
||||||
/* render заполняет до НЕкапнутого tgt_full (по cc); для plain cc==seg_col */
|
|
||||||
gc_fill(' ', styles_map[line_style], (uint8_t)(tgt_full - old_sc));
|
|
||||||
seg_col = tgt;
|
|
||||||
q++; /* soft_break здесь всегда 0 (ch!=' ') */
|
|
||||||
prev_ch = ' ';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == ' ') {
|
if (ch == ' ') {
|
||||||
gc_put(' ', styles_map[line_style]);
|
gc_put(' ', styles_map[line_style]);
|
||||||
if (soft_break) {
|
if (soft_break) {
|
||||||
|
|||||||
Reference in New Issue
Block a user