1 | const NEWLINE = /\r?\n/;
|
2 | const WHITE_SPACE = /[\t\f\v ]+/;
|
3 | const ANYTHING = /[^\r\n]+/;
|
4 |
|
5 | module.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 |
|
115 | function iseq(start_token, ...tokens) {
|
116 | return seq(token.immediate(start_token), ...tokens);
|
117 | }
|