codemirror-rails 3.02 → 3.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/codemirror-rails.gemspec +1 -0
- data/doc/CodeMirror-LICENSE +5 -1
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror/{utils → addons/dialog}/dialog.js +4 -0
- data/vendor/assets/javascripts/codemirror/addons/display/placeholder.js +54 -0
- data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +54 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/edit}/closetag.js +9 -8
- data/vendor/assets/javascripts/codemirror/{utils → addons/edit}/continuecomment.js +12 -4
- data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +25 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/edit}/matchbrackets.js +30 -11
- data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +31 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +32 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/indent-fold.js +11 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +64 -0
- data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +582 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/hint}/javascript-hint.js +15 -11
- data/vendor/assets/javascripts/codemirror/{utils → addons/hint}/pig-hint.js +19 -19
- data/vendor/assets/javascripts/codemirror/{utils → addons/hint}/python-hint.js +2 -2
- data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +180 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/hint}/xml-hint.js +5 -18
- data/vendor/assets/javascripts/codemirror/addons/lint/javascript-lint.js +127 -0
- data/vendor/assets/javascripts/codemirror/addons/lint/json-lint.js +14 -0
- data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +197 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/mode}/loadmode.js +0 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/mode}/multiplex.js +2 -2
- data/vendor/assets/javascripts/codemirror/{utils → addons/mode}/overlay.js +2 -2
- data/vendor/assets/javascripts/codemirror/{utils → addons/runmode}/colorize.js +0 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/runmode}/runmode-standalone.js +2 -3
- data/vendor/assets/javascripts/codemirror/{utils → addons/runmode}/runmode.js +0 -0
- data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +89 -0
- data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +60 -0
- data/vendor/assets/javascripts/codemirror/{utils → addons/search}/search.js +5 -5
- data/vendor/assets/javascripts/codemirror/{utils → addons/search}/searchcursor.js +37 -30
- data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +39 -0
- data/vendor/assets/javascripts/codemirror/addons/selection/mark-selection.js +34 -0
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +721 -188
- data/vendor/assets/javascripts/codemirror/modes/asterisk.js +6 -6
- data/vendor/assets/javascripts/codemirror/modes/clike.js +14 -14
- data/vendor/assets/javascripts/codemirror/modes/clojure.js +23 -7
- data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/css.js +337 -235
- data/vendor/assets/javascripts/codemirror/modes/ecl.js +12 -12
- data/vendor/assets/javascripts/codemirror/modes/erlang.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/gas.js +326 -0
- data/vendor/assets/javascripts/codemirror/modes/gfm.js +1 -0
- data/vendor/assets/javascripts/codemirror/modes/haskell.js +26 -26
- data/vendor/assets/javascripts/codemirror/modes/haxe.js +17 -17
- data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +6 -6
- data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +43 -23
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +78 -33
- data/vendor/assets/javascripts/codemirror/modes/jinja2.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/less.js +38 -38
- data/vendor/assets/javascripts/codemirror/modes/livescript.js +267 -0
- data/vendor/assets/javascripts/codemirror/modes/lua.js +7 -7
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +108 -57
- data/vendor/assets/javascripts/codemirror/modes/mirc.js +177 -0
- data/vendor/assets/javascripts/codemirror/modes/ntriples.js +22 -22
- data/vendor/assets/javascripts/codemirror/modes/ocaml.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/perl.js +791 -791
- data/vendor/assets/javascripts/codemirror/modes/php.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/pig.js +163 -163
- data/vendor/assets/javascripts/codemirror/modes/python.js +31 -31
- data/vendor/assets/javascripts/codemirror/modes/q.js +124 -0
- data/vendor/assets/javascripts/codemirror/modes/rst.js +486 -250
- data/vendor/assets/javascripts/codemirror/modes/sass.js +3 -3
- data/vendor/assets/javascripts/codemirror/modes/scss_test.js +80 -0
- data/vendor/assets/javascripts/codemirror/modes/shell.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/sieve.js +10 -10
- data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +129 -129
- data/vendor/assets/javascripts/codemirror/modes/smarty.js +3 -3
- data/vendor/assets/javascripts/codemirror/modes/sparql.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/sql.js +23 -23
- data/vendor/assets/javascripts/codemirror/modes/stex.js +192 -121
- data/vendor/assets/javascripts/codemirror/modes/tcl.js +131 -0
- data/vendor/assets/javascripts/codemirror/modes/test.js +64 -0
- data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +345 -345
- data/vendor/assets/javascripts/codemirror/modes/tiki.js +297 -298
- data/vendor/assets/javascripts/codemirror/modes/turtle.js +145 -0
- data/vendor/assets/javascripts/codemirror/modes/vb.js +31 -32
- data/vendor/assets/javascripts/codemirror/modes/vbscript.js +4 -4
- data/vendor/assets/javascripts/codemirror/modes/xml.js +10 -6
- data/vendor/assets/javascripts/codemirror/modes/xquery.js +55 -55
- data/vendor/assets/javascripts/codemirror/modes/yaml.js +90 -90
- data/vendor/assets/javascripts/codemirror/modes/z80.js +82 -110
- data/vendor/assets/javascripts/codemirror.js +1914 -1115
- data/vendor/assets/stylesheets/codemirror/{utils → addons/dialog}/dialog.css +0 -0
- data/vendor/assets/stylesheets/codemirror/addons/hint/show-hint.css +38 -0
- data/vendor/assets/stylesheets/codemirror/addons/lint/lint.css +96 -0
- data/vendor/assets/stylesheets/codemirror/modes/tiki.css +2 -2
- data/vendor/assets/stylesheets/codemirror/themes/ambiance-mobile.css +0 -1
- data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +0 -1
- data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +2 -2
- data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +5 -5
- data/vendor/assets/stylesheets/codemirror/themes/midnight.css +52 -0
- data/vendor/assets/stylesheets/codemirror/themes/xq-light.css +43 -0
- data/vendor/assets/stylesheets/codemirror.css +16 -10
- metadata +60 -52
- data/vendor/assets/javascripts/codemirror/modes/mysql.js +0 -203
- data/vendor/assets/javascripts/codemirror/modes/plsql.js +0 -216
- data/vendor/assets/javascripts/codemirror/utils/collapserange.js +0 -68
- data/vendor/assets/javascripts/codemirror/utils/continuelist.js +0 -28
- data/vendor/assets/javascripts/codemirror/utils/foldcode.js +0 -183
- data/vendor/assets/javascripts/codemirror/utils/formatting.js +0 -114
- data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +0 -46
- data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +0 -102
- data/vendor/assets/stylesheets/codemirror/utils/simple-hint.css +0 -16
@@ -3,9 +3,10 @@
|
|
3
3
|
*
|
4
4
|
* Motion:
|
5
5
|
* h, j, k, l
|
6
|
+
* gj, gk
|
6
7
|
* e, E, w, W, b, B, ge, gE
|
7
8
|
* f<character>, F<character>, t<character>, T<character>
|
8
|
-
* $, ^, 0
|
9
|
+
* $, ^, 0, -, +, _
|
9
10
|
* gg, G
|
10
11
|
* %
|
11
12
|
* '<character>, `<character>
|
@@ -21,6 +22,7 @@
|
|
21
22
|
*
|
22
23
|
* Action:
|
23
24
|
* a, i, s, A, I, S, o, O
|
25
|
+
* zz, z., z<CR>, zt, zb, z-
|
24
26
|
* J
|
25
27
|
* u, Ctrl-r
|
26
28
|
* m<character>
|
@@ -77,6 +79,15 @@
|
|
77
79
|
{ keys: ['PageUp'], type: 'keyToKey', toKeys: ['Ctrl-b'] },
|
78
80
|
{ keys: ['PageDown'], type: 'keyToKey', toKeys: ['Ctrl-f'] },
|
79
81
|
// Motions
|
82
|
+
{ keys: ['H'], type: 'motion',
|
83
|
+
motion: 'moveToTopLine',
|
84
|
+
motionArgs: { linewise: true }},
|
85
|
+
{ keys: ['M'], type: 'motion',
|
86
|
+
motion: 'moveToMiddleLine',
|
87
|
+
motionArgs: { linewise: true }},
|
88
|
+
{ keys: ['L'], type: 'motion',
|
89
|
+
motion: 'moveToBottomLine',
|
90
|
+
motionArgs: { linewise: true }},
|
80
91
|
{ keys: ['h'], type: 'motion',
|
81
92
|
motion: 'moveByCharacters',
|
82
93
|
motionArgs: { forward: false }},
|
@@ -89,6 +100,12 @@
|
|
89
100
|
{ keys: ['k'], type: 'motion',
|
90
101
|
motion: 'moveByLines',
|
91
102
|
motionArgs: { forward: false, linewise: true }},
|
103
|
+
{ keys: ['g','j'], type: 'motion',
|
104
|
+
motion: 'moveByDisplayLines',
|
105
|
+
motionArgs: { forward: true }},
|
106
|
+
{ keys: ['g','k'], type: 'motion',
|
107
|
+
motion: 'moveByDisplayLines',
|
108
|
+
motionArgs: { forward: false }},
|
92
109
|
{ keys: ['w'], type: 'motion',
|
93
110
|
motion: 'moveByWords',
|
94
111
|
motionArgs: { forward: true, wordEnd: false }},
|
@@ -123,6 +140,12 @@
|
|
123
140
|
motion: 'moveByPage', motionArgs: { forward: true }},
|
124
141
|
{ keys: ['Ctrl-b'], type: 'motion',
|
125
142
|
motion: 'moveByPage', motionArgs: { forward: false }},
|
143
|
+
{ keys: ['Ctrl-d'], type: 'motion',
|
144
|
+
motion: 'moveByScroll',
|
145
|
+
motionArgs: { forward: true, explicitRepeat: true }},
|
146
|
+
{ keys: ['Ctrl-u'], type: 'motion',
|
147
|
+
motion: 'moveByScroll',
|
148
|
+
motionArgs: { forward: false, explicitRepeat: true }},
|
126
149
|
{ keys: ['g', 'g'], type: 'motion',
|
127
150
|
motion: 'moveToLineOrEdgeOfDocument',
|
128
151
|
motionArgs: { forward: false, explicitRepeat: true, linewise: true }},
|
@@ -132,6 +155,15 @@
|
|
132
155
|
{ keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' },
|
133
156
|
{ keys: ['^'], type: 'motion',
|
134
157
|
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
158
|
+
{ keys: ['+'], type: 'motion',
|
159
|
+
motion: 'moveByLines',
|
160
|
+
motionArgs: { forward: true, toFirstChar:true }},
|
161
|
+
{ keys: ['-'], type: 'motion',
|
162
|
+
motion: 'moveByLines',
|
163
|
+
motionArgs: { forward: false, toFirstChar:true }},
|
164
|
+
{ keys: ['_'], type: 'motion',
|
165
|
+
motion: 'moveByLines',
|
166
|
+
motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }},
|
135
167
|
{ keys: ['$'], type: 'motion',
|
136
168
|
motion: 'moveToEol',
|
137
169
|
motionArgs: { inclusive: true }},
|
@@ -150,8 +182,22 @@
|
|
150
182
|
{ keys: ['T', 'character'], type: 'motion',
|
151
183
|
motion: 'moveTillCharacter',
|
152
184
|
motionArgs: { forward: false }},
|
185
|
+
{ keys: [';'], type: 'motion', motion: 'repeatLastCharacterSearch',
|
186
|
+
motionArgs: { forward: true }},
|
187
|
+
{ keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch',
|
188
|
+
motionArgs: { forward: false }},
|
153
189
|
{ keys: ['\'', 'character'], type: 'motion', motion: 'goToMark' },
|
154
190
|
{ keys: ['`', 'character'], type: 'motion', motion: 'goToMark' },
|
191
|
+
{ keys: [']', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
|
192
|
+
{ keys: ['[', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
|
193
|
+
{ keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
|
194
|
+
{ keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
|
195
|
+
{ keys: [']', 'character'], type: 'motion',
|
196
|
+
motion: 'moveToSymbol',
|
197
|
+
motionArgs: { forward: true}},
|
198
|
+
{ keys: ['[', 'character'], type: 'motion',
|
199
|
+
motion: 'moveToSymbol',
|
200
|
+
motionArgs: { forward: false}},
|
155
201
|
{ keys: ['|'], type: 'motion',
|
156
202
|
motion: 'moveToColumn',
|
157
203
|
motionArgs: { }},
|
@@ -165,8 +211,10 @@
|
|
165
211
|
{ keys: ['<'], type: 'operator', operator: 'indent',
|
166
212
|
operatorArgs: { indentRight: false }},
|
167
213
|
{ keys: ['g', '~'], type: 'operator', operator: 'swapcase' },
|
168
|
-
{ keys: ['n'], type: 'motion', motion: 'findNext'
|
169
|
-
|
214
|
+
{ keys: ['n'], type: 'motion', motion: 'findNext',
|
215
|
+
motionArgs: { forward: true }},
|
216
|
+
{ keys: ['N'], type: 'motion', motion: 'findNext',
|
217
|
+
motionArgs: { forward: false }},
|
170
218
|
// Operator-Motion dual commands
|
171
219
|
{ keys: ['x'], type: 'operatorMotion', operator: 'delete',
|
172
220
|
motion: 'moveByCharacters', motionArgs: { forward: true },
|
@@ -211,7 +259,26 @@
|
|
211
259
|
{ keys: ['Ctrl-r'], type: 'action', action: 'redo' },
|
212
260
|
{ keys: ['m', 'character'], type: 'action', action: 'setMark' },
|
213
261
|
{ keys: ['\"', 'character'], type: 'action', action: 'setRegister' },
|
214
|
-
{ keys: ['
|
262
|
+
{ keys: ['z', 'z'], type: 'action', action: 'scrollToCursor',
|
263
|
+
actionArgs: { position: 'center' }},
|
264
|
+
{ keys: ['z', '.'], type: 'action', action: 'scrollToCursor',
|
265
|
+
actionArgs: { position: 'center' },
|
266
|
+
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
267
|
+
{ keys: ['z', 't'], type: 'action', action: 'scrollToCursor',
|
268
|
+
actionArgs: { position: 'top' }},
|
269
|
+
{ keys: ['z', 'Enter'], type: 'action', action: 'scrollToCursor',
|
270
|
+
actionArgs: { position: 'top' },
|
271
|
+
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
272
|
+
{ keys: ['z', '-'], type: 'action', action: 'scrollToCursor',
|
273
|
+
actionArgs: { position: 'bottom' }},
|
274
|
+
{ keys: ['z', 'b'], type: 'action', action: 'scrollToCursor',
|
275
|
+
actionArgs: { position: 'bottom' },
|
276
|
+
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
277
|
+
{ keys: ['.'], type: 'action', action: 'repeatLastEdit' },
|
278
|
+
{ keys: ['Ctrl-a'], type: 'action', action: 'incrementNumberToken',
|
279
|
+
actionArgs: {increase: true, backtrack: false}},
|
280
|
+
{ keys: ['Ctrl-x'], type: 'action', action: 'incrementNumberToken',
|
281
|
+
actionArgs: {increase: false, backtrack: false}},
|
215
282
|
// Text object motions
|
216
283
|
{ keys: ['a', 'character'], type: 'motion',
|
217
284
|
motion: 'textObjectManipulation' },
|
@@ -249,7 +316,7 @@
|
|
249
316
|
var SPECIAL_SYMBOLS = '~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'';
|
250
317
|
var specialSymbols = SPECIAL_SYMBOLS.split('');
|
251
318
|
var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
|
252
|
-
'Esc', 'Home', 'End', 'PageUp', 'PageDown'];
|
319
|
+
'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter'];
|
253
320
|
var validMarks = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
|
254
321
|
numbers).concat(['<', '>']);
|
255
322
|
var validRegisters = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
|
@@ -259,7 +326,7 @@
|
|
259
326
|
return alphabetRegex.test(k);
|
260
327
|
}
|
261
328
|
function isLine(cm, line) {
|
262
|
-
return line >=
|
329
|
+
return line >= cm.firstLine() && line <= cm.lastLine();
|
263
330
|
}
|
264
331
|
function isLowerCase(k) {
|
265
332
|
return (/^[a-z]$/).test(k);
|
@@ -303,6 +370,8 @@
|
|
303
370
|
searchQuery: null,
|
304
371
|
// Whether we are searching backwards.
|
305
372
|
searchIsReversed: false,
|
373
|
+
// Recording latest f, t, F or T motion command.
|
374
|
+
lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
|
306
375
|
registerController: new RegisterController({})
|
307
376
|
};
|
308
377
|
}
|
@@ -319,6 +388,8 @@
|
|
319
388
|
// cursor should go back to its horizontal position on the longer
|
320
389
|
// line if it can. This is to keep track of the horizontal position.
|
321
390
|
lastHPos: -1,
|
391
|
+
// Doing the same with screen-position for gj/gk
|
392
|
+
lastHSPos: -1,
|
322
393
|
// The last motion command run. Cleared if a non-motion command gets
|
323
394
|
// executed in between.
|
324
395
|
lastMotion: null,
|
@@ -348,6 +419,12 @@
|
|
348
419
|
// Add user defined key bindings.
|
349
420
|
exCommandDispatcher.map(lhs, rhs);
|
350
421
|
},
|
422
|
+
defineEx: function(name, prefix, func){
|
423
|
+
if (name.indexOf(prefix) === 0) {
|
424
|
+
exCommands[name]=func;
|
425
|
+
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
|
426
|
+
}else throw new Error("(Vim.defineEx) \""+prefix+"\" is not a prefix of \""+name+"\", command not registered");
|
427
|
+
},
|
351
428
|
// Initializes vim state variable on the CodeMirror object. Should only be
|
352
429
|
// called lazily by handleKey or for testing.
|
353
430
|
maybeInitState: function(cm) {
|
@@ -360,7 +437,7 @@
|
|
360
437
|
var vim = getVimState(cm);
|
361
438
|
if (key == 'Esc') {
|
362
439
|
// Clear input state and get back to normal mode.
|
363
|
-
vim.inputState
|
440
|
+
vim.inputState = new InputState();
|
364
441
|
if (vim.visualMode) {
|
365
442
|
exitVisualMode(cm, vim);
|
366
443
|
}
|
@@ -400,9 +477,6 @@
|
|
400
477
|
|
401
478
|
// Represents the current input state.
|
402
479
|
function InputState() {
|
403
|
-
this.reset();
|
404
|
-
}
|
405
|
-
InputState.prototype.reset = function() {
|
406
480
|
this.prefixRepeat = [];
|
407
481
|
this.motionRepeat = [];
|
408
482
|
|
@@ -412,7 +486,7 @@
|
|
412
486
|
this.motionArgs = null;
|
413
487
|
this.keyBuffer = []; // For matching multi-key commands.
|
414
488
|
this.registerName = null; // Defaults to the unamed register.
|
415
|
-
}
|
489
|
+
}
|
416
490
|
InputState.prototype.pushRepeatDigit = function(n) {
|
417
491
|
if (!this.operator) {
|
418
492
|
this.prefixRepeat = this.prefixRepeat.concat(n);
|
@@ -567,6 +641,18 @@
|
|
567
641
|
// Matches whole comand. Return the command.
|
568
642
|
if (command.keys[keys.length - 1] == 'character') {
|
569
643
|
inputState.selectedCharacter = keys[keys.length - 1];
|
644
|
+
if(inputState.selectedCharacter.length>1){
|
645
|
+
switch(inputState.selectedCharacter){
|
646
|
+
case "Enter":
|
647
|
+
inputState.selectedCharacter='\n';
|
648
|
+
break;
|
649
|
+
case "Space":
|
650
|
+
inputState.selectedCharacter=' ';
|
651
|
+
break;
|
652
|
+
default:
|
653
|
+
continue;
|
654
|
+
}
|
655
|
+
}
|
570
656
|
}
|
571
657
|
inputState.keyBuffer = [];
|
572
658
|
return command;
|
@@ -578,6 +664,7 @@
|
|
578
664
|
return null;
|
579
665
|
},
|
580
666
|
processCommand: function(cm, vim, command) {
|
667
|
+
vim.inputState.repeatOverride = command.repeatOverride;
|
581
668
|
switch (command.type) {
|
582
669
|
case 'motion':
|
583
670
|
this.processMotion(cm, vim, command);
|
@@ -619,7 +706,7 @@
|
|
619
706
|
return;
|
620
707
|
} else {
|
621
708
|
// 2 different operators in a row doesn't make sense.
|
622
|
-
inputState
|
709
|
+
vim.inputState = new InputState();
|
623
710
|
}
|
624
711
|
}
|
625
712
|
inputState.operator = command.operator;
|
@@ -664,7 +751,7 @@
|
|
664
751
|
actionArgs.repeat = repeat || 1;
|
665
752
|
actionArgs.repeatIsExplicit = repeatIsExplicit;
|
666
753
|
actionArgs.registerName = inputState.registerName;
|
667
|
-
inputState
|
754
|
+
vim.inputState = new InputState();
|
668
755
|
vim.lastMotion = null,
|
669
756
|
actions[command.action](cm, actionArgs, vim);
|
670
757
|
},
|
@@ -676,19 +763,61 @@
|
|
676
763
|
var forward = command.searchArgs.forward;
|
677
764
|
getSearchState(cm).setReversed(!forward);
|
678
765
|
var promptPrefix = (forward) ? '/' : '?';
|
766
|
+
var originalQuery = getSearchState(cm).getQuery();
|
767
|
+
var originalScrollPos = cm.getScrollInfo();
|
679
768
|
function handleQuery(query, ignoreCase, smartCase) {
|
680
|
-
|
769
|
+
try {
|
770
|
+
updateSearchQuery(cm, query, ignoreCase, smartCase);
|
771
|
+
} catch (e) {
|
772
|
+
showConfirm(cm, 'Invalid regex: ' + regexPart);
|
773
|
+
return;
|
774
|
+
}
|
681
775
|
commandDispatcher.processMotion(cm, vim, {
|
682
776
|
type: 'motion',
|
683
|
-
motion: 'findNext'
|
777
|
+
motion: 'findNext',
|
778
|
+
motionArgs: { forward: true }
|
684
779
|
});
|
685
780
|
}
|
686
781
|
function onPromptClose(query) {
|
782
|
+
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
|
687
783
|
handleQuery(query, true /** ignoreCase */, true /** smartCase */);
|
688
784
|
}
|
785
|
+
function onPromptKeyUp(e, query) {
|
786
|
+
var parsedQuery;
|
787
|
+
try {
|
788
|
+
parsedQuery = updateSearchQuery(cm, query,
|
789
|
+
true /** ignoreCase */, true /** smartCase */)
|
790
|
+
} catch (e) {
|
791
|
+
// Swallow bad regexes for incremental search.
|
792
|
+
}
|
793
|
+
if (parsedQuery) {
|
794
|
+
cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30);
|
795
|
+
} else {
|
796
|
+
clearSearchHighlight(cm);
|
797
|
+
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
|
798
|
+
}
|
799
|
+
}
|
800
|
+
function onPromptKeyDown(e, query, close) {
|
801
|
+
var keyName = CodeMirror.keyName(e);
|
802
|
+
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') {
|
803
|
+
updateSearchQuery(cm, originalQuery);
|
804
|
+
clearSearchHighlight(cm);
|
805
|
+
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
|
806
|
+
|
807
|
+
CodeMirror.e_stop(e);
|
808
|
+
close();
|
809
|
+
cm.focus();
|
810
|
+
}
|
811
|
+
}
|
689
812
|
switch (command.searchArgs.querySrc) {
|
690
813
|
case 'prompt':
|
691
|
-
showPrompt(cm,
|
814
|
+
showPrompt(cm, {
|
815
|
+
onClose: onPromptClose,
|
816
|
+
prefix: promptPrefix,
|
817
|
+
desc: searchPromptDesc,
|
818
|
+
onKeyUp: onPromptKeyUp,
|
819
|
+
onKeyDown: onPromptKeyDown
|
820
|
+
});
|
692
821
|
break;
|
693
822
|
case 'wordUnderCursor':
|
694
823
|
var word = expandWordUnderCursor(cm, false /** inclusive */,
|
@@ -720,14 +849,24 @@
|
|
720
849
|
function onPromptClose(input) {
|
721
850
|
exCommandDispatcher.processCommand(cm, input);
|
722
851
|
}
|
852
|
+
function onPromptKeyDown(e, input, close) {
|
853
|
+
var keyName = CodeMirror.keyName(e);
|
854
|
+
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') {
|
855
|
+
CodeMirror.e_stop(e);
|
856
|
+
close();
|
857
|
+
cm.focus();
|
858
|
+
}
|
859
|
+
}
|
723
860
|
if (command.type == 'keyToEx') {
|
724
861
|
// Handle user defined Ex to Ex mappings
|
725
862
|
exCommandDispatcher.processCommand(cm, command.exArgs.input);
|
726
863
|
} else {
|
727
864
|
if (vim.visualMode) {
|
728
|
-
showPrompt(cm, onPromptClose, ':',
|
865
|
+
showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
|
866
|
+
onKeyDown: onPromptKeyDown});
|
729
867
|
} else {
|
730
|
-
showPrompt(cm, onPromptClose, ':'
|
868
|
+
showPrompt(cm, { onClose: onPromptClose, prefix: ':',
|
869
|
+
onKeyDown: onPromptKeyDown});
|
731
870
|
}
|
732
871
|
}
|
733
872
|
},
|
@@ -748,10 +887,13 @@
|
|
748
887
|
var curOriginal = copyCursor(curStart);
|
749
888
|
var curEnd;
|
750
889
|
var repeat;
|
751
|
-
if (
|
752
|
-
|
890
|
+
if (operator) {
|
891
|
+
this.recordLastEdit(cm, vim, inputState);
|
892
|
+
}
|
893
|
+
if (inputState.repeatOverride !== undefined) {
|
894
|
+
// If repeatOverride is specified, that takes precedence over the
|
753
895
|
// input state's repeat. Used by Ex mode and can be user defined.
|
754
|
-
repeat = inputState.
|
896
|
+
repeat = inputState.repeatOverride;
|
755
897
|
} else {
|
756
898
|
repeat = inputState.getRepeat();
|
757
899
|
}
|
@@ -768,7 +910,7 @@
|
|
768
910
|
inputState.selectedCharacter;
|
769
911
|
}
|
770
912
|
motionArgs.repeat = repeat;
|
771
|
-
inputState
|
913
|
+
vim.inputState = new InputState();
|
772
914
|
if (motion) {
|
773
915
|
var motionResult = motions[motion](cm, motionArgs, vim);
|
774
916
|
vim.lastMotion = motions[motion];
|
@@ -810,9 +952,6 @@
|
|
810
952
|
selectionStart.ch = lineLength(cm, selectionStart.line);
|
811
953
|
}
|
812
954
|
}
|
813
|
-
// Need to set the cursor to clear the selection. Otherwise,
|
814
|
-
// CodeMirror can't figure out that we changed directions...
|
815
|
-
cm.setCursor(selectionStart);
|
816
955
|
cm.setSelection(selectionStart, selectionEnd);
|
817
956
|
updateMark(cm, vim, '<',
|
818
957
|
cursorIsBefore(selectionStart, selectionEnd) ? selectionStart
|
@@ -868,6 +1007,9 @@
|
|
868
1007
|
actions.enterInsertMode(cm);
|
869
1008
|
}
|
870
1009
|
}
|
1010
|
+
},
|
1011
|
+
recordLastEdit: function(cm, vim, inputState) {
|
1012
|
+
vim.lastEdit = inputState;
|
871
1013
|
}
|
872
1014
|
};
|
873
1015
|
|
@@ -877,6 +1019,19 @@
|
|
877
1019
|
*/
|
878
1020
|
// All of the functions below return Cursor objects.
|
879
1021
|
var motions = {
|
1022
|
+
moveToTopLine: function(cm, motionArgs) {
|
1023
|
+
var line = getUserVisibleLines(cm).top + motionArgs.repeat -1;
|
1024
|
+
return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
|
1025
|
+
},
|
1026
|
+
moveToMiddleLine: function(cm) {
|
1027
|
+
var range = getUserVisibleLines(cm);
|
1028
|
+
var line = Math.floor((range.top + range.bottom) * 0.5);
|
1029
|
+
return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
|
1030
|
+
},
|
1031
|
+
moveToBottomLine: function(cm, motionArgs) {
|
1032
|
+
var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1;
|
1033
|
+
return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
|
1034
|
+
},
|
880
1035
|
expandToLine: function(cm, motionArgs) {
|
881
1036
|
// Expands forward to end of line, and then to next line if repeat is
|
882
1037
|
// >1. Does not handle backward motion!
|
@@ -884,10 +1039,16 @@
|
|
884
1039
|
return { line: cur.line + motionArgs.repeat - 1, ch: Infinity };
|
885
1040
|
},
|
886
1041
|
findNext: function(cm, motionArgs, vim) {
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
1042
|
+
var state = getSearchState(cm);
|
1043
|
+
var query = state.getQuery();
|
1044
|
+
if (!query) {
|
1045
|
+
return;
|
1046
|
+
}
|
1047
|
+
var prev = !motionArgs.forward;
|
1048
|
+
// If search is initiated with ? instead of /, negate direction.
|
1049
|
+
prev = (state.isReversed()) ? !prev : prev;
|
1050
|
+
highlightSearchMatches(cm, query);
|
1051
|
+
return findNext(cm, prev/** prev */, query, motionArgs.repeat);
|
891
1052
|
},
|
892
1053
|
goToMark: function(cm, motionArgs, vim) {
|
893
1054
|
var mark = vim.marks[motionArgs.selectedCharacter];
|
@@ -896,6 +1057,44 @@
|
|
896
1057
|
}
|
897
1058
|
return null;
|
898
1059
|
},
|
1060
|
+
jumpToMark: function(cm, motionArgs, vim) {
|
1061
|
+
var best = cm.getCursor();
|
1062
|
+
for (var i = 0; i < motionArgs.repeat; i++) {
|
1063
|
+
var cursor = best;
|
1064
|
+
for (var key in vim.marks) {
|
1065
|
+
if (!isLowerCase(key)) {
|
1066
|
+
continue;
|
1067
|
+
}
|
1068
|
+
var mark = vim.marks[key].find();
|
1069
|
+
var isWrongDirection = (motionArgs.forward) ?
|
1070
|
+
cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark)
|
1071
|
+
|
1072
|
+
if (isWrongDirection) {
|
1073
|
+
continue;
|
1074
|
+
}
|
1075
|
+
if (motionArgs.linewise && (mark.line == cursor.line)) {
|
1076
|
+
continue;
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
var equal = cursorEqual(cursor, best);
|
1080
|
+
var between = (motionArgs.forward) ?
|
1081
|
+
cusrorIsBetween(cursor, mark, best) :
|
1082
|
+
cusrorIsBetween(best, mark, cursor);
|
1083
|
+
|
1084
|
+
if (equal || between) {
|
1085
|
+
best = mark;
|
1086
|
+
}
|
1087
|
+
}
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
if (motionArgs.linewise) {
|
1091
|
+
// Vim places the cursor on the first non-whitespace character of
|
1092
|
+
// the line if there is one, else it places the cursor at the end
|
1093
|
+
// of the line, regardless of whether a mark was found.
|
1094
|
+
best.ch = findFirstNonWhiteSpaceCharacter(cm.getLine(best.line));
|
1095
|
+
}
|
1096
|
+
return best;
|
1097
|
+
},
|
899
1098
|
moveByCharacters: function(cm, motionArgs) {
|
900
1099
|
var cur = cm.getCursor();
|
901
1100
|
var repeat = motionArgs.repeat;
|
@@ -903,7 +1102,8 @@
|
|
903
1102
|
return { line: cur.line, ch: ch };
|
904
1103
|
},
|
905
1104
|
moveByLines: function(cm, motionArgs, vim) {
|
906
|
-
var
|
1105
|
+
var cur = cm.getCursor();
|
1106
|
+
var endCh = cur.ch;
|
907
1107
|
// Depending what our last motion was, we may want to do different
|
908
1108
|
// things. If our last motion was moving vertically, we want to
|
909
1109
|
// preserve the HPos from our last horizontal move. If our last motion
|
@@ -911,6 +1111,8 @@
|
|
911
1111
|
// the end of the line, etc.
|
912
1112
|
switch (vim.lastMotion) {
|
913
1113
|
case this.moveByLines:
|
1114
|
+
case this.moveByDisplayLines:
|
1115
|
+
case this.moveByScroll:
|
914
1116
|
case this.moveToColumn:
|
915
1117
|
case this.moveToEol:
|
916
1118
|
endCh = vim.lastHPos;
|
@@ -918,14 +1120,46 @@
|
|
918
1120
|
default:
|
919
1121
|
vim.lastHPos = endCh;
|
920
1122
|
}
|
921
|
-
var
|
922
|
-
var repeat = motionArgs.repeat;
|
1123
|
+
var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);
|
923
1124
|
var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
|
924
|
-
if (line <
|
1125
|
+
if (line < cm.firstLine() || line > cm.lastLine() ) {
|
925
1126
|
return null;
|
926
1127
|
}
|
1128
|
+
if(motionArgs.toFirstChar){
|
1129
|
+
endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
|
1130
|
+
vim.lastHPos = endCh;
|
1131
|
+
}
|
1132
|
+
vim.lastHSPos = cm.charCoords({line:line, ch:endCh},"div").left;
|
927
1133
|
return { line: line, ch: endCh };
|
928
1134
|
},
|
1135
|
+
moveByDisplayLines: function(cm, motionArgs, vim) {
|
1136
|
+
var cur = cm.getCursor();
|
1137
|
+
switch (vim.lastMotion) {
|
1138
|
+
case this.moveByDisplayLines:
|
1139
|
+
case this.moveByScroll:
|
1140
|
+
case this.moveByLines:
|
1141
|
+
case this.moveToColumn:
|
1142
|
+
case this.moveToEol:
|
1143
|
+
break;
|
1144
|
+
default:
|
1145
|
+
vim.lastHSPos = cm.charCoords(cur,"div").left;
|
1146
|
+
}
|
1147
|
+
var repeat = motionArgs.repeat;
|
1148
|
+
var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),"line",vim.lastHSPos);
|
1149
|
+
if (res.hitSide) {
|
1150
|
+
if (motionArgs.forward) {
|
1151
|
+
var lastCharCoords = cm.charCoords(res, 'div');
|
1152
|
+
var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos };
|
1153
|
+
var res = cm.coordsChar(goalCoords, 'div');
|
1154
|
+
} else {
|
1155
|
+
var resCoords = cm.charCoords({ line: cm.firstLine(), ch: 0}, 'div');
|
1156
|
+
resCoords.left = vim.lastHSPos;
|
1157
|
+
res = cm.coordsChar(resCoords, 'div');
|
1158
|
+
}
|
1159
|
+
}
|
1160
|
+
vim.lastHPos = res.ch;
|
1161
|
+
return res;
|
1162
|
+
},
|
929
1163
|
moveByPage: function(cm, motionArgs) {
|
930
1164
|
// CodeMirror only exposes functions that move the cursor page down, so
|
931
1165
|
// doing this bad hack to move the cursor and move it back. evalInput
|
@@ -942,17 +1176,35 @@
|
|
942
1176
|
var repeat = motionArgs.repeat;
|
943
1177
|
var inc = motionArgs.forward ? 1 : -1;
|
944
1178
|
for (var i = 0; i < repeat; i++) {
|
945
|
-
if ((!motionArgs.forward && line ===
|
946
|
-
(motionArgs.forward && line == cm.
|
1179
|
+
if ((!motionArgs.forward && line === cm.firstLine() ) ||
|
1180
|
+
(motionArgs.forward && line == cm.lastLine())) {
|
947
1181
|
break;
|
948
1182
|
}
|
949
1183
|
line += inc;
|
950
|
-
while (line !==
|
1184
|
+
while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) {
|
951
1185
|
line += inc;
|
952
1186
|
}
|
953
1187
|
}
|
954
1188
|
return { line: line, ch: 0 };
|
955
1189
|
},
|
1190
|
+
moveByScroll: function(cm, motionArgs, vim) {
|
1191
|
+
var globalState = getVimGlobalState();
|
1192
|
+
var scrollbox = cm.getScrollInfo();
|
1193
|
+
var curEnd = null;
|
1194
|
+
var repeat = motionArgs.repeat;
|
1195
|
+
if (!repeat) {
|
1196
|
+
repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight());
|
1197
|
+
}
|
1198
|
+
var orig = cm.charCoords(cm.getCursor(), 'local');
|
1199
|
+
motionArgs.repeat = repeat;
|
1200
|
+
var curEnd = motions.moveByDisplayLines(cm, motionArgs, vim);
|
1201
|
+
if (!curEnd) {
|
1202
|
+
return null;
|
1203
|
+
}
|
1204
|
+
var dest = cm.charCoords(curEnd, 'local');
|
1205
|
+
cm.scrollTo(null, scrollbox.top + dest.top - orig.top);
|
1206
|
+
return curEnd;
|
1207
|
+
},
|
956
1208
|
moveByWords: function(cm, motionArgs) {
|
957
1209
|
return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward,
|
958
1210
|
!!motionArgs.wordEnd, !!motionArgs.bigWord);
|
@@ -962,30 +1214,42 @@
|
|
962
1214
|
var curEnd = moveToCharacter(cm, repeat, motionArgs.forward,
|
963
1215
|
motionArgs.selectedCharacter);
|
964
1216
|
var increment = motionArgs.forward ? -1 : 1;
|
1217
|
+
recordLastCharacterSearch(increment, motionArgs);
|
1218
|
+
if(!curEnd)return cm.getCursor();
|
965
1219
|
curEnd.ch += increment;
|
966
1220
|
return curEnd;
|
967
1221
|
},
|
968
1222
|
moveToCharacter: function(cm, motionArgs) {
|
969
1223
|
var repeat = motionArgs.repeat;
|
1224
|
+
recordLastCharacterSearch(0, motionArgs);
|
970
1225
|
return moveToCharacter(cm, repeat, motionArgs.forward,
|
971
|
-
motionArgs.selectedCharacter);
|
1226
|
+
motionArgs.selectedCharacter) || cm.getCursor();
|
1227
|
+
},
|
1228
|
+
moveToSymbol: function(cm, motionArgs) {
|
1229
|
+
var repeat = motionArgs.repeat;
|
1230
|
+
return findSymbol(cm, repeat, motionArgs.forward,
|
1231
|
+
motionArgs.selectedCharacter) || cm.getCursor();
|
972
1232
|
},
|
973
1233
|
moveToColumn: function(cm, motionArgs, vim) {
|
974
1234
|
var repeat = motionArgs.repeat;
|
975
1235
|
// repeat is equivalent to which column we want to move to!
|
976
1236
|
vim.lastHPos = repeat - 1;
|
1237
|
+
vim.lastHSPos = cm.charCoords(cm.getCursor(),"div").left;
|
977
1238
|
return moveToColumn(cm, repeat);
|
978
1239
|
},
|
979
1240
|
moveToEol: function(cm, motionArgs, vim) {
|
980
1241
|
var cur = cm.getCursor();
|
981
1242
|
vim.lastHPos = Infinity;
|
982
|
-
|
1243
|
+
var retval={ line: cur.line + motionArgs.repeat - 1, ch: Infinity }
|
1244
|
+
var end=cm.clipPos(retval);
|
1245
|
+
end.ch--;
|
1246
|
+
vim.lastHSPos = cm.charCoords(end,"div").left;
|
1247
|
+
return retval;
|
983
1248
|
},
|
984
1249
|
moveToFirstNonWhiteSpaceCharacter: function(cm) {
|
985
1250
|
// Go to the start of the line where the text begins, or the end for
|
986
1251
|
// whitespace-only lines
|
987
1252
|
var cursor = cm.getCursor();
|
988
|
-
var line = cm.getLine(cursor.line);
|
989
1253
|
return { line: cursor.line,
|
990
1254
|
ch: findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line)) };
|
991
1255
|
},
|
@@ -1003,9 +1267,9 @@
|
|
1003
1267
|
return { line: cursor.line, ch: 0 };
|
1004
1268
|
},
|
1005
1269
|
moveToLineOrEdgeOfDocument: function(cm, motionArgs) {
|
1006
|
-
var lineNum = motionArgs.forward ? cm.
|
1270
|
+
var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine();
|
1007
1271
|
if (motionArgs.repeatIsExplicit) {
|
1008
|
-
lineNum = motionArgs.repeat -
|
1272
|
+
lineNum = motionArgs.repeat - cm.getOption('firstLineNumber');
|
1009
1273
|
}
|
1010
1274
|
return { line: lineNum,
|
1011
1275
|
ch: findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)) };
|
@@ -1026,6 +1290,21 @@
|
|
1026
1290
|
var start = tmp.start;
|
1027
1291
|
var end = tmp.end;
|
1028
1292
|
return [start, end];
|
1293
|
+
},
|
1294
|
+
repeatLastCharacterSearch: function(cm, motionArgs) {
|
1295
|
+
var lastSearch = getVimGlobalState().lastChararacterSearch;
|
1296
|
+
var repeat = motionArgs.repeat;
|
1297
|
+
var forward = motionArgs.forward === lastSearch.forward;
|
1298
|
+
var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);
|
1299
|
+
cm.moveH(-increment, 'char');
|
1300
|
+
motionArgs.inclusive = forward ? true : false;
|
1301
|
+
var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter);
|
1302
|
+
if (!curEnd) {
|
1303
|
+
cm.moveH(increment, 'char')
|
1304
|
+
return cm.getCursor();
|
1305
|
+
}
|
1306
|
+
curEnd.ch += increment;
|
1307
|
+
return curEnd;
|
1029
1308
|
}
|
1030
1309
|
};
|
1031
1310
|
|
@@ -1104,7 +1383,25 @@
|
|
1104
1383
|
};
|
1105
1384
|
|
1106
1385
|
var actions = {
|
1107
|
-
|
1386
|
+
scrollToCursor: function(cm, actionArgs) {
|
1387
|
+
var lineNum = cm.getCursor().line;
|
1388
|
+
var heightProp = window.getComputedStyle(cm.getScrollerElement()).
|
1389
|
+
getPropertyValue('height');
|
1390
|
+
var height = parseInt(heightProp);
|
1391
|
+
var y = cm.charCoords({line: lineNum, ch: 0}, "local").top;
|
1392
|
+
var halfHeight = parseInt(height) / 2;
|
1393
|
+
switch (actionArgs.position) {
|
1394
|
+
case 'center': y = y - (height / 2) + 10;
|
1395
|
+
break;
|
1396
|
+
case 'bottom': y = y - height;
|
1397
|
+
break;
|
1398
|
+
case 'top': break;
|
1399
|
+
}
|
1400
|
+
cm.scrollTo(null, y);
|
1401
|
+
// The calculations are slightly off, use scrollIntoView to nudge the
|
1402
|
+
// view into the right place.
|
1403
|
+
cm.scrollIntoView();
|
1404
|
+
},
|
1108
1405
|
enterInsertMode: function(cm, actionArgs) {
|
1109
1406
|
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
|
1110
1407
|
if (insertAt == 'eol') {
|
@@ -1202,10 +1499,10 @@
|
|
1202
1499
|
},
|
1203
1500
|
newLineAndEnterInsertMode: function(cm, actionArgs) {
|
1204
1501
|
var insertAt = cm.getCursor();
|
1205
|
-
if (insertAt.line ===
|
1502
|
+
if (insertAt.line === cm.firstLine() && !actionArgs.after) {
|
1206
1503
|
// Special case for inserting newline before start of document.
|
1207
|
-
cm.replaceRange('\n', { line:
|
1208
|
-
cm.setCursor(
|
1504
|
+
cm.replaceRange('\n', { line: cm.firstLine(), ch: 0 });
|
1505
|
+
cm.setCursor(cm.firstLine(), 0);
|
1209
1506
|
} else {
|
1210
1507
|
insertAt.line = (actionArgs.after) ? insertAt.line :
|
1211
1508
|
insertAt.line - 1;
|
@@ -1272,21 +1569,82 @@
|
|
1272
1569
|
var markName = actionArgs.selectedCharacter;
|
1273
1570
|
updateMark(cm, vim, markName, cm.getCursor());
|
1274
1571
|
},
|
1275
|
-
replace: function(cm, actionArgs) {
|
1572
|
+
replace: function(cm, actionArgs, vim) {
|
1276
1573
|
var replaceWith = actionArgs.selectedCharacter;
|
1277
1574
|
var curStart = cm.getCursor();
|
1278
|
-
var
|
1279
|
-
var
|
1280
|
-
if
|
1575
|
+
var replaceTo;
|
1576
|
+
var curEnd;
|
1577
|
+
if(vim.visualMode){
|
1578
|
+
curStart=cm.getCursor('start');
|
1579
|
+
curEnd=cm.getCursor('end');
|
1580
|
+
// workaround to catch the character under the cursor
|
1581
|
+
// existing workaround doesn't cover actions
|
1582
|
+
curEnd=cm.clipPos({line: curEnd.line, ch: curEnd.ch+1});
|
1583
|
+
}else{
|
1584
|
+
var line = cm.getLine(curStart.line);
|
1585
|
+
replaceTo = curStart.ch + actionArgs.repeat;
|
1586
|
+
if (replaceTo > line.length) {
|
1587
|
+
replaceTo=line.length;
|
1588
|
+
}
|
1589
|
+
curEnd = { line: curStart.line, ch: replaceTo };
|
1590
|
+
}
|
1591
|
+
if(replaceWith=='\n'){
|
1592
|
+
if(!vim.visualMode) cm.replaceRange('', curStart, curEnd);
|
1593
|
+
// special case, where vim help says to replace by just one line-break
|
1594
|
+
(CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm);
|
1595
|
+
}else {
|
1596
|
+
var replaceWithStr=cm.getRange(curStart, curEnd);
|
1597
|
+
//replace all characters in range by selected, but keep linebreaks
|
1598
|
+
replaceWithStr=replaceWithStr.replace(/[^\n]/g,replaceWith);
|
1599
|
+
cm.replaceRange(replaceWithStr, curStart, curEnd);
|
1600
|
+
if(vim.visualMode){
|
1601
|
+
cm.setCursor(curStart);
|
1602
|
+
exitVisualMode(cm,vim);
|
1603
|
+
}else{
|
1604
|
+
cm.setCursor(offsetCursor(curEnd, 0, -1));
|
1605
|
+
}
|
1606
|
+
}
|
1607
|
+
},
|
1608
|
+
incrementNumberToken: function(cm, actionArgs, vim) {
|
1609
|
+
var cur = cm.getCursor();
|
1610
|
+
var lineStr = cm.getLine(cur.line);
|
1611
|
+
var re = /-?\d+/g;
|
1612
|
+
var match;
|
1613
|
+
var start;
|
1614
|
+
var end;
|
1615
|
+
var numberStr;
|
1616
|
+
var token;
|
1617
|
+
while ((match = re.exec(lineStr)) !== null) {
|
1618
|
+
token = match[0];
|
1619
|
+
start = match.index;
|
1620
|
+
end = start + token.length;
|
1621
|
+
if(cur.ch < end)break;
|
1622
|
+
}
|
1623
|
+
if(!actionArgs.backtrack && (end <= cur.ch))return;
|
1624
|
+
if (token) {
|
1625
|
+
var increment = actionArgs.increase ? 1 : -1;
|
1626
|
+
var number = parseInt(token) + (increment * actionArgs.repeat);
|
1627
|
+
var from = {ch:start, line:cur.line};
|
1628
|
+
var to = {ch:end, line:cur.line};
|
1629
|
+
numberStr = number.toString();
|
1630
|
+
cm.replaceRange(numberStr, from, to);
|
1631
|
+
} else {
|
1281
1632
|
return;
|
1282
1633
|
}
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1634
|
+
cm.setCursor({line: cur.line, ch: start + numberStr.length - 1});
|
1635
|
+
},
|
1636
|
+
repeatLastEdit: function(cm, actionArgs, vim) {
|
1637
|
+
// TODO: Make this repeat insert mode changes.
|
1638
|
+
var lastEdit = vim.lastEdit;
|
1639
|
+
if (lastEdit) {
|
1640
|
+
if (actionArgs.repeat && actionArgs.repeatIsExplicit) {
|
1641
|
+
vim.lastEdit.repeatOverride = actionArgs.repeat;
|
1642
|
+
}
|
1643
|
+
var currentInputState = vim.inputState;
|
1644
|
+
vim.inputState = vim.lastEdit;
|
1645
|
+
commandDispatcher.evalInput(cm, vim);
|
1646
|
+
vim.inputState = currentInputState;
|
1287
1647
|
}
|
1288
|
-
cm.replaceRange(replaceWithStr, curStart, curEnd);
|
1289
|
-
cm.setCursor(offsetCursor(curEnd, 0, -1));
|
1290
1648
|
}
|
1291
1649
|
};
|
1292
1650
|
|
@@ -1325,14 +1683,11 @@
|
|
1325
1683
|
*/
|
1326
1684
|
|
1327
1685
|
/**
|
1328
|
-
* Clips cursor to ensure that
|
1329
|
-
* 0 <= cur.ch < lineLength
|
1330
|
-
* AND
|
1331
|
-
* 0 <= cur.line < lineCount
|
1686
|
+
* Clips cursor to ensure that line is within the buffer's range
|
1332
1687
|
* If includeLineBreak is true, then allow cur.ch == lineLength.
|
1333
1688
|
*/
|
1334
1689
|
function clipCursorToContent(cm, cur, includeLineBreak) {
|
1335
|
-
var line = Math.min(Math.max(
|
1690
|
+
var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() );
|
1336
1691
|
var maxCh = lineLength(cm, line) - 1;
|
1337
1692
|
maxCh = (includeLineBreak) ? maxCh + 1 : maxCh;
|
1338
1693
|
var ch = Math.min(Math.max(0, cur.ch), maxCh);
|
@@ -1407,6 +1762,12 @@
|
|
1407
1762
|
}
|
1408
1763
|
return false;
|
1409
1764
|
}
|
1765
|
+
function cusrorIsBetween(cur1, cur2, cur3) {
|
1766
|
+
// returns true if cur2 is between cur1 and cur3.
|
1767
|
+
var cur1before2 = cursorIsBefore(cur1, cur2);
|
1768
|
+
var cur2before3 = cursorIsBefore(cur2, cur3);
|
1769
|
+
return cur1before2 && cur2before3;
|
1770
|
+
}
|
1410
1771
|
function lineLength(cm, lineNum) {
|
1411
1772
|
return cm.getLine(lineNum).length;
|
1412
1773
|
}
|
@@ -1515,6 +1876,134 @@
|
|
1515
1876
|
end: { line: cur.line, ch: wordEnd }};
|
1516
1877
|
}
|
1517
1878
|
|
1879
|
+
function recordLastCharacterSearch(increment, args) {
|
1880
|
+
var vimGlobalState = getVimGlobalState();
|
1881
|
+
vimGlobalState.lastChararacterSearch.increment = increment;
|
1882
|
+
vimGlobalState.lastChararacterSearch.forward = args.forward;
|
1883
|
+
vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter;
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
var symbolToMode = {
|
1887
|
+
'(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket',
|
1888
|
+
'[': 'section', ']': 'section',
|
1889
|
+
'*': 'comment', '/': 'comment',
|
1890
|
+
'm': 'method', 'M': 'method',
|
1891
|
+
'#': 'preprocess'
|
1892
|
+
};
|
1893
|
+
var findSymbolModes = {
|
1894
|
+
bracket: {
|
1895
|
+
isComplete: function(state) {
|
1896
|
+
if (state.nextCh === state.symb) {
|
1897
|
+
state.depth++;
|
1898
|
+
if(state.depth >= 1)return true;
|
1899
|
+
} else if (state.nextCh === state.reverseSymb) {
|
1900
|
+
state.depth--;
|
1901
|
+
}
|
1902
|
+
return false;
|
1903
|
+
}
|
1904
|
+
},
|
1905
|
+
section: {
|
1906
|
+
init: function(state) {
|
1907
|
+
state.curMoveThrough = true;
|
1908
|
+
state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}';
|
1909
|
+
},
|
1910
|
+
isComplete: function(state) {
|
1911
|
+
return state.index === 0 && state.nextCh === state.symb;
|
1912
|
+
}
|
1913
|
+
},
|
1914
|
+
comment: {
|
1915
|
+
isComplete: function(state) {
|
1916
|
+
var found = state.lastCh === '*' && state.nextCh === '/';
|
1917
|
+
state.lastCh = state.nextCh;
|
1918
|
+
return found;
|
1919
|
+
}
|
1920
|
+
},
|
1921
|
+
// TODO: The original Vim implementation only operates on level 1 and 2.
|
1922
|
+
// The current implementation doesn't check for code block level and
|
1923
|
+
// therefore it operates on any levels.
|
1924
|
+
method: {
|
1925
|
+
init: function(state) {
|
1926
|
+
state.symb = (state.symb === 'm' ? '{' : '}');
|
1927
|
+
state.reverseSymb = state.symb === '{' ? '}' : '{';
|
1928
|
+
},
|
1929
|
+
isComplete: function(state) {
|
1930
|
+
if(state.nextCh === state.symb)return true;
|
1931
|
+
return false;
|
1932
|
+
}
|
1933
|
+
},
|
1934
|
+
preprocess: {
|
1935
|
+
init: function(state) {
|
1936
|
+
state.index = 0;
|
1937
|
+
},
|
1938
|
+
isComplete: function(state) {
|
1939
|
+
if (state.nextCh === '#') {
|
1940
|
+
var token = state.lineText.match(/#(\w+)/)[1];
|
1941
|
+
if (token === 'endif') {
|
1942
|
+
if (state.forward && state.depth === 0) {
|
1943
|
+
return true;
|
1944
|
+
}
|
1945
|
+
state.depth++;
|
1946
|
+
} else if (token === 'if') {
|
1947
|
+
if (!state.forward && state.depth === 0) {
|
1948
|
+
return true;
|
1949
|
+
}
|
1950
|
+
state.depth--;
|
1951
|
+
}
|
1952
|
+
if(token === 'else' && state.depth === 0)return true;
|
1953
|
+
}
|
1954
|
+
return false;
|
1955
|
+
}
|
1956
|
+
}
|
1957
|
+
};
|
1958
|
+
function findSymbol(cm, repeat, forward, symb) {
|
1959
|
+
var cur = cm.getCursor();
|
1960
|
+
var increment = forward ? 1 : -1;
|
1961
|
+
var endLine = forward ? cm.lineCount() : -1;
|
1962
|
+
var curCh = cur.ch;
|
1963
|
+
var line = cur.line;
|
1964
|
+
var lineText = cm.getLine(line);
|
1965
|
+
var state = {
|
1966
|
+
lineText: lineText,
|
1967
|
+
nextCh: lineText.charAt(curCh),
|
1968
|
+
lastCh: null,
|
1969
|
+
index: curCh,
|
1970
|
+
symb: symb,
|
1971
|
+
reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb],
|
1972
|
+
forward: forward,
|
1973
|
+
depth: 0,
|
1974
|
+
curMoveThrough: false
|
1975
|
+
};
|
1976
|
+
var mode = symbolToMode[symb];
|
1977
|
+
if(!mode)return cur;
|
1978
|
+
var init = findSymbolModes[mode].init;
|
1979
|
+
var isComplete = findSymbolModes[mode].isComplete;
|
1980
|
+
if(init)init(state);
|
1981
|
+
while (line !== endLine && repeat) {
|
1982
|
+
state.index += increment;
|
1983
|
+
state.nextCh = state.lineText.charAt(state.index);
|
1984
|
+
if (!state.nextCh) {
|
1985
|
+
line += increment;
|
1986
|
+
state.lineText = cm.getLine(line) || '';
|
1987
|
+
if (increment > 0) {
|
1988
|
+
state.index = 0;
|
1989
|
+
} else {
|
1990
|
+
var lineLen = state.lineText.length;
|
1991
|
+
state.index = (lineLen > 0) ? (lineLen-1) : 0;
|
1992
|
+
}
|
1993
|
+
state.nextCh = state.lineText.charAt(state.index);
|
1994
|
+
}
|
1995
|
+
if (isComplete(state)) {
|
1996
|
+
cur.line = line;
|
1997
|
+
cur.ch = state.index;
|
1998
|
+
repeat--;
|
1999
|
+
}
|
2000
|
+
}
|
2001
|
+
if (state.nextCh || state.curMoveThrough) {
|
2002
|
+
return { line: line, ch: state.index };
|
2003
|
+
}
|
2004
|
+
return cur;
|
2005
|
+
}
|
2006
|
+
|
1518
2007
|
/*
|
1519
2008
|
* Returns the boundaries of the next word. If the cursor in the middle of
|
1520
2009
|
* the word, then returns the boundaries of the current word, starting at
|
@@ -1654,7 +2143,7 @@
|
|
1654
2143
|
var line = cm.getLine(cur.line);
|
1655
2144
|
idx = charIdxInLine(start, line, character, forward, true);
|
1656
2145
|
if (idx == -1) {
|
1657
|
-
return
|
2146
|
+
return null;
|
1658
2147
|
}
|
1659
2148
|
start = idx;
|
1660
2149
|
}
|
@@ -1703,9 +2192,6 @@
|
|
1703
2192
|
var line = cur.line;
|
1704
2193
|
symb = symb ? symb : cm.getLine(line).charAt(cur.ch);
|
1705
2194
|
|
1706
|
-
// Are we at the opening or closing char
|
1707
|
-
var forwards = inArray(symb, ['(', '[', '{']);
|
1708
|
-
|
1709
2195
|
var reverseSymb = ({
|
1710
2196
|
'(': ')', ')': '(',
|
1711
2197
|
'[': ']', ']': '[',
|
@@ -1719,18 +2205,24 @@
|
|
1719
2205
|
// set our increment to move forward (+1) or backwards (-1)
|
1720
2206
|
// depending on which bracket we're matching
|
1721
2207
|
var increment = ({'(': 1, '{': 1, '[': 1})[symb] || -1;
|
2208
|
+
var endLine = increment === 1 ? cm.lineCount() : -1;
|
1722
2209
|
var depth = 1, nextCh = symb, index = cur.ch, lineText = cm.getLine(line);
|
1723
2210
|
// Simple search for closing paren--just count openings and closings till
|
1724
2211
|
// we find our match
|
1725
2212
|
// TODO: use info from CodeMirror to ignore closing brackets in comments
|
1726
2213
|
// and quotes, etc.
|
1727
|
-
while (
|
2214
|
+
while (line !== endLine && depth > 0) {
|
1728
2215
|
index += increment;
|
1729
2216
|
nextCh = lineText.charAt(index);
|
1730
2217
|
if (!nextCh) {
|
1731
2218
|
line += increment;
|
1732
|
-
index = 0;
|
1733
2219
|
lineText = cm.getLine(line) || '';
|
2220
|
+
if (increment > 0) {
|
2221
|
+
index = 0;
|
2222
|
+
} else {
|
2223
|
+
var lineLen = lineText.length;
|
2224
|
+
index = (lineLen > 0) ? (lineLen-1) : 0;
|
2225
|
+
}
|
1734
2226
|
nextCh = lineText.charAt(index);
|
1735
2227
|
}
|
1736
2228
|
if (nextCh === symb) {
|
@@ -1829,10 +2321,7 @@
|
|
1829
2321
|
}
|
1830
2322
|
|
1831
2323
|
// Search functions
|
1832
|
-
function SearchState() {
|
1833
|
-
// Highlighted text that match the query.
|
1834
|
-
this.marked = null;
|
1835
|
-
}
|
2324
|
+
function SearchState() {}
|
1836
2325
|
SearchState.prototype = {
|
1837
2326
|
getQuery: function() {
|
1838
2327
|
return getVimGlobalState().query;
|
@@ -1840,12 +2329,6 @@
|
|
1840
2329
|
setQuery: function(query) {
|
1841
2330
|
getVimGlobalState().query = query;
|
1842
2331
|
},
|
1843
|
-
getMarked: function() {
|
1844
|
-
return this.marked;
|
1845
|
-
},
|
1846
|
-
setMarked: function(marked) {
|
1847
|
-
this.marked = marked;
|
1848
|
-
},
|
1849
2332
|
getOverlay: function() {
|
1850
2333
|
return this.searchOverlay;
|
1851
2334
|
},
|
@@ -1863,9 +2346,10 @@
|
|
1863
2346
|
var vim = getVimState(cm);
|
1864
2347
|
return vim.searchState_ || (vim.searchState_ = new SearchState());
|
1865
2348
|
}
|
1866
|
-
function dialog(cm,
|
2349
|
+
function dialog(cm, template, shortText, onClose, options) {
|
1867
2350
|
if (cm.openDialog) {
|
1868
|
-
cm.openDialog(
|
2351
|
+
cm.openDialog(template, onClose, { bottom: true, value: options.value,
|
2352
|
+
onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp });
|
1869
2353
|
}
|
1870
2354
|
else {
|
1871
2355
|
callback(prompt(shortText, ""));
|
@@ -1894,6 +2378,8 @@
|
|
1894
2378
|
* through to the Regex object.
|
1895
2379
|
*/
|
1896
2380
|
function parseQuery(cm, query, ignoreCase, smartCase) {
|
2381
|
+
// Check if the query is already a regex.
|
2382
|
+
if (query instanceof RegExp) { return query; }
|
1897
2383
|
// First try to extract regex + flags from the input. If no flags found,
|
1898
2384
|
// extract just the regex. IE does not accept flags directly defined in
|
1899
2385
|
// the regex string in the form /regex/flags
|
@@ -1915,13 +2401,9 @@
|
|
1915
2401
|
if (smartCase) {
|
1916
2402
|
ignoreCase = (/^[^A-Z]*$/).test(regexPart);
|
1917
2403
|
}
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
return regexp;
|
1922
|
-
} catch (e) {
|
1923
|
-
showConfirm(cm, 'Invalid regex: ' + regexPart);
|
1924
|
-
}
|
2404
|
+
var regexp = new RegExp(regexPart,
|
2405
|
+
(ignoreCase || forceIgnoreCase) ? 'i' : undefined);
|
2406
|
+
return regexp;
|
1925
2407
|
}
|
1926
2408
|
function showConfirm(cm, text) {
|
1927
2409
|
if (cm.openConfirm) {
|
@@ -1947,10 +2429,10 @@
|
|
1947
2429
|
return raw;
|
1948
2430
|
}
|
1949
2431
|
var searchPromptDesc = '(Javascript regexp)';
|
1950
|
-
function showPrompt(cm,
|
1951
|
-
var shortText = (prefix || '') + ' ' + (desc || '');
|
1952
|
-
|
1953
|
-
|
2432
|
+
function showPrompt(cm, options) {
|
2433
|
+
var shortText = (options.prefix || '') + ' ' + (options.desc || '');
|
2434
|
+
var prompt = makePrompt(options.prefix, options.desc);
|
2435
|
+
dialog(cm, prompt, shortText, options.onClose, options);
|
1954
2436
|
}
|
1955
2437
|
function regexEqual(r1, r2) {
|
1956
2438
|
if (r1 instanceof RegExp && r2 instanceof RegExp) {
|
@@ -1965,29 +2447,40 @@
|
|
1965
2447
|
}
|
1966
2448
|
return(false);
|
1967
2449
|
}
|
2450
|
+
// Returns true if the query is valid.
|
1968
2451
|
function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) {
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
state.setQuery(query);
|
1984
|
-
});
|
2452
|
+
if (!rawQuery) {
|
2453
|
+
return;
|
2454
|
+
}
|
2455
|
+
var state = getSearchState(cm);
|
2456
|
+
var query = parseQuery(cm, rawQuery, !!ignoreCase, !!smartCase);
|
2457
|
+
if (!query) {
|
2458
|
+
return;
|
2459
|
+
}
|
2460
|
+
highlightSearchMatches(cm, query);
|
2461
|
+
if (regexEqual(query, state.getQuery())) {
|
2462
|
+
return query;
|
2463
|
+
}
|
2464
|
+
state.setQuery(query);
|
2465
|
+
return query;
|
1985
2466
|
}
|
1986
2467
|
function searchOverlay(query) {
|
2468
|
+
if (query.source.charAt(0) == '^') {
|
2469
|
+
var matchSol = true;
|
2470
|
+
}
|
1987
2471
|
return {
|
1988
2472
|
token: function(stream) {
|
2473
|
+
if (matchSol && !stream.sol()) {
|
2474
|
+
stream.skipToEnd();
|
2475
|
+
return;
|
2476
|
+
}
|
1989
2477
|
var match = stream.match(query, false);
|
1990
2478
|
if (match) {
|
2479
|
+
if (match[0].length == 0) {
|
2480
|
+
// Matched empty string, skip to next.
|
2481
|
+
stream.next();
|
2482
|
+
return;
|
2483
|
+
}
|
1991
2484
|
if (!stream.sol()) {
|
1992
2485
|
// Backtrack 1 to match \b
|
1993
2486
|
stream.backUp(1);
|
@@ -2008,43 +2501,20 @@
|
|
2008
2501
|
};
|
2009
2502
|
}
|
2010
2503
|
function highlightSearchMatches(cm, query) {
|
2011
|
-
|
2012
|
-
|
2013
|
-
if (
|
2014
|
-
|
2015
|
-
cm.removeOverlay(overlay);
|
2016
|
-
}
|
2017
|
-
overlay = searchOverlay(query);
|
2018
|
-
cm.addOverlay(overlay);
|
2019
|
-
getSearchState(cm).setOverlay(overlay);
|
2020
|
-
}
|
2021
|
-
} else {
|
2022
|
-
// TODO: Highlight only text inside the viewport. Highlighting everything
|
2023
|
-
// is inefficient and expensive.
|
2024
|
-
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
|
2025
|
-
var marked = [];
|
2026
|
-
for (var cursor = cm.getSearchCursor(query);
|
2027
|
-
cursor.findNext();) {
|
2028
|
-
marked.push(cm.markText(cursor.from(), cursor.to(),
|
2029
|
-
{ className: 'cm-searching' }));
|
2030
|
-
}
|
2031
|
-
getSearchState(cm).setMarked(marked);
|
2504
|
+
var overlay = getSearchState(cm).getOverlay();
|
2505
|
+
if (!overlay || query != overlay.query) {
|
2506
|
+
if (overlay) {
|
2507
|
+
cm.removeOverlay(overlay);
|
2032
2508
|
}
|
2509
|
+
overlay = searchOverlay(query);
|
2510
|
+
cm.addOverlay(overlay);
|
2511
|
+
getSearchState(cm).setOverlay(overlay);
|
2033
2512
|
}
|
2034
2513
|
}
|
2035
|
-
function findNext(cm, prev, repeat) {
|
2514
|
+
function findNext(cm, prev, query, repeat) {
|
2515
|
+
if (repeat === undefined) { repeat = 1; }
|
2036
2516
|
return cm.operation(function() {
|
2037
|
-
var state = getSearchState(cm);
|
2038
|
-
var query = state.getQuery();
|
2039
|
-
if (!query) {
|
2040
|
-
return;
|
2041
|
-
}
|
2042
|
-
if (!state.getMarked()) {
|
2043
|
-
highlightSearchMatches(cm, query);
|
2044
|
-
}
|
2045
2517
|
var pos = cm.getCursor();
|
2046
|
-
// If search is initiated with ? instead of /, negate direction.
|
2047
|
-
prev = (state.isReversed()) ? !prev : prev;
|
2048
2518
|
if (!prev) {
|
2049
2519
|
pos.ch += 1;
|
2050
2520
|
}
|
@@ -2054,7 +2524,7 @@
|
|
2054
2524
|
// SearchCursor may have returned null because it hit EOF, wrap
|
2055
2525
|
// around and try again.
|
2056
2526
|
cursor = cm.getSearchCursor(query,
|
2057
|
-
(prev) ? { line: cm.
|
2527
|
+
(prev) ? { line: cm.lastLine() } : {line: cm.firstLine(), ch: 0} );
|
2058
2528
|
if (!cursor.find(prev)) {
|
2059
2529
|
return;
|
2060
2530
|
}
|
@@ -2063,25 +2533,8 @@
|
|
2063
2533
|
return cursor.from();
|
2064
2534
|
});}
|
2065
2535
|
function clearSearchHighlight(cm) {
|
2066
|
-
|
2067
|
-
|
2068
|
-
getSearchState(cm).setOverlay(null);
|
2069
|
-
} else {
|
2070
|
-
cm.operation(function() {
|
2071
|
-
var state = getSearchState(cm);
|
2072
|
-
if (!state.getQuery()) {
|
2073
|
-
return;
|
2074
|
-
}
|
2075
|
-
var marked = state.getMarked();
|
2076
|
-
if (!marked) {
|
2077
|
-
return;
|
2078
|
-
}
|
2079
|
-
for (var i = 0; i < marked.length; ++i) {
|
2080
|
-
marked[i].clear();
|
2081
|
-
}
|
2082
|
-
state.setMarked(null);
|
2083
|
-
});
|
2084
|
-
}
|
2536
|
+
cm.removeOverlay(getSearchState(cm).getOverlay());
|
2537
|
+
getSearchState(cm).setOverlay(null);
|
2085
2538
|
}
|
2086
2539
|
/**
|
2087
2540
|
* Check if pos is in the specified range, INCLUSIVE.
|
@@ -2109,6 +2562,15 @@
|
|
2109
2562
|
}
|
2110
2563
|
}
|
2111
2564
|
}
|
2565
|
+
function getUserVisibleLines(cm) {
|
2566
|
+
var scrollInfo = cm.getScrollInfo();
|
2567
|
+
var occludeTorleranceTop = 6;
|
2568
|
+
var occludeTorleranceBottom = 10;
|
2569
|
+
var from = cm.coordsChar({left:0, top: occludeTorleranceTop}, 'local');
|
2570
|
+
var bottomY = scrollInfo.clientHeight - occludeTorleranceBottom;
|
2571
|
+
var to = cm.coordsChar({left:0, top: bottomY}, 'local');
|
2572
|
+
return {top: from.line, bottom: to.line};
|
2573
|
+
}
|
2112
2574
|
|
2113
2575
|
// Ex command handling
|
2114
2576
|
// Care must be taken when adding to the default Ex command map. For any
|
@@ -2119,7 +2581,9 @@
|
|
2119
2581
|
{ name: 'write', shortName: 'w', type: 'builtIn' },
|
2120
2582
|
{ name: 'undo', shortName: 'u', type: 'builtIn' },
|
2121
2583
|
{ name: 'redo', shortName: 'red', type: 'builtIn' },
|
2122
|
-
{ name: 'substitute', shortName: 's', type: 'builtIn'}
|
2584
|
+
{ name: 'substitute', shortName: 's', type: 'builtIn'},
|
2585
|
+
{ name: 'nohlsearch', shortName: 'noh', type: 'builtIn'},
|
2586
|
+
{ name: 'delmarks', shortName: 'delm', type: 'builtin'}
|
2123
2587
|
];
|
2124
2588
|
Vim.ExCommandDispatcher = function() {
|
2125
2589
|
this.buildCommandMap_();
|
@@ -2169,8 +2633,8 @@
|
|
2169
2633
|
inputStream.eatWhile(':');
|
2170
2634
|
// Parse range.
|
2171
2635
|
if (inputStream.eat('%')) {
|
2172
|
-
result.line =
|
2173
|
-
result.lineEnd = cm.
|
2636
|
+
result.line = cm.firstLine();
|
2637
|
+
result.lineEnd = cm.lastLine();
|
2174
2638
|
} else {
|
2175
2639
|
result.line = this.parseLineSpec_(cm, inputStream);
|
2176
2640
|
if (result.line !== undefined && inputStream.eat(',')) {
|
@@ -2197,7 +2661,7 @@
|
|
2197
2661
|
case '.':
|
2198
2662
|
return cm.getCursor().line;
|
2199
2663
|
case '$':
|
2200
|
-
return cm.
|
2664
|
+
return cm.lastLine();
|
2201
2665
|
case '\'':
|
2202
2666
|
var mark = getVimState(cm).marks[inputStream.next()];
|
2203
2667
|
if (mark && mark.find()) {
|
@@ -2300,25 +2764,28 @@
|
|
2300
2764
|
var vimKeyNotationStart = ++idx;
|
2301
2765
|
while (str.charAt(idx++) != '>') {}
|
2302
2766
|
var vimKeyNotation = str.substring(vimKeyNotationStart, idx - 1);
|
2767
|
+
var mod='';
|
2303
2768
|
var match = (/^C-(.+)$/).exec(vimKeyNotation);
|
2304
2769
|
if (match) {
|
2305
|
-
|
2306
|
-
|
2307
|
-
case 'BS':
|
2308
|
-
key = 'Backspace';
|
2309
|
-
break;
|
2310
|
-
case 'CR':
|
2311
|
-
key = 'Enter';
|
2312
|
-
break;
|
2313
|
-
case 'Del':
|
2314
|
-
key = 'Delete';
|
2315
|
-
break;
|
2316
|
-
default:
|
2317
|
-
key = match[1];
|
2318
|
-
break;
|
2319
|
-
}
|
2320
|
-
keys.push('Ctrl-' + key);
|
2770
|
+
mod='Ctrl-';
|
2771
|
+
vimKeyNotation=match[1];
|
2321
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);
|
2322
2789
|
}
|
2323
2790
|
return keys;
|
2324
2791
|
}
|
@@ -2335,10 +2802,12 @@
|
|
2335
2802
|
exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
|
2336
2803
|
},
|
2337
2804
|
move: function(cm, params) {
|
2338
|
-
commandDispatcher.
|
2805
|
+
commandDispatcher.processCommand(cm, getVimState(cm), {
|
2806
|
+
type: 'motion',
|
2339
2807
|
motion: 'moveToLineOrEdgeOfDocument',
|
2340
2808
|
motionArgs: { forward: false, explicitRepeat: true,
|
2341
|
-
linewise: true
|
2809
|
+
linewise: true },
|
2810
|
+
repeatOverride: params.line+1});
|
2342
2811
|
},
|
2343
2812
|
substitute: function(cm, params) {
|
2344
2813
|
var argString = params.argString;
|
@@ -2368,12 +2837,17 @@
|
|
2368
2837
|
if (regexPart) {
|
2369
2838
|
// If regex part is empty, then use the previous query. Otherwise use
|
2370
2839
|
// the regex part as the new query.
|
2371
|
-
|
2372
|
-
true /**
|
2840
|
+
try {
|
2841
|
+
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
|
2842
|
+
true /** smartCase */);
|
2843
|
+
} catch (e) {
|
2844
|
+
showConfirm(cm, 'Invalid regex: ' + regexPart);
|
2845
|
+
return;
|
2846
|
+
}
|
2373
2847
|
}
|
2374
2848
|
var state = getSearchState(cm);
|
2375
2849
|
var query = state.getQuery();
|
2376
|
-
var lineStart = params.line ||
|
2850
|
+
var lineStart = params.line || cm.firstLine();
|
2377
2851
|
var lineEnd = params.lineEnd || lineStart;
|
2378
2852
|
if (count) {
|
2379
2853
|
lineStart = lineEnd;
|
@@ -2393,12 +2867,7 @@
|
|
2393
2867
|
exitVisualMode(cm, vim);
|
2394
2868
|
}
|
2395
2869
|
}
|
2396
|
-
|
2397
|
-
// Only exists in v2
|
2398
|
-
cm.compoundChange(doReplace);
|
2399
|
-
} else {
|
2400
|
-
cm.operation(doReplace);
|
2401
|
-
}
|
2870
|
+
cm.operation(doReplace);
|
2402
2871
|
},
|
2403
2872
|
redo: CodeMirror.commands.redo,
|
2404
2873
|
undo: CodeMirror.commands.undo,
|
@@ -2410,6 +2879,70 @@
|
|
2410
2879
|
// Saves to text area if no save command is defined.
|
2411
2880
|
cm.save();
|
2412
2881
|
}
|
2882
|
+
},
|
2883
|
+
nohlsearch: function(cm) {
|
2884
|
+
clearSearchHighlight(cm);
|
2885
|
+
},
|
2886
|
+
delmarks: function(cm, params) {
|
2887
|
+
if (!params.argString || !params.argString.trim()) {
|
2888
|
+
showConfirm(cm, 'Argument required');
|
2889
|
+
return;
|
2890
|
+
}
|
2891
|
+
|
2892
|
+
var state = getVimState(cm);
|
2893
|
+
var stream = new CodeMirror.StringStream(params.argString.trim());
|
2894
|
+
while (!stream.eol()) {
|
2895
|
+
stream.eatSpace();
|
2896
|
+
|
2897
|
+
// Record the streams position at the beginning of the loop for use
|
2898
|
+
// in error messages.
|
2899
|
+
var count = stream.pos;
|
2900
|
+
|
2901
|
+
if (!stream.match(/[a-zA-Z]/, false)) {
|
2902
|
+
showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
|
2903
|
+
return;
|
2904
|
+
}
|
2905
|
+
|
2906
|
+
var sym = stream.next();
|
2907
|
+
// Check if this symbol is part of a range
|
2908
|
+
if (stream.match('-', true)) {
|
2909
|
+
// This symbol is part of a range.
|
2910
|
+
|
2911
|
+
// The range must terminate at an alphabetic character.
|
2912
|
+
if (!stream.match(/[a-zA-Z]/, false)) {
|
2913
|
+
showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
|
2914
|
+
return;
|
2915
|
+
}
|
2916
|
+
|
2917
|
+
var startMark = sym;
|
2918
|
+
var finishMark = stream.next();
|
2919
|
+
// The range must terminate at an alphabetic character which
|
2920
|
+
// shares the same case as the start of the range.
|
2921
|
+
if (isLowerCase(startMark) && isLowerCase(finishMark) ||
|
2922
|
+
isUpperCase(startMark) && isUpperCase(finishMark)) {
|
2923
|
+
var start = startMark.charCodeAt(0);
|
2924
|
+
var finish = finishMark.charCodeAt(0);
|
2925
|
+
if (start >= finish) {
|
2926
|
+
showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
|
2927
|
+
return;
|
2928
|
+
}
|
2929
|
+
|
2930
|
+
// Because marks are always ASCII values, and we have
|
2931
|
+
// determined that they are the same case, we can use
|
2932
|
+
// their char codes to iterate through the defined range.
|
2933
|
+
for (var j = 0; j <= finish - start; j++) {
|
2934
|
+
var mark = String.fromCharCode(start + j);
|
2935
|
+
delete state.marks[mark];
|
2936
|
+
}
|
2937
|
+
} else {
|
2938
|
+
showConfirm(cm, 'Invalid argument: ' + startMark + "-");
|
2939
|
+
return;
|
2940
|
+
}
|
2941
|
+
} else {
|
2942
|
+
// This symbol is a valid mark, and is not part of a range.
|
2943
|
+
delete state.marks[sym];
|
2944
|
+
}
|
2945
|
+
}
|
2413
2946
|
}
|
2414
2947
|
};
|
2415
2948
|
|