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.
This commit is contained in:
2026-06-06 12:01:15 +03:00
parent 0dedc4dac8
commit 035d93ab51
+50 -7
View File
@@ -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;