| 1 |
// CodeMirror, copyright (c) by Marijn Haverbeke and others |
| 2 |
// Distributed under an MIT license: http://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 |
var eolState = cm.getStateAfter(pos.line); |
| 24 |
var inList = eolState.list !== false; |
| 25 |
var inQuote = eolState.quote !== 0; |
| 26 |
|
| 27 |
var line = cm.getLine(pos.line), match = listRE.exec(line); |
| 28 |
var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); |
| 29 |
if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { |
| 30 |
cm.execCommand("newlineAndIndent"); |
| 31 |
return; |
| 32 |
} |
| 33 |
if (emptyListRE.test(line)) { |
| 34 |
if (!/>\s*$/.test(line)) cm.replaceRange("", { |
| 35 |
line: pos.line, ch: 0 |
| 36 |
}, { |
| 37 |
line: pos.line, ch: pos.ch + 1 |
| 38 |
}); |
| 39 |
replacements[i] = "\n"; |
| 40 |
} else { |
| 41 |
var indent = match[1], after = match[5]; |
| 42 |
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 |
| 43 |
? match[2].replace("x", " ") |
| 44 |
: (parseInt(match[3], 10) + 1) + match[4]; |
| 45 |
|
| 46 |
replacements[i] = "\n" + indent + bullet + after; |
| 47 |
|
| 48 |
incrementRemainingMarkdownListNumbers(cm, pos); |
| 49 |
} |
| 50 |
} |
| 51 |
|
| 52 |
cm.replaceSelections(replacements); |
| 53 |
}; |
| 54 |
|
| 55 |
// Auto-updating Markdown list numbers when a new item is added to the |
| 56 |
// middle of a list |
| 57 |
function incrementRemainingMarkdownListNumbers(cm, pos) { |
| 58 |
var startLine = pos.line, lookAhead = 0, skipCount = 0; |
| 59 |
var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; |
| 60 |
|
| 61 |
do { |
| 62 |
lookAhead += 1; |
| 63 |
var nextLineNumber = startLine + lookAhead; |
| 64 |
var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); |
| 65 |
|
| 66 |
if (nextItem) { |
| 67 |
var nextIndent = nextItem[1]; |
| 68 |
var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); |
| 69 |
var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; |
| 70 |
|
| 71 |
if (startIndent === nextIndent) { |
| 72 |
if (newNumber === nextNumber) itemNumber = nextNumber + 1; |
| 73 |
if (newNumber > nextNumber) itemNumber = newNumber + 1; |
| 74 |
cm.replaceRange( |
| 75 |
nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), |
| 76 |
{ |
| 77 |
line: nextLineNumber, ch: 0 |
| 78 |
}, { |
| 79 |
line: nextLineNumber, ch: nextLine.length |
| 80 |
}); |
| 81 |
} else { |
| 82 |
if (startIndent.length > nextIndent.length) return; |
| 83 |
// This doesn't run if the next line immediatley indents, as it is |
| 84 |
// not clear of the users intention (new indented item or same level) |
| 85 |
if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; |
| 86 |
skipCount += 1; |
| 87 |
} |
| 88 |
} |
| 89 |
} while (nextItem); |
| 90 |
} |
| 91 |
}); |
| 92 |
|