multiplex.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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.multiplexingMode = function (outer /*, others */) {
  15. // Others should be {open, close, mode [, delimStyle] [, innerStyle] [, parseDelimiters]} objects
  16. var others = Array.prototype.slice.call(arguments, 1)
  17. function indexOf(string, pattern, from, returnEnd) {
  18. if (typeof pattern == 'string') {
  19. var found = string.indexOf(pattern, from)
  20. return returnEnd && found > -1 ? found + pattern.length : found
  21. }
  22. var m = pattern.exec(from ? string.slice(from) : string)
  23. return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1
  24. }
  25. return {
  26. startState: function () {
  27. return {
  28. outer: CodeMirror.startState(outer),
  29. innerActive: null,
  30. inner: null,
  31. startingInner: false,
  32. }
  33. },
  34. copyState: function (state) {
  35. return {
  36. outer: CodeMirror.copyState(outer, state.outer),
  37. innerActive: state.innerActive,
  38. inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner),
  39. startingInner: state.startingInner,
  40. }
  41. },
  42. token: function (stream, state) {
  43. if (!state.innerActive) {
  44. var cutOff = Infinity,
  45. oldContent = stream.string
  46. for (var i = 0; i < others.length; ++i) {
  47. var other = others[i]
  48. var found = indexOf(oldContent, other.open, stream.pos)
  49. if (found == stream.pos) {
  50. if (!other.parseDelimiters) stream.match(other.open)
  51. state.startingInner = !!other.parseDelimiters
  52. state.innerActive = other
  53. // Get the outer indent, making sure to handle CodeMirror.Pass
  54. var outerIndent = 0
  55. if (outer.indent) {
  56. var possibleOuterIndent = outer.indent(state.outer, '', '')
  57. if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent
  58. }
  59. state.inner = CodeMirror.startState(other.mode, outerIndent)
  60. return other.delimStyle && other.delimStyle + ' ' + other.delimStyle + '-open'
  61. } else if (found != -1 && found < cutOff) {
  62. cutOff = found
  63. }
  64. }
  65. if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff)
  66. var outerToken = outer.token(stream, state.outer)
  67. if (cutOff != Infinity) stream.string = oldContent
  68. return outerToken
  69. } else {
  70. var curInner = state.innerActive,
  71. oldContent = stream.string
  72. if (!curInner.close && stream.sol()) {
  73. state.innerActive = state.inner = null
  74. return this.token(stream, state)
  75. }
  76. var found = curInner.close && !state.startingInner ? indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1
  77. if (found == stream.pos && !curInner.parseDelimiters) {
  78. stream.match(curInner.close)
  79. state.innerActive = state.inner = null
  80. return curInner.delimStyle && curInner.delimStyle + ' ' + curInner.delimStyle + '-close'
  81. }
  82. if (found > -1) stream.string = oldContent.slice(0, found)
  83. var innerToken = curInner.mode.token(stream, state.inner)
  84. if (found > -1) stream.string = oldContent
  85. else if (stream.pos > stream.start) state.startingInner = false
  86. if (found == stream.pos && curInner.parseDelimiters) state.innerActive = state.inner = null
  87. if (curInner.innerStyle) {
  88. if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle
  89. else innerToken = curInner.innerStyle
  90. }
  91. return innerToken
  92. }
  93. },
  94. indent: function (state, textAfter, line) {
  95. var mode = state.innerActive ? state.innerActive.mode : outer
  96. if (!mode.indent) return CodeMirror.Pass
  97. return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line)
  98. },
  99. blankLine: function (state) {
  100. var mode = state.innerActive ? state.innerActive.mode : outer
  101. if (mode.blankLine) {
  102. mode.blankLine(state.innerActive ? state.inner : state.outer)
  103. }
  104. if (!state.innerActive) {
  105. for (var i = 0; i < others.length; ++i) {
  106. var other = others[i]
  107. if (other.open === '\n') {
  108. state.innerActive = other
  109. state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, '', '') : 0)
  110. }
  111. }
  112. } else if (state.innerActive.close === '\n') {
  113. state.innerActive = state.inner = null
  114. }
  115. },
  116. electricChars: outer.electricChars,
  117. innerMode: function (state) {
  118. return state.inner ? { state: state.inner, mode: state.innerActive.mode } : { state: state.outer, mode: outer }
  119. },
  120. }
  121. }
  122. })