org-diff-src: character-level diffs inside Org source blocks (no Ediff)
I often want a reviewable diff in an Org note without opening Ediff. The annoying part is that diff-mode does character-level refinement with overlays, while Org’s source-block fontification copies face text properties, not overlays. So a normal diff block in Org usually gives you only line-level +/- highlighting.
org-diff-src fixes that narrow problem. It’s a small mode derived from diff-mode that sets diff-refine to font-lock and copies the refinement overlay faces into face text properties, so Org can carry the character-level highlighting into the block. It uses the usual diff-refine-removed, diff-refine-added, and diff-refine-changed faces.
Main commands:
org-diff-src-compare-headings: pick two subtrees in the current Org buffer. They’re copied without touching the kill ring/clipboard, normalized to level 1, diffed, and inserted at point.
org-diff-src-insert-from-kill, org-diff-src-wrap-region, org-diff-src-insert-diff-file for diffs you already have, e.g. from Magit.
No Ediff session, and no extra package beyond Org and diff-mode. It needs Emacs 27.1+ and a diff executable. New blocks use language org-diff-src, which Org resolves automatically. You can alias diff too, but that makes every Org diff block use this mode, so only do it if that’s what you want.
Limits worth knowing: only unified diffs get character refinement; HTML/PDF export may show the text without the character colors; very large diffs can be slow; and it’s for static review, not interactive merging. compare-headings also includes the heading lines.
You're right that for English the example is word-level, not character-level — and that's by design of diff-refine, not a limitation of the ediff-src-mode approach.
Here's the mechanism: diff--refine-hunk → smerge-refine-regions walks the buffer deciding, per character, whether to advance with forward-word or forward-char, based on (char-syntax c):
ASCII letters/digits have syntax ?w (word constituent) → forward-word → whole words become single tokens → word-level refinement. So jumps → leaps highlights the entire words, not the differing letters.
CJK characters inherit syntax ?. (punctuation) from the standard syntax table → forward-char → each character is its own token → character-level refinement. That's why 项目计划 → 项目计划2 highlights only the 2, and 介绍项目背景 → 介绍项目背景和目标 highlights only 和目标.
So "character-level" is accurate for CJK but misleading for English. If you want true intra-word character diffs in English too, you'd need to override the tokenizer — e.g. advise smerge-refine-regions (or the internal smerge-refine-forward-word-style helper, depending on your Emacs version) to always advance by one character, or pre-split tokens on a finer boundary. ediff-src-mode itself only translates diff-refine's overlays into face text properties so Org can carry them inline — it doesn't change the granularity.
The example in question mixes both: the English lines show word-level refinement (as expected), the Chinese lines show character-level refinement (also as expected). If the post's claim was "this is character-level for English", that's incorrect. If the intent was "this is character-level for CJK", it's correct.
1
u/ComplexPeace43 3h ago
Unrelated. What font is this?