diff --git a/examples/mdview2/mdview2.c b/examples/mdview2/mdview2.c index 2baca9f..339ad76 100644 --- a/examples/mdview2/mdview2.c +++ b/examples/mdview2/mdview2.c @@ -780,15 +780,16 @@ static uint8_t marker_visible_col(uint8_t kind, uint32_t p_start, uint32_t conte * по файлу — без отдельного второго скана. На каждом emit_seg ячейки * ПРЕДЫДУЩего сегмента флашатся в кэш (lag-1: к этому моменту сегмент уже * полностью просканирован); последний сегмент флашится после цикла index_lines. - * g_cur_merged переживает переносы внутри одного параграфа; g_next_merged - * выставляет index_lines перед блоком (рудимент эпохи поэтапной миграции — - * сейчас все типы строит merge, так что флаг всегда 1). */ + * g_ncells_at_space — снимок длины на последнем пробеле для усечения буфера + * при переносе строки (отбрасываем уехавшее за границу слово). */ static uint8_t g_cells[MAX_CACHE_LINE_LEN * 2]; static uint8_t g_ncells = 0; /* ячеек в текущем сегменте */ static uint8_t g_ncells_at_space = 0; /* снимок g_ncells на последнем пробеле (для усечения при переносе) */ -static uint8_t g_cur_merged = 0; /* строящийся сегмент построен merge'ем (всегда 1) */ -static uint8_t g_next_merged = 0; /* статус следующего сегмента (ставит index_lines) */ +/* Пишет одну (char,attr)-ячейку в g_cells, молча игнорируя переполнение + * MAX_CACHE_LINE_LEN. Оставлена ФУНКЦИЕЙ намеренно: инлайн в сильно + * регистро-нагруженный скан-цикл на Z80/SDCC увеличивает спиллы и замедляет + * (проверено замером — макро-инлайн дал регрессию ~11→13с). */ static void gc_put(char ch, uint8_t attr) { if (g_ncells < MAX_CACHE_LINE_LEN) { @@ -838,7 +839,6 @@ static void emit_seg(uint32_t off, uint8_t style, uint8_t ckind, uint8_t cont) n_lines++; /* Флаш ячеек ПРЕДЫДУЩего сегмента (lag-1): он полностью собран форвард-сканером. */ if (n_lines >= 2) seg_commit_cells((uint16_t)(n_lines - 2)); - g_cur_merged = g_next_merged; /* статус нового сегмента (сейчас всегда 1) */ g_ncells = 0; /* буфер ячеек под новый сегмент */ g_ncells_at_space = 0; } @@ -929,7 +929,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col, 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; } - if (g_cur_merged) gc_put('`', emph_to_attr(line_style, base)); + gc_put('`', emph_to_attr(line_style, base)); seg_col++; q++; prev_ch = '`'; continue; } if (ch == '*' && (q + 1) < q_end && fb(q + 1) == '*') { @@ -941,7 +941,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col, line_style = INIT_STYLE_PLAIN; q += 2; continue; } } - if (g_cur_merged) { gc_put('*', emph_to_attr(line_style, base)); gc_put('*', emph_to_attr(line_style, base)); } + { 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) == '~') { @@ -953,7 +953,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col, line_style = INIT_STYLE_PLAIN; q += 2; continue; } } - if (g_cur_merged) { gc_put('~', emph_to_attr(line_style, base)); gc_put('~', emph_to_attr(line_style, base)); } + { 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 == '_') { @@ -967,7 +967,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col, line_style = INIT_STYLE_PLAIN; q++; continue; } } - if (g_cur_merged) gc_put(ch, emph_to_attr(line_style, base)); + gc_put(ch, emph_to_attr(line_style, base)); seg_col++; q++; prev_ch = ch; continue; } if (ch == '\t') { @@ -975,17 +975,17 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t 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; - if (g_cur_merged) gc_fill(' ', emph_to_attr(line_style, base), (uint8_t)(tgt_full - old_sc)); + gc_fill(' ', emph_to_attr(line_style, base), (uint8_t)(tgt_full - old_sc)); seg_col = tgt; q++; prev_ch = ' '; continue; } if (ch == ' ') { - if (g_cur_merged) gc_put(' ', emph_to_attr(line_style, base)); + gc_put(' ', emph_to_attr(line_style, base)); last_space = q + 1; last_space_style = line_style; - if (g_cur_merged) g_ncells_at_space = g_ncells; + g_ncells_at_space = g_ncells; seg_col++; q++; prev_ch = ' '; } else { - if (g_cur_merged) gc_put(ch, emph_to_attr(line_style, base)); + gc_put(ch, emph_to_attr(line_style, base)); seg_col++; q++; prev_ch = ch; } if (!nowrap && seg_col >= SCREEN_W) { @@ -993,7 +993,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col, uint32_t wrap_at = use_ls ? last_space : q; if (wrap_at >= q_end || wrap_at == cur_seg_off) break; uint8_t wrap_style = use_ls ? last_space_style : line_style; - if (g_cur_merged && use_ls) g_ncells = g_ncells_at_space; + if (use_ls) g_ncells = g_ncells_at_space; emit_seg(wrap_at, wrap_style, ckind, 1); base = ATTR_TEXT; /* continuation заголовка → PLAIN */ seg_col = col; last_space = 0xFFFFFFFFu; prev_ch = ' '; q = wrap_at; @@ -1147,7 +1147,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, if (!soft_break) q++; continue; } - if (g_cur_merged) gc_put('`', styles_map[line_style]); + gc_put('`', styles_map[line_style]); seg_col++; if (!soft_break) q++; else q++; prev_ch = '`'; @@ -1166,7 +1166,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, continue; } } - if (g_cur_merged) { gc_put('*', styles_map[line_style]); gc_put('*', styles_map[line_style]); } + { gc_put('*', styles_map[line_style]); gc_put('*', styles_map[line_style]); } seg_col += 2; if (!soft_break) q += 2; else q++; prev_ch = '*'; @@ -1185,7 +1185,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, continue; } } - if (g_cur_merged) { gc_put('~', styles_map[line_style]); gc_put('~', styles_map[line_style]); } + { gc_put('~', styles_map[line_style]); gc_put('~', styles_map[line_style]); } seg_col += 2; if (!soft_break) q += 2; else q++; prev_ch = '~'; @@ -1206,7 +1206,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, continue; } } - if (g_cur_merged) gc_put(ch, styles_map[line_style]); + gc_put(ch, styles_map[line_style]); seg_col++; if (!soft_break) q++; else q++; prev_ch = ch; @@ -1218,14 +1218,14 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, uint8_t tgt = tgt_full; if (tgt > SCREEN_W) tgt = SCREEN_W; /* render заполняет до НЕкапнутого tgt_full (по cc); для plain cc==seg_col */ - if (g_cur_merged) gc_fill(' ', styles_map[line_style], (uint8_t)(tgt_full - old_sc)); + gc_fill(' ', styles_map[line_style], (uint8_t)(tgt_full - old_sc)); seg_col = tgt; if (!soft_break) q++; else q++; prev_ch = ' '; continue; } if (ch == ' ') { - if (g_cur_merged) gc_put(' ', styles_map[line_style]); + gc_put(' ', styles_map[line_style]); if (soft_break) { last_space = q; last_space_style = line_style; @@ -1236,10 +1236,10 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, seg_col++; q++; } - if (g_cur_merged) g_ncells_at_space = g_ncells; /* снимок для усечения */ + g_ncells_at_space = g_ncells; /* снимок для усечения */ prev_ch = ' '; } else { - if (g_cur_merged) gc_put(ch, styles_map[line_style]); + gc_put(ch, styles_map[line_style]); seg_col++; if (!soft_break) q++; else q++; prev_ch = ch; @@ -1249,13 +1249,13 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col, uint32_t wrap_at = use_ls ? last_space : q; if (wrap_at >= file_size || wrap_at == cur_seg_off) break; uint8_t wrap_style = use_ls ? last_space_style : line_style; - if (g_cur_merged && use_ls) g_ncells = g_ncells_at_space; /* усечь до пробела */ + if (use_ls) g_ncells = g_ncells_at_space; /* усечь до пробела */ emit_seg(wrap_at, wrap_style, ckind, 1); /* Префикс continuation-сегмента (как render в cont-блоке): список — * col пробелов; цитата — отступ + маркер 0xB3 + пробел; plain — без префикса. */ - if (g_cur_merged && ckind == CK_LIST) { + if (ckind == CK_LIST) { gc_fill(' ', ATTR_TEXT, col); - } else if (g_cur_merged && ckind == CK_QUOTE) { + } else if (ckind == CK_QUOTE) { uint32_t content_off2 = para_start + col; uint8_t qsp = 0; while (qsp + 2 < content_off2 && qsp < SCREEN_W && fb(para_start + qsp) == ' ') qsp++; @@ -1293,7 +1293,6 @@ static void index_lines(void) uint32_t p = 0; while (p < file_size && n_lines < max_lines) { - g_next_merged = 0; /* по умолчанию блок не мигрирован → render; мигрированные типы выставят 1 */ if ((n_lines & 15) == 0) spinner_tick(); @@ -1305,7 +1304,6 @@ static void index_lines(void) if (p < file_size) p++; /* Серия пустых строк схлопывается в одну визуальную строку. */ if (n_lines == 0 || !(cur_rec.flags & IF_BLANK)) { - g_next_merged = 1; /* S5: blank — пустой буфер (len 0) */ emit_seg(p, INIT_STYLE_PLAIN, CK_PLAIN, 0); set_blank_cur(); } @@ -1315,7 +1313,6 @@ static void index_lines(void) /* ---- fenced code-блок (граница или тело) ---- */ if (is_fence_raw(p)) { in_block = !in_block; - g_next_merged = 1; /* S5: граница ``` — пустой буфер (len 0) */ emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0); set_nowrap_cur(); while (p < file_size && fb(p) != '\n') p++; @@ -1323,12 +1320,11 @@ static void index_lines(void) continue; } if (in_block) { - g_next_merged = 1; /* S5: тело кода — verbatim ATTR_TEXT_CODE */ emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0); set_nowrap_cur(); set_code_cur(); set_hscroll_cur(); /* код скроллится целым блоком */ - if (g_cur_merged) { + { uint8_t ccx = 0; uint32_t pp = p; while (pp < file_size && fb(pp) != '\n') { @@ -1352,10 +1348,9 @@ static void index_lines(void) /* ---- горизонтальный разделитель ---- */ if (is_hr_raw(p)) { - g_next_merged = 1; /* S5: HR — 80×0xC4 ATTR_HR */ emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0); set_nowrap_cur(); - if (g_cur_merged) gc_fill(0xC4, ATTR_HR, SCREEN_W); + gc_fill(0xC4, ATTR_HR, SCREEN_W); while (p < file_size && fb(p) != '\n') p++; if (p < file_size) p++; continue; @@ -1363,11 +1358,10 @@ static void index_lines(void) /* ---- строка таблицы (| ... |): один nowrap-сегмент на исходную строку ---- */ if (is_table_raw(p)) { - g_next_merged = 1; /* S5: таблица — inline-парсинг без переноса */ emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0); set_nowrap_cur(); set_hscroll_cur(); /* таблица скроллится целым блоком */ - if (g_cur_merged) { + { uint32_t line_end = p; while (line_end < file_size && fb(line_end) != '\n') line_end++; (void)inline_scan(p, line_end, 0, CK_OTHER, INIT_STYLE_PLAIN, ATTR_TEXT, 1); @@ -1390,7 +1384,6 @@ static void index_lines(void) case LK_H3: hbase = ATTR_TEXT_TITLE3; break; default: hbase = ATTR_TEXT_TITLE4; break; } - g_next_merged = 1; /* S2: заголовки строит merge */ emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0); uint32_t line_end = content_off; while (line_end < file_size && fb(line_end) != '\n') line_end++; @@ -1406,10 +1399,9 @@ static void index_lines(void) uint8_t line_style = INIT_STYLE_PLAIN; uint32_t q = content_off; - g_next_merged = 1; /* S3: списки строит merge */ emit_seg(p, line_style, CK_LIST, 0); /* Префикс ПЕРВОГО сегмента: отступ + маркер + пробел (как render). */ - if (g_cur_merged) { + { uint32_t qq = p, qmax = p + SCREEN_W; if (kind == LK_ULIST) { while (qq + 2 < content_off && qq < qmax && fb(qq) == ' ') qq++; @@ -1462,10 +1454,9 @@ static void index_lines(void) uint8_t line_style = INIT_STYLE_PLAIN; uint32_t q = content_off; - g_next_merged = 1; /* S4: цитаты строит merge */ emit_seg(p, line_style, CK_QUOTE, 0); /* Префикс ПЕРВОГО сегмента: отступ + маркер 0xB3 + пробел (как render LK_QUOTE). */ - if (g_cur_merged) { + { uint32_t qq = p, qmax = p + SCREEN_W; while (qq + 1 < content_off && qq < qmax && fb(qq) == ' ') qq++; gc_fill(' ', ATTR_TEXT, (uint8_t)(qq - p)); @@ -1483,7 +1474,6 @@ static void index_lines(void) /* ---- Обычный текстовый параграф: склейка через soft-break ---- */ { uint8_t line_style = INIT_STYLE_PLAIN; - g_next_merged = 1; /* S1: параграфы строит merge */ emit_seg(p, line_style, CK_PLAIN, 0); uint32_t q = p;