codemirror-rails 3.21 → 3.22
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 +89 -43
- data/vendor/assets/javascripts/codemirror/addons/comment/continuecomment.js +16 -3
- data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -0
- data/vendor/assets/javascripts/codemirror/addons/display/rulers.js +47 -0
- data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +1 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +6 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/markdown-fold.js +34 -0
- data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +2 -2
- data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +0 -0
- data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +25 -18
- data/vendor/assets/javascripts/codemirror/addons/lint/yaml-lint.js +14 -0
- data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +2 -2
- data/vendor/assets/javascripts/codemirror/addons/scroll/scrollpastend.js +2 -0
- data/vendor/assets/javascripts/codemirror/addons/search/search.js +9 -3
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +126 -54
- data/vendor/assets/javascripts/codemirror/modes/clojure.js +6 -5
- data/vendor/assets/javascripts/codemirror/modes/css.js +19 -9
- data/vendor/assets/javascripts/codemirror/modes/gas.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +4 -1
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +11 -3
- data/vendor/assets/javascripts/codemirror/modes/julia.js +47 -23
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +5 -3
- data/vendor/assets/javascripts/codemirror/modes/octave.js +6 -4
- data/vendor/assets/javascripts/codemirror/modes/puppet.js +204 -0
- data/vendor/assets/javascripts/codemirror/modes/python.js +4 -0
- data/vendor/assets/javascripts/codemirror/modes/rst.js +520 -517
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +1 -0
- data/vendor/assets/javascripts/codemirror/modes/solr.js +89 -0
- data/vendor/assets/javascripts/codemirror/modes/sql.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/xml.js +2 -1
- data/vendor/assets/stylesheets/codemirror.css +12 -11
- data/vendor/assets/stylesheets/codemirror/themes/mdn-like.css +44 -0
- data/vendor/assets/stylesheets/codemirror/themes/solarized.css +1 -0
- metadata +8 -2
@@ -0,0 +1,47 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
CodeMirror.defineOption("rulers", false, function(cm, val, old) {
|
5
|
+
if (old && old != CodeMirror.Init) {
|
6
|
+
clearRulers(cm);
|
7
|
+
cm.off("refresh", refreshRulers);
|
8
|
+
}
|
9
|
+
if (val && val.length) {
|
10
|
+
setRulers(cm);
|
11
|
+
cm.on("refresh", refreshRulers);
|
12
|
+
}
|
13
|
+
});
|
14
|
+
|
15
|
+
function clearRulers(cm) {
|
16
|
+
for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) {
|
17
|
+
var node = cm.display.lineSpace.childNodes[i];
|
18
|
+
if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
|
19
|
+
node.parentNode.removeChild(node);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
function setRulers(cm) {
|
24
|
+
var val = cm.getOption("rulers");
|
25
|
+
var cw = cm.defaultCharWidth();
|
26
|
+
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
|
27
|
+
var bot = -cm.display.scroller.offsetHeight;
|
28
|
+
for (var i = 0; i < val.length; i++) {
|
29
|
+
var elt = document.createElement("div");
|
30
|
+
var col, cls = null;
|
31
|
+
if (typeof val[i] == "number") {
|
32
|
+
col = val[i];
|
33
|
+
} else {
|
34
|
+
col = val[i].column;
|
35
|
+
cls = val[i].className;
|
36
|
+
}
|
37
|
+
elt.className = "CodeMirror-ruler" + (cls ? " " + cls : "");
|
38
|
+
elt.style.cssText = "left: " + (left + col * cw) + "px; top: -50px; bottom: " + bot + "px";
|
39
|
+
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
function refreshRulers(cm) {
|
44
|
+
clearRulers(cm);
|
45
|
+
setRulers(cm);
|
46
|
+
}
|
47
|
+
})();
|
@@ -62,6 +62,12 @@
|
|
62
62
|
doFold(this, pos, options, force);
|
63
63
|
});
|
64
64
|
|
65
|
+
CodeMirror.defineExtension("isFolded", function(pos) {
|
66
|
+
var marks = this.findMarksAt(pos);
|
67
|
+
for (var i = 0; i < marks.length; ++i)
|
68
|
+
if (marks[i].__isFold) return true;
|
69
|
+
});
|
70
|
+
|
65
71
|
CodeMirror.commands.fold = function(cm) {
|
66
72
|
cm.foldCode(cm.getCursor());
|
67
73
|
};
|
@@ -0,0 +1,34 @@
|
|
1
|
+
CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
|
2
|
+
var maxDepth = 100;
|
3
|
+
|
4
|
+
function isHeader(lineNo) {
|
5
|
+
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
|
6
|
+
return tokentype && /\bheader\b/.test(tokentype);
|
7
|
+
}
|
8
|
+
|
9
|
+
function headerLevel(lineNo, line, nextLine) {
|
10
|
+
var match = line && line.match(/^#+/);
|
11
|
+
if (match && isHeader(lineNo)) return match[0].length;
|
12
|
+
match = nextLine && nextLine.match(/^[=\-]+\s*$/);
|
13
|
+
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
|
14
|
+
return maxDepth;
|
15
|
+
}
|
16
|
+
|
17
|
+
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
|
18
|
+
var level = headerLevel(start.line, firstLine, nextLine);
|
19
|
+
if (level === maxDepth) return undefined;
|
20
|
+
|
21
|
+
var lastLineNo = cm.lastLine();
|
22
|
+
var end = start.line, nextNextLine = cm.getLine(end + 2);
|
23
|
+
while (end < lastLineNo) {
|
24
|
+
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
|
25
|
+
++end;
|
26
|
+
nextLine = nextNextLine;
|
27
|
+
nextNextLine = cm.getLine(end + 2);
|
28
|
+
}
|
29
|
+
|
30
|
+
return {
|
31
|
+
from: CodeMirror.Pos(start.line, firstLine.length),
|
32
|
+
to: CodeMirror.Pos(end, cm.getLine(end).length)
|
33
|
+
};
|
34
|
+
});
|
@@ -15,8 +15,8 @@
|
|
15
15
|
var list = [], seen = {};
|
16
16
|
var re = new RegExp(word.source, "g");
|
17
17
|
for (var dir = -1; dir <= 1; dir += 2) {
|
18
|
-
var line = cur.line,
|
19
|
-
for (; line !=
|
18
|
+
var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
|
19
|
+
for (; line != endLine; line += dir) {
|
20
20
|
var text = editor.getLine(line), m;
|
21
21
|
while (m = re.exec(text)) {
|
22
22
|
if (line == cur.line && m[0] === curWord) continue;
|
File without changes
|
@@ -46,7 +46,7 @@
|
|
46
46
|
pick: function(data, i) {
|
47
47
|
var completion = data.list[i];
|
48
48
|
if (completion.hint) completion.hint(this.cm, data, completion);
|
49
|
-
else this.cm.replaceRange(getText(completion), data.from, data.to);
|
49
|
+
else this.cm.replaceRange(getText(completion), completion.from||data.from, completion.to||data.to);
|
50
50
|
CodeMirror.signal(data, "pick", completion);
|
51
51
|
this.close();
|
52
52
|
},
|
@@ -193,8 +193,24 @@
|
|
193
193
|
var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
|
194
194
|
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
|
195
195
|
(options.container || document.body).appendChild(hints);
|
196
|
-
var box = hints.getBoundingClientRect();
|
197
|
-
|
196
|
+
var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
|
197
|
+
if (overlapY > 0) {
|
198
|
+
var height = box.bottom - box.top, curTop = box.top - (pos.bottom - pos.top);
|
199
|
+
if (curTop - height > 0) { // Fits above cursor
|
200
|
+
hints.style.top = (top = curTop - height) + "px";
|
201
|
+
below = false;
|
202
|
+
} else if (height > winH) {
|
203
|
+
hints.style.height = (winH - 5) + "px";
|
204
|
+
hints.style.top = (top = pos.bottom - box.top) + "px";
|
205
|
+
var cursor = cm.getCursor();
|
206
|
+
if (data.from.ch != cursor.ch) {
|
207
|
+
pos = cm.cursorCoords(cursor);
|
208
|
+
hints.style.left = (left = pos.left) + "px";
|
209
|
+
box = hints.getBoundingClientRect();
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
var overlapX = box.left - winW;
|
198
214
|
if (overlapX > 0) {
|
199
215
|
if (box.right - box.left > winW) {
|
200
216
|
hints.style.width = (winW - 5) + "px";
|
@@ -202,17 +218,6 @@
|
|
202
218
|
}
|
203
219
|
hints.style.left = (left = pos.left - overlapX) + "px";
|
204
220
|
}
|
205
|
-
if (overlapY > 0) {
|
206
|
-
var height = box.bottom - box.top;
|
207
|
-
if (box.top - (pos.bottom - pos.top) - height > 0) {
|
208
|
-
overlapY = height + (pos.bottom - pos.top);
|
209
|
-
below = false;
|
210
|
-
} else if (height > winH) {
|
211
|
-
hints.style.height = (winH - 5) + "px";
|
212
|
-
overlapY -= height - winH;
|
213
|
-
}
|
214
|
-
hints.style.top = (top = pos.bottom - overlapY) + "px";
|
215
|
-
}
|
216
221
|
|
217
222
|
cm.addKeyMap(this.keyMap = buildKeyMap(options, {
|
218
223
|
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
|
@@ -220,7 +225,8 @@
|
|
220
225
|
menuSize: function() { return widget.screenAmount(); },
|
221
226
|
length: completions.length,
|
222
227
|
close: function() { completion.close(); },
|
223
|
-
pick: function() { widget.pick(); }
|
228
|
+
pick: function() { widget.pick(); },
|
229
|
+
data: data
|
224
230
|
}));
|
225
231
|
|
226
232
|
if (options.closeOnUnfocus !== false) {
|
@@ -303,15 +309,16 @@
|
|
303
309
|
};
|
304
310
|
|
305
311
|
CodeMirror.registerHelper("hint", "auto", function(cm, options) {
|
306
|
-
var helpers = cm.getHelpers(cm.getCursor(), "hint");
|
312
|
+
var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
|
307
313
|
if (helpers.length) {
|
308
314
|
for (var i = 0; i < helpers.length; i++) {
|
309
315
|
var cur = helpers[i](cm, options);
|
310
316
|
if (cur && cur.list.length) return cur;
|
311
317
|
}
|
312
|
-
} else {
|
313
|
-
var words = cm.getHelper(cm.getCursor(), "hintWords");
|
318
|
+
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
|
314
319
|
if (words) return CodeMirror.hint.fromList(cm, {words: words});
|
320
|
+
} else if (CodeMirror.hint.anyword) {
|
321
|
+
return CodeMirror.hint.anyword(cm, options);
|
315
322
|
}
|
316
323
|
});
|
317
324
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
// Depends on js-yaml.js from https://github.com/nodeca/js-yaml
|
2
|
+
|
3
|
+
// declare global: jsyaml
|
4
|
+
|
5
|
+
CodeMirror.registerHelper("lint", "yaml", function(text) {
|
6
|
+
var found = [];
|
7
|
+
try { jsyaml.load(text); }
|
8
|
+
catch(e) {
|
9
|
+
var loc = e.mark;
|
10
|
+
found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message });
|
11
|
+
}
|
12
|
+
return found;
|
13
|
+
});
|
14
|
+
CodeMirror.yamlValidator = CodeMirror.lint.yaml; // deprecated
|
@@ -92,14 +92,14 @@ exports.resolveMode = function(spec) {
|
|
92
92
|
else return spec || {name: "null"};
|
93
93
|
};
|
94
94
|
exports.getMode = function(options, spec) {
|
95
|
-
spec = exports.resolveMode(
|
95
|
+
spec = exports.resolveMode(spec);
|
96
96
|
var mfactory = modes[spec.name];
|
97
97
|
if (!mfactory) throw new Error("Unknown mode: " + spec);
|
98
98
|
return mfactory(options, spec);
|
99
99
|
};
|
100
100
|
exports.registerHelper = exports.registerGlobalHelper = Math.min;
|
101
101
|
|
102
|
-
exports.runMode = function(string, modespec, callback) {
|
102
|
+
exports.runMode = function(string, modespec, callback, options) {
|
103
103
|
var mode = exports.getMode({indentUnit: 2}, modespec);
|
104
104
|
var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
|
105
105
|
for (var i = 0, e = lines.length; i < e; ++i) {
|
@@ -4,11 +4,13 @@
|
|
4
4
|
CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) {
|
5
5
|
if (old && old != CodeMirror.Init) {
|
6
6
|
cm.off("change", onChange);
|
7
|
+
cm.off("refresh", updateBottomMargin);
|
7
8
|
cm.display.lineSpace.parentNode.style.paddingBottom = "";
|
8
9
|
cm.state.scrollPastEndPadding = null;
|
9
10
|
}
|
10
11
|
if (val) {
|
11
12
|
cm.on("change", onChange);
|
13
|
+
cm.on("refresh", updateBottomMargin);
|
12
14
|
updateBottomMargin(cm);
|
13
15
|
}
|
14
16
|
});
|
@@ -56,7 +56,13 @@
|
|
56
56
|
}
|
57
57
|
function parseQuery(query) {
|
58
58
|
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
59
|
-
|
59
|
+
if (isRE) {
|
60
|
+
query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i");
|
61
|
+
if (query.test("")) query = /x^/;
|
62
|
+
} else if (query == "") {
|
63
|
+
query = /x^/;
|
64
|
+
}
|
65
|
+
return query;
|
60
66
|
}
|
61
67
|
var queryDialog =
|
62
68
|
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
@@ -107,7 +113,7 @@
|
|
107
113
|
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
108
114
|
if (typeof query != "string") {
|
109
115
|
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
110
|
-
cursor.replace(text.replace(/\$(\d)
|
116
|
+
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
111
117
|
} else cursor.replace(text);
|
112
118
|
}
|
113
119
|
});
|
@@ -128,7 +134,7 @@
|
|
128
134
|
};
|
129
135
|
var doReplace = function(match) {
|
130
136
|
cursor.replace(typeof query == "string" ? text :
|
131
|
-
text.replace(/\$(\d)
|
137
|
+
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
132
138
|
advance();
|
133
139
|
};
|
134
140
|
advance();
|
@@ -74,7 +74,7 @@
|
|
74
74
|
{ keys: ['<S-BS>'], type: 'keyToKey', toKeys: ['b'] },
|
75
75
|
{ keys: ['<C-n>'], type: 'keyToKey', toKeys: ['j'] },
|
76
76
|
{ keys: ['<C-p>'], type: 'keyToKey', toKeys: ['k'] },
|
77
|
-
{ keys: ['C-['], type: 'keyToKey', toKeys: ['<Esc>'] },
|
77
|
+
{ keys: ['<C-[>'], type: 'keyToKey', toKeys: ['<Esc>'] },
|
78
78
|
{ keys: ['<C-c>'], type: 'keyToKey', toKeys: ['<Esc>'] },
|
79
79
|
{ keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'], context: 'normal' },
|
80
80
|
{ keys: ['s'], type: 'keyToKey', toKeys: ['x', 'i'], context: 'visual'},
|
@@ -1457,7 +1457,7 @@
|
|
1457
1457
|
motionArgs.selectedCharacter);
|
1458
1458
|
var increment = motionArgs.forward ? -1 : 1;
|
1459
1459
|
recordLastCharacterSearch(increment, motionArgs);
|
1460
|
-
if(!curEnd)return
|
1460
|
+
if (!curEnd) return null;
|
1461
1461
|
curEnd.ch += increment;
|
1462
1462
|
return curEnd;
|
1463
1463
|
},
|
@@ -1532,22 +1532,44 @@
|
|
1532
1532
|
ch: findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)) };
|
1533
1533
|
},
|
1534
1534
|
textObjectManipulation: function(cm, motionArgs) {
|
1535
|
+
// TODO: lots of possible exceptions that can be thrown here. Try da(
|
1536
|
+
// outside of a () block.
|
1537
|
+
|
1538
|
+
// TODO: adding <> >< to this map doesn't work, presumably because
|
1539
|
+
// they're operators
|
1540
|
+
var mirroredPairs = {'(': ')', ')': '(',
|
1541
|
+
'{': '}', '}': '{',
|
1542
|
+
'[': ']', ']': '['};
|
1543
|
+
var selfPaired = {'\'': true, '"': true};
|
1544
|
+
|
1535
1545
|
var character = motionArgs.selectedCharacter;
|
1546
|
+
|
1536
1547
|
// Inclusive is the difference between a and i
|
1537
1548
|
// TODO: Instead of using the additional text object map to perform text
|
1538
1549
|
// object operations, merge the map into the defaultKeyMap and use
|
1539
1550
|
// motionArgs to define behavior. Define separate entries for 'aw',
|
1540
1551
|
// 'iw', 'a[', 'i[', etc.
|
1541
1552
|
var inclusive = !motionArgs.textObjectInner;
|
1542
|
-
|
1553
|
+
|
1554
|
+
var tmp;
|
1555
|
+
if (mirroredPairs[character]) {
|
1556
|
+
tmp = selectCompanionObject(cm, mirroredPairs[character], inclusive);
|
1557
|
+
} else if (selfPaired[character]) {
|
1558
|
+
tmp = findBeginningAndEnd(cm, character, inclusive);
|
1559
|
+
} else if (character === 'W') {
|
1560
|
+
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
1561
|
+
true /** bigWord */);
|
1562
|
+
} else if (character === 'w') {
|
1563
|
+
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
1564
|
+
false /** bigWord */);
|
1565
|
+
} else {
|
1543
1566
|
// No text object defined for this, don't move.
|
1544
1567
|
return null;
|
1545
1568
|
}
|
1546
|
-
|
1547
|
-
|
1548
|
-
var end = tmp.end;
|
1549
|
-
return [start, end];
|
1569
|
+
|
1570
|
+
return [tmp.start, tmp.end];
|
1550
1571
|
},
|
1572
|
+
|
1551
1573
|
repeatLastCharacterSearch: function(cm, motionArgs) {
|
1552
1574
|
var lastSearch = vimGlobalState.lastChararacterSearch;
|
1553
1575
|
var repeat = motionArgs.repeat;
|
@@ -2015,36 +2037,6 @@
|
|
2015
2037
|
}
|
2016
2038
|
};
|
2017
2039
|
|
2018
|
-
var textObjects = {
|
2019
|
-
// TODO: lots of possible exceptions that can be thrown here. Try da(
|
2020
|
-
// outside of a () block.
|
2021
|
-
// TODO: implement text objects for the reverse like }. Should just be
|
2022
|
-
// an additional mapping after moving to the defaultKeyMap.
|
2023
|
-
'w': function(cm, inclusive) {
|
2024
|
-
return expandWordUnderCursor(cm, inclusive, true /** forward */,
|
2025
|
-
false /** bigWord */);
|
2026
|
-
},
|
2027
|
-
'W': function(cm, inclusive) {
|
2028
|
-
return expandWordUnderCursor(cm, inclusive,
|
2029
|
-
true /** forward */, true /** bigWord */);
|
2030
|
-
},
|
2031
|
-
'{': function(cm, inclusive) {
|
2032
|
-
return selectCompanionObject(cm, '}', inclusive);
|
2033
|
-
},
|
2034
|
-
'(': function(cm, inclusive) {
|
2035
|
-
return selectCompanionObject(cm, ')', inclusive);
|
2036
|
-
},
|
2037
|
-
'[': function(cm, inclusive) {
|
2038
|
-
return selectCompanionObject(cm, ']', inclusive);
|
2039
|
-
},
|
2040
|
-
'\'': function(cm, inclusive) {
|
2041
|
-
return findBeginningAndEnd(cm, "'", inclusive);
|
2042
|
-
},
|
2043
|
-
'"': function(cm, inclusive) {
|
2044
|
-
return findBeginningAndEnd(cm, '"', inclusive);
|
2045
|
-
}
|
2046
|
-
};
|
2047
|
-
|
2048
2040
|
/*
|
2049
2041
|
* Below are miscellaneous utility functions used by vim.js
|
2050
2042
|
*/
|
@@ -2634,13 +2626,25 @@
|
|
2634
2626
|
return cur;
|
2635
2627
|
}
|
2636
2628
|
|
2629
|
+
// TODO: perhaps this finagling of start and end positions belonds
|
2630
|
+
// in codmirror/replaceRange?
|
2637
2631
|
function selectCompanionObject(cm, revSymb, inclusive) {
|
2638
2632
|
var cur = cm.getCursor();
|
2639
|
-
|
2640
2633
|
var end = findMatchedSymbol(cm, cur, revSymb);
|
2641
2634
|
var start = findMatchedSymbol(cm, end);
|
2642
|
-
|
2643
|
-
|
2635
|
+
|
2636
|
+
if((start.line == end.line && start.ch > end.ch)
|
2637
|
+
|| (start.line > end.line)) {
|
2638
|
+
var tmp = start;
|
2639
|
+
start = end;
|
2640
|
+
end = tmp;
|
2641
|
+
}
|
2642
|
+
|
2643
|
+
if(inclusive) {
|
2644
|
+
end.ch += 1;
|
2645
|
+
} else {
|
2646
|
+
start.ch += 1;
|
2647
|
+
}
|
2644
2648
|
|
2645
2649
|
return { start: start, end: end };
|
2646
2650
|
}
|
@@ -2750,10 +2754,84 @@
|
|
2750
2754
|
if (!escapeNextChar && c == '/') {
|
2751
2755
|
slashes.push(i);
|
2752
2756
|
}
|
2753
|
-
escapeNextChar = (c == '\\');
|
2757
|
+
escapeNextChar = !escapeNextChar && (c == '\\');
|
2754
2758
|
}
|
2755
2759
|
return slashes;
|
2756
2760
|
}
|
2761
|
+
|
2762
|
+
// Translates a search string from ex (vim) syntax into javascript form.
|
2763
|
+
function fixRegex(str) {
|
2764
|
+
// When these match, add a '\' if unescaped or remove one if escaped.
|
2765
|
+
var specials = ['|', '(', ')', '{'];
|
2766
|
+
// Remove, but never add, a '\' for these.
|
2767
|
+
var unescape = ['}'];
|
2768
|
+
var escapeNextChar = false;
|
2769
|
+
var out = [];
|
2770
|
+
for (var i = -1; i < str.length; i++) {
|
2771
|
+
var c = str.charAt(i) || '';
|
2772
|
+
var n = str.charAt(i+1) || '';
|
2773
|
+
var specialComesNext = (specials.indexOf(n) != -1);
|
2774
|
+
if (escapeNextChar) {
|
2775
|
+
if (c !== '\\' || !specialComesNext) {
|
2776
|
+
out.push(c);
|
2777
|
+
}
|
2778
|
+
escapeNextChar = false;
|
2779
|
+
} else {
|
2780
|
+
if (c === '\\') {
|
2781
|
+
escapeNextChar = true;
|
2782
|
+
// Treat the unescape list as special for removing, but not adding '\'.
|
2783
|
+
if (unescape.indexOf(n) != -1) {
|
2784
|
+
specialComesNext = true;
|
2785
|
+
}
|
2786
|
+
// Not passing this test means removing a '\'.
|
2787
|
+
if (!specialComesNext || n === '\\') {
|
2788
|
+
out.push(c);
|
2789
|
+
}
|
2790
|
+
} else {
|
2791
|
+
out.push(c);
|
2792
|
+
if (specialComesNext && n !== '\\') {
|
2793
|
+
out.push('\\');
|
2794
|
+
}
|
2795
|
+
}
|
2796
|
+
}
|
2797
|
+
}
|
2798
|
+
return out.join('');
|
2799
|
+
}
|
2800
|
+
|
2801
|
+
// Translates the replace part of a search and replace from ex (vim) syntax into
|
2802
|
+
// javascript form. Similar to fixRegex, but additionally fixes back references
|
2803
|
+
// (translates '\[0..9]' to '$[0..9]') and follows different rules for escaping '$'.
|
2804
|
+
function fixRegexReplace(str) {
|
2805
|
+
var escapeNextChar = false;
|
2806
|
+
var out = [];
|
2807
|
+
for (var i = -1; i < str.length; i++) {
|
2808
|
+
var c = str.charAt(i) || '';
|
2809
|
+
var n = str.charAt(i+1) || '';
|
2810
|
+
if (escapeNextChar) {
|
2811
|
+
out.push(c);
|
2812
|
+
escapeNextChar = false;
|
2813
|
+
} else {
|
2814
|
+
if (c === '\\') {
|
2815
|
+
escapeNextChar = true;
|
2816
|
+
if ((isNumber(n) || n === '$')) {
|
2817
|
+
out.push('$');
|
2818
|
+
} else if (n !== '/' && n !== '\\') {
|
2819
|
+
out.push('\\');
|
2820
|
+
}
|
2821
|
+
} else {
|
2822
|
+
if (c === '$') {
|
2823
|
+
out.push('$');
|
2824
|
+
}
|
2825
|
+
out.push(c);
|
2826
|
+
if (n === '/') {
|
2827
|
+
out.push('\\');
|
2828
|
+
}
|
2829
|
+
}
|
2830
|
+
}
|
2831
|
+
}
|
2832
|
+
return out.join('');
|
2833
|
+
}
|
2834
|
+
|
2757
2835
|
/**
|
2758
2836
|
* Extract the regular expression from the query and return a Regexp object.
|
2759
2837
|
* Returns null if the query is blank.
|
@@ -2785,6 +2863,7 @@
|
|
2785
2863
|
if (!regexPart) {
|
2786
2864
|
return null;
|
2787
2865
|
}
|
2866
|
+
regexPart = fixRegex(regexPart);
|
2788
2867
|
if (smartCase) {
|
2789
2868
|
ignoreCase = (/^[^A-Z]*$/).test(regexPart);
|
2790
2869
|
}
|
@@ -3279,6 +3358,7 @@
|
|
3279
3358
|
var confirm = false; // Whether to confirm each replace.
|
3280
3359
|
if (slashes[1]) {
|
3281
3360
|
replacePart = argString.substring(slashes[1] + 1, slashes[2]);
|
3361
|
+
replacePart = fixRegexReplace(replacePart);
|
3282
3362
|
}
|
3283
3363
|
if (slashes[2]) {
|
3284
3364
|
// After the 3rd slash, we can have flags followed by a space followed
|
@@ -3495,18 +3575,10 @@
|
|
3495
3575
|
* Shift + key modifier to the resulting letter, while preserving other
|
3496
3576
|
* modifers.
|
3497
3577
|
*/
|
3498
|
-
// TODO: Figure out a way to catch capslock.
|
3499
3578
|
function cmKeyToVimKey(key, modifier) {
|
3500
3579
|
var vimKey = key;
|
3501
|
-
if (isUpperCase(vimKey)) {
|
3502
|
-
// Convert to lower case if shift is not the modifier since the key
|
3503
|
-
// we get from CodeMirror is always upper case.
|
3504
|
-
if (modifier == 'Shift') {
|
3505
|
-
modifier = null;
|
3506
|
-
}
|
3507
|
-
else {
|
3580
|
+
if (isUpperCase(vimKey) && modifier == 'Ctrl') {
|
3508
3581
|
vimKey = vimKey.toLowerCase();
|
3509
|
-
}
|
3510
3582
|
}
|
3511
3583
|
if (modifier) {
|
3512
3584
|
// Vim will parse modifier+key combination as a single key.
|
@@ -3532,9 +3604,9 @@
|
|
3532
3604
|
function bindKeys(keys, modifier) {
|
3533
3605
|
for (var i = 0; i < keys.length; i++) {
|
3534
3606
|
var key = keys[i];
|
3535
|
-
if (!modifier &&
|
3536
|
-
// Wrap
|
3537
|
-
//
|
3607
|
+
if (!modifier && key.length == 1) {
|
3608
|
+
// Wrap all keys without modifiers with '' to identify them by their
|
3609
|
+
// key characters instead of key identifiers.
|
3538
3610
|
key = "'" + key + "'";
|
3539
3611
|
}
|
3540
3612
|
var vimKey = cmKeyToVimKey(keys[i], modifier);
|
@@ -3543,7 +3615,7 @@
|
|
3543
3615
|
}
|
3544
3616
|
}
|
3545
3617
|
bindKeys(upperCaseAlphabet);
|
3546
|
-
bindKeys(
|
3618
|
+
bindKeys(lowerCaseAlphabet);
|
3547
3619
|
bindKeys(upperCaseAlphabet, 'Ctrl');
|
3548
3620
|
bindKeys(specialSymbols);
|
3549
3621
|
bindKeys(specialSymbols, 'Ctrl');
|