File modules/editor/codemirror/keymap/emacs.min.js
Last commit: Tue May 22 22:39:49 2018 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.
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 Pos = CodeMirror.Pos; 15 function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } 16 17 // Kill 'ring' 18 19 var killRing = []; 20 function addToRing(str) { 21 killRing.push(str); 22 if (killRing.length > 50) killRing.shift(); 23 } 24 function growRingTop(str) { 25 if (!killRing.length) return addToRing(str); 26 killRing[killRing.length - 1] += str; 27 } 28 function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; } 29 function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); } 30 31 var lastKill = null; 32 33 function kill(cm, from, to, ring, text) { 34 if (text == null) text = cm.getRange(from, to); 35 36 if (ring == "grow" && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen)) 37 growRingTop(text); 38 else if (ring !== false) 39 addToRing(text); 40 cm.replaceRange("", from, to, "+delete"); 41 42 if (ring == "grow") lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()}; 43 else lastKill = null; 44 } 45 46 // Boundaries of various units 47 48 function byChar(cm, pos, dir) { 49 return cm.findPosH(pos, dir, "char", true); 50 } 51 52 function byWord(cm, pos, dir) { 53 return cm.findPosH(pos, dir, "word", true); 54 } 55 56 function byLine(cm, pos, dir) { 57 return cm.findPosV(pos, dir, "line", cm.doc.sel.goalColumn); 58 } 59 60 function byPage(cm, pos, dir) { 61 return cm.findPosV(pos, dir, "page", cm.doc.sel.goalColumn); 62 } 63 64 function byParagraph(cm, pos, dir) { 65 var no = pos.line, line = cm.getLine(no); 66 var sawText = /\S/.test(dir < 0 ? line.slice(0, pos.ch) : line.slice(pos.ch)); 67 var fst = cm.firstLine(), lst = cm.lastLine(); 68 for (;;) { 69 no += dir; 70 if (no < fst || no > lst) 71 return cm.clipPos(Pos(no - dir, dir < 0 ? 0 : null)); 72 line = cm.getLine(no); 73 var hasText = /\S/.test(line); 74 if (hasText) sawText = true; 75 else if (sawText) return Pos(no, 0); 76 } 77 } 78 79 function bySentence(cm, pos, dir) { 80 var line = pos.line, ch = pos.ch; 81 var text = cm.getLine(pos.line), sawWord = false; 82 for (;;) { 83 var next = text.charAt(ch + (dir < 0 ? -1 : 0)); 84 if (!next) { // End/beginning of line reached 85 if (line == (dir < 0 ? cm.firstLine() : cm.lastLine())) return Pos(line, ch); 86 text = cm.getLine(line + dir); 87 if (!/\S/.test(text)) return Pos(line, ch); 88 line += dir; 89 ch = dir < 0 ? text.length : 0; 90 continue; 91 } 92 if (sawWord && /[!?.]/.test(next)) return Pos(line, ch + (dir > 0 ? 1 : 0)); 93 if (!sawWord) sawWord = /\w/.test(next); 94 ch += dir; 95 } 96 } 97 98 function byExpr(cm, pos, dir) { 99 var wrap; 100 if (cm.findMatchingBracket && (wrap = cm.findMatchingBracket(pos, {strict: true})) 101 && wrap.match && (wrap.forward ? 1 : -1) == dir) 102 return dir > 0 ? Pos(wrap.to.line, wrap.to.ch + 1) : wrap.to; 103 104 for (var first = true;; first = false) { 105 var token = cm.getTokenAt(pos); 106 var after = Pos(pos.line, dir < 0 ? token.start : token.end); 107 if (first && dir > 0 && token.end == pos.ch || !/\w/.test(token.string)) { 108 var newPos = cm.findPosH(after, dir, "char"); 109 if (posEq(after, newPos)) return pos; 110 else pos = newPos; 111 } else { 112 return after; 113 } 114 } 115 } 116 117 // Prefixes (only crudely supported) 118 119 function getPrefix(cm, precise) { 120 var digits = cm.state.emacsPrefix; 121 if (!digits) return precise ? null : 1; 122 clearPrefix(cm); 123 return digits == "-" ? -1 : Number(digits); 124 } 125 126 function repeated(cmd) { 127 var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd; 128 return function(cm) { 129 var prefix = getPrefix(cm); 130 f(cm); 131 for (var i = 1; i < prefix; ++i) f(cm); 132 }; 133 } 134 135 function findEnd(cm, pos, by, dir) { 136 var prefix = getPrefix(cm); 137 if (prefix < 0) { dir = -dir; prefix = -prefix; } 138 for (var i = 0; i < prefix; ++i) { 139 var newPos = by(cm, pos, dir); 140 if (posEq(newPos, pos)) break; 141 pos = newPos; 142 } 143 return pos; 144 } 145 146 function move(by, dir) { 147 var f = function(cm) { 148 cm.extendSelection(findEnd(cm, cm.getCursor(), by, dir)); 149 }; 150 f.motion = true; 151 return f; 152 } 153 154 function killTo(cm, by, dir, ring) { 155 var selections = cm.listSelections(), cursor; 156 var i = selections.length; 157 while (i--) { 158 cursor = selections[i].head; 159 kill(cm, cursor, findEnd(cm, cursor, by, dir), ring); 160 } 161 } 162 163 function killRegion(cm, ring) { 164 if (cm.somethingSelected()) { 165 var selections = cm.listSelections(), selection; 166 var i = selections.length; 167 while (i--) { 168 selection = selections[i]; 169 kill(cm, selection.anchor, selection.head, ring); 170 } 171 return true; 172 } 173 } 174 175 function addPrefix(cm, digit) { 176 if (cm.state.emacsPrefix) { 177 if (digit != "-") cm.state.emacsPrefix += digit; 178 return; 179 } 180 // Not active yet 181 cm.state.emacsPrefix = digit; 182 cm.on("keyHandled", maybeClearPrefix); 183 cm.on("inputRead", maybeDuplicateInput); 184 } 185 186 var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true}; 187 188 function maybeClearPrefix(cm, arg) { 189 if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg)) 190 clearPrefix(cm); 191 } 192 193 function clearPrefix(cm) { 194 cm.state.emacsPrefix = null; 195 cm.off("keyHandled", maybeClearPrefix); 196 cm.off("inputRead", maybeDuplicateInput); 197 } 198 199 function maybeDuplicateInput(cm, event) { 200 var dup = getPrefix(cm); 201 if (dup > 1 && event.origin == "+input") { 202 var one = event.text.join("\n"), txt = ""; 203 for (var i = 1; i < dup; ++i) txt += one; 204 cm.replaceSelection(txt); 205 } 206 } 207 208 function addPrefixMap(cm) { 209 cm.state.emacsPrefixMap = true; 210 cm.addKeyMap(prefixMap); 211 cm.on("keyHandled", maybeRemovePrefixMap); 212 cm.on("inputRead", maybeRemovePrefixMap); 213 } 214 215 function maybeRemovePrefixMap(cm, arg) { 216 if (typeof arg == "string" && (/^\d$/.test(arg) || arg == "Ctrl-U")) return; 217 cm.removeKeyMap(prefixMap); 218 cm.state.emacsPrefixMap = false; 219 cm.off("keyHandled", maybeRemovePrefixMap); 220 cm.off("inputRead", maybeRemovePrefixMap); 221 } 222 223 // Utilities 224 225 function setMark(cm) { 226 cm.setCursor(cm.getCursor()); 227 cm.setExtending(!cm.getExtending()); 228 cm.on("change", function() { cm.setExtending(false); }); 229 } 230 231 function clearMark(cm) { 232 cm.setExtending(false); 233 cm.setCursor(cm.getCursor()); 234 } 235 236 function getInput(cm, msg, f) { 237 if (cm.openDialog) 238 cm.openDialog(msg + ": <input type=\"text\" style=\"width: 10em\"/>", f, {bottom: true}); 239 else 240 f(prompt(msg, "")); 241 } 242 243 function operateOnWord(cm, op) { 244 var start = cm.getCursor(), end = cm.findPosH(start, 1, "word"); 245 cm.replaceRange(op(cm.getRange(start, end)), start, end); 246 cm.setCursor(end); 247 } 248 249 function toEnclosingExpr(cm) { 250 var pos = cm.getCursor(), line = pos.line, ch = pos.ch; 251 var stack = []; 252 while (line >= cm.firstLine()) { 253 var text = cm.getLine(line); 254 for (var i = ch == null ? text.length : ch; i > 0;) { 255 var ch = text.charAt(--i); 256 if (ch == ")") 257 stack.push("("); 258 else if (ch == "]") 259 stack.push("["); 260 else if (ch == "}") 261 stack.push("{"); 262 else if (/[\(\{\[]/.test(ch) && (!stack.length || stack.pop() != ch)) 263 return cm.extendSelection(Pos(line, i)); 264 } 265 --line; ch = null; 266 } 267 } 268 269 function quit(cm) { 270 cm.execCommand("clearSearch"); 271 clearMark(cm); 272 } 273 274 CodeMirror.emacs = {kill: kill, killRegion: killRegion, repeated: repeated}; 275 276 // Actual keymap 277 278 var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({ 279 "Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"), true);}, 280 "Ctrl-K": repeated(function(cm) { 281 var start = cm.getCursor(), end = cm.clipPos(Pos(start.line)); 282 var text = cm.getRange(start, end); 283 if (!/\S/.test(text)) { 284 text += "\n"; 285 end = Pos(start.line + 1, 0); 286 } 287 kill(cm, start, end, "grow", text); 288 }), 289 "Alt-W": function(cm) { 290 addToRing(cm.getSelection()); 291 clearMark(cm); 292 }, 293 "Ctrl-Y": function(cm) { 294 var start = cm.getCursor(); 295 cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste"); 296 cm.setSelection(start, cm.getCursor()); 297 }, 298 "Alt-Y": function(cm) {cm.replaceSelection(popFromRing(), "around", "paste");}, 299 300 "Ctrl-Space": setMark, "Ctrl-Shift-2": setMark, 301 302 "Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1), 303 "Right": move(byChar, 1), "Left": move(byChar, -1), 304 "Ctrl-D": function(cm) { killTo(cm, byChar, 1, false); }, 305 "Delete": function(cm) { killRegion(cm, false) || killTo(cm, byChar, 1, false); }, 306 "Ctrl-H": function(cm) { killTo(cm, byChar, -1, false); }, 307 "Backspace": function(cm) { killRegion(cm, false) || killTo(cm, byChar, -1, false); }, 308 309 "Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1), 310 "Alt-D": function(cm) { killTo(cm, byWord, 1, "grow"); }, 311 "Alt-Backspace": function(cm) { killTo(cm, byWord, -1, "grow"); }, 312 313 "Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1), 314 "Down": move(byLine, 1), "Up": move(byLine, -1), 315 "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", 316 "End": "goLineEnd", "Home": "goLineStart", 317 318 "Alt-V": move(byPage, -1), "Ctrl-V": move(byPage, 1), 319 "PageUp": move(byPage, -1), "PageDown": move(byPage, 1), 320 321 "Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1), 322 323 "Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1), 324 "Alt-K": function(cm) { killTo(cm, bySentence, 1, "grow"); }, 325 326 "Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1, "grow"); }, 327 "Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1, "grow"); }, 328 "Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1, "grow"), 329 330 "Shift-Ctrl-Alt-2": function(cm) { 331 var cursor = cm.getCursor(); 332 cm.setSelection(findEnd(cm, cursor, byExpr, 1), cursor); 333 }, 334 "Ctrl-Alt-T": function(cm) { 335 var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1); 336 var rightEnd = byExpr(cm, leftEnd, 1), rightStart = byExpr(cm, rightEnd, -1); 337 cm.replaceRange(cm.getRange(rightStart, rightEnd) + cm.getRange(leftEnd, rightStart) + 338 cm.getRange(leftStart, leftEnd), leftStart, rightEnd); 339 }, 340 "Ctrl-Alt-U": repeated(toEnclosingExpr), 341 342 "Alt-Space": function(cm) { 343 var pos = cm.getCursor(), from = pos.ch, to = pos.ch, text = cm.getLine(pos.line); 344 while (from && /\s/.test(text.charAt(from - 1))) --from; 345 while (to < text.length && /\s/.test(text.charAt(to))) ++to; 346 cm.replaceRange(" ", Pos(pos.line, from), Pos(pos.line, to)); 347 }, 348 "Ctrl-O": repeated(function(cm) { cm.replaceSelection("\n", "start"); }), 349 "Ctrl-T": repeated(function(cm) { 350 cm.execCommand("transposeChars"); 351 }), 352 353 "Alt-C": repeated(function(cm) { 354 operateOnWord(cm, function(w) { 355 var letter = w.search(/\w/); 356 if (letter == -1) return w; 357 return w.slice(0, letter) + w.charAt(letter).toUpperCase() + w.slice(letter + 1).toLowerCase(); 358 }); 359 }), 360 "Alt-U": repeated(function(cm) { 361 operateOnWord(cm, function(w) { return w.toUpperCase(); }); 362 }), 363 "Alt-L": repeated(function(cm) { 364 operateOnWord(cm, function(w) { return w.toLowerCase(); }); 365 }), 366 367 "Alt-;": "toggleComment", 368 369 "Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"), 370 "Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"), 371 "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd", 372 "Ctrl-S": "findPersistentNext", "Ctrl-R": "findPersistentPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace", 373 "Alt-/": "autocomplete", 374 "Enter": "newlineAndIndent", 375 "Ctrl-J": repeated(function(cm) { cm.replaceSelection("\n", "end"); }), 376 "Tab": "indentAuto", 377 378 "Alt-G G": function(cm) { 379 var prefix = getPrefix(cm, true); 380 if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1); 381 382 getInput(cm, "Goto line", function(str) { 383 var num; 384 if (str && !isNaN(num = Number(str)) && num == (num|0) && num > 0) 385 cm.setCursor(num - 1); 386 }); 387 }, 388 389 "Ctrl-X Tab": function(cm) { 390 cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit")); 391 }, 392 "Ctrl-X Ctrl-X": function(cm) { 393 cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor")); 394 }, 395 "Ctrl-X Ctrl-S": "save", 396 "Ctrl-X Ctrl-W": "save", 397 "Ctrl-X S": "saveAll", 398 "Ctrl-X F": "open", 399 "Ctrl-X U": repeated("undo"), 400 "Ctrl-X K": "close", 401 "Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), "grow"); }, 402 "Ctrl-X H": "selectAll", 403 404 "Ctrl-Q Tab": repeated("insertTab"), 405 "Ctrl-U": addPrefixMap 406 }); 407 408 var prefixMap = {"Ctrl-G": clearPrefix}; 409 function regPrefix(d) { 410 prefixMap[d] = function(cm) { addPrefix(cm, d); }; 411 keyMap["Ctrl-" + d] = function(cm) { addPrefix(cm, d); }; 412 prefixPreservingKeys["Ctrl-" + d] = true; 413 } 414 for (var i = 0; i < 10; ++i) regPrefix(String(i)); 415 regPrefix("-"); 416 });
Downloadmodules/editor/codemirror/keymap/emacs.min.js
History Tue, 22 May 2018 22:39:49 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.