comparison .cms/lib/codemirror/keymap/sublime.js @ 0:78edf6b517a0 draft

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