Update CodeMirror to 3.14.1.
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / External / CodeMirror / xml.js
1 CodeMirror.defineMode("xml", function(config, parserConfig) {
2   var indentUnit = config.indentUnit;
3   var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
4
5   var Kludges = parserConfig.htmlMode ? {
6     autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
7                       'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
8                       'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
9                       'track': true, 'wbr': true},
10     implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
11                        'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
12                        'th': true, 'tr': true},
13     contextGrabbers: {
14       'dd': {'dd': true, 'dt': true},
15       'dt': {'dd': true, 'dt': true},
16       'li': {'li': true},
17       'option': {'option': true, 'optgroup': true},
18       'optgroup': {'optgroup': true},
19       'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
20             'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
21             'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
22             'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
23             'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
24       'rp': {'rp': true, 'rt': true},
25       'rt': {'rp': true, 'rt': true},
26       'tbody': {'tbody': true, 'tfoot': true},
27       'td': {'td': true, 'th': true},
28       'tfoot': {'tbody': true},
29       'th': {'td': true, 'th': true},
30       'thead': {'tbody': true, 'tfoot': true},
31       'tr': {'tr': true}
32     },
33     doNotIndent: {"pre": true},
34     allowUnquoted: true,
35     allowMissing: true
36   } : {
37     autoSelfClosers: {},
38     implicitlyClosed: {},
39     contextGrabbers: {},
40     doNotIndent: {},
41     allowUnquoted: false,
42     allowMissing: false
43   };
44   var alignCDATA = parserConfig.alignCDATA;
45
46   // Return variables for tokenizers
47   var tagName, type;
48
49   function inText(stream, state) {
50     function chain(parser) {
51       state.tokenize = parser;
52       return parser(stream, state);
53     }
54
55     var ch = stream.next();
56     if (ch == "<") {
57       if (stream.eat("!")) {
58         if (stream.eat("[")) {
59           if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
60           else return null;
61         } else if (stream.match("--")) {
62           return chain(inBlock("comment", "-->"));
63         } else if (stream.match("DOCTYPE", true, true)) {
64           stream.eatWhile(/[\w\._\-]/);
65           return chain(doctype(1));
66         } else {
67           return null;
68         }
69       } else if (stream.eat("?")) {
70         stream.eatWhile(/[\w\._\-]/);
71         state.tokenize = inBlock("meta", "?>");
72         return "meta";
73       } else {
74         var isClose = stream.eat("/");
75         tagName = "";
76         var c;
77         while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
78         if (!tagName) return "error";
79         type = isClose ? "closeTag" : "openTag";
80         state.tokenize = inTag;
81         return "tag";
82       }
83     } else if (ch == "&") {
84       var ok;
85       if (stream.eat("#")) {
86         if (stream.eat("x")) {
87           ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
88         } else {
89           ok = stream.eatWhile(/[\d]/) && stream.eat(";");
90         }
91       } else {
92         ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
93       }
94       return ok ? "atom" : "error";
95     } else {
96       stream.eatWhile(/[^&<]/);
97       return null;
98     }
99   }
100
101   function inTag(stream, state) {
102     var ch = stream.next();
103     if (ch == ">" || (ch == "/" && stream.eat(">"))) {
104       state.tokenize = inText;
105       type = ch == ">" ? "endTag" : "selfcloseTag";
106       return "tag";
107     } else if (ch == "=") {
108       type = "equals";
109       return null;
110     } else if (ch == "<") {
111       return "error";
112     } else if (/[\'\"]/.test(ch)) {
113       state.tokenize = inAttribute(ch);
114       return state.tokenize(stream, state);
115     } else {
116       stream.eatWhile(/[^\s\u00a0=<>\"\']/);
117       return "word";
118     }
119   }
120
121   function inAttribute(quote) {
122     return function(stream, state) {
123       while (!stream.eol()) {
124         if (stream.next() == quote) {
125           state.tokenize = inTag;
126           break;
127         }
128       }
129       return "string";
130     };
131   }
132
133   function inBlock(style, terminator) {
134     return function(stream, state) {
135       while (!stream.eol()) {
136         if (stream.match(terminator)) {
137           state.tokenize = inText;
138           break;
139         }
140         stream.next();
141       }
142       return style;
143     };
144   }
145   function doctype(depth) {
146     return function(stream, state) {
147       var ch;
148       while ((ch = stream.next()) != null) {
149         if (ch == "<") {
150           state.tokenize = doctype(depth + 1);
151           return state.tokenize(stream, state);
152         } else if (ch == ">") {
153           if (depth == 1) {
154             state.tokenize = inText;
155             break;
156           } else {
157             state.tokenize = doctype(depth - 1);
158             return state.tokenize(stream, state);
159           }
160         }
161       }
162       return "meta";
163     };
164   }
165
166   var curState, curStream, setStyle;
167   function pass() {
168     for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
169   }
170   function cont() {
171     pass.apply(null, arguments);
172     return true;
173   }
174
175   function pushContext(tagName, startOfLine) {
176     var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
177     curState.context = {
178       prev: curState.context,
179       tagName: tagName,
180       indent: curState.indented,
181       startOfLine: startOfLine,
182       noIndent: noIndent
183     };
184   }
185   function popContext() {
186     if (curState.context) curState.context = curState.context.prev;
187   }
188
189   function element(type) {
190     if (type == "openTag") {
191       curState.tagName = tagName;
192       curState.tagStart = curStream.column();
193       return cont(attributes, endtag(curState.startOfLine));
194     } else if (type == "closeTag") {
195       var err = false;
196       if (curState.context) {
197         if (curState.context.tagName != tagName) {
198           if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
199             popContext();
200           }
201           err = !curState.context || curState.context.tagName != tagName;
202         }
203       } else {
204         err = true;
205       }
206       if (err) setStyle = "error";
207       return cont(endclosetag(err));
208     }
209     return cont();
210   }
211   function endtag(startOfLine) {
212     return function(type) {
213       var tagName = curState.tagName;
214       curState.tagName = curState.tagStart = null;
215       if (type == "selfcloseTag" ||
216           (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
217         maybePopContext(tagName.toLowerCase());
218         return cont();
219       }
220       if (type == "endTag") {
221         maybePopContext(tagName.toLowerCase());
222         pushContext(tagName, startOfLine);
223         return cont();
224       }
225       return cont();
226     };
227   }
228   function endclosetag(err) {
229     return function(type) {
230       if (err) setStyle = "error";
231       if (type == "endTag") { popContext(); return cont(); }
232       setStyle = "error";
233       return cont(arguments.callee);
234     };
235   }
236   function maybePopContext(nextTagName) {
237     var parentTagName;
238     while (true) {
239       if (!curState.context) {
240         return;
241       }
242       parentTagName = curState.context.tagName.toLowerCase();
243       if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
244           !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
245         return;
246       }
247       popContext();
248     }
249   }
250
251   function attributes(type) {
252     if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
253     if (type == "endTag" || type == "selfcloseTag") return pass();
254     setStyle = "error";
255     return cont(attributes);
256   }
257   function attribute(type) {
258     if (type == "equals") return cont(attvalue, attributes);
259     if (!Kludges.allowMissing) setStyle = "error";
260     else if (type == "word") setStyle = "attribute";
261     return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
262   }
263   function attvalue(type) {
264     if (type == "string") return cont(attvaluemaybe);
265     if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
266     setStyle = "error";
267     return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
268   }
269   function attvaluemaybe(type) {
270     if (type == "string") return cont(attvaluemaybe);
271     else return pass();
272   }
273
274   return {
275     startState: function() {
276       return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
277     },
278
279     token: function(stream, state) {
280       if (!state.tagName && stream.sol()) {
281         state.startOfLine = true;
282         state.indented = stream.indentation();
283       }
284       if (stream.eatSpace()) return null;
285
286       setStyle = type = tagName = null;
287       var style = state.tokenize(stream, state);
288       state.type = type;
289       if ((style || type) && style != "comment") {
290         curState = state; curStream = stream;
291         while (true) {
292           var comb = state.cc.pop() || element;
293           if (comb(type || style)) break;
294         }
295       }
296       state.startOfLine = false;
297       return setStyle || style;
298     },
299
300     indent: function(state, textAfter, fullLine) {
301       var context = state.context;
302       if ((state.tokenize != inTag && state.tokenize != inText) ||
303           context && context.noIndent)
304         return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
305       if (state.tagName) return state.tagStart + indentUnit * multilineTagIndentFactor;
306       if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
307       if (context && /^<\//.test(textAfter))
308         context = context.prev;
309       while (context && !context.startOfLine)
310         context = context.prev;
311       if (context) return context.indent + indentUnit;
312       else return 0;
313     },
314
315     electricChars: "/",
316     blockCommentStart: "<!--",
317     blockCommentEnd: "-->",
318
319     configuration: parserConfig.htmlMode ? "html" : "xml",
320     helperType: parserConfig.htmlMode ? "html" : "xml"
321   };
322 });
323
324 CodeMirror.defineMIME("text/xml", "xml");
325 CodeMirror.defineMIME("application/xml", "xml");
326 if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
327   CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});