1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/sourceeditor/codemirror/keymap/sublime.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,505 @@ 1.4 +// A rough approximation of Sublime Text's keybindings 1.5 +// Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js 1.6 + 1.7 +(function(mod) { 1.8 + if (typeof exports == "object" && typeof module == "object") // CommonJS 1.9 + mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/edit/matchbrackets")); 1.10 + else if (typeof define == "function" && define.amd) // AMD 1.11 + define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod); 1.12 + else // Plain browser env 1.13 + mod(CodeMirror); 1.14 +})(function(CodeMirror) { 1.15 + "use strict"; 1.16 + 1.17 + var map = CodeMirror.keyMap.sublime = {fallthrough: "default"}; 1.18 + var cmds = CodeMirror.commands; 1.19 + var Pos = CodeMirror.Pos; 1.20 + var ctrl = CodeMirror.keyMap["default"] == CodeMirror.keyMap.pcDefault ? "Ctrl-" : "Cmd-"; 1.21 + 1.22 + // This is not exactly Sublime's algorithm. I couldn't make heads or tails of that. 1.23 + function findPosSubword(doc, start, dir) { 1.24 + if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1)); 1.25 + var line = doc.getLine(start.line); 1.26 + if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0)); 1.27 + var state = "start", type; 1.28 + for (var pos = start.ch, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) { 1.29 + var next = line.charAt(dir < 0 ? pos - 1 : pos); 1.30 + var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o"; 1.31 + if (cat == "w" && next.toUpperCase() == next) cat = "W"; 1.32 + if (state == "start") { 1.33 + if (cat != "o") { state = "in"; type = cat; } 1.34 + } else if (state == "in") { 1.35 + if (type != cat) { 1.36 + if (type == "w" && cat == "W" && dir < 0) pos--; 1.37 + if (type == "W" && cat == "w" && dir > 0) { type = "w"; continue; } 1.38 + break; 1.39 + } 1.40 + } 1.41 + } 1.42 + return Pos(start.line, pos); 1.43 + } 1.44 + 1.45 + function moveSubword(cm, dir) { 1.46 + cm.extendSelectionsBy(function(range) { 1.47 + if (cm.display.shift || cm.doc.extend || range.empty()) 1.48 + return findPosSubword(cm.doc, range.head, dir); 1.49 + else 1.50 + return dir < 0 ? range.from() : range.to(); 1.51 + }); 1.52 + } 1.53 + 1.54 + cmds[map["Alt-Left"] = "goSubwordLeft"] = function(cm) { moveSubword(cm, -1); }; 1.55 + cmds[map["Alt-Right"] = "goSubwordRight"] = function(cm) { moveSubword(cm, 1); }; 1.56 + 1.57 + cmds[map[ctrl + "Up"] = "scrollLineUp"] = function(cm) { 1.58 + cm.scrollTo(null, cm.getScrollInfo().top - cm.defaultTextHeight()); 1.59 + }; 1.60 + cmds[map[ctrl + "Down"] = "scrollLineDown"] = function(cm) { 1.61 + cm.scrollTo(null, cm.getScrollInfo().top + cm.defaultTextHeight()); 1.62 + }; 1.63 + 1.64 + cmds[map["Shift-" + ctrl + "L"] = "splitSelectionByLine"] = function(cm) { 1.65 + var ranges = cm.listSelections(), lineRanges = []; 1.66 + for (var i = 0; i < ranges.length; i++) { 1.67 + var from = ranges[i].from(), to = ranges[i].to(); 1.68 + for (var line = from.line; line <= to.line; ++line) 1.69 + if (!(to.line > from.line && line == to.line && to.ch == 0)) 1.70 + lineRanges.push({anchor: line == from.line ? from : Pos(line, 0), 1.71 + head: line == to.line ? to : Pos(line)}); 1.72 + } 1.73 + cm.setSelections(lineRanges, 0); 1.74 + }; 1.75 + 1.76 + map["Shift-Tab"] = "indentLess"; 1.77 + 1.78 + cmds[map["Esc"] = "singleSelectionTop"] = function(cm) { 1.79 + var range = cm.listSelections()[0]; 1.80 + cm.setSelection(range.anchor, range.head, {scroll: false}); 1.81 + }; 1.82 + 1.83 + cmds[map[ctrl + "L"] = "selectLine"] = function(cm) { 1.84 + var ranges = cm.listSelections(), extended = []; 1.85 + for (var i = 0; i < ranges.length; i++) { 1.86 + var range = ranges[i]; 1.87 + extended.push({anchor: Pos(range.from().line, 0), 1.88 + head: Pos(range.to().line + 1, 0)}); 1.89 + } 1.90 + cm.setSelections(extended); 1.91 + }; 1.92 + 1.93 + map["Shift-" + ctrl + "K"] = "deleteLine"; 1.94 + 1.95 + function insertLine(cm, above) { 1.96 + cm.operation(function() { 1.97 + var len = cm.listSelections().length, newSelection = [], last = -1; 1.98 + for (var i = 0; i < len; i++) { 1.99 + var head = cm.listSelections()[i].head; 1.100 + if (head.line <= last) continue; 1.101 + var at = Pos(head.line + (above ? 0 : 1), 0); 1.102 + cm.replaceRange("\n", at, null, "+insertLine"); 1.103 + cm.indentLine(at.line, null, true); 1.104 + newSelection.push({head: at, anchor: at}); 1.105 + last = head.line + 1; 1.106 + } 1.107 + cm.setSelections(newSelection); 1.108 + }); 1.109 + } 1.110 + 1.111 + cmds[map[ctrl + "Enter"] = "insertLineAfter"] = function(cm) { insertLine(cm, false); }; 1.112 + 1.113 + cmds[map["Shift-" + ctrl + "Enter"] = "insertLineBefore"] = function(cm) { insertLine(cm, true); }; 1.114 + 1.115 + function wordAt(cm, pos) { 1.116 + var start = pos.ch, end = start, line = cm.getLine(pos.line); 1.117 + while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start; 1.118 + while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end; 1.119 + return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)}; 1.120 + } 1.121 + 1.122 + cmds[map[ctrl + "D"] = "selectNextOccurrence"] = function(cm) { 1.123 + var from = cm.getCursor("from"), to = cm.getCursor("to"); 1.124 + var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel; 1.125 + if (CodeMirror.cmpPos(from, to) == 0) { 1.126 + var word = wordAt(cm, from); 1.127 + if (!word.word) return; 1.128 + cm.setSelection(word.from, word.to); 1.129 + fullWord = true; 1.130 + } else { 1.131 + var text = cm.getRange(from, to); 1.132 + var query = fullWord ? new RegExp("\\b" + text + "\\b") : text; 1.133 + var cur = cm.getSearchCursor(query, to); 1.134 + if (cur.findNext()) { 1.135 + cm.addSelection(cur.from(), cur.to()); 1.136 + } else { 1.137 + cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0)); 1.138 + if (cur.findNext()) 1.139 + cm.addSelection(cur.from(), cur.to()); 1.140 + } 1.141 + } 1.142 + if (fullWord) 1.143 + cm.state.sublimeFindFullWord = cm.doc.sel; 1.144 + }; 1.145 + 1.146 + var mirror = "(){}[]"; 1.147 + function selectBetweenBrackets(cm) { 1.148 + var pos = cm.getCursor(), opening = cm.scanForBracket(pos, -1); 1.149 + if (!opening) return; 1.150 + for (;;) { 1.151 + var closing = cm.scanForBracket(pos, 1); 1.152 + if (!closing) return; 1.153 + if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { 1.154 + cm.setSelection(Pos(opening.pos.line, opening.pos.ch + 1), closing.pos, false); 1.155 + return true; 1.156 + } 1.157 + pos = Pos(closing.pos.line, closing.pos.ch + 1); 1.158 + } 1.159 + } 1.160 + 1.161 + cmds[map["Shift-" + ctrl + "Space"] = "selectScope"] = function(cm) { 1.162 + selectBetweenBrackets(cm) || cm.execCommand("selectAll"); 1.163 + }; 1.164 + cmds[map["Shift-" + ctrl + "M"] = "selectBetweenBrackets"] = function(cm) { 1.165 + if (!selectBetweenBrackets(cm)) return CodeMirror.Pass; 1.166 + }; 1.167 + 1.168 + cmds[map[ctrl + "M"] = "goToBracket"] = function(cm) { 1.169 + cm.extendSelectionsBy(function(range) { 1.170 + var next = cm.scanForBracket(range.head, 1); 1.171 + if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos; 1.172 + var prev = cm.scanForBracket(range.head, -1); 1.173 + return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head; 1.174 + }); 1.175 + }; 1.176 + 1.177 + cmds[map["Shift-" + ctrl + "Up"] = "swapLineUp"] = function(cm) { 1.178 + var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1; 1.179 + for (var i = 0; i < ranges.length; i++) { 1.180 + var range = ranges[i], from = range.from().line - 1, to = range.to().line; 1.181 + if (from > at) linesToMove.push(from, to); 1.182 + else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; 1.183 + at = to; 1.184 + } 1.185 + cm.operation(function() { 1.186 + for (var i = 0; i < linesToMove.length; i += 2) { 1.187 + var from = linesToMove[i], to = linesToMove[i + 1]; 1.188 + var line = cm.getLine(from); 1.189 + cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); 1.190 + if (to > cm.lastLine()) { 1.191 + cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine"); 1.192 + var sels = cm.listSelections(), last = sels[sels.length - 1]; 1.193 + var head = last.head.line == to ? Pos(to - 1) : last.head; 1.194 + var anchor = last.anchor.line == to ? Pos(to - 1) : last.anchor; 1.195 + cm.setSelections(sels.slice(0, sels.length - 1).concat([{head: head, anchor: anchor}])); 1.196 + } else { 1.197 + cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); 1.198 + } 1.199 + } 1.200 + cm.scrollIntoView(); 1.201 + }); 1.202 + }; 1.203 + 1.204 + cmds[map["Shift-" + ctrl + "Down"] = "swapLineDown"] = function(cm) { 1.205 + var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1; 1.206 + for (var i = ranges.length - 1; i >= 0; i--) { 1.207 + var range = ranges[i], from = range.to().line + 1, to = range.from().line; 1.208 + if (from < at) linesToMove.push(from, to); 1.209 + else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; 1.210 + at = to; 1.211 + } 1.212 + cm.operation(function() { 1.213 + for (var i = linesToMove.length - 2; i >= 0; i -= 2) { 1.214 + var from = linesToMove[i], to = linesToMove[i + 1]; 1.215 + var line = cm.getLine(from); 1.216 + if (from == cm.lastLine()) 1.217 + cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine"); 1.218 + else 1.219 + cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); 1.220 + cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); 1.221 + } 1.222 + cm.scrollIntoView(); 1.223 + }); 1.224 + }; 1.225 + 1.226 + map[ctrl + "/"] = "toggleComment"; 1.227 + 1.228 + cmds[map[ctrl + "J"] = "joinLines"] = function(cm) { 1.229 + var ranges = cm.listSelections(), joined = []; 1.230 + for (var i = 0; i < ranges.length; i++) { 1.231 + var range = ranges[i], from = range.from(); 1.232 + var start = from.line, end = range.to().line; 1.233 + while (i < ranges.length - 1 && ranges[i + 1].from().line == end) 1.234 + end = ranges[++i].to().line; 1.235 + joined.push({start: start, end: end, anchor: !range.empty() && from}); 1.236 + } 1.237 + cm.operation(function() { 1.238 + var offset = 0, ranges = []; 1.239 + for (var i = 0; i < joined.length; i++) { 1.240 + var obj = joined[i]; 1.241 + var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head; 1.242 + for (var line = obj.start; line <= obj.end; line++) { 1.243 + var actual = line - offset; 1.244 + if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1); 1.245 + if (actual < cm.lastLine()) { 1.246 + cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length)); 1.247 + ++offset; 1.248 + } 1.249 + } 1.250 + ranges.push({anchor: anchor || head, head: head}); 1.251 + } 1.252 + cm.setSelections(ranges, 0); 1.253 + }); 1.254 + }; 1.255 + 1.256 + cmds[map["Shift-" + ctrl + "D"] = "duplicateLine"] = function(cm) { 1.257 + cm.operation(function() { 1.258 + var rangeCount = cm.listSelections().length; 1.259 + for (var i = 0; i < rangeCount; i++) { 1.260 + var range = cm.listSelections()[i]; 1.261 + if (range.empty()) 1.262 + cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0)); 1.263 + else 1.264 + cm.replaceRange(cm.getRange(range.from(), range.to()), range.from()); 1.265 + } 1.266 + cm.scrollIntoView(); 1.267 + }); 1.268 + }; 1.269 + 1.270 + map[ctrl + "T"] = "transposeChars"; 1.271 + 1.272 + function sortLines(cm, caseSensitive) { 1.273 + var ranges = cm.listSelections(), toSort = [], selected; 1.274 + for (var i = 0; i < ranges.length; i++) { 1.275 + var range = ranges[i]; 1.276 + if (range.empty()) continue; 1.277 + var from = range.from().line, to = range.to().line; 1.278 + while (i < ranges.length - 1 && ranges[i + 1].from().line == to) 1.279 + to = range[++i].to().line; 1.280 + toSort.push(from, to); 1.281 + } 1.282 + if (toSort.length) selected = true; 1.283 + else toSort.push(cm.firstLine(), cm.lastLine()); 1.284 + 1.285 + cm.operation(function() { 1.286 + var ranges = []; 1.287 + for (var i = 0; i < toSort.length; i += 2) { 1.288 + var from = toSort[i], to = toSort[i + 1]; 1.289 + var start = Pos(from, 0), end = Pos(to); 1.290 + var lines = cm.getRange(start, end, false); 1.291 + if (caseSensitive) 1.292 + lines.sort(); 1.293 + else 1.294 + lines.sort(function(a, b) { 1.295 + var au = a.toUpperCase(), bu = b.toUpperCase(); 1.296 + if (au != bu) { a = au; b = bu; } 1.297 + return a < b ? -1 : a == b ? 0 : 1; 1.298 + }); 1.299 + cm.replaceRange(lines, start, end); 1.300 + if (selected) ranges.push({anchor: start, head: end}); 1.301 + } 1.302 + if (selected) cm.setSelections(ranges, 0); 1.303 + }); 1.304 + } 1.305 + 1.306 + cmds[map["F9"] = "sortLines"] = function(cm) { sortLines(cm, true); }; 1.307 + cmds[map[ctrl + "F9"] = "sortLinesInsensitive"] = function(cm) { sortLines(cm, false); }; 1.308 + 1.309 + cmds[map["F2"] = "nextBookmark"] = function(cm) { 1.310 + var marks = cm.state.sublimeBookmarks; 1.311 + if (marks) while (marks.length) { 1.312 + var current = marks.shift(); 1.313 + var found = current.find(); 1.314 + if (found) { 1.315 + marks.push(current); 1.316 + return cm.setSelection(found.from, found.to); 1.317 + } 1.318 + } 1.319 + }; 1.320 + 1.321 + cmds[map["Shift-F2"] = "prevBookmark"] = function(cm) { 1.322 + var marks = cm.state.sublimeBookmarks; 1.323 + if (marks) while (marks.length) { 1.324 + marks.unshift(marks.pop()); 1.325 + var found = marks[marks.length - 1].find(); 1.326 + if (!found) 1.327 + marks.pop(); 1.328 + else 1.329 + return cm.setSelection(found.from, found.to); 1.330 + } 1.331 + }; 1.332 + 1.333 + cmds[map[ctrl + "F2"] = "toggleBookmark"] = function(cm) { 1.334 + var ranges = cm.listSelections(); 1.335 + var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []); 1.336 + for (var i = 0; i < ranges.length; i++) { 1.337 + var from = ranges[i].from(), to = ranges[i].to(); 1.338 + var found = cm.findMarks(from, to); 1.339 + for (var j = 0; j < found.length; j++) { 1.340 + if (found[j].sublimeBookmark) { 1.341 + found[j].clear(); 1.342 + for (var k = 0; k < marks.length; k++) 1.343 + if (marks[k] == found[j]) 1.344 + marks.splice(k--, 1); 1.345 + break; 1.346 + } 1.347 + } 1.348 + if (j == found.length) 1.349 + marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false})); 1.350 + } 1.351 + }; 1.352 + 1.353 + cmds[map["Shift-" + ctrl + "F2"] = "clearBookmarks"] = function(cm) { 1.354 + var marks = cm.state.sublimeBookmarks; 1.355 + if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear(); 1.356 + marks.length = 0; 1.357 + }; 1.358 + 1.359 + cmds[map["Alt-F2"] = "selectBookmarks"] = function(cm) { 1.360 + var marks = cm.state.sublimeBookmarks, ranges = []; 1.361 + if (marks) for (var i = 0; i < marks.length; i++) { 1.362 + var found = marks[i].find(); 1.363 + if (!found) 1.364 + marks.splice(i--, 0); 1.365 + else 1.366 + ranges.push({anchor: found.from, head: found.to}); 1.367 + } 1.368 + if (ranges.length) 1.369 + cm.setSelections(ranges, 0); 1.370 + }; 1.371 + 1.372 + map["Alt-Q"] = "wrapLines"; 1.373 + 1.374 + var mapK = CodeMirror.keyMap["sublime-Ctrl-K"] = {auto: "sublime", nofallthrough: true}; 1.375 + 1.376 + map[ctrl + "K"] = function(cm) {cm.setOption("keyMap", "sublime-Ctrl-K");}; 1.377 + 1.378 + function modifyWordOrSelection(cm, mod) { 1.379 + cm.operation(function() { 1.380 + var ranges = cm.listSelections(), indices = [], replacements = []; 1.381 + for (var i = 0; i < ranges.length; i++) { 1.382 + var range = ranges[i]; 1.383 + if (range.empty()) { indices.push(i); replacements.push(""); } 1.384 + else replacements.push(mod(cm.getRange(range.from(), range.to()))); 1.385 + } 1.386 + cm.replaceSelections(replacements, "around", "case"); 1.387 + for (var i = indices.length - 1, at; i >= 0; i--) { 1.388 + var range = ranges[indices[i]]; 1.389 + if (at && CodeMirror.cmpPos(range.head, at) > 0) continue; 1.390 + var word = wordAt(cm, range.head); 1.391 + at = word.from; 1.392 + cm.replaceRange(mod(word.word), word.from, word.to); 1.393 + } 1.394 + }); 1.395 + } 1.396 + 1.397 + mapK[ctrl + "Backspace"] = "delLineLeft"; 1.398 + 1.399 + cmds[mapK[ctrl + "K"] = "delLineRight"] = function(cm) { 1.400 + cm.operation(function() { 1.401 + var ranges = cm.listSelections(); 1.402 + for (var i = ranges.length - 1; i >= 0; i--) 1.403 + cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete"); 1.404 + cm.scrollIntoView(); 1.405 + }); 1.406 + }; 1.407 + 1.408 + cmds[mapK[ctrl + "U"] = "upcaseAtCursor"] = function(cm) { 1.409 + modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); }); 1.410 + }; 1.411 + cmds[mapK[ctrl + "L"] = "downcaseAtCursor"] = function(cm) { 1.412 + modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); }); 1.413 + }; 1.414 + 1.415 + cmds[mapK[ctrl + "Space"] = "setSublimeMark"] = function(cm) { 1.416 + if (cm.state.sublimeMark) cm.state.sublimeMark.clear(); 1.417 + cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); 1.418 + }; 1.419 + cmds[mapK[ctrl + "A"] = "selectToSublimeMark"] = function(cm) { 1.420 + var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); 1.421 + if (found) cm.setSelection(cm.getCursor(), found); 1.422 + }; 1.423 + cmds[mapK[ctrl + "W"] = "deleteToSublimeMark"] = function(cm) { 1.424 + var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); 1.425 + if (found) { 1.426 + var from = cm.getCursor(), to = found; 1.427 + if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; } 1.428 + cm.state.sublimeKilled = cm.getRange(from, to); 1.429 + cm.replaceRange("", from, to); 1.430 + } 1.431 + }; 1.432 + cmds[mapK[ctrl + "X"] = "swapWithSublimeMark"] = function(cm) { 1.433 + var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); 1.434 + if (found) { 1.435 + cm.state.sublimeMark.clear(); 1.436 + cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); 1.437 + cm.setCursor(found); 1.438 + } 1.439 + }; 1.440 + cmds[mapK[ctrl + "Y"] = "sublimeYank"] = function(cm) { 1.441 + if (cm.state.sublimeKilled != null) 1.442 + cm.replaceSelection(cm.state.sublimeKilled, null, "paste"); 1.443 + }; 1.444 + 1.445 + mapK[ctrl + "G"] = "clearBookmarks"; 1.446 + cmds[mapK[ctrl + "C"] = "showInCenter"] = function(cm) { 1.447 + var pos = cm.cursorCoords(null, "local"); 1.448 + cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2); 1.449 + }; 1.450 + 1.451 + cmds[map["Shift-Alt-Up"] = "selectLinesUpward"] = function(cm) { 1.452 + cm.operation(function() { 1.453 + var ranges = cm.listSelections(); 1.454 + for (var i = 0; i < ranges.length; i++) { 1.455 + var range = ranges[i]; 1.456 + if (range.head.line > cm.firstLine()) 1.457 + cm.addSelection(Pos(range.head.line - 1, range.head.ch)); 1.458 + } 1.459 + }); 1.460 + }; 1.461 + cmds[map["Shift-Alt-Down"] = "selectLinesDownward"] = function(cm) { 1.462 + cm.operation(function() { 1.463 + var ranges = cm.listSelections(); 1.464 + for (var i = 0; i < ranges.length; i++) { 1.465 + var range = ranges[i]; 1.466 + if (range.head.line < cm.lastLine()) 1.467 + cm.addSelection(Pos(range.head.line + 1, range.head.ch)); 1.468 + } 1.469 + }); 1.470 + }; 1.471 + 1.472 + function findAndGoTo(cm, forward) { 1.473 + var from = cm.getCursor("from"), to = cm.getCursor("to"); 1.474 + if (CodeMirror.cmpPos(from, to) == 0) { 1.475 + var word = wordAt(cm, from); 1.476 + if (!word.word) return; 1.477 + from = word.from; 1.478 + to = word.to; 1.479 + } 1.480 + 1.481 + var query = cm.getRange(from, to); 1.482 + var cur = cm.getSearchCursor(query, forward ? to : from); 1.483 + 1.484 + if (forward ? cur.findNext() : cur.findPrevious()) { 1.485 + cm.setSelection(cur.from(), cur.to()); 1.486 + } else { 1.487 + cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0) 1.488 + : cm.clipPos(Pos(cm.lastLine()))); 1.489 + if (forward ? cur.findNext() : cur.findPrevious()) 1.490 + cm.setSelection(cur.from(), cur.to()); 1.491 + else if (word) 1.492 + cm.setSelection(from, to); 1.493 + } 1.494 + }; 1.495 + cmds[map[ctrl + "F3"] = "findUnder"] = function(cm) { findAndGoTo(cm, true); }; 1.496 + cmds[map["Shift-" + ctrl + "F3"] = "findUnderPrevious"] = function(cm) { findAndGoTo(cm,false); }; 1.497 + 1.498 + map["Shift-" + ctrl + "["] = "fold"; 1.499 + map["Shift-" + ctrl + "]"] = "unfold"; 1.500 + mapK[ctrl + "0"] = mapK[ctrl + "j"] = "unfoldAll"; 1.501 + 1.502 + map[ctrl + "I"] = "findIncremental"; 1.503 + map["Shift-" + ctrl + "I"] = "findIncrementalReverse"; 1.504 + map[ctrl + "H"] = "replace"; 1.505 + map["F3"] = "findNext"; 1.506 + map["Shift-F3"] = "findPrev"; 1.507 + 1.508 +});