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