codemirror-rails 4.6 → 4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +24 -25
- data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +1 -1
- data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +4 -1
- data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +7 -6
- data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +21 -8
- data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +54 -20
- data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +10 -15
- data/vendor/assets/javascripts/codemirror/addons/mode/simple.js +210 -0
- data/vendor/assets/javascripts/codemirror/addons/runmode/runmode-standalone.js +5 -1
- data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +2 -4
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +425 -554
- data/vendor/assets/javascripts/codemirror/modes/clike.js +28 -5
- data/vendor/assets/javascripts/codemirror/modes/clojure.js +5 -3
- data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +8 -7
- data/vendor/assets/javascripts/codemirror/modes/d.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/dtd.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/gherkin.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/go.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/haskell.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +3 -3
- data/vendor/assets/javascripts/codemirror/modes/julia.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +4 -3
- data/vendor/assets/javascripts/codemirror/modes/octave.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/perl.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/php.js +37 -44
- data/vendor/assets/javascripts/codemirror/modes/python.js +17 -4
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +12 -11
- data/vendor/assets/javascripts/codemirror/modes/rust.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/smartymixed.js +5 -1
- data/vendor/assets/javascripts/codemirror/modes/sql.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/stex.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/tcl.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/textile.js +553 -0
- data/vendor/assets/javascripts/codemirror/modes/tornado.js +68 -0
- data/vendor/assets/javascripts/codemirror/modes/verilog.js +14 -9
- data/vendor/assets/stylesheets/codemirror.css +1 -1
- data/vendor/assets/stylesheets/codemirror/themes/base16-dark.css +2 -2
- data/vendor/assets/stylesheets/codemirror/themes/mdn-like.css +1 -1
- metadata +4 -1
@@ -74,7 +74,11 @@ CodeMirror.startState = function (mode, a1, a2) {
|
|
74
74
|
};
|
75
75
|
|
76
76
|
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
|
77
|
-
CodeMirror.defineMode = function (name, mode) {
|
77
|
+
CodeMirror.defineMode = function (name, mode) {
|
78
|
+
if (arguments.length > 2)
|
79
|
+
mode.dependencies = Array.prototype.slice.call(arguments, 2);
|
80
|
+
modes[name] = mode;
|
81
|
+
};
|
78
82
|
CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };
|
79
83
|
CodeMirror.resolveMode = function(spec) {
|
80
84
|
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
|
@@ -74,10 +74,8 @@ exports.startState = function(mode, a1, a2) {
|
|
74
74
|
|
75
75
|
var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
|
76
76
|
exports.defineMode = function(name, mode) {
|
77
|
-
if (arguments.length > 2)
|
78
|
-
mode.dependencies =
|
79
|
-
for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
|
80
|
-
}
|
77
|
+
if (arguments.length > 2)
|
78
|
+
mode.dependencies = Array.prototype.slice.call(arguments, 2);
|
81
79
|
modes[name] = mode;
|
82
80
|
};
|
83
81
|
exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
|
@@ -72,290 +72,205 @@
|
|
72
72
|
var defaultKeymap = [
|
73
73
|
// Key to key mapping. This goes first to make it possible to override
|
74
74
|
// existing mappings.
|
75
|
-
{ keys:
|
76
|
-
{ keys:
|
77
|
-
{ keys:
|
78
|
-
{ keys:
|
79
|
-
{ keys:
|
80
|
-
{ keys:
|
81
|
-
{ keys:
|
82
|
-
{ keys:
|
83
|
-
{ keys:
|
84
|
-
{ keys:
|
85
|
-
{ keys:
|
86
|
-
{ keys:
|
87
|
-
{ keys:
|
88
|
-
{ keys:
|
89
|
-
{ keys: ['
|
90
|
-
{ keys:
|
91
|
-
{ keys:
|
92
|
-
{ keys:
|
93
|
-
{ keys:
|
94
|
-
{ keys:
|
95
|
-
{ keys:
|
96
|
-
{ keys:
|
97
|
-
{ keys:
|
75
|
+
{ keys: '<Left>', type: 'keyToKey', toKeys: 'h' },
|
76
|
+
{ keys: '<Right>', type: 'keyToKey', toKeys: 'l' },
|
77
|
+
{ keys: '<Up>', type: 'keyToKey', toKeys: 'k' },
|
78
|
+
{ keys: '<Down>', type: 'keyToKey', toKeys: 'j' },
|
79
|
+
{ keys: '<Space>', type: 'keyToKey', toKeys: 'l' },
|
80
|
+
{ keys: '<BS>', type: 'keyToKey', toKeys: 'h' },
|
81
|
+
{ keys: '<C-Space>', type: 'keyToKey', toKeys: 'W' },
|
82
|
+
{ keys: '<C-BS>', type: 'keyToKey', toKeys: 'B' },
|
83
|
+
{ keys: '<S-Space>', type: 'keyToKey', toKeys: 'w' },
|
84
|
+
{ keys: '<S-BS>', type: 'keyToKey', toKeys: 'b' },
|
85
|
+
{ keys: '<C-n>', type: 'keyToKey', toKeys: 'j' },
|
86
|
+
{ keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },
|
87
|
+
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },
|
88
|
+
{ keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>' },
|
89
|
+
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },
|
90
|
+
{ keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },
|
91
|
+
{ keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' },
|
92
|
+
{ keys: 's', type: 'keyToKey', toKeys: 'xi', context: 'visual'},
|
93
|
+
{ keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' },
|
94
|
+
{ keys: 'S', type: 'keyToKey', toKeys: 'dcc', context: 'visual' },
|
95
|
+
{ keys: '<Home>', type: 'keyToKey', toKeys: '0' },
|
96
|
+
{ keys: '<End>', type: 'keyToKey', toKeys: '$' },
|
97
|
+
{ keys: '<PageUp>', type: 'keyToKey', toKeys: '<C-b>' },
|
98
|
+
{ keys: '<PageDown>', type: 'keyToKey', toKeys: '<C-f>' },
|
99
|
+
{ keys: '<CR>', type: 'keyToKey', toKeys: 'j^', context: 'normal' },
|
98
100
|
// Motions
|
99
|
-
{ keys:
|
100
|
-
|
101
|
-
|
102
|
-
{ keys:
|
103
|
-
|
104
|
-
|
105
|
-
{ keys:
|
106
|
-
|
107
|
-
|
108
|
-
{ keys:
|
109
|
-
|
110
|
-
|
111
|
-
{ keys:
|
112
|
-
|
113
|
-
|
114
|
-
{ keys:
|
115
|
-
|
116
|
-
|
117
|
-
{ keys:
|
118
|
-
|
119
|
-
|
120
|
-
{ keys:
|
121
|
-
|
122
|
-
|
123
|
-
{ keys:
|
124
|
-
|
125
|
-
|
126
|
-
{ keys:
|
127
|
-
|
128
|
-
|
129
|
-
{ keys:
|
130
|
-
|
131
|
-
|
132
|
-
{ keys:
|
133
|
-
|
134
|
-
|
135
|
-
{ keys:
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
{ keys:
|
140
|
-
|
141
|
-
|
142
|
-
{ keys: ['
|
143
|
-
motion: 'moveByWords',
|
144
|
-
motionArgs: { forward: false, wordEnd: false, bigWord: true }},
|
145
|
-
{ keys: ['g', 'e'], type: 'motion',
|
146
|
-
motion: 'moveByWords',
|
147
|
-
motionArgs: { forward: false, wordEnd: true, inclusive: true }},
|
148
|
-
{ keys: ['g', 'E'], type: 'motion',
|
149
|
-
motion: 'moveByWords',
|
150
|
-
motionArgs: { forward: false, wordEnd: true, bigWord: true,
|
151
|
-
inclusive: true }},
|
152
|
-
{ keys: ['{'], type: 'motion', motion: 'moveByParagraph',
|
153
|
-
motionArgs: { forward: false, toJumplist: true }},
|
154
|
-
{ keys: ['}'], type: 'motion', motion: 'moveByParagraph',
|
155
|
-
motionArgs: { forward: true, toJumplist: true }},
|
156
|
-
{ keys: ['<C-f>'], type: 'motion',
|
157
|
-
motion: 'moveByPage', motionArgs: { forward: true }},
|
158
|
-
{ keys: ['<C-b>'], type: 'motion',
|
159
|
-
motion: 'moveByPage', motionArgs: { forward: false }},
|
160
|
-
{ keys: ['<C-d>'], type: 'motion',
|
161
|
-
motion: 'moveByScroll',
|
162
|
-
motionArgs: { forward: true, explicitRepeat: true }},
|
163
|
-
{ keys: ['<C-u>'], type: 'motion',
|
164
|
-
motion: 'moveByScroll',
|
165
|
-
motionArgs: { forward: false, explicitRepeat: true }},
|
166
|
-
{ keys: ['g', 'g'], type: 'motion',
|
167
|
-
motion: 'moveToLineOrEdgeOfDocument',
|
168
|
-
motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }},
|
169
|
-
{ keys: ['G'], type: 'motion',
|
170
|
-
motion: 'moveToLineOrEdgeOfDocument',
|
171
|
-
motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }},
|
172
|
-
{ keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' },
|
173
|
-
{ keys: ['^'], type: 'motion',
|
174
|
-
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
175
|
-
{ keys: ['+'], type: 'motion',
|
176
|
-
motion: 'moveByLines',
|
177
|
-
motionArgs: { forward: true, toFirstChar:true }},
|
178
|
-
{ keys: ['-'], type: 'motion',
|
179
|
-
motion: 'moveByLines',
|
180
|
-
motionArgs: { forward: false, toFirstChar:true }},
|
181
|
-
{ keys: ['_'], type: 'motion',
|
182
|
-
motion: 'moveByLines',
|
183
|
-
motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }},
|
184
|
-
{ keys: ['$'], type: 'motion',
|
185
|
-
motion: 'moveToEol',
|
186
|
-
motionArgs: { inclusive: true }},
|
187
|
-
{ keys: ['%'], type: 'motion',
|
188
|
-
motion: 'moveToMatchedSymbol',
|
189
|
-
motionArgs: { inclusive: true, toJumplist: true }},
|
190
|
-
{ keys: ['f', 'character'], type: 'motion',
|
191
|
-
motion: 'moveToCharacter',
|
192
|
-
motionArgs: { forward: true , inclusive: true }},
|
193
|
-
{ keys: ['F', 'character'], type: 'motion',
|
194
|
-
motion: 'moveToCharacter',
|
195
|
-
motionArgs: { forward: false }},
|
196
|
-
{ keys: ['t', 'character'], type: 'motion',
|
197
|
-
motion: 'moveTillCharacter',
|
198
|
-
motionArgs: { forward: true, inclusive: true }},
|
199
|
-
{ keys: ['T', 'character'], type: 'motion',
|
200
|
-
motion: 'moveTillCharacter',
|
201
|
-
motionArgs: { forward: false }},
|
202
|
-
{ keys: [';'], type: 'motion', motion: 'repeatLastCharacterSearch',
|
203
|
-
motionArgs: { forward: true }},
|
204
|
-
{ keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch',
|
205
|
-
motionArgs: { forward: false }},
|
206
|
-
{ keys: ['\'', 'character'], type: 'motion', motion: 'goToMark',
|
207
|
-
motionArgs: {toJumplist: true, linewise: true}},
|
208
|
-
{ keys: ['`', 'character'], type: 'motion', motion: 'goToMark',
|
209
|
-
motionArgs: {toJumplist: true}},
|
210
|
-
{ keys: [']', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
|
211
|
-
{ keys: ['[', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
|
212
|
-
{ keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
|
213
|
-
{ keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
|
101
|
+
{ keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true }},
|
102
|
+
{ keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true }},
|
103
|
+
{ keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true }},
|
104
|
+
{ keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }},
|
105
|
+
{ keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true }},
|
106
|
+
{ keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true }},
|
107
|
+
{ keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }},
|
108
|
+
{ keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true }},
|
109
|
+
{ keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false }},
|
110
|
+
{ keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }},
|
111
|
+
{ keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true }},
|
112
|
+
{ keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true }},
|
113
|
+
{ keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true }},
|
114
|
+
{ keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }},
|
115
|
+
{ keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true }},
|
116
|
+
{ keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true }},
|
117
|
+
{ keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }},
|
118
|
+
{ keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }},
|
119
|
+
{ keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }},
|
120
|
+
{ keys: '<C-f>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }},
|
121
|
+
{ keys: '<C-b>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }},
|
122
|
+
{ keys: '<C-d>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }},
|
123
|
+
{ keys: '<C-u>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }},
|
124
|
+
{ keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }},
|
125
|
+
{ keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }},
|
126
|
+
{ keys: '0', type: 'motion', motion: 'moveToStartOfLine' },
|
127
|
+
{ keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
128
|
+
{ keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }},
|
129
|
+
{ keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar:true }},
|
130
|
+
{ keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }},
|
131
|
+
{ keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true }},
|
132
|
+
{ keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true }},
|
133
|
+
{ keys: 'f<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }},
|
134
|
+
{ keys: 'F<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false }},
|
135
|
+
{ keys: 't<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true }},
|
136
|
+
{ keys: 'T<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }},
|
137
|
+
{ keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true }},
|
138
|
+
{ keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }},
|
139
|
+
{ keys: '\'<character>', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true, linewise: true}},
|
140
|
+
{ keys: '`<character>', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}},
|
141
|
+
{ keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
|
142
|
+
{ keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
|
143
|
+
{ keys: ']\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
|
144
|
+
{ keys: '[\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
|
214
145
|
// the next two aren't motions but must come before more general motion declarations
|
215
|
-
{ keys:
|
216
|
-
|
217
|
-
{ keys:
|
218
|
-
|
219
|
-
{ keys:
|
220
|
-
|
221
|
-
|
222
|
-
{ keys: ['[', 'character'], type: 'motion',
|
223
|
-
motion: 'moveToSymbol',
|
224
|
-
motionArgs: { forward: false, toJumplist: true}},
|
225
|
-
{ keys: ['|'], type: 'motion',
|
226
|
-
motion: 'moveToColumn',
|
227
|
-
motionArgs: { }},
|
228
|
-
{ keys: ['o'], type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: { }, context:'visual'},
|
229
|
-
{ keys: ['O'], type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'},
|
146
|
+
{ keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true}},
|
147
|
+
{ keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true}},
|
148
|
+
{ keys: ']<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true}},
|
149
|
+
{ keys: '[<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true}},
|
150
|
+
{ keys: '|', type: 'motion', motion: 'moveToColumn'},
|
151
|
+
{ keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context:'visual'},
|
152
|
+
{ keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'},
|
230
153
|
// Operators
|
231
|
-
{ keys:
|
232
|
-
{ keys:
|
233
|
-
{ keys:
|
234
|
-
{ keys:
|
235
|
-
|
236
|
-
{ keys:
|
237
|
-
|
238
|
-
{ keys:
|
239
|
-
{ keys: ['n'], type: 'motion', motion: 'findNext',
|
240
|
-
motionArgs: { forward: true, toJumplist: true }},
|
241
|
-
{ keys: ['N'], type: 'motion', motion: 'findNext',
|
242
|
-
motionArgs: { forward: false, toJumplist: true }},
|
154
|
+
{ keys: 'd', type: 'operator', operator: 'delete' },
|
155
|
+
{ keys: 'y', type: 'operator', operator: 'yank' },
|
156
|
+
{ keys: 'c', type: 'operator', operator: 'change' },
|
157
|
+
{ keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }},
|
158
|
+
{ keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }},
|
159
|
+
{ keys: 'g~', type: 'operator', operator: 'swapcase' },
|
160
|
+
{ keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }},
|
161
|
+
{ keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }},
|
243
162
|
// Operator-Motion dual commands
|
244
|
-
{ keys:
|
245
|
-
|
246
|
-
|
247
|
-
{ keys:
|
248
|
-
|
249
|
-
|
250
|
-
{ keys:
|
251
|
-
motion: 'moveToEol', motionArgs: { inclusive: true },
|
252
|
-
operatorMotionArgs: { visualLine: true }},
|
253
|
-
{ keys: ['Y'], type: 'operatorMotion', operator: 'yank',
|
254
|
-
motion: 'moveToEol', motionArgs: { inclusive: true },
|
255
|
-
operatorMotionArgs: { visualLine: true }},
|
256
|
-
{ keys: ['C'], type: 'operatorMotion',
|
257
|
-
operator: 'change',
|
258
|
-
motion: 'moveToEol', motionArgs: { inclusive: true },
|
259
|
-
operatorMotionArgs: { visualLine: true }},
|
260
|
-
{ keys: ['~'], type: 'operatorMotion',
|
261
|
-
operator: 'swapcase', operatorArgs: { shouldMoveCursor: true },
|
262
|
-
motion: 'moveByCharacters', motionArgs: { forward: true }},
|
163
|
+
{ keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }},
|
164
|
+
{ keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }},
|
165
|
+
{ keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, operatorMotionArgs: { visualLine: true }},
|
166
|
+
{ keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'moveToEol', motionArgs: { inclusive: true }, operatorMotionArgs: { visualLine: true }},
|
167
|
+
{ keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, operatorMotionArgs: { visualLine: true }},
|
168
|
+
{ keys: '~', type: 'operatorMotion', operator: 'swapcase', operatorArgs: { shouldMoveCursor: true }, motion: 'moveByCharacters', motionArgs: { forward: true }},
|
169
|
+
{ keys: '<C-w>', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' },
|
263
170
|
// Actions
|
264
|
-
{ keys:
|
265
|
-
|
266
|
-
{ keys:
|
267
|
-
|
268
|
-
{ keys:
|
269
|
-
|
270
|
-
|
271
|
-
{ keys:
|
272
|
-
|
273
|
-
|
274
|
-
{ keys:
|
275
|
-
|
276
|
-
{ keys:
|
277
|
-
|
278
|
-
{ keys:
|
279
|
-
{ keys:
|
280
|
-
|
281
|
-
{ keys:
|
282
|
-
|
283
|
-
{ keys:
|
284
|
-
|
285
|
-
actionArgs: { after: true }},
|
286
|
-
{ keys: ['O'], type: 'action', action: 'newLineAndEnterInsertMode',
|
287
|
-
isEdit: true, interlaceInsertRepeat: true,
|
288
|
-
actionArgs: { after: false }},
|
289
|
-
{ keys: ['v'], type: 'action', action: 'toggleVisualMode' },
|
290
|
-
{ keys: ['V'], type: 'action', action: 'toggleVisualMode',
|
291
|
-
actionArgs: { linewise: true }},
|
292
|
-
{ keys: ['<C-v>'], type: 'action', action: 'toggleVisualMode',
|
293
|
-
actionArgs: { blockwise: true }},
|
294
|
-
{ keys: ['g', 'v'], type: 'action', action: 'reselectLastSelection' },
|
295
|
-
{ keys: ['J'], type: 'action', action: 'joinLines', isEdit: true },
|
296
|
-
{ keys: ['p'], type: 'action', action: 'paste', isEdit: true,
|
297
|
-
actionArgs: { after: true, isEdit: true }},
|
298
|
-
{ keys: ['P'], type: 'action', action: 'paste', isEdit: true,
|
299
|
-
actionArgs: { after: false, isEdit: true }},
|
300
|
-
{ keys: ['r', 'character'], type: 'action', action: 'replace', isEdit: true },
|
301
|
-
{ keys: ['@', 'character'], type: 'action', action: 'replayMacro' },
|
302
|
-
{ keys: ['q', 'character'], type: 'action', action: 'enterMacroRecordMode' },
|
171
|
+
{ keys: '<C-i>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }},
|
172
|
+
{ keys: '<C-o>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }},
|
173
|
+
{ keys: '<C-e>', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true }},
|
174
|
+
{ keys: '<C-y>', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true }},
|
175
|
+
{ keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' },
|
176
|
+
{ keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' },
|
177
|
+
{ keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' },
|
178
|
+
{ keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' },
|
179
|
+
{ keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank' }},
|
180
|
+
{ keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' },
|
181
|
+
{ keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' },
|
182
|
+
{ keys: 'v', type: 'action', action: 'toggleVisualMode' },
|
183
|
+
{ keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }},
|
184
|
+
{ keys: '<C-v>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},
|
185
|
+
{ keys: 'gv', type: 'action', action: 'reselectLastSelection' },
|
186
|
+
{ keys: 'J', type: 'action', action: 'joinLines', isEdit: true },
|
187
|
+
{ keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }},
|
188
|
+
{ keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }},
|
189
|
+
{ keys: 'r<character>', type: 'action', action: 'replace', isEdit: true },
|
190
|
+
{ keys: '@<character>', type: 'action', action: 'replayMacro' },
|
191
|
+
{ keys: 'q<character>', type: 'action', action: 'enterMacroRecordMode' },
|
303
192
|
// Handle Replace-mode as a special case of insert mode.
|
304
|
-
{ keys:
|
305
|
-
|
306
|
-
{ keys:
|
307
|
-
{ keys:
|
308
|
-
{ keys:
|
309
|
-
{ keys:
|
310
|
-
{ keys:
|
311
|
-
{ keys:
|
312
|
-
{ keys:
|
313
|
-
|
314
|
-
{ keys:
|
315
|
-
|
316
|
-
|
317
|
-
{ keys:
|
318
|
-
|
319
|
-
{ keys:
|
320
|
-
actionArgs: { position: 'top' },
|
321
|
-
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
322
|
-
{ keys: ['z', '-'], type: 'action', action: 'scrollToCursor',
|
323
|
-
actionArgs: { position: 'bottom' }},
|
324
|
-
{ keys: ['z', 'b'], type: 'action', action: 'scrollToCursor',
|
325
|
-
actionArgs: { position: 'bottom' },
|
326
|
-
motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
327
|
-
{ keys: ['.'], type: 'action', action: 'repeatLastEdit' },
|
328
|
-
{ keys: ['<C-a>'], type: 'action', action: 'incrementNumberToken',
|
329
|
-
isEdit: true,
|
330
|
-
actionArgs: {increase: true, backtrack: false}},
|
331
|
-
{ keys: ['<C-x>'], type: 'action', action: 'incrementNumberToken',
|
332
|
-
isEdit: true,
|
333
|
-
actionArgs: {increase: false, backtrack: false}},
|
193
|
+
{ keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }},
|
194
|
+
{ keys: 'u', type: 'action', action: 'undo', context: 'normal' },
|
195
|
+
{ keys: 'u', type: 'action', action: 'changeCase', actionArgs: {toLower: true}, context: 'visual', isEdit: true },
|
196
|
+
{ keys: 'U',type: 'action', action: 'changeCase', actionArgs: {toLower: false}, context: 'visual', isEdit: true },
|
197
|
+
{ keys: '<C-r>', type: 'action', action: 'redo' },
|
198
|
+
{ keys: 'm<character>', type: 'action', action: 'setMark' },
|
199
|
+
{ keys: '"<character>', type: 'action', action: 'setRegister' },
|
200
|
+
{ keys: 'zz', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }},
|
201
|
+
{ keys: 'z.', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
202
|
+
{ keys: 'zt', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }},
|
203
|
+
{ keys: 'z<CR>', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
204
|
+
{ keys: 'z-', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }},
|
205
|
+
{ keys: 'zb', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
206
|
+
{ keys: '.', type: 'action', action: 'repeatLastEdit' },
|
207
|
+
{ keys: '<C-a>', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}},
|
208
|
+
{ keys: '<C-x>', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}},
|
334
209
|
// Text object motions
|
335
|
-
{ keys:
|
336
|
-
|
337
|
-
{ keys: ['i', 'character'], type: 'motion',
|
338
|
-
motion: 'textObjectManipulation',
|
339
|
-
motionArgs: { textObjectInner: true }},
|
210
|
+
{ keys: 'a<character>', type: 'motion', motion: 'textObjectManipulation' },
|
211
|
+
{ keys: 'i<character>', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }},
|
340
212
|
// Search
|
341
|
-
{ keys:
|
342
|
-
|
343
|
-
{ keys:
|
344
|
-
|
345
|
-
{ keys:
|
346
|
-
|
347
|
-
{ keys: ['#'], type: 'search',
|
348
|
-
searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},
|
349
|
-
{ keys: ['g', '*'], type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }},
|
350
|
-
{ keys: ['g', '#'], type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }},
|
213
|
+
{ keys: '/', type: 'search', searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }},
|
214
|
+
{ keys: '?', type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }},
|
215
|
+
{ keys: '*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},
|
216
|
+
{ keys: '#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},
|
217
|
+
{ keys: 'g*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }},
|
218
|
+
{ keys: 'g#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }},
|
351
219
|
// Ex command
|
352
|
-
{ keys:
|
220
|
+
{ keys: ':', type: 'ex' }
|
353
221
|
];
|
354
222
|
|
355
223
|
var Pos = CodeMirror.Pos;
|
356
224
|
|
225
|
+
var modifierCodes = [16, 17, 18, 91];
|
226
|
+
var specialKey = {Enter:'CR',Backspace:'BS',Delete:'Del'};
|
227
|
+
var mac = /Mac/.test(navigator.platform);
|
357
228
|
var Vim = function() {
|
358
229
|
CodeMirror.defineOption('vimMode', false, function(cm, val) {
|
230
|
+
function lookupKey(e) {
|
231
|
+
var keyCode = e.keyCode;
|
232
|
+
if (modifierCodes.indexOf(keyCode) != -1) { return; }
|
233
|
+
var hasModifier = e.ctrlKey || e.metaKey;
|
234
|
+
var key = CodeMirror.keyNames[keyCode];
|
235
|
+
key = specialKey[key] || key;
|
236
|
+
var name = '';
|
237
|
+
if (e.ctrlKey) { name += 'C-'; }
|
238
|
+
if (e.altKey) { name += 'A-'; }
|
239
|
+
if (mac && e.metaKey || (!hasModifier && e.shiftKey) && key.length < 2) {
|
240
|
+
// Shift key bindings can only specified for special characters.
|
241
|
+
return;
|
242
|
+
} else if (e.shiftKey && !/^[A-Za-z]$/.test(key)) {
|
243
|
+
name += 'S-';
|
244
|
+
}
|
245
|
+
if (key.length == 1) { key = key.toLowerCase(); }
|
246
|
+
name += key;
|
247
|
+
if (name.length > 1) { name = '<' + name + '>'; }
|
248
|
+
return name;
|
249
|
+
}
|
250
|
+
// Keys with modifiers are handled using keydown due to limitations of
|
251
|
+
// keypress event.
|
252
|
+
function handleKeyDown(cm, e) {
|
253
|
+
var name = lookupKey(e);
|
254
|
+
if (!name) { return; }
|
255
|
+
|
256
|
+
CodeMirror.signal(cm, 'vim-keypress', name);
|
257
|
+
if (CodeMirror.Vim.handleKey(cm, name, 'user')) {
|
258
|
+
CodeMirror.e_stop(e);
|
259
|
+
}
|
260
|
+
}
|
261
|
+
// Keys without modifiers are handled using keypress to work best with
|
262
|
+
// non-standard keyboard layouts.
|
263
|
+
function handleKeyPress(cm, e) {
|
264
|
+
var code = e.charCode || e.keyCode;
|
265
|
+
if (e.ctrlKey || e.metaKey || e.altKey ||
|
266
|
+
e.shiftKey && code < 32) { return; }
|
267
|
+
var name = String.fromCharCode(code);
|
268
|
+
|
269
|
+
CodeMirror.signal(cm, 'vim-keypress', name);
|
270
|
+
if (CodeMirror.Vim.handleKey(cm, name, 'user')) {
|
271
|
+
CodeMirror.e_stop(e);
|
272
|
+
}
|
273
|
+
}
|
359
274
|
if (val) {
|
360
275
|
cm.setOption('keyMap', 'vim');
|
361
276
|
cm.setOption('disableInput', true);
|
@@ -364,12 +279,16 @@
|
|
364
279
|
cm.on('cursorActivity', onCursorActivity);
|
365
280
|
maybeInitVimState(cm);
|
366
281
|
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
282
|
+
cm.on('keypress', handleKeyPress);
|
283
|
+
cm.on('keydown', handleKeyDown);
|
367
284
|
} else if (cm.state.vim) {
|
368
285
|
cm.setOption('keyMap', 'default');
|
369
286
|
cm.setOption('disableInput', false);
|
370
287
|
cm.off('cursorActivity', onCursorActivity);
|
371
288
|
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
372
289
|
cm.state.vim = null;
|
290
|
+
cm.off('keypress', handleKeyPress);
|
291
|
+
cm.off('keydown', handleKeyDown);
|
373
292
|
}
|
374
293
|
});
|
375
294
|
function getOnPasteFn(cm) {
|
@@ -397,9 +316,6 @@
|
|
397
316
|
var upperCaseAlphabet = makeKeyRange(65, 26);
|
398
317
|
var lowerCaseAlphabet = makeKeyRange(97, 26);
|
399
318
|
var numbers = makeKeyRange(48, 10);
|
400
|
-
var specialSymbols = '~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;"\''.split('');
|
401
|
-
var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
|
402
|
-
'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter'];
|
403
319
|
var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']);
|
404
320
|
var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']);
|
405
321
|
|
@@ -648,6 +564,7 @@
|
|
648
564
|
}
|
649
565
|
}
|
650
566
|
|
567
|
+
var lastInsertModeKeyTimer;
|
651
568
|
var vimApi= {
|
652
569
|
buildKeyMap: function() {
|
653
570
|
// TODO: Convert keymap into dictionary format for fast lookup.
|
@@ -685,58 +602,111 @@
|
|
685
602
|
},
|
686
603
|
// This is the outermost function called by CodeMirror, after keys have
|
687
604
|
// been mapped to their Vim equivalents.
|
688
|
-
handleKey: function(cm, key) {
|
689
|
-
var command;
|
605
|
+
handleKey: function(cm, key, origin) {
|
690
606
|
var vim = maybeInitVimState(cm);
|
691
|
-
|
692
|
-
|
693
|
-
if (
|
694
|
-
|
695
|
-
|
696
|
-
|
607
|
+
function handleMacroRecording() {
|
608
|
+
var macroModeState = vimGlobalState.macroModeState;
|
609
|
+
if (macroModeState.isRecording) {
|
610
|
+
if (key == 'q') {
|
611
|
+
macroModeState.exitMacroRecordMode();
|
612
|
+
clearInputState(cm);
|
613
|
+
return true;
|
614
|
+
}
|
615
|
+
if (origin != 'mapping') {
|
616
|
+
logKey(macroModeState, key);
|
617
|
+
}
|
697
618
|
}
|
698
619
|
}
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
620
|
+
function handleEsc() {
|
621
|
+
if (key == '<Esc>') {
|
622
|
+
// Clear input state and get back to normal mode.
|
623
|
+
clearInputState(cm);
|
624
|
+
if (vim.visualMode) {
|
625
|
+
exitVisualMode(cm);
|
626
|
+
} else if (vim.insertMode) {
|
627
|
+
exitInsertMode(cm);
|
628
|
+
}
|
629
|
+
return true;
|
704
630
|
}
|
705
|
-
return;
|
706
631
|
}
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
632
|
+
function doKeyToKey(keys) {
|
633
|
+
// TODO: prevent infinite recursion.
|
634
|
+
var match;
|
635
|
+
while (keys) {
|
636
|
+
// Pull off one command key, which is either a single character
|
637
|
+
// or a special sequence wrapped in '<' and '>', e.g. '<Space>'.
|
638
|
+
match = (/<\w+-.+?>|<\w+>|./).exec(keys);
|
639
|
+
key = match[0];
|
640
|
+
keys = keys.substring(match.index + key.length);
|
641
|
+
CodeMirror.Vim.handleKey(cm, key, 'mapping');
|
642
|
+
}
|
718
643
|
}
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
644
|
+
|
645
|
+
function handleKeyInsertMode() {
|
646
|
+
if (handleEsc()) { return true; }
|
647
|
+
var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;
|
648
|
+
var keysAreChars = key.length == 1;
|
649
|
+
var match = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert');
|
650
|
+
// Need to check all key substrings in insert mode.
|
651
|
+
while (keys.length > 1 && match.type != 'full') {
|
652
|
+
var keys = vim.inputState.keyBuffer = keys.slice(1);
|
653
|
+
var thisMatch = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert');
|
654
|
+
if (thisMatch.type != 'none') { match = thisMatch; }
|
723
655
|
}
|
724
|
-
if (
|
725
|
-
|
656
|
+
if (match.type == 'none') { clearInputState(cm); return false; }
|
657
|
+
else if (match.type == 'partial') {
|
658
|
+
if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); }
|
659
|
+
lastInsertModeKeyTimer = window.setTimeout(
|
660
|
+
function() { if (vim.insertMode && vim.inputState.keyBuffer) { clearInputState(cm); } },
|
661
|
+
getOption('insertModeEscKeysTimeout'));
|
662
|
+
return !keysAreChars;
|
726
663
|
}
|
727
|
-
|
664
|
+
|
665
|
+
if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); }
|
666
|
+
if (keysAreChars) {
|
667
|
+
var here = cm.getCursor();
|
668
|
+
cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');
|
669
|
+
}
|
670
|
+
clearInputState(cm);
|
671
|
+
var command = match.command;
|
672
|
+
if (command.type == 'keyToKey') {
|
673
|
+
doKeyToKey(command.toKeys);
|
674
|
+
} else {
|
675
|
+
commandDispatcher.processCommand(cm, vim, command);
|
676
|
+
}
|
677
|
+
return !keysAreChars;
|
728
678
|
}
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
679
|
+
|
680
|
+
function handleKeyNonInsertMode() {
|
681
|
+
if (handleMacroRecording() || handleEsc()) { return true; };
|
682
|
+
|
683
|
+
var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;
|
684
|
+
if (/^[1-9]\d*$/.test(keys)) { return true; }
|
685
|
+
|
686
|
+
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
687
|
+
if (!keysMatcher) { clearInputState(cm); return false; }
|
688
|
+
var context = vim.visualMode ? 'visual' :
|
689
|
+
'normal';
|
690
|
+
var match = commandDispatcher.matchCommand(keysMatcher[2] || keysMatcher[1], defaultKeymap, vim.inputState, context);
|
691
|
+
if (match.type == 'none') { clearInputState(cm); return false; }
|
692
|
+
else if (match.type == 'partial') { return true; }
|
693
|
+
|
694
|
+
vim.inputState.keyBuffer = '';
|
695
|
+
var command = match.command;
|
696
|
+
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
697
|
+
if (keysMatcher[1] && keysMatcher[1] != '0') {
|
698
|
+
vim.inputState.pushRepeatDigit(keysMatcher[1]);
|
733
699
|
}
|
734
|
-
|
735
|
-
|
736
|
-
|
700
|
+
if (command.type == 'keyToKey') {
|
701
|
+
doKeyToKey(command.toKeys);
|
702
|
+
} else {
|
703
|
+
commandDispatcher.processCommand(cm, vim, command);
|
737
704
|
}
|
738
|
-
|
705
|
+
return true;
|
739
706
|
}
|
707
|
+
|
708
|
+
if (vim.insertMode) { return handleKeyInsertMode(); }
|
709
|
+
else { return handleKeyNonInsertMode(); }
|
740
710
|
},
|
741
711
|
handleEx: function(cm, input) {
|
742
712
|
exCommandDispatcher.processCommand(cm, input);
|
@@ -953,83 +923,25 @@
|
|
953
923
|
}
|
954
924
|
};
|
955
925
|
var commandDispatcher = {
|
956
|
-
matchCommand: function(
|
957
|
-
var
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
var command = keyMap[i];
|
963
|
-
if (matchKeysPartial(keys, command.keys)) {
|
964
|
-
if (inputState.operator && command.type == 'action') {
|
965
|
-
// Ignore matched action commands after an operator. Operators
|
966
|
-
// only operate on motions. This check is really for text
|
967
|
-
// objects since aW, a[ etcs conflicts with a.
|
968
|
-
continue;
|
969
|
-
}
|
970
|
-
// Match commands that take <character> as an argument.
|
971
|
-
if (command.keys[keys.length - 1] == 'character') {
|
972
|
-
selectedCharacter = keys[keys.length - 1];
|
973
|
-
if (selectedCharacter.length>1){
|
974
|
-
switch(selectedCharacter){
|
975
|
-
case '<CR>':
|
976
|
-
selectedCharacter='\n';
|
977
|
-
break;
|
978
|
-
case '<Space>':
|
979
|
-
selectedCharacter=' ';
|
980
|
-
break;
|
981
|
-
default:
|
982
|
-
continue;
|
983
|
-
}
|
984
|
-
}
|
985
|
-
}
|
986
|
-
// Add the command to the list of matched commands. Choose the best
|
987
|
-
// command later.
|
988
|
-
matchedCommands.push(command);
|
989
|
-
}
|
926
|
+
matchCommand: function(keys, keyMap, inputState, context) {
|
927
|
+
var matches = commandMatches(keys, keyMap, context, inputState);
|
928
|
+
if (!matches.full && !matches.partial) {
|
929
|
+
return {type: 'none'};
|
930
|
+
} else if (!matches.full && matches.partial) {
|
931
|
+
return {type: 'partial'};
|
990
932
|
}
|
991
933
|
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
inputState.keyBuffer.push(key);
|
998
|
-
return null;
|
999
|
-
} else {
|
1000
|
-
if (command.keys[keys.length - 1] == 'character') {
|
1001
|
-
inputState.selectedCharacter = selectedCharacter;
|
1002
|
-
}
|
1003
|
-
// Clear the buffer since a full match was found.
|
1004
|
-
inputState.keyBuffer = [];
|
1005
|
-
return command;
|
934
|
+
var bestMatch;
|
935
|
+
for (var i = 0; i < matches.full.length; i++) {
|
936
|
+
var match = matches.full[i];
|
937
|
+
if (!bestMatch) {
|
938
|
+
bestMatch = match;
|
1006
939
|
}
|
1007
940
|
}
|
1008
|
-
|
1009
|
-
|
1010
|
-
// Clear the buffer since there were no matches.
|
1011
|
-
inputState.keyBuffer = [];
|
1012
|
-
return null;
|
1013
|
-
} else if (matchedCommands.length == 1) {
|
1014
|
-
return getFullyMatchedCommandOrNull(matchedCommands[0]);
|
1015
|
-
} else {
|
1016
|
-
// Find the best match in the list of matchedCommands.
|
1017
|
-
var context = vim.visualMode ? 'visual' : 'normal';
|
1018
|
-
var bestMatch; // Default to first in the list.
|
1019
|
-
for (var i = 0; i < matchedCommands.length; i++) {
|
1020
|
-
var current = matchedCommands[i];
|
1021
|
-
if (current.context == context) {
|
1022
|
-
bestMatch = current;
|
1023
|
-
break;
|
1024
|
-
} else if (!bestMatch && !current.context) {
|
1025
|
-
// Only set an imperfect match to best match if no best match is
|
1026
|
-
// set and the imperfect match is not restricted to another
|
1027
|
-
// context.
|
1028
|
-
bestMatch = current;
|
1029
|
-
}
|
1030
|
-
}
|
1031
|
-
return getFullyMatchedCommandOrNull(bestMatch);
|
941
|
+
if (bestMatch.keys.slice(-11) == '<character>') {
|
942
|
+
inputState.selectedCharacter = lastChar(keys);
|
1032
943
|
}
|
944
|
+
return {type: 'full', command: bestMatch};
|
1033
945
|
},
|
1034
946
|
processCommand: function(cm, vim, command) {
|
1035
947
|
vim.inputState.repeatOverride = command.repeatOverride;
|
@@ -1584,8 +1496,8 @@
|
|
1584
1496
|
|
1585
1497
|
var equal = cursorEqual(cursor, best);
|
1586
1498
|
var between = (motionArgs.forward) ?
|
1587
|
-
|
1588
|
-
|
1499
|
+
cursorIsBetween(cursor, mark, best) :
|
1500
|
+
cursorIsBetween(best, mark, cursor);
|
1589
1501
|
|
1590
1502
|
if (equal || between) {
|
1591
1503
|
best = mark;
|
@@ -1837,7 +1749,11 @@
|
|
1837
1749
|
return null;
|
1838
1750
|
}
|
1839
1751
|
|
1840
|
-
|
1752
|
+
if (!cm.state.vim.visualMode) {
|
1753
|
+
return [tmp.start, tmp.end];
|
1754
|
+
} else {
|
1755
|
+
return expandSelection(cm, tmp.start, tmp.end);
|
1756
|
+
}
|
1841
1757
|
},
|
1842
1758
|
|
1843
1759
|
repeatLastCharacterSearch: function(cm, motionArgs) {
|
@@ -1944,10 +1860,15 @@
|
|
1944
1860
|
// including the trailing \n, include the \n before the starting line
|
1945
1861
|
if (operatorArgs.linewise &&
|
1946
1862
|
curEnd.line == cm.lastLine() && curStart.line == curEnd.line) {
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
1863
|
+
if (curEnd.line == 0) {
|
1864
|
+
curStart.ch = 0;
|
1865
|
+
}
|
1866
|
+
else {
|
1867
|
+
var tmp = copyCursor(curEnd);
|
1868
|
+
curStart.line--;
|
1869
|
+
curStart.ch = lineLength(cm, curStart.line);
|
1870
|
+
curEnd = tmp;
|
1871
|
+
}
|
1951
1872
|
cm.replaceRange('', curStart, curEnd);
|
1952
1873
|
} else {
|
1953
1874
|
cm.replaceSelections(replacement);
|
@@ -2604,7 +2525,8 @@
|
|
2604
2525
|
if (vim.visualMode) {
|
2605
2526
|
exitVisualMode(cm);
|
2606
2527
|
}
|
2607
|
-
}
|
2528
|
+
},
|
2529
|
+
exitInsertMode: exitInsertMode
|
2608
2530
|
};
|
2609
2531
|
|
2610
2532
|
/*
|
@@ -2634,14 +2556,54 @@
|
|
2634
2556
|
function offsetCursor(cur, offsetLine, offsetCh) {
|
2635
2557
|
return Pos(cur.line + offsetLine, cur.ch + offsetCh);
|
2636
2558
|
}
|
2637
|
-
function
|
2638
|
-
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2559
|
+
function commandMatches(keys, keyMap, context, inputState) {
|
2560
|
+
// Partial matches are not applied. They inform the key handler
|
2561
|
+
// that the current key sequence is a subsequence of a valid key
|
2562
|
+
// sequence, so that the key buffer is not cleared.
|
2563
|
+
var match, partial = [], full = [];
|
2564
|
+
for (var i = 0; i < keyMap.length; i++) {
|
2565
|
+
var command = keyMap[i];
|
2566
|
+
if (context == 'insert' && command.context != 'insert' ||
|
2567
|
+
command.context && command.context != context ||
|
2568
|
+
inputState.operator && command.type == 'action' ||
|
2569
|
+
!(match = commandMatch(keys, command.keys))) { continue; }
|
2570
|
+
if (match == 'partial') { partial.push(command); }
|
2571
|
+
if (match == 'full') { full.push(command); }
|
2572
|
+
}
|
2573
|
+
return {
|
2574
|
+
partial: partial.length && partial,
|
2575
|
+
full: full.length && full
|
2576
|
+
};
|
2577
|
+
}
|
2578
|
+
function commandMatch(pressed, mapped) {
|
2579
|
+
if (mapped.slice(-11) == '<character>') {
|
2580
|
+
// Last character matches anything.
|
2581
|
+
var prefixLen = mapped.length - 11;
|
2582
|
+
var pressedPrefix = pressed.slice(0, prefixLen);
|
2583
|
+
var mappedPrefix = mapped.slice(0, prefixLen);
|
2584
|
+
return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? 'full' :
|
2585
|
+
mappedPrefix.indexOf(pressedPrefix) == 0 ? 'partial' : false;
|
2586
|
+
} else {
|
2587
|
+
return pressed == mapped ? 'full' :
|
2588
|
+
mapped.indexOf(pressed) == 0 ? 'partial' : false;
|
2589
|
+
}
|
2590
|
+
}
|
2591
|
+
function lastChar(keys) {
|
2592
|
+
var match = /^.*(<[\w\-]+>)$/.exec(keys);
|
2593
|
+
var selectedCharacter = match ? match[1] : keys.slice(-1);
|
2594
|
+
if (selectedCharacter.length > 1){
|
2595
|
+
switch(selectedCharacter){
|
2596
|
+
case '<CR>':
|
2597
|
+
selectedCharacter='\n';
|
2598
|
+
break;
|
2599
|
+
case '<Space>':
|
2600
|
+
selectedCharacter=' ';
|
2601
|
+
break;
|
2602
|
+
default:
|
2603
|
+
break;
|
2642
2604
|
}
|
2643
2605
|
}
|
2644
|
-
return
|
2606
|
+
return selectedCharacter;
|
2645
2607
|
}
|
2646
2608
|
function repeatFn(cm, fn, repeat) {
|
2647
2609
|
return function() {
|
@@ -2665,7 +2627,13 @@
|
|
2665
2627
|
}
|
2666
2628
|
return false;
|
2667
2629
|
}
|
2668
|
-
function
|
2630
|
+
function cursorMin(cur1, cur2) {
|
2631
|
+
return cursorIsBefore(cur1, cur2) ? cur1 : cur2;
|
2632
|
+
}
|
2633
|
+
function cursorMax(cur1, cur2) {
|
2634
|
+
return cursorIsBefore(cur1, cur2) ? cur2 : cur1;
|
2635
|
+
}
|
2636
|
+
function cursorIsBetween(cur1, cur2, cur3) {
|
2669
2637
|
// returns true if cur2 is between cur1 and cur3.
|
2670
2638
|
var cur1before2 = cursorIsBefore(cur1, cur2);
|
2671
2639
|
var cur2before3 = cursorIsBefore(cur2, cur3);
|
@@ -2892,6 +2860,33 @@
|
|
2892
2860
|
'visualLine': vim.visualLine,
|
2893
2861
|
'visualBlock': block};
|
2894
2862
|
}
|
2863
|
+
function expandSelection(cm, start, end) {
|
2864
|
+
var head = cm.getCursor('head');
|
2865
|
+
var anchor = cm.getCursor('anchor');
|
2866
|
+
var tmp;
|
2867
|
+
if (cursorIsBefore(end, start)) {
|
2868
|
+
tmp = end;
|
2869
|
+
end = start;
|
2870
|
+
start = tmp;
|
2871
|
+
}
|
2872
|
+
if (cursorIsBefore(head, anchor)) {
|
2873
|
+
head = cursorMin(start, head);
|
2874
|
+
anchor = cursorMax(anchor, end);
|
2875
|
+
} else {
|
2876
|
+
anchor = cursorMin(start, anchor);
|
2877
|
+
head = cursorMax(head, end);
|
2878
|
+
}
|
2879
|
+
return [anchor, head];
|
2880
|
+
}
|
2881
|
+
function getHead(cm) {
|
2882
|
+
var cur = cm.getCursor('head');
|
2883
|
+
if (cm.getSelection().length == 1) {
|
2884
|
+
// Small corner case when only 1 character is selected. The "real"
|
2885
|
+
// head is the left of head and anchor.
|
2886
|
+
cur = cursorMin(cur, cm.getCursor('anchor'));
|
2887
|
+
}
|
2888
|
+
return cur;
|
2889
|
+
}
|
2895
2890
|
|
2896
2891
|
function exitVisualMode(cm) {
|
2897
2892
|
cm.off('mousedown', exitVisualMode);
|
@@ -2964,7 +2959,7 @@
|
|
2964
2959
|
}
|
2965
2960
|
|
2966
2961
|
function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) {
|
2967
|
-
var cur = cm
|
2962
|
+
var cur = getHead(cm);
|
2968
2963
|
var line = cm.getLine(cur.line);
|
2969
2964
|
var idx = cur.ch;
|
2970
2965
|
|
@@ -3350,7 +3345,7 @@
|
|
3350
3345
|
// TODO: perhaps this finagling of start and end positions belonds
|
3351
3346
|
// in codmirror/replaceRange?
|
3352
3347
|
function selectCompanionObject(cm, symb, inclusive) {
|
3353
|
-
var cur = cm
|
3348
|
+
var cur = getHead(cm), start, end;
|
3354
3349
|
|
3355
3350
|
var bracketRegexp = ({
|
3356
3351
|
'(': /[()]/, ')': /[()]/,
|
@@ -3395,7 +3390,7 @@
|
|
3395
3390
|
// have identical opening and closing symbols
|
3396
3391
|
// TODO support across multiple lines
|
3397
3392
|
function findBeginningAndEnd(cm, symb, inclusive) {
|
3398
|
-
var cur = copyCursor(cm
|
3393
|
+
var cur = copyCursor(getHead(cm));
|
3399
3394
|
var line = cm.getLine(cur.line);
|
3400
3395
|
var chars = line.split('');
|
3401
3396
|
var start, end, i, len;
|
@@ -3828,6 +3823,7 @@
|
|
3828
3823
|
// shortNames must not match the prefix of the other command.
|
3829
3824
|
var defaultExCommandMap = [
|
3830
3825
|
{ name: 'map' },
|
3826
|
+
{ name: 'imap', shortName: 'im' },
|
3831
3827
|
{ name: 'nmap', shortName: 'nm' },
|
3832
3828
|
{ name: 'vmap', shortName: 'vm' },
|
3833
3829
|
{ name: 'unmap' },
|
@@ -3882,7 +3878,7 @@
|
|
3882
3878
|
if (command.type == 'exToKey') {
|
3883
3879
|
// Handle Ex to Key mapping.
|
3884
3880
|
for (var i = 0; i < command.toKeys.length; i++) {
|
3885
|
-
CodeMirror.Vim.handleKey(cm, command.toKeys[i]);
|
3881
|
+
CodeMirror.Vim.handleKey(cm, command.toKeys[i], 'mapping');
|
3886
3882
|
}
|
3887
3883
|
return;
|
3888
3884
|
} else if (command.type == 'exToEx') {
|
@@ -4006,7 +4002,7 @@
|
|
4006
4002
|
this.commandMap_[commandName] = {
|
4007
4003
|
name: commandName,
|
4008
4004
|
type: 'exToKey',
|
4009
|
-
toKeys:
|
4005
|
+
toKeys: rhs,
|
4010
4006
|
user: true
|
4011
4007
|
};
|
4012
4008
|
}
|
@@ -4014,7 +4010,7 @@
|
|
4014
4010
|
if (rhs != ':' && rhs.charAt(0) == ':') {
|
4015
4011
|
// Key to Ex mapping.
|
4016
4012
|
var mapping = {
|
4017
|
-
keys:
|
4013
|
+
keys: lhs,
|
4018
4014
|
type: 'keyToEx',
|
4019
4015
|
exArgs: { input: rhs.substring(1) },
|
4020
4016
|
user: true};
|
@@ -4023,9 +4019,9 @@
|
|
4023
4019
|
} else {
|
4024
4020
|
// Key to key mapping
|
4025
4021
|
var mapping = {
|
4026
|
-
keys:
|
4022
|
+
keys: lhs,
|
4027
4023
|
type: 'keyToKey',
|
4028
|
-
toKeys:
|
4024
|
+
toKeys: rhs,
|
4029
4025
|
user: true
|
4030
4026
|
};
|
4031
4027
|
if (ctx) { mapping.context = ctx; }
|
@@ -4034,15 +4030,6 @@
|
|
4034
4030
|
}
|
4035
4031
|
},
|
4036
4032
|
unmap: function(lhs, ctx) {
|
4037
|
-
var arrayEquals = function(a, b) {
|
4038
|
-
if (a === b) return true;
|
4039
|
-
if (a == null || b == null) return true;
|
4040
|
-
if (a.length != b.length) return false;
|
4041
|
-
for (var i = 0; i < a.length; i++) {
|
4042
|
-
if (a[i] !== b[i]) return false;
|
4043
|
-
}
|
4044
|
-
return true;
|
4045
|
-
};
|
4046
4033
|
if (lhs != ':' && lhs.charAt(0) == ':') {
|
4047
4034
|
// Ex to Ex or Ex to key mapping
|
4048
4035
|
if (ctx) { throw Error('Mode not supported for ex mappings'); }
|
@@ -4053,9 +4040,9 @@
|
|
4053
4040
|
}
|
4054
4041
|
} else {
|
4055
4042
|
// Key to Ex or key to key mapping
|
4056
|
-
var keys =
|
4043
|
+
var keys = lhs;
|
4057
4044
|
for (var i = 0; i < defaultKeymap.length; i++) {
|
4058
|
-
if (
|
4045
|
+
if (keys == defaultKeymap[i].keys
|
4059
4046
|
&& defaultKeymap[i].context === ctx
|
4060
4047
|
&& defaultKeymap[i].user) {
|
4061
4048
|
defaultKeymap.splice(i, 1);
|
@@ -4067,21 +4054,6 @@
|
|
4067
4054
|
}
|
4068
4055
|
};
|
4069
4056
|
|
4070
|
-
// Converts a key string sequence of the form a<C-w>bd<Left> into Vim's
|
4071
|
-
// keymap representation.
|
4072
|
-
function parseKeyString(str) {
|
4073
|
-
var key, match;
|
4074
|
-
var keys = [];
|
4075
|
-
while (str) {
|
4076
|
-
match = (/<\w+-.+?>|<\w+>|./).exec(str);
|
4077
|
-
if (match === null)break;
|
4078
|
-
key = match[0];
|
4079
|
-
str = str.substring(match.index + key.length);
|
4080
|
-
keys.push(key);
|
4081
|
-
}
|
4082
|
-
return keys;
|
4083
|
-
}
|
4084
|
-
|
4085
4057
|
var exCommands = {
|
4086
4058
|
map: function(cm, params, ctx) {
|
4087
4059
|
var mapArgs = params.args;
|
@@ -4093,6 +4065,7 @@
|
|
4093
4065
|
}
|
4094
4066
|
exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx);
|
4095
4067
|
},
|
4068
|
+
imap: function(cm, params) { this.map(cm, params, 'insert'); },
|
4096
4069
|
nmap: function(cm, params) { this.map(cm, params, 'normal'); },
|
4097
4070
|
vmap: function(cm, params) { this.map(cm, params, 'visual'); },
|
4098
4071
|
unmap: function(cm, params, ctx) {
|
@@ -4574,65 +4547,10 @@
|
|
4574
4547
|
});
|
4575
4548
|
}
|
4576
4549
|
|
4577
|
-
|
4578
|
-
function buildVimKeyMap() {
|
4579
|
-
/**
|
4580
|
-
* Handle the raw key event from CodeMirror. Translate the
|
4581
|
-
* Shift + key modifier to the resulting letter, while preserving other
|
4582
|
-
* modifers.
|
4583
|
-
*/
|
4584
|
-
function cmKeyToVimKey(key, modifier) {
|
4585
|
-
var vimKey = key;
|
4586
|
-
if (isUpperCase(vimKey) && modifier == 'Ctrl') {
|
4587
|
-
vimKey = vimKey.toLowerCase();
|
4588
|
-
}
|
4589
|
-
if (modifier) {
|
4590
|
-
// Vim will parse modifier+key combination as a single key.
|
4591
|
-
vimKey = modifier.charAt(0) + '-' + vimKey;
|
4592
|
-
}
|
4593
|
-
var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[vimKey];
|
4594
|
-
vimKey = specialKey ? specialKey : vimKey;
|
4595
|
-
vimKey = vimKey.length > 1 ? '<'+ vimKey + '>' : vimKey;
|
4596
|
-
return vimKey;
|
4597
|
-
}
|
4598
|
-
|
4599
|
-
// Closure to bind CodeMirror, key, modifier.
|
4600
|
-
function keyMapper(vimKey) {
|
4601
|
-
return function(cm) {
|
4602
|
-
CodeMirror.signal(cm, 'vim-keypress', vimKey);
|
4603
|
-
CodeMirror.Vim.handleKey(cm, vimKey);
|
4604
|
-
};
|
4605
|
-
}
|
4606
|
-
|
4607
|
-
var cmToVimKeymap = {
|
4550
|
+
CodeMirror.keyMap.vim = {
|
4608
4551
|
'nofallthrough': true,
|
4609
4552
|
'style': 'fat-cursor'
|
4610
4553
|
};
|
4611
|
-
function bindKeys(keys, modifier) {
|
4612
|
-
for (var i = 0; i < keys.length; i++) {
|
4613
|
-
var key = keys[i];
|
4614
|
-
if (!modifier && key.length == 1) {
|
4615
|
-
// Wrap all keys without modifiers with '' to identify them by their
|
4616
|
-
// key characters instead of key identifiers.
|
4617
|
-
key = "'" + key + "'";
|
4618
|
-
}
|
4619
|
-
var vimKey = cmKeyToVimKey(keys[i], modifier);
|
4620
|
-
var cmKey = modifier ? modifier + '-' + key : key;
|
4621
|
-
cmToVimKeymap[cmKey] = keyMapper(vimKey);
|
4622
|
-
}
|
4623
|
-
}
|
4624
|
-
bindKeys(upperCaseAlphabet);
|
4625
|
-
bindKeys(lowerCaseAlphabet);
|
4626
|
-
bindKeys(upperCaseAlphabet, 'Ctrl');
|
4627
|
-
bindKeys(specialSymbols);
|
4628
|
-
bindKeys(specialSymbols, 'Ctrl');
|
4629
|
-
bindKeys(numbers);
|
4630
|
-
bindKeys(numbers, 'Ctrl');
|
4631
|
-
bindKeys(specialKeys);
|
4632
|
-
bindKeys(specialKeys, 'Ctrl');
|
4633
|
-
return cmToVimKeymap;
|
4634
|
-
}
|
4635
|
-
CodeMirror.keyMap.vim = buildVimKeyMap();
|
4636
4554
|
|
4637
4555
|
function exitInsertMode(cm) {
|
4638
4556
|
var vim = cm.state.vim;
|
@@ -4688,63 +4606,13 @@
|
|
4688
4606
|
}
|
4689
4607
|
}
|
4690
4608
|
|
4691
|
-
defineOption('enableInsertModeEscKeys', false, 'boolean');
|
4692
|
-
// Use this option to customize the two-character ESC keymap.
|
4693
|
-
// If you want to use characters other than i j or k you'll have to add
|
4694
|
-
// lines to the vim-insert and await-second keymaps later in this file.
|
4695
|
-
defineOption('insertModeEscKeys', 'kj', 'string');
|
4696
4609
|
// The timeout in milliseconds for the two-character ESC keymap should be
|
4697
4610
|
// adjusted according to your typing speed to prevent false positives.
|
4698
4611
|
defineOption('insertModeEscKeysTimeout', 200, 'number');
|
4699
|
-
function firstEscCharacterHandler(ch) {
|
4700
|
-
return function(cm){
|
4701
|
-
var keys = getOption('insertModeEscKeys');
|
4702
|
-
var firstEscCharacter = keys && keys.length > 1 && keys.charAt(0);
|
4703
|
-
if (!getOption('enableInsertModeEscKeys')|| firstEscCharacter !== ch) {
|
4704
|
-
return CodeMirror.Pass;
|
4705
|
-
} else {
|
4706
|
-
cm.replaceRange(ch, cm.getCursor(), cm.getCursor(), "+input");
|
4707
|
-
cm.setOption('keyMap', 'await-second');
|
4708
|
-
cm.state.vim.awaitingEscapeSecondCharacter = true;
|
4709
|
-
setTimeout(
|
4710
|
-
function(){
|
4711
|
-
if(cm.state.vim.awaitingEscapeSecondCharacter) {
|
4712
|
-
cm.state.vim.awaitingEscapeSecondCharacter = false;
|
4713
|
-
cm.setOption('keyMap', 'vim-insert');
|
4714
|
-
}
|
4715
|
-
},
|
4716
|
-
getOption('insertModeEscKeysTimeout'));
|
4717
|
-
}
|
4718
|
-
};
|
4719
|
-
}
|
4720
|
-
function secondEscCharacterHandler(ch){
|
4721
|
-
return function(cm) {
|
4722
|
-
var keys = getOption('insertModeEscKeys');
|
4723
|
-
var secondEscCharacter = keys && keys.length > 1 && keys.charAt(1);
|
4724
|
-
if (!getOption('enableInsertModeEscKeys')|| secondEscCharacter !== ch) {
|
4725
|
-
return CodeMirror.Pass;
|
4726
|
-
// This is not the handler you're looking for. Just insert as usual.
|
4727
|
-
} else {
|
4728
|
-
if (cm.state.vim.insertMode) {
|
4729
|
-
var lastChange = vimGlobalState.macroModeState.lastInsertModeChanges;
|
4730
|
-
if (lastChange && lastChange.changes.length) {
|
4731
|
-
lastChange.changes.pop();
|
4732
|
-
}
|
4733
|
-
}
|
4734
|
-
cm.state.vim.awaitingEscapeSecondCharacter = false;
|
4735
|
-
cm.replaceRange('', {ch: cm.getCursor().ch - 1, line: cm.getCursor().line},
|
4736
|
-
cm.getCursor(), "+input");
|
4737
|
-
exitInsertMode(cm);
|
4738
|
-
}
|
4739
|
-
};
|
4740
|
-
}
|
4741
4612
|
|
4742
4613
|
CodeMirror.keyMap['vim-insert'] = {
|
4743
4614
|
// TODO: override navigation keys so that Esc will cancel automatic
|
4744
4615
|
// indentation from o, O, i_<CR>
|
4745
|
-
'Esc': exitInsertMode,
|
4746
|
-
'Ctrl-[': exitInsertMode,
|
4747
|
-
'Ctrl-C': exitInsertMode,
|
4748
4616
|
'Ctrl-N': 'autocomplete',
|
4749
4617
|
'Ctrl-P': 'autocomplete',
|
4750
4618
|
'Enter': function(cm) {
|
@@ -4752,20 +4620,10 @@
|
|
4752
4620
|
CodeMirror.commands.newlineAndIndent;
|
4753
4621
|
fn(cm);
|
4754
4622
|
},
|
4755
|
-
// The next few lines are where you'd add additional handlers if
|
4756
|
-
// you wanted to use keys other than i j and k for two-character
|
4757
|
-
// escape sequences. Don't forget to add them in the await-second
|
4758
|
-
// section as well.
|
4759
|
-
"'i'": firstEscCharacterHandler('i'),
|
4760
|
-
"'j'": firstEscCharacterHandler('j'),
|
4761
|
-
"'k'": firstEscCharacterHandler('k'),
|
4762
4623
|
fallthrough: ['default']
|
4763
4624
|
};
|
4764
4625
|
|
4765
4626
|
CodeMirror.keyMap['await-second'] = {
|
4766
|
-
"'i'": secondEscCharacterHandler('i'),
|
4767
|
-
"'j'": secondEscCharacterHandler('j'),
|
4768
|
-
"'k'": secondEscCharacterHandler('k'),
|
4769
4627
|
fallthrough: ['vim-insert']
|
4770
4628
|
};
|
4771
4629
|
|
@@ -4789,7 +4647,7 @@
|
|
4789
4647
|
match = (/<\w+-.+?>|<\w+>|./).exec(text);
|
4790
4648
|
key = match[0];
|
4791
4649
|
text = text.substring(match.index + key.length);
|
4792
|
-
CodeMirror.Vim.handleKey(cm, key);
|
4650
|
+
CodeMirror.Vim.handleKey(cm, key, 'macro');
|
4793
4651
|
if (vim.insertMode) {
|
4794
4652
|
var changes = register.insertModeChanges[imc++].changes;
|
4795
4653
|
vimGlobalState.macroModeState.lastInsertModeChanges.changes =
|
@@ -4869,10 +4727,7 @@
|
|
4869
4727
|
} else if (cm.doc.history.lastSelOrigin == '*mouse') {
|
4870
4728
|
// Reset lastHPos if mouse click was done in normal mode.
|
4871
4729
|
vim.lastHPos = cm.doc.getCursor().ch;
|
4872
|
-
|
4873
|
-
// If something is still selected, enter visual mode.
|
4874
|
-
vim.visualMode = true;
|
4875
|
-
}
|
4730
|
+
handleExternalSelection(cm, vim);
|
4876
4731
|
}
|
4877
4732
|
if (vim.visualMode) {
|
4878
4733
|
var from, head;
|
@@ -4891,6 +4746,22 @@
|
|
4891
4746
|
}
|
4892
4747
|
}
|
4893
4748
|
|
4749
|
+
function handleExternalSelection(cm, vim) {
|
4750
|
+
var anchor = cm.getCursor('anchor');
|
4751
|
+
var head = cm.getCursor('head');
|
4752
|
+
// Enter visual mode when the mouse selects text.
|
4753
|
+
if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) {
|
4754
|
+
vim.visualMode = true;
|
4755
|
+
vim.visualLine = false;
|
4756
|
+
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"});
|
4757
|
+
cm.on('mousedown', exitVisualMode);
|
4758
|
+
}
|
4759
|
+
if (vim.visualMode) {
|
4760
|
+
updateMark(cm, vim, '<', cursorMin(head, anchor));
|
4761
|
+
updateMark(cm, vim, '>', cursorMax(head, anchor));
|
4762
|
+
}
|
4763
|
+
}
|
4764
|
+
|
4894
4765
|
/** Wrapper for special keys pressed in insert mode */
|
4895
4766
|
function InsertModeKey(keyName) {
|
4896
4767
|
this.keyName = keyName;
|