scripts/CodeMirror/mode/jinja2/jinja2.js (view raw)
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4(function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11})(function(CodeMirror) {
12 "use strict";
13
14 CodeMirror.defineMode("jinja2", function() {
15 var keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif",
16 "extends", "filter", "endfilter", "firstof", "for",
17 "endfor", "if", "endif", "ifchanged", "endifchanged",
18 "ifequal", "endifequal", "ifnotequal",
19 "endifnotequal", "in", "include", "load", "not", "now", "or",
20 "parsed", "regroup", "reversed", "spaceless",
21 "endspaceless", "ssi", "templatetag", "openblock",
22 "closeblock", "openvariable", "closevariable",
23 "openbrace", "closebrace", "opencomment",
24 "closecomment", "widthratio", "url", "with", "endwith",
25 "get_current_language", "trans", "endtrans", "noop", "blocktrans",
26 "endblocktrans", "get_available_languages",
27 "get_current_language_bidi", "plural"],
28 operator = /^[+\-*&%=<>!?|~^]/,
29 sign = /^[:\[\(\{]/,
30 atom = ["true", "false"],
31 number = /^(\d[+\-\*\/])?\d+(\.\d+)?/;
32
33 keywords = new RegExp("((" + keywords.join(")|(") + "))\\b");
34 atom = new RegExp("((" + atom.join(")|(") + "))\\b");
35
36 function tokenBase (stream, state) {
37 var ch = stream.peek();
38
39 //Comment
40 if (state.incomment) {
41 if(!stream.skipTo("#}")) {
42 stream.skipToEnd();
43 } else {
44 stream.eatWhile(/\#|}/);
45 state.incomment = false;
46 }
47 return "comment";
48 //Tag
49 } else if (state.intag) {
50 //After operator
51 if(state.operator) {
52 state.operator = false;
53 if(stream.match(atom)) {
54 return "atom";
55 }
56 if(stream.match(number)) {
57 return "number";
58 }
59 }
60 //After sign
61 if(state.sign) {
62 state.sign = false;
63 if(stream.match(atom)) {
64 return "atom";
65 }
66 if(stream.match(number)) {
67 return "number";
68 }
69 }
70
71 if(state.instring) {
72 if(ch == state.instring) {
73 state.instring = false;
74 }
75 stream.next();
76 return "string";
77 } else if(ch == "'" || ch == '"') {
78 state.instring = ch;
79 stream.next();
80 return "string";
81 } else if(stream.match(state.intag + "}") || stream.eat("-") && stream.match(state.intag + "}")) {
82 state.intag = false;
83 return "tag";
84 } else if(stream.match(operator)) {
85 state.operator = true;
86 return "operator";
87 } else if(stream.match(sign)) {
88 state.sign = true;
89 } else {
90 if(stream.eat(" ") || stream.sol()) {
91 if(stream.match(keywords)) {
92 return "keyword";
93 }
94 if(stream.match(atom)) {
95 return "atom";
96 }
97 if(stream.match(number)) {
98 return "number";
99 }
100 if(stream.sol()) {
101 stream.next();
102 }
103 } else {
104 stream.next();
105 }
106
107 }
108 return "variable";
109 } else if (stream.eat("{")) {
110 if (stream.eat("#")) {
111 state.incomment = true;
112 if(!stream.skipTo("#}")) {
113 stream.skipToEnd();
114 } else {
115 stream.eatWhile(/\#|}/);
116 state.incomment = false;
117 }
118 return "comment";
119 //Open tag
120 } else if (ch = stream.eat(/\{|%/)) {
121 //Cache close tag
122 state.intag = ch;
123 if(ch == "{") {
124 state.intag = "}";
125 }
126 stream.eat("-");
127 return "tag";
128 }
129 }
130 stream.next();
131 };
132
133 return {
134 startState: function () {
135 return {tokenize: tokenBase};
136 },
137 token: function (stream, state) {
138 return state.tokenize(stream, state);
139 },
140 blockCommentStart: "{#",
141 blockCommentEnd: "#}"
142 };
143 });
144
145 CodeMirror.defineMIME("text/jinja2", "jinja2");
146});