Skip to content

[lexical-code][lexical-markdown][lexical-playground] Feature: Add code diff highlighting#7613

Merged
etrepum merged 2 commits intofacebook:mainfrom
jeromew:code-diff
Jun 9, 2025
Merged

[lexical-code][lexical-markdown][lexical-playground] Feature: Add code diff highlighting#7613
etrepum merged 2 commits intofacebook:mainfrom
jeromew:code-diff

Conversation

@jeromew
Copy link
Copy Markdown
Contributor

@jeromew jeromew commented Jun 8, 2025

Description

This PR adds code diff highlighting to the Code Blocks.
I needed to display code blocks in Lexical so I looked at what Prismjs is doing in https://prismjs.com/plugins/diff-highlight/ to see how it could be ported to Lexical.

Prismjs, in its v2 branch, has a diff-highlight plugin implementation that works at the token level (not at the html level like what 1.30 is doing). This fits well with Lexical and I could integrate this implementation into packages/lexical-code/src/CodeHighlighterPrism.ts
Basically it works by first tokenizing the code with a diff grammar that detects the inserted/deleted/unchanged blocks and then tokenizes each block with the language grammar to have both diff highlighting & language highlighting.

The result is that with this PR you can see highlighted & editable diffs in Lexical

image

it uses the same API is diff-highlight, by adding "diff-" in front of the language name so to use it in Lexical, create a code block with language diff-javascript for example (it can be specified in the markdown mode for example)

modifications:

  1. [lexical-markdown] is modified to allow languages with "-" inside their id. It seems ok & necessary in any case as Prismjs accepts language ids with "-", like "excel-formula" or "firestone-security-rules"

  2. [lexical-playground] is modified to create new styles for the inserted/deleted/unchanged nodes. The proposed solution was hard to find as it is not easy to colorize the diff lines in the current html layout which is fully flattened. I created a discussion on Adding support for code diff in Code Blocks #7608 where I explain the css difficulty. The solution manages to highlight the full line with a little hint at the beginning of the line to highlight the fact that each line should begin with its diff status:

  • "+ or >" for inserted
  • "- or <" for deleted
  • " " for unchanged

The only limitation is that the css do not colorize wrapped lines, i.e when the code line before linebreak is too long to fit in the code view. I think the trade-off is acceptable as we already have this problem with the gutter with line numbers that are not aligned with their "true" line when some lines have wrapping. The trade-off would mean that this is an acceptable solution until either

  • the @scope-siblings css directive becomes mainstream
  • the html for Code blocks is revamped to another layout, maybe with line containers (?).

For now I did not add new UX to activate the diff mode. Either we can leave it is a power user mode (via markdown or a programmatic way) or maybe add a toggle in the playground. Tell me what you prefer.

  1. [lexical-code] is modified to
  • add the diff prismjs grammar
  • integrate the new semantics where a language id can now begin with diff-xxxx to mean the code should be highlighted with diff and then xxxx
  • replicate the diff-highlight tokenization strategy in packages/lexical-code/src/CodeHighlighterPrism.ts as Prismsjs v2 is I think not going to get published in the short term.
  • adapt the codeNodeTransform code to implement the strategy : xxxx is tokenized as xxxx and diff-xxxx is tokenized as diff plus diff-highlight(xxxx).

Test plan

At this stage, I mainly did manual tests in the playground. I could add tests if you see interesting axes to test, or we could rely on the existing code block tests.

I hope that this PR will raise some interest and that we can work to make it merged into the project ! thanks for your time looking at this and for your feedback.

@vercel
Copy link
Copy Markdown

vercel bot commented Jun 8, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
lexical ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 9, 2025 9:56am
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 9, 2025 9:56am

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 8, 2025
@etrepum etrepum added the extended-tests Run extended e2e tests on a PR label Jun 8, 2025
Copy link
Copy Markdown
Collaborator

@etrepum etrepum left a comment

Choose a reason for hiding this comment

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

This seems straightforward and seemed to work well enough in the playground, it would be great to have at least one e2e test that shows that the diff support produces the expected markup both with and without a second language to tokenize (e.g. 'diff' and 'diff-javascript')

@jeromew
Copy link
Copy Markdown
Contributor Author

jeromew commented Jun 9, 2025

@etrepum I added e2e tests for language diff and diff-javascript to check the expected markup

Copy link
Copy Markdown
Collaborator

@etrepum etrepum left a comment

Choose a reason for hiding this comment

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

Nice work!

@etrepum etrepum added this pull request to the merge queue Jun 9, 2025
Merged via the queue into facebook:main with commit b07879e Jun 9, 2025
39 checks passed
@etrepum etrepum mentioned this pull request Jul 3, 2025
fantactuka pushed a commit that referenced this pull request Aug 11, 2025
GermanJablo added a commit to payloadcms/payload that referenced this pull request Sep 3, 2025
Fixes #13386

Below I write a clarification to copy and paste into the release note,
based on our latest upgrade of Lexical [in
v3.29.0](https://github.com/payloadcms/payload/releases/tag/v3.29.0).

## Important
This release upgrades the lexical dependency from 0.28.0 to 0.34.0.

If you installed lexical manually, update it to 0.34.0. Installing
lexical manually is not recommended, as it may break between updates,
and our re-exported versions should be used. See the [yellow banner
box](https://payloadcms.com/docs/rich-text/custom-features) for details.

If you still encounter richtext-lexical errors, do the following, in
this order:

- Delete node_modules
- Delete your lockfile (e.g. pnpm-lock.json)
- Reinstall your dependencies (e.g. pnpm install)

### Lexical Breaking Changes

The following Lexical releases describe breaking changes. We recommend
reading them if you're using Lexical APIs directly
(`@payloadcms/richtext-lexical/lexical/*`).

- [v.0.33.0](https://github.com/facebook/lexical/releases/tag/v0.33.0)
- [v.0.30.0](https://github.com/facebook/lexical/releases/tag/v0.30.0)
- [v.0.29.0](https://github.com/facebook/lexical/releases/tag/v0.29.0)

___

TODO:
- [x] facebook/lexical#7719
- [x] facebook/lexical#7362
- [x] facebook/lexical#7707
- [x] facebook/lexical#7388
- [x] facebook/lexical#7357
- [x] facebook/lexical#7352
- [x] facebook/lexical#7472
- [x] facebook/lexical#7556
- [x] facebook/lexical#7417
- [x] facebook/lexical#1036
- [x] facebook/lexical#7509
- [x] facebook/lexical#7693
- [x] facebook/lexical#7408
- [x] facebook/lexical#7450
- [x] facebook/lexical#7415
- [x] facebook/lexical#7368
- [x] facebook/lexical#7372
- [x] facebook/lexical#7572
- [x] facebook/lexical#7558
- [x] facebook/lexical#7613
- [x] facebook/lexical#7405
- [x] facebook/lexical#7420
- [x] facebook/lexical#7662

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1211202581885926
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. extended-tests Run extended e2e tests on a PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants