codemirror-rails 3.00 → 3.02
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.
- data/README.md +5 -2
- data/lib/codemirror/rails/version.rb +2 -2
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/db/.gitkeep +0 -0
- data/test/integration/codemirror_rails_integration_test.rb +1 -1
- data/vendor/assets/javascripts/codemirror.js +385 -152
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +279 -66
- data/vendor/assets/javascripts/codemirror/modes/apl.js +160 -0
- data/vendor/assets/javascripts/codemirror/modes/asterisk.js +183 -0
- data/vendor/assets/javascripts/codemirror/modes/clike.js +2 -0
- data/vendor/assets/javascripts/codemirror/modes/clojure.js +3 -3
- data/vendor/assets/javascripts/codemirror/modes/css.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/d.js +205 -0
- data/vendor/assets/javascripts/codemirror/modes/gfm.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +13 -2
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +8 -7
- data/vendor/assets/javascripts/codemirror/modes/properties.js +0 -0
- data/vendor/assets/javascripts/codemirror/modes/sass.js +349 -0
- data/vendor/assets/javascripts/codemirror/modes/sieve.js +37 -10
- data/vendor/assets/javascripts/codemirror/modes/sql.js +268 -0
- data/vendor/assets/javascripts/codemirror/modes/xquery.js +8 -8
- data/vendor/assets/javascripts/codemirror/utils/collapserange.js +68 -0
- data/vendor/assets/javascripts/codemirror/utils/dialog.js +1 -0
- data/vendor/assets/javascripts/codemirror/utils/foldcode.js +2 -1
- data/vendor/assets/javascripts/codemirror/utils/formatting.js +9 -3
- data/vendor/assets/javascripts/codemirror/utils/javascript-hint.js +5 -4
- data/vendor/assets/javascripts/codemirror/utils/python-hint.js +93 -0
- data/vendor/assets/javascripts/codemirror/utils/runmode-standalone.js +51 -10
- data/vendor/assets/javascripts/codemirror/utils/search.js +20 -8
- data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +17 -10
- data/vendor/assets/stylesheets/codemirror.css +10 -9
- metadata +47 -15
- data/vendor/assets/javascripts/codemirror/modes/xmlpure.js +0 -490
- data/vendor/assets/stylesheets/codemirror/modes/diff.css +0 -3
@@ -115,6 +115,10 @@
|
|
115
115
|
motion: 'moveByWords',
|
116
116
|
motionArgs: { forward: false, wordEnd: true, bigWord: true,
|
117
117
|
inclusive: true }},
|
118
|
+
{ keys: ['{'], type: 'motion', motion: 'moveByParagraph',
|
119
|
+
motionArgs: { forward: false }},
|
120
|
+
{ keys: ['}'], type: 'motion', motion: 'moveByParagraph',
|
121
|
+
motionArgs: { forward: true }},
|
118
122
|
{ keys: ['Ctrl-f'], type: 'motion',
|
119
123
|
motion: 'moveByPage', motionArgs: { forward: true }},
|
120
124
|
{ keys: ['Ctrl-b'], type: 'motion',
|
@@ -247,7 +251,7 @@
|
|
247
251
|
var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
|
248
252
|
'Esc', 'Home', 'End', 'PageUp', 'PageDown'];
|
249
253
|
var validMarks = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
|
250
|
-
numbers);
|
254
|
+
numbers).concat(['<', '>']);
|
251
255
|
var validRegisters = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
|
252
256
|
numbers).concat('-\"'.split(''));
|
253
257
|
|
@@ -720,7 +724,11 @@
|
|
720
724
|
// Handle user defined Ex to Ex mappings
|
721
725
|
exCommandDispatcher.processCommand(cm, command.exArgs.input);
|
722
726
|
} else {
|
723
|
-
|
727
|
+
if (vim.visualMode) {
|
728
|
+
showPrompt(cm, onPromptClose, ':', undefined, '\'<,\'>');
|
729
|
+
} else {
|
730
|
+
showPrompt(cm, onPromptClose, ':');
|
731
|
+
}
|
724
732
|
}
|
725
733
|
},
|
726
734
|
evalInput: function(cm, vim) {
|
@@ -806,6 +814,12 @@
|
|
806
814
|
// CodeMirror can't figure out that we changed directions...
|
807
815
|
cm.setCursor(selectionStart);
|
808
816
|
cm.setSelection(selectionStart, selectionEnd);
|
817
|
+
updateMark(cm, vim, '<',
|
818
|
+
cursorIsBefore(selectionStart, selectionEnd) ? selectionStart
|
819
|
+
: selectionEnd);
|
820
|
+
updateMark(cm, vim, '>',
|
821
|
+
cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd
|
822
|
+
: selectionStart);
|
809
823
|
} else if (!operator) {
|
810
824
|
curEnd = clipCursorToContent(cm, curEnd);
|
811
825
|
cm.setCursor(curEnd.line, curEnd.ch);
|
@@ -923,6 +937,22 @@
|
|
923
937
|
cm.setCursor(curStart);
|
924
938
|
return curEnd;
|
925
939
|
},
|
940
|
+
moveByParagraph: function(cm, motionArgs) {
|
941
|
+
var line = cm.getCursor().line;
|
942
|
+
var repeat = motionArgs.repeat;
|
943
|
+
var inc = motionArgs.forward ? 1 : -1;
|
944
|
+
for (var i = 0; i < repeat; i++) {
|
945
|
+
if ((!motionArgs.forward && line === 0) ||
|
946
|
+
(motionArgs.forward && line == cm.lineCount() - 1)) {
|
947
|
+
break;
|
948
|
+
}
|
949
|
+
line += inc;
|
950
|
+
while (line !== 0 && line != cm.lineCount - 1 && cm.getLine(line)) {
|
951
|
+
line += inc;
|
952
|
+
}
|
953
|
+
}
|
954
|
+
return { line: line, ch: 0 };
|
955
|
+
},
|
926
956
|
moveByWords: function(cm, motionArgs) {
|
927
957
|
return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward,
|
928
958
|
!!motionArgs.wordEnd, !!motionArgs.bigWord);
|
@@ -1119,21 +1149,29 @@
|
|
1119
1149
|
cm.setSelection(curStart, curEnd);
|
1120
1150
|
}
|
1121
1151
|
} else {
|
1152
|
+
curStart = cm.getCursor('anchor');
|
1153
|
+
curEnd = cm.getCursor('head');
|
1122
1154
|
if (!vim.visualLine && actionArgs.linewise) {
|
1123
1155
|
// Shift-V pressed in characterwise visual mode. Switch to linewise
|
1124
1156
|
// visual mode instead of exiting visual mode.
|
1125
1157
|
vim.visualLine = true;
|
1126
|
-
curStart = cm.getCursor('anchor');
|
1127
|
-
curEnd = cm.getCursor('head');
|
1128
1158
|
curStart.ch = cursorIsBefore(curStart, curEnd) ? 0 :
|
1129
1159
|
lineLength(cm, curStart.line);
|
1130
1160
|
curEnd.ch = cursorIsBefore(curStart, curEnd) ?
|
1131
1161
|
lineLength(cm, curEnd.line) : 0;
|
1132
1162
|
cm.setSelection(curStart, curEnd);
|
1163
|
+
} else if (vim.visualLine && !actionArgs.linewise) {
|
1164
|
+
// v pressed in linewise visual mode. Switch to characterwise visual
|
1165
|
+
// mode instead of exiting visual mode.
|
1166
|
+
vim.visualLine = false;
|
1133
1167
|
} else {
|
1134
1168
|
exitVisualMode(cm, vim);
|
1135
1169
|
}
|
1136
1170
|
}
|
1171
|
+
updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
|
1172
|
+
: curEnd);
|
1173
|
+
updateMark(cm, vim, '>', cursorIsBefore(curStart, curEnd) ? curEnd
|
1174
|
+
: curStart);
|
1137
1175
|
},
|
1138
1176
|
joinLines: function(cm, actionArgs, vim) {
|
1139
1177
|
var curStart, curEnd;
|
@@ -1232,13 +1270,7 @@
|
|
1232
1270
|
},
|
1233
1271
|
setMark: function(cm, actionArgs, vim) {
|
1234
1272
|
var markName = actionArgs.selectedCharacter;
|
1235
|
-
|
1236
|
-
return;
|
1237
|
-
}
|
1238
|
-
if (vim.marks[markName]) {
|
1239
|
-
vim.marks[markName].clear();
|
1240
|
-
}
|
1241
|
-
vim.marks[markName] = cm.setBookmark(cm.getCursor());
|
1273
|
+
updateMark(cm, vim, markName, cm.getCursor());
|
1242
1274
|
},
|
1243
1275
|
replace: function(cm, actionArgs) {
|
1244
1276
|
var replaceWith = actionArgs.selectedCharacter;
|
@@ -1636,6 +1668,16 @@
|
|
1636
1668
|
return clipCursorToContent(cm, { line: line, ch: repeat - 1 });
|
1637
1669
|
}
|
1638
1670
|
|
1671
|
+
function updateMark(cm, vim, markName, pos) {
|
1672
|
+
if (!inArray(markName, validMarks)) {
|
1673
|
+
return;
|
1674
|
+
}
|
1675
|
+
if (vim.marks[markName]) {
|
1676
|
+
vim.marks[markName].clear();
|
1677
|
+
}
|
1678
|
+
vim.marks[markName] = cm.setBookmark(pos);
|
1679
|
+
}
|
1680
|
+
|
1639
1681
|
function charIdxInLine(start, line, character, forward, includeChar) {
|
1640
1682
|
// Search for char in line.
|
1641
1683
|
// motion_options: {forward, includeChar}
|
@@ -1804,6 +1846,12 @@
|
|
1804
1846
|
setMarked: function(marked) {
|
1805
1847
|
this.marked = marked;
|
1806
1848
|
},
|
1849
|
+
getOverlay: function() {
|
1850
|
+
return this.searchOverlay;
|
1851
|
+
},
|
1852
|
+
setOverlay: function(overlay) {
|
1853
|
+
this.searchOverlay = overlay;
|
1854
|
+
},
|
1807
1855
|
isReversed: function() {
|
1808
1856
|
return getVimGlobalState().isReversed;
|
1809
1857
|
},
|
@@ -1815,9 +1863,9 @@
|
|
1815
1863
|
var vim = getVimState(cm);
|
1816
1864
|
return vim.searchState_ || (vim.searchState_ = new SearchState());
|
1817
1865
|
}
|
1818
|
-
function dialog(cm, text, shortText, callback) {
|
1866
|
+
function dialog(cm, text, shortText, callback, initialValue) {
|
1819
1867
|
if (cm.openDialog) {
|
1820
|
-
cm.openDialog(text, callback, {bottom: true});
|
1868
|
+
cm.openDialog(text, callback, { bottom: true, value: initialValue });
|
1821
1869
|
}
|
1822
1870
|
else {
|
1823
1871
|
callback(prompt(shortText, ""));
|
@@ -1899,9 +1947,10 @@
|
|
1899
1947
|
return raw;
|
1900
1948
|
}
|
1901
1949
|
var searchPromptDesc = '(Javascript regexp)';
|
1902
|
-
function showPrompt(cm, onPromptClose, prefix, desc) {
|
1950
|
+
function showPrompt(cm, onPromptClose, prefix, desc, initialValue) {
|
1903
1951
|
var shortText = (prefix || '') + ' ' + (desc || '');
|
1904
|
-
dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose
|
1952
|
+
dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose,
|
1953
|
+
initialValue);
|
1905
1954
|
}
|
1906
1955
|
function regexEqual(r1, r2) {
|
1907
1956
|
if (r1 instanceof RegExp && r2 instanceof RegExp) {
|
@@ -1934,17 +1983,53 @@
|
|
1934
1983
|
state.setQuery(query);
|
1935
1984
|
});
|
1936
1985
|
}
|
1986
|
+
function searchOverlay(query) {
|
1987
|
+
return {
|
1988
|
+
token: function(stream) {
|
1989
|
+
var match = stream.match(query, false);
|
1990
|
+
if (match) {
|
1991
|
+
if (!stream.sol()) {
|
1992
|
+
// Backtrack 1 to match \b
|
1993
|
+
stream.backUp(1);
|
1994
|
+
if (!query.exec(stream.next() + match[0])) {
|
1995
|
+
stream.next();
|
1996
|
+
return null;
|
1997
|
+
}
|
1998
|
+
}
|
1999
|
+
stream.match(query);
|
2000
|
+
return "searching";
|
2001
|
+
}
|
2002
|
+
while (!stream.eol()) {
|
2003
|
+
stream.next();
|
2004
|
+
if (stream.match(query, false)) break;
|
2005
|
+
}
|
2006
|
+
},
|
2007
|
+
query: query
|
2008
|
+
};
|
2009
|
+
}
|
1937
2010
|
function highlightSearchMatches(cm, query) {
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
|
2011
|
+
if (cm.addOverlay) {
|
2012
|
+
var overlay = getSearchState(cm).getOverlay();
|
2013
|
+
if (!overlay || query != overlay.query) {
|
2014
|
+
if (overlay) {
|
2015
|
+
cm.removeOverlay(overlay);
|
2016
|
+
}
|
2017
|
+
overlay = searchOverlay(query);
|
2018
|
+
cm.addOverlay(overlay);
|
2019
|
+
getSearchState(cm).setOverlay(overlay);
|
2020
|
+
}
|
2021
|
+
} else {
|
2022
|
+
// TODO: Highlight only text inside the viewport. Highlighting everything
|
2023
|
+
// is inefficient and expensive.
|
2024
|
+
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
|
2025
|
+
var marked = [];
|
2026
|
+
for (var cursor = cm.getSearchCursor(query);
|
2027
|
+
cursor.findNext();) {
|
2028
|
+
marked.push(cm.markText(cursor.from(), cursor.to(),
|
2029
|
+
{ className: 'cm-searching' }));
|
2030
|
+
}
|
2031
|
+
getSearchState(cm).setMarked(marked);
|
1946
2032
|
}
|
1947
|
-
getSearchState(cm).setMarked(marked);
|
1948
2033
|
}
|
1949
2034
|
}
|
1950
2035
|
function findNext(cm, prev, repeat) {
|
@@ -1978,20 +2063,52 @@
|
|
1978
2063
|
return cursor.from();
|
1979
2064
|
});}
|
1980
2065
|
function clearSearchHighlight(cm) {
|
1981
|
-
cm.
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
marked
|
2066
|
+
if (cm.addOverlay) {
|
2067
|
+
cm.removeOverlay(getSearchState(cm).getOverlay());
|
2068
|
+
getSearchState(cm).setOverlay(null);
|
2069
|
+
} else {
|
2070
|
+
cm.operation(function() {
|
2071
|
+
var state = getSearchState(cm);
|
2072
|
+
if (!state.getQuery()) {
|
2073
|
+
return;
|
2074
|
+
}
|
2075
|
+
var marked = state.getMarked();
|
2076
|
+
if (!marked) {
|
2077
|
+
return;
|
2078
|
+
}
|
2079
|
+
for (var i = 0; i < marked.length; ++i) {
|
2080
|
+
marked[i].clear();
|
2081
|
+
}
|
2082
|
+
state.setMarked(null);
|
2083
|
+
});
|
2084
|
+
}
|
2085
|
+
}
|
2086
|
+
/**
|
2087
|
+
* Check if pos is in the specified range, INCLUSIVE.
|
2088
|
+
* Range can be specified with 1 or 2 arguments.
|
2089
|
+
* If the first range argument is an array, treat it as an array of line
|
2090
|
+
* numbers. Match pos against any of the lines.
|
2091
|
+
* If the first range argument is a number,
|
2092
|
+
* if there is only 1 range argument, check if pos has the same line
|
2093
|
+
* number
|
2094
|
+
* if there are 2 range arguments, then check if pos is in between the two
|
2095
|
+
* range arguments.
|
2096
|
+
*/
|
2097
|
+
function isInRange(pos, start, end) {
|
2098
|
+
if (typeof pos != 'number') {
|
2099
|
+
// Assume it is a cursor position. Get the line number.
|
2100
|
+
pos = pos.line;
|
2101
|
+
}
|
2102
|
+
if (start instanceof Array) {
|
2103
|
+
return inArray(pos, start);
|
2104
|
+
} else {
|
2105
|
+
if (end) {
|
2106
|
+
return (pos >= start && pos <= end);
|
2107
|
+
} else {
|
2108
|
+
return pos == start;
|
1992
2109
|
}
|
1993
|
-
|
1994
|
-
|
2110
|
+
}
|
2111
|
+
}
|
1995
2112
|
|
1996
2113
|
// Ex command handling
|
1997
2114
|
// Care must be taken when adding to the default Ex command map. For any
|
@@ -2001,14 +2118,23 @@
|
|
2001
2118
|
{ name: 'map', type: 'builtIn' },
|
2002
2119
|
{ name: 'write', shortName: 'w', type: 'builtIn' },
|
2003
2120
|
{ name: 'undo', shortName: 'u', type: 'builtIn' },
|
2004
|
-
{ name: 'redo', shortName: 'red', type: 'builtIn' }
|
2121
|
+
{ name: 'redo', shortName: 'red', type: 'builtIn' },
|
2122
|
+
{ name: 'substitute', shortName: 's', type: 'builtIn'}
|
2005
2123
|
];
|
2006
|
-
|
2124
|
+
Vim.ExCommandDispatcher = function() {
|
2007
2125
|
this.buildCommandMap_();
|
2008
2126
|
};
|
2009
|
-
ExCommandDispatcher.prototype = {
|
2127
|
+
Vim.ExCommandDispatcher.prototype = {
|
2010
2128
|
processCommand: function(cm, input) {
|
2011
|
-
var
|
2129
|
+
var inputStream = new CodeMirror.StringStream(input);
|
2130
|
+
var params = {};
|
2131
|
+
params.input = input;
|
2132
|
+
try {
|
2133
|
+
this.parseInput_(cm, inputStream, params);
|
2134
|
+
} catch(e) {
|
2135
|
+
showConfirm(cm, e);
|
2136
|
+
return;
|
2137
|
+
}
|
2012
2138
|
var commandName;
|
2013
2139
|
if (!params.commandName) {
|
2014
2140
|
// If only a line range is defined, move to the line.
|
@@ -2019,6 +2145,7 @@
|
|
2019
2145
|
var command = this.matchCommand_(params.commandName);
|
2020
2146
|
if (command) {
|
2021
2147
|
commandName = command.name;
|
2148
|
+
this.parseCommandArgs_(inputStream, params, command);
|
2022
2149
|
if (command.type == 'exToKey') {
|
2023
2150
|
// Handle Ex to Key mapping.
|
2024
2151
|
for (var i = 0; i < command.toKeys.length; i++) {
|
@@ -2038,37 +2165,63 @@
|
|
2038
2165
|
}
|
2039
2166
|
exCommands[commandName](cm, params);
|
2040
2167
|
},
|
2041
|
-
parseInput_: function(
|
2042
|
-
|
2043
|
-
result.input = input;
|
2044
|
-
var idx = 0;
|
2045
|
-
// Trim preceding ':'.
|
2046
|
-
var colons = (/^:+/).exec(input);
|
2047
|
-
if (colons) {
|
2048
|
-
idx += colons[0].length;
|
2049
|
-
}
|
2050
|
-
|
2168
|
+
parseInput_: function(cm, inputStream, result) {
|
2169
|
+
inputStream.eatWhile(':');
|
2051
2170
|
// Parse range.
|
2052
|
-
|
2053
|
-
|
2054
|
-
result.
|
2055
|
-
|
2171
|
+
if (inputStream.eat('%')) {
|
2172
|
+
result.line = 0;
|
2173
|
+
result.lineEnd = cm.lineCount() - 1;
|
2174
|
+
} else {
|
2175
|
+
result.line = this.parseLineSpec_(cm, inputStream);
|
2176
|
+
if (result.line !== undefined && inputStream.eat(',')) {
|
2177
|
+
result.lineEnd = this.parseLineSpec_(cm, inputStream);
|
2178
|
+
}
|
2056
2179
|
}
|
2057
2180
|
|
2058
2181
|
// Parse command name.
|
2059
|
-
var commandMatch = (/^(\w+)/)
|
2182
|
+
var commandMatch = inputStream.match(/^(\w+)/);
|
2060
2183
|
if (commandMatch) {
|
2061
2184
|
result.commandName = commandMatch[1];
|
2062
|
-
|
2185
|
+
} else {
|
2186
|
+
result.commandName = inputStream.match(/.*/)[0];
|
2063
2187
|
}
|
2064
2188
|
|
2189
|
+
return result;
|
2190
|
+
},
|
2191
|
+
parseLineSpec_: function(cm, inputStream) {
|
2192
|
+
var numberMatch = inputStream.match(/^(\d+)/);
|
2193
|
+
if (numberMatch) {
|
2194
|
+
return parseInt(numberMatch[1], 10) - 1;
|
2195
|
+
}
|
2196
|
+
switch (inputStream.next()) {
|
2197
|
+
case '.':
|
2198
|
+
return cm.getCursor().line;
|
2199
|
+
case '$':
|
2200
|
+
return cm.lineCount() - 1;
|
2201
|
+
case '\'':
|
2202
|
+
var mark = getVimState(cm).marks[inputStream.next()];
|
2203
|
+
if (mark && mark.find()) {
|
2204
|
+
return mark.find().line;
|
2205
|
+
} else {
|
2206
|
+
throw "Mark not set";
|
2207
|
+
}
|
2208
|
+
break;
|
2209
|
+
default:
|
2210
|
+
inputStream.backUp(1);
|
2211
|
+
return cm.getCursor().line;
|
2212
|
+
}
|
2213
|
+
},
|
2214
|
+
parseCommandArgs_: function(inputStream, params, command) {
|
2215
|
+
if (inputStream.eol()) {
|
2216
|
+
return;
|
2217
|
+
}
|
2218
|
+
params.argString = inputStream.match(/.*/)[0];
|
2065
2219
|
// Parse command-line arguments
|
2066
|
-
var
|
2220
|
+
var delim = command.argDelimiter || /\s+/;
|
2221
|
+
var args = trim(params.argString).split(delim);
|
2067
2222
|
if (args.length && args[0]) {
|
2068
|
-
|
2223
|
+
params.args = args;
|
2069
2224
|
}
|
2070
|
-
|
2071
|
-
return result;
|
2072
2225
|
},
|
2073
2226
|
matchCommand_: function(commandName) {
|
2074
2227
|
// Return the command in the command map that matches the shortest
|
@@ -2095,9 +2248,9 @@
|
|
2095
2248
|
}
|
2096
2249
|
},
|
2097
2250
|
map: function(lhs, rhs) {
|
2098
|
-
if (lhs.charAt(0) == ':') {
|
2251
|
+
if (lhs != ':' && lhs.charAt(0) == ':') {
|
2099
2252
|
var commandName = lhs.substring(1);
|
2100
|
-
if (rhs.charAt(0) == ':') {
|
2253
|
+
if (rhs != ':' && rhs.charAt(0) == ':') {
|
2101
2254
|
// Ex to Ex mapping
|
2102
2255
|
this.commandMap_[commandName] = {
|
2103
2256
|
name: commandName,
|
@@ -2113,7 +2266,7 @@
|
|
2113
2266
|
};
|
2114
2267
|
}
|
2115
2268
|
} else {
|
2116
|
-
if (rhs.charAt(0) == ':') {
|
2269
|
+
if (rhs != ':' && rhs.charAt(0) == ':') {
|
2117
2270
|
// Key to Ex mapping.
|
2118
2271
|
defaultKeymap.unshift({
|
2119
2272
|
keys: parseKeyString(lhs),
|
@@ -2172,7 +2325,7 @@
|
|
2172
2325
|
|
2173
2326
|
var exCommands = {
|
2174
2327
|
map: function(cm, params) {
|
2175
|
-
var mapArgs = params.
|
2328
|
+
var mapArgs = params.args;
|
2176
2329
|
if (!mapArgs || mapArgs.length < 2) {
|
2177
2330
|
if (cm) {
|
2178
2331
|
showConfirm(cm, 'Invalid mapping: ' + params.input);
|
@@ -2187,6 +2340,66 @@
|
|
2187
2340
|
motionArgs: { forward: false, explicitRepeat: true,
|
2188
2341
|
linewise: true, repeat: params.line }});
|
2189
2342
|
},
|
2343
|
+
substitute: function(cm, params) {
|
2344
|
+
var argString = params.argString;
|
2345
|
+
var slashes = findUnescapedSlashes(argString);
|
2346
|
+
if (slashes[0] !== 0) {
|
2347
|
+
showConfirm(cm, 'Substitutions should be of the form ' +
|
2348
|
+
':s/pattern/replace/');
|
2349
|
+
return;
|
2350
|
+
}
|
2351
|
+
var regexPart = argString.substring(slashes[0] + 1, slashes[1]);
|
2352
|
+
var replacePart = '';
|
2353
|
+
var flagsPart;
|
2354
|
+
var count;
|
2355
|
+
if (slashes[1]) {
|
2356
|
+
replacePart = argString.substring(slashes[1] + 1, slashes[2]);
|
2357
|
+
}
|
2358
|
+
if (slashes[2]) {
|
2359
|
+
// After the 3rd slash, we can have flags followed by a space followed
|
2360
|
+
// by count.
|
2361
|
+
var trailing = argString.substring(slashes[2] + 1).split(' ');
|
2362
|
+
flagsPart = trailing[0];
|
2363
|
+
count = parseInt(trailing[1]);
|
2364
|
+
}
|
2365
|
+
if (flagsPart) {
|
2366
|
+
regexPart = regexPart + '/' + flagsPart;
|
2367
|
+
}
|
2368
|
+
if (regexPart) {
|
2369
|
+
// If regex part is empty, then use the previous query. Otherwise use
|
2370
|
+
// the regex part as the new query.
|
2371
|
+
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
|
2372
|
+
true /** smartCase */);
|
2373
|
+
}
|
2374
|
+
var state = getSearchState(cm);
|
2375
|
+
var query = state.getQuery();
|
2376
|
+
var lineStart = params.line || 0;
|
2377
|
+
var lineEnd = params.lineEnd || lineStart;
|
2378
|
+
if (count) {
|
2379
|
+
lineStart = lineEnd;
|
2380
|
+
lineEnd = lineStart + count - 1;
|
2381
|
+
}
|
2382
|
+
var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 });
|
2383
|
+
function doReplace() {
|
2384
|
+
for (var cursor = cm.getSearchCursor(query, startPos);
|
2385
|
+
cursor.findNext() &&
|
2386
|
+
isInRange(cursor.from(), lineStart, lineEnd);) {
|
2387
|
+
var text = cm.getRange(cursor.from(), cursor.to());
|
2388
|
+
var newText = text.replace(query, replacePart);
|
2389
|
+
cursor.replace(newText);
|
2390
|
+
}
|
2391
|
+
var vim = getVimState(cm);
|
2392
|
+
if (vim.visualMode) {
|
2393
|
+
exitVisualMode(cm, vim);
|
2394
|
+
}
|
2395
|
+
}
|
2396
|
+
if (cm.compoundChange) {
|
2397
|
+
// Only exists in v2
|
2398
|
+
cm.compoundChange(doReplace);
|
2399
|
+
} else {
|
2400
|
+
cm.operation(doReplace);
|
2401
|
+
}
|
2402
|
+
},
|
2190
2403
|
redo: CodeMirror.commands.redo,
|
2191
2404
|
undo: CodeMirror.commands.undo,
|
2192
2405
|
write: function(cm) {
|
@@ -2200,7 +2413,7 @@
|
|
2200
2413
|
}
|
2201
2414
|
};
|
2202
2415
|
|
2203
|
-
var exCommandDispatcher = new ExCommandDispatcher();
|
2416
|
+
var exCommandDispatcher = new Vim.ExCommandDispatcher();
|
2204
2417
|
|
2205
2418
|
// Register Vim with CodeMirror
|
2206
2419
|
function buildVimKeyMap() {
|