// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE import CodeMirror from "codemirror/lib/codemirror"; (function (CodeMirror) { var defaults = { pairs: "()[]{}''\"\"", closeBefore: ")]}'\":;>", triples: "", explode: "[]{}", }; var Pos = CodeMirror.Pos; CodeMirror.defineOption("autoCloseBrackets", false, function ( cm, val, old ) { if (old && old != CodeMirror.Init) { cm.removeKeyMap(keyMap); cm.state.closeBrackets = null; } if (val) { ensureBound(getOption(val, "pairs")); cm.state.closeBrackets = val; cm.addKeyMap(keyMap); } }); function getOption(conf, name) { if (name == "pairs" && typeof conf == "string") return conf; if (typeof conf == "object" && conf[name] != null) return conf[name]; return defaults[name]; } var keyMap = { Backspace: handleBackspace, Enter: handleEnter, }; function ensureBound(chars) { for (var i = 0; i < chars.length; i++) { var ch = chars.charAt(i), key = "'" + ch + "'"; if (!keyMap[key]) keyMap[key] = handler(ch); } } ensureBound(defaults.pairs + "`"); function handler(ch) { return function (cm) { return handleChar(cm, ch); }; } function getConfig(cm) { var deflt = cm.state.closeBrackets; if (!deflt || deflt.override) return deflt; var mode = cm.getModeAt(cm.getCursor()); return mode.closeBrackets || deflt; } function handleBackspace(cm) { var conf = getConfig(cm); if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; var pairs = getOption(conf, "pairs"); var ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { if (!ranges[i].empty()) return CodeMirror.Pass; var around = charsAround(cm, ranges[i].head); if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; } for (var i = ranges.length - 1; i >= 0; i--) { var cur = ranges[i].head; cm.replaceRange( "", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete" ); } } function handleEnter(cm) { var conf = getConfig(cm); var explode = conf && getOption(conf, "explode"); if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; var ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { if (!ranges[i].empty()) return CodeMirror.Pass; var around = charsAround(cm, ranges[i].head); if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; } cm.operation(function () { var linesep = cm.lineSeparator() || "\n"; cm.replaceSelection(linesep + linesep, null); cm.execCommand("goCharLeft"); ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { var line = ranges[i].head.line; cm.indentLine(line, null, true); cm.indentLine(line + 1, null, true); } }); } function contractSelection(sel) { var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; return { anchor: new Pos( sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1) ), head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1)), }; } function handleChar(cm, ch) { var conf = getConfig(cm); if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; var pairs = getOption(conf, "pairs"); var pos = pairs.indexOf(ch); if (pos == -1) return CodeMirror.Pass; var closeBefore = getOption(conf, "closeBefore"); var triples = getOption(conf, "triples"); var identical = pairs.charAt(pos + 1) == ch; var ranges = cm.listSelections(); var opening = pos % 2 == 0; var type; for (var i = 0; i < ranges.length; i++) { var range = ranges[i], cur = range.head, curType; var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); if (opening && !range.empty()) { curType = "surround"; } else if ((identical || !opening) && next == ch) { if (identical && stringStartsAfter(cm, cur)) curType = "both"; else if ( triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch ) curType = "skipThree"; else curType = "skip"; } else if ( identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch ) { if ( cur.ch > 2 && /\bstring/.test( cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)) ) ) return CodeMirror.Pass; curType = "addFour"; } else if (identical) { var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur); if ( !CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev) ) curType = "both"; else return CodeMirror.Pass; } else if ( opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1) ) { curType = "both"; } else { return CodeMirror.Pass; } if (!type) type = curType; else if (type != curType) return CodeMirror.Pass; } var left = pos % 2 ? pairs.charAt(pos - 1) : ch; var right = pos % 2 ? ch : pairs.charAt(pos + 1); cm.operation(function () { if (type == "skip") { cm.execCommand("goCharRight"); } else if (type == "skipThree") { for (var i = 0; i < 3; i++) cm.execCommand("goCharRight"); } else if (type == "surround") { var sels = cm.getSelections(); for (var i = 0; i < sels.length; i++) sels[i] = left + sels[i] + right; cm.replaceSelections(sels, "around"); sels = cm.listSelections().slice(); for (var i = 0; i < sels.length; i++) sels[i] = contractSelection(sels[i]); cm.setSelections(sels); } else if (type == "both") { cm.replaceSelection(left + right, null); cm.triggerElectric(left + right); cm.execCommand("goCharLeft"); } else if (type == "addFour") { cm.replaceSelection(left + left + left + left, "before"); cm.execCommand("goCharRight"); } }); } function charsAround(cm, pos) { var str = cm.getRange( Pos(pos.line, pos.ch - 1), Pos(pos.line, pos.ch + 1) ); return str.length == 2 ? str : null; } function stringStartsAfter(cm, pos) { var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)); return ( /\bstring/.test(token.type) && token.start == pos.ch && (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) ); } })(CodeMirror);