123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
- // Distributed under an MIT license: https://codemirror.net/LICENSE
- ;(function (mod) {
- if (typeof exports == 'object' && typeof module == 'object')
- // CommonJS
- mod(require('../../lib/codemirror'), require('../xml/xml'), require('../javascript/javascript'))
- else if (typeof define == 'function' && define.amd)
- // AMD
- define(['../../lib/codemirror', '../xml/xml', '../javascript/javascript'], mod)
- // Plain browser env
- else mod(CodeMirror)
- })(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 new Context(CodeMirror.copyState(context.mode, context.state), context.mode, context.depth, context.prev && copyContext(context.prev))
- }
- CodeMirror.defineMode(
- 'jsx',
- function (config, modeConfig) {
- var xmlMode = CodeMirror.getMode(config, { name: 'xml', allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true })
- 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)) {
- state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, '', '')), xmlMode, 0, state.context)
- jsMode.skipExpression(cx.state)
- 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: new Context(CodeMirror.startState(jsMode), jsMode) }
- },
- copyState: function (state) {
- return { context: copyContext(state.context) }
- },
- token: token,
- indent: function (state, textAfter, fullLine) {
- return state.context.mode.indent(state.context.state, textAfter, fullLine)
- },
- innerMode: function (state) {
- return state.context
- },
- }
- },
- 'xml',
- 'javascript'
- )
- CodeMirror.defineMIME('text/jsx', 'jsx')
- CodeMirror.defineMIME('text/typescript-jsx', { name: 'jsx', base: { name: 'javascript', typescript: true } })
- })
|