From 035d93ab51a8a12038cf2a9ee25db14f44611b47 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Sat, 6 Jun 2026 12:01:15 +0300 Subject: [PATCH] mdview: fix fenced code block emphasis leak and carry emphasis across wrap lines - Add fenced code block tracking to the wrap-pass in index_lines(). line_style is reset to PLAIN at every ``` delimiter, and all segs inside a fenced block get init_style=PLAIN. This prevents emphasis markers (e.g. _ in __var) inside code blocks from leaking into later normal text. - Also carry init_style across wrap continuation segs so that a long bold/italic line that is wrapped continues with the correct style on the next segment. - The fence bitmap pass now only updates in_code[], since init_style is already set correctly by the wrap pass. --- examples/mdview/mdview.c | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/examples/mdview/mdview.c b/examples/mdview/mdview.c index cf0ad85..57f5231 100644 --- a/examples/mdview/mdview.c +++ b/examples/mdview/mdview.c @@ -551,15 +551,25 @@ static void index_lines(void) } else { /* Wrap: walk logical lines, split each into one or more segs. */ uint32_t p = 0; + uint8_t in_block = 0; /* inside fenced code block? */ line_style = INIT_STYLE_PLAIN; while (p < file_size && n_lines < MAX_LINES) { - set_init_style_raw(n_lines, line_style); if ((n_lines & 15) == 0) spinner_tick(); /* Find end of logical line (\n or EOF). */ uint32_t line_end = p; while (line_end < file_size && fb(line_end) != '\n') line_end++; + /* Detect fenced-code delimiter (``` at col 0). Toggle in_block + * and reset emphasis tracking — code blocks never carry inline + * style across their boundaries. */ + if (p + 2 < file_size && + fb(p) == '`' && fb(p + 1) == '`' && fb(p + 2) == '`') { + in_block = (uint8_t)!in_block; + line_style = INIT_STYLE_PLAIN; + } + /* Emit the first seg of this logical line (no CONT). */ + set_init_style_raw(n_lines, in_block ? INIT_STYLE_PLAIN : line_style); line_offset[n_lines++] = p; if (!is_nowrap_line(p)) { @@ -579,6 +589,37 @@ static void index_lines(void) char prev_ch = ' '; /* for emphasis flanking */ while (q < line_end && n_lines < MAX_LINES) { char ch = fb(q); + /* Inside fenced code block: every byte is literal, no + * emphasis markers, but wrap still applies. */ + if (in_block) { + if (ch == '\t') { + uint8_t tgt = (uint8_t)((col & (uint8_t)~(TAB_STOP - 1)) + TAB_STOP); + if (tgt > SCREEN_W) tgt = SCREEN_W; + col = tgt; + q++; + prev_ch = ' '; + } else { + if (ch == ' ') last_space = q + 1; + col++; + q++; + prev_ch = ch; + } + if (col >= SCREEN_W && q < line_end) { + uint32_t wrap_at = (last_space != 0xFFFFFFFFu && + last_space > line_offset[n_lines - 1]) + ? last_space : q; + if (wrap_at >= line_end) break; + line_offset[n_lines] = wrap_at; + set_init_style_raw(n_lines, INIT_STYLE_PLAIN); + set_cont(n_lines); + n_lines++; + col = 0; + last_space = 0xFFFFFFFFu; + prev_ch = ' '; + q = wrap_at; + } + continue; + } /* Backtick — always zero-width (inline code delimiter). */ if (ch == '`') { q++; @@ -598,7 +639,7 @@ static void index_lines(void) line_style = INIT_STYLE_PLAIN; q += 2; continue; - } + } } col += 2; q += 2; @@ -618,7 +659,7 @@ static void index_lines(void) line_style = INIT_STYLE_PLAIN; q++; continue; - } + } } col++; q++; @@ -642,6 +683,7 @@ static void index_lines(void) ? last_space : q; if (wrap_at >= line_end) break; line_offset[n_lines] = wrap_at; + set_init_style_raw(n_lines, line_style); /* carry style across wrap */ set_cont(n_lines); n_lines++; col = 0; @@ -656,18 +698,19 @@ static void index_lines(void) } } - /* Fence/code-body bitmap pass — only non-CONT segs participate. */ + /* Fence/code-body bitmap pass — only non-CONT segs participate. + * The wrap-pass above already tracked fenced blocks and set init_style + * to PLAIN for every seg inside; this pass only fixes the in_code[] + * bitmap (used by render_line to disable inline parsing). */ { uint8_t in_block = 0; for (uint16_t i = 0; i < n_lines; i++) { if (is_cont(i)) { - if(is_code_body(i - 1)) { + if (is_code_body(i - 1)) { in_code[i >> 3] |= (uint8_t)(1u << (i & 7)); set_init_style_raw(i, INIT_STYLE_PLAIN); } continue; - } else { - } if (is_fence_delim(i)) { in_block = (uint8_t)!in_block;