(quote, f)
| 241 | // tokenizer for string literals |
| 242 | // optionally pass a tokenizer function to set state.tokenize back to when finished |
| 243 | function tokenString(quote, f) { |
| 244 | return function(stream, state) { |
| 245 | var ch; |
| 246 | |
| 247 | if(isInString(state) && stream.current() == quote) { |
| 248 | popStateStack(state); |
| 249 | if(f) state.tokenize = f; |
| 250 | return ret("string", "string"); |
| 251 | } |
| 252 | |
| 253 | pushStateStack(state, { type: "string", name: quote, tokenize: tokenString(quote, f) }); |
| 254 | |
| 255 | // if we're in a string and in an XML block, allow an embedded code block |
| 256 | if(stream.match("{", false) && isInXmlAttributeBlock(state)) { |
| 257 | state.tokenize = tokenBase; |
| 258 | return ret("string", "string"); |
| 259 | } |
| 260 | |
| 261 | |
| 262 | while (ch = stream.next()) { |
| 263 | if (ch == quote) { |
| 264 | popStateStack(state); |
| 265 | if(f) state.tokenize = f; |
| 266 | break; |
| 267 | } |
| 268 | else { |
| 269 | // if we're in a string and in an XML block, allow an embedded code block in an attribute |
| 270 | if(stream.match("{", false) && isInXmlAttributeBlock(state)) { |
| 271 | state.tokenize = tokenBase; |
| 272 | return ret("string", "string"); |
| 273 | } |
| 274 | |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | return ret("string", "string"); |
| 279 | }; |
| 280 | } |
| 281 | |
| 282 | // tokenizer for variables |
| 283 | function tokenVariable(stream, state) { |
no test coverage detected