aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/mode/xmlpure/xmlpure.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/mode/xmlpure/xmlpure.js')
-rw-r--r--imports/codemirror/mode/xmlpure/xmlpure.js490
1 files changed, 0 insertions, 490 deletions
diff --git a/imports/codemirror/mode/xmlpure/xmlpure.js b/imports/codemirror/mode/xmlpure/xmlpure.js
deleted file mode 100644
index 18d710cf..00000000
--- a/imports/codemirror/mode/xmlpure/xmlpure.js
+++ /dev/null
@@ -1,490 +0,0 @@
1/**
2 * xmlpure.js
3 *
4 * Building upon and improving the CodeMirror 2 XML parser
5 * @author: Dror BG (deebug.dev@gmail.com)
6 * @date: August, 2011
7 */
8
9CodeMirror.defineMode("xmlpure", function(config, parserConfig) {
10 // constants
11 var STYLE_ERROR = "error";
12 var STYLE_INSTRUCTION = "comment";
13 var STYLE_COMMENT = "comment";
14 var STYLE_ELEMENT_NAME = "tag";
15 var STYLE_ATTRIBUTE = "attribute";
16 var STYLE_WORD = "string";
17 var STYLE_TEXT = "atom";
18 var STYLE_ENTITIES = "string";
19
20 var TAG_INSTRUCTION = "!instruction";
21 var TAG_CDATA = "!cdata";
22 var TAG_COMMENT = "!comment";
23 var TAG_TEXT = "!text";
24
25 var doNotIndent = {
26 "!cdata": true,
27 "!comment": true,
28 "!text": true,
29 "!instruction": true
30 };
31
32 // options
33 var indentUnit = config.indentUnit;
34
35 ///////////////////////////////////////////////////////////////////////////
36 // helper functions
37
38 // chain a parser to another parser
39 function chain(stream, state, parser) {
40 state.tokenize = parser;
41 return parser(stream, state);
42 }
43
44 // parse a block (comment, CDATA or text)
45 function inBlock(style, terminator, nextTokenize) {
46 return function(stream, state) {
47 while (!stream.eol()) {
48 if (stream.match(terminator)) {
49 popContext(state);
50 state.tokenize = nextTokenize;
51 break;
52 }
53 stream.next();
54 }
55 return style;
56 };
57 }
58
59 // go down a level in the document
60 // (hint: look at who calls this function to know what the contexts are)
61 function pushContext(state, tagName) {
62 var noIndent = doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.doIndent);
63 var newContext = {
64 tagName: tagName,
65 prev: state.context,
66 indent: state.context ? state.context.indent + indentUnit : 0,
67 lineNumber: state.lineNumber,
68 indented: state.indented,
69 noIndent: noIndent
70 };
71 state.context = newContext;
72 }
73
74 // go up a level in the document
75 function popContext(state) {
76 if (state.context) {
77 var oldContext = state.context;
78 state.context = oldContext.prev;
79 return oldContext;
80 }
81
82 // we shouldn't be here - it means we didn't have a context to pop
83 return null;
84 }
85
86 // return true if the current token is seperated from the tokens before it
87 // which means either this is the start of the line, or there is at least
88 // one space or tab character behind the token
89 // otherwise returns false
90 function isTokenSeparated(stream) {
91 return stream.sol() ||
92 stream.string.charAt(stream.start - 1) == " " ||
93 stream.string.charAt(stream.start - 1) == "\t";
94 }
95
96 ///////////////////////////////////////////////////////////////////////////
97 // context: document
98 //
99 // an XML document can contain:
100 // - a single declaration (if defined, it must be the very first line)
101 // - exactly one root element
102 // @todo try to actually limit the number of root elements to 1
103 // - zero or more comments
104 function parseDocument(stream, state) {
105 if(stream.eat("<")) {
106 if(stream.eat("?")) {
107 // processing instruction
108 pushContext(state, TAG_INSTRUCTION);
109 state.tokenize = parseProcessingInstructionStartTag;
110 return STYLE_INSTRUCTION;
111 } else if(stream.match("!--")) {
112 // new context: comment
113 pushContext(state, TAG_COMMENT);
114 return chain(stream, state, inBlock(STYLE_COMMENT, "-->", parseDocument));
115 } else if(stream.eatSpace() || stream.eol() ) {
116 stream.skipToEnd();
117 return STYLE_ERROR;
118 } else {
119 // element
120 state.tokenize = parseElementTagName;
121 return STYLE_ELEMENT_NAME;
122 }
123 }
124
125 // error on line
126 stream.skipToEnd();
127 return STYLE_ERROR;
128 }
129
130 ///////////////////////////////////////////////////////////////////////////
131 // context: XML element start-tag or end-tag
132 //
133 // - element start-tag can contain attributes
134 // - element start-tag may self-close (or start an element block if it doesn't)
135 // - element end-tag can contain only the tag name
136 function parseElementTagName(stream, state) {
137 // get the name of the tag
138 var startPos = stream.pos;
139 if(stream.match(/^[a-zA-Z_:][-a-zA-Z0-9_:.]*/)) {
140 // element start-tag
141 var tagName = stream.string.substring(startPos, stream.pos);
142 pushContext(state, tagName);
143 state.tokenize = parseElement;
144 return STYLE_ELEMENT_NAME;
145 } else if(stream.match(/^\/[a-zA-Z_:][-a-zA-Z0-9_:.]*( )*>/)) {
146 // element end-tag
147 var endTagName = stream.string.substring(startPos + 1, stream.pos - 1).trim();
148 var oldContext = popContext(state);
149 state.tokenize = state.context == null ? parseDocument : parseElementBlock;
150 if(oldContext == null || endTagName != oldContext.tagName) {
151 // the start and end tag names should match - error
152 return STYLE_ERROR;
153 }
154 return STYLE_ELEMENT_NAME;
155 } else {
156 // no tag name - error
157 state.tokenize = state.context == null ? parseDocument : parseElementBlock;
158 stream.eatWhile(/[^>]/);
159 stream.eat(">");
160 return STYLE_ERROR;
161 }
162
163 stream.skipToEnd();
164 return null;
165 }
166
167 function parseElement(stream, state) {
168 if(stream.match(/^\/>/)) {
169 // self-closing tag
170 popContext(state);
171 state.tokenize = state.context == null ? parseDocument : parseElementBlock;
172 return STYLE_ELEMENT_NAME;
173 } else if(stream.eat(/^>/)) {
174 state.tokenize = parseElementBlock;
175 return STYLE_ELEMENT_NAME;
176 } else if(isTokenSeparated(stream) && stream.match(/^[a-zA-Z_:][-a-zA-Z0-9_:.]*( )*=/)) {
177 // attribute
178 state.tokenize = parseAttribute;
179 return STYLE_ATTRIBUTE;
180 }
181
182 // no other options - this is an error
183 state.tokenize = state.context == null ? parseDocument : parseDocument;
184 stream.eatWhile(/[^>]/);
185 stream.eat(">");
186 return STYLE_ERROR;
187 }
188
189 ///////////////////////////////////////////////////////////////////////////
190 // context: attribute
191 //
192 // attribute values may contain everything, except:
193 // - the ending quote (with ' or ") - this marks the end of the value
194 // - the character "<" - should never appear
195 // - ampersand ("&") - unless it starts a reference: a string that ends with a semi-colon (";")
196 // ---> note: this parser is lax in what may be put into a reference string,
197 // ---> consult http://www.w3.org/TR/REC-xml/#NT-Reference if you want to make it tighter
198 function parseAttribute(stream, state) {
199 var quote = stream.next();
200 if(quote != "\"" && quote != "'") {
201 // attribute must be quoted
202 stream.skipToEnd();
203 state.tokenize = parseElement;
204 return STYLE_ERROR;
205 }
206
207 state.tokParams.quote = quote;
208 state.tokenize = parseAttributeValue;
209 return STYLE_WORD;
210 }
211
212 // @todo: find out whether this attribute value spans multiple lines,
213 // and if so, push a context for it in order not to indent it
214 // (or something of the sort..)
215 function parseAttributeValue(stream, state) {
216 var ch = "";
217 while(!stream.eol()) {
218 ch = stream.next();
219 if(ch == state.tokParams.quote) {
220 // end quote found
221 state.tokenize = parseElement;
222 return STYLE_WORD;
223 } else if(ch == "<") {
224 // can't have less-than signs in an attribute value, ever
225 stream.skipToEnd()
226 state.tokenize = parseElement;
227 return STYLE_ERROR;