diff options
Diffstat (limited to 'imports/codemirror/mode/xmlpure/xmlpure.js')
-rw-r--r-- | imports/codemirror/mode/xmlpure/xmlpure.js | 490 |
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 | |||
9 | CodeMirror.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; | ||