123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- // 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('../javascript/javascript'), require('../css/css'), require('../htmlmixed/htmlmixed'))
- else if (typeof define == 'function' && define.amd)
- // AMD
- define(['../../lib/codemirror', '../javascript/javascript', '../css/css', '../htmlmixed/htmlmixed'], mod)
- // Plain browser env
- else mod(CodeMirror)
- })(function (CodeMirror) {
- 'use strict'
- CodeMirror.defineMode(
- 'pug',
- function (config) {
- // token types
- var KEYWORD = 'keyword'
- var DOCTYPE = 'meta'
- var ID = 'builtin'
- var CLASS = 'qualifier'
- var ATTRS_NEST = {
- '{': '}',
- '(': ')',
- '[': ']',
- }
- var jsMode = CodeMirror.getMode(config, 'javascript')
- function State() {
- this.javaScriptLine = false
- this.javaScriptLineExcludesColon = false
- this.javaScriptArguments = false
- this.javaScriptArgumentsDepth = 0
- this.isInterpolating = false
- this.interpolationNesting = 0
- this.jsState = CodeMirror.startState(jsMode)
- this.restOfLine = ''
- this.isIncludeFiltered = false
- this.isEach = false
- this.lastTag = ''
- this.scriptType = ''
- // Attributes Mode
- this.isAttrs = false
- this.attrsNest = []
- this.inAttributeName = true
- this.attributeIsType = false
- this.attrValue = ''
- // Indented Mode
- this.indentOf = Infinity
- this.indentToken = ''
- this.innerMode = null
- this.innerState = null
- this.innerModeForLine = false
- }
- /**
- * Safely copy a state
- *
- * @return {State}
- */
- State.prototype.copy = function () {
- var res = new State()
- res.javaScriptLine = this.javaScriptLine
- res.javaScriptLineExcludesColon = this.javaScriptLineExcludesColon
- res.javaScriptArguments = this.javaScriptArguments
- res.javaScriptArgumentsDepth = this.javaScriptArgumentsDepth
- res.isInterpolating = this.isInterpolating
- res.interpolationNesting = this.interpolationNesting
- res.jsState = CodeMirror.copyState(jsMode, this.jsState)
- res.innerMode = this.innerMode
- if (this.innerMode && this.innerState) {
- res.innerState = CodeMirror.copyState(this.innerMode, this.innerState)
- }
- res.restOfLine = this.restOfLine
- res.isIncludeFiltered = this.isIncludeFiltered
- res.isEach = this.isEach
- res.lastTag = this.lastTag
- res.scriptType = this.scriptType
- res.isAttrs = this.isAttrs
- res.attrsNest = this.attrsNest.slice()
- res.inAttributeName = this.inAttributeName
- res.attributeIsType = this.attributeIsType
- res.attrValue = this.attrValue
- res.indentOf = this.indentOf
- res.indentToken = this.indentToken
- res.innerModeForLine = this.innerModeForLine
- return res
- }
- function javaScript(stream, state) {
- if (stream.sol()) {
- // if javaScriptLine was set at end of line, ignore it
- state.javaScriptLine = false
- state.javaScriptLineExcludesColon = false
- }
- if (state.javaScriptLine) {
- if (state.javaScriptLineExcludesColon && stream.peek() === ':') {
- state.javaScriptLine = false
- state.javaScriptLineExcludesColon = false
- return
- }
- var tok = jsMode.token(stream, state.jsState)
- if (stream.eol()) state.javaScriptLine = false
- return tok || true
- }
- }
- function javaScriptArguments(stream, state) {
- if (state.javaScriptArguments) {
- if (state.javaScriptArgumentsDepth === 0 && stream.peek() !== '(') {
- state.javaScriptArguments = false
- return
- }
- if (stream.peek() === '(') {
- state.javaScriptArgumentsDepth++
- } else if (stream.peek() === ')') {
- state.javaScriptArgumentsDepth--
- }
- if (state.javaScriptArgumentsDepth === 0) {
- state.javaScriptArguments = false
- return
- }
- var tok = jsMode.token(stream, state.jsState)
- return tok || true
- }
- }
- function yieldStatement(stream) {
- if (stream.match(/^yield\b/)) {
- return 'keyword'
- }
- }
- function doctype(stream) {
- if (stream.match(/^(?:doctype) *([^\n]+)?/)) {
- return DOCTYPE
- }
- }
- function interpolation(stream, state) {
- if (stream.match('#{')) {
- state.isInterpolating = true
- state.interpolationNesting = 0
- return 'punctuation'
- }
- }
- function interpolationContinued(stream, state) {
- if (state.isInterpolating) {
- if (stream.peek() === '}') {
- state.interpolationNesting--
- if (state.interpolationNesting < 0) {
- stream.next()
- state.isInterpolating = false
- return 'punctuation'
- }
- } else if (stream.peek() === '{') {
- state.interpolationNesting++
- }
- return jsMode.token(stream, state.jsState) || true
- }
- }
- function caseStatement(stream, state) {
- if (stream.match(/^case\b/)) {
- state.javaScriptLine = true
- return KEYWORD
- }
- }
- function when(stream, state) {
- if (stream.match(/^when\b/)) {
- state.javaScriptLine = true
- state.javaScriptLineExcludesColon = true
- return KEYWORD
- }
- }
- function defaultStatement(stream) {
- if (stream.match(/^default\b/)) {
- return KEYWORD
- }
- }
- function extendsStatement(stream, state) {
- if (stream.match(/^extends?\b/)) {
- state.restOfLine = 'string'
- return KEYWORD
- }
- }
- function append(stream, state) {
- if (stream.match(/^append\b/)) {
- state.restOfLine = 'variable'
- return KEYWORD
- }
- }
- function prepend(stream, state) {
- if (stream.match(/^prepend\b/)) {
- state.restOfLine = 'variable'
- return KEYWORD
- }
- }
- function block(stream, state) {
- if (stream.match(/^block\b *(?:(prepend|append)\b)?/)) {
- state.restOfLine = 'variable'
- return KEYWORD
- }
- }
- function include(stream, state) {
- if (stream.match(/^include\b/)) {
- state.restOfLine = 'string'
- return KEYWORD
- }
- }
- function includeFiltered(stream, state) {
- if (stream.match(/^include:([a-zA-Z0-9\-]+)/, false) && stream.match('include')) {
- state.isIncludeFiltered = true
- return KEYWORD
- }
- }
- function includeFilteredContinued(stream, state) {
- if (state.isIncludeFiltered) {
- var tok = filter(stream, state)
- state.isIncludeFiltered = false
- state.restOfLine = 'string'
- return tok
- }
- }
- function mixin(stream, state) {
- if (stream.match(/^mixin\b/)) {
- state.javaScriptLine = true
- return KEYWORD
- }
- }
- function call(stream, state) {
- if (stream.match(/^\+([-\w]+)/)) {
- if (!stream.match(/^\( *[-\w]+ *=/, false)) {
- state.javaScriptArguments = true
- state.javaScriptArgumentsDepth = 0
- }
- return 'variable'
- }
- if (stream.match('+#{', false)) {
- stream.next()
- state.mixinCallAfter = true
- return interpolation(stream, state)
- }
- }
- function callArguments(stream, state) {
- if (state.mixinCallAfter) {
- state.mixinCallAfter = false
- if (!stream.match(/^\( *[-\w]+ *=/, false)) {
- state.javaScriptArguments = true
- state.javaScriptArgumentsDepth = 0
- }
- return true
- }
- }
- function conditional(stream, state) {
- if (stream.match(/^(if|unless|else if|else)\b/)) {
- state.javaScriptLine = true
- return KEYWORD
- }
- }
- function each(stream, state) {
- if (stream.match(/^(- *)?(each|for)\b/)) {
- state.isEach = true
- return KEYWORD
- }
- }
- function eachContinued(stream, state) {
- if (state.isEach) {
- if (stream.match(/^ in\b/)) {
- state.javaScriptLine = true
- state.isEach = false
- return KEYWORD
- } else if (stream.sol() || stream.eol()) {
- state.isEach = false
- } else if (stream.next()) {
- while (!stream.match(/^ in\b/, false) && stream.next());
- return 'variable'
- }
- }
- }
- function whileStatement(stream, state) {
- if (stream.match(/^while\b/)) {
- state.javaScriptLine = true
- return KEYWORD
- }
- }
- function tag(stream, state) {
- var captures
- if ((captures = stream.match(/^(\w(?:[-:\w]*\w)?)\/?/))) {
- state.lastTag = captures[1].toLowerCase()
- if (state.lastTag === 'script') {
- state.scriptType = 'application/javascript'
- }
- return 'tag'
- }
- }
- function filter(stream, state) {
- if (stream.match(/^:([\w\-]+)/)) {
- var innerMode
- if (config && config.innerModes) {
- innerMode = config.innerModes(stream.current().substring(1))
- }
- if (!innerMode) {
- innerMode = stream.current().substring(1)
- }
- if (typeof innerMode === 'string') {
- innerMode = CodeMirror.getMode(config, innerMode)
- }
- setInnerMode(stream, state, innerMode)
- return 'atom'
- }
- }
- function code(stream, state) {
- if (stream.match(/^(!?=|-)/)) {
- state.javaScriptLine = true
- return 'punctuation'
- }
- }
- function id(stream) {
- if (stream.match(/^#([\w-]+)/)) {
- return ID
- }
- }
- function className(stream) {
- if (stream.match(/^\.([\w-]+)/)) {
- return CLASS
- }
- }
- function attrs(stream, state) {
- if (stream.peek() == '(') {
- stream.next()
- state.isAttrs = true
- state.attrsNest = []
- state.inAttributeName = true
- state.attrValue = ''
- state.attributeIsType = false
- return 'punctuation'
- }
- }
- function attrsContinued(stream, state) {
- if (state.isAttrs) {
- if (ATTRS_NEST[stream.peek()]) {
- state.attrsNest.push(ATTRS_NEST[stream.peek()])
- }
- if (state.attrsNest[state.attrsNest.length - 1] === stream.peek()) {
- state.attrsNest.pop()
- } else if (stream.eat(')')) {
- state.isAttrs = false
- return 'punctuation'
- }
- if (state.inAttributeName && stream.match(/^[^=,\)!]+/)) {
- if (stream.peek() === '=' || stream.peek() === '!') {
- state.inAttributeName = false
- state.jsState = CodeMirror.startState(jsMode)
- if (state.lastTag === 'script' && stream.current().trim().toLowerCase() === 'type') {
- state.attributeIsType = true
- } else {
- state.attributeIsType = false
- }
- }
- return 'attribute'
- }
- var tok = jsMode.token(stream, state.jsState)
- if (state.attributeIsType && tok === 'string') {
- state.scriptType = stream.current().toString()
- }
- if (state.attrsNest.length === 0 && (tok === 'string' || tok === 'variable' || tok === 'keyword')) {
- try {
- Function('', 'var x ' + state.attrValue.replace(/,\s*$/, '').replace(/^!/, ''))
- state.inAttributeName = true
- state.attrValue = ''
- stream.backUp(stream.current().length)
- return attrsContinued(stream, state)
- } catch (ex) {
- //not the end of an attribute
- }
- }
- state.attrValue += stream.current()
- return tok || true
- }
- }
- function attributesBlock(stream, state) {
- if (stream.match(/^&attributes\b/)) {
- state.javaScriptArguments = true
- state.javaScriptArgumentsDepth = 0
- return 'keyword'
- }
- }
- function indent(stream) {
- if (stream.sol() && stream.eatSpace()) {
- return 'indent'
- }
- }
- function comment(stream, state) {
- if (stream.match(/^ *\/\/(-)?([^\n]*)/)) {
- state.indentOf = stream.indentation()
- state.indentToken = 'comment'
- return 'comment'
- }
- }
- function colon(stream) {
- if (stream.match(/^: */)) {
- return 'colon'
- }
- }
- function text(stream, state) {
- if (stream.match(/^(?:\| ?| )([^\n]+)/)) {
- return 'string'
- }
- if (stream.match(/^(<[^\n]*)/, false)) {
- // html string
- setInnerMode(stream, state, 'htmlmixed')
- state.innerModeForLine = true
- return innerMode(stream, state, true)
- }
- }
- function dot(stream, state) {
- if (stream.eat('.')) {
- var innerMode = null
- if (state.lastTag === 'script' && state.scriptType.toLowerCase().indexOf('javascript') != -1) {
- innerMode = state.scriptType.toLowerCase().replace(/"|'/g, '')
- } else if (state.lastTag === 'style') {
- innerMode = 'css'
- }
- setInnerMode(stream, state, innerMode)
- return 'dot'
- }
- }
- function fail(stream) {
- stream.next()
- return null
- }
- function setInnerMode(stream, state, mode) {
- mode = CodeMirror.mimeModes[mode] || mode
- mode = config.innerModes ? config.innerModes(mode) || mode : mode
- mode = CodeMirror.mimeModes[mode] || mode
- mode = CodeMirror.getMode(config, mode)
- state.indentOf = stream.indentation()
- if (mode && mode.name !== 'null') {
- state.innerMode = mode
- } else {
- state.indentToken = 'string'
- }
- }
- function innerMode(stream, state, force) {
- if (stream.indentation() > state.indentOf || (state.innerModeForLine && !stream.sol()) || force) {
- if (state.innerMode) {
- if (!state.innerState) {
- state.innerState = state.innerMode.startState ? CodeMirror.startState(state.innerMode, stream.indentation()) : {}
- }
- return stream.hideFirstChars(state.indentOf + 2, function () {
- return state.innerMode.token(stream, state.innerState) || true
- })
- } else {
- stream.skipToEnd()
- return state.indentToken
- }
- } else if (stream.sol()) {
- state.indentOf = Infinity
- state.indentToken = null
- state.innerMode = null
- state.innerState = null
- }
- }
- function restOfLine(stream, state) {
- if (stream.sol()) {
- // if restOfLine was set at end of line, ignore it
- state.restOfLine = ''
- }
- if (state.restOfLine) {
- stream.skipToEnd()
- var tok = state.restOfLine
- state.restOfLine = ''
- return tok
- }
- }
- function startState() {
- return new State()
- }
- function copyState(state) {
- return state.copy()
- }
- /**
- * Get the next token in the stream
- *
- * @param {Stream} stream
- * @param {State} state
- */
- function nextToken(stream, state) {
- var tok =
- innerMode(stream, state) ||
- restOfLine(stream, state) ||
- interpolationContinued(stream, state) ||
- includeFilteredContinued(stream, state) ||
- eachContinued(stream, state) ||
- attrsContinued(stream, state) ||
- javaScript(stream, state) ||
- javaScriptArguments(stream, state) ||
- callArguments(stream, state) ||
- yieldStatement(stream) ||
- doctype(stream) ||
- interpolation(stream, state) ||
- caseStatement(stream, state) ||
- when(stream, state) ||
- defaultStatement(stream) ||
- extendsStatement(stream, state) ||
- append(stream, state) ||
- prepend(stream, state) ||
- block(stream, state) ||
- include(stream, state) ||
- includeFiltered(stream, state) ||
- mixin(stream, state) ||
- call(stream, state) ||
- conditional(stream, state) ||
- each(stream, state) ||
- whileStatement(stream, state) ||
- tag(stream, state) ||
- filter(stream, state) ||
- code(stream, state) ||
- id(stream) ||
- className(stream) ||
- attrs(stream, state) ||
- attributesBlock(stream, state) ||
- indent(stream) ||
- text(stream, state) ||
- comment(stream, state) ||
- colon(stream) ||
- dot(stream, state) ||
- fail(stream)
- return tok === true ? null : tok
- }
- return {
- startState: startState,
- copyState: copyState,
- token: nextToken,
- }
- },
- 'javascript',
- 'css',
- 'htmlmixed'
- )
- CodeMirror.defineMIME('text/x-pug', 'pug')
- CodeMirror.defineMIME('text/x-jade', 'pug')
- })
|