clike.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. ;(function (mod) {
  4. if (typeof exports == 'object' && typeof module == 'object')
  5. // CommonJS
  6. mod(require('../../lib/codemirror'))
  7. else if (typeof define == 'function' && define.amd)
  8. // AMD
  9. define(['../../lib/codemirror'], mod)
  10. // Plain browser env
  11. else mod(CodeMirror)
  12. })(function (CodeMirror) {
  13. 'use strict'
  14. function Context(indented, column, type, info, align, prev) {
  15. this.indented = indented
  16. this.column = column
  17. this.type = type
  18. this.info = info
  19. this.align = align
  20. this.prev = prev
  21. }
  22. function pushContext(state, col, type, info) {
  23. var indent = state.indented
  24. if (state.context && state.context.type == 'statement' && type != 'statement') indent = state.context.indented
  25. return (state.context = new Context(indent, col, type, info, null, state.context))
  26. }
  27. function popContext(state) {
  28. var t = state.context.type
  29. if (t == ')' || t == ']' || t == '}') state.indented = state.context.indented
  30. return (state.context = state.context.prev)
  31. }
  32. function typeBefore(stream, state, pos) {
  33. if (state.prevToken == 'variable' || state.prevToken == 'type') return true
  34. if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true
  35. if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true
  36. }
  37. function isTopScope(context) {
  38. for (;;) {
  39. if (!context || context.type == 'top') return true
  40. if (context.type == '}' && context.prev.info != 'namespace') return false
  41. context = context.prev
  42. }
  43. }
  44. CodeMirror.defineMode('clike', function (config, parserConfig) {
  45. var indentUnit = config.indentUnit,
  46. statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
  47. dontAlignCalls = parserConfig.dontAlignCalls,
  48. keywords = parserConfig.keywords || {},
  49. types = parserConfig.types || {},
  50. builtin = parserConfig.builtin || {},
  51. blockKeywords = parserConfig.blockKeywords || {},
  52. defKeywords = parserConfig.defKeywords || {},
  53. atoms = parserConfig.atoms || {},
  54. hooks = parserConfig.hooks || {},
  55. multiLineStrings = parserConfig.multiLineStrings,
  56. indentStatements = parserConfig.indentStatements !== false,
  57. indentSwitch = parserConfig.indentSwitch !== false,
  58. namespaceSeparator = parserConfig.namespaceSeparator,
  59. isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
  60. numberStart = parserConfig.numberStart || /[\d\.]/,
  61. number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
  62. isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
  63. isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/,
  64. // An optional function that takes a {string} token and returns true if it
  65. // should be treated as a builtin.
  66. isReservedIdentifier = parserConfig.isReservedIdentifier || false
  67. var curPunc, isDefKeyword
  68. function tokenBase(stream, state) {
  69. var ch = stream.next()
  70. if (hooks[ch]) {
  71. var result = hooks[ch](stream, state)
  72. if (result !== false) return result
  73. }
  74. if (ch == '"' || ch == "'") {
  75. state.tokenize = tokenString(ch)
  76. return state.tokenize(stream, state)
  77. }
  78. if (numberStart.test(ch)) {
  79. stream.backUp(1)
  80. if (stream.match(number)) return 'number'
  81. stream.next()
  82. }
  83. if (isPunctuationChar.test(ch)) {
  84. curPunc = ch
  85. return null
  86. }
  87. if (ch == '/') {
  88. if (stream.eat('*')) {
  89. state.tokenize = tokenComment
  90. return tokenComment(stream, state)
  91. }
  92. if (stream.eat('/')) {
  93. stream.skipToEnd()
  94. return 'comment'
  95. }
  96. }
  97. if (isOperatorChar.test(ch)) {
  98. while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
  99. return 'operator'
  100. }
  101. stream.eatWhile(isIdentifierChar)
  102. if (namespaceSeparator) while (stream.match(namespaceSeparator)) stream.eatWhile(isIdentifierChar)
  103. var cur = stream.current()
  104. if (contains(keywords, cur)) {
  105. if (contains(blockKeywords, cur)) curPunc = 'newstatement'
  106. if (contains(defKeywords, cur)) isDefKeyword = true
  107. return 'keyword'
  108. }
  109. if (contains(types, cur)) return 'type'
  110. if (contains(builtin, cur) || (isReservedIdentifier && isReservedIdentifier(cur))) {
  111. if (contains(blockKeywords, cur)) curPunc = 'newstatement'
  112. return 'builtin'
  113. }
  114. if (contains(atoms, cur)) return 'atom'
  115. return 'variable'
  116. }
  117. function tokenString(quote) {
  118. return function (stream, state) {
  119. var escaped = false,
  120. next,
  121. end = false
  122. while ((next = stream.next()) != null) {
  123. if (next == quote && !escaped) {
  124. end = true
  125. break
  126. }
  127. escaped = !escaped && next == '\\'
  128. }
  129. if (end || !(escaped || multiLineStrings)) state.tokenize = null
  130. return 'string'
  131. }
  132. }
  133. function tokenComment(stream, state) {
  134. var maybeEnd = false,
  135. ch
  136. while ((ch = stream.next())) {
  137. if (ch == '/' && maybeEnd) {
  138. state.tokenize = null
  139. break
  140. }
  141. maybeEnd = ch == '*'
  142. }
  143. return 'comment'
  144. }
  145. function maybeEOL(stream, state) {
  146. if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
  147. }
  148. // Interface
  149. return {
  150. startState: function (basecolumn) {
  151. return {
  152. tokenize: null,
  153. context: new Context((basecolumn || 0) - indentUnit, 0, 'top', null, false),
  154. indented: 0,
  155. startOfLine: true,
  156. prevToken: null,
  157. }
  158. },
  159. token: function (stream, state) {
  160. var ctx = state.context
  161. if (stream.sol()) {
  162. if (ctx.align == null) ctx.align = false
  163. state.indented = stream.indentation()
  164. state.startOfLine = true
  165. }
  166. if (stream.eatSpace()) {
  167. maybeEOL(stream, state)
  168. return null
  169. }
  170. curPunc = isDefKeyword = null
  171. var style = (state.tokenize || tokenBase)(stream, state)
  172. if (style == 'comment' || style == 'meta') return style
  173. if (ctx.align == null) ctx.align = true
  174. if (curPunc == ';' || curPunc == ':' || (curPunc == ',' && stream.match(/^\s*(?:\/\/.*)?$/, false))) while (state.context.type == 'statement') popContext(state)
  175. else if (curPunc == '{') pushContext(state, stream.column(), '}')
  176. else if (curPunc == '[') pushContext(state, stream.column(), ']')
  177. else if (curPunc == '(') pushContext(state, stream.column(), ')')
  178. else if (curPunc == '}') {
  179. while (ctx.type == 'statement') ctx = popContext(state)
  180. if (ctx.type == '}') ctx = popContext(state)
  181. while (ctx.type == 'statement') ctx = popContext(state)
  182. } else if (curPunc == ctx.type) popContext(state)
  183. else if (indentStatements && (((ctx.type == '}' || ctx.type == 'top') && curPunc != ';') || (ctx.type == 'statement' && curPunc == 'newstatement'))) {
  184. pushContext(state, stream.column(), 'statement', stream.current())
  185. }
  186. if (
  187. style == 'variable' &&
  188. (state.prevToken == 'def' || (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) && isTopScope(state.context) && stream.match(/^\s*\(/, false)))
  189. )
  190. style = 'def'
  191. if (hooks.token) {
  192. var result = hooks.token(stream, state, style)
  193. if (result !== undefined) style = result
  194. }
  195. if (style == 'def' && parserConfig.styleDefs === false) style = 'variable'
  196. state.startOfLine = false
  197. state.prevToken = isDefKeyword ? 'def' : style || curPunc
  198. maybeEOL(stream, state)
  199. return style
  200. },
  201. indent: function (state, textAfter) {
  202. if ((state.tokenize != tokenBase && state.tokenize != null) || state.typeAtEndOfLine) return CodeMirror.Pass
  203. var ctx = state.context,
  204. firstChar = textAfter && textAfter.charAt(0)
  205. var closing = firstChar == ctx.type
  206. if (ctx.type == 'statement' && firstChar == '}') ctx = ctx.prev
  207. if (parserConfig.dontIndentStatements) while (ctx.type == 'statement' && parserConfig.dontIndentStatements.test(ctx.info)) ctx = ctx.prev
  208. if (hooks.indent) {
  209. var hook = hooks.indent(state, ctx, textAfter, indentUnit)
  210. if (typeof hook == 'number') return hook
  211. }
  212. var switchBlock = ctx.prev && ctx.prev.info == 'switch'
  213. if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
  214. while (ctx.type != 'top' && ctx.type != '}') ctx = ctx.prev
  215. return ctx.indented
  216. }
  217. if (ctx.type == 'statement') return ctx.indented + (firstChar == '{' ? 0 : statementIndentUnit)
  218. if (ctx.align && (!dontAlignCalls || ctx.type != ')')) return ctx.column + (closing ? 0 : 1)
  219. if (ctx.type == ')' && !closing) return ctx.indented + statementIndentUnit
  220. return ctx.indented + (closing ? 0 : indentUnit) + (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0)
  221. },
  222. electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
  223. blockCommentStart: '/*',
  224. blockCommentEnd: '*/',
  225. blockCommentContinue: ' * ',
  226. lineComment: '//',
  227. fold: 'brace',
  228. }
  229. })
  230. function words(str) {
  231. var obj = {},
  232. words = str.split(' ')
  233. for (var i = 0; i < words.length; ++i) obj[words[i]] = true
  234. return obj
  235. }
  236. function contains(words, word) {
  237. if (typeof words === 'function') {
  238. return words(word)
  239. } else {
  240. return words.propertyIsEnumerable(word)
  241. }
  242. }
  243. var cKeywords =
  244. 'auto if break case register continue return default do sizeof ' + 'static else struct switch extern typedef union for goto while enum const ' + 'volatile inline restrict asm fortran'
  245. // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20.
  246. var cppKeywords =
  247. 'alignas alignof and and_eq audit axiom bitand bitor catch ' +
  248. 'class compl concept constexpr const_cast decltype delete dynamic_cast ' +
  249. 'explicit export final friend import module mutable namespace new noexcept ' +
  250. 'not not_eq operator or or_eq override private protected public ' +
  251. 'reinterpret_cast requires static_assert static_cast template this ' +
  252. 'thread_local throw try typeid typename using virtual xor xor_eq'
  253. var objCKeywords =
  254. 'bycopy byref in inout oneway out self super atomic nonatomic retain copy ' +
  255. 'readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd ' +
  256. '@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class ' +
  257. '@public @package @private @protected @required @optional @try @catch @finally @import ' +
  258. '@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available'
  259. var objCBuiltins =
  260. 'FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION ' +
  261. ' NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER ' +
  262. 'NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION ' +
  263. 'NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT'
  264. // Do not use this. Use the cTypes function below. This is global just to avoid
  265. // excessive calls when cTypes is being called multiple times during a parse.
  266. var basicCTypes = words('int long char short double float unsigned signed ' + 'void bool')
  267. // Do not use this. Use the objCTypes function below. This is global just to avoid
  268. // excessive calls when objCTypes is being called multiple times during a parse.
  269. var basicObjCTypes = words('SEL instancetype id Class Protocol BOOL')
  270. // Returns true if identifier is a "C" type.
  271. // C type is defined as those that are reserved by the compiler (basicTypes),
  272. // and those that end in _t (Reserved by POSIX for types)
  273. // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
  274. function cTypes(identifier) {
  275. return contains(basicCTypes, identifier) || /.+_t$/.test(identifier)
  276. }
  277. // Returns true if identifier is a "Objective C" type.
  278. function objCTypes(identifier) {
  279. return cTypes(identifier) || contains(basicObjCTypes, identifier)
  280. }
  281. var cBlockKeywords = 'case do else for if switch while struct enum union'
  282. var cDefKeywords = 'struct enum union'
  283. function cppHook(stream, state) {
  284. if (!state.startOfLine) return false
  285. for (var ch, next = null; (ch = stream.peek()); ) {
  286. if (ch == '\\' && stream.match(/^.$/)) {
  287. next = cppHook
  288. break
  289. } else if (ch == '/' && stream.match(/^\/[\/\*]/, false)) {
  290. break
  291. }
  292. stream.next()
  293. }
  294. state.tokenize = next
  295. return 'meta'
  296. }
  297. function pointerHook(_stream, state) {
  298. if (state.prevToken == 'type') return 'type'
  299. return false
  300. }
  301. // For C and C++ (and ObjC): identifiers starting with __
  302. // or _ followed by a capital letter are reserved for the compiler.
  303. function cIsReservedIdentifier(token) {
  304. if (!token || token.length < 2) return false
  305. if (token[0] != '_') return false
  306. return token[1] == '_' || token[1] !== token[1].toLowerCase()
  307. }
  308. function cpp14Literal(stream) {
  309. stream.eatWhile(/[\w\.']/)
  310. return 'number'
  311. }
  312. function cpp11StringHook(stream, state) {
  313. stream.backUp(1)
  314. // Raw strings.
  315. if (stream.match(/^(?:R|u8R|uR|UR|LR)/)) {
  316. var match = stream.match(/^"([^\s\\()]{0,16})\(/)
  317. if (!match) {
  318. return false
  319. }
  320. state.cpp11RawStringDelim = match[1]
  321. state.tokenize = tokenRawString
  322. return tokenRawString(stream, state)
  323. }
  324. // Unicode strings/chars.
  325. if (stream.match(/^(?:u8|u|U|L)/)) {
  326. if (stream.match(/^["']/, /* eat */ false)) {
  327. return 'string'
  328. }
  329. return false
  330. }
  331. // Ignore this hook.
  332. stream.next()
  333. return false
  334. }
  335. function cppLooksLikeConstructor(word) {
  336. var lastTwo = /(\w+)::~?(\w+)$/.exec(word)
  337. return lastTwo && lastTwo[1] == lastTwo[2]
  338. }
  339. // C#-style strings where "" escapes a quote.
  340. function tokenAtString(stream, state) {
  341. var next
  342. while ((next = stream.next()) != null) {
  343. if (next == '"' && !stream.eat('"')) {
  344. state.tokenize = null
  345. break
  346. }
  347. }
  348. return 'string'
  349. }
  350. // C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
  351. // <delim> can be a string up to 16 characters long.
  352. function tokenRawString(stream, state) {
  353. // Escape characters that have special regex meanings.
  354. var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&')
  355. var match = stream.match(new RegExp('.*?\\)' + delim + '"'))
  356. if (match) state.tokenize = null
  357. else stream.skipToEnd()
  358. return 'string'
  359. }
  360. function def(mimes, mode) {
  361. if (typeof mimes == 'string') mimes = [mimes]
  362. var words = []
  363. function add(obj) {
  364. if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) words.push(prop)
  365. }
  366. add(mode.keywords)
  367. add(mode.types)
  368. add(mode.builtin)
  369. add(mode.atoms)
  370. if (words.length) {
  371. mode.helperType = mimes[0]
  372. CodeMirror.registerHelper('hintWords', mimes[0], words)
  373. }
  374. for (var i = 0; i < mimes.length; ++i) CodeMirror.defineMIME(mimes[i], mode)
  375. }
  376. def(['text/x-csrc', 'text/x-c', 'text/x-chdr'], {
  377. name: 'clike',
  378. keywords: words(cKeywords),
  379. types: cTypes,
  380. blockKeywords: words(cBlockKeywords),
  381. defKeywords: words(cDefKeywords),
  382. typeFirstDefinitions: true,
  383. atoms: words('NULL true false'),
  384. isReservedIdentifier: cIsReservedIdentifier,
  385. hooks: {
  386. '#': cppHook,
  387. '*': pointerHook,
  388. },
  389. modeProps: { fold: ['brace', 'include'] },
  390. })
  391. def(['text/x-c++src', 'text/x-c++hdr'], {
  392. name: 'clike',
  393. keywords: words(cKeywords + ' ' + cppKeywords),
  394. types: cTypes,
  395. blockKeywords: words(cBlockKeywords + ' class try catch'),
  396. defKeywords: words(cDefKeywords + ' class namespace'),
  397. typeFirstDefinitions: true,
  398. atoms: words('true false NULL nullptr'),
  399. dontIndentStatements: /^template$/,
  400. isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
  401. isReservedIdentifier: cIsReservedIdentifier,
  402. hooks: {
  403. '#': cppHook,
  404. '*': pointerHook,
  405. u: cpp11StringHook,
  406. U: cpp11StringHook,
  407. L: cpp11StringHook,
  408. R: cpp11StringHook,
  409. 0: cpp14Literal,
  410. 1: cpp14Literal,
  411. 2: cpp14Literal,
  412. 3: cpp14Literal,
  413. 4: cpp14Literal,
  414. 5: cpp14Literal,
  415. 6: cpp14Literal,
  416. 7: cpp14Literal,
  417. 8: cpp14Literal,
  418. 9: cpp14Literal,
  419. token: function (stream, state, style) {
  420. if (style == 'variable' && stream.peek() == '(' && (state.prevToken == ';' || state.prevToken == null || state.prevToken == '}') && cppLooksLikeConstructor(stream.current()))
  421. return 'def'
  422. },
  423. },
  424. namespaceSeparator: '::',
  425. modeProps: { fold: ['brace', 'include'] },
  426. })
  427. def('text/x-java', {
  428. name: 'clike',
  429. keywords: words(
  430. 'abstract assert break case catch class const continue default ' +
  431. 'do else enum extends final finally for goto if implements import ' +
  432. 'instanceof interface native new package private protected public ' +
  433. 'return static strictfp super switch synchronized this throw throws transient ' +
  434. 'try volatile while @interface'
  435. ),
  436. types: words('var byte short int long float double boolean char void Boolean Byte Character Double Float ' + 'Integer Long Number Object Short String StringBuffer StringBuilder Void'),
  437. blockKeywords: words('catch class do else finally for if switch try while'),
  438. defKeywords: words('class interface enum @interface'),
  439. typeFirstDefinitions: true,
  440. atoms: words('true false null'),
  441. number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
  442. hooks: {
  443. '@': function (stream) {
  444. // Don't match the @interface keyword.
  445. if (stream.match('interface', false)) return false
  446. stream.eatWhile(/[\w\$_]/)
  447. return 'meta'
  448. },
  449. '"': function (stream, state) {
  450. if (!stream.match('""\n')) return false
  451. state.tokenize = tokenTripleString
  452. return state.tokenize(stream, state)
  453. },
  454. },
  455. modeProps: { fold: ['brace', 'import'] },
  456. })
  457. def('text/x-csharp', {
  458. name: 'clike',
  459. keywords: words(
  460. 'abstract as async await base break case catch checked class const continue' +
  461. ' default delegate do else enum event explicit extern finally fixed for' +
  462. ' foreach goto if implicit in interface internal is lock namespace new' +
  463. ' operator out override params private protected public readonly ref return sealed' +
  464. ' sizeof stackalloc static struct switch this throw try typeof unchecked' +
  465. ' unsafe using virtual void volatile while add alias ascending descending dynamic from get' +
  466. ' global group into join let orderby partial remove select set value var yield'
  467. ),
  468. types: words(
  469. 'Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func' +
  470. ' Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32' +
  471. ' UInt64 bool byte char decimal double short int long object' +
  472. ' sbyte float string ushort uint ulong'
  473. ),
  474. blockKeywords: words('catch class do else finally for foreach if struct switch try while'),
  475. defKeywords: words('class interface namespace struct var'),
  476. typeFirstDefinitions: true,
  477. atoms: words('true false null'),
  478. hooks: {
  479. '@': function (stream, state) {
  480. if (stream.eat('"')) {
  481. state.tokenize = tokenAtString
  482. return tokenAtString(stream, state)
  483. }
  484. stream.eatWhile(/[\w\$_]/)
  485. return 'meta'
  486. },
  487. },
  488. })
  489. function tokenTripleString(stream, state) {
  490. var escaped = false
  491. while (!stream.eol()) {
  492. if (!escaped && stream.match('"""')) {
  493. state.tokenize = null
  494. break
  495. }
  496. escaped = stream.next() == '\\' && !escaped
  497. }
  498. return 'string'
  499. }
  500. function tokenNestedComment(depth) {
  501. return function (stream, state) {
  502. var ch
  503. while ((ch = stream.next())) {
  504. if (ch == '*' && stream.eat('/')) {
  505. if (depth == 1) {
  506. state.tokenize = null
  507. break
  508. } else {
  509. state.tokenize = tokenNestedComment(depth - 1)
  510. return state.tokenize(stream, state)
  511. }
  512. } else if (ch == '/' && stream.eat('*')) {
  513. state.tokenize = tokenNestedComment(depth + 1)
  514. return state.tokenize(stream, state)
  515. }
  516. }
  517. return 'comment'
  518. }
  519. }
  520. def('text/x-scala', {
  521. name: 'clike',
  522. keywords: words(
  523. /* scala */
  524. 'abstract case catch class def do else extends final finally for forSome if ' +
  525. 'implicit import lazy match new null object override package private protected return ' +
  526. 'sealed super this throw trait try type val var while with yield _ ' +
  527. /* package scala */
  528. 'assert assume require print println printf readLine readBoolean readByte readShort ' +
  529. 'readChar readInt readLong readFloat readDouble'
  530. ),
  531. types: words(
  532. 'AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either ' +
  533. 'Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable ' +
  534. 'Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering ' +
  535. 'Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder ' +
  536. 'StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector ' +
  537. /* package java.lang */
  538. 'Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable ' +
  539. 'Compiler Double Exception Float Integer Long Math Number Object Package Pair Process ' +
  540. 'Runtime Runnable SecurityManager Short StackTraceElement StrictMath String ' +
  541. 'StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void'
  542. ),
  543. multiLineStrings: true,
  544. blockKeywords: words('catch class enum do else finally for forSome if match switch try while'),
  545. defKeywords: words('class enum def object package trait type val var'),
  546. atoms: words('true false null'),
  547. indentStatements: false,
  548. indentSwitch: false,
  549. isOperatorChar: /[+\-*&%=<>!?|\/#:@]/,
  550. hooks: {
  551. '@': function (stream) {
  552. stream.eatWhile(/[\w\$_]/)
  553. return 'meta'
  554. },
  555. '"': function (stream, state) {
  556. if (!stream.match('""')) return false
  557. state.tokenize = tokenTripleString
  558. return state.tokenize(stream, state)
  559. },
  560. "'": function (stream) {
  561. stream.eatWhile(/[\w\$_\xa1-\uffff]/)
  562. return 'atom'
  563. },
  564. '=': function (stream, state) {
  565. var cx = state.context
  566. if (cx.type == '}' && cx.align && stream.eat('>')) {
  567. state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
  568. return 'operator'
  569. } else {
  570. return false
  571. }
  572. },
  573. '/': function (stream, state) {
  574. if (!stream.eat('*')) return false
  575. state.tokenize = tokenNestedComment(1)
  576. return state.tokenize(stream, state)
  577. },
  578. },
  579. modeProps: { closeBrackets: { pairs: '()[]{}""', triples: '"' } },
  580. })
  581. function tokenKotlinString(tripleString) {
  582. return function (stream, state) {
  583. var escaped = false,
  584. next,
  585. end = false
  586. while (!stream.eol()) {
  587. if (!tripleString && !escaped && stream.match('"')) {
  588. end = true
  589. break
  590. }
  591. if (tripleString && stream.match('"""')) {
  592. end = true
  593. break
  594. }
  595. next = stream.next()
  596. if (!escaped && next == '$' && stream.match('{')) stream.skipTo('}')
  597. escaped = !escaped && next == '\\' && !tripleString
  598. }
  599. if (end || !tripleString) state.tokenize = null
  600. return 'string'
  601. }
  602. }
  603. def('text/x-kotlin', {
  604. name: 'clike',
  605. keywords: words(
  606. /*keywords*/
  607. 'package as typealias class interface this super val operator ' +
  608. 'var fun for is in This throw return annotation ' +
  609. 'break continue object if else while do try when !in !is as? ' +
  610. /*soft keywords*/
  611. 'file import where by get set abstract enum open inner override private public internal ' +
  612. 'protected catch finally out final vararg reified dynamic companion constructor init ' +
  613. 'sealed field property receiver param sparam lateinit data inline noinline tailrec ' +
  614. 'external annotation crossinline const operator infix suspend actual expect setparam value'
  615. ),
  616. types: words(
  617. /* package java.lang */
  618. 'Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable ' +
  619. 'Compiler Double Exception Float Integer Long Math Number Object Package Pair Process ' +
  620. 'Runtime Runnable SecurityManager Short StackTraceElement StrictMath String ' +
  621. 'StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray ' +
  622. 'ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy ' +
  623. 'LazyThreadSafetyMode LongArray Nothing ShortArray Unit'
  624. ),
  625. intendSwitch: false,
  626. indentStatements: false,
  627. multiLineStrings: true,
  628. number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
  629. blockKeywords: words('catch class do else finally for if where try while enum'),
  630. defKeywords: words('class val var object interface fun'),
  631. atoms: words('true false null this'),
  632. hooks: {
  633. '@': function (stream) {
  634. stream.eatWhile(/[\w\$_]/)
  635. return 'meta'
  636. },
  637. '*': function (_stream, state) {
  638. return state.prevToken == '.' ? 'variable' : 'operator'
  639. },
  640. '"': function (stream, state) {
  641. state.tokenize = tokenKotlinString(stream.match('""'))
  642. return state.tokenize(stream, state)
  643. },
  644. '/': function (stream, state) {
  645. if (!stream.eat('*')) return false
  646. state.tokenize = tokenNestedComment(1)
  647. return state.tokenize(stream, state)
  648. },
  649. indent: function (state, ctx, textAfter, indentUnit) {
  650. var firstChar = textAfter && textAfter.charAt(0)
  651. if ((state.prevToken == '}' || state.prevToken == ')') && textAfter == '') return state.indented
  652. if (
  653. (state.prevToken == 'operator' && textAfter != '}' && state.context.type != '}') ||
  654. (state.prevToken == 'variable' && firstChar == '.') ||
  655. ((state.prevToken == '}' || state.prevToken == ')') && firstChar == '.')
  656. )
  657. return indentUnit * 2 + ctx.indented
  658. if (ctx.align && ctx.type == '}') return ctx.indented + (state.context.type == (textAfter || '').charAt(0) ? 0 : indentUnit)
  659. },
  660. },
  661. modeProps: { closeBrackets: { triples: '"' } },
  662. })
  663. def(['x-shader/x-vertex', 'x-shader/x-fragment'], {
  664. name: 'clike',
  665. keywords: words(
  666. 'sampler1D sampler2D sampler3D samplerCube ' +
  667. 'sampler1DShadow sampler2DShadow ' +
  668. 'const attribute uniform varying ' +
  669. 'break continue discard return ' +
  670. 'for while do if else struct ' +
  671. 'in out inout'
  672. ),
  673. types: words('float int bool void ' + 'vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 ' + 'mat2 mat3 mat4'),
  674. blockKeywords: words('for while do if else struct'),
  675. builtin: words(
  676. 'radians degrees sin cos tan asin acos atan ' +
  677. 'pow exp log exp2 sqrt inversesqrt ' +
  678. 'abs sign floor ceil fract mod min max clamp mix step smoothstep ' +
  679. 'length distance dot cross normalize ftransform faceforward ' +
  680. 'reflect refract matrixCompMult ' +
  681. 'lessThan lessThanEqual greaterThan greaterThanEqual ' +
  682. 'equal notEqual any all not ' +
  683. 'texture1D texture1DProj texture1DLod texture1DProjLod ' +
  684. 'texture2D texture2DProj texture2DLod texture2DProjLod ' +
  685. 'texture3D texture3DProj texture3DLod texture3DProjLod ' +
  686. 'textureCube textureCubeLod ' +
  687. 'shadow1D shadow2D shadow1DProj shadow2DProj ' +
  688. 'shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod ' +
  689. 'dFdx dFdy fwidth ' +
  690. 'noise1 noise2 noise3 noise4'
  691. ),
  692. atoms: words(
  693. 'true false ' +
  694. 'gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex ' +
  695. 'gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 ' +
  696. 'gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 ' +
  697. 'gl_FogCoord gl_PointCoord ' +
  698. 'gl_Position gl_PointSize gl_ClipVertex ' +
  699. 'gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor ' +
  700. 'gl_TexCoord gl_FogFragCoord ' +
  701. 'gl_FragCoord gl_FrontFacing ' +
  702. 'gl_FragData gl_FragDepth ' +
  703. 'gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix ' +
  704. 'gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse ' +
  705. 'gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse ' +
  706. 'gl_TextureMatrixTranspose gl_ModelViewMatrixInverseTranspose ' +
  707. 'gl_ProjectionMatrixInverseTranspose ' +
  708. 'gl_ModelViewProjectionMatrixInverseTranspose ' +
  709. 'gl_TextureMatrixInverseTranspose ' +
  710. 'gl_NormalScale gl_DepthRange gl_ClipPlane ' +
  711. 'gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel ' +
  712. 'gl_FrontLightModelProduct gl_BackLightModelProduct ' +
  713. 'gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ ' +
  714. 'gl_FogParameters ' +
  715. 'gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords ' +
  716. 'gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats ' +
  717. 'gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits ' +
  718. 'gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits ' +
  719. 'gl_MaxDrawBuffers'
  720. ),
  721. indentSwitch: false,
  722. hooks: { '#': cppHook },
  723. modeProps: { fold: ['brace', 'include'] },
  724. })
  725. def('text/x-nesc', {
  726. name: 'clike',
  727. keywords: words(
  728. cKeywords +
  729. ' as atomic async call command component components configuration event generic ' +
  730. 'implementation includes interface module new norace nx_struct nx_union post provides ' +
  731. 'signal task uses abstract extends'
  732. ),
  733. types: cTypes,
  734. blockKeywords: words(cBlockKeywords),
  735. atoms: words('null true false'),
  736. hooks: { '#': cppHook },
  737. modeProps: { fold: ['brace', 'include'] },
  738. })
  739. def('text/x-objectivec', {
  740. name: 'clike',
  741. keywords: words(cKeywords + ' ' + objCKeywords),
  742. types: objCTypes,
  743. builtin: words(objCBuiltins),
  744. blockKeywords: words(cBlockKeywords + ' @synthesize @try @catch @finally @autoreleasepool @synchronized'),
  745. defKeywords: words(cDefKeywords + ' @interface @implementation @protocol @class'),
  746. dontIndentStatements: /^@.*$/,
  747. typeFirstDefinitions: true,
  748. atoms: words('YES NO NULL Nil nil true false nullptr'),
  749. isReservedIdentifier: cIsReservedIdentifier,
  750. hooks: {
  751. '#': cppHook,
  752. '*': pointerHook,
  753. },
  754. modeProps: { fold: ['brace', 'include'] },
  755. })
  756. def('text/x-objectivec++', {
  757. name: 'clike',
  758. keywords: words(cKeywords + ' ' + objCKeywords + ' ' + cppKeywords),
  759. types: objCTypes,
  760. builtin: words(objCBuiltins),
  761. blockKeywords: words(cBlockKeywords + ' @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch'),
  762. defKeywords: words(cDefKeywords + ' @interface @implementation @protocol @class class namespace'),
  763. dontIndentStatements: /^@.*$|^template$/,
  764. typeFirstDefinitions: true,
  765. atoms: words('YES NO NULL Nil nil true false nullptr'),
  766. isReservedIdentifier: cIsReservedIdentifier,
  767. hooks: {
  768. '#': cppHook,
  769. '*': pointerHook,
  770. u: cpp11StringHook,
  771. U: cpp11StringHook,
  772. L: cpp11StringHook,
  773. R: cpp11StringHook,
  774. 0: cpp14Literal,
  775. 1: cpp14Literal,
  776. 2: cpp14Literal,
  777. 3: cpp14Literal,
  778. 4: cpp14Literal,
  779. 5: cpp14Literal,
  780. 6: cpp14Literal,
  781. 7: cpp14Literal,
  782. 8: cpp14Literal,
  783. 9: cpp14Literal,
  784. token: function (stream, state, style) {
  785. if (style == 'variable' && stream.peek() == '(' && (state.prevToken == ';' || state.prevToken == null || state.prevToken == '}') && cppLooksLikeConstructor(stream.current()))
  786. return 'def'
  787. },
  788. },
  789. namespaceSeparator: '::',
  790. modeProps: { fold: ['brace', 'include'] },
  791. })
  792. def('text/x-squirrel', {
  793. name: 'clike',
  794. keywords: words('base break clone continue const default delete enum extends function in class' + ' foreach local resume return this throw typeof yield constructor instanceof static'),
  795. types: cTypes,
  796. blockKeywords: words('case catch class else for foreach if switch try while'),
  797. defKeywords: words('function local class'),
  798. typeFirstDefinitions: true,
  799. atoms: words('true false null'),
  800. hooks: { '#': cppHook },
  801. modeProps: { fold: ['brace', 'include'] },
  802. })
  803. // Ceylon Strings need to deal with interpolation
  804. var stringTokenizer = null
  805. function tokenCeylonString(type) {
  806. return function (stream, state) {
  807. var escaped = false,
  808. next,
  809. end = false
  810. while (!stream.eol()) {
  811. if (!escaped && stream.match('"') && (type == 'single' || stream.match('""'))) {
  812. end = true
  813. break
  814. }
  815. if (!escaped && stream.match('``')) {
  816. stringTokenizer = tokenCeylonString(type)
  817. end = true
  818. break
  819. }
  820. next = stream.next()
  821. escaped = type == 'single' && !escaped && next == '\\'
  822. }
  823. if (end) state.tokenize = null
  824. return 'string'
  825. }
  826. }
  827. def('text/x-ceylon', {
  828. name: 'clike',
  829. keywords: words(
  830. 'abstracts alias assembly assert assign break case catch class continue dynamic else' +
  831. ' exists extends finally for function given if import in interface is let module new' +
  832. ' nonempty object of out outer package return satisfies super switch then this throw' +
  833. ' try value void while'
  834. ),
  835. types: function (word) {
  836. // In Ceylon all identifiers that start with an uppercase are types
  837. var first = word.charAt(0)
  838. return first === first.toUpperCase() && first !== first.toLowerCase()
  839. },
  840. blockKeywords: words('case catch class dynamic else finally for function if interface module new object switch try while'),
  841. defKeywords: words('class dynamic function interface module object package value'),
  842. builtin: words(
  843. 'abstract actual aliased annotation by default deprecated doc final formal late license' + ' native optional sealed see serializable shared suppressWarnings tagged throws variable'
  844. ),
  845. isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
  846. isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
  847. numberStart: /[\d#$]/,
  848. number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
  849. multiLineStrings: true,
  850. typeFirstDefinitions: true,
  851. atoms: words('true false null larger smaller equal empty finished'),
  852. indentSwitch: false,
  853. styleDefs: false,
  854. hooks: {
  855. '@': function (stream) {
  856. stream.eatWhile(/[\w\$_]/)
  857. return 'meta'
  858. },
  859. '"': function (stream, state) {
  860. state.tokenize = tokenCeylonString(stream.match('""') ? 'triple' : 'single')
  861. return state.tokenize(stream, state)
  862. },
  863. '`': function (stream, state) {
  864. if (!stringTokenizer || !stream.match('`')) return false
  865. state.tokenize = stringTokenizer
  866. stringTokenizer = null
  867. return state.tokenize(stream, state)
  868. },
  869. "'": function (stream) {
  870. stream.eatWhile(/[\w\$_\xa1-\uffff]/)
  871. return 'atom'
  872. },
  873. token: function (_stream, state, style) {
  874. if ((style == 'variable' || style == 'type') && state.prevToken == '.') {
  875. return 'variable-2'
  876. }
  877. },
  878. },
  879. modeProps: {
  880. fold: ['brace', 'import'],
  881. closeBrackets: { triples: '"' },
  882. },
  883. })
  884. })