turtle.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. CodeMirror.defineMode('turtle', function (config) {
  15. var indentUnit = config.indentUnit
  16. var curPunc
  17. function wordRegexp(words) {
  18. return new RegExp('^(?:' + words.join('|') + ')$', 'i')
  19. }
  20. var ops = wordRegexp([])
  21. var keywords = wordRegexp(['@prefix', '@base', 'a'])
  22. var operatorChars = /[*+\-<>=&|]/
  23. function tokenBase(stream, state) {
  24. var ch = stream.next()
  25. curPunc = null
  26. if (ch == '<' && !stream.match(/^[\s\u00a0=]/, false)) {
  27. stream.match(/^[^\s\u00a0>]*>?/)
  28. return 'atom'
  29. } else if (ch == '"' || ch == "'") {
  30. state.tokenize = tokenLiteral(ch)
  31. return state.tokenize(stream, state)
  32. } else if (/[{}\(\),\.;\[\]]/.test(ch)) {
  33. curPunc = ch
  34. return null
  35. } else if (ch == '#') {
  36. stream.skipToEnd()
  37. return 'comment'
  38. } else if (operatorChars.test(ch)) {
  39. stream.eatWhile(operatorChars)
  40. return null
  41. } else if (ch == ':') {
  42. return 'operator'
  43. } else {
  44. stream.eatWhile(/[_\w\d]/)
  45. if (stream.peek() == ':') {
  46. return 'variable-3'
  47. } else {
  48. var word = stream.current()
  49. if (keywords.test(word)) {
  50. return 'meta'
  51. }
  52. if (ch >= 'A' && ch <= 'Z') {
  53. return 'comment'
  54. } else {
  55. return 'keyword'
  56. }
  57. }
  58. var word = stream.current()
  59. if (ops.test(word)) return null
  60. else if (keywords.test(word)) return 'meta'
  61. else return 'variable'
  62. }
  63. }
  64. function tokenLiteral(quote) {
  65. return function (stream, state) {
  66. var escaped = false,
  67. ch
  68. while ((ch = stream.next()) != null) {
  69. if (ch == quote && !escaped) {
  70. state.tokenize = tokenBase
  71. break
  72. }
  73. escaped = !escaped && ch == '\\'
  74. }
  75. return 'string'
  76. }
  77. }
  78. function pushContext(state, type, col) {
  79. state.context = { prev: state.context, indent: state.indent, col: col, type: type }
  80. }
  81. function popContext(state) {
  82. state.indent = state.context.indent
  83. state.context = state.context.prev
  84. }
  85. return {
  86. startState: function () {
  87. return { tokenize: tokenBase, context: null, indent: 0, col: 0 }
  88. },
  89. token: function (stream, state) {
  90. if (stream.sol()) {
  91. if (state.context && state.context.align == null) state.context.align = false
  92. state.indent = stream.indentation()
  93. }
  94. if (stream.eatSpace()) return null
  95. var style = state.tokenize(stream, state)
  96. if (style != 'comment' && state.context && state.context.align == null && state.context.type != 'pattern') {
  97. state.context.align = true
  98. }
  99. if (curPunc == '(') pushContext(state, ')', stream.column())
  100. else if (curPunc == '[') pushContext(state, ']', stream.column())
  101. else if (curPunc == '{') pushContext(state, '}', stream.column())
  102. else if (/[\]\}\)]/.test(curPunc)) {
  103. while (state.context && state.context.type == 'pattern') popContext(state)
  104. if (state.context && curPunc == state.context.type) popContext(state)
  105. } else if (curPunc == '.' && state.context && state.context.type == 'pattern') popContext(state)
  106. else if (/atom|string|variable/.test(style) && state.context) {
  107. if (/[\}\]]/.test(state.context.type)) pushContext(state, 'pattern', stream.column())
  108. else if (state.context.type == 'pattern' && !state.context.align) {
  109. state.context.align = true
  110. state.context.col = stream.column()
  111. }
  112. }
  113. return style
  114. },
  115. indent: function (state, textAfter) {
  116. var firstChar = textAfter && textAfter.charAt(0)
  117. var context = state.context
  118. if (/[\]\}]/.test(firstChar)) while (context && context.type == 'pattern') context = context.prev
  119. var closing = context && firstChar == context.type
  120. if (!context) return 0
  121. else if (context.type == 'pattern') return context.col
  122. else if (context.align) return context.col + (closing ? 0 : 1)
  123. else return context.indent + (closing ? 0 : indentUnit)
  124. },
  125. lineComment: '#',
  126. }
  127. })
  128. CodeMirror.defineMIME('text/turtle', 'turtle')
  129. })