Просмотр исходного кода

fix(tui): fix markdown rendering bold leak, bullets, and color reset

- Keep **markers as plain text through reflowText to prevent ANSI code splitting
- Strip \x1b[0m full-reset codes that override Ink's <Text color> context
- Replace * bullets with · in post-processing
- Convert **text** to ANSI bold after reflow is complete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fanghanjun 7 месяцев назад
Родитель
Сommit
b04dca7ce6
1 измененных файлов с 22 добавлено и 2 удалено
  1. 22 2
      packages/cli/src/tui/markdown.ts

+ 22 - 2
packages/cli/src/tui/markdown.ts

@@ -7,16 +7,36 @@ marked.use(markedTerminal({
   reflowText: true,
   showSectionPrefix: false,
   tab: 2,
+  // Preserve inline formatting through reflow: keep ** markers as plain text
+  // so reflowText won't split ANSI codes across lines. Post-process converts them.
+  listitem: (text: string) => text,
+  strong: (text: string) => `**${text}**`,
 }) as never);
 
+const BOLD_ON = "\x1b[1m";
+const BOLD_OFF = "\x1b[22m";
+
+/**
+ * Post-process marked-terminal output:
+ * 1. Replace `* ` bullets with `· `
+ * 2. Convert `**text**` markers to ANSI bold (applied after reflow to avoid code splitting)
+ */
+function postProcess(text: string): string {
+  return text
+    // Strip \x1b[0m (full reset) — it overrides the color set by Ink's <Text color>.
+    // Table/block-level ANSI (e.g. [90m for borders, [39m for fg reset) is preserved.
+    .replace(/\x1b\[0m/g, "")
+    .replace(/^(\s*)\* /gm, "$1· ")
+    .replace(/\*\*(.+?)\*\*/g, `${BOLD_ON}$1${BOLD_OFF}`);
+}
+
 export function renderMarkdown(text: string): string {
   try {
     const rendered = marked.parse(text);
     if (typeof rendered !== "string") {
       return text;
     }
-    // marked-terminal adds trailing newlines; trim them
-    return rendered.replace(/\n+$/, "");
+    return postProcess(rendered.replace(/\n+$/, ""));
   } catch {
     return text;
   }