123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- // 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'))
- } else if (typeof define == 'function' && define.amd) {
- // AMD
- define(['../../lib/codemirror'], mod)
- } else {
- // Plain browser env
- mod(CodeMirror)
- }
- })(function (CodeMirror) {
- 'use strict'
- var TOKEN_STYLES = {
- addition: 'positive',
- attributes: 'attribute',
- bold: 'strong',
- cite: 'keyword',
- code: 'atom',
- definitionList: 'number',
- deletion: 'negative',
- div: 'punctuation',
- em: 'em',
- footnote: 'variable',
- footCite: 'qualifier',
- header: 'header',
- html: 'comment',
- image: 'string',
- italic: 'em',
- link: 'link',
- linkDefinition: 'link',
- list1: 'variable-2',
- list2: 'variable-3',
- list3: 'keyword',
- notextile: 'string-2',
- pre: 'operator',
- p: 'property',
- quote: 'bracket',
- span: 'quote',
- specialChar: 'tag',
- strong: 'strong',
- sub: 'builtin',
- sup: 'builtin',
- table: 'variable-3',
- tableHeading: 'operator',
- }
- function startNewLine(stream, state) {
- state.mode = Modes.newLayout
- state.tableHeading = false
- if (state.layoutType === 'definitionList' && state.spanningLayout && stream.match(RE('definitionListEnd'), false)) state.spanningLayout = false
- }
- function handlePhraseModifier(stream, state, ch) {
- if (ch === '_') {
- if (stream.eat('_')) return togglePhraseModifier(stream, state, 'italic', /__/, 2)
- else return togglePhraseModifier(stream, state, 'em', /_/, 1)
- }
- if (ch === '*') {
- if (stream.eat('*')) {
- return togglePhraseModifier(stream, state, 'bold', /\*\*/, 2)
- }
- return togglePhraseModifier(stream, state, 'strong', /\*/, 1)
- }
- if (ch === '[') {
- if (stream.match(/\d+\]/)) state.footCite = true
- return tokenStyles(state)
- }
- if (ch === '(') {
- var spec = stream.match(/^(r|tm|c)\)/)
- if (spec) return tokenStylesWith(state, TOKEN_STYLES.specialChar)
- }
- if (ch === '<' && stream.match(/(\w+)[^>]+>[^<]+<\/\1>/)) return tokenStylesWith(state, TOKEN_STYLES.html)
- if (ch === '?' && stream.eat('?')) return togglePhraseModifier(stream, state, 'cite', /\?\?/, 2)
- if (ch === '=' && stream.eat('=')) return togglePhraseModifier(stream, state, 'notextile', /==/, 2)
- if (ch === '-' && !stream.eat('-')) return togglePhraseModifier(stream, state, 'deletion', /-/, 1)
- if (ch === '+') return togglePhraseModifier(stream, state, 'addition', /\+/, 1)
- if (ch === '~') return togglePhraseModifier(stream, state, 'sub', /~/, 1)
- if (ch === '^') return togglePhraseModifier(stream, state, 'sup', /\^/, 1)
- if (ch === '%') return togglePhraseModifier(stream, state, 'span', /%/, 1)
- if (ch === '@') return togglePhraseModifier(stream, state, 'code', /@/, 1)
- if (ch === '!') {
- var type = togglePhraseModifier(stream, state, 'image', /(?:\([^\)]+\))?!/, 1)
- stream.match(/^:\S+/) // optional Url portion
- return type
- }
- return tokenStyles(state)
- }
- function togglePhraseModifier(stream, state, phraseModifier, closeRE, openSize) {
- var charBefore = stream.pos > openSize ? stream.string.charAt(stream.pos - openSize - 1) : null
- var charAfter = stream.peek()
- if (state[phraseModifier]) {
- if ((!charAfter || /\W/.test(charAfter)) && charBefore && /\S/.test(charBefore)) {
- var type = tokenStyles(state)
- state[phraseModifier] = false
- return type
- }
- } else if ((!charBefore || /\W/.test(charBefore)) && charAfter && /\S/.test(charAfter) && stream.match(new RegExp('^.*\\S' + closeRE.source + '(?:\\W|$)'), false)) {
- state[phraseModifier] = true
- state.mode = Modes.attributes
- }
- return tokenStyles(state)
- }
- function tokenStyles(state) {
- var disabled = textileDisabled(state)
- if (disabled) return disabled
- var styles = []
- if (state.layoutType) styles.push(TOKEN_STYLES[state.layoutType])
- styles = styles.concat(
- activeStyles(state, 'addition', 'bold', 'cite', 'code', 'deletion', 'em', 'footCite', 'image', 'italic', 'link', 'span', 'strong', 'sub', 'sup', 'table', 'tableHeading')
- )
- if (state.layoutType === 'header') styles.push(TOKEN_STYLES.header + '-' + state.header)
- return styles.length ? styles.join(' ') : null
- }
- function textileDisabled(state) {
- var type = state.layoutType
- switch (type) {
- case 'notextile':
- case 'code':
- case 'pre':
- return TOKEN_STYLES[type]
- default:
- if (state.notextile) return TOKEN_STYLES.notextile + (type ? ' ' + TOKEN_STYLES[type] : '')
- return null
- }
- }
- function tokenStylesWith(state, extraStyles) {
- var disabled = textileDisabled(state)
- if (disabled) return disabled
- var type = tokenStyles(state)
- if (extraStyles) return type ? type + ' ' + extraStyles : extraStyles
- else return type
- }
- function activeStyles(state) {
- var styles = []
- for (var i = 1; i < arguments.length; ++i) {
- if (state[arguments[i]]) styles.push(TOKEN_STYLES[arguments[i]])
- }
- return styles
- }
- function blankLine(state) {
- var spanningLayout = state.spanningLayout,
- type = state.layoutType
- for (var key in state) if (state.hasOwnProperty(key)) delete state[key]
- state.mode = Modes.newLayout
- if (spanningLayout) {
- state.layoutType = type
- state.spanningLayout = true
- }
- }
- var REs = {
- cache: {},
- single: {
- bc: 'bc',
- bq: 'bq',
- definitionList: /- .*?:=+/,
- definitionListEnd: /.*=:\s*$/,
- div: 'div',
- drawTable: /\|.*\|/,
- foot: /fn\d+/,
- header: /h[1-6]/,
- html: /\s*<(?:\/)?(\w+)(?:[^>]+)?>(?:[^<]+<\/\1>)?/,
- link: /[^"]+":\S/,
- linkDefinition: /\[[^\s\]]+\]\S+/,
- list: /(?:#+|\*+)/,
- notextile: 'notextile',
- para: 'p',
- pre: 'pre',
- table: 'table',
- tableCellAttributes: /[\/\\]\d+/,
- tableHeading: /\|_\./,
- tableText: /[^"_\*\[\(\?\+~\^%@|-]+/,
- text: /[^!"_=\*\[\(<\?\+~\^%@-]+/,
- },
- attributes: {
- align: /(?:<>|<|>|=)/,
- selector: /\([^\(][^\)]+\)/,
- lang: /\[[^\[\]]+\]/,
- pad: /(?:\(+|\)+){1,2}/,
- css: /\{[^\}]+\}/,
- },
- createRe: function (name) {
- switch (name) {
- case 'drawTable':
- return REs.makeRe('^', REs.single.drawTable, '$')
- case 'html':
- return REs.makeRe('^', REs.single.html, '(?:', REs.single.html, ')*', '$')
- case 'linkDefinition':
- return REs.makeRe('^', REs.single.linkDefinition, '$')
- case 'listLayout':
- return REs.makeRe('^', REs.single.list, RE('allAttributes'), '*\\s+')
- case 'tableCellAttributes':
- return REs.makeRe('^', REs.choiceRe(REs.single.tableCellAttributes, RE('allAttributes')), '+\\.')
- case 'type':
- return REs.makeRe('^', RE('allTypes'))
- case 'typeLayout':
- return REs.makeRe('^', RE('allTypes'), RE('allAttributes'), '*\\.\\.?', '(\\s+|$)')
- case 'attributes':
- return REs.makeRe('^', RE('allAttributes'), '+')
- case 'allTypes':
- return REs.choiceRe(REs.single.div, REs.single.foot, REs.single.header, REs.single.bc, REs.single.bq, REs.single.notextile, REs.single.pre, REs.single.table, REs.single.para)
- case 'allAttributes':
- return REs.choiceRe(REs.attributes.selector, REs.attributes.css, REs.attributes.lang, REs.attributes.align, REs.attributes.pad)
- default:
- return REs.makeRe('^', REs.single[name])
- }
- },
- makeRe: function () {
- var pattern = ''
- for (var i = 0; i < arguments.length; ++i) {
- var arg = arguments[i]
- pattern += typeof arg === 'string' ? arg : arg.source
- }
- return new RegExp(pattern)
- },
- choiceRe: function () {
- var parts = [arguments[0]]
- for (var i = 1; i < arguments.length; ++i) {
- parts[i * 2 - 1] = '|'
- parts[i * 2] = arguments[i]
- }
- parts.unshift('(?:')
- parts.push(')')
- return REs.makeRe.apply(null, parts)
- },
- }
- function RE(name) {
- return REs.cache[name] || (REs.cache[name] = REs.createRe(name))
- }
- var Modes = {
- newLayout: function (stream, state) {
- if (stream.match(RE('typeLayout'), false)) {
- state.spanningLayout = false
- return (state.mode = Modes.blockType)(stream, state)
- }
- var newMode
- if (!textileDisabled(state)) {
- if (stream.match(RE('listLayout'), false)) newMode = Modes.list
- else if (stream.match(RE('drawTable'), false)) newMode = Modes.table
- else if (stream.match(RE('linkDefinition'), false)) newMode = Modes.linkDefinition
- else if (stream.match(RE('definitionList'))) newMode = Modes.definitionList
- else if (stream.match(RE('html'), false)) newMode = Modes.html
- }
- return (state.mode = newMode || Modes.text)(stream, state)
- },
- blockType: function (stream, state) {
- var match, type
- state.layoutType = null
- if ((match = stream.match(RE('type')))) type = match[0]
- else return (state.mode = Modes.text)(stream, state)
- if ((match = type.match(RE('header')))) {
- state.layoutType = 'header'
- state.header = parseInt(match[0][1])
- } else if (type.match(RE('bq'))) {
- state.layoutType = 'quote'
- } else if (type.match(RE('bc'))) {
- state.layoutType = 'code'
- } else if (type.match(RE('foot'))) {
- state.layoutType = 'footnote'
- } else if (type.match(RE('notextile'))) {
- state.layoutType = 'notextile'
- } else if (type.match(RE('pre'))) {
- state.layoutType = 'pre'
- } else if (type.match(RE('div'))) {
- state.layoutType = 'div'
- } else if (type.match(RE('table'))) {
- state.layoutType = 'table'
- }
- state.mode = Modes.attributes
- return tokenStyles(state)
- },
- text: function (stream, state) {
- if (stream.match(RE('text'))) return tokenStyles(state)
- var ch = stream.next()
- if (ch === '"') return (state.mode = Modes.link)(stream, state)
- return handlePhraseModifier(stream, state, ch)
- },
- attributes: function (stream, state) {
- state.mode = Modes.layoutLength
- if (stream.match(RE('attributes'))) return tokenStylesWith(state, TOKEN_STYLES.attributes)
- else return tokenStyles(state)
- },
- layoutLength: function (stream, state) {
- if (stream.eat('.') && stream.eat('.')) state.spanningLayout = true
- state.mode = Modes.text
- return tokenStyles(state)
- },
- list: function (stream, state) {
- var match = stream.match(RE('list'))
- state.listDepth = match[0].length
- var listMod = (state.listDepth - 1) % 3
- if (!listMod) state.layoutType = 'list1'
- else if (listMod === 1) state.layoutType = 'list2'
- else state.layoutType = 'list3'
- state.mode = Modes.attributes
- return tokenStyles(state)
- },
- link: function (stream, state) {
- state.mode = Modes.text
- if (stream.match(RE('link'))) {
- stream.match(/\S+/)
- return tokenStylesWith(state, TOKEN_STYLES.link)
- }
- return tokenStyles(state)
- },
- linkDefinition: function (stream, state) {
- stream.skipToEnd()
- return tokenStylesWith(state, TOKEN_STYLES.linkDefinition)
- },
- definitionList: function (stream, state) {
- stream.match(RE('definitionList'))
- state.layoutType = 'definitionList'
- if (stream.match(/\s*$/)) state.spanningLayout = true
- else state.mode = Modes.attributes
- return tokenStyles(state)
- },
- html: function (stream, state) {
- stream.skipToEnd()
- return tokenStylesWith(state, TOKEN_STYLES.html)
- },
- table: function (stream, state) {
- state.layoutType = 'table'
- return (state.mode = Modes.tableCell)(stream, state)
- },
- tableCell: function (stream, state) {
- if (stream.match(RE('tableHeading'))) state.tableHeading = true
- else stream.eat('|')
- state.mode = Modes.tableCellAttributes
- return tokenStyles(state)
- },
- tableCellAttributes: function (stream, state) {
- state.mode = Modes.tableText
- if (stream.match(RE('tableCellAttributes'))) return tokenStylesWith(state, TOKEN_STYLES.attributes)
- else return tokenStyles(state)
- },
- tableText: function (stream, state) {
- if (stream.match(RE('tableText'))) return tokenStyles(state)
- if (stream.peek() === '|') {
- // end of cell
- state.mode = Modes.tableCell
- return tokenStyles(state)
- }
- return handlePhraseModifier(stream, state, stream.next())
- },
- }
- CodeMirror.defineMode('textile', function () {
- return {
- startState: function () {
- return { mode: Modes.newLayout }
- },
- token: function (stream, state) {
- if (stream.sol()) startNewLine(stream, state)
- return state.mode(stream, state)
- },
- blankLine: blankLine,
- }
- })
- CodeMirror.defineMIME('text/x-textile', 'textile')
- })
|