MakeupDiff
A Makeup lexer for diffs and patches.
Diffs are a line-oriented format, so — unlike a lexer for a programming language — this one classifies whole lines rather than individual syntactic atoms.
Supported dialects
- Unified diffs (
diff -u,git diff,hg diff,svn diff), including@@ -old,count +new,count @@ sectionhunk headers and the@@@ ... @@@headers produced by combined (merge) diffs. - Context diffs (
diff -c): the*** old/--- newbanner pair, the***************hunk separator, the*** 1,5 ****and--- 1,7 ----range lines, and the!change marker. - Normal diffs (
diffwith no flags):1,5c1,7/3d2/0a1command lines and the</>content markers. - Git extended headers:
diff --git,index,old mode,new mode,new file mode,deleted file mode,copy from/copy to,rename from/rename to,similarity index,dissimilarity index,Binary files ... differ,GIT binary patch. - Subversion / CVS scaffolding:
Index: path, the====...rule,Property changes on:,RCS file:,retrieving revision. git format-patchmail preambles: the mboxFrom <sha> Mon Sep 17line plus the usualFrom:/Date:/Subject:/ MIME headers.- The
\ No newline at end of filemarker.
Token mapping
| Construct | Token type |
|---|---|
added lines (+, >) | :generic_inserted |
removed lines (-, <) | :generic_deleted |
changed lines in context diffs (!) | :generic_strong |
| hunk headers, range lines, file banners | :generic_subheading |
repository-level metadata (diff --git, index, ...) | :generic_heading |
| section hint trailing a unified hunk header | :name_function |
mail headers of a git format-patch preamble | :comment_preproc |
\ No newline at end of file | :comment_special |
| context lines and anything unrecognised | :text |
Ambiguity of --- and +++
A line starting with --- is either the old file banner of a unified diff
or the removal of a line whose content begins with --; the same holds for
+++. The tokenizer emits a provisional token for both and resolves it in
the postprocessing pass from the surrounding lines:
- a
---immediately followed by a+++is a banner pair; - a
---right after a repository-level heading, or at the very start of the input, is a banner; - everything else is ordinary added/removed content.
So a literal --- inside a hunk — right after an @@ header, say — is
correctly highlighted as a deleted line rather than as a file banner.
Installation
Add makeup_patch to your list of dependencies in mix.exs:
def deps do
[
{:makeup_patch, "~> 0.1"}
]
end
The lexer will be automatically registered in Makeup for the language names
"diff", "udiff" and "patch", and for the file extensions .diff and
.patch.
Usage
Once installed, ExDoc and any other tool using Makeup will automatically
syntax-highlight diff code blocks (tagged with diff as the language).
You can also use it directly:
alias Makeup.Lexers.DiffLexer
DiffLexer.lex("""
--- a/lib/app.ex
+++ b/lib/app.ex
@@ -1,3 +1,3 @@ defmodule App do
def hello do
- :world
+ :diff
end
""")
The lexer round-trips: for any input, input |> DiffLexer.lex() |> Makeup.Lexer.unlex() returns the original string.
License
MIT—see LICENSE for details.