Skip to content

fix(edit): track fence state so apply keeps nested code blocks in markdown files#12594

Open
rodboev wants to merge 1 commit into
continuedev:mainfrom
rodboev:pr/fix-markdown-fence-nesting
Open

fix(edit): track fence state so apply keeps nested code blocks in markdown files#12594
rodboev wants to merge 1 commit into
continuedev:mainfrom
rodboev:pr/fix-markdown-fence-nesting

Conversation

@rodboev

@rodboev rodboev commented Jun 10, 2026

Copy link
Copy Markdown

Fixes #7143

Summary

Applying edits to markdown files truncates the file at the first fenced code block: the diff flashes and the saved file is cut short, or the model's wrapper fence leaks into the file. README and docs edits are the common casualty.

Root cause

stopAtLinesWithMarkdownSupport (core/utils/streamMarkdownUtils.ts) decides where the model's prefilled outer fence ends. For markdown files it had two paths: a tracker-based one used only when the file contains explicit ```md-tagged blocks, and a simple scan that stops at the first bare line. Any markdown file whose inner blocks use other language tags (````javascript , ```bash ````) hits the simple scan and is truncated at the first inner closing fence.

Changes

  • core/utils/streamMarkdownUtils.ts: replaced both paths with a single CommonMark-based scan:
    • a fence line requires 3+ backticks and at most 3 spaces of indentation; short or over-indented backtick lines are content
    • while an inner block is open, fences do not nest: only a bare line with at least the opener's backtick count closes it (so ```` correctly closes a four-backtick block, and an info-string line inside a block is content)
    • a bare top-level fence is the outer closer only when no fence lines follow it; otherwise it opens a plain inner block
    • if the stream ends with an unclosed inner fence or a trailing fence line, the final fence is treated as the outer closer so the wrapper delimiter never leaks into the file
  • core/utils/streamMarkdownUtils.vitest.ts: 10 new cases (single/sequential/nested blocks, four-backtick fences, unclosed inner fence, info-string-inside-block, short/over-indented lines, non-markdown regression)

What this doesn't change

  • The non-markdown path: still stops at the first bare ``` exactly as before
  • shouldStopAtMarkdownBlock and MarkdownBlockStateTracker consumers elsewhere (the tracker import here is now type-only)
  • The legacy-completions-endpoint behavior and model-output quality issues also discussed in Continue not making changes to code #7143 are out of scope for this PR

Checklist

  • I've read the contributing guide
  • The relevant docs, if any, have been updated or created
  • The relevant tests, if any, have been updated or created

Screen recording or screenshot

N/A — streaming parser fix; the user-visible effect is markdown files no longer truncating at the first inner code block on apply.

Tests

  • cd core && npx vitest run utils/streamMarkdownUtils.vitest.ts — 13/13 passing (3 existing + 10 new). Covers: fence-depth handling for plain, sequential, nested, and four-backtick blocks; unclosed inner fences; info-string lines inside open blocks; short/over-indented backtick lines; and the non-markdown stop-at-first-fence regression guard.
  • cd core && npx vitest run utils/markdownUtils.vitest.ts — 34/34 passing (adjacent module regression guard).

Summary by cubic

Tracks and closes fenced code blocks in markdown so applying edits no longer truncates files or leaks the wrapper fence. Fixes #7143.

  • Bug Fixes
    • Replaced previous logic with a CommonMark-based fence scan in core/utils/streamMarkdownUtils.ts (tracks backtick count, ≤3-space indent, and non-nesting).
    • Stops at the true outer closing fence; if the stream ends mid-block or on a fence line, treats the last fence as the closer to prevent leakage.
    • Non-markdown behavior is unchanged (still stops at the first bare ```).
    • Added 10 tests covering nested/sequential/four-backtick fences, malformed/unclosed blocks, info-string lines, short/over-indented lines, and non-markdown regression.

Written for commit e8f1c9d. Summary will update on new commits.

Review in cubic

@rodboev rodboev requested a review from a team as a code owner June 10, 2026 20:07
@rodboev rodboev requested review from sestinj and removed request for a team June 10, 2026 20:07
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jun 10, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Continue not making changes to code

1 participant