diff --git a/.changeset/fix-single-tilde-strikethrough.md b/.changeset/fix-single-tilde-strikethrough.md new file mode 100644 index 0000000..e9a0a5d --- /dev/null +++ b/.changeset/fix-single-tilde-strikethrough.md @@ -0,0 +1,6 @@ +--- +"@silicajs/core": patch +"@silicajs/assistant": patch +--- + +Disable GFM single-tilde strikethrough so `~text~` is not crossed out, matching Obsidian syntax. diff --git a/packages/assistant/src/ui/message.tsx b/packages/assistant/src/ui/message.tsx index 23be91e..28a4b76 100644 --- a/packages/assistant/src/ui/message.tsx +++ b/packages/assistant/src/ui/message.tsx @@ -43,7 +43,7 @@ export function AssistantMessage({ message, onRetry }: AssistantMessageProps) { {message.content ? (
{message.content} diff --git a/packages/core/src/pipeline.test.tsx b/packages/core/src/pipeline.test.tsx index 973b404..9447931 100644 --- a/packages/core/src/pipeline.test.tsx +++ b/packages/core/src/pipeline.test.tsx @@ -411,6 +411,19 @@ describe("renderMarkdown", () => { expect(html).toContain(" { + const result = await renderMarkdown( + "~~crossed out~~ and ~not crossed~", + testContext("index", ["index"]), + ); + + const html = renderToStaticMarkup(<>{result.content}); + + expect(html).toContain("crossed out"); + expect(html).toContain("~not crossed~"); + expect(html).not.toContain("not crossed"); + }, 15_000); + it("sanitizes raw HTML and escapes OFM-injected labels", async () => { const result = await renderMarkdown( '[[]]\n\n\n\n\n\n

Raw heading

\n\n

User heading

', diff --git a/packages/core/src/pipeline/index.ts b/packages/core/src/pipeline/index.ts index 2f5368d..80adb5f 100644 --- a/packages/core/src/pipeline/index.ts +++ b/packages/core/src/pipeline/index.ts @@ -37,6 +37,9 @@ import { rehypeUnwrapSilicaEmbeds, } from "./plugins.js"; +/** Obsidian strikethrough uses `~~text~~`; single tildes are subscript, not delete. */ +const remarkGfmOptions = { singleTilde: false } as const; + type MdastNode = { type: string; value?: string; @@ -367,7 +370,7 @@ function baseProcessor(context: RenderContext) { return unified() .use(remarkParse) .use(remarkFrontmatter, ["yaml"]) - .use(remarkGfm) + .use(remarkGfm, remarkGfmOptions) .use(remarkMath) .use(remarkObsidian, { inlineTags: context.tags?.inline ?? true }) .use(remarkSilicaObsidian, context) @@ -381,7 +384,7 @@ async function runRemarkObsidian(markdown: string, context: RenderContext) { const processor = unified() .use(remarkParse) .use(remarkFrontmatter, ["yaml"]) - .use(remarkGfm) + .use(remarkGfm, remarkGfmOptions) .use(remarkMath) .use(remarkObsidian, { inlineTags: context.tags?.inline ?? true }) .use(remarkSilicaObsidian, context); @@ -413,7 +416,7 @@ function parsePlainTextMarkdown(markdown: string): MdastNode { return unified() .use(remarkParse) .use(remarkFrontmatter, ["yaml"]) - .use(remarkGfm) + .use(remarkGfm, remarkGfmOptions) .use(remarkMath) .use(remarkObsidian) .parse(markdown) as MdastNode;