JavaScriptgrammar.js -rw-r--r-- 2.7 KiB
1const NEWLINE = /\r?\n/;
2const WHITE_SPACE = /[\t\f\v ]+/;
3const ANYTHING = /[^\r\n]+/;
4
5module.exports = grammar({
6 name: "diff",
7
8 extras: ($) => [WHITE_SPACE],
9
10 rules: {
11 source: ($) =>
12 seq(
13 repeat(choice($.block, seq(optional($._line), NEWLINE))),
14 optional($._line)
15 ),
16
17 _line: ($) =>
18 choice(
19 $.file_change,
20 $.binary_change,
21 $.index,
22 $.similarity,
23 $.old_file,
24 $.new_file,
25 $.location,
26 $.addition,
27 $.deletion,
28 $.context,
29 $.comment
30 ),
31
32 block: ($) =>
33 prec.right(
34 seq(
35 $.command,
36 NEWLINE,
37 repeat(
38 seq(
39 choice($.file_change, $.binary_change, $.index, $.similarity),
40 NEWLINE
41 )
42 ),
43 optional(seq($.old_file, NEWLINE, $.new_file, NEWLINE, $.hunks))
44 )
45 ),
46
47 hunks: ($) => prec.right(repeat1($.hunk)),
48
49 hunk: ($) =>
50 prec.right(
51 seq(
52 field("location", $.location),
53 NEWLINE,
54 optional(field("changes", $.changes))
55 )
56 ),
57
58 changes: ($) =>
59 prec.right(
60 repeat1(
61 seq(
62 choice($.addition, $.deletion, $.context),
63 prec.right(repeat1(NEWLINE))
64 )
65 )
66 ),
67
68 command: ($) => iseq("diff", alias(/[-\w]+/, $.argument), $.filename),
69
70 file_change: ($) =>
71 choice(
72 seq(choice("new", "deleted"), "file", "mode", $.mode),
73 seq(choice("new", "old"), "mode", $.mode),
74 seq("rename", choice("from", "to"), $.filename)
75 ),
76
77 binary_change: ($) =>
78 iseq("Binary", "files", $.filename, "and", $.filename, "differ"),
79
80 index: ($) => iseq("index", $.commit, "..", $.commit, optional($.mode)),
81
82 similarity: ($) => iseq("similarity", "index", alias(/\d+/, $.score), "%"),
83
84 old_file: ($) => iseq("---", $.filename),
85 new_file: ($) => iseq("+++", $.filename),
86
87 location: ($) =>
88 iseq("@@", $.linerange, $.linerange, "@@", optional(ANYTHING)),
89
90 addition: ($) =>
91 choice(
92 iseq("+", optional(ANYTHING)),
93 iseq("++", optional(ANYTHING)),
94 iseq("+++"),
95 iseq("++++", optional(ANYTHING))
96 ),
97 deletion: ($) =>
98 choice(
99 iseq("-", optional(ANYTHING)),
100 iseq("--", optional(ANYTHING)),
101 iseq("---"),
102 iseq("----", optional(ANYTHING))
103 ),
104
105 context: ($) => token(prec(-1, ANYTHING)),
106 comment: ($) => iseq("#", optional(ANYTHING)),
107
108 linerange: ($) => /[-\+]\d+(,\d+)?/,
109 filename: ($) => repeat1(/\S+/),
110 commit: ($) => /[a-f0-9]{7,40}/,
111 mode: ($) => /\d+/,
112 },
113});
114
115function iseq(start_token, ...tokens) {
116 return seq(token.immediate(start_token), ...tokens);
117}