sublime.js (25463B)
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: https://codemirror.net/LICENSE 3 4 // A rough approximation of Sublime Text's keybindings 5 // Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js 6 7 (function(mod) { 8 if (typeof exports == "object" && typeof module == "object") // CommonJS 9 mod(require("resource://devtools/client/shared/sourceeditor/codemirror/lib/codemirror.js"), require("resource://devtools/client/shared/sourceeditor/codemirror/addon/search/searchcursor.js"), require("resource://devtools/client/shared/sourceeditor/codemirror/addon/edit/matchbrackets.js")); 10 else if (typeof define == "function" && define.amd) // AMD 11 define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod); 12 else // Plain browser env 13 mod(CodeMirror); 14 })(function(CodeMirror) { 15 "use strict"; 16 17 var cmds = CodeMirror.commands; 18 var Pos = CodeMirror.Pos; 19 20 // This is not exactly Sublime's algorithm. I couldn't make heads or tails of that. 21 function findPosSubword(doc, start, dir) { 22 if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1)); 23 var line = doc.getLine(start.line); 24 if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0)); 25 var state = "start", type; 26 for (var pos = start.ch, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) { 27 var next = line.charAt(dir < 0 ? pos - 1 : pos); 28 var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o"; 29 if (cat == "w" && next.toUpperCase() == next) cat = "W"; 30 if (state == "start") { 31 if (cat != "o") { state = "in"; type = cat; } 32 } else if (state == "in") { 33 if (type != cat) { 34 if (type == "w" && cat == "W" && dir < 0) pos--; 35 if (type == "W" && cat == "w" && dir > 0) { type = "w"; continue; } 36 break; 37 } 38 } 39 } 40 return Pos(start.line, pos); 41 } 42 43 function moveSubword(cm, dir) { 44 cm.extendSelectionsBy(function(range) { 45 if (cm.display.shift || cm.doc.extend || range.empty()) 46 return findPosSubword(cm.doc, range.head, dir); 47 else 48 return dir < 0 ? range.from() : range.to(); 49 }); 50 } 51 52 cmds.goSubwordLeft = function(cm) { moveSubword(cm, -1); }; 53 cmds.goSubwordRight = function(cm) { moveSubword(cm, 1); }; 54 55 cmds.scrollLineUp = function(cm) { 56 var info = cm.getScrollInfo(); 57 if (!cm.somethingSelected()) { 58 var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local"); 59 if (cm.getCursor().line >= visibleBottomLine) 60 cm.execCommand("goLineUp"); 61 } 62 cm.scrollTo(null, info.top - cm.defaultTextHeight()); 63 }; 64 cmds.scrollLineDown = function(cm) { 65 var info = cm.getScrollInfo(); 66 if (!cm.somethingSelected()) { 67 var visibleTopLine = cm.lineAtHeight(info.top, "local")+1; 68 if (cm.getCursor().line <= visibleTopLine) 69 cm.execCommand("goLineDown"); 70 } 71 cm.scrollTo(null, info.top + cm.defaultTextHeight()); 72 }; 73 74 cmds.splitSelectionByLine = function(cm) { 75 var ranges = cm.listSelections(), lineRanges = []; 76 for (var i = 0; i < ranges.length; i++) { 77 var from = ranges[i].from(), to = ranges[i].to(); 78 for (var line = from.line; line <= to.line; ++line) 79 if (!(to.line > from.line && line == to.line && to.ch == 0)) 80 lineRanges.push({anchor: line == from.line ? from : Pos(line, 0), 81 head: line == to.line ? to : Pos(line)}); 82 } 83 cm.setSelections(lineRanges, 0); 84 }; 85 86 cmds.singleSelectionTop = function(cm) { 87 var range = cm.listSelections()[0]; 88 cm.setSelection(range.anchor, range.head, {scroll: false}); 89 }; 90 91 cmds.selectLine = function(cm) { 92 var ranges = cm.listSelections(), extended = []; 93 for (var i = 0; i < ranges.length; i++) { 94 var range = ranges[i]; 95 extended.push({anchor: Pos(range.from().line, 0), 96 head: Pos(range.to().line + 1, 0)}); 97 } 98 cm.setSelections(extended); 99 }; 100 101 function insertLine(cm, above) { 102 if (cm.isReadOnly()) return CodeMirror.Pass 103 cm.operation(function() { 104 var len = cm.listSelections().length, newSelection = [], last = -1; 105 for (var i = 0; i < len; i++) { 106 var head = cm.listSelections()[i].head; 107 if (head.line <= last) continue; 108 var at = Pos(head.line + (above ? 0 : 1), 0); 109 cm.replaceRange("\n", at, null, "+insertLine"); 110 cm.indentLine(at.line, null, true); 111 newSelection.push({head: at, anchor: at}); 112 last = head.line + 1; 113 } 114 cm.setSelections(newSelection); 115 }); 116 cm.execCommand("indentAuto"); 117 } 118 119 cmds.insertLineAfter = function(cm) { return insertLine(cm, false); }; 120 121 cmds.insertLineBefore = function(cm) { return insertLine(cm, true); }; 122 123 function wordAt(cm, pos) { 124 var start = pos.ch, end = start, line = cm.getLine(pos.line); 125 while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start; 126 while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end; 127 return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)}; 128 } 129 130 cmds.selectNextOccurrence = function(cm) { 131 var from = cm.getCursor("from"), to = cm.getCursor("to"); 132 var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel; 133 if (CodeMirror.cmpPos(from, to) == 0) { 134 var word = wordAt(cm, from); 135 if (!word.word) return; 136 cm.setSelection(word.from, word.to); 137 fullWord = true; 138 } else { 139 var text = cm.getRange(from, to); 140 var query = fullWord ? new RegExp("\\b" + text + "\\b") : text; 141 var cur = cm.getSearchCursor(query, to); 142 var found = cur.findNext(); 143 if (!found) { 144 cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0)); 145 found = cur.findNext(); 146 } 147 if (!found || isSelectedRange(cm.listSelections(), cur.from(), cur.to())) 148 return CodeMirror.Pass 149 cm.addSelection(cur.from(), cur.to()); 150 } 151 if (fullWord) 152 cm.state.sublimeFindFullWord = cm.doc.sel; 153 }; 154 155 function addCursorToSelection(cm, dir) { 156 var ranges = cm.listSelections(), newRanges = []; 157 for (var i = 0; i < ranges.length; i++) { 158 var range = ranges[i]; 159 var newAnchor = cm.findPosV( 160 range.anchor, dir, "line", range.anchor.goalColumn); 161 var newHead = cm.findPosV( 162 range.head, dir, "line", range.head.goalColumn); 163 newAnchor.goalColumn = range.anchor.goalColumn != null ? 164 range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left; 165 newHead.goalColumn = range.head.goalColumn != null ? 166 range.head.goalColumn : cm.cursorCoords(range.head, "div").left; 167 var newRange = {anchor: newAnchor, head: newHead}; 168 newRanges.push(range); 169 newRanges.push(newRange); 170 } 171 cm.setSelections(newRanges); 172 } 173 cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); }; 174 cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); }; 175 176 function isSelectedRange(ranges, from, to) { 177 for (var i = 0; i < ranges.length; i++) 178 if (ranges[i].from() == from && ranges[i].to() == to) return true 179 return false 180 } 181 182 var mirror = "(){}[]"; 183 function selectBetweenBrackets(cm) { 184 var ranges = cm.listSelections(), newRanges = [] 185 for (var i = 0; i < ranges.length; i++) { 186 var range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1); 187 if (!opening) return false; 188 for (;;) { 189 var closing = cm.scanForBracket(pos, 1); 190 if (!closing) return false; 191 if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { 192 var startPos = Pos(opening.pos.line, opening.pos.ch + 1); 193 if (CodeMirror.cmpPos(startPos, range.from()) == 0 && 194 CodeMirror.cmpPos(closing.pos, range.to()) == 0) { 195 opening = cm.scanForBracket(opening.pos, -1); 196 if (!opening) return false; 197 } else { 198 newRanges.push({anchor: startPos, head: closing.pos}); 199 break; 200 } 201 } 202 pos = Pos(closing.pos.line, closing.pos.ch + 1); 203 } 204 } 205 cm.setSelections(newRanges); 206 return true; 207 } 208 209 cmds.selectScope = function(cm) { 210 selectBetweenBrackets(cm) || cm.execCommand("selectAll"); 211 }; 212 cmds.selectBetweenBrackets = function(cm) { 213 if (!selectBetweenBrackets(cm)) return CodeMirror.Pass; 214 }; 215 216 cmds.goToBracket = function(cm) { 217 cm.extendSelectionsBy(function(range) { 218 var next = cm.scanForBracket(range.head, 1); 219 if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos; 220 var prev = cm.scanForBracket(range.head, -1); 221 return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head; 222 }); 223 }; 224 225 cmds.swapLineUp = function(cm) { 226 if (cm.isReadOnly()) return CodeMirror.Pass 227 var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = []; 228 for (var i = 0; i < ranges.length; i++) { 229 var range = ranges[i], from = range.from().line - 1, to = range.to().line; 230 newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch), 231 head: Pos(range.head.line - 1, range.head.ch)}); 232 if (range.to().ch == 0 && !range.empty()) --to; 233 if (from > at) linesToMove.push(from, to); 234 else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; 235 at = to; 236 } 237 cm.operation(function() { 238 for (var i = 0; i < linesToMove.length; i += 2) { 239 var from = linesToMove[i], to = linesToMove[i + 1]; 240 var line = cm.getLine(from); 241 cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); 242 if (to > cm.lastLine()) 243 cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine"); 244 else 245 cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); 246 } 247 cm.setSelections(newSels); 248 cm.scrollIntoView(); 249 }); 250 }; 251 252 cmds.swapLineDown = function(cm) { 253 if (cm.isReadOnly()) return CodeMirror.Pass 254 var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1; 255 for (var i = ranges.length - 1; i >= 0; i--) { 256 var range = ranges[i], from = range.to().line + 1, to = range.from().line; 257 if (range.to().ch == 0 && !range.empty()) from--; 258 if (from < at) linesToMove.push(from, to); 259 else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; 260 at = to; 261 } 262 cm.operation(function() { 263 for (var i = linesToMove.length - 2; i >= 0; i -= 2) { 264 var from = linesToMove[i], to = linesToMove[i + 1]; 265 var line = cm.getLine(from); 266 if (from == cm.lastLine()) 267 cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine"); 268 else 269 cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); 270 cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); 271 } 272 cm.scrollIntoView(); 273 }); 274 }; 275 276 cmds.toggleCommentIndented = function(cm) { 277 cm.toggleComment({ indent: true }); 278 } 279 280 cmds.joinLines = function(cm) { 281 var ranges = cm.listSelections(), joined = []; 282 for (var i = 0; i < ranges.length; i++) { 283 var range = ranges[i], from = range.from(); 284 var start = from.line, end = range.to().line; 285 while (i < ranges.length - 1 && ranges[i + 1].from().line == end) 286 end = ranges[++i].to().line; 287 joined.push({start: start, end: end, anchor: !range.empty() && from}); 288 } 289 cm.operation(function() { 290 var offset = 0, ranges = []; 291 for (var i = 0; i < joined.length; i++) { 292 var obj = joined[i]; 293 var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head; 294 for (var line = obj.start; line <= obj.end; line++) { 295 var actual = line - offset; 296 if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1); 297 if (actual < cm.lastLine()) { 298 cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length)); 299 ++offset; 300 } 301 } 302 ranges.push({anchor: anchor || head, head: head}); 303 } 304 cm.setSelections(ranges, 0); 305 }); 306 }; 307 308 cmds.duplicateLine = function(cm) { 309 cm.operation(function() { 310 var rangeCount = cm.listSelections().length; 311 for (var i = 0; i < rangeCount; i++) { 312 var range = cm.listSelections()[i]; 313 if (range.empty()) 314 cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0)); 315 else 316 cm.replaceRange(cm.getRange(range.from(), range.to()), range.from()); 317 } 318 cm.scrollIntoView(); 319 }); 320 }; 321 322 323 function sortLines(cm, caseSensitive) { 324 if (cm.isReadOnly()) return CodeMirror.Pass 325 var ranges = cm.listSelections(), toSort = [], selected; 326 for (var i = 0; i < ranges.length; i++) { 327 var range = ranges[i]; 328 if (range.empty()) continue; 329 var from = range.from().line, to = range.to().line; 330 while (i < ranges.length - 1 && ranges[i + 1].from().line == to) 331 to = ranges[++i].to().line; 332 if (!ranges[i].to().ch) to--; 333 toSort.push(from, to); 334 } 335 if (toSort.length) selected = true; 336 else toSort.push(cm.firstLine(), cm.lastLine()); 337 338 cm.operation(function() { 339 var ranges = []; 340 for (var i = 0; i < toSort.length; i += 2) { 341 var from = toSort[i], to = toSort[i + 1]; 342 var start = Pos(from, 0), end = Pos(to); 343 var lines = cm.getRange(start, end, false); 344 if (caseSensitive) 345 lines.sort(); 346 else 347 lines.sort(function(a, b) { 348 var au = a.toUpperCase(), bu = b.toUpperCase(); 349 if (au != bu) { a = au; b = bu; } 350 return a < b ? -1 : a == b ? 0 : 1; 351 }); 352 cm.replaceRange(lines, start, end); 353 if (selected) ranges.push({anchor: start, head: Pos(to + 1, 0)}); 354 } 355 if (selected) cm.setSelections(ranges, 0); 356 }); 357 } 358 359 cmds.sortLines = function(cm) { sortLines(cm, true); }; 360 cmds.sortLinesInsensitive = function(cm) { sortLines(cm, false); }; 361 362 cmds.nextBookmark = function(cm) { 363 var marks = cm.state.sublimeBookmarks; 364 if (marks) while (marks.length) { 365 var current = marks.shift(); 366 var found = current.find(); 367 if (found) { 368 marks.push(current); 369 return cm.setSelection(found.from, found.to); 370 } 371 } 372 }; 373 374 cmds.prevBookmark = function(cm) { 375 var marks = cm.state.sublimeBookmarks; 376 if (marks) while (marks.length) { 377 marks.unshift(marks.pop()); 378 var found = marks[marks.length - 1].find(); 379 if (!found) 380 marks.pop(); 381 else 382 return cm.setSelection(found.from, found.to); 383 } 384 }; 385 386 cmds.toggleBookmark = function(cm) { 387 var ranges = cm.listSelections(); 388 var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []); 389 for (var i = 0; i < ranges.length; i++) { 390 var from = ranges[i].from(), to = ranges[i].to(); 391 var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to); 392 for (var j = 0; j < found.length; j++) { 393 if (found[j].sublimeBookmark) { 394 found[j].clear(); 395 for (var k = 0; k < marks.length; k++) 396 if (marks[k] == found[j]) 397 marks.splice(k--, 1); 398 break; 399 } 400 } 401 if (j == found.length) 402 marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false})); 403 } 404 }; 405 406 cmds.clearBookmarks = function(cm) { 407 var marks = cm.state.sublimeBookmarks; 408 if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear(); 409 marks.length = 0; 410 }; 411 412 cmds.selectBookmarks = function(cm) { 413 var marks = cm.state.sublimeBookmarks, ranges = []; 414 if (marks) for (var i = 0; i < marks.length; i++) { 415 var found = marks[i].find(); 416 if (!found) 417 marks.splice(i--, 0); 418 else 419 ranges.push({anchor: found.from, head: found.to}); 420 } 421 if (ranges.length) 422 cm.setSelections(ranges, 0); 423 }; 424 425 function modifyWordOrSelection(cm, mod) { 426 cm.operation(function() { 427 var ranges = cm.listSelections(), indices = [], replacements = []; 428 for (var i = 0; i < ranges.length; i++) { 429 var range = ranges[i]; 430 if (range.empty()) { indices.push(i); replacements.push(""); } 431 else replacements.push(mod(cm.getRange(range.from(), range.to()))); 432 } 433 cm.replaceSelections(replacements, "around", "case"); 434 for (var i = indices.length - 1, at; i >= 0; i--) { 435 var range = ranges[indices[i]]; 436 if (at && CodeMirror.cmpPos(range.head, at) > 0) continue; 437 var word = wordAt(cm, range.head); 438 at = word.from; 439 cm.replaceRange(mod(word.word), word.from, word.to); 440 } 441 }); 442 } 443 444 cmds.smartBackspace = function(cm) { 445 if (cm.somethingSelected()) return CodeMirror.Pass; 446 447 cm.operation(function() { 448 var cursors = cm.listSelections(); 449 var indentUnit = cm.getOption("indentUnit"); 450 451 for (var i = cursors.length - 1; i >= 0; i--) { 452 var cursor = cursors[i].head; 453 var toStartOfLine = cm.getRange({line: cursor.line, ch: 0}, cursor); 454 var column = CodeMirror.countColumn(toStartOfLine, null, cm.getOption("tabSize")); 455 456 // Delete by one character by default 457 var deletePos = cm.findPosH(cursor, -1, "char", false); 458 459 if (toStartOfLine && !/\S/.test(toStartOfLine) && column % indentUnit == 0) { 460 var prevIndent = new Pos(cursor.line, 461 CodeMirror.findColumn(toStartOfLine, column - indentUnit, indentUnit)); 462 463 // Smart delete only if we found a valid prevIndent location 464 if (prevIndent.ch != cursor.ch) deletePos = prevIndent; 465 } 466 467 cm.replaceRange("", deletePos, cursor, "+delete"); 468 } 469 }); 470 }; 471 472 cmds.delLineRight = function(cm) { 473 cm.operation(function() { 474 var ranges = cm.listSelections(); 475 for (var i = ranges.length - 1; i >= 0; i--) 476 cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete"); 477 cm.scrollIntoView(); 478 }); 479 }; 480 481 cmds.upcaseAtCursor = function(cm) { 482 modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); }); 483 }; 484 cmds.downcaseAtCursor = function(cm) { 485 modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); }); 486 }; 487 488 cmds.setSublimeMark = function(cm) { 489 if (cm.state.sublimeMark) cm.state.sublimeMark.clear(); 490 cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); 491 }; 492 cmds.selectToSublimeMark = function(cm) { 493 var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); 494 if (found) cm.setSelection(cm.getCursor(), found); 495 }; 496 cmds.deleteToSublimeMark = function(cm) { 497 var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); 498 if (found) { 499 var from = cm.getCursor(), to = found; 500 if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; } 501 cm.state.sublimeKilled = cm.getRange(from, to); 502 cm.replaceRange("", from, to); 503 } 504 }; 505 cmds.swapWithSublimeMark = function(cm) { 506 var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); 507 if (found) { 508 cm.state.sublimeMark.clear(); 509 cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); 510 cm.setCursor(found); 511 } 512 }; 513 cmds.sublimeYank = function(cm) { 514 if (cm.state.sublimeKilled != null) 515 cm.replaceSelection(cm.state.sublimeKilled, null, "paste"); 516 }; 517 518 cmds.showInCenter = function(cm) { 519 var pos = cm.cursorCoords(null, "local"); 520 cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2); 521 }; 522 523 function getTarget(cm) { 524 var from = cm.getCursor("from"), to = cm.getCursor("to"); 525 if (CodeMirror.cmpPos(from, to) == 0) { 526 var word = wordAt(cm, from); 527 if (!word.word) return; 528 from = word.from; 529 to = word.to; 530 } 531 return {from: from, to: to, query: cm.getRange(from, to), word: word}; 532 } 533 534 function findAndGoTo(cm, forward) { 535 var target = getTarget(cm); 536 if (!target) return; 537 var query = target.query; 538 var cur = cm.getSearchCursor(query, forward ? target.to : target.from); 539 540 if (forward ? cur.findNext() : cur.findPrevious()) { 541 cm.setSelection(cur.from(), cur.to()); 542 } else { 543 cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0) 544 : cm.clipPos(Pos(cm.lastLine()))); 545 if (forward ? cur.findNext() : cur.findPrevious()) 546 cm.setSelection(cur.from(), cur.to()); 547 else if (target.word) 548 cm.setSelection(target.from, target.to); 549 } 550 }; 551 cmds.findUnder = function(cm) { findAndGoTo(cm, true); }; 552 cmds.findUnderPrevious = function(cm) { findAndGoTo(cm,false); }; 553 cmds.findAllUnder = function(cm) { 554 var target = getTarget(cm); 555 if (!target) return; 556 var cur = cm.getSearchCursor(target.query); 557 var matches = []; 558 var primaryIndex = -1; 559 while (cur.findNext()) { 560 matches.push({anchor: cur.from(), head: cur.to()}); 561 if (cur.from().line <= target.from.line && cur.from().ch <= target.from.ch) 562 primaryIndex++; 563 } 564 cm.setSelections(matches, primaryIndex); 565 }; 566 567 568 var keyMap = CodeMirror.keyMap; 569 keyMap.macSublime = { 570 "Cmd-Left": "goLineStartSmart", 571 "Shift-Tab": "indentLess", 572 "Shift-Ctrl-K": "deleteLine", 573 "Alt-Q": "wrapLines", 574 "Ctrl-Left": "goSubwordLeft", 575 "Ctrl-Right": "goSubwordRight", 576 "Ctrl-Alt-Up": "scrollLineUp", 577 "Ctrl-Alt-Down": "scrollLineDown", 578 "Cmd-L": "selectLine", 579 "Shift-Cmd-L": "splitSelectionByLine", 580 "Esc": "singleSelectionTop", 581 "Cmd-Enter": "insertLineAfter", 582 "Shift-Cmd-Enter": "insertLineBefore", 583 "Cmd-D": "selectNextOccurrence", 584 "Shift-Cmd-Space": "selectScope", 585 "Shift-Cmd-M": "selectBetweenBrackets", 586 "Cmd-M": "goToBracket", 587 "Cmd-Ctrl-Up": "swapLineUp", 588 "Cmd-Ctrl-Down": "swapLineDown", 589 "Cmd-/": "toggleCommentIndented", 590 "Cmd-J": "joinLines", 591 "Shift-Cmd-D": "duplicateLine", 592 "F5": "sortLines", 593 "Cmd-F5": "sortLinesInsensitive", 594 "F2": "nextBookmark", 595 "Shift-F2": "prevBookmark", 596 "Cmd-F2": "toggleBookmark", 597 "Shift-Cmd-F2": "clearBookmarks", 598 "Alt-F2": "selectBookmarks", 599 "Backspace": "smartBackspace", 600 "Cmd-K Cmd-K": "delLineRight", 601 "Cmd-K Cmd-U": "upcaseAtCursor", 602 "Cmd-K Cmd-L": "downcaseAtCursor", 603 "Cmd-K Cmd-Space": "setSublimeMark", 604 "Cmd-K Cmd-A": "selectToSublimeMark", 605 "Cmd-K Cmd-W": "deleteToSublimeMark", 606 "Cmd-K Cmd-X": "swapWithSublimeMark", 607 "Cmd-K Cmd-Y": "sublimeYank", 608 "Cmd-K Cmd-C": "showInCenter", 609 "Cmd-K Cmd-G": "clearBookmarks", 610 "Cmd-K Cmd-Backspace": "delLineLeft", 611 "Cmd-K Cmd-0": "unfoldAll", 612 "Cmd-K Cmd-J": "unfoldAll", 613 "Ctrl-Shift-Up": "addCursorToPrevLine", 614 "Ctrl-Shift-Down": "addCursorToNextLine", 615 "Cmd-F3": "findUnder", 616 "Shift-Cmd-F3": "findUnderPrevious", 617 "Alt-F3": "findAllUnder", 618 "Shift-Cmd-[": "fold", 619 "Shift-Cmd-]": "unfold", 620 "Cmd-I": "findIncremental", 621 "Shift-Cmd-I": "findIncrementalReverse", 622 "Cmd-H": "replace", 623 "F3": "findNext", 624 "Shift-F3": "findPrev", 625 "fallthrough": "macDefault" 626 }; 627 CodeMirror.normalizeKeyMap(keyMap.macSublime); 628 629 keyMap.pcSublime = { 630 "Shift-Tab": "indentLess", 631 "Shift-Ctrl-K": "deleteLine", 632 "Alt-Q": "wrapLines", 633 "Ctrl-T": "transposeChars", 634 "Alt-Left": "goSubwordLeft", 635 "Alt-Right": "goSubwordRight", 636 "Ctrl-Up": "scrollLineUp", 637 "Ctrl-Down": "scrollLineDown", 638 "Ctrl-L": "selectLine", 639 "Shift-Ctrl-L": "splitSelectionByLine", 640 "Esc": "singleSelectionTop", 641 "Ctrl-Enter": "insertLineAfter", 642 "Shift-Ctrl-Enter": "insertLineBefore", 643 "Ctrl-D": "selectNextOccurrence", 644 "Shift-Ctrl-Space": "selectScope", 645 "Shift-Ctrl-M": "selectBetweenBrackets", 646 "Ctrl-M": "goToBracket", 647 "Shift-Ctrl-Up": "swapLineUp", 648 "Shift-Ctrl-Down": "swapLineDown", 649 "Ctrl-/": "toggleCommentIndented", 650 "Ctrl-J": "joinLines", 651 "Shift-Ctrl-D": "duplicateLine", 652 "F9": "sortLines", 653 "Ctrl-F9": "sortLinesInsensitive", 654 "F2": "nextBookmark", 655 "Shift-F2": "prevBookmark", 656 "Ctrl-F2": "toggleBookmark", 657 "Shift-Ctrl-F2": "clearBookmarks", 658 "Alt-F2": "selectBookmarks", 659 "Backspace": "smartBackspace", 660 "Ctrl-K Ctrl-K": "delLineRight", 661 "Ctrl-K Ctrl-U": "upcaseAtCursor", 662 "Ctrl-K Ctrl-L": "downcaseAtCursor", 663 "Ctrl-K Ctrl-Space": "setSublimeMark", 664 "Ctrl-K Ctrl-A": "selectToSublimeMark", 665 "Ctrl-K Ctrl-W": "deleteToSublimeMark", 666 "Ctrl-K Ctrl-X": "swapWithSublimeMark", 667 "Ctrl-K Ctrl-Y": "sublimeYank", 668 "Ctrl-K Ctrl-C": "showInCenter", 669 "Ctrl-K Ctrl-G": "clearBookmarks", 670 "Ctrl-K Ctrl-Backspace": "delLineLeft", 671 "Ctrl-K Ctrl-0": "unfoldAll", 672 "Ctrl-K Ctrl-J": "unfoldAll", 673 "Ctrl-Alt-Up": "addCursorToPrevLine", 674 "Ctrl-Alt-Down": "addCursorToNextLine", 675 "Ctrl-F3": "findUnder", 676 "Shift-Ctrl-F3": "findUnderPrevious", 677 "Alt-F3": "findAllUnder", 678 "Shift-Ctrl-[": "fold", 679 "Shift-Ctrl-]": "unfold", 680 "Ctrl-I": "findIncremental", 681 "Shift-Ctrl-I": "findIncrementalReverse", 682 "Ctrl-H": "replace", 683 "F3": "findNext", 684 "Shift-F3": "findPrev", 685 "fallthrough": "pcDefault" 686 }; 687 CodeMirror.normalizeKeyMap(keyMap.pcSublime); 688 689 var mac = keyMap.default == keyMap.macDefault; 690 keyMap.sublime = mac ? keyMap.macSublime : keyMap.pcSublime; 691 });