Index: third_party/WebKit/Source/devtools/front_end/cm_modes/jsx.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/cm_modes/jsx.js b/third_party/WebKit/Source/devtools/front_end/cm_modes/jsx.js |
index c3d227a88206039d24bab7aac80490e2459fd2ba..aff01b8d355665439b84201950e7a6b0616d5dff 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/cm_modes/jsx.js |
+++ b/third_party/WebKit/Source/devtools/front_end/cm_modes/jsx.js |
@@ -11,75 +11,137 @@ |
})(function(CodeMirror) { |
"use strict" |
+ // Depth means the amount of open braces in JS context, in XML |
+ // context 0 means not in tag, 1 means in tag, and 2 means in tag |
+ // and js block comment. |
+ function Context(state, mode, depth, prev) { |
+ this.state = state; this.mode = mode; this.depth = depth; this.prev = prev |
+ } |
+ |
function copyContext(context) { |
- return {state: CodeMirror.copyState(context.mode, context.state), |
- mode: context.mode, |
- depth: context.depth, |
- prev: context.prev && copyContext(context.prev)} |
+ return new Context(CodeMirror.copyState(context.mode, context.state), |
+ context.mode, |
+ context.depth, |
+ context.prev && copyContext(context.prev)) |
} |
- CodeMirror.defineMode("jsx", function(config) { |
- var xmlMode = CodeMirror.getMode(config, "xml") |
- var jsMode = CodeMirror.getMode(config, "javascript") |
+ CodeMirror.defineMode("jsx", function(config, modeConfig) { |
+ var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false}) |
+ var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript") |
+ |
+ function flatXMLIndent(state) { |
+ var tagName = state.tagName |
+ state.tagName = null |
+ var result = xmlMode.indent(state, "") |
+ state.tagName = tagName |
+ return result |
+ } |
+ |
+ function token(stream, state) { |
+ if (state.context.mode == xmlMode) |
+ return xmlToken(stream, state, state.context) |
+ else |
+ return jsToken(stream, state, state.context) |
+ } |
+ |
+ function xmlToken(stream, state, cx) { |
+ if (cx.depth == 2) { // Inside a JS /* */ comment |
+ if (stream.match(/^.*?\*\//)) cx.depth = 1 |
+ else stream.skipToEnd() |
+ return "comment" |
+ } |
+ |
+ if (stream.peek() == "{") { |
+ xmlMode.skipAttribute(cx.state) |
+ |
+ var indent = flatXMLIndent(cx.state), xmlContext = cx.state.context |
+ // If JS starts on same line as tag |
+ if (xmlContext && stream.match(/^[^>]*>\s*$/, false)) { |
+ while (xmlContext.prev && !xmlContext.startOfLine) |
+ xmlContext = xmlContext.prev |
+ // If tag starts the line, use XML indentation level |
+ if (xmlContext.startOfLine) indent -= config.indentUnit |
+ // Else use JS indentation level |
+ else if (cx.prev.state.lexical) indent = cx.prev.state.lexical.indented |
+ // Else if inside of tag |
+ } else if (cx.depth == 1) { |
+ indent += config.indentUnit |
+ } |
+ |
+ state.context = new Context(CodeMirror.startState(jsMode, indent), |
+ jsMode, 0, state.context) |
+ return null |
+ } |
+ |
+ if (cx.depth == 1) { // Inside of tag |
+ if (stream.peek() == "<") { // Tag inside of tag |
+ xmlMode.skipAttribute(cx.state) |
+ state.context = new Context(CodeMirror.startState(xmlMode, flatXMLIndent(cx.state)), |
+ xmlMode, 0, state.context) |
+ return null |
+ } else if (stream.match("//")) { |
+ stream.skipToEnd() |
+ return "comment" |
+ } else if (stream.match("/*")) { |
+ cx.depth = 2 |
+ return token(stream, state) |
+ } |
+ } |
+ |
+ var style = xmlMode.token(stream, cx.state), cur = stream.current(), stop |
+ if (/\btag\b/.test(style)) { |
+ if (/>$/.test(cur)) { |
+ if (cx.state.context) cx.depth = 0 |
+ else state.context = state.context.prev |
+ } else if (/^</.test(cur)) { |
+ cx.depth = 1 |
+ } |
+ } else if (!style && (stop = cur.indexOf("{")) > -1) { |
+ stream.backUp(cur.length - stop) |
+ } |
+ return style |
+ } |
+ |
+ function jsToken(stream, state, cx) { |
+ if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) { |
+ jsMode.skipExpression(cx.state) |
+ state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")), |
+ xmlMode, 0, state.context) |
+ return null |
+ } |
+ |
+ var style = jsMode.token(stream, cx.state) |
+ if (!style && cx.depth != null) { |
+ var cur = stream.current() |
+ if (cur == "{") { |
+ cx.depth++ |
+ } else if (cur == "}") { |
+ if (--cx.depth == 0) state.context = state.context.prev |
+ } |
+ } |
+ return style |
+ } |
return { |
startState: function() { |
- return {context: {state: CodeMirror.startState(jsMode), mode: jsMode}} |
+ return {context: new Context(CodeMirror.startState(jsMode), jsMode)} |
}, |
copyState: function(state) { |
return {context: copyContext(state.context)} |
}, |
- token: function(stream, state) { |
- var cx = state.context |
- if (cx.mode == xmlMode) { |
- if (stream.peek() == "{") { |
- xmlMode.skipAttribute(cx.state) |
- state.context = {state: CodeMirror.startState(jsMode, xmlMode.indent(cx.state, "")), |
- mode: jsMode, |
- depth: 1, |
- prev: state.context} |
- return jsMode.token(stream, state.context.state) |
- } else { // FIXME skip attribute |
- var style = xmlMode.token(stream, cx.state), cur, brace |
- if (/\btag\b/.test(style) && !cx.state.context && /^\/?>$/.test(stream.current())) |
- state.context = state.context.prev |
- else if (!style && (brace = (cur = stream.current()).indexOf("{")) > -1) |
- stream.backUp(cur.length - brace) |
- return style |
- } |
- } else { // jsMode |
- if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) { |
- jsMode.skipExpression(cx.state) |
- state.context = {state: CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")), |
- mode: xmlMode, |
- prev: state.context} |
- return xmlMode.token(stream, state.context.state) |
- } else { |
- var style = jsMode.token(stream, cx.state) |
- if (!style && cx.depth != null) { |
- var cur = stream.current() |
- if (cur == "{") { |
- cx.depth++ |
- } else if (cur == "}") { |
- if (--cx.depth == 0) state.context = state.context.prev |
- } |
- } |
- return style |
- } |
- } |
- }, |
+ token: token, |
indent: function(state, textAfter, fullLine) { |
return state.context.mode.indent(state.context.state, textAfter, fullLine) |
}, |
innerMode: function(state) { |
- return state.context[state.context.length - 1] |
+ return state.context |
} |
} |
}, "xml", "javascript") |
CodeMirror.defineMIME("text/jsx", "jsx") |
-}) |
+}); |