codemirror-rails 3.02 → 3.12
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 +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
|
|