codemirror-rails 4.6 → 4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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;
|