codemirror-rails 2.35 → 2.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +22 -16
- data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +2 -1
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +263 -154
- data/vendor/assets/javascripts/codemirror/modes/clike.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/gfm.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +3 -1
- data/vendor/assets/javascripts/codemirror/modes/mysql.js +23 -6
- data/vendor/assets/javascripts/codemirror/modes/php.js +13 -33
- data/vendor/assets/javascripts/codemirror/modes/python.js +5 -3
- data/vendor/assets/javascripts/codemirror/modes/xml.js +5 -3
- data/vendor/assets/javascripts/codemirror/modes/z80.js +113 -0
- data/vendor/assets/javascripts/codemirror/utils/continuecomment.js +36 -0
- data/vendor/assets/javascripts/codemirror/utils/formatting.js +10 -7
- data/vendor/assets/javascripts/codemirror/utils/xml-hint.js +0 -6
- data/vendor/assets/stylesheets/codemirror/themes/ambiance-mobile.css +6 -0
- data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +1 -1
- data/vendor/assets/stylesheets/codemirror/themes/twilight.css +26 -0
- metadata +16 -12
@@ -1,4 +1,4 @@
|
|
1
|
-
// CodeMirror version 2.
|
1
|
+
// CodeMirror version 2.36
|
2
2
|
//
|
3
3
|
// All functions that need access to the editor's state live inside
|
4
4
|
// the CodeMirror function. Below that, at the bottom of the file,
|
@@ -232,6 +232,7 @@ window.CodeMirror = (function() {
|
|
232
232
|
var off = eltOffset(lineSpace);
|
233
233
|
return coordsChar(coords.x - off.left, coords.y - off.top);
|
234
234
|
},
|
235
|
+
defaultTextHeight: function() { return textHeight(); },
|
235
236
|
markText: operation(markText),
|
236
237
|
setBookmark: setBookmark,
|
237
238
|
findMarksAt: findMarksAt,
|
@@ -346,6 +347,11 @@ window.CodeMirror = (function() {
|
|
346
347
|
return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
|
347
348
|
height: scrollbar.scrollHeight, width: scroller.scrollWidth};
|
348
349
|
},
|
350
|
+
scrollIntoView: function(pos) {
|
351
|
+
var coords = localCoords(pos ? clipPos(pos) : sel.inverted ? sel.from : sel.to);
|
352
|
+
scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
|
353
|
+
},
|
354
|
+
|
349
355
|
setSize: function(width, height) {
|
350
356
|
function interpret(val) {
|
351
357
|
val = String(val);
|
@@ -395,7 +401,7 @@ window.CodeMirror = (function() {
|
|
395
401
|
}
|
396
402
|
|
397
403
|
function onScrollBar(e) {
|
398
|
-
if (scrollbar.scrollTop
|
404
|
+
if (Math.abs(scrollbar.scrollTop - lastScrollTop) > 1) {
|
399
405
|
lastScrollTop = scroller.scrollTop = scrollbar.scrollTop;
|
400
406
|
updateDisplay([]);
|
401
407
|
}
|
@@ -404,7 +410,7 @@ window.CodeMirror = (function() {
|
|
404
410
|
function onScrollMain(e) {
|
405
411
|
if (options.fixedGutter && gutter.style.left != scroller.scrollLeft + "px")
|
406
412
|
gutter.style.left = scroller.scrollLeft + "px";
|
407
|
-
if (scroller.scrollTop
|
413
|
+
if (Math.abs(scroller.scrollTop - lastScrollTop) > 1) {
|
408
414
|
lastScrollTop = scroller.scrollTop;
|
409
415
|
if (scrollbar.scrollTop != lastScrollTop)
|
410
416
|
scrollbar.scrollTop = lastScrollTop;
|
@@ -637,7 +643,7 @@ window.CodeMirror = (function() {
|
|
637
643
|
if (handled) {
|
638
644
|
e_preventDefault(e);
|
639
645
|
restartBlink();
|
640
|
-
if (
|
646
|
+
if (ie_lt9) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
|
641
647
|
}
|
642
648
|
return handled;
|
643
649
|
}
|
@@ -2174,7 +2180,7 @@ window.CodeMirror = (function() {
|
|
2174
2180
|
keyMap.emacsy = {
|
2175
2181
|
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
|
2176
2182
|
"Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
|
2177
|
-
"Ctrl-V": "
|
2183
|
+
"Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft",
|
2178
2184
|
"Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
|
2179
2185
|
};
|
2180
2186
|
|
@@ -2232,15 +2238,13 @@ window.CodeMirror = (function() {
|
|
2232
2238
|
if (textarea.form) {
|
2233
2239
|
// Deplorable hack to make the submit method do the right thing.
|
2234
2240
|
var rmSubmit = connect(textarea.form, "submit", save, true);
|
2235
|
-
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
};
|
2243
|
-
}
|
2241
|
+
var realSubmit = textarea.form.submit;
|
2242
|
+
textarea.form.submit = function wrappedSubmit() {
|
2243
|
+
save();
|
2244
|
+
textarea.form.submit = realSubmit;
|
2245
|
+
textarea.form.submit();
|
2246
|
+
textarea.form.submit = wrappedSubmit;
|
2247
|
+
};
|
2244
2248
|
}
|
2245
2249
|
|
2246
2250
|
textarea.style.display = "none";
|
@@ -3102,8 +3106,10 @@ window.CodeMirror = (function() {
|
|
3102
3106
|
if (collection[i] == elt) return i;
|
3103
3107
|
return -1;
|
3104
3108
|
}
|
3109
|
+
var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc]/;
|
3105
3110
|
function isWordChar(ch) {
|
3106
|
-
return /\w/.test(ch) || ch
|
3111
|
+
return /\w/.test(ch) || ch > "\x80" &&
|
3112
|
+
(ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
|
3107
3113
|
}
|
3108
3114
|
|
3109
3115
|
// See if "".split is the broken IE version, if so, provide an
|
@@ -3159,7 +3165,7 @@ window.CodeMirror = (function() {
|
|
3159
3165
|
for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
|
3160
3166
|
})();
|
3161
3167
|
|
3162
|
-
CodeMirror.version = "2.
|
3168
|
+
CodeMirror.version = "2.36";
|
3163
3169
|
|
3164
3170
|
return CodeMirror;
|
3165
3171
|
})();
|
@@ -18,7 +18,8 @@
|
|
18
18
|
"Alt-Y": function(cm) {cm.replaceSelection(popFromRing());},
|
19
19
|
"Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
|
20
20
|
"Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
|
21
|
-
"Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete",
|
21
|
+
"Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete", "Alt-V": "goPageUp",
|
22
|
+
"Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",
|
22
23
|
fallthrough: ["basic", "emacsy"]
|
23
24
|
};
|
24
25
|
|
@@ -17,7 +17,7 @@
|
|
17
17
|
// Entering insert mode:
|
18
18
|
// i, I, a, A, o, O
|
19
19
|
// s
|
20
|
-
// ce, cb
|
20
|
+
// ce, cb
|
21
21
|
// cc
|
22
22
|
// S, C TODO
|
23
23
|
// cf<char>, cF<char>, ct<char>, cT<char>
|
@@ -26,7 +26,7 @@
|
|
26
26
|
// x, X
|
27
27
|
// J
|
28
28
|
// dd, D
|
29
|
-
// de, db
|
29
|
+
// de, db
|
30
30
|
// df<char>, dF<char>, dt<char>, dT<char>
|
31
31
|
//
|
32
32
|
// Yanking and pasting:
|
@@ -48,22 +48,28 @@
|
|
48
48
|
//
|
49
49
|
|
50
50
|
(function() {
|
51
|
-
var count = "";
|
52
51
|
var sdir = "f";
|
53
52
|
var buf = "";
|
54
|
-
var
|
55
|
-
var
|
56
|
-
|
53
|
+
var mark = {};
|
54
|
+
var repeatCount = 0;
|
55
|
+
function isLine(cm, line) { return line >= 0 && line < cm.lineCount(); }
|
57
56
|
function emptyBuffer() { buf = ""; }
|
58
57
|
function pushInBuffer(str) { buf += str; }
|
59
|
-
function
|
60
|
-
function
|
58
|
+
function pushRepeatCountDigit(digit) {return function(cm) {repeatCount = (repeatCount * 10) + digit}; }
|
59
|
+
function getCountOrOne() {
|
60
|
+
var i = repeatCount;
|
61
|
+
return i || 1;
|
62
|
+
}
|
63
|
+
function clearCount() {
|
64
|
+
repeatCount = 0;
|
65
|
+
}
|
61
66
|
function iterTimes(func) {
|
62
|
-
for (var i = 0, c =
|
67
|
+
for (var i = 0, c = getCountOrOne(); i < c; ++i) func(i, i == c - 1);
|
68
|
+
clearCount();
|
63
69
|
}
|
64
70
|
function countTimes(func) {
|
65
71
|
if (typeof func == "string") func = CodeMirror.commands[func];
|
66
|
-
return function(cm) { iterTimes(function () { func(cm); }); };
|
72
|
+
return function(cm) { iterTimes(function (i, last) { func(cm, i, last); }); };
|
67
73
|
}
|
68
74
|
|
69
75
|
function iterObj(o, f) {
|
@@ -93,50 +99,110 @@
|
|
93
99
|
}
|
94
100
|
|
95
101
|
var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
102
|
+
// Finds a word on the given line, and continue searching the next line if it can't find one.
|
103
|
+
function findWord(cm, lineNum, pos, dir, regexps) {
|
104
|
+
var line = cm.getLine(lineNum);
|
105
|
+
while (true) {
|
106
|
+
var stop = (dir > 0) ? line.length : -1;
|
107
|
+
var wordStart = stop, wordEnd = stop;
|
108
|
+
// Find bounds of next word.
|
109
|
+
for (; pos != stop; pos += dir) {
|
110
|
+
for (var i = 0; i < regexps.length; ++i) {
|
111
|
+
if (regexps[i].test(line.charAt(pos))) {
|
112
|
+
wordStart = pos;
|
113
|
+
// Advance to end of word.
|
114
|
+
for (; pos != stop && regexps[i].test(line.charAt(pos)); pos += dir) {}
|
115
|
+
wordEnd = (dir > 0) ? pos : pos + 1;
|
116
|
+
return {
|
117
|
+
from: Math.min(wordStart, wordEnd),
|
118
|
+
to: Math.max(wordStart, wordEnd),
|
119
|
+
line: lineNum};
|
107
120
|
}
|
108
|
-
end = pos;
|
109
|
-
break outer;
|
110
121
|
}
|
111
122
|
}
|
123
|
+
// Advance to next/prev line.
|
124
|
+
lineNum += dir;
|
125
|
+
if (!isLine(cm, lineNum)) return null;
|
126
|
+
line = cm.getLine(lineNum);
|
127
|
+
pos = (dir > 0) ? 0 : line.length;
|
112
128
|
}
|
113
|
-
return {from: Math.min(start, end), to: Math.max(start, end)};
|
114
129
|
}
|
115
|
-
|
130
|
+
/**
|
131
|
+
* @param {boolean} cm CodeMirror object.
|
132
|
+
* @param {regexp} regexps Regular expressions for word characters.
|
133
|
+
* @param {number} dir Direction, +/- 1.
|
134
|
+
* @param {number} times Number of times to advance word.
|
135
|
+
* @param {string} where Go to "start" or "end" of word, 'e' vs 'w'.
|
136
|
+
* @param {boolean} yank Whether we are finding words to yank. If true,
|
137
|
+
* do not go to the next line to look for the last word. This is to
|
138
|
+
* prevent deleting new line on 'dw' at the end of a line.
|
139
|
+
*/
|
140
|
+
function moveToWord(cm, regexps, dir, times, where, yank) {
|
116
141
|
var cur = cm.getCursor();
|
117
|
-
|
142
|
+
if (yank) {
|
143
|
+
where = 'start';
|
144
|
+
}
|
118
145
|
for (var i = 0; i < times; i++) {
|
119
|
-
var
|
146
|
+
var startCh = cur.ch, startLine = cur.line, word;
|
120
147
|
while (true) {
|
121
|
-
//
|
122
|
-
|
123
|
-
|
124
|
-
cur.
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
148
|
+
// Search and advance.
|
149
|
+
word = findWord(cm, cur.line, cur.ch, dir, regexps);
|
150
|
+
if (word) {
|
151
|
+
if (yank && times == 1 && dir == 1 && cur.line != word.line) {
|
152
|
+
// Stop at end of line of last word. Don't want to delete line return
|
153
|
+
// for dw if the last deleted word is at the end of a line.
|
154
|
+
cur.ch = cm.getLine(cur.line).length;
|
155
|
+
break;
|
156
|
+
} else {
|
157
|
+
// Move to the word we just found. If by moving to the word we end up
|
158
|
+
// in the same spot, then move an extra character and search again.
|
159
|
+
cur.line = word.line;
|
160
|
+
if (dir > 0 && where == 'end') {
|
161
|
+
// 'e'
|
162
|
+
if (startCh != word.to - 1 || startLine != word.line) {
|
163
|
+
cur.ch = word.to - 1;
|
164
|
+
break;
|
165
|
+
} else {
|
166
|
+
cur.ch = word.to;
|
167
|
+
}
|
168
|
+
} else if (dir > 0 && where == 'start') {
|
169
|
+
// 'w'
|
170
|
+
if (startCh != word.from || startLine != word.line) {
|
171
|
+
cur.ch = word.from;
|
172
|
+
break;
|
173
|
+
} else {
|
174
|
+
cur.ch = word.to;
|
175
|
+
}
|
176
|
+
} else if (dir < 0 && where == 'end') {
|
177
|
+
// 'ge'
|
178
|
+
if (startCh != word.to || startLine != word.line) {
|
179
|
+
cur.ch = word.to;
|
180
|
+
break;
|
181
|
+
} else {
|
182
|
+
cur.ch = word.from - 1;
|
183
|
+
}
|
184
|
+
} else if (dir < 0 && where == 'start') {
|
185
|
+
// 'b'
|
186
|
+
if (startCh != word.from || startLine != word.line) {
|
187
|
+
cur.ch = word.from;
|
188
|
+
break;
|
189
|
+
} else {
|
190
|
+
cur.ch = word.from - 1;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
} else {
|
195
|
+
// No more words to be found. Move to end of document.
|
196
|
+
for (; isLine(cm, cur.line + dir); cur.line += dir) {}
|
197
|
+
cur.ch = (dir > 0) ? cm.getLine(cur.line).length : 0;
|
198
|
+
break;
|
130
199
|
}
|
131
|
-
if (!line) break;
|
132
|
-
|
133
|
-
// On to the actual searching
|
134
|
-
word = findWord(line, cur.ch, dir, regexps);
|
135
|
-
cur.ch = word[where == "end" ? "to" : "from"];
|
136
|
-
if (startCh == cur.ch && word.from != word.to) cur.ch = word[dir < 0 ? "from" : "to"];
|
137
|
-
else break;
|
138
200
|
}
|
139
201
|
}
|
202
|
+
if (where == 'end' && yank) {
|
203
|
+
// Include the last character of the word for actions.
|
204
|
+
cur.ch++;
|
205
|
+
}
|
140
206
|
return cur;
|
141
207
|
}
|
142
208
|
function joinLineNext(cm) {
|
@@ -157,7 +223,7 @@
|
|
157
223
|
var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
|
158
224
|
cm.setCursor(start);
|
159
225
|
for (var c = start; c <= end; c++) {
|
160
|
-
pushInBuffer("\n"+cm.getLine(start));
|
226
|
+
pushInBuffer("\n" + cm.getLine(start));
|
161
227
|
cm.removeLine(start);
|
162
228
|
}
|
163
229
|
}
|
@@ -169,7 +235,7 @@
|
|
169
235
|
}
|
170
236
|
var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
|
171
237
|
for (var c = start; c <= end; c++) {
|
172
|
-
pushInBuffer("\n"+cm.getLine(c));
|
238
|
+
pushInBuffer("\n" + cm.getLine(c));
|
173
239
|
}
|
174
240
|
cm.setCursor(start);
|
175
241
|
}
|
@@ -220,7 +286,7 @@
|
|
220
286
|
|
221
287
|
function enterInsertMode(cm) {
|
222
288
|
// enter insert mode: switch mode and cursor
|
223
|
-
|
289
|
+
clearCount();
|
224
290
|
cm.setOption("keyMap", "vim-insert");
|
225
291
|
}
|
226
292
|
|
@@ -238,7 +304,8 @@
|
|
238
304
|
var map = CodeMirror.keyMap.vim = {
|
239
305
|
// Pipe (|); TODO: should be *screen* chars, so need a util function to turn tabs into spaces?
|
240
306
|
"'|'": function(cm) {
|
241
|
-
cm.setCursor(cm.getCursor().line,
|
307
|
+
cm.setCursor(cm.getCursor().line, getCountOrOne() - 1, true);
|
308
|
+
clearCount();
|
242
309
|
},
|
243
310
|
"A": function(cm) {
|
244
311
|
cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true);
|
@@ -260,16 +327,26 @@
|
|
260
327
|
},
|
261
328
|
"G": function(cm) { cm.setOption("keyMap", "vim-prefix-g");},
|
262
329
|
"Shift-D": function(cm) {
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
*/
|
330
|
+
var cursor = cm.getCursor();
|
331
|
+
var lineN = cursor.line;
|
332
|
+
var line = cm.getLine(lineN);
|
333
|
+
cm.setLine(lineN, line.slice(0, cursor.ch));
|
334
|
+
|
269
335
|
emptyBuffer();
|
270
|
-
|
271
|
-
|
272
|
-
|
336
|
+
pushInBuffer(line.slice(cursor.ch));
|
337
|
+
|
338
|
+
if (repeatCount > 1) {
|
339
|
+
// we've already done it once
|
340
|
+
--repeatCount;
|
341
|
+
// the lines dissapear (ie, cursor stays on the same lineN),
|
342
|
+
// so only incremenet once
|
343
|
+
++lineN;
|
344
|
+
|
345
|
+
iterTimes(function() {
|
346
|
+
pushInBuffer(cm.getLine(lineN));
|
347
|
+
cm.removeLine(lineN);
|
348
|
+
});
|
349
|
+
}
|
273
350
|
},
|
274
351
|
|
275
352
|
"S": function (cm) {
|
@@ -278,13 +355,11 @@
|
|
278
355
|
})(cm);
|
279
356
|
enterInsertMode(cm);
|
280
357
|
},
|
281
|
-
"M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark =
|
282
|
-
"Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer();
|
358
|
+
"M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark = {};},
|
359
|
+
"Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer();},
|
283
360
|
"Shift-Y": function(cm) {
|
284
361
|
emptyBuffer();
|
285
|
-
|
286
|
-
cm.setCursor(cm.getCursor(true).line);
|
287
|
-
yankTillMark(cm,"Shift-D"); mark = [];
|
362
|
+
iterTimes(function(i) { pushInBuffer("\n" + cm.getLine(cm.getCursor().line + i)); });
|
288
363
|
},
|
289
364
|
"/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f";},
|
290
365
|
"'?'": function(cm) {
|
@@ -300,8 +375,8 @@
|
|
300
375
|
if (fn) sdir != "r" ? CodeMirror.commands.findPrev(cm) : fn.findNext(cm);
|
301
376
|
},
|
302
377
|
"Shift-G": function(cm) {
|
303
|
-
|
304
|
-
|
378
|
+
(repeatCount == 0) ? cm.setCursor(cm.lineCount()) : cm.setCursor(repeatCount - 1);
|
379
|
+
clearCount();
|
305
380
|
CodeMirror.commands.goLineStart(cm);
|
306
381
|
},
|
307
382
|
"':'": function(cm) {
|
@@ -325,21 +400,9 @@
|
|
325
400
|
};
|
326
401
|
});
|
327
402
|
|
328
|
-
function addCountBindings(keyMap) {
|
329
|
-
// Add bindings for number keys
|
330
|
-
keyMap["0"] = function(cm) {
|
331
|
-
count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);
|
332
|
-
};
|
333
|
-
for (var i = 1; i < 10; ++i) keyMap[i] = pushCountDigit(i);
|
334
|
-
}
|
335
|
-
addCountBindings(CodeMirror.keyMap.vim);
|
336
|
-
|
337
403
|
// main num keymap
|
338
404
|
// Add bindings that are influenced by number keys
|
339
405
|
iterObj({
|
340
|
-
"Left": "goColumnLeft", "Right": "goColumnRight",
|
341
|
-
"Down": "goLineDown", "Up": "goLineUp", "Backspace": "goCharLeft",
|
342
|
-
"Space": "goCharRight",
|
343
406
|
"X": function(cm) {CodeMirror.commands.delCharRight(cm);},
|
344
407
|
"P": function(cm) {
|
345
408
|
var cur = cm.getCursor().line;
|
@@ -401,15 +464,18 @@
|
|
401
464
|
});
|
402
465
|
|
403
466
|
CodeMirror.keyMap["vim-prefix-g"] = {
|
404
|
-
"E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, word, -1, 1, "
|
405
|
-
"Shift-E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, bigWord, -1, 1, "
|
406
|
-
"G": function (cm) {
|
467
|
+
"E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, word, -1, 1, "end"));}),
|
468
|
+
"Shift-E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, bigWord, -1, 1, "end"));}),
|
469
|
+
"G": function (cm) {
|
470
|
+
cm.setCursor({line: repeatCount - 1, ch: cm.getCursor().ch});
|
471
|
+
clearCount();
|
472
|
+
},
|
407
473
|
auto: "vim", nofallthrough: true, style: "fat-cursor"
|
408
474
|
};
|
409
475
|
|
410
476
|
CodeMirror.keyMap["vim-prefix-d"] = {
|
411
477
|
"D": countTimes(function(cm) {
|
412
|
-
pushInBuffer("\n"+cm.getLine(cm.getCursor().line));
|
478
|
+
pushInBuffer("\n" + cm.getLine(cm.getCursor().line));
|
413
479
|
cm.removeLine(cm.getCursor().line);
|
414
480
|
cm.setOption("keyMap", "vim");
|
415
481
|
}),
|
@@ -428,8 +494,6 @@
|
|
428
494
|
},
|
429
495
|
nofallthrough: true, style: "fat-cursor"
|
430
496
|
};
|
431
|
-
// FIXME - does not work for bindings like "d3e"
|
432
|
-
addCountBindings(CodeMirror.keyMap["vim-prefix-d"]);
|
433
497
|
|
434
498
|
CodeMirror.keyMap["vim-prefix-c"] = {
|
435
499
|
"B": function (cm) {
|
@@ -471,10 +535,10 @@
|
|
471
535
|
mark[m] = cm.getCursor().line;
|
472
536
|
};
|
473
537
|
CodeMirror.keyMap["vim-prefix-d'"][m] = function(cm) {
|
474
|
-
delTillMark(cm,m);
|
538
|
+
delTillMark(cm, m);
|
475
539
|
};
|
476
540
|
CodeMirror.keyMap["vim-prefix-y'"][m] = function(cm) {
|
477
|
-
yankTillMark(cm,m);
|
541
|
+
yankTillMark(cm, m);
|
478
542
|
};
|
479
543
|
CodeMirror.keyMap["vim-prefix-r"][m] = function (cm) {
|
480
544
|
var cur = cm.getCursor();
|
@@ -508,8 +572,8 @@
|
|
508
572
|
setupPrefixBindingForKey("Space");
|
509
573
|
|
510
574
|
CodeMirror.keyMap["vim-prefix-y"] = {
|
511
|
-
"Y": countTimes(function(cm) {
|
512
|
-
pushInBuffer("\n"+cm.getLine(cm.getCursor().line+
|
575
|
+
"Y": countTimes(function(cm, i, last) {
|
576
|
+
pushInBuffer("\n" + cm.getLine(cm.getCursor().line + i));
|
513
577
|
cm.setOption("keyMap", "vim");
|
514
578
|
}),
|
515
579
|
"'": function(cm) {cm.setOption("keyMap", "vim-prefix-y'"); emptyBuffer();},
|
@@ -588,67 +652,107 @@
|
|
588
652
|
return {start: start, end: end};
|
589
653
|
}
|
590
654
|
|
591
|
-
//
|
592
|
-
//
|
593
|
-
|
655
|
+
// takes in a symbol and a cursor and tries to simulate text objects that have
|
656
|
+
// identical opening and closing symbols
|
657
|
+
// TODO support across multiple lines
|
658
|
+
function findBeginningAndEnd(cm, symb, inclusive) {
|
659
|
+
var cur = cm.getCursor();
|
660
|
+
var line = cm.getLine(cur.line);
|
661
|
+
var chars = line.split('');
|
662
|
+
var start = undefined;
|
663
|
+
var end = undefined;
|
664
|
+
var firstIndex = chars.indexOf(symb);
|
665
|
+
|
666
|
+
// the decision tree is to always look backwards for the beginning first,
|
667
|
+
// but if the cursor is in front of the first instance of the symb,
|
668
|
+
// then move the cursor forward
|
669
|
+
if (cur.ch < firstIndex) {
|
670
|
+
cur.ch = firstIndex;
|
671
|
+
cm.setCursor(cur.line, firstIndex+1);
|
672
|
+
}
|
673
|
+
// otherwise if the cursor is currently on the closing symbol
|
674
|
+
else if (firstIndex < cur.ch && chars[cur.ch] == symb) {
|
675
|
+
end = cur.ch; // assign end to the current cursor
|
676
|
+
--cur.ch; // make sure to look backwards
|
677
|
+
}
|
594
678
|
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
},
|
679
|
+
// if we're currently on the symbol, we've got a start
|
680
|
+
if (chars[cur.ch] == symb && end == null)
|
681
|
+
start = cur.ch + 1; // assign start to ahead of the cursor
|
682
|
+
else {
|
683
|
+
// go backwards to find the start
|
684
|
+
for (var i = cur.ch; i > -1 && start == null; i--)
|
685
|
+
if (chars[i] == symb) start = i + 1;
|
686
|
+
}
|
604
687
|
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
688
|
+
// look forwards for the end symbol
|
689
|
+
if (start != null && end == null) {
|
690
|
+
for (var i = start, len = chars.length; i < len && end == null; i++) {
|
691
|
+
if (chars[i] == symb) end = i;
|
692
|
+
}
|
693
|
+
}
|
609
694
|
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
695
|
+
// nothing found
|
696
|
+
// FIXME still enters insert mode
|
697
|
+
if (start == null || end == null) return {
|
698
|
+
start: cur, end: cur
|
699
|
+
};
|
614
700
|
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
}
|
619
|
-
'W': function(cm, times) { return moveToWord(cm, word, 1, times); },
|
620
|
-
'Shift-W': function(cm, times) { return moveToWord(cm, bigWord, 1, times); },
|
621
|
-
"'^'": function(cm, times) {
|
622
|
-
var cur = cm.getCursor();
|
623
|
-
var line = cm.getLine(cur.line).split('');
|
701
|
+
// include the symbols
|
702
|
+
if (inclusive) {
|
703
|
+
--start; ++end;
|
704
|
+
}
|
624
705
|
|
625
|
-
|
626
|
-
|
706
|
+
return {
|
707
|
+
start: {line: cur.line, ch: start},
|
708
|
+
end: {line: cur.line, ch: end}
|
709
|
+
};
|
710
|
+
}
|
627
711
|
|
628
|
-
|
629
|
-
|
712
|
+
function offsetCursor(cm, line, ch) {
|
713
|
+
var cur = cm.getCursor(); return {line: cur.line + line, ch: cur.ch + ch};
|
714
|
+
}
|
715
|
+
|
716
|
+
// These are the motion commands we use for navigation and selection with
|
717
|
+
// certain other commands. All should return a cursor object.
|
718
|
+
var motions = {
|
719
|
+
"J": function(cm, times) { return offsetCursor(cm, times, 0); },
|
720
|
+
"Down": function(cm, times) { return offsetCursor(cm, times, 0); },
|
721
|
+
"K": function(cm, times) { return offsetCursor(cm, -times, 0); },
|
722
|
+
"Up": function(cm, times) { return offsetCursor(cm, -times, 0); },
|
723
|
+
"L": function(cm, times) { return offsetCursor(cm, 0, times); },
|
724
|
+
"Right": function(cm, times) { return offsetCursor(cm, 0, times); },
|
725
|
+
"Space": function(cm, times) { return offsetCursor(cm, 0, times); },
|
726
|
+
"H": function(cm, times) { return offsetCursor(cm, 0, -times); },
|
727
|
+
"Left": function(cm, times) { return offsetCursor(cm, 0, -times); },
|
728
|
+
"Backspace": function(cm, times) { return offsetCursor(cm, 0, -times); },
|
729
|
+
"B": function(cm, times, yank) { return moveToWord(cm, word, -1, times, 'start', yank); },
|
730
|
+
"Shift-B": function(cm, times, yank) { return moveToWord(cm, bigWord, -1, times, 'start', yank); },
|
731
|
+
"E": function(cm, times, yank) { return moveToWord(cm, word, 1, times, 'end', yank); },
|
732
|
+
"Shift-E": function(cm, times, yank) { return moveToWord(cm, bigWord, 1, times, 'end', yank); },
|
733
|
+
"W": function(cm, times, yank) { return moveToWord(cm, word, 1, times, 'start', yank); },
|
734
|
+
"Shift-W": function(cm, times, yank) { return moveToWord(cm, bigWord, 1, times, 'start', yank); },
|
735
|
+
"'^'": function(cm, times) {
|
736
|
+
var cur = cm.getCursor(), line = cm.getLine(cur.line).split('');
|
737
|
+
for (var i = 0; i < line.length; i++) {
|
738
|
+
if (line[i].match(/[^\s]/)) return {line: cur.line, ch: index};
|
630
739
|
}
|
740
|
+
return cur;
|
631
741
|
},
|
632
742
|
"'$'": function(cm) {
|
633
|
-
var cur = cm.getCursor();
|
634
|
-
|
635
|
-
return {line: cur.line, ch: line.length};
|
743
|
+
var cur = cm.getCursor(), ch = cm.getLine(cur.line).length;
|
744
|
+
return {line: cur.line, ch: ch};
|
636
745
|
},
|
637
746
|
"'%'": function(cm) { return findMatchedSymbol(cm, cm.getCursor()); },
|
638
|
-
"Esc" : function(cm) {
|
639
|
-
cm.setOption('vim');
|
640
|
-
reptTimes = 0;
|
641
|
-
|
642
|
-
return cm.getCursor();
|
643
|
-
}
|
747
|
+
"Esc" : function(cm) { cm.setOption("keyMap", "vim"); repeatCount = 0; return cm.getCursor(); }
|
644
748
|
};
|
645
749
|
|
646
750
|
// Map our movement actions each operator and non-operational movement
|
647
|
-
|
751
|
+
iterObj(motions, function(key, motion) {
|
648
752
|
CodeMirror.keyMap['vim-prefix-d'][key] = function(cm) {
|
649
753
|
// Get our selected range
|
650
754
|
var start = cm.getCursor();
|
651
|
-
var end =
|
755
|
+
var end = motion(cm, repeatCount ? repeatCount : 1, true);
|
652
756
|
|
653
757
|
// Set swap var if range is of negative length
|
654
758
|
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
|
@@ -658,56 +762,59 @@
|
|
658
762
|
cm.replaceRange("", swap ? end : start, swap ? start : end);
|
659
763
|
|
660
764
|
// And clean up
|
661
|
-
|
765
|
+
repeatCount = 0;
|
662
766
|
cm.setOption("keyMap", "vim");
|
663
767
|
};
|
664
768
|
|
665
769
|
CodeMirror.keyMap['vim-prefix-c'][key] = function(cm) {
|
666
770
|
var start = cm.getCursor();
|
667
|
-
var end =
|
771
|
+
var end = motion(cm, repeatCount ? repeatCount : 1, true);
|
668
772
|
|
669
773
|
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
|
670
774
|
pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
|
671
775
|
cm.replaceRange("", swap ? end : start, swap ? start : end);
|
672
776
|
|
673
|
-
|
777
|
+
repeatCount = 0;
|
674
778
|
cm.setOption('keyMap', 'vim-insert');
|
675
779
|
};
|
676
780
|
|
677
781
|
CodeMirror.keyMap['vim-prefix-y'][key] = function(cm) {
|
678
782
|
var start = cm.getCursor();
|
679
|
-
var end =
|
783
|
+
var end = motion(cm, repeatCount ? repeatCount : 1, true);
|
680
784
|
|
681
785
|
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
|
682
786
|
pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
|
683
787
|
|
684
|
-
|
788
|
+
repeatCount = 0;
|
685
789
|
cm.setOption("keyMap", "vim");
|
686
790
|
};
|
687
791
|
|
688
792
|
CodeMirror.keyMap['vim'][key] = function(cm) {
|
689
|
-
var cur =
|
793
|
+
var cur = motion(cm, repeatCount ? repeatCount : 1);
|
690
794
|
cm.setCursor(cur.line, cur.ch);
|
691
795
|
|
692
|
-
|
796
|
+
repeatCount = 0;
|
693
797
|
};
|
694
798
|
});
|
695
799
|
|
696
|
-
|
697
|
-
|
698
|
-
CodeMirror.keyMap[
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
reptTimes = (reptTimes * 10) + key;
|
706
|
-
};
|
707
|
-
CodeMirror.keyMap['vim-prefix-c'][key] = function (cm) {
|
708
|
-
reptTimes = (reptTimes * 10) + key;
|
800
|
+
function addCountBindings(keyMapName) {
|
801
|
+
// Add bindings for number keys
|
802
|
+
keyMap = CodeMirror.keyMap[keyMapName];
|
803
|
+
keyMap["0"] = function(cm) {
|
804
|
+
if (repeatCount > 0) {
|
805
|
+
pushRepeatCountDigit(0)(cm);
|
806
|
+
} else {
|
807
|
+
CodeMirror.commands.goLineStart(cm);
|
808
|
+
}
|
709
809
|
};
|
710
|
-
|
810
|
+
for (var i = 1; i < 10; ++i) {
|
811
|
+
keyMap[i] = pushRepeatCountDigit(i);
|
812
|
+
}
|
813
|
+
}
|
814
|
+
addCountBindings('vim');
|
815
|
+
addCountBindings('vim-prefix-d');
|
816
|
+
addCountBindings('vim-prefix-y');
|
817
|
+
addCountBindings('vim-prefix-c');
|
711
818
|
|
712
819
|
// Create our keymaps for each operator and make xa and xi where x is an operator
|
713
820
|
// change to the corrosponding keymap
|
@@ -721,12 +828,12 @@
|
|
721
828
|
};
|
722
829
|
|
723
830
|
CodeMirror.keyMap['vim-prefix-'+key]['A'] = function(cm) {
|
724
|
-
|
831
|
+
repeatCount = 0;
|
725
832
|
cm.setOption('keyMap', 'vim-prefix-' + key + 'a');
|
726
833
|
};
|
727
834
|
|
728
835
|
CodeMirror.keyMap['vim-prefix-'+key]['I'] = function(cm) {
|
729
|
-
|
836
|
+
repeatCount = 0;
|
730
837
|
cm.setOption('keyMap', 'vim-prefix-' + key + 'i');
|
731
838
|
};
|
732
839
|
});
|
@@ -739,7 +846,7 @@
|
|
739
846
|
|
740
847
|
// Create our text object functions. They work similar to motions but they
|
741
848
|
// return a start cursor as well
|
742
|
-
var textObjectList = ['W', 'Shift-[', 'Shift-9', '['];
|
849
|
+
var textObjectList = ['W', 'Shift-[', 'Shift-9', '[', "'", "Shift-'"];
|
743
850
|
var textObjects = {
|
744
851
|
'W': function(cm, inclusive) {
|
745
852
|
var cur = cm.getCursor();
|
@@ -754,7 +861,9 @@
|
|
754
861
|
},
|
755
862
|
'Shift-[': function(cm, inclusive) { return selectCompanionObject(cm, '}', inclusive); },
|
756
863
|
'Shift-9': function(cm, inclusive) { return selectCompanionObject(cm, ')', inclusive); },
|
757
|
-
'[': function(cm, inclusive) { return selectCompanionObject(cm, ']', inclusive); }
|
864
|
+
'[': function(cm, inclusive) { return selectCompanionObject(cm, ']', inclusive); },
|
865
|
+
"'": function(cm, inclusive) { return findBeginningAndEnd(cm, "'", inclusive); },
|
866
|
+
"Shift-'": function(cm, inclusive) { return findBeginningAndEnd(cm, '"', inclusive); }
|
758
867
|
};
|
759
868
|
|
760
869
|
// One function to handle all operation upon text objects. Kinda funky but it works
|