[Bug] Code block keeps the previous language's highlighting after the language is cleared or set to an unknown one · Issue #5515 · marktext/marktext · GitHub
Skip to content

[Bug] Code block keeps the previous language's highlighting after the language is cleared or set to an unknown one #5515

Closed

Description

@Jocs

Description

Clearing a code block's language, or changing it to one Prism does not know, leaves the block rendered with the previous language's syntax highlighting. The markdown is written correctly — only what you see is stale, until the block is re-rendered for some other reason (typing in it, reopening the document).

Steps to Reproduce

  1. Create a fenced code block with a known language and some code that highlights, e.g.

    ```js
    const x = 1
    ```
    
  2. Click into the language input (the js at the top of the block).

  3. Select it and delete it, so the language is empty.

Expected Behavior

The code block drops the JavaScript highlighting and renders as plain text.

Actual Behavior

const stays keyword-coloured, 1 stays number-coloured — the block keeps rendering as JavaScript. The markdown correctly becomes ``` with no language.

The same happens when the language is replaced with an unknown one (notalanguage): the block keeps the old highlighting even though the fence now says notalanguage.

Changing to another known language (js → python) re-renders correctly, so only these two cases are affected.

Root cause

CodeBlock's lang setter (packages/muya/src/block/commonMark/codeBlock/index.ts) only re-renders when Prism reports the grammar was loaded or already cached:

const language = firstWordOfInfo(value)
!!language
&& loadLanguage(language)
    .then((infoList) => {
        const needRender = infoList.some(
            ({ status }) => status === 'loaded' || status === 'cached',
        )
        if (needRender)
            this.lastContentInDescendant()?.update()
    })
  • An empty language short-circuits on !!language, so update() is never reached.
  • An unknown language resolves with status: 'noexist', so needRender is false.

In both cases the DOM is left holding the markup the previous grammar produced. Both are exactly the cases where a re-render is required, because the block has to fall back to plain text.

Measured

Driving the real _updateLanguage path (what the language input calls on every keystroke) against a js block containing const x = 1, counting Prism token spans:

language change markdown token spans
js (initial) ```js 3
→ cleared ``` ✅ 3 — still JavaScript ❌
→ notalanguage ```notalanguage ✅ 3 — still JavaScript ❌
→ python ```python ✅ 2 ✅

Environment

Reproduces on current develop. Display-only — no data loss.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions