codemirror-rails 3.12 → 3.13
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.
- checksums.yaml +4 -4
- data/codemirror-rails.gemspec +1 -1
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +168 -116
- data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +144 -0
- data/vendor/assets/javascripts/codemirror/addons/display/placeholder.js +4 -4
- data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +2 -2
- data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +9 -3
- data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +13 -13
- data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.js +5 -1
- data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +13 -1
- data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +4 -4
- data/vendor/assets/javascripts/codemirror/addons/search/search.js +1 -1
- data/vendor/assets/javascripts/codemirror/addons/search/searchcursor.js +15 -5
- data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +6 -6
- data/vendor/assets/javascripts/codemirror/addons/selection/mark-selection.js +89 -15
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +451 -187
- data/vendor/assets/javascripts/codemirror/modes/clike.js +6 -3
- data/vendor/assets/javascripts/codemirror/modes/clojure.js +3 -1
- data/vendor/assets/javascripts/codemirror/modes/cobol.js +240 -0
- data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +5 -1
- data/vendor/assets/javascripts/codemirror/modes/css.js +63 -24
- data/vendor/assets/javascripts/codemirror/modes/erlang.js +3 -2
- data/vendor/assets/javascripts/codemirror/modes/gas.js +5 -1
- data/vendor/assets/javascripts/codemirror/modes/go.js +4 -1
- data/vendor/assets/javascripts/codemirror/modes/haml.js +153 -0
- data/vendor/assets/javascripts/codemirror/modes/haskell.js +5 -1
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +5 -1
- data/vendor/assets/javascripts/codemirror/modes/less.js +0 -8
- data/vendor/assets/javascripts/codemirror/modes/lua.js +5 -1
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/ocaml.js +4 -1
- data/vendor/assets/javascripts/codemirror/modes/php.js +3 -0
- data/vendor/assets/javascripts/codemirror/modes/python.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/rust.js +4 -1
- data/vendor/assets/javascripts/codemirror/modes/sass.js +8 -27
- data/vendor/assets/javascripts/codemirror/modes/scheme.js +3 -1
- data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +6 -4
- data/vendor/assets/javascripts/codemirror/modes/sql.js +3 -4
- data/vendor/assets/javascripts/codemirror/modes/stex.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/xml.js +2 -0
- data/vendor/assets/javascripts/codemirror/modes/yaml.js +3 -1
- data/vendor/assets/stylesheets/codemirror.css +7 -4
- data/vendor/assets/stylesheets/codemirror/addons/lint/lint.css +3 -3
- data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +1 -1
- metadata +14 -6
- data/vendor/assets/javascripts/codemirror/modes/test.js +0 -64
@@ -58,36 +58,36 @@
|
|
58
58
|
var defaultKeymap = [
|
59
59
|
// Key to key mapping. This goes first to make it possible to override
|
60
60
|
// existing mappings.
|
61
|
-
{ keys: ['Left'], type: 'keyToKey', toKeys: ['h'] },
|
62
|
-
{ keys: ['Right'], type: 'keyToKey', toKeys: ['l'] },
|
63
|
-
{ keys: ['Up'], type: 'keyToKey', toKeys: ['k'] },
|
64
|
-
{ keys: ['Down'], type: 'keyToKey', toKeys: ['j'] },
|
65
|
-
{ keys: ['Space'], type: 'keyToKey', toKeys: ['l'] },
|
66
|
-
{ keys: ['
|
67
|
-
{ keys: ['
|
68
|
-
{ keys: ['
|
69
|
-
{ keys: ['
|
70
|
-
{ keys: ['
|
71
|
-
{ keys: ['
|
72
|
-
{ keys: ['
|
73
|
-
{ keys: ['
|
74
|
-
{ keys: ['
|
61
|
+
{ keys: ['<Left>'], type: 'keyToKey', toKeys: ['h'] },
|
62
|
+
{ keys: ['<Right>'], type: 'keyToKey', toKeys: ['l'] },
|
63
|
+
{ keys: ['<Up>'], type: 'keyToKey', toKeys: ['k'] },
|
64
|
+
{ keys: ['<Down>'], type: 'keyToKey', toKeys: ['j'] },
|
65
|
+
{ keys: ['<Space>'], type: 'keyToKey', toKeys: ['l'] },
|
66
|
+
{ keys: ['<BS>'], type: 'keyToKey', toKeys: ['h'] },
|
67
|
+
{ keys: ['<C-Space>'], type: 'keyToKey', toKeys: ['W'] },
|
68
|
+
{ keys: ['<C-BS>'], type: 'keyToKey', toKeys: ['B'] },
|
69
|
+
{ keys: ['<S-Space>'], type: 'keyToKey', toKeys: ['w'] },
|
70
|
+
{ keys: ['<S-BS>'], type: 'keyToKey', toKeys: ['b'] },
|
71
|
+
{ keys: ['<C-n>'], type: 'keyToKey', toKeys: ['j'] },
|
72
|
+
{ keys: ['<C-p>'], type: 'keyToKey', toKeys: ['k'] },
|
73
|
+
{ keys: ['C-['], type: 'keyToKey', toKeys: ['<Esc>'] },
|
74
|
+
{ keys: ['<C-c>'], type: 'keyToKey', toKeys: ['<Esc>'] },
|
75
75
|
{ keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'] },
|
76
76
|
{ keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'] },
|
77
|
-
{ keys: ['Home'], type: 'keyToKey', toKeys: ['0'] },
|
78
|
-
{ keys: ['End'], type: 'keyToKey', toKeys: ['$'] },
|
79
|
-
{ keys: ['PageUp'], type: 'keyToKey', toKeys: ['
|
80
|
-
{ keys: ['PageDown'], type: 'keyToKey', toKeys: ['
|
77
|
+
{ keys: ['<Home>'], type: 'keyToKey', toKeys: ['0'] },
|
78
|
+
{ keys: ['<End>'], type: 'keyToKey', toKeys: ['$'] },
|
79
|
+
{ keys: ['<PageUp>'], type: 'keyToKey', toKeys: ['<C-b>'] },
|
80
|
+
{ keys: ['<PageDown>'], type: 'keyToKey', toKeys: ['<C-f>'] },
|
81
81
|
// Motions
|
82
82
|
{ keys: ['H'], type: 'motion',
|
83
83
|
motion: 'moveToTopLine',
|
84
|
-
motionArgs: { linewise: true }},
|
84
|
+
motionArgs: { linewise: true, toJumplist: true }},
|
85
85
|
{ keys: ['M'], type: 'motion',
|
86
86
|
motion: 'moveToMiddleLine',
|
87
|
-
motionArgs: { linewise: true }},
|
87
|
+
motionArgs: { linewise: true, toJumplist: true }},
|
88
88
|
{ keys: ['L'], type: 'motion',
|
89
89
|
motion: 'moveToBottomLine',
|
90
|
-
motionArgs: { linewise: true }},
|
90
|
+
motionArgs: { linewise: true, toJumplist: true }},
|
91
91
|
{ keys: ['h'], type: 'motion',
|
92
92
|
motion: 'moveByCharacters',
|
93
93
|
motionArgs: { forward: false }},
|
@@ -133,25 +133,25 @@
|
|
133
133
|
motionArgs: { forward: false, wordEnd: true, bigWord: true,
|
134
134
|
inclusive: true }},
|
135
135
|
{ keys: ['{'], type: 'motion', motion: 'moveByParagraph',
|
136
|
-
motionArgs: { forward: false }},
|
136
|
+
motionArgs: { forward: false, toJumplist: true }},
|
137
137
|
{ keys: ['}'], type: 'motion', motion: 'moveByParagraph',
|
138
|
-
motionArgs: { forward: true }},
|
139
|
-
{ keys: ['
|
138
|
+
motionArgs: { forward: true, toJumplist: true }},
|
139
|
+
{ keys: ['<C-f>'], type: 'motion',
|
140
140
|
motion: 'moveByPage', motionArgs: { forward: true }},
|
141
|
-
{ keys: ['
|
141
|
+
{ keys: ['<C-b>'], type: 'motion',
|
142
142
|
motion: 'moveByPage', motionArgs: { forward: false }},
|
143
|
-
{ keys: ['
|
143
|
+
{ keys: ['<C-d>'], type: 'motion',
|
144
144
|
motion: 'moveByScroll',
|
145
145
|
motionArgs: { forward: true, explicitRepeat: true }},
|
146
|
-
{ keys: ['
|
146
|
+
{ keys: ['<C-u>'], type: 'motion',
|
147
147
|
motion: 'moveByScroll',
|
148
148
|
motionArgs: { forward: false, explicitRepeat: true }},
|
149
149
|
{ keys: ['g', 'g'], type: 'motion',
|
150
150
|
motion: 'moveToLineOrEdgeOfDocument',
|
151
|
-
motionArgs: { forward: false, explicitRepeat: true, linewise: true }},
|
151
|
+
motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }},
|
152
152
|
{ keys: ['G'], type: 'motion',
|
153
153
|
motion: 'moveToLineOrEdgeOfDocument',
|
154
|
-
motionArgs: { forward: true, explicitRepeat: true, linewise: true }},
|
154
|
+
motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }},
|
155
155
|
{ keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' },
|
156
156
|
{ keys: ['^'], type: 'motion',
|
157
157
|
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
@@ -169,7 +169,7 @@
|
|
169
169
|
motionArgs: { inclusive: true }},
|
170
170
|
{ keys: ['%'], type: 'motion',
|
171
171
|
motion: 'moveToMatchedSymbol',
|
172
|
-
motionArgs: { inclusive: true }},
|
172
|
+
motionArgs: { inclusive: true, toJumplist: true }},
|
173
173
|
{ keys: ['f', 'character'], type: 'motion',
|
174
174
|
motion: 'moveToCharacter',
|
175
175
|
motionArgs: { forward: true , inclusive: true }},
|
@@ -186,18 +186,20 @@
|
|
186
186
|
motionArgs: { forward: true }},
|
187
187
|
{ keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch',
|
188
188
|
motionArgs: { forward: false }},
|
189
|
-
{ keys: ['\'', 'character'], type: 'motion', motion: 'goToMark'
|
190
|
-
|
189
|
+
{ keys: ['\'', 'character'], type: 'motion', motion: 'goToMark',
|
190
|
+
motionArgs: {toJumplist: true}},
|
191
|
+
{ keys: ['`', 'character'], type: 'motion', motion: 'goToMark',
|
192
|
+
motionArgs: {toJumplist: true}},
|
191
193
|
{ keys: [']', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
|
192
194
|
{ keys: ['[', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
|
193
195
|
{ keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
|
194
196
|
{ keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
|
195
197
|
{ keys: [']', 'character'], type: 'motion',
|
196
198
|
motion: 'moveToSymbol',
|
197
|
-
motionArgs: { forward: true}},
|
199
|
+
motionArgs: { forward: true, toJumplist: true}},
|
198
200
|
{ keys: ['[', 'character'], type: 'motion',
|
199
201
|
motion: 'moveToSymbol',
|
200
|
-
motionArgs: { forward: false}},
|
202
|
+
motionArgs: { forward: false, toJumplist: true}},
|
201
203
|
{ keys: ['|'], type: 'motion',
|
202
204
|
motion: 'moveToColumn',
|
203
205
|
motionArgs: { }},
|
@@ -212,9 +214,9 @@
|
|
212
214
|
operatorArgs: { indentRight: false }},
|
213
215
|
{ keys: ['g', '~'], type: 'operator', operator: 'swapcase' },
|
214
216
|
{ keys: ['n'], type: 'motion', motion: 'findNext',
|
215
|
-
motionArgs: { forward: true }},
|
217
|
+
motionArgs: { forward: true, toJumplist: true }},
|
216
218
|
{ keys: ['N'], type: 'motion', motion: 'findNext',
|
217
|
-
motionArgs: { forward: false }},
|
219
|
+
motionArgs: { forward: false, toJumplist: true }},
|
218
220
|
// Operator-Motion dual commands
|
219
221
|
{ keys: ['x'], type: 'operatorMotion', operator: 'delete',
|
220
222
|
motion: 'moveByCharacters', motionArgs: { forward: true },
|
@@ -235,13 +237,18 @@
|
|
235
237
|
{ keys: ['~'], type: 'operatorMotion', operator: 'swapcase',
|
236
238
|
motion: 'moveByCharacters', motionArgs: { forward: true }},
|
237
239
|
// Actions
|
240
|
+
{ keys: ['<C-i>'], type: 'action', action: 'jumpListWalk',
|
241
|
+
actionArgs: { forward: true }},
|
242
|
+
{ keys: ['<C-o>'], type: 'action', action: 'jumpListWalk',
|
243
|
+
actionArgs: { forward: false }},
|
238
244
|
{ keys: ['a'], type: 'action', action: 'enterInsertMode',
|
239
245
|
actionArgs: { insertAt: 'charAfter' }},
|
240
246
|
{ keys: ['A'], type: 'action', action: 'enterInsertMode',
|
241
247
|
actionArgs: { insertAt: 'eol' }},
|
242
|
-
{ keys: ['i'], type: 'action', action: 'enterInsertMode'
|
248
|
+
{ keys: ['i'], type: 'action', action: 'enterInsertMode',
|
249
|
+
actionArgs: { insertAt: 'inplace' }},
|
243
250
|
{ keys: ['I'], type: 'action', action: 'enterInsertMode',
|
244
|
-
|
251
|
+
actionArgs: { insertAt: 'firstNonBlank' }},
|
245
252
|
{ keys: ['o'], type: 'action', action: 'newLineAndEnterInsertMode',
|
246
253
|
actionArgs: { after: true }},
|
247
254
|
{ keys: ['O'], type: 'action', action: 'newLineAndEnterInsertMode',
|
@@ -255,8 +262,11 @@
|
|
255
262
|
{ keys: ['P'], type: 'action', action: 'paste',
|
256
263
|
actionArgs: { after: false }},
|
257
264
|
{ keys: ['r', 'character'], type: 'action', action: 'replace' },
|
265
|
+
{ keys: ['@', 'character'], type: 'action', action: 'replayMacro' },
|
266
|
+
{ keys: ['q', 'character'], type: 'action', action: 'enterMacroRecordMode' },
|
267
|
+
{ keys: ['R'], type: 'action', action: 'enterReplaceMode' },
|
258
268
|
{ keys: ['u'], type: 'action', action: 'undo' },
|
259
|
-
{ keys: ['
|
269
|
+
{ keys: ['<C-r>'], type: 'action', action: 'redo' },
|
260
270
|
{ keys: ['m', 'character'], type: 'action', action: 'setMark' },
|
261
271
|
{ keys: ['\"', 'character'], type: 'action', action: 'setRegister' },
|
262
272
|
{ keys: ['z', 'z'], type: 'action', action: 'scrollToCursor',
|
@@ -266,7 +276,7 @@
|
|
266
276
|
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
267
277
|
{ keys: ['z', 't'], type: 'action', action: 'scrollToCursor',
|
268
278
|
actionArgs: { position: 'top' }},
|
269
|
-
{ keys: ['z', '
|
279
|
+
{ keys: ['z', '<CR>'], type: 'action', action: 'scrollToCursor',
|
270
280
|
actionArgs: { position: 'top' },
|
271
281
|
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
272
282
|
{ keys: ['z', '-'], type: 'action', action: 'scrollToCursor',
|
@@ -275,9 +285,9 @@
|
|
275
285
|
actionArgs: { position: 'bottom' },
|
276
286
|
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
277
287
|
{ keys: ['.'], type: 'action', action: 'repeatLastEdit' },
|
278
|
-
{ keys: ['
|
288
|
+
{ keys: ['<C-a>'], type: 'action', action: 'incrementNumberToken',
|
279
289
|
actionArgs: {increase: true, backtrack: false}},
|
280
|
-
{ keys: ['
|
290
|
+
{ keys: ['<C-x>'], type: 'action', action: 'incrementNumberToken',
|
281
291
|
actionArgs: {increase: false, backtrack: false}},
|
282
292
|
// Text object motions
|
283
293
|
{ keys: ['a', 'character'], type: 'motion',
|
@@ -287,13 +297,13 @@
|
|
287
297
|
motionArgs: { textObjectInner: true }},
|
288
298
|
// Search
|
289
299
|
{ keys: ['/'], type: 'search',
|
290
|
-
searchArgs: { forward: true, querySrc: 'prompt' }},
|
300
|
+
searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }},
|
291
301
|
{ keys: ['?'], type: 'search',
|
292
|
-
searchArgs: { forward: false, querySrc: 'prompt' }},
|
302
|
+
searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }},
|
293
303
|
{ keys: ['*'], type: 'search',
|
294
|
-
searchArgs: { forward: true, querySrc: 'wordUnderCursor' }},
|
304
|
+
searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }},
|
295
305
|
{ keys: ['#'], type: 'search',
|
296
|
-
searchArgs: { forward: false, querySrc: 'wordUnderCursor' }},
|
306
|
+
searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }},
|
297
307
|
// Ex command
|
298
308
|
{ keys: [':'], type: 'ex' }
|
299
309
|
];
|
@@ -361,6 +371,91 @@
|
|
361
371
|
return false;
|
362
372
|
}
|
363
373
|
|
374
|
+
var createCircularJumpList = function() {
|
375
|
+
var size = 100;
|
376
|
+
var pointer = -1;
|
377
|
+
var head = 0;
|
378
|
+
var tail = 0;
|
379
|
+
var buffer = new Array(size);
|
380
|
+
function add(cm, oldCur, newCur) {
|
381
|
+
var current = pointer % size;
|
382
|
+
var curMark = buffer[current];
|
383
|
+
function useNextSlot(cursor) {
|
384
|
+
var next = ++pointer % size;
|
385
|
+
var trashMark = buffer[next];
|
386
|
+
if (trashMark) {
|
387
|
+
trashMark.clear();
|
388
|
+
}
|
389
|
+
buffer[next] = cm.setBookmark(cursor);
|
390
|
+
}
|
391
|
+
if (curMark) {
|
392
|
+
var markPos = curMark.find();
|
393
|
+
// avoid recording redundant cursor position
|
394
|
+
if (markPos && !cursorEqual(markPos, oldCur)) {
|
395
|
+
useNextSlot(oldCur);
|
396
|
+
}
|
397
|
+
} else {
|
398
|
+
useNextSlot(oldCur);
|
399
|
+
}
|
400
|
+
useNextSlot(newCur);
|
401
|
+
head = pointer;
|
402
|
+
tail = pointer - size + 1;
|
403
|
+
if (tail < 0) {
|
404
|
+
tail = 0;
|
405
|
+
}
|
406
|
+
}
|
407
|
+
function move(cm, offset) {
|
408
|
+
pointer += offset;
|
409
|
+
if (pointer > head) {
|
410
|
+
pointer = head;
|
411
|
+
} else if (pointer < tail) {
|
412
|
+
pointer = tail;
|
413
|
+
}
|
414
|
+
var mark = buffer[(size + pointer) % size];
|
415
|
+
// skip marks that are temporarily removed from text buffer
|
416
|
+
if (mark && !mark.find()) {
|
417
|
+
var inc = offset > 0 ? 1 : -1;
|
418
|
+
var newCur;
|
419
|
+
var oldCur = cm.getCursor();
|
420
|
+
do {
|
421
|
+
pointer += inc;
|
422
|
+
mark = buffer[(size + pointer) % size];
|
423
|
+
// skip marks that are the same as current position
|
424
|
+
if (mark &&
|
425
|
+
(newCur = mark.find()) &&
|
426
|
+
!cursorEqual(oldCur, newCur)) {
|
427
|
+
break;
|
428
|
+
}
|
429
|
+
} while (pointer < head && pointer > tail);
|
430
|
+
}
|
431
|
+
return mark;
|
432
|
+
}
|
433
|
+
return {
|
434
|
+
cachedCursor: undefined, //used for # and * jumps
|
435
|
+
add: add,
|
436
|
+
move: move
|
437
|
+
};
|
438
|
+
};
|
439
|
+
|
440
|
+
var createMacroState = function() {
|
441
|
+
return {
|
442
|
+
macroKeyBuffer: [],
|
443
|
+
latestRegister: undefined,
|
444
|
+
enteredMacroMode: undefined,
|
445
|
+
isMacroPlaying: false,
|
446
|
+
toggle: function(cm, registerName) {
|
447
|
+
if (this.enteredMacroMode) { //onExit
|
448
|
+
this.enteredMacroMode(); // close dialog
|
449
|
+
this.enteredMacroMode = undefined;
|
450
|
+
} else { //onEnter
|
451
|
+
this.latestRegister = registerName;
|
452
|
+
this.enteredMacroMode = cm.openDialog(
|
453
|
+
'(recording)['+registerName+']', null, {bottom:true});
|
454
|
+
}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
|
364
459
|
// Global Vim state. Call getVimGlobalState to get and initialize.
|
365
460
|
var vimGlobalState;
|
366
461
|
function getVimGlobalState() {
|
@@ -370,6 +465,8 @@
|
|
370
465
|
searchQuery: null,
|
371
466
|
// Whether we are searching backwards.
|
372
467
|
searchIsReversed: false,
|
468
|
+
jumpList: createCircularJumpList(),
|
469
|
+
macroModeState: createMacroState(),
|
373
470
|
// Recording latest f, t, F or T motion command.
|
374
471
|
lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
|
375
472
|
registerController: new RegisterController({})
|
@@ -435,7 +532,15 @@
|
|
435
532
|
handleKey: function(cm, key) {
|
436
533
|
var command;
|
437
534
|
var vim = getVimState(cm);
|
438
|
-
|
535
|
+
var macroModeState = getVimGlobalState().macroModeState;
|
536
|
+
if (macroModeState.enteredMacroMode) {
|
537
|
+
if (key == 'q') {
|
538
|
+
actions.exitMacroRecordMode();
|
539
|
+
return;
|
540
|
+
}
|
541
|
+
logKey(macroModeState, key);
|
542
|
+
}
|
543
|
+
if (key == '<Esc>') {
|
439
544
|
// Clear input state and get back to normal mode.
|
440
545
|
vim.inputState = new InputState();
|
441
546
|
if (vim.visualMode) {
|
@@ -597,6 +702,9 @@
|
|
597
702
|
this.unamedRegister.set(text, linewise);
|
598
703
|
}
|
599
704
|
},
|
705
|
+
setRegisterText: function(name, text, linewise) {
|
706
|
+
this.getRegister(name).set(text, linewise);
|
707
|
+
},
|
600
708
|
// Gets the register named @name. If one of @name doesn't already exist,
|
601
709
|
// create it. If @name is invalid, return the unamedRegister.
|
602
710
|
getRegister: function(name) {
|
@@ -643,10 +751,10 @@
|
|
643
751
|
inputState.selectedCharacter = keys[keys.length - 1];
|
644
752
|
if(inputState.selectedCharacter.length>1){
|
645
753
|
switch(inputState.selectedCharacter){
|
646
|
-
case "
|
754
|
+
case "<CR>":
|
647
755
|
inputState.selectedCharacter='\n';
|
648
756
|
break;
|
649
|
-
case "Space":
|
757
|
+
case "<Space>":
|
650
758
|
inputState.selectedCharacter=' ';
|
651
759
|
break;
|
652
760
|
default:
|
@@ -769,13 +877,13 @@
|
|
769
877
|
try {
|
770
878
|
updateSearchQuery(cm, query, ignoreCase, smartCase);
|
771
879
|
} catch (e) {
|
772
|
-
showConfirm(cm, 'Invalid regex: ' +
|
880
|
+
showConfirm(cm, 'Invalid regex: ' + query);
|
773
881
|
return;
|
774
882
|
}
|
775
883
|
commandDispatcher.processMotion(cm, vim, {
|
776
884
|
type: 'motion',
|
777
885
|
motion: 'findNext',
|
778
|
-
motionArgs: { forward: true }
|
886
|
+
motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist }
|
779
887
|
});
|
780
888
|
}
|
781
889
|
function onPromptClose(query) {
|
@@ -834,13 +942,19 @@
|
|
834
942
|
return;
|
835
943
|
}
|
836
944
|
var query = cm.getLine(word.start.line).substring(word.start.ch,
|
837
|
-
word.end.ch
|
945
|
+
word.end.ch);
|
838
946
|
if (isKeyword) {
|
839
947
|
query = '\\b' + query + '\\b';
|
840
948
|
} else {
|
841
949
|
query = escapeRegex(query);
|
842
950
|
}
|
951
|
+
|
952
|
+
// cachedCursor is used to save the old position of the cursor
|
953
|
+
// when * or # causes vim to seek for the nearest word and shift
|
954
|
+
// the cursor before entering the motion.
|
955
|
+
getVimGlobalState().jumpList.cachedCursor = cm.getCursor();
|
843
956
|
cm.setCursor(word.start);
|
957
|
+
|
844
958
|
handleQuery(query, true /** ignoreCase */, false /** smartCase */);
|
845
959
|
break;
|
846
960
|
}
|
@@ -917,6 +1031,17 @@
|
|
917
1031
|
if (!motionResult) {
|
918
1032
|
return;
|
919
1033
|
}
|
1034
|
+
if (motionArgs.toJumplist) {
|
1035
|
+
var jumpList = getVimGlobalState().jumpList;
|
1036
|
+
// if the current motion is # or *, use cachedCursor
|
1037
|
+
var cachedCursor = jumpList.cachedCursor;
|
1038
|
+
if (cachedCursor) {
|
1039
|
+
recordJumpPosition(cm, cachedCursor, motionResult);
|
1040
|
+
delete jumpList.cachedCursor;
|
1041
|
+
} else {
|
1042
|
+
recordJumpPosition(cm, curOriginal, motionResult);
|
1043
|
+
}
|
1044
|
+
}
|
920
1045
|
if (motionResult instanceof Array) {
|
921
1046
|
curStart = motionResult[0];
|
922
1047
|
curEnd = motionResult[1];
|
@@ -992,7 +1117,7 @@
|
|
992
1117
|
// Expand selection to entire line.
|
993
1118
|
expandSelectionToLine(cm, curStart, curEnd);
|
994
1119
|
} else if (motionArgs.forward) {
|
995
|
-
// Clip to trailing newlines only if
|
1120
|
+
// Clip to trailing newlines only if the motion goes forward.
|
996
1121
|
clipToLine(cm, curStart, curEnd);
|
997
1122
|
}
|
998
1123
|
operatorArgs.registerName = registerName;
|
@@ -1077,7 +1202,7 @@
|
|
1077
1202
|
}
|
1078
1203
|
|
1079
1204
|
var equal = cursorEqual(cursor, best);
|
1080
|
-
var between = (motionArgs.forward) ?
|
1205
|
+
var between = (motionArgs.forward) ?
|
1081
1206
|
cusrorIsBetween(cursor, mark, best) :
|
1082
1207
|
cusrorIsBetween(best, mark, cursor);
|
1083
1208
|
|
@@ -1255,9 +1380,24 @@
|
|
1255
1380
|
},
|
1256
1381
|
moveToMatchedSymbol: function(cm, motionArgs) {
|
1257
1382
|
var cursor = cm.getCursor();
|
1258
|
-
var
|
1259
|
-
|
1260
|
-
|
1383
|
+
var line = cursor.line;
|
1384
|
+
var ch = cursor.ch;
|
1385
|
+
var lineText = cm.getLine(line);
|
1386
|
+
var symbol;
|
1387
|
+
var startContext = cm.getTokenAt(cursor).type;
|
1388
|
+
var startCtxLevel = getContextLevel(startContext);
|
1389
|
+
do {
|
1390
|
+
symbol = lineText.charAt(ch++);
|
1391
|
+
if (symbol && isMatchableSymbol(symbol)) {
|
1392
|
+
var endContext = cm.getTokenAt({line:line, ch:ch}).type;
|
1393
|
+
var endCtxLevel = getContextLevel(endContext);
|
1394
|
+
if (startCtxLevel >= endCtxLevel) {
|
1395
|
+
break;
|
1396
|
+
}
|
1397
|
+
}
|
1398
|
+
} while (symbol);
|
1399
|
+
if (symbol) {
|
1400
|
+
return findMatchedSymbol(cm, {line:line, ch:ch-1}, symbol);
|
1261
1401
|
} else {
|
1262
1402
|
return cursor;
|
1263
1403
|
}
|
@@ -1383,24 +1523,58 @@
|
|
1383
1523
|
};
|
1384
1524
|
|
1385
1525
|
var actions = {
|
1526
|
+
jumpListWalk: function(cm, actionArgs, vim) {
|
1527
|
+
if (vim.visualMode) {
|
1528
|
+
return;
|
1529
|
+
}
|
1530
|
+
var repeat = actionArgs.repeat;
|
1531
|
+
var forward = actionArgs.forward;
|
1532
|
+
var jumpList = getVimGlobalState().jumpList;
|
1533
|
+
|
1534
|
+
var mark = jumpList.move(cm, forward ? repeat : -repeat);
|
1535
|
+
var markPos = mark ? mark.find() : undefined;
|
1536
|
+
markPos = markPos ? markPos : cm.getCursor();
|
1537
|
+
cm.setCursor(markPos);
|
1538
|
+
},
|
1386
1539
|
scrollToCursor: function(cm, actionArgs) {
|
1387
1540
|
var lineNum = cm.getCursor().line;
|
1388
|
-
var
|
1389
|
-
|
1390
|
-
var
|
1391
|
-
var
|
1392
|
-
var halfHeight = parseInt(height) / 2;
|
1541
|
+
var charCoords = cm.charCoords({line: lineNum, ch: 0}, "local");
|
1542
|
+
var height = cm.getScrollInfo().clientHeight;
|
1543
|
+
var y = charCoords.top;
|
1544
|
+
var lineHeight = charCoords.bottom - y;
|
1393
1545
|
switch (actionArgs.position) {
|
1394
|
-
case 'center': y = y - (height / 2) +
|
1395
|
-
|
1396
|
-
case 'bottom': y = y - height;
|
1397
|
-
|
1398
|
-
case 'top':
|
1546
|
+
case 'center': y = y - (height / 2) + lineHeight;
|
1547
|
+
break;
|
1548
|
+
case 'bottom': y = y - height + lineHeight*1.4;
|
1549
|
+
break;
|
1550
|
+
case 'top': y = y + lineHeight*0.4;
|
1551
|
+
break;
|
1399
1552
|
}
|
1400
1553
|
cm.scrollTo(null, y);
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1554
|
+
},
|
1555
|
+
replayMacro: function(cm, actionArgs) {
|
1556
|
+
var registerName = actionArgs.selectedCharacter;
|
1557
|
+
var repeat = actionArgs.repeat;
|
1558
|
+
var macroModeState = getVimGlobalState().macroModeState;
|
1559
|
+
if (registerName == '@') {
|
1560
|
+
registerName = macroModeState.latestRegister;
|
1561
|
+
}
|
1562
|
+
var keyBuffer = parseRegisterToKeyBuffer(macroModeState, registerName);
|
1563
|
+
while(repeat--){
|
1564
|
+
executeMacroKeyBuffer(cm, macroModeState, keyBuffer);
|
1565
|
+
}
|
1566
|
+
},
|
1567
|
+
exitMacroRecordMode: function(cm, actionArgs) {
|
1568
|
+
var macroModeState = getVimGlobalState().macroModeState;
|
1569
|
+
macroModeState.toggle();
|
1570
|
+
parseKeyBufferToRegister(macroModeState.latestRegister,
|
1571
|
+
macroModeState.macroKeyBuffer);
|
1572
|
+
},
|
1573
|
+
enterMacroRecordMode: function(cm, actionArgs) {
|
1574
|
+
var macroModeState = getVimGlobalState().macroModeState;
|
1575
|
+
var registerName = actionArgs.selectedCharacter;
|
1576
|
+
macroModeState.toggle(cm, registerName);
|
1577
|
+
emptyMacroKeyBuffer(macroModeState);
|
1404
1578
|
},
|
1405
1579
|
enterInsertMode: function(cm, actionArgs) {
|
1406
1580
|
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
|
@@ -1410,6 +1584,8 @@
|
|
1410
1584
|
cm.setCursor(cursor);
|
1411
1585
|
} else if (insertAt == 'charAfter') {
|
1412
1586
|
cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
|
1587
|
+
} else if (insertAt == 'firstNonBlank') {
|
1588
|
+
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
1413
1589
|
}
|
1414
1590
|
cm.setOption('keyMap', 'vim-insert');
|
1415
1591
|
},
|
@@ -1605,6 +1781,10 @@
|
|
1605
1781
|
}
|
1606
1782
|
}
|
1607
1783
|
},
|
1784
|
+
enterReplaceMode: function(cm, actionArgs) {
|
1785
|
+
cm.setOption('keyMap', 'vim-replace');
|
1786
|
+
cm.toggleOverwrite();
|
1787
|
+
},
|
1608
1788
|
incrementNumberToken: function(cm, actionArgs, vim) {
|
1609
1789
|
var cur = cm.getCursor();
|
1610
1790
|
var lineStr = cm.getLine(cur.line);
|
@@ -1804,10 +1984,30 @@
|
|
1804
1984
|
// caret to the first character of the next line.
|
1805
1985
|
function clipToLine(cm, curStart, curEnd) {
|
1806
1986
|
var selection = cm.getRange(curStart, curEnd);
|
1807
|
-
|
1808
|
-
if (
|
1809
|
-
|
1810
|
-
|
1987
|
+
// Only clip if the selection ends with trailing newline + whitespace
|
1988
|
+
if (/\n\s*$/.test(selection)) {
|
1989
|
+
var lines = selection.split('\n');
|
1990
|
+
// We know this is all whitepsace.
|
1991
|
+
lines.pop();
|
1992
|
+
|
1993
|
+
// Cases:
|
1994
|
+
// 1. Last word is an empty line - do not clip the trailing '\n'
|
1995
|
+
// 2. Last word is not an empty line - clip the trailing '\n'
|
1996
|
+
var line;
|
1997
|
+
// Find the line containing the last word, and clip all whitespace up
|
1998
|
+
// to it.
|
1999
|
+
for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) {
|
2000
|
+
var clipped = false;
|
2001
|
+
curEnd.line--;
|
2002
|
+
curEnd.ch = 0;
|
2003
|
+
}
|
2004
|
+
// If the last word is not an empty line, clip an additional newline
|
2005
|
+
if (line) {
|
2006
|
+
curEnd.line--;
|
2007
|
+
curEnd.ch = lineLength(cm, curEnd.line);
|
2008
|
+
} else {
|
2009
|
+
curEnd.ch = 0;
|
2010
|
+
}
|
1811
2011
|
}
|
1812
2012
|
}
|
1813
2013
|
|
@@ -1861,21 +2061,39 @@
|
|
1861
2061
|
|
1862
2062
|
var wordAfterRegex = matchRegex.exec(textAfterIdx);
|
1863
2063
|
var wordStart = idx;
|
1864
|
-
var wordEnd = idx + wordAfterRegex[0].length
|
2064
|
+
var wordEnd = idx + wordAfterRegex[0].length;
|
1865
2065
|
// TODO: Find a better way to do this. It will be slow on very long lines.
|
1866
|
-
var
|
2066
|
+
var revTextBeforeIdx = reverse(textBeforeIdx);
|
2067
|
+
var wordBeforeRegex = matchRegex.exec(revTextBeforeIdx);
|
1867
2068
|
if (wordBeforeRegex) {
|
1868
2069
|
wordStart -= wordBeforeRegex[0].length;
|
1869
2070
|
}
|
1870
2071
|
|
1871
2072
|
if (inclusive) {
|
1872
|
-
|
2073
|
+
// If present, trim all whitespace after word.
|
2074
|
+
// Otherwise, trim all whitespace before word.
|
2075
|
+
var textAfterWordEnd = line.substring(wordEnd);
|
2076
|
+
var whitespacesAfterWord = textAfterWordEnd.match(/^\s*/)[0].length;
|
2077
|
+
if (whitespacesAfterWord > 0) {
|
2078
|
+
wordEnd += whitespacesAfterWord;
|
2079
|
+
} else {
|
2080
|
+
var revTrim = revTextBeforeIdx.length - wordStart;
|
2081
|
+
var textBeforeWordStart = revTextBeforeIdx.substring(revTrim);
|
2082
|
+
var whitespacesBeforeWord = textBeforeWordStart.match(/^\s*/)[0].length;
|
2083
|
+
wordStart -= whitespacesBeforeWord;
|
2084
|
+
}
|
1873
2085
|
}
|
1874
2086
|
|
1875
2087
|
return { start: { line: cur.line, ch: wordStart },
|
1876
2088
|
end: { line: cur.line, ch: wordEnd }};
|
1877
2089
|
}
|
1878
2090
|
|
2091
|
+
function recordJumpPosition(cm, oldCur, newCur) {
|
2092
|
+
if(!cursorEqual(oldCur, newCur)) {
|
2093
|
+
getVimGlobalState().jumpList.add(cm, oldCur, newCur);
|
2094
|
+
}
|
2095
|
+
}
|
2096
|
+
|
1879
2097
|
function recordLastCharacterSearch(increment, args) {
|
1880
2098
|
var vimGlobalState = getVimGlobalState();
|
1881
2099
|
vimGlobalState.lastChararacterSearch.increment = increment;
|
@@ -2016,18 +2234,31 @@
|
|
2016
2234
|
* backward.
|
2017
2235
|
* @param {boolean} bigWord True if punctuation count as part of the word.
|
2018
2236
|
* False if only [a-zA-Z0-9] characters count as part of the word.
|
2237
|
+
* @param {boolean} emptyLineIsWord True if empty lines should be treated
|
2238
|
+
* as words.
|
2019
2239
|
* @return {Object{from:number, to:number, line: number}} The boundaries of
|
2020
2240
|
* the word, or null if there are no more words.
|
2021
2241
|
*/
|
2022
|
-
|
2023
|
-
function findWord(cm, cur, forward, bigWord) {
|
2242
|
+
function findWord(cm, cur, forward, bigWord, emptyLineIsWord) {
|
2024
2243
|
var lineNum = cur.line;
|
2025
2244
|
var pos = cur.ch;
|
2026
2245
|
var line = cm.getLine(lineNum);
|
2027
2246
|
var dir = forward ? 1 : -1;
|
2028
2247
|
var regexps = bigWord ? bigWordRegexp : wordRegexp;
|
2029
2248
|
|
2249
|
+
if (emptyLineIsWord && line == '') {
|
2250
|
+
lineNum += dir;
|
2251
|
+
line = cm.getLine(lineNum);
|
2252
|
+
if (!isLine(cm, lineNum)) {
|
2253
|
+
return null;
|
2254
|
+
}
|
2255
|
+
pos = (forward) ? 0 : line.length;
|
2256
|
+
}
|
2257
|
+
|
2030
2258
|
while (true) {
|
2259
|
+
if (emptyLineIsWord && line == '') {
|
2260
|
+
return { from: 0, to: 0, line: lineNum };
|
2261
|
+
}
|
2031
2262
|
var stop = (dir > 0) ? line.length : -1;
|
2032
2263
|
var wordStart = stop, wordEnd = stop;
|
2033
2264
|
// Find bounds of next word.
|
@@ -2083,56 +2314,48 @@
|
|
2083
2314
|
*/
|
2084
2315
|
function moveToWord(cm, repeat, forward, wordEnd, bigWord) {
|
2085
2316
|
var cur = cm.getCursor();
|
2317
|
+
var curStart = copyCursor(cur);
|
2318
|
+
var words = [];
|
2319
|
+
if (forward && !wordEnd || !forward && wordEnd) {
|
2320
|
+
repeat++;
|
2321
|
+
}
|
2322
|
+
// For 'e', empty lines are not considered words, go figure.
|
2323
|
+
var emptyLineIsWord = !(forward && wordEnd);
|
2086
2324
|
for (var i = 0; i < repeat; i++) {
|
2087
|
-
var
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2097
|
-
|
2098
|
-
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2103
|
-
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2115
|
-
|
2116
|
-
|
2117
|
-
|
2118
|
-
|
2119
|
-
|
2120
|
-
}
|
2121
|
-
} else if (!forward && !wordEnd) {
|
2122
|
-
// 'b'
|
2123
|
-
cur.ch = word.from;
|
2124
|
-
}
|
2125
|
-
} else {
|
2126
|
-
// No more words to be found. Move to the end.
|
2127
|
-
if (forward) {
|
2128
|
-
return { line: cur.line, ch: lineLength(cm, cur.line) };
|
2129
|
-
} else {
|
2130
|
-
return { line: cur.line, ch: 0 };
|
2131
|
-
}
|
2132
|
-
}
|
2133
|
-
}
|
2325
|
+
var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord);
|
2326
|
+
if (!word) {
|
2327
|
+
var eodCh = lineLength(cm, cm.lastLine());
|
2328
|
+
words.push(forward
|
2329
|
+
? {line: cm.lastLine(), from: eodCh, to: eodCh}
|
2330
|
+
: {line: 0, from: 0, to: 0});
|
2331
|
+
break;
|
2332
|
+
}
|
2333
|
+
words.push(word);
|
2334
|
+
cur = {line: word.line, ch: forward ? (word.to - 1) : word.from};
|
2335
|
+
}
|
2336
|
+
var shortCircuit = words.length != repeat;
|
2337
|
+
var firstWord = words[0];
|
2338
|
+
var lastWord = words.pop();
|
2339
|
+
if (forward && !wordEnd) {
|
2340
|
+
// w
|
2341
|
+
if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) {
|
2342
|
+
// We did not start in the middle of a word. Discard the extra word at the end.
|
2343
|
+
lastWord = words.pop();
|
2344
|
+
}
|
2345
|
+
return {line: lastWord.line, ch: lastWord.from};
|
2346
|
+
} else if (forward && wordEnd) {
|
2347
|
+
return {line: lastWord.line, ch: lastWord.to - 1};
|
2348
|
+
} else if (!forward && wordEnd) {
|
2349
|
+
// ge
|
2350
|
+
if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) {
|
2351
|
+
// We did not start in the middle of a word. Discard the extra word at the end.
|
2352
|
+
lastWord = words.pop();
|
2353
|
+
}
|
2354
|
+
return {line: lastWord.line, ch: lastWord.to};
|
2355
|
+
} else {
|
2356
|
+
// b
|
2357
|
+
return {line: lastWord.line, ch: lastWord.from};
|
2134
2358
|
}
|
2135
|
-
return cur;
|
2136
2359
|
}
|
2137
2360
|
|
2138
2361
|
function moveToCharacter(cm, repeat, forward, character) {
|
@@ -2188,9 +2411,17 @@
|
|
2188
2411
|
return idx;
|
2189
2412
|
}
|
2190
2413
|
|
2414
|
+
function getContextLevel(ctx) {
|
2415
|
+
return (ctx === 'string' || ctx === 'comment') ? 1 : 0;
|
2416
|
+
}
|
2417
|
+
|
2191
2418
|
function findMatchedSymbol(cm, cur, symb) {
|
2192
2419
|
var line = cur.line;
|
2193
|
-
|
2420
|
+
var ch = cur.ch;
|
2421
|
+
symb = symb ? symb : cm.getLine(line).charAt(ch);
|
2422
|
+
|
2423
|
+
var symbContext = cm.getTokenAt({line:line, ch:ch+1}).type;
|
2424
|
+
var symbCtxLevel = getContextLevel(symbContext);
|
2194
2425
|
|
2195
2426
|
var reverseSymb = ({
|
2196
2427
|
'(': ')', ')': '(',
|
@@ -2206,7 +2437,7 @@
|
|
2206
2437
|
// depending on which bracket we're matching
|
2207
2438
|
var increment = ({'(': 1, '{': 1, '[': 1})[symb] || -1;
|
2208
2439
|
var endLine = increment === 1 ? cm.lineCount() : -1;
|
2209
|
-
var depth = 1, nextCh = symb, index =
|
2440
|
+
var depth = 1, nextCh = symb, index = ch, lineText = cm.getLine(line);
|
2210
2441
|
// Simple search for closing paren--just count openings and closings till
|
2211
2442
|
// we find our match
|
2212
2443
|
// TODO: use info from CodeMirror to ignore closing brackets in comments
|
@@ -2225,10 +2456,14 @@
|
|
2225
2456
|
}
|
2226
2457
|
nextCh = lineText.charAt(index);
|
2227
2458
|
}
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2459
|
+
var revSymbContext = cm.getTokenAt({line:line, ch:index+1}).type;
|
2460
|
+
var revSymbCtxLevel = getContextLevel(revSymbContext);
|
2461
|
+
if (symbCtxLevel >= revSymbCtxLevel) {
|
2462
|
+
if (nextCh === symb) {
|
2463
|
+
depth++;
|
2464
|
+
} else if (nextCh === reverseSymb) {
|
2465
|
+
depth--;
|
2466
|
+
}
|
2232
2467
|
}
|
2233
2468
|
}
|
2234
2469
|
|
@@ -2352,7 +2587,7 @@
|
|
2352
2587
|
onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp });
|
2353
2588
|
}
|
2354
2589
|
else {
|
2355
|
-
|
2590
|
+
onClose(prompt(shortText, ""));
|
2356
2591
|
}
|
2357
2592
|
}
|
2358
2593
|
function findUnescapedSlashes(str) {
|
@@ -2479,7 +2714,7 @@
|
|
2479
2714
|
if (match[0].length == 0) {
|
2480
2715
|
// Matched empty string, skip to next.
|
2481
2716
|
stream.next();
|
2482
|
-
return;
|
2717
|
+
return "searching";
|
2483
2718
|
}
|
2484
2719
|
if (!stream.sol()) {
|
2485
2720
|
// Backtrack 1 to match \b
|
@@ -2515,12 +2750,11 @@
|
|
2515
2750
|
if (repeat === undefined) { repeat = 1; }
|
2516
2751
|
return cm.operation(function() {
|
2517
2752
|
var pos = cm.getCursor();
|
2518
|
-
if (!prev) {
|
2519
|
-
pos.ch += 1;
|
2520
|
-
}
|
2521
2753
|
var cursor = cm.getSearchCursor(query, pos);
|
2522
2754
|
for (var i = 0; i < repeat; i++) {
|
2523
|
-
|
2755
|
+
var found = cursor.find(prev);
|
2756
|
+
if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); }
|
2757
|
+
if (!found) {
|
2524
2758
|
// SearchCursor may have returned null because it hit EOF, wrap
|
2525
2759
|
// around and try again.
|
2526
2760
|
cursor = cm.getSearchCursor(query,
|
@@ -2751,41 +2985,14 @@
|
|
2751
2985
|
// Converts a key string sequence of the form a<C-w>bd<Left> into Vim's
|
2752
2986
|
// keymap representation.
|
2753
2987
|
function parseKeyString(str) {
|
2754
|
-
var
|
2988
|
+
var key, match;
|
2755
2989
|
var keys = [];
|
2756
|
-
while (
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
// Vim key notation here means desktop Vim key-notation.
|
2763
|
-
// See :help key-notation in desktop Vim.
|
2764
|
-
var vimKeyNotationStart = ++idx;
|
2765
|
-
while (str.charAt(idx++) != '>') {}
|
2766
|
-
var vimKeyNotation = str.substring(vimKeyNotationStart, idx - 1);
|
2767
|
-
var mod='';
|
2768
|
-
var match = (/^C-(.+)$/).exec(vimKeyNotation);
|
2769
|
-
if (match) {
|
2770
|
-
mod='Ctrl-';
|
2771
|
-
vimKeyNotation=match[1];
|
2772
|
-
}
|
2773
|
-
var key;
|
2774
|
-
switch (vimKeyNotation) {
|
2775
|
-
case 'BS':
|
2776
|
-
key = 'Backspace';
|
2777
|
-
break;
|
2778
|
-
case 'CR':
|
2779
|
-
key = 'Enter';
|
2780
|
-
break;
|
2781
|
-
case 'Del':
|
2782
|
-
key = 'Delete';
|
2783
|
-
break;
|
2784
|
-
default:
|
2785
|
-
key = vimKeyNotation;
|
2786
|
-
break;
|
2787
|
-
}
|
2788
|
-
keys.push(mod + key);
|
2990
|
+
while (str) {
|
2991
|
+
match = (/<\w+-.+?>|<\w+>|./).exec(str);
|
2992
|
+
if(match === null)break;
|
2993
|
+
key = match[0];
|
2994
|
+
str = str.substring(match.index + key.length);
|
2995
|
+
keys.push(key);
|
2789
2996
|
}
|
2790
2997
|
return keys;
|
2791
2998
|
}
|
@@ -2956,33 +3163,37 @@
|
|
2956
3163
|
* modifers.
|
2957
3164
|
*/
|
2958
3165
|
// TODO: Figure out a way to catch capslock.
|
2959
|
-
function
|
2960
|
-
|
3166
|
+
function cmKeyToVimKey(key, modifier) {
|
3167
|
+
var vimKey = key;
|
3168
|
+
if (isUpperCase(vimKey)) {
|
2961
3169
|
// Convert to lower case if shift is not the modifier since the key
|
2962
3170
|
// we get from CodeMirror is always upper case.
|
2963
3171
|
if (modifier == 'Shift') {
|
2964
3172
|
modifier = null;
|
2965
3173
|
}
|
2966
3174
|
else {
|
2967
|
-
|
3175
|
+
vimKey = vimKey.toLowerCase();
|
2968
3176
|
}
|
2969
3177
|
}
|
2970
3178
|
if (modifier) {
|
2971
3179
|
// Vim will parse modifier+key combination as a single key.
|
2972
|
-
|
3180
|
+
vimKey = modifier.charAt(0) + '-' + vimKey;
|
2973
3181
|
}
|
2974
|
-
|
3182
|
+
var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[vimKey];
|
3183
|
+
vimKey = specialKey ? specialKey : vimKey;
|
3184
|
+
vimKey = vimKey.length > 1 ? '<'+ vimKey + '>' : vimKey;
|
3185
|
+
return vimKey;
|
2975
3186
|
}
|
2976
3187
|
|
2977
3188
|
// Closure to bind CodeMirror, key, modifier.
|
2978
|
-
function keyMapper(
|
3189
|
+
function keyMapper(vimKey) {
|
2979
3190
|
return function(cm) {
|
2980
|
-
|
3191
|
+
vim.handleKey(cm, vimKey);
|
2981
3192
|
};
|
2982
3193
|
}
|
2983
3194
|
|
2984
3195
|
var modifiers = ['Shift', 'Ctrl'];
|
2985
|
-
var
|
3196
|
+
var cmToVimKeymap = {
|
2986
3197
|
'nofallthrough': true,
|
2987
3198
|
'style': 'fat-cursor'
|
2988
3199
|
};
|
@@ -2994,11 +3205,9 @@
|
|
2994
3205
|
// them.
|
2995
3206
|
key = "'" + key + "'";
|
2996
3207
|
}
|
2997
|
-
|
2998
|
-
|
2999
|
-
|
3000
|
-
keyMap[key] = keyMapper(keys[i]);
|
3001
|
-
}
|
3208
|
+
var vimKey = cmKeyToVimKey(keys[i], modifier);
|
3209
|
+
var cmKey = modifier ? modifier + '-' + key : key;
|
3210
|
+
cmToVimKeymap[cmKey] = keyMapper(vimKey);
|
3002
3211
|
}
|
3003
3212
|
}
|
3004
3213
|
bindKeys(upperCaseAlphabet);
|
@@ -3010,7 +3219,7 @@
|
|
3010
3219
|
bindKeys(numbers, 'Ctrl');
|
3011
3220
|
bindKeys(specialKeys);
|
3012
3221
|
bindKeys(specialKeys, 'Ctrl');
|
3013
|
-
return
|
3222
|
+
return cmToVimKeymap;
|
3014
3223
|
}
|
3015
3224
|
CodeMirror.keyMap.vim = buildVimKeyMap();
|
3016
3225
|
|
@@ -3035,6 +3244,61 @@
|
|
3035
3244
|
fallthrough: ['default']
|
3036
3245
|
};
|
3037
3246
|
|
3247
|
+
function parseRegisterToKeyBuffer(macroModeState, registerName) {
|
3248
|
+
var match, key;
|
3249
|
+
var register = getVimGlobalState().registerController.getRegister(registerName);
|
3250
|
+
var text = register.toString();
|
3251
|
+
var macroKeyBuffer = macroModeState.macroKeyBuffer;
|
3252
|
+
emptyMacroKeyBuffer(macroModeState);
|
3253
|
+
do {
|
3254
|
+
match = text.match(/<\w+-.+>|<\w+>|.|\n/);
|
3255
|
+
if(match === null)break;
|
3256
|
+
key = match[0];
|
3257
|
+
text = text.substring(match.index + key.length);
|
3258
|
+
macroKeyBuffer.push(key);
|
3259
|
+
} while (text);
|
3260
|
+
return macroKeyBuffer;
|
3261
|
+
}
|
3262
|
+
|
3263
|
+
function parseKeyBufferToRegister(registerName, keyBuffer) {
|
3264
|
+
var text = keyBuffer.join('');
|
3265
|
+
getVimGlobalState().registerController.setRegisterText(registerName, text);
|
3266
|
+
}
|
3267
|
+
|
3268
|
+
function emptyMacroKeyBuffer(macroModeState) {
|
3269
|
+
if(macroModeState.isMacroPlaying)return;
|
3270
|
+
var macroKeyBuffer = macroModeState.macroKeyBuffer;
|
3271
|
+
macroKeyBuffer.length = 0;
|
3272
|
+
}
|
3273
|
+
|
3274
|
+
function executeMacroKeyBuffer(cm, macroModeState, keyBuffer) {
|
3275
|
+
macroModeState.isMacroPlaying = true;
|
3276
|
+
for (var i = 0, len = keyBuffer.length; i < len; i++) {
|
3277
|
+
CodeMirror.Vim.handleKey(cm, keyBuffer[i]);
|
3278
|
+
};
|
3279
|
+
macroModeState.isMacroPlaying = false;
|
3280
|
+
}
|
3281
|
+
|
3282
|
+
function logKey(macroModeState, key) {
|
3283
|
+
if(macroModeState.isMacroPlaying)return;
|
3284
|
+
var macroKeyBuffer = macroModeState.macroKeyBuffer;
|
3285
|
+
macroKeyBuffer.push(key);
|
3286
|
+
}
|
3287
|
+
|
3288
|
+
function exitReplaceMode(cm) {
|
3289
|
+
cm.toggleOverwrite();
|
3290
|
+
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
|
3291
|
+
cm.setOption('keyMap', 'vim');
|
3292
|
+
}
|
3293
|
+
|
3294
|
+
CodeMirror.keyMap['vim-replace'] = {
|
3295
|
+
'Esc': exitReplaceMode,
|
3296
|
+
'Ctrl-[': exitReplaceMode,
|
3297
|
+
'Ctrl-C': exitReplaceMode,
|
3298
|
+
'Backspace': 'goCharLeft',
|
3299
|
+
fallthrough: ['default']
|
3300
|
+
};
|
3301
|
+
|
3038
3302
|
return vimApi;
|
3039
3303
|
};
|
3040
3304
|
// Initialize Vim and make it available as an API.
|