636 lines
31 KiB
JavaScript
Vendored
636 lines
31 KiB
JavaScript
Vendored
// HyperMD, copyright (c) by laobubu
|
|
// Distributed under an MIT license: http://laobubu.net/HyperMD/LICENSE
|
|
//
|
|
// powerful keymap for HyperMD and Markdown modes
|
|
//
|
|
|
|
(function (mod){ //[HyperMD] UMD patched!
|
|
/*commonjs*/ ("object"==typeof exports&&"undefined"!=typeof module) ? mod(null, exports, require("codemirror"), require("codemirror"), require("../core")) :
|
|
/*amd*/ ("function"==typeof define&&define.amd) ? define(["require","exports","codemirror","codemirror","../core"], mod) :
|
|
/*plain env*/ mod(null, (this.HyperMD.KeyMap = this.HyperMD.KeyMap || {}), CodeMirror, CodeMirror, HyperMD);
|
|
})(function (require, exports, CodeMirror, codemirror_1, core_1) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var _a;
|
|
/**
|
|
Some codes in this files are from CodeMirror's source code.
|
|
|
|
CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
MIT license: http://codemirror.net/LICENSE
|
|
|
|
@see codemirror\addon\edit\continuelist.js
|
|
*/
|
|
// loq = List Or Quote
|
|
var LoQRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/, emptyLoQRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/, unorderedListRE = /[*+-]\s/;
|
|
var ListRE = /^(\s*)([*+-]\s|(\d+)([.)]))(\s*)/;
|
|
var isRealTableSep = function (token) { return /hmd-table-sep/.test(token.type) && !/hmd-table-sep-dummy/.test(token.type); };
|
|
/**
|
|
* continue list / quote / insert table row
|
|
* start a table
|
|
*/
|
|
function newlineAndContinue(cm) {
|
|
if (cm.getOption("disableInput"))
|
|
return CodeMirror.Pass;
|
|
var selections = cm.listSelections();
|
|
var replacements = [];
|
|
for (var _i = 0, selections_1 = selections; _i < selections_1.length; _i++) {
|
|
var range = selections_1[_i];
|
|
var pos = range.head;
|
|
var rangeEmpty = range.empty();
|
|
var eolState = cm.getStateAfter(pos.line);
|
|
var line = cm.getLine(pos.line);
|
|
var handled = false;
|
|
if (!handled) {
|
|
var inList = eolState.list !== false;
|
|
var inQuote = eolState.quote;
|
|
var match = LoQRE.exec(line);
|
|
var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch));
|
|
if (rangeEmpty && (inList || inQuote) && match && !cursorBeforeBullet) {
|
|
handled = true;
|
|
if (emptyLoQRE.test(line)) {
|
|
if (!/>\s*$/.test(line))
|
|
cm.replaceRange("", { line: pos.line, ch: 0 }, { line: pos.line, ch: pos.ch + 1 });
|
|
replacements.push("\n");
|
|
}
|
|
else {
|
|
var indent = match[1], after = match[5];
|
|
var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
|
|
var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
|
|
replacements.push("\n" + indent + bullet + after);
|
|
if (numbered)
|
|
incrementRemainingMarkdownListNumbers(cm, pos);
|
|
}
|
|
}
|
|
}
|
|
if (!handled) {
|
|
var table = rangeEmpty ? eolState.hmdTable : 0 /* NONE */;
|
|
if (table != 0 /* NONE */) {
|
|
if (/^[\s\|]+$/.test(line) && (pos.line === cm.lastLine() || (cm.getStateAfter(pos.line + 1).hmdTable !== table))) {
|
|
// if this is last row and is empty
|
|
// remove this row and insert a new line
|
|
cm.setCursor({ line: pos.line, ch: 0 });
|
|
cm.replaceRange("\n", { line: pos.line, ch: 0 }, { line: pos.line, ch: line.length });
|
|
}
|
|
else {
|
|
// insert a row below
|
|
var columns = eolState.hmdTableColumns;
|
|
var newline_1 = core_1.repeatStr(" | ", columns.length - 1);
|
|
var leading = "\n";
|
|
if (table === 2 /* NORMAL */) {
|
|
leading += "| ";
|
|
newline_1 += " |";
|
|
}
|
|
// There are always nut users!
|
|
if (eolState.hmdTableRow == 0) {
|
|
cm.setCursor({ line: pos.line + 1, ch: cm.getLine(pos.line + 1).length });
|
|
}
|
|
else {
|
|
cm.setCursor({ line: pos.line, ch: line.length });
|
|
}
|
|
cm.replaceSelection(leading);
|
|
cm.replaceSelection(newline_1, "start");
|
|
}
|
|
handled = true;
|
|
return;
|
|
}
|
|
else if (rangeEmpty && pos.ch >= line.length && !eolState.code && !eolState.hmdInnerMode && /^\|.+\|.+\|$/.test(line)) {
|
|
// current line is | this | format |
|
|
// let's make a table
|
|
var lineTokens = cm.getLineTokens(pos.line);
|
|
var ans = "|", ans2 = "|";
|
|
for (var i = 1; i < lineTokens.length; i++) { // first token must be "|"
|
|
var token = lineTokens[i];
|
|
if (token.string === "|" && (!token.type || !token.type.trim().length)) {
|
|
ans += " ------- |";
|
|
ans2 += " |";
|
|
}
|
|
}
|
|
// multi-cursor is meanless for this
|
|
// replacements.push("\n" + ans + "\n" + ans2 + "\n")
|
|
cm.setCursor({ line: pos.line, ch: line.length });
|
|
cm.replaceSelection("\n" + ans + "\n| ");
|
|
cm.replaceSelection(ans2.slice(1) + "\n", "start");
|
|
handled = true;
|
|
return;
|
|
}
|
|
}
|
|
if (!handled) {
|
|
if (rangeEmpty && line.slice(pos.ch - 2, pos.ch) == "$$" && /math-end/.test(cm.getTokenTypeAt(pos))) {
|
|
// ignore indentations of MathBlock Tex lines
|
|
replacements.push("\n");
|
|
handled = true;
|
|
}
|
|
}
|
|
if (!handled) {
|
|
cm.execCommand("newlineAndIndent");
|
|
return;
|
|
}
|
|
}
|
|
cm.replaceSelections(replacements);
|
|
}
|
|
exports.newlineAndContinue = newlineAndContinue;
|
|
/** insert "\n" , or if in list, insert "\n" + indentation */
|
|
function newline(cm) {
|
|
if (cm.getOption("disableInput"))
|
|
return CodeMirror.Pass;
|
|
var selections = cm.listSelections();
|
|
var replacements = core_1.repeat("\n", selections.length);
|
|
for (var i = 0; i < selections.length; i++) {
|
|
var range = selections[i];
|
|
var pos = range.head;
|
|
var eolState = cm.getStateAfter(pos.line);
|
|
if (eolState.list !== false) {
|
|
replacements[i] += core_1.repeatStr(" ", eolState.listStack.slice(-1)[0]);
|
|
}
|
|
}
|
|
cm.replaceSelections(replacements);
|
|
}
|
|
exports.newline = newline;
|
|
function killIndent(cm, lineNo, spaces) {
|
|
if (!spaces || spaces < 0)
|
|
return;
|
|
var oldSpaces = /^ */.exec(cm.getLine(lineNo))[0].length;
|
|
if (oldSpaces < spaces)
|
|
spaces = oldSpaces;
|
|
if (spaces > 0)
|
|
cm.replaceRange("", { line: lineNo, ch: 0 }, { line: lineNo, ch: spaces });
|
|
}
|
|
/** unindent or move cursor into prev table cell */
|
|
function shiftTab(cm) {
|
|
var _a;
|
|
var selections = cm.listSelections();
|
|
var replacements = [];
|
|
var tokenSeeker = new core_1.TokenSeeker(cm);
|
|
for (var i = 0; i < selections.length; i++) {
|
|
var range = selections[i];
|
|
var left = range.head;
|
|
var right = range.anchor;
|
|
var rangeEmpty = range.empty();
|
|
if (!rangeEmpty && codemirror_1.cmpPos(left, right) > 0)
|
|
_a = [left, right], right = _a[0], left = _a[1];
|
|
else if (right === left) {
|
|
right = range.anchor = { ch: left.ch, line: left.line };
|
|
}
|
|
var eolState = cm.getStateAfter(left.line);
|
|
if (eolState.hmdTable) {
|
|
tokenSeeker.setPos(left.line, left.ch);
|
|
var isNormalTable = eolState.hmdTable === 2 /* NORMAL */; // leading and ending | is not omitted
|
|
var line = left.line;
|
|
var lineText = cm.getLine(line);
|
|
var chStart = 0, chEnd = 0;
|
|
var rightPipe = tokenSeeker.findPrev(isRealTableSep);
|
|
if (rightPipe) { // prev cell is in this line
|
|
var leftPipe = tokenSeeker.findPrev(isRealTableSep, rightPipe.i_token - 1);
|
|
chStart = leftPipe ? leftPipe.token.end : 0;
|
|
chEnd = rightPipe.token.start;
|
|
if (chStart == 0 && isNormalTable)
|
|
chStart += lineText.match(/^\s*\|/)[0].length;
|
|
}
|
|
else { // jump to prev line, last cell
|
|
if (eolState.hmdTableRow == 0)
|
|
return; // no more row before
|
|
if (eolState.hmdTableRow == 2)
|
|
line--; // skip row #1 (| ----- | ----- |)
|
|
line--;
|
|
lineText = cm.getLine(line);
|
|
tokenSeeker.setPos(line, lineText.length);
|
|
var leftPipe = tokenSeeker.findPrev(isRealTableSep);
|
|
chStart = leftPipe.token.end;
|
|
chEnd = lineText.length;
|
|
if (isNormalTable)
|
|
chEnd -= lineText.match(/\|\s*$/)[0].length;
|
|
}
|
|
if (lineText.charAt(chStart) === " ")
|
|
chStart += 1;
|
|
if (chStart > 0 && lineText.substr(chStart - 1, 2) === ' |')
|
|
chStart--;
|
|
if (lineText.charAt(chEnd - 1) === " ")
|
|
chEnd -= 1;
|
|
cm.setSelection({ line: line, ch: chStart }, { line: line, ch: chEnd });
|
|
return;
|
|
}
|
|
else if (eolState.listStack.length > 0) {
|
|
var lineNo = left.line;
|
|
while (!ListRE.test(cm.getLine(lineNo))) { // beginning line has no bullet? go up
|
|
lineNo--;
|
|
var isList = cm.getStateAfter(lineNo).listStack.length > 0;
|
|
if (!isList) {
|
|
lineNo++;
|
|
break;
|
|
}
|
|
}
|
|
var lastLine = cm.lastLine();
|
|
var tmp = void 0;
|
|
for (; lineNo <= right.line && (tmp = ListRE.exec(cm.getLine(lineNo))); lineNo++) {
|
|
var listStack = cm.getStateAfter(lineNo).listStack;
|
|
var listLevel = listStack.length;
|
|
var spaces = 0;
|
|
if (listLevel == 1) {
|
|
// maybe user wants to trimLeft?
|
|
spaces = tmp[1].length;
|
|
}
|
|
else {
|
|
// make bullets right-aligned
|
|
spaces = (listStack[listLevel - 1] - (listStack[listLevel - 2] || 0));
|
|
}
|
|
killIndent(cm, lineNo, spaces);
|
|
// if current list item is multi-line...
|
|
while (++lineNo <= lastLine) {
|
|
if ( /*corrupted */cm.getStateAfter(lineNo).listStack.length !== listLevel) {
|
|
lineNo = Infinity;
|
|
break;
|
|
}
|
|
if ( /*has bullet*/ListRE.test(cm.getLine(lineNo))) {
|
|
lineNo--;
|
|
break;
|
|
}
|
|
killIndent(cm, lineNo, spaces);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
cm.execCommand("indentLess");
|
|
}
|
|
exports.shiftTab = shiftTab;
|
|
/**
|
|
* 1. for tables, move cursor into next table cell, and maybe insert a cell
|
|
* 2.
|
|
*/
|
|
function tab(cm) {
|
|
var _a;
|
|
// PATCHED: listSelections() returns the live selection ranges, and the
|
|
// code below mutates head/anchor in place. That silently rewrites the
|
|
// current selection, so the final setSelections() compares equal to it
|
|
// and CodeMirror skips the cursor redraw - the cursor visually stays
|
|
// in the old table cell while typing goes to the new one. Copy first.
|
|
var selections = cm.listSelections().map(function (r) {
|
|
return {
|
|
anchor: { line: r.anchor.line, ch: r.anchor.ch },
|
|
head: { line: r.head.line, ch: r.head.ch },
|
|
empty: function () {
|
|
return this.anchor.line === this.head.line && this.anchor.ch === this.head.ch;
|
|
},
|
|
};
|
|
});
|
|
var beforeCur = [];
|
|
var afterCur = [];
|
|
var selected = [];
|
|
var addIndentTo = {}; // {lineNo: stringIndent}
|
|
var tokenSeeker = new core_1.TokenSeeker(cm);
|
|
/** indicate previous 4 variable changed or not */
|
|
var flag0 = false, flag1 = false, flag2 = false, flag3 = true;
|
|
function setBeforeCur(text) { beforeCur[i] = text; if (text)
|
|
flag1 = true; }
|
|
function setAfterCur(text) { afterCur[i] = text; if (text)
|
|
flag2 = true; }
|
|
function setSelected(text) { selected[i] = text; if (text)
|
|
flag3 = true; }
|
|
for (var i = 0; i < selections.length; i++) {
|
|
beforeCur[i] = afterCur[i] = selected[i] = "";
|
|
var range = selections[i];
|
|
var left = range.head;
|
|
var right = range.anchor;
|
|
var rangeEmpty = range.empty();
|
|
if (!rangeEmpty && codemirror_1.cmpPos(left, right) > 0)
|
|
_a = [left, right], right = _a[0], left = _a[1];
|
|
else if (right === left) {
|
|
right = range.anchor = { ch: left.ch, line: left.line };
|
|
}
|
|
var eolState = cm.getStateAfter(left.line);
|
|
var line = cm.getLine(left.line);
|
|
if (eolState.hmdTable) {
|
|
// yeah, we are inside a table
|
|
flag0 = true; // cursor will move
|
|
var isNormalTable = eolState.hmdTable === 2 /* NORMAL */;
|
|
var columns = eolState.hmdTableColumns;
|
|
tokenSeeker.setPos(left.line, left.ch);
|
|
var nextCellLeft = tokenSeeker.findNext(isRealTableSep, tokenSeeker.i_token);
|
|
if (!nextCellLeft) { // already last cell
|
|
var lineSpan = eolState.hmdTableRow === 0 ? 2 : 1; // skip |---|---| line
|
|
if ((left.line + lineSpan) > cm.lastLine() || cm.getStateAfter(left.line + lineSpan).hmdTable != eolState.hmdTable) {
|
|
// insert a row after this line
|
|
left.ch = right.ch = line.length;
|
|
var newline_2 = core_1.repeatStr(" | ", columns.length - 1);
|
|
// There are always nut users!
|
|
if (eolState.hmdTableRow === 0) {
|
|
right.line = left.line += 1;
|
|
right.ch = left.ch = cm.getLine(left.line).length;
|
|
}
|
|
if (isNormalTable) {
|
|
setBeforeCur("\n| ");
|
|
setAfterCur(newline_2 + " |");
|
|
}
|
|
else {
|
|
setBeforeCur("\n");
|
|
setAfterCur(newline_2.trimRight());
|
|
}
|
|
setSelected("");
|
|
}
|
|
else {
|
|
// move cursor to next line, first cell
|
|
right.line = left.line += lineSpan;
|
|
tokenSeeker.setPos(left.line, 0);
|
|
var line_1 = tokenSeeker.line.text;
|
|
var dummySep = isNormalTable && tokenSeeker.findNext(/hmd-table-sep-dummy/, 0);
|
|
var nextCellRight = tokenSeeker.findNext(/hmd-table-sep/, dummySep ? dummySep.i_token + 1 : 1);
|
|
left.ch = dummySep ? dummySep.token.end : 0;
|
|
right.ch = nextCellRight ? nextCellRight.token.start : line_1.length;
|
|
if (right.ch > left.ch && line_1.charAt(left.ch) === " ")
|
|
left.ch++;
|
|
if (right.ch > left.ch && line_1.charAt(right.ch - 1) === " ")
|
|
right.ch--;
|
|
setSelected(right.ch > left.ch ? cm.getRange(left, right) : "");
|
|
}
|
|
}
|
|
else {
|
|
var nextCellRight = tokenSeeker.findNext(/hmd-table-sep/, nextCellLeft.i_token + 1);
|
|
left.ch = nextCellLeft.token.end;
|
|
right.ch = nextCellRight ? nextCellRight.token.start : line.length;
|
|
if (right.ch > left.ch && line.charAt(left.ch) === " ")
|
|
left.ch++;
|
|
if (right.ch > left.ch && line.charAt(right.ch - 1) === " ")
|
|
right.ch--;
|
|
setSelected(right.ch > left.ch ? cm.getRange(left, right) : "");
|
|
}
|
|
// console.log("selected cell", left.ch, right.ch, selected[i])
|
|
}
|
|
else if (eolState.listStack.length > 0) {
|
|
// add indent to current line
|
|
var lineNo = left.line;
|
|
var tmp = void 0; // [" * ", " ", "* "]
|
|
while (!(tmp = ListRE.exec(cm.getLine(lineNo)))) { // beginning line has no bullet? go up
|
|
lineNo--;
|
|
var isList = cm.getStateAfter(lineNo).listStack.length > 0;
|
|
if (!isList) {
|
|
lineNo++;
|
|
break;
|
|
}
|
|
}
|
|
var firstLine = cm.firstLine();
|
|
var lastLine = cm.lastLine();
|
|
for (; lineNo <= right.line && (tmp = ListRE.exec(cm.getLine(lineNo))); lineNo++) {
|
|
var eolState_1 = cm.getStateAfter(lineNo);
|
|
var listStack = eolState_1.listStack;
|
|
var listStackOfPrevLine = cm.getStateAfter(lineNo - 1).listStack;
|
|
var listLevel = listStack.length;
|
|
var spaces = "";
|
|
// avoid uncontinuous list levels
|
|
if (lineNo > firstLine && listLevel <= listStackOfPrevLine.length) {
|
|
if (listLevel == listStackOfPrevLine.length) {
|
|
// tmp[1] is existed leading spaces
|
|
// listStackOfPrevLine[listLevel-1] is desired indentation
|
|
spaces = core_1.repeatStr(" ", listStackOfPrevLine[listLevel - 1] - tmp[1].length);
|
|
}
|
|
else {
|
|
// make bullets right-aligned
|
|
// tmp[0].length is end pos of current bullet
|
|
spaces = core_1.repeatStr(" ", listStackOfPrevLine[listLevel] - tmp[0].length);
|
|
}
|
|
}
|
|
addIndentTo[lineNo] = spaces;
|
|
// if current list item is multi-line...
|
|
while (++lineNo <= lastLine) {
|
|
if ( /*corrupted */cm.getStateAfter(lineNo).listStack.length !== listLevel) {
|
|
lineNo = Infinity;
|
|
break;
|
|
}
|
|
if ( /*has bullet*/ListRE.test(cm.getLine(lineNo))) {
|
|
lineNo--;
|
|
break;
|
|
}
|
|
addIndentTo[lineNo] = spaces;
|
|
}
|
|
}
|
|
if (!rangeEmpty) {
|
|
flag3 = false;
|
|
break; // f**k
|
|
}
|
|
}
|
|
else {
|
|
// emulate Tab
|
|
if (rangeEmpty) {
|
|
setBeforeCur(" ");
|
|
}
|
|
else {
|
|
setSelected(cm.getRange(left, right));
|
|
for (var lineNo = left.line; lineNo <= right.line; lineNo++) {
|
|
if (!(lineNo in addIndentTo))
|
|
addIndentTo[lineNo] = " ";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// if (!(flag0 || flag1 || flag2 || flag3)) return cm.execCommand("defaultTab")
|
|
// console.log(flag0, flag1, flag2, flag3)
|
|
for (var lineNo in addIndentTo) {
|
|
if (addIndentTo[lineNo])
|
|
cm.replaceRange(addIndentTo[lineNo], { line: ~~lineNo, ch: 0 });
|
|
}
|
|
if (flag0)
|
|
cm.setSelections(selections);
|
|
if (flag1)
|
|
cm.replaceSelections(beforeCur);
|
|
if (flag2)
|
|
cm.replaceSelections(afterCur, "start");
|
|
if (flag3)
|
|
cm.replaceSelections(selected, "around");
|
|
}
|
|
exports.tab = tab;
|
|
/**
|
|
* add / delete bracket pair to every selections,
|
|
* or just add left bracket to cursor if nothing selected.
|
|
*
|
|
* This provides a `createStyleToggler`-like feature,
|
|
* but don't rely on HyperMD mode
|
|
*
|
|
* @example
|
|
* When brackets are "(" and ")" :
|
|
* (Hello) => Hello (Selected "(Hello)" or just "Hello")
|
|
* Hello => (Hello)
|
|
*
|
|
* @param rightBracket if null, will use leftBracket
|
|
*/
|
|
function wrapTexts(cm, leftBracket, rightBracket) {
|
|
var _a;
|
|
if (cm.getOption("disableInput"))
|
|
return CodeMirror.Pass;
|
|
var selections = cm.listSelections();
|
|
var replacements = new Array(selections.length);
|
|
var insertBeforeCursor = new Array(selections.length);
|
|
var flag0 = false; // replacements changed
|
|
var flag1 = false; // insertBeforeCursor changed
|
|
var flag2 = false; // selections changed
|
|
if (!rightBracket)
|
|
rightBracket = leftBracket;
|
|
var lb_len = leftBracket.length;
|
|
var rb_len = rightBracket.length;
|
|
for (var i = 0; i < selections.length; i++) {
|
|
replacements[i] = insertBeforeCursor[i] = "";
|
|
var range = selections[i];
|
|
var left = range.head;
|
|
var right = range.anchor;
|
|
var line = cm.getLine(left.line);
|
|
if (range.empty()) {
|
|
if (left.ch >= lb_len && line.substr(left.ch - lb_len, lb_len) === leftBracket) {
|
|
// wipe out the left bracket
|
|
flag2 = true;
|
|
left.ch -= lb_len;
|
|
}
|
|
else {
|
|
// insert left bracket
|
|
flag1 = true;
|
|
insertBeforeCursor[i] = leftBracket;
|
|
}
|
|
continue;
|
|
}
|
|
flag0 = true;
|
|
var headAfterAnchor = codemirror_1.cmpPos(left, right) > 0;
|
|
if (headAfterAnchor)
|
|
_a = [left, right], right = _a[0], left = _a[1];
|
|
var text = cm.getRange(left, right);
|
|
if (left.ch >= lb_len && left.line === right.line) {
|
|
if (line.substr(left.ch - lb_len, lb_len) === leftBracket && line.substr(right.ch, rb_len) === rightBracket) {
|
|
flag2 = true;
|
|
right.ch += rb_len;
|
|
left.ch -= lb_len;
|
|
text = leftBracket + text + rightBracket;
|
|
}
|
|
}
|
|
if (text.slice(0, lb_len) === leftBracket && text.slice(-rb_len) === rightBracket) {
|
|
replacements[i] = text.slice(lb_len, -rb_len);
|
|
}
|
|
else {
|
|
replacements[i] = leftBracket + text + rightBracket;
|
|
}
|
|
}
|
|
if (flag2)
|
|
cm.setSelections(selections);
|
|
if (flag1)
|
|
cm.replaceSelections(insertBeforeCursor);
|
|
if (flag0)
|
|
cm.replaceSelections(replacements, "around");
|
|
}
|
|
exports.wrapTexts = wrapTexts;
|
|
function createStyleToggler(isStyled, isFormattingToken, getFormattingText) {
|
|
return function (cm) {
|
|
var _a;
|
|
if (cm.getOption("disableInput"))
|
|
return CodeMirror.Pass;
|
|
var ts = new core_1.TokenSeeker(cm);
|
|
var selections = cm.listSelections();
|
|
var replacements = new Array(selections.length);
|
|
for (var i = 0; i < selections.length; i++) {
|
|
var range = selections[i];
|
|
var left = range.head;
|
|
var right = range.anchor;
|
|
var eolState = cm.getStateAfter(left.line);
|
|
var rangeEmpty = range.empty();
|
|
if (codemirror_1.cmpPos(left, right) > 0)
|
|
_a = [left, right], right = _a[0], left = _a[1];
|
|
var rangeText = replacements[i] = rangeEmpty ? "" : cm.getRange(left, right);
|
|
if (rangeEmpty || isStyled(cm.getTokenAt(left).state)) { // nothing selected
|
|
var line = left.line;
|
|
ts.setPos(line, left.ch, true);
|
|
var token_1 = ts.lineTokens[ts.i_token];
|
|
var state_1 = token_1 ? token_1.state : eolState;
|
|
if (!token_1 || /^\s*$/.test(token_1.string)) {
|
|
token_1 = ts.lineTokens[--ts.i_token]; // maybe eol, or current token is space
|
|
}
|
|
var _b = ts.expandRange(function (token) { return token && (isStyled(token.state) || isFormattingToken(token)); }), from = _b.from, to = _b.to;
|
|
if (to.i_token === from.i_token) { // current token "word" is not formatted
|
|
var f = getFormattingText();
|
|
if (token_1 && !/^\s*$/.test(token_1.string)) { // not empty line, not spaces
|
|
var pos1 = { line: line, ch: token_1.start }, pos2 = { line: line, ch: token_1.end };
|
|
token_1 = from.token;
|
|
cm.replaceRange(f + token_1.string + f, pos1, pos2);
|
|
pos2.ch += f.length;
|
|
cm.setCursor(pos2);
|
|
return;
|
|
}
|
|
else {
|
|
replacements[i] = f;
|
|
}
|
|
}
|
|
else { // **wor|d** **|** **word| **|
|
|
if (isFormattingToken(to.token)) {
|
|
cm.replaceRange("", { line: line, ch: to.token.start }, { line: line, ch: to.token.end });
|
|
}
|
|
if (from.i_token !== to.i_token && isFormattingToken(from.token)) {
|
|
cm.replaceRange("", { line: line, ch: from.token.start }, { line: line, ch: from.token.end });
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
var token = cm.getTokenAt(left);
|
|
var state = token ? token.state : eolState;
|
|
var formatter = getFormattingText(state);
|
|
replacements[i] = formatter + rangeText + formatter;
|
|
}
|
|
cm.replaceSelections(replacements);
|
|
};
|
|
}
|
|
exports.createStyleToggler = createStyleToggler;
|
|
// Auto-updating Markdown list numbers when a new item is added to the
|
|
// middle of a list
|
|
function incrementRemainingMarkdownListNumbers(cm, pos) {
|
|
var listRE = LoQRE;
|
|
var startLine = pos.line, lookAhead = 0, skipCount = 0;
|
|
var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1];
|
|
do {
|
|
lookAhead += 1;
|
|
var nextLineNumber = startLine + lookAhead;
|
|
var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine);
|
|
if (nextItem) {
|
|
var nextIndent = nextItem[1];
|
|
var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount);
|
|
var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber;
|
|
if (startIndent === nextIndent && !isNaN(nextNumber)) {
|
|
if (newNumber === nextNumber)
|
|
itemNumber = nextNumber + 1;
|
|
if (newNumber > nextNumber)
|
|
itemNumber = newNumber + 1;
|
|
cm.replaceRange(nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), {
|
|
line: nextLineNumber, ch: 0
|
|
}, {
|
|
line: nextLineNumber, ch: nextLine.length
|
|
});
|
|
}
|
|
else {
|
|
if (startIndent.length > nextIndent.length)
|
|
return;
|
|
// This doesn't run if the next line immediatley indents, as it is
|
|
// not clear of the users intention (new indented item or same level)
|
|
if ((startIndent.length < nextIndent.length) && (lookAhead === 1))
|
|
return;
|
|
skipCount += 1;
|
|
}
|
|
}
|
|
} while (nextItem);
|
|
}
|
|
Object.assign(CodeMirror.commands, {
|
|
hmdNewlineAndContinue: newlineAndContinue,
|
|
hmdNewline: newline,
|
|
hmdShiftTab: shiftTab,
|
|
hmdTab: tab,
|
|
});
|
|
var defaultKeyMap = CodeMirror.keyMap["default"];
|
|
var modPrefix = defaultKeyMap === CodeMirror.keyMap["macDefault"] ? "Cmd" : "Ctrl";
|
|
exports.keyMap = (_a = {
|
|
"Shift-Tab": "hmdShiftTab",
|
|
"Tab": "hmdTab",
|
|
"Enter": "hmdNewlineAndContinue",
|
|
"Shift-Enter": "hmdNewline"
|
|
},
|
|
_a[modPrefix + "-K"] = createStyleToggler(function (state) { return state.strong; }, function (token) { return / formatting-strong /.test(token.type); }, function (state) { return core_1.repeatStr(state && state.strong || "*", 2); } // ** or __
|
|
),
|
|
_a[modPrefix + "-B"] = createStyleToggler(function (state) { return state.strong; }, function (token) { return / formatting-strong /.test(token.type); }, function (state) { return core_1.repeatStr(state && state.strong || "*", 2); } // ** or __
|
|
),
|
|
_a[modPrefix + "-I"] = createStyleToggler(function (state) { return state.em; }, function (token) { return / formatting-em /.test(token.type); }, function (state) { return (state && state.em || "*"); }),
|
|
_a[modPrefix + "-D"] = createStyleToggler(function (state) { return state.strikethrough; }, function (token) { return / formatting-strikethrough /.test(token.type); }, function (state) { return "~~"; }),
|
|
_a.fallthrough = "default",
|
|
_a);
|
|
exports.keyMap = CodeMirror.normalizeKeyMap(exports.keyMap);
|
|
CodeMirror.keyMap["hypermd"] = exports.keyMap;
|
|
core_1.suggestedEditorConfig.keyMap = "hypermd";
|
|
}); |