Mercurial
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 }); |