multiplex.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. CodeMirror.multiplexingMode = function(outer /*, others */) {
  2. // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects
  3. var others = Array.prototype.slice.call(arguments, 1);
  4. var n_others = others.length;
  5. function indexOf(string, pattern, from) {
  6. if (typeof pattern == "string") return string.indexOf(pattern, from);
  7. var m = pattern.exec(from ? string.slice(from) : string);
  8. return m ? m.index + from : -1;
  9. }
  10. return {
  11. startState: function() {
  12. return {
  13. outer: CodeMirror.startState(outer),
  14. innerActive: null,
  15. inner: null
  16. };
  17. },
  18. copyState: function(state) {
  19. return {
  20. outer: CodeMirror.copyState(outer, state.outer),
  21. innerActive: state.innerActive,
  22. inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
  23. };
  24. },
  25. token: function(stream, state) {
  26. if (!state.innerActive) {
  27. var cutOff = Infinity, oldContent = stream.string;
  28. for (var i = 0; i < n_others; ++i) {
  29. var other = others[i];
  30. var found = indexOf(oldContent, other.open, stream.pos);
  31. if (found == stream.pos) {
  32. stream.match(other.open);
  33. state.innerActive = other;
  34. state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
  35. return other.delimStyle;
  36. } else if (found != -1 && found < cutOff) {
  37. cutOff = found;
  38. }
  39. }
  40. if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
  41. var outerToken = outer.token(stream, state.outer);
  42. if (cutOff != Infinity) stream.string = oldContent;
  43. return outerToken;
  44. } else {
  45. var curInner = state.innerActive, oldContent = stream.string;
  46. var found = indexOf(oldContent, curInner.close, stream.pos);
  47. if (found == stream.pos) {
  48. stream.match(curInner.close);
  49. state.innerActive = state.inner = null;
  50. return curInner.delimStyle;
  51. }
  52. if (found > -1) stream.string = oldContent.slice(0, found);
  53. var innerToken = curInner.mode.token(stream, state.inner);
  54. if (found > -1) stream.string = oldContent;
  55. var cur = stream.current(), found = cur.indexOf(curInner.close);
  56. if (found > -1) stream.backUp(cur.length - found);
  57. if (curInner.innerStyle) {
  58. if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle;
  59. else innerToken = curInner.innerStyle;
  60. }
  61. return innerToken;
  62. }
  63. },
  64. indent: function(state, textAfter) {
  65. var mode = state.innerActive ? state.innerActive.mode : outer;
  66. if (!mode.indent) return CodeMirror.Pass;
  67. return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
  68. },
  69. blankLine: function(state) {
  70. var mode = state.innerActive ? state.innerActive.mode : outer;
  71. if (mode.blankLine) {
  72. mode.blankLine(state.innerActive ? state.inner : state.outer);
  73. }
  74. if (!state.innerActive) {
  75. for (var i = 0; i < n_others; ++i) {
  76. var other = others[i];
  77. if (other.open === "\n") {
  78. state.innerActive = other;
  79. state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0);
  80. }
  81. }
  82. } else if (state.innerActive.close === "\n") {
  83. state.innerActive = state.inner = null;
  84. }
  85. },
  86. electricChars: outer.electricChars,
  87. innerMode: function(state) {
  88. return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
  89. }
  90. };
  91. };