continuelist.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
  15. emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
  16. unorderedListRE = /[*+-]\s/
  17. CodeMirror.commands.newlineAndIndentContinueMarkdownList = function (cm) {
  18. if (cm.getOption('disableInput')) return CodeMirror.Pass
  19. var ranges = cm.listSelections(),
  20. replacements = []
  21. for (var i = 0; i < ranges.length; i++) {
  22. var pos = ranges[i].head
  23. // If we're not in Markdown mode, fall back to normal newlineAndIndent
  24. var eolState = cm.getStateAfter(pos.line)
  25. var inner = CodeMirror.innerMode(cm.getMode(), eolState)
  26. if (inner.mode.name !== 'markdown' && inner.mode.helperType !== 'markdown') {
  27. cm.execCommand('newlineAndIndent')
  28. return
  29. } else {
  30. eolState = inner.state
  31. }
  32. var inList = eolState.list !== false
  33. var inQuote = eolState.quote !== 0
  34. var line = cm.getLine(pos.line),
  35. match = listRE.exec(line)
  36. var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch))
  37. if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) {
  38. cm.execCommand('newlineAndIndent')
  39. return
  40. }
  41. if (emptyListRE.test(line)) {
  42. var endOfQuote = inQuote && />\s*$/.test(line)
  43. var endOfList = !/>\s*$/.test(line)
  44. if (endOfQuote || endOfList)
  45. cm.replaceRange(
  46. '',
  47. {
  48. line: pos.line,
  49. ch: 0,
  50. },
  51. {
  52. line: pos.line,
  53. ch: pos.ch + 1,
  54. }
  55. )
  56. replacements[i] = '\n'
  57. } else {
  58. var indent = match[1],
  59. after = match[5]
  60. var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf('>') >= 0)
  61. var bullet = numbered ? parseInt(match[3], 10) + 1 + match[4] : match[2].replace('x', ' ')
  62. replacements[i] = '\n' + indent + bullet + after
  63. if (numbered) incrementRemainingMarkdownListNumbers(cm, pos)
  64. }
  65. }
  66. cm.replaceSelections(replacements)
  67. }
  68. // Auto-updating Markdown list numbers when a new item is added to the
  69. // middle of a list
  70. function incrementRemainingMarkdownListNumbers(cm, pos) {
  71. var startLine = pos.line,
  72. lookAhead = 0,
  73. skipCount = 0
  74. var startItem = listRE.exec(cm.getLine(startLine)),
  75. startIndent = startItem[1]
  76. do {
  77. lookAhead += 1
  78. var nextLineNumber = startLine + lookAhead
  79. var nextLine = cm.getLine(nextLineNumber),
  80. nextItem = listRE.exec(nextLine)
  81. if (nextItem) {
  82. var nextIndent = nextItem[1]
  83. var newNumber = parseInt(startItem[3], 10) + lookAhead - skipCount
  84. var nextNumber = parseInt(nextItem[3], 10),
  85. itemNumber = nextNumber
  86. if (startIndent === nextIndent && !isNaN(nextNumber)) {
  87. if (newNumber === nextNumber) itemNumber = nextNumber + 1
  88. if (newNumber > nextNumber) itemNumber = newNumber + 1
  89. cm.replaceRange(
  90. nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]),
  91. {
  92. line: nextLineNumber,
  93. ch: 0,
  94. },
  95. {
  96. line: nextLineNumber,
  97. ch: nextLine.length,
  98. }
  99. )
  100. } else {
  101. if (startIndent.length > nextIndent.length) return
  102. // This doesn't run if the next line immediately indents, as it is
  103. // not clear of the users intention (new indented item or same level)
  104. if (startIndent.length < nextIndent.length && lookAhead === 1) return
  105. skipCount += 1
  106. }
  107. }
  108. } while (nextItem)
  109. }
  110. })