// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE // LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's // CodeMirror 1 mode. // highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting ;(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) // Plain browser env else mod(CodeMirror) })(function (CodeMirror) { 'use strict' CodeMirror.defineMode('lua', function (config, parserConfig) { var indentUnit = config.indentUnit function prefixRE(words) { return new RegExp('^(?:' + words.join('|') + ')', 'i') } function wordRE(words) { return new RegExp('^(?:' + words.join('|') + ')$', 'i') } var specials = wordRE(parserConfig.specials || []) // long list of standard functions from lua manual var builtins = wordRE([ '_G', '_VERSION', 'assert', 'collectgarbage', 'dofile', 'error', 'getfenv', 'getmetatable', 'ipairs', 'load', 'loadfile', 'loadstring', 'module', 'next', 'pairs', 'pcall', 'print', 'rawequal', 'rawget', 'rawset', 'require', 'select', 'setfenv', 'setmetatable', 'tonumber', 'tostring', 'type', 'unpack', 'xpcall', 'coroutine.create', 'coroutine.resume', 'coroutine.running', 'coroutine.status', 'coroutine.wrap', 'coroutine.yield', 'debug.debug', 'debug.getfenv', 'debug.gethook', 'debug.getinfo', 'debug.getlocal', 'debug.getmetatable', 'debug.getregistry', 'debug.getupvalue', 'debug.setfenv', 'debug.sethook', 'debug.setlocal', 'debug.setmetatable', 'debug.setupvalue', 'debug.traceback', 'close', 'flush', 'lines', 'read', 'seek', 'setvbuf', 'write', 'io.close', 'io.flush', 'io.input', 'io.lines', 'io.open', 'io.output', 'io.popen', 'io.read', 'io.stderr', 'io.stdin', 'io.stdout', 'io.tmpfile', 'io.type', 'io.write', 'math.abs', 'math.acos', 'math.asin', 'math.atan', 'math.atan2', 'math.ceil', 'math.cos', 'math.cosh', 'math.deg', 'math.exp', 'math.floor', 'math.fmod', 'math.frexp', 'math.huge', 'math.ldexp', 'math.log', 'math.log10', 'math.max', 'math.min', 'math.modf', 'math.pi', 'math.pow', 'math.rad', 'math.random', 'math.randomseed', 'math.sin', 'math.sinh', 'math.sqrt', 'math.tan', 'math.tanh', 'os.clock', 'os.date', 'os.difftime', 'os.execute', 'os.exit', 'os.getenv', 'os.remove', 'os.rename', 'os.setlocale', 'os.time', 'os.tmpname', 'package.cpath', 'package.loaded', 'package.loaders', 'package.loadlib', 'package.path', 'package.preload', 'package.seeall', 'string.byte', 'string.char', 'string.dump', 'string.find', 'string.format', 'string.gmatch', 'string.gsub', 'string.len', 'string.lower', 'string.match', 'string.rep', 'string.reverse', 'string.sub', 'string.upper', 'table.concat', 'table.insert', 'table.maxn', 'table.remove', 'table.sort', ]) var keywords = wordRE([ 'and', 'break', 'elseif', 'false', 'nil', 'not', 'or', 'return', 'true', 'function', 'end', 'if', 'then', 'else', 'do', 'while', 'repeat', 'until', 'for', 'in', 'local', ]) var indentTokens = wordRE(['function', 'if', 'repeat', 'do', '\\(', '{']) var dedentTokens = wordRE(['end', 'until', '\\)', '}']) var dedentPartial = prefixRE(['end', 'until', '\\)', '}', 'else', 'elseif']) function readBracket(stream) { var level = 0 while (stream.eat('=')) ++level stream.eat('[') return level } function normal(stream, state) { var ch = stream.next() if (ch == '-' && stream.eat('-')) { if (stream.eat('[') && stream.eat('[')) return (state.cur = bracketed(readBracket(stream), 'comment'))(stream, state) stream.skipToEnd() return 'comment' } if (ch == '"' || ch == "'") return (state.cur = string(ch))(stream, state) if (ch == '[' && /[\[=]/.test(stream.peek())) return (state.cur = bracketed(readBracket(stream), 'string'))(stream, state) if (/\d/.test(ch)) { stream.eatWhile(/[\w.%]/) return 'number' } if (/[\w_]/.test(ch)) { stream.eatWhile(/[\w\\\-_.]/) return 'variable' } return null } function bracketed(level, style) { return function (stream, state) { var curlev = null, ch while ((ch = stream.next()) != null) { if (curlev == null) { if (ch == ']') curlev = 0 } else if (ch == '=') ++curlev else if (ch == ']' && curlev == level) { state.cur = normal break } else curlev = null } return style } } function string(quote) { return function (stream, state) { var escaped = false, ch while ((ch = stream.next()) != null) { if (ch == quote && !escaped) break escaped = !escaped && ch == '\\' } if (!escaped) state.cur = normal return 'string' } } return { startState: function (basecol) { return { basecol: basecol || 0, indentDepth: 0, cur: normal } }, token: function (stream, state) { if (stream.eatSpace()) return null var style = state.cur(stream, state) var word = stream.current() if (style == 'variable') { if (keywords.test(word)) style = 'keyword' else if (builtins.test(word)) style = 'builtin' else if (specials.test(word)) style = 'variable-2' } if (style != 'comment' && style != 'string') { if (indentTokens.test(word)) ++state.indentDepth else if (dedentTokens.test(word)) --state.indentDepth } return style }, indent: function (state, textAfter) { var closing = dedentPartial.test(textAfter) return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0)) }, electricInput: /^\s*(?:end|until|else|\)|\})$/, lineComment: '--', blockCommentStart: '--[[', blockCommentEnd: ']]', } }) CodeMirror.defineMIME('text/x-lua', 'lua') })